Skip to content

Commit f07af59

Browse files
sambostockmatzbot
authored andcommitted
[ruby/prism] Dynamically register events to dispatch
Instead of requiring the consumer to provide a list of all events which they wish to handle, we can give them to option of dynamically detecting them, by scanning the listener's public methods. This approach is similar to that used by Minitest (scanning for `test_` methods) and Rails generators (running all public methods in the order they are defined). While this is slower than specifying a hard coded list, the penalty is only during registration. There is no change the the behaviour of dispatching the events. ruby/prism@781ebed743
1 parent de097fb commit f07af59

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

prism/templates/lib/prism/dispatcher.rb.erb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ module Prism
4444
#
4545
# def register: (Listener, *Symbol) -> void
4646
def register(listener, *events)
47+
register_events(listener, events)
48+
end
49+
50+
# Register all public methods of a listener that match the pattern
51+
# `on_<node_name>_(enter|leave)`.
52+
#
53+
# def register_public_methods: (Listener) -> void
54+
def register_public_methods(listener)
55+
register_events(listener, listener.public_methods(false).grep(/\Aon_.+_(?:enter|leave)\z/))
56+
end
57+
58+
# Register a listener for the given events.
59+
private def register_events(listener, events)
4760
events.each { |event| (listeners[event] ||= []) << listener }
4861
end
4962

test/prism/ruby/dispatcher_test.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ def on_integer_node_enter(node)
2525
end
2626

2727
def test_dispatching_events
28-
listener = TestListener.new
28+
listener_manual = TestListener.new
29+
listener_public = TestListener.new
30+
2931
dispatcher = Dispatcher.new
30-
dispatcher.register(listener, :on_call_node_enter, :on_call_node_leave, :on_integer_node_enter)
32+
dispatcher.register(listener_manual, :on_call_node_enter, :on_call_node_leave, :on_integer_node_enter)
33+
dispatcher.register_public_methods(listener_public)
3134

3235
root = Prism.parse(<<~RUBY).value
3336
def foo
@@ -36,11 +39,17 @@ def foo
3639
RUBY
3740

3841
dispatcher.dispatch(root)
39-
assert_equal([:on_call_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_call_node_leave], listener.events_received)
4042

41-
listener.events_received.clear
43+
[listener_manual, listener_public].each do |listener|
44+
assert_equal([:on_call_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_call_node_leave], listener.events_received)
45+
listener.events_received.clear
46+
end
47+
4248
dispatcher.dispatch_once(root.statements.body.first.body.body.first)
43-
assert_equal([:on_call_node_enter, :on_call_node_leave], listener.events_received)
49+
50+
[listener_manual, listener_public].each do |listener|
51+
assert_equal([:on_call_node_enter, :on_call_node_leave], listener.events_received)
52+
end
4453
end
4554
end
4655
end

0 commit comments

Comments
 (0)