Skip to content

Commit

Permalink
NodePattern: Use param === node to match params.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcandre committed Jun 11, 2020
1 parent f496d2b commit 0e6ed2c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* [#4](https://github.com/rubocop-hq/rubocop-ast/issues/4): Add `interpolation?` for `RegexpNode`. ([@tejasbubane][])
* [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][])
* [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][])
* [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][])

## 0.0.3 (2020-05-15)

Expand Down
35 changes: 35 additions & 0 deletions docs/modules/ROOT/pages/node_pattern.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,41 @@ def_node_matcher :initializing_with_user?, <<~PATTERN
PATTERN
----

== `%` for arguments

Arguments can be passed to matchers, either as external method arguments,
or to be used to compare elements. An example of method argument:

[source,ruby]
----
def multiple_of?(n, factor)
n % factor == 0
end
def_node_matcher :int_node_multiple?, '(int #multiple_of?(%1))'
# ...
int_node_multiple?(node, 10) # => true if node is an 'int' node with a multiple of 10
----

Arguments can be used to match nodes directly:

[source,ruby]
----
def_node_matcher :has_sensitive_data?, '(hash <(pair (_ %1) $_) ...>)'
# ...
has_user_data?(node, :password) # => true if node is a hash with a key +:password+
# matching uses ===, so to match strings or symbols, 'pass' or 'password' one can:
has_user_data?(node, /^pass(word)?$/i)
# one can also pass lambdas...
has_user_data?(node, ->(key) { # return true or false depending on key })
----

== `nil` or `nil?`

Take a special attention to nil behavior:
Expand Down
5 changes: 3 additions & 2 deletions lib/rubocop/ast/node_pattern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ module AST
# '(send %1 _)' # % stands for a parameter which must be supplied to
# # #match at matching time
# # it will be compared to the corresponding value in
# # the AST using #==
# # the AST using #=== so you can pass Procs, Regexp
# # in addition to Nodes or literals.
# # a bare '%' is the same as '%1'
# # the number of extra parameters passed to #match
# # must equal the highest % value in the pattern
Expand Down Expand Up @@ -612,7 +613,7 @@ def compile_nodetype(type)
end

def compile_param(number)
"#{CUR_ELEMENT} == #{get_param(number)}"
"#{get_param(number)} === #{CUR_ELEMENT}"
end

def compile_args(tokens)
Expand Down
11 changes: 11 additions & 0 deletions spec/rubocop/ast/node_pattern_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,17 @@
let(:ruby) { '10' }

it_behaves_like 'matching'

context 'in root position' do
let(:pattern) { '%1' }
let(:matcher) { Object.new }
let(:params) { [matcher] }
let(:ruby) { '10' }

before { expect(matcher).to receive(:===).with(s(:int, 10)).and_return true } # rubocop:todo RSpec/ExpectInHook

it_behaves_like 'matching'
end
end

context 'in a nested sequence' do
Expand Down

0 comments on commit 0e6ed2c

Please sign in to comment.