Class: I18n::Tasks::Data::Tree::Siblings

Inherits:
Nodes
  • Object
show all
Extended by:
SplitKey
Includes:
PluralKeys, SplitKey
Defined in:
lib/i18n/tasks/data/tree/siblings.rb

Overview

Siblings represents a subtree sharing a common parent in case of an empty parent (nil) it represents a forest siblings’ keys are unique

Constant Summary

Constants included from PluralKeys

PluralKeys::CLDR_CATEGORY_KEYS, PluralKeys::PLURAL_KEY_RE, PluralKeys::PLURAL_KEY_SUFFIXES

Instance Attribute Summary collapse

Attributes inherited from Nodes

#list

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SplitKey

last_key_part, split_key

Methods included from PluralKeys

#collapse_plural_nodes!, #depluralize_key, #plural_forms?, #plural_nodes, #plural_suffix?

Methods inherited from Nodes

#children, #derive, #inspect, #to_hash, #to_nodes

Methods included from Traversal

#breadth_first, #depth_first, #get_nodes_by_key_filter, #grep_keys, #intersect_keys, #key_names, #key_values, #keys, #leaves, #levels, #nodes, #root_key_value_data, #root_key_values, #select_keys, #select_keys!, #select_nodes, #select_nodes!, #set_each_value!

Constructor Details

#initialize(opts = {}) ⇒ Siblings

Returns a new instance of Siblings.



17
18
19
20
21
22
23
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 17

def initialize(opts = {})
  super(nodes: opts[:nodes])
  @parent = opts[:parent] || first.try(:parent)
  @list.map! { |node| node.parent == @parent ? node : node.derive(parent: @parent) }
  @key_to_node = @list.each_with_object({}) { |node, h| h[node.key] = node }
  @warn_about_add_children_to_leaf = opts.fetch(:warn_about_add_children_to_leaf, true)
end

Instance Attribute Details

#key_to_nodeObject (readonly)

Returns the value of attribute key_to_node.



15
16
17
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 15

def key_to_node
  @key_to_node
end

#parentObject (readonly)

Returns the value of attribute parent.



15
16
17
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 15

def parent
  @parent
end

Class Method Details

.build_forest(opts = {}) {|forest| ... } ⇒ Object

Yields:

  • (forest)


254
255
256
257
258
259
260
261
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 254

def build_forest(opts = {}, &block)
  opts[:nodes] ||= []
  parse_parent_opt!(opts)
  forest = Siblings.new(opts)
  yield(forest) if block
  # forest.parent.children = forest
  forest
end

.from_flat_pairs(pairs) ⇒ Object

build forest from [[Full Key, Value]]



311
312
313
314
315
316
317
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 311

def from_flat_pairs(pairs)
  Siblings.new.tap do |siblings|
    pairs.each do |full_key, value|
      siblings[full_key] = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last, value: value)
    end
  end
end

.from_key_attr(key_attrs, opts = {}, &block) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 276

def from_key_attr(key_attrs, opts = {}, &block)
  build_forest(opts) do |forest|
    key_attrs.each do |(full_key, attr)|
      fail "Invalid key #{full_key.inspect}" if full_key.end_with?('.')

      node = ::I18n::Tasks::Data::Tree::Node.new(**attr.merge(key: split_key(full_key).last))
      yield(full_key, node) if block
      forest[full_key] = node
    end
  end
end

.from_key_names(keys, opts = {}, &block) ⇒ Object



288
289
290
291
292
293
294
295
296
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 288

def from_key_names(keys, opts = {}, &block)
  build_forest(opts) do |forest|
    keys.each do |full_key|
      node = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last)
      yield(full_key, node) if block
      forest[full_key] = node
    end
  end
end

.from_key_occurrences(key_occurrences) ⇒ Siblings

Parameters:

  • key_occurrences (I18n::Tasks::Scanners::KeyOccurrences)

Returns:



265
266
267
268
269
270
271
272
273
274
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 265

def from_key_occurrences(key_occurrences)
  build_forest(warn_about_add_children_to_leaf: false) do |forest|
    key_occurrences.each do |key_occurrence|
      forest[key_occurrence.key] = ::I18n::Tasks::Data::Tree::Node.new(
        key: split_key(key_occurrence.key).last,
        data: { occurrences: key_occurrence.occurrences }
      )
    end
  end
end

.from_nested_hash(hash, opts = {}) ⇒ Object Also known as: []

build forest from nested hash, e.g. {‘es’ => { ‘common’ => { name => ‘Nombre’, ‘age’ => ‘Edad’ } } } this is the native i18n gem format



300
301
302
303
304
305
306
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 300

def from_nested_hash(hash, opts = {})
  parse_parent_opt!(opts)
  fail I18n::Tasks::CommandError, "invalid tree #{hash.inspect}" unless hash.respond_to?(:map)

  opts[:nodes] = hash.map { |key, value| Node.from_key_value key, value }
  Siblings.new(opts)
end

.nullObject



250
251
252
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 250

def null
  new
end

Instance Method Details

#append(nodes) ⇒ Object



142
143
144
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 142

def append(nodes)
  derive.append!(nodes)
end

#append!(nodes) ⇒ Object



132
133
134
135
136
137
138
139
140
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 132

def append!(nodes)
  nodes = nodes.map do |node|
    fail "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)

    key_to_node[node.key] = (node.parent == parent ? node : node.derive(parent: parent))
  end
  super(nodes)
  self
end

#attributesObject



25
26
27
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 25

def attributes
  super.merge(parent: @parent)
end

#get(full_key) ⇒ Node Also known as: []

Returns by full key.

Returns:

  • (Node)

    by full key



83
84
85
86
87
88
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 83

def get(full_key)
  first_key, rest = split_key(full_key.to_s, 2)
  node            = key_to_node[first_key]
  node = node.children.try(:get, rest) if rest && node
  node
end

#merge(nodes) ⇒ Object



155
156
157
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 155

def merge(nodes)
  derive.merge!(nodes)
end

#merge!(nodes, on_leaves_merge: nil) ⇒ Object

Parameters:

  • on_leaves_merge (Proc) (defaults to: nil)

    invoked when a leaf is merged with another leaf



147
148
149
150
151
152
153
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 147

def merge!(nodes, on_leaves_merge: nil)
  nodes = Siblings.from_nested_hash(nodes) if nodes.is_a?(Hash)
  nodes.each do |node|
    merge_node! node, on_leaves_merge: on_leaves_merge
  end
  self
end

#merge_node!(node, on_leaves_merge: nil) ⇒ Object

Parameters:

  • on_leaves_merge (Proc) (defaults to: nil)

    invoked when a leaf is merged with another leaf



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 184

def merge_node!(node, on_leaves_merge: nil) # rubocop:disable Metrics/AbcSize
  if key_to_node.key?(node.key)
    our = key_to_node[node.key]
    return if our == node

    our.value = node.value if node.leaf?
    our.data.merge!(node.data) if node.data?
    if node.children?
      if our.children
        our.children.merge!(node.children)
      else
        conditionally_warn_add_children_to_leaf(our, node.children)
        our.children = node.children
      end
    elsif on_leaves_merge
      on_leaves_merge.call(our, node)
    end
  else
    @list << (key_to_node[node.key] = node.derive(parent: parent))
    dirty!
  end
end

#mv_key!(from_pattern, to_pattern, root: false, retain: false) ⇒ old key => new key

Parameters:

  • from_pattern (Regexp)
  • to_pattern (Regexp)
  • root (Boolean) (defaults to: false)

Returns:

  • (old key => new key)


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 39

def mv_key!(from_pattern, to_pattern, root: false, retain: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
  moved_forest = Siblings.new
  moved_nodes = []
  old_key_to_new_key = {}
  nodes do |node|
    full_key = node.full_key(root: root)
    if from_pattern =~ full_key
      moved_nodes << node
      if to_pattern.empty?
        old_key_to_new_key[full_key] = nil
        next
      end
      match = $~
      new_key = to_pattern.gsub(/\\\d+/) { |m| match[m[1..].to_i] }
      old_key_to_new_key[full_key] = new_key
      moved_forest.merge!(Siblings.new.tap do |forest|
        forest[[(node.root.try(:key) unless root), new_key].compact.join('.')] =
          node.derive(key: split_key(new_key).last)
      end)
    end
  end
  # Adjust references
  # TODO: support nested references better
  nodes do |node|
    next unless node.reference?

    old_target = [(node.root.key if root), node.value.to_s].compact.join('.')
    new_target = old_key_to_new_key[old_target]
    if new_target
      new_target = new_target.sub(/\A[^.]*\./, '') if root
      node.value = new_target.to_sym
    end
  end
  remove_nodes_and_emptied_ancestors!(moved_nodes) unless retain
  merge! moved_forest
  old_key_to_new_key
end

#remove!(node) ⇒ Object

methods below change state



126
127
128
129
130
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 126

def remove!(node)
  super
  key_to_node.delete(node.key)
  self
end

#remove_nodes_and_emptied_ancestors(nodes) ⇒ Object

Parameters:

  • nodes (Enumerable)

    Modified in-place.



208
209
210
211
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 208

def remove_nodes_and_emptied_ancestors(nodes)
  add_ancestors_that_only_contain_nodes! nodes
  select_nodes { |node| !nodes.include?(node) }
end

#remove_nodes_and_emptied_ancestors!(nodes) ⇒ Object

Parameters:

  • nodes (Enumerable)

    Modified in-place.



214
215
216
217
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 214

def remove_nodes_and_emptied_ancestors!(nodes)
  add_ancestors_that_only_contain_nodes! nodes
  select_nodes! { |node| !nodes.include?(node) }
end

#rename_key(key, new_key) ⇒ Object



29
30
31
32
33
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 29

def rename_key(key, new_key)
  node = key_to_node.delete(key)
  replace_node! node, node.derive(key: new_key)
  self
end

#replace_node!(node, new_node) ⇒ Object



77
78
79
80
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 77

def replace_node!(node, new_node)
  @list[@list.index(node)]  = new_node
  key_to_node[new_node.key] = new_node
end

#set(full_key, node) ⇒ Object Also known as: []=

add or replace node by full key



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 93

def set(full_key, node)
  fail 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)

  key_part, rest = split_key(full_key, 2)
  child          = key_to_node[key_part]

  if rest
    unless child
      child = Node.new(
        key: key_part,
        parent: parent,
        children: [],
        warn_about_add_children_to_leaf: @warn_about_add_children_to_leaf
      )
      append! child
    end
    unless child.children
      conditionally_warn_add_children_to_leaf(child, [])
      child.children = []
    end
    child.children.set rest, node
  else
    remove! child if child
    append! node
  end
  dirty!
  node
end

#set_root_key!(new_key, data = nil) ⇒ Object



175
176
177
178
179
180
181
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 175

def set_root_key!(new_key, data = nil)
  return self if empty?

  rename_key first.key, new_key
  leaves { |node| node.data.merge! data } if data
  self
end

#subtract_by_key(other) ⇒ Object



167
168
169
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 167

def subtract_by_key(other)
  subtract_keys other.key_names(root: true)
end

#subtract_by_key!(other) ⇒ Object



171
172
173
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 171

def subtract_by_key!(other)
  subtract_keys! other.key_names(root: true)
end

#subtract_keys(keys) ⇒ Object



159
160
161
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 159

def subtract_keys(keys)
  remove_nodes_and_emptied_ancestors(find_nodes(keys))
end

#subtract_keys!(keys) ⇒ Object



163
164
165
# File 'lib/i18n/tasks/data/tree/siblings.rb', line 163

def subtract_keys!(keys)
  remove_nodes_and_emptied_ancestors!(find_nodes(keys))
end