[ruby-core:117235] [Ruby master Feature#20349] Pattern Matching - Expose local variable captures
From:
"Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>
Date:
2024-03-19 20:01:58 UTC
List:
ruby-core #117235
Issue #20349 has been updated by Eregon (Benoit Daloze).
This would make every pattern matching a lot slower which seems a big no-no performance wise.
I think that's enough to reject this proposal.
Because it would force to create that binding/Hash eagerly in case `PatternMatch.last_match` is used later.
Actually, `$~`/`Regexp.last_match` and `$_` are already causing significant performance problems for Ruby implementations, so I am strongly against any more of these "magically create variables in the caller".
BTW the example doesn't show how this is useful, is it to print the current state for debugging?
If so a helper method taking a `binding` seems appropriate (called inside the `longform_block?` method, not outside).
----------------------------------------
Feature #20349: Pattern Matching - Expose local variable captures
https://bugs.ruby-lang.org/issues/20349#change-107322
* Author: baweaver (Brandon Weaver)
* Status: Open
----------------------------------------
In Regular Expressions we have the ability to utilize `Regexp.last_match` ([link](https://ruby-doc.org/3.2.2/Regexp.html#method-c-last_match)) to access the most recent match data from a regular expression match. I would like to propose that we have similar functionality for pattern matching:
```ruby
require "rubocop"
def ast_from(string)
case string
when String then processed_source_from(string).ast
when RuboCop::ProcessedSource then string.ast
when RuboCop::AST::Node then string
else nil
end
end
def longform_block?(node)
node in [:block, # s(:block,
[:send, target, target_method], # s(:send, s(:array), :select),
[[:arg, v]], # s(:args, s(:arg, :v)),
[:send, [:lvar, ^v], block_method] # s(:send, s(:lvar, :v), :even?))
]
end
longform_block?(ast_from("[1, 2, 3].select { |v| v.even? }"))
# => true
# Name is not important, idea is, name can be debated. `source` is used to not
# show AST nodes
PatternMatch.last_match.transform_values(&:source)
# => {:node=>"[1, 2, 3].select { |v| v.even? }",
# :result=>"[1, 2, 3].select { |v| v.even? }",
# :target=>"[1, 2, 3]",
# :target_method=>:select,
# :v=>:v,
# :block_method=>:even?}
# Hacky version to show how / where behavior could be captured
def longform_block?(node)
result = node in [:block, # s(:block,
[:send, target, target_method], # s(:send, s(:array), :select),
[[:arg, v]], # s(:args, s(:arg, :v)),
[:send, [:lvar, ^v], block_method] # s(:send, s(:lvar, :v), :even?))
]
pp(binding.local_variables.to_h { [_1, binding.local_variable_get(_1).then { |s| s.source rescue s }] })
result
end
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- [email protected]
To unsubscribe send an email to [email protected]
ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/