Spec-Zone.ru › Ruby 3.4
  1. Prism::
  2. Pattern

class Prism::Pattern

Родительский класс:
Object

Шаблон — это объект, оборачивающий выражение сопоставления с образцом 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.

Атрибуты

query [R]

Запрос, с которым был инициализирован этот шаблон.

Публичные методы класса

new (query) Показать исходный код
# File lib/prism/pattern.rb, line 64
def initialize(query)
  @query = query
  @compiled = nil
end

Создаёт новый шаблон с указанным запросом. Запрос должен быть строкой, содержащей выражение сопоставления с образцом Ruby.

Публичные методы экземпляра

compile () Показать исходный код
# 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

Компилирует запрос в вызываемый объект, который можно использовать для сопоставления с узлами.

scan (root) { |node| ... } Показать исходный код
# 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

Выполняет поиск узлов, соответствующих шаблону, в указанном узле и всех его дочерних узлах. Если передан блок, он будет вызван для каждого узла, соответствующего шаблону. Если блок не передан, будет возвращён перечислитель, который выдаёт каждый узел, соответствующий шаблону.

Приватные методы экземпляра

combine_and (left, right) Показать исходный код
# File lib/prism/pattern.rb, line 103
def combine_and(left, right)
  ->(other) { left.call(other) && right.call(other) }
end

Сокращённая запись для объединения двух proc в один, который возвращает true, если оба возвращают true.

combine_or (left, right) Показать исходный код
# File lib/prism/pattern.rb, line 109
def combine_or(left, right)
  ->(other) { left.call(other) || right.call(other) }
end

Сокращённая запись для объединения двух proc в один, который возвращает true, если хотя бы один из них возвращает true.

compile_alternation_pattern_node (node) Показать исходный код
# 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

compile_array_pattern_node (node) Показать исходный код
# 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]

compile_constant_name (node, name) Показать исходный код
# 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

Компилирует имя, связанное с константой.

compile_constant_path_node (node) Показать исходный код
# 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

in Prism::ConstantReadNode

compile_constant_read_node (node) Показать исходный код
# File lib/prism/pattern.rb, line 164
def compile_constant_read_node(node)
  compile_constant_name(node, node.name)
end

in ConstantReadNode in String

compile_error (node) Показать исходный код
# File lib/prism/pattern.rb, line 114
def compile_error(node)
  raise CompilationError, node.inspect
end

Вызывает ошибку, поскольку указанный узел не поддерживается.

compile_hash_pattern_node (node) Показать исходный код
# 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 }

compile_nil_node (node) Показать исходный код
# File lib/prism/pattern.rb, line 215
def compile_nil_node(node)
  ->(attribute) { attribute.nil? }
end

in nil

compile_node (node) Показать исходный код
# 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

Компилирует узел любого типа. Направляет обработку соответствующим методам компиляции в зависимости от типа узла.

compile_regular_expression_node (node) Показать исходный код
# 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/

compile_string_node (node) Показать исходный код
# File lib/prism/pattern.rb, line 228
def compile_string_node(node)
  string = node.unescaped

  ->(attribute) { string === attribute }
end

in “” in “foo”

compile_symbol_node (node) Показать исходный код
# 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API