module I18n::Processes::Data::Tree::Traversal

Any Enumerable that yields nodes can mix in this module

Public Instance Methods

breadth_first(&visitor) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 36
def breadth_first(&visitor)
  return to_enum(:breadth_first) unless visitor
  levels do |nodes|
    nodes.each { |node| visitor.yield(node) }
  end
  self
end
depth_first(&visitor) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 44
def depth_first(&visitor)
  return to_enum(:depth_first) unless visitor
  each do |node|
    visitor.yield node
    next unless node.children?
    node.children.each do |child|
      child.depth_first(&visitor)
    end
  end
  self
end
get_nodes_by_key_filter(root: false, &block) click to toggle source

@return [Set<I18n::Processes::Data::Tree::Node>]

# File lib/i18n/processes/data/tree/traversal.rb, line 134
def get_nodes_by_key_filter(root: false, &block)
  matches = Set.new
  keys(root: root) do |full_key, node|
    if block.yield(full_key, node)
      node.walk_to_root do |p|
        break unless matches.add?(p)
      end
    end
  end
  matches
end
grep_keys(match, opts = {}) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 158
def grep_keys(match, opts = {})
  select_keys(opts) do |full_key, _node|
    match === full_key # rubocop:disable Style/CaseEquality
  end
end
intersect_keys(other_tree, key_opts = {}) { |key, node, other_node| ... } click to toggle source

@return [Siblings]

# File lib/i18n/processes/data/tree/traversal.rb, line 147
def intersect_keys(other_tree, key_opts = {}, &block)
  if block
    select_keys(key_opts) do |key, node|
      other_node = other_tree[key]
      other_node && yield(key, node, other_node)
    end
  else
    select_keys(key_opts) { |key, _node| other_tree[key] }
  end
end
key_names(opts = {}) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 63
def key_names(opts = {})
  opts[:root] = false unless opts.key?(:root)
  keys(opts).map { |key, _node| key }
end
key_values(opts = {}) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 68
def key_values(opts = {})
  opts[:root] = false unless opts.key?(:root)
  keys(opts).map { |key, node| [key, node.value] }
end
keys(root: false, &visitor) click to toggle source

@option root include root in full key

# File lib/i18n/processes/data/tree/traversal.rb, line 57
def keys(root: false, &visitor)
  return to_enum(:keys, root: root) unless visitor
  leaves { |node| visitor.yield(node.full_key(root: root), node) }
  self
end
leaves(&visitor) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 13
def leaves(&visitor)
  return to_enum(:leaves) unless visitor
  nodes do |node|
    visitor.yield(node) if node.leaf?
  end
  self
end
levels(&block) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 21
def levels(&block)
  return to_enum(:levels) unless block
  nodes = to_nodes
  unless nodes.empty?
    block.yield nodes
    if nodes.size == 1
      node = first
      node.children.levels(&block) if node.children?
    else
      I18n::Processes::Data::Tree::Nodes.new(nodes: nodes.children).levels(&block)
    end
  end
  self
end
nodes(&block) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 9
def nodes(&block)
  depth_first(&block)
end
root_key_value_data(sort = false) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 79
def root_key_value_data(sort = false)
  result = keys(root: false).map { |key, node| [node.root.key, key, node.value, node.data] }
  result.sort! { |a, b| a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] } if sort
  result
end
root_key_values(sort = false) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 73
def root_key_values(sort = false)
  result = keys(root: false).map { |key, node| [node.root.key, key, node.value] }
  result.sort! { |a, b| a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] } if sort
  result
end
select_keys(root: false, &block) click to toggle source

@return [Siblings]

# File lib/i18n/processes/data/tree/traversal.rb, line 118
def select_keys(root: false, &block)
  matches = get_nodes_by_key_filter(root: root, &block)
  select_nodes do |node|
    matches.include?(node)
  end
end
select_keys!(root: false, &block) click to toggle source

@return [Siblings]

# File lib/i18n/processes/data/tree/traversal.rb, line 126
def select_keys!(root: false, &block)
  matches = get_nodes_by_key_filter(root: root, &block)
  select_nodes! do |node|
    matches.include?(node)
  end
end
select_nodes(&block) click to toggle source

Select the nodes for which the block returns true. Pre-order traversal. @return [Siblings] a new tree

# File lib/i18n/processes/data/tree/traversal.rb, line 89
def select_nodes(&block)
  tree = Siblings.new
  each do |node|
    next unless block.yield(node)
    tree.append! node.derive(
      parent: tree.parent,
      children: (node.children.select_nodes(&block).to_a if node.children)
    )
  end
  tree
end
select_nodes!(&block) click to toggle source

Select the nodes for which the block returns true. Pre-order traversal. @return [Siblings] self

# File lib/i18n/processes/data/tree/traversal.rb, line 103
def select_nodes!(&block)
  to_remove = []
  each do |node|
    if block.yield(node)
      node.children.select_nodes!(&block) if node.children
    else
      # removing during each is unsafe
      to_remove << node
    end
  end
  to_remove.each { |node| remove! node }
  self
end
set_each_value!(val_pattern, key_pattern = nil, &value_proc) click to toggle source
# File lib/i18n/processes/data/tree/traversal.rb, line 164
def set_each_value!(val_pattern, key_pattern = nil, &value_proc)
  value_proc ||= proc do |node|
    node_value = node.value
    next node_value if node.reference?
    human_key = ActiveSupport::Inflector.humanize(node.key.to_s)
    full_key = node.full_key
    default = (node.data[:occurrences] || []).detect { |o| o.default_arg.presence }.try(:default_arg)
    StringInterpolation.interpolate_soft(
      val_pattern,
      value: node_value,
      human_key: human_key,
      key: full_key,
      default: default,
      value_or_human_key: node_value.presence || human_key,
      value_or_default_or_human_key: node_value.presence || default || human_key
    )
  end
  pattern_re = I18n::Processes::KeyPatternMatching.compile_key_pattern(key_pattern) if key_pattern.present?
  keys.each do |key, node|
    next if pattern_re && key !~ pattern_re
    node.value = value_proc.call(node)
  end
  self
end