класс Prism::Pattern
Шаблон — это объект, который оборачивает выражение соответствия шаблонам Ruby. Выражение обычно передаётся в оператор «in» внутри выражения `case` или в оператор присваивания справа. Например, в следующем фрагменте:
case node in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]] end
шаблоном является ConstantPathNode[...] выражение.
Шаблон компилируется в объект, который отвечает на вызов, выполняя метод compile. Этот метод сам вызовет Prism для разбора выражения в дерево, а затем пройдёт по дереву, чтобы сгенерировать необходимые вызываемые объекты. Например, если вы хотите скомпилировать вышеприведённое выражение в вызываемый объект, то вам нужно:
callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
callable.call(node)
Вызываемый объект, возвращаемый методом compile, гарантированно отвечает на вызов с одним аргументом — узлом для сопоставления. Он также гарантированно отвечает на ===, что означает, что сам он может использоваться в выражении `case`, как в этом примере:
case node when callable end
Если запрос, переданный в инициализатор, не может быть скомпилирован в корректный согласующий объект (из-за синтаксической ошибки или использования синтаксиса, который мы ещё не поддерживаем), то будет поднято исключение Prism::Pattern::CompilationError.
Атрибуты
Запрос, с которым был инициализирован этот шаблон.
Открытые методы класса
# File lib/prism/pattern.rb, line 63 def initialize(query) @query = query @compiled = nil end
Создаёт новый шаблон с заданным запросом. Запрос должен быть строкой, содержащей выражение соответствия шаблонам Ruby.
Открытые методы экземпляра
# File lib/prism/pattern.rb, line 70
def compile
result = Prism.parse("case nil\nin #{query}\nend")
compile_node(result.value.statements.body.last.conditions.last.pattern)
end Компилирует запрос в вызываемый объект, который может использоваться для сопоставления с узлами.
# File lib/prism/pattern.rb, line 79
def scan(root)
return to_enum(__method__, root) unless block_given?
@compiled ||= compile
queue = [root]
while (node = queue.shift)
yield node if @compiled.call(node)
queue.concat(node.compact_child_nodes)
end
end Просматривает заданный узел и все его дочерние узлы на предмет узлов, соответствующих шаблону. Если задан блок, он будет вызываться с каждым узлом, соответствующим шаблону. Если блок не задан, будет возвращён перечислитель, который будет выводить каждый узел, соответствующий шаблону.
Методы частного экземпляра
# File lib/prism/pattern.rb, line 95
def combine_and(left, right)
->(other) { left.call(other) && right.call(other) }
end Сокращённая запись для объединения двух просов в один, возвращающий true, если оба возвращают true.
# File lib/prism/pattern.rb, line 101
def combine_or(left, right)
->(other) { left.call(other) || right.call(other) }
end Сокращённая запись для объединения двух просов в один, возвращающий true, если хотя бы один возвращает true.
# File lib/prism/pattern.rb, line 136 def compile_alternation_pattern_node(node) combine_or(compile_node(node.left), compile_node(node.right)) end
в foo | bar
# File lib/prism/pattern.rb, line 111
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 в [foo, bar, baz]
# File lib/prism/pattern.rb, line 141
def compile_constant_path_node(node)
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
compile_node(node.child)
else
compile_error(node)
end
end # File lib/prism/pattern.rb, line 153
def compile_constant_read_node(node)
value = node.slice
if Prism.const_defined?(value, false)
clazz = Prism.const_get(value)
->(other) { clazz === other }
elsif Object.const_defined?(value, false)
clazz = Object.const_get(value)
->(other) { clazz === other }
else
compile_error(node)
end
end # File lib/prism/pattern.rb, line 106 def compile_error(node) raise CompilationError, node.inspect end
Вызывает ошибку, так как указанный узел не поддерживается.
# File lib/prism/pattern.rb, line 171
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|
[element.key.unescaped.to_sym, compile_node(element.value)]
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 в InstanceVariableReadNode[name: Symbol] в { name: Symbol }
# File lib/prism/pattern.rb, line 196
def compile_nil_node(node)
->(attribute) { attribute.nil? }
end в nil
# File lib/prism/pattern.rb, line 225
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 201
def compile_regular_expression_node(node)
regexp = Regexp.new(node.unescaped, node.closing[1..])
->(attribute) { regexp === attribute }
end в /foo/
# File lib/prism/pattern.rb, line 209
def compile_string_node(node)
string = node.unescaped
->(attribute) { string === attribute }
end в “” в “foo”
# File lib/prism/pattern.rb, line 217
def compile_symbol_node(node)
symbol = node.unescaped.to_sym
->(attribute) { symbol === attribute }
end в :+ в :foo
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.