Class: Prism::Pattern
- Inherits:
-
Object
- Object
- Prism::Pattern
- Defined in:
- lib/prism/pattern.rb
Overview
A pattern is an object that wraps a Ruby pattern matching expression. The expression would normally be passed to an ‘in` clause within a `case` expression or a rightward assignment expression. For example, in the following snippet:
case node
in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]
end
the pattern is the ConstantPathNode[...]
expression.
The pattern gets compiled into an object that responds to #call by running the #compile method. This method itself will run back through Prism to parse the expression into a tree, then walk the tree to generate the necessary callable objects. For example, if you wanted to compile the expression above into a callable, you would:
callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
callable.call(node)
The callable object returned by #compile is guaranteed to respond to #call with a single argument, which is the node to match against. It also is guaranteed to respond to #===, which means it itself can be used in a ‘case` expression, as in:
case node
when callable
end
If the query given to the initializer cannot be compiled into a valid matcher (either because of a syntax error or because it is using syntax we do not yet support) then a Prism::Pattern::CompilationError will be raised.
Defined Under Namespace
Classes: CompilationError
Instance Attribute Summary collapse
-
#query ⇒ Object
readonly
The query that this pattern was initialized with.
Instance Method Summary collapse
-
#compile ⇒ Object
Compile the query into a callable object that can be used to match against nodes.
-
#initialize(query) ⇒ Pattern
constructor
Create a new pattern with the given query.
-
#scan(root) ⇒ Object
Scan the given node and all of its children for nodes that match the pattern.
Constructor Details
#initialize(query) ⇒ Pattern
Create a new pattern with the given query. The query should be a string containing a Ruby pattern matching expression.
63 64 65 66 |
# File 'lib/prism/pattern.rb', line 63 def initialize(query) @query = query @compiled = nil end |
Instance Attribute Details
#query ⇒ Object (readonly)
The query that this pattern was initialized with.
59 60 61 |
# File 'lib/prism/pattern.rb', line 59 def query @query end |
Instance Method Details
#compile ⇒ Object
Compile the query into a callable object that can be used to match against nodes.
70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/prism/pattern.rb', line 70 def compile result = Prism.parse("case nil\nin #{query}\nend") case_match_node = result.value.statements.body.last raise CompilationError, case_match_node.inspect unless case_match_node.is_a?(CaseMatchNode) in_node = case_match_node.conditions.last raise CompilationError, in_node.inspect unless in_node.is_a?(InNode) compile_node(in_node.pattern) end |
#scan(root) ⇒ Object
Scan the given node and all of its children for nodes that match the pattern. If a block is given, it will be called with each node that matches the pattern. If no block is given, an enumerator will be returned that will yield each node that matches the pattern.
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/prism/pattern.rb', line 86 def scan(root) return to_enum(:scan, root) unless block_given? @compiled ||= compile queue = [root] while (node = queue.shift) yield node if @compiled.call(node) # steep:ignore queue.concat(node.compact_child_nodes) end end |