summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Bostock <[email protected]>2025-03-11 15:11:26 +0000
committergit <[email protected]>2025-03-20 17:28:59 +0000
commitf07af59a2f10beeb99878c967cefed2912310030 (patch)
treedfe881ce4fc50031816ad3526f469a471a19a79e
parentde097fbe5f3df105bd2a26e72db06b0f5139bc1a (diff)
[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. https://github.com/ruby/prism/commit/781ebed743
-rw-r--r--prism/templates/lib/prism/dispatcher.rb.erb13
-rw-r--r--test/prism/ruby/dispatcher_test.rb19
2 files changed, 27 insertions, 5 deletions
diff --git a/prism/templates/lib/prism/dispatcher.rb.erb b/prism/templates/lib/prism/dispatcher.rb.erb
index 0db0003464..52478451c9 100644
--- a/prism/templates/lib/prism/dispatcher.rb.erb
+++ b/prism/templates/lib/prism/dispatcher.rb.erb
@@ -44,6 +44,19 @@ module Prism
#
# def register: (Listener, *Symbol) -> void
def register(listener, *events)
+ register_events(listener, events)
+ end
+
+ # Register all public methods of a listener that match the pattern
+ # `on_<node_name>_(enter|leave)`.
+ #
+ # def register_public_methods: (Listener) -> void
+ def register_public_methods(listener)
+ register_events(listener, listener.public_methods(false).grep(/\Aon_.+_(?:enter|leave)\z/))
+ end
+
+ # Register a listener for the given events.
+ private def register_events(listener, events)
events.each { |event| (listeners[event] ||= []) << listener }
end
diff --git a/test/prism/ruby/dispatcher_test.rb b/test/prism/ruby/dispatcher_test.rb
index 1b6d7f4117..83eb29e1f3 100644
--- a/test/prism/ruby/dispatcher_test.rb
+++ b/test/prism/ruby/dispatcher_test.rb
@@ -25,9 +25,12 @@ module Prism
end
def test_dispatching_events
- listener = TestListener.new
+ listener_manual = TestListener.new
+ listener_public = TestListener.new
+
dispatcher = Dispatcher.new
- dispatcher.register(listener, :on_call_node_enter, :on_call_node_leave, :on_integer_node_enter)
+ dispatcher.register(listener_manual, :on_call_node_enter, :on_call_node_leave, :on_integer_node_enter)
+ dispatcher.register_public_methods(listener_public)
root = Prism.parse(<<~RUBY).value
def foo
@@ -36,11 +39,17 @@ module Prism
RUBY
dispatcher.dispatch(root)
- 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)
- listener.events_received.clear
+ [listener_manual, listener_public].each do |listener|
+ 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)
+ listener.events_received.clear
+ end
+
dispatcher.dispatch_once(root.statements.body.first.body.body.first)
- assert_equal([:on_call_node_enter, :on_call_node_leave], listener.events_received)
+
+ [listener_manual, listener_public].each do |listener|
+ assert_equal([:on_call_node_enter, :on_call_node_leave], listener.events_received)
+ end
end
end
end