Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically register events to dispatch #3490

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

sambostock
Copy link

@sambostock sambostock commented Mar 11, 2025

Note

This draft PR is a companion to Shopify/ruby-lsp#3291, which proposes this approach. Tests and other things have been omitted for now in the interest of getting feedback on the approach first, and will be added if we decide to move forward.

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. It is also a non-breaking change, so consumers can continue specifying each event if desired.

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.
Copy link
Collaborator

@kddnewton kddnewton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have a separate method for this, as this behavior gets magically triggered by having no events in the list currently. Something like:

def register(listener, *events)
  events.each { |event| (listeners[event] ||= []) << listener }
end

def register_public_methods(listener)
  register(listener, *listener.public_methods(false).grep(/^on_.*_(enter|leave)$/))
end

The other difference I would like to see I have in the example here, which is that I think we should not include inherited methods, (so using public_methods(false)).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants