Spec-Zone.ru › Ruby 3.3

класс 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.

Атрибуты

query[R]

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

Открытые методы класса

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

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

Открытые методы экземпляра

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

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

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

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

Методы частного экземпляра

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

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

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

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

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

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

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

в Prism::ConstantReadNode

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

в ConstantReadNode в String

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

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

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

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

в nil

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

Компилирует любой тип узла. Перенаправляет вызов на отдельные методы компиляции в зависимости от типа узла.

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

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

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

в “” в “foo”

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

Spec-Zone.ru

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