class RuboCop::NodePattern
The compiler code is very simple; don’t be afraid to read through it!
in a certain place in the AST, you can do it like this: ‘[!nil <pattern>]`
Also note that if you need a “guard clause” to protect against possible nils
a pattern.
`#prefix_type?` to the AST node class, then ’prefix’ will become usable as
and so on. Therefore, if you add methods which are named like
the node being matched, ‘const’ by ‘#const_type?`, ’int’ by ‘#int_type?`,
Note that patterns like ’send’ are implemented by calling ‘#send_type?` on
’(if (send _ :== _) _ nil)‘
# and no ’else’ branch:
# matches a node parsed from an ‘if’, with a ‘==’ comparison,
‘(casgn nil const (send (const nil {:Class :Module}) :new)))’
# matches node parsed from ‘Const = Class.new’ or ‘Const = Module.new’:
You can nest arbitrarily deep:
‘#method(%0, 1)’ # funcalls can also be given 1 or more extra args
’equal?(%1)‘ # predicates can be given 1 or more extra args
# if that returns a truthy value, the match succeeds
# context where a pattern-matching method is defined
’#method’ # we call this a ‘funcall’; it calls a method in the
# so this matches against the grandparent node
’^^send’ # each ^ ascends one level in the AST
# matching process starts
# passed as the 1st argument to #match, where the
# for consistency, %0 is the ‘root node’ which is
# must equal the highest % value in the pattern
# the number of extra parameters passed to #match
# a bare ‘%’ is the same as ‘%1’
# the AST using #==
# it will be compared to the corresponding value in
# #match at matching time
’(send %1 _)‘ # % stands for a parameter which must be supplied to
# OR), [] is intersection (logical AND)
# in other words, while {} is pattern union (logical
# match in that position
’(int [!1 !2])‘ # [] contains multiple patterns, ALL of which must
# if a truthy value is returned, the match succeeds
# can be used
# any Ruby method which the matched object supports
# are are called on the target to see if it matches
’(int odd?)‘ # words which end with a ? are predicate methods,
# (#== is used to see if values unify)
# (like Prolog variables…)
’(send _x :+ _x)‘ # unification is performed on named wildcards
’(send $… int)‘ # capture all children but the last as an array
’(send $…)‘ # capture all the children as an array
# (this only works for the very last)
’(send … :new)‘ # you can specifically match against the last child
’(send _recv _msg)‘ # wildcards can be named (for readability)
’$(send const …)‘ # arbitrary matching can be performed on a capture
’(send !const …)‘ # ! negates the next part of the pattern
’(send $_ $_)‘ # you can use as many captures as you want
’(send $_ :new)‘ # as above, but whatever matches the $_ is captured
’(send _ :new)‘ # matches (send <anything> :new)
’(send const)‘ # matches (send (const …))
’({send class})‘ # matches (send) or (class)
’{send class}‘ # matches (send …) or (class …)
’(send …)‘ # matches (send …)
’(send)‘ # matches (send)
’send’ # matches (send …)
‘nil’ # matches a literal nil
’1’ # matches a literal integer
’:sym’ # matches a literal symbol
## Pattern string format examples
- With no captures: #match returns ‘true`.
- With no block, but multiple captures: captures are returned as an array.
- With no block, but one capture: the capture is returned.
value of the block through.
- With block: #match yields the captures (if any) and passes the return
from a matching AST.)
whether the pattern contained any “captures” (values which are extracted
return value depends on whether a block was provided to `#match`, and
If the match fails, `nil` will be returned. If the match succeeds, the
macros in `NodePattern::Macros` to define your own pattern-matching method.
pass an AST node to `NodePattern#match`. Alternatively, use one of the class
Initialize a new `NodePattern` with `NodePattern.new(pattern_string)`, then
This class performs a pattern-matching operation on an AST node.
def initialize(str)
def initialize(str) compiler = Compiler.new(str) src = "def match(node0#{compiler.emit_trailing_params});" \ "#{compiler.emit_method_code}end" instance_eval(src) end