Merged
Conversation
Addresses `ArgumentError`s when using `&:method_name` with `expose`, a scenario particularly affected by Ruby 3.0's stricter argument handling for procs. The previous arity check, including the condition `block.parameters == [[:req], [:rest]]`, was not consistently reliable for these cases. This change introduces `determine_block_arity` which: 1. Attempts to parse the original method name from `Proc#to_s` for blocks likely created via `&:method_name`. 2. If the method name is found and the object responds to it, this logic uses the *actual arity of the original method* to correctly determine how `instance_exec` should be called. 3. If the original method name can't be determined, it falls back to using `block.parameters.size`. This ensures methods exposed via `&:method_name` are called with the correct arguments (i.e., with or without `options`), resolving the `ArgumentError`s and removing the need for the previous `rescue` logic.
Ruby 3.0’s stricter arity rules meant `&:method_name` blocks could be called with wrong args, causing errors. The old check (`parameters == [[:req],[:rest]]` + `parameters.size`) was unreliable. This update: - Adds `symbol_to_proc_wrapper?` to detect pure `&:method_name` Procs (checks `lambda?`, `source_location.nil?`, and `parameters == [[:req],[:rest]]`). - Introduces `determine_block_arity`, which parses the method name from `block.to_s`; if the object responds to it, it uses `object.method(name).arity`, otherwise falls back to `block.arity`. - In `exec_with_object`, symbol-to-proc wrappers are required to have zero arity (raising `ArgumentError` otherwise), while regular Procs use `block.arity` to decide between `instance_exec(object)` and `instance_exec(object, options)`. This removes rescue logic and ensures `&:method_name` is only used for zero-argument methods.
Ensure symbol-to-proc exposures only work for zero-argument methods: - Raise if the method is undefined on the object - Raise if the method expects one or more arguments - Fall back to `Proc#arity` for regular blocks
Collaborator
Author
|
More details in #376 (comment) |
Member
|
I merged this following the "didn't break existing specs and added new ones" rule ;) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ruby 3’s stricter Proc arity rules could slip unwanted arguments into &:method_name exposures, causing confusing errors. This change detects pure symbol-to-proc wrappers up front, looks up the actual method’s arity on the entity object, and raises an error if it’s not zero. Regular blocks still use their own arity to decide whether to pass options. In practice, this makes it impossible to accidentally expose a one- or two-argument method with &:foo, ensuring only truly zero-argument methods are used in that shorthand.
Possible sollution #376