class Prism::Pattern
Шаблон — это объект, оборачивающий выражение сопоставления с образцом Ruby. Обычно выражение передаётся в предложение in внутри выражения case или в выражение присваивания вправо. Например, в следующем фрагменте:
case node in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]] end
шаблоном является выражение ConstantPathNode[...].
Шаблон компилируется в объект, который отвечает на вызов call, выполняя метод compile. Сам этот метод снова обращается к Prism, чтобы разобрать выражение в дерево, а затем обходит дерево и создаёт необходимые вызываемые объекты. Например, если вы хотите скомпилировать приведённое выше выражение в вызываемый объект, выполните следующее:
callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
callable.call(node)
Гарантируется, что вызываемый объект, возвращённый методом compile, отвечает на вызов call с одним аргументом — узлом, с которым нужно выполнить сопоставление. Также гарантируется, что он отвечает на ===, а это значит, что его самого можно использовать в выражении case, например:
case node when callable end
Если запрос, переданный инициализатору, нельзя скомпилировать в допустимый сопоставитель (из-за синтаксической ошибки или использования синтаксиса, который пока не поддерживается), будет вызвано исключение Prism::Pattern::CompilationError.
Атрибуты
Запрос, с которым был инициализирован этот шаблон.
Публичные методы класса
# File lib/prism/pattern.rb, line 64 def initialize(query) @query = query @compiled = nil end
Создаёт новый шаблон с указанным запросом. Запрос должен быть строкой, содержащей выражение сопоставления с образцом Ruby.
Публичные методы экземпляра
# File lib/prism/pattern.rb, line 71
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 Компилирует запрос в вызываемый объект, который можно использовать для сопоставления с узлами.
# File lib/prism/pattern.rb, line 87
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 Выполняет поиск узлов, соответствующих шаблону, в указанном узле и всех его дочерних узлах. Если передан блок, он будет вызван для каждого узла, соответствующего шаблону. Если блок не передан, будет возвращён перечислитель, который выдаёт каждый узел, соответствующий шаблону.
Приватные методы экземпляра
# File lib/prism/pattern.rb, line 103
def combine_and(left, right)
->(other) { left.call(other) && right.call(other) }
end Сокращённая запись для объединения двух proc в один, который возвращает true, если оба возвращают true.
# File lib/prism/pattern.rb, line 109
def combine_or(left, right)
->(other) { left.call(other) || right.call(other) }
end Сокращённая запись для объединения двух proc в один, который возвращает true, если хотя бы один из них возвращает true.
# File lib/prism/pattern.rb, line 144 def compile_alternation_pattern_node(node) combine_or(compile_node(node.left), compile_node(node.right)) end
in foo | bar
# File lib/prism/pattern.rb, line 119
def compile_array_pattern_node(node)
compile_error(node) if !node.rest.nil? || node.posts.any?
constant = node.constant
compiled_constant = compile_node(constant) if constant
preprocessed = node.requireds.map { |required| compile_node(required) }
compiled_requireds = ->(other) do
deconstructed = other.deconstruct
deconstructed.length == preprocessed.length &&
preprocessed
.zip(deconstructed)
.all? { |(matcher, value)| matcher.call(value) }
end
if compiled_constant
combine_and(compiled_constant, compiled_requireds)
else
compiled_requireds
end
end in [foo, bar, baz]
# File lib/prism/pattern.rb, line 169
def compile_constant_name(node, name)
if Prism.const_defined?(name, false)
clazz = Prism.const_get(name)
->(other) { clazz === other }
elsif Object.const_defined?(name, false)
clazz = Object.const_get(name)
->(other) { clazz === other }
else
compile_error(node)
end
end Компилирует имя, связанное с константой.
# File lib/prism/pattern.rb, line 149
def compile_constant_path_node(node)
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
name = node.name
raise CompilationError, node.inspect if name.nil?
compile_constant_name(node, name)
else
compile_error(node)
end
end # File lib/prism/pattern.rb, line 164 def compile_constant_read_node(node) compile_constant_name(node, node.name) end
in ConstantReadNode in String
# File lib/prism/pattern.rb, line 114 def compile_error(node) raise CompilationError, node.inspect end
Вызывает ошибку, поскольку указанный узел не поддерживается.
# File lib/prism/pattern.rb, line 185
def compile_hash_pattern_node(node)
compile_error(node) if node.rest
compiled_constant = compile_node(node.constant) if node.constant
preprocessed =
node.elements.to_h do |element|
key = element.key
if key.is_a?(SymbolNode)
[key.unescaped.to_sym, compile_node(element.value)]
else
raise CompilationError, element.inspect
end
end
compiled_keywords = ->(other) do
deconstructed = other.deconstruct_keys(preprocessed.keys)
preprocessed.all? do |keyword, matcher|
deconstructed.key?(keyword) && matcher.call(deconstructed[keyword])
end
end
if compiled_constant
combine_and(compiled_constant, compiled_keywords)
else
compiled_keywords
end
end in InstanceVariableReadNode[name: Symbol] in { name: Symbol }
# File lib/prism/pattern.rb, line 215
def compile_nil_node(node)
->(attribute) { attribute.nil? }
end in nil
# File lib/prism/pattern.rb, line 244
def compile_node(node)
case node
when AlternationPatternNode
compile_alternation_pattern_node(node)
when ArrayPatternNode
compile_array_pattern_node(node)
when ConstantPathNode
compile_constant_path_node(node)
when ConstantReadNode
compile_constant_read_node(node)
when HashPatternNode
compile_hash_pattern_node(node)
when NilNode
compile_nil_node(node)
when RegularExpressionNode
compile_regular_expression_node(node)
when StringNode
compile_string_node(node)
when SymbolNode
compile_symbol_node(node)
else
compile_error(node)
end
end Компилирует узел любого типа. Направляет обработку соответствующим методам компиляции в зависимости от типа узла.
# File lib/prism/pattern.rb, line 220
def compile_regular_expression_node(node)
regexp = Regexp.new(node.unescaped, node.closing[1..])
->(attribute) { regexp === attribute }
end in /foo/
# File lib/prism/pattern.rb, line 228
def compile_string_node(node)
string = node.unescaped
->(attribute) { string === attribute }
end in “” in “foo”
# File lib/prism/pattern.rb, line 236
def compile_symbol_node(node)
symbol = node.unescaped.to_sym
->(attribute) { symbol === attribute }
end in :+ in :foo
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.