i18n-tasks 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +2 -1
  4. data/bin/i18n-tasks +1 -0
  5. data/config/locales/en.yml +15 -9
  6. data/config/locales/ru.yml +80 -74
  7. data/i18n-tasks.gemspec +9 -8
  8. data/lib/i18n/tasks.rb +2 -5
  9. data/lib/i18n/tasks/cli.rb +14 -18
  10. data/lib/i18n/tasks/command/commander.rb +2 -3
  11. data/lib/i18n/tasks/command/commands/health.rb +1 -1
  12. data/lib/i18n/tasks/command/commands/meta.rb +2 -2
  13. data/lib/i18n/tasks/command/commands/missing.rb +17 -19
  14. data/lib/i18n/tasks/command/commands/tree.rb +3 -3
  15. data/lib/i18n/tasks/command/commands/usages.rb +6 -5
  16. data/lib/i18n/tasks/command/commands/xlsx.rb +1 -1
  17. data/lib/i18n/tasks/command/dsl.rb +1 -2
  18. data/lib/i18n/tasks/command/option_parsers/enum.rb +6 -6
  19. data/lib/i18n/tasks/command/option_parsers/locale.rb +3 -1
  20. data/lib/i18n/tasks/command/options/data.rb +22 -21
  21. data/lib/i18n/tasks/command_error.rb +1 -3
  22. data/lib/i18n/tasks/configuration.rb +37 -27
  23. data/lib/i18n/tasks/console_context.rb +3 -2
  24. data/lib/i18n/tasks/data.rb +5 -4
  25. data/lib/i18n/tasks/data/adapter/json_adapter.rb +13 -12
  26. data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +13 -14
  27. data/lib/i18n/tasks/data/file_formats.rb +15 -10
  28. data/lib/i18n/tasks/data/file_system_base.rb +18 -22
  29. data/lib/i18n/tasks/data/router/conservative_router.rb +3 -6
  30. data/lib/i18n/tasks/data/router/pattern_router.rb +4 -5
  31. data/lib/i18n/tasks/data/tree/node.rb +20 -19
  32. data/lib/i18n/tasks/data/tree/nodes.rb +4 -3
  33. data/lib/i18n/tasks/data/tree/siblings.rb +36 -29
  34. data/lib/i18n/tasks/data/tree/traversal.rb +32 -35
  35. data/lib/i18n/tasks/google_translation.rb +22 -25
  36. data/lib/i18n/tasks/html_keys.rb +2 -0
  37. data/lib/i18n/tasks/ignore_keys.rb +3 -2
  38. data/lib/i18n/tasks/key_pattern_matching.rb +9 -8
  39. data/lib/i18n/tasks/locale_list.rb +4 -6
  40. data/lib/i18n/tasks/locale_pathname.rb +8 -8
  41. data/lib/i18n/tasks/logging.rb +3 -3
  42. data/lib/i18n/tasks/missing_keys.rb +29 -31
  43. data/lib/i18n/tasks/plural_keys.rb +6 -7
  44. data/lib/i18n/tasks/references.rb +72 -41
  45. data/lib/i18n/tasks/reports/base.rb +8 -7
  46. data/lib/i18n/tasks/reports/spreadsheet.rb +15 -16
  47. data/lib/i18n/tasks/reports/terminal.rb +32 -32
  48. data/lib/i18n/tasks/scanners/file_scanner.rb +6 -5
  49. data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +1 -2
  50. data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +0 -1
  51. data/lib/i18n/tasks/scanners/files/file_finder.rb +12 -15
  52. data/lib/i18n/tasks/scanners/files/file_reader.rb +0 -1
  53. data/lib/i18n/tasks/scanners/occurrence_from_position.rb +8 -7
  54. data/lib/i18n/tasks/scanners/pattern_mapper.rb +2 -2
  55. data/lib/i18n/tasks/scanners/pattern_scanner.rb +9 -7
  56. data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +1 -2
  57. data/lib/i18n/tasks/scanners/relative_keys.rb +11 -11
  58. data/lib/i18n/tasks/scanners/results/key_occurrences.rb +3 -4
  59. data/lib/i18n/tasks/scanners/results/occurrence.rb +8 -7
  60. data/lib/i18n/tasks/scanners/ruby_ast_call_finder.rb +2 -2
  61. data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +39 -31
  62. data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +9 -3
  63. data/lib/i18n/tasks/split_key.rb +5 -6
  64. data/lib/i18n/tasks/stats.rb +10 -8
  65. data/lib/i18n/tasks/string_interpolation.rb +1 -1
  66. data/lib/i18n/tasks/unused_keys.rb +2 -2
  67. data/lib/i18n/tasks/used_keys.rb +47 -43
  68. data/lib/i18n/tasks/version.rb +1 -1
  69. data/templates/rspec/i18n_spec.rb +2 -2
  70. metadata +30 -3
@@ -5,21 +5,22 @@ module I18n::Tasks
5
5
  module Data
6
6
  module Adapter
7
7
  module JsonAdapter
8
- extend self
8
+ class << self
9
+ # @return [Hash] locale tree
10
+ def parse(str, opts)
11
+ JSON.parse(str, parse_opts(opts))
12
+ end
9
13
 
10
- # @return [Hash] locale tree
11
- def parse(str, opts)
12
- JSON.parse(str, parse_opts(opts))
13
- end
14
+ # @return [String]
15
+ def dump(tree, opts)
16
+ JSON.generate(tree, parse_opts(opts))
17
+ end
14
18
 
15
- # @return [String]
16
- def dump(tree, opts)
17
- JSON.generate(tree, parse_opts(opts))
18
- end
19
+ private
19
20
 
20
- private
21
- def parse_opts(opts)
22
- opts.try(:symbolize_keys) || {}
21
+ def parse_opts(opts)
22
+ opts.try(:symbolize_keys) || {}
23
+ end
23
24
  end
24
25
  end
25
26
  end
@@ -4,23 +4,22 @@ module I18n::Tasks
4
4
  module Data
5
5
  module Adapter
6
6
  module YamlAdapter
7
- extend self
8
-
9
- # @return [Hash] locale tree
10
- def parse(str, options)
11
- if YAML.method(:load).arity.abs == 2
12
- YAML.load(str, options || {})
13
- else
14
- # older jruby and rbx 2.2.7 do not accept options
15
- YAML.load(str)
7
+ class << self
8
+ # @return [Hash] locale tree
9
+ def parse(str, options)
10
+ if YAML.method(:load).arity.abs == 2
11
+ YAML.load(str, options || {})
12
+ else
13
+ # older jruby and rbx 2.2.7 do not accept options
14
+ YAML.load(str)
15
+ end
16
16
  end
17
- end
18
17
 
19
- # @return [String]
20
- def dump(tree, options)
21
- tree.to_yaml(options || {})
18
+ # @return [String]
19
+ def dump(tree, options)
20
+ tree.to_yaml(options || {})
21
+ end
22
22
  end
23
-
24
23
  end
25
24
  end
26
25
  end
@@ -19,8 +19,8 @@ module I18n
19
19
 
20
20
  def adapter_op(op, format, tree, config)
21
21
  self.class.adapter_by_name(format).send(op, tree, config)
22
- rescue Exception => e
23
- raise CommandError.new("#{format} #{op} error: #{e.message}")
22
+ rescue Exception => e # rubocop:disable Lint/RescueException
23
+ raise CommandError, "#{format} #{op} error: #{e.message}"
24
24
  end
25
25
 
26
26
  protected
@@ -43,10 +43,10 @@ module I18n
43
43
  content = adapter_dump(hash, adapter)
44
44
  # Ignore unchanged data
45
45
  return if File.file?(path) &&
46
- # Comparing hashes for equality directly would ignore key order.
47
- # Round-trip through the adapter and compare the strings instead:
48
- content == adapter_dump(load_file(path), adapter)
49
- ::FileUtils.mkpath(File.dirname path)
46
+ # Comparing hashes for equality directly would ignore key order.
47
+ # Round-trip through the adapter and compare the strings instead:
48
+ content == adapter_dump(load_file(path), adapter)
49
+ ::FileUtils.mkpath(File.dirname(path))
50
50
  ::File.open(path, 'w') { |f| f.write content }
51
51
  end
52
52
 
@@ -58,9 +58,11 @@ module I18n
58
58
  end
59
59
 
60
60
  def adapter_name_for_path(path)
61
- @fn_patterns.detect { |(_name, pattern, _adapter)|
61
+ @fn_patterns.detect do |(_name, pattern, _adapter)|
62
62
  ::File.fnmatch(pattern, path)
63
- }.try(:first) or raise CommandError.new("Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}")
63
+ end.try(:first) || fail(
64
+ CommandError, "Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}"
65
+ )
64
66
  end
65
67
 
66
68
  def adapter_names
@@ -69,9 +71,12 @@ module I18n
69
71
 
70
72
  def adapter_by_name(name)
71
73
  name = name.to_s
72
- @fn_patterns.detect { |(adapter_name, _pattern, _adapter)|
74
+ @fn_patterns.detect do |(adapter_name, _pattern, _adapter)|
73
75
  adapter_name.to_s == name
74
- }.try(:last) or raise CommandError.new("Adapter with name #{name.inspect} not found. Registered adapters: #{@fn_patterns.inspect}")
76
+ end.try(:last) || fail(
77
+ CommandError,
78
+ "Adapter with name #{name.inspect} not found. Registered adapters: #{@fn_patterns.inspect}"
79
+ )
75
80
  end
76
81
  end
77
82
  end
@@ -15,9 +15,9 @@ module I18n::Tasks
15
15
  attr_writer :locales
16
16
 
17
17
  DEFAULTS = {
18
- read: ['config/locales/%{locale}.yml'],
19
- write: ['config/locales/%{locale}.yml']
20
- }
18
+ read: ['config/locales/%{locale}.yml'],
19
+ write: ['config/locales/%{locale}.yml']
20
+ }.freeze
21
21
 
22
22
  def initialize(config = {})
23
23
  self.config = config.except(:base_locale, :locales)
@@ -33,10 +33,10 @@ module I18n::Tasks
33
33
 
34
34
  # get locale tree
35
35
  def get(locale)
36
- locale = locale.to_s
36
+ locale = locale.to_s
37
37
  @trees ||= {}
38
38
  @trees[locale] ||= Tree::Siblings[locale => {}].merge!(
39
- read_locale locale
39
+ read_locale(locale)
40
40
  )
41
41
  end
42
42
 
@@ -57,12 +57,12 @@ module I18n::Tasks
57
57
  end
58
58
 
59
59
  def merge!(forest)
60
- forest.inject(Tree::Siblings.new) { |result, root|
60
+ forest.inject(Tree::Siblings.new) do |result, root|
61
61
  locale = root.key
62
62
  merged = get(locale).merge(root)
63
63
  set locale, merged
64
64
  result.merge! merged
65
- }
65
+ end
66
66
  end
67
67
 
68
68
  def remove_by_key!(forest)
@@ -88,17 +88,13 @@ module I18n::Tasks
88
88
  @available_locales ||= begin
89
89
  locales = Set.new
90
90
  Array(config[:read]).map do |pattern|
91
- [pattern, Dir.glob(pattern % {locale: '*'})] if pattern.include?('%{locale}'.freeze)
91
+ [pattern, Dir.glob(pattern % { locale: '*' })] if pattern.include?('%{locale}')
92
92
  end.compact.each do |pattern, paths|
93
- p = pattern.gsub('\\'.freeze, '\\\\'.freeze).gsub('/'.freeze, '\/'.freeze).gsub('.'.freeze, '\.'.freeze)
94
- p = p.gsub(/(\*+)/) {
95
- $1 == '**'.freeze ? '.*'.freeze : '[^/]*?'.freeze
96
- }.gsub('%{locale}'.freeze, '([^/.]+)'.freeze)
93
+ p = pattern.gsub('\\', '\\\\').gsub('/', '\/').gsub('.', '\.')
94
+ p = p.gsub(/(\*+)/) { Regexp.last_match(1) == '**' ? '.*' : '[^/]*?' }.gsub('%{locale}', '([^/.]+)')
97
95
  re = /\A#{p}\z/
98
96
  paths.each do |path|
99
- if re =~ path
100
- locales << $1
101
- end
97
+ locales << Regexp.last_match(1) if re =~ path
102
98
  end
103
99
  end
104
100
  locales
@@ -112,7 +108,7 @@ module I18n::Tasks
112
108
  end
113
109
 
114
110
  def config=(config)
115
- @config = DEFAULTS.deep_merge((config || {}).reject { |k, v| v.nil? })
111
+ @config = DEFAULTS.deep_merge((config || {}).reject { |_k, v| v.nil? })
116
112
  reload
117
113
  end
118
114
 
@@ -124,16 +120,16 @@ module I18n::Tasks
124
120
  self.router = router_was
125
121
  end
126
122
 
127
-
128
123
  ROUTER_NAME_ALIASES = {
129
- 'conservative_router' => 'I18n::Tasks::Data::Router::ConservativeRouter',
130
- 'pattern_router' => 'I18n::Tasks::Data::Router::PatternRouter'
131
- }
124
+ 'conservative_router' => 'I18n::Tasks::Data::Router::ConservativeRouter',
125
+ 'pattern_router' => 'I18n::Tasks::Data::Router::PatternRouter'
126
+ }.freeze
132
127
  def router
133
128
  @router ||= begin
134
129
  name = @config[:router].presence || 'conservative_router'
135
130
  name = ROUTER_NAME_ALIASES[name] || name
136
- ActiveSupport::Inflector.constantize(name).new(self, @config.merge(base_locale: base_locale, locales: locales))
131
+ router_class = ActiveSupport::Inflector.constantize(name)
132
+ router_class.new(self, @config.merge(base_locale: base_locale, locales: locales))
137
133
  end
138
134
  end
139
135
  attr_writer :router
@@ -142,7 +138,7 @@ module I18n::Tasks
142
138
 
143
139
  def read_locale(locale)
144
140
  Array(config[:read]).map do |path|
145
- Dir.glob path % {locale: locale}
141
+ Dir.glob path % { locale: locale }
146
142
  end.reduce(:+).map do |path|
147
143
  [path.freeze, load_file(path) || {}]
148
144
  end.map do |path, data|
@@ -20,9 +20,7 @@ module I18n::Tasks
20
20
  path = key_path(locale, key)
21
21
  # infer from another locale
22
22
  unless path
23
- inferred_from = (locales - [locale]).detect { |loc|
24
- path = key_path(loc, key)
25
- }
23
+ inferred_from = (locales - [locale]).detect { |loc| path = key_path(loc, key) }
26
24
  path = LocalePathname.replace_locale(path, inferred_from, locale) if inferred_from
27
25
  end
28
26
  key_with_locale = "#{locale}.#{key}"
@@ -36,9 +34,9 @@ module I18n::Tasks
36
34
  if not_found.present?
37
35
  # fall back to pattern router
38
36
  not_found_tree = forest.select_keys(root: true) { |key, _| not_found.include?(key) }
39
- super(locale, not_found_tree) { |path, tree|
37
+ super(locale, not_found_tree) do |path, tree|
40
38
  out[path] += tree.key_names(root: true)
41
- }
39
+ end
42
40
  end
43
41
 
44
42
  out.each do |dest, keys|
@@ -60,4 +58,3 @@ module I18n::Tasks
60
58
  end
61
59
  end
62
60
  end
63
-
@@ -32,11 +32,11 @@ module I18n::Tasks
32
32
  pattern, path = routes.detect { |route| route[0] =~ key }
33
33
  if pattern
34
34
  key_match = $~
35
- path = path % {locale: locale}
35
+ path = path % { locale: locale }
36
36
  path.gsub!(/\\\d+/) { |m| key_match[m[1..-1].to_i] }
37
37
  (out[path] ||= Set.new) << "#{locale}.#{key}"
38
38
  else
39
- raise CommandError.new("Cannot route key #{key}. Routes are #{@routes_config.inspect}")
39
+ fail CommandError, "Cannot route key #{key}. Routes are #{@routes_config.inspect}"
40
40
  end
41
41
  end
42
42
  out.each do |dest, keys|
@@ -48,11 +48,10 @@ module I18n::Tasks
48
48
  private
49
49
 
50
50
  def compile_routes(routes)
51
- routes.map { |x| x.is_a?(String) ? ['*', x] : x }.map { |x|
51
+ routes.map { |x| x.is_a?(String) ? ['*', x] : x }.map do |x|
52
52
  [compile_key_pattern(x[0]), x[1]]
53
- }
53
+ end
54
54
  end
55
55
  end
56
56
  end
57
57
  end
58
-
@@ -3,7 +3,7 @@
3
3
  require 'i18n/tasks/data/tree/traversal'
4
4
  require 'i18n/tasks/data/tree/siblings'
5
5
  module I18n::Tasks::Data::Tree
6
- class Node
6
+ class Node # rubocop:disable Metrics/ClassLength
7
7
  include Enumerable
8
8
  include Traversal
9
9
 
@@ -11,16 +11,16 @@ module I18n::Tasks::Data::Tree
11
11
  attr_reader :key, :children, :parent
12
12
 
13
13
  def initialize(key:, value: nil, data: nil, parent: nil, children: nil)
14
- @key = key
14
+ @key = key
15
15
  @key = @key.to_s.freeze if @key
16
- @value = value
17
- @data = data
18
- @parent = parent
16
+ @value = value
17
+ @data = data
18
+ @parent = parent
19
19
  self.children = (children if children)
20
20
  end
21
21
 
22
22
  def attributes
23
- {key: @key, value: @value, data: @data.try(:clone), parent: @parent, children: @children}
23
+ { key: @key, value: @value, data: @data.try(:clone), parent: @parent, children: @children }
24
24
  end
25
25
 
26
26
  def derive(new_attr = {})
@@ -29,12 +29,12 @@ module I18n::Tasks::Data::Tree
29
29
 
30
30
  def children=(children)
31
31
  @children = case children
32
- when Siblings
33
- children.parent == self ? children : children.derive(parent: self)
34
- when NilClass
35
- nil
36
- else
37
- Siblings.new(nodes: children, parent: self)
32
+ when Siblings
33
+ children.parent == self ? children : children.derive(parent: self)
34
+ when NilClass
35
+ nil
36
+ else
37
+ Siblings.new(nodes: children, parent: self)
38
38
  end
39
39
  dirty!
40
40
  end
@@ -59,7 +59,7 @@ module I18n::Tasks::Data::Tree
59
59
  end
60
60
 
61
61
  def parent?
62
- !!parent
62
+ !parent.nil?
63
63
  end
64
64
 
65
65
  def children?
@@ -99,8 +99,8 @@ module I18n::Tasks::Data::Tree
99
99
  end
100
100
 
101
101
  def full_key(opts = {})
102
- root = opts.key?(:root) ? opts[:root] : true
103
- @full_key ||= {}
102
+ root = opts.key?(:root) ? opts[:root] : true
103
+ @full_key ||= {}
104
104
  @full_key[root] ||= "#{"#{parent.full_key(root: root)}." if parent? && (root || parent.parent?)}#{key}"
105
105
  end
106
106
 
@@ -128,6 +128,7 @@ module I18n::Tasks::Data::Tree
128
128
  dirty!
129
129
  node
130
130
  end
131
+
131
132
  alias []= set
132
133
 
133
134
  def to_nodes
@@ -144,9 +145,9 @@ module I18n::Tasks::Data::Tree
144
145
  if key.nil?
145
146
  children_hash
146
147
  elsif leaf?
147
- {key => value}
148
+ { key => value }
148
149
  else
149
- {key => children_hash}
150
+ { key => children_hash }
150
151
  end
151
152
  end
152
153
  end
@@ -167,7 +168,7 @@ module I18n::Tasks::Data::Tree
167
168
 
168
169
  def format_value_for_inspect(value)
169
170
  if value.is_a?(Symbol)
170
- "#{Term::ANSIColor.bold(Term::ANSIColor.yellow '⮕ ')}#{Term::ANSIColor.yellow value.to_s}"
171
+ "#{Term::ANSIColor.bold(Term::ANSIColor.yellow('⮕ '))}#{Term::ANSIColor.yellow value.to_s}"
171
172
  else
172
173
  Term::ANSIColor.cyan(value.to_s)
173
174
  end
@@ -176,7 +177,7 @@ module I18n::Tasks::Data::Tree
176
177
  protected
177
178
 
178
179
  def dirty!
179
- @hash = nil
180
+ @hash = nil
180
181
  @full_key = nil
181
182
  end
182
183
 
@@ -20,7 +20,7 @@ module I18n::Tasks::Data::Tree
20
20
  end
21
21
 
22
22
  def attributes
23
- {nodes: @list}
23
+ { nodes: @list }
24
24
  end
25
25
 
26
26
  def derive(new_attr = {})
@@ -33,7 +33,7 @@ module I18n::Tasks::Data::Tree
33
33
  def to_hash(sort = false)
34
34
  (@hash ||= {})[sort] ||= begin
35
35
  if sort
36
- self.sort { |a, b| a.key <=> b.key }
36
+ sort_by(&:key)
37
37
  else
38
38
  self
39
39
  end.map { |node| node.to_hash(sort) }.reduce({}, :deep_merge!)
@@ -54,7 +54,7 @@ module I18n::Tasks::Data::Tree
54
54
  # methods below change state
55
55
 
56
56
  def remove!(node)
57
- @list.delete(node) or raise "#{node.full_key} not found in #{self.inspect}"
57
+ @list.delete(node) || fail("#{node.full_key} not found in #{inspect}")
58
58
  dirty!
59
59
  self
60
60
  end
@@ -88,6 +88,7 @@ module I18n::Tasks::Data::Tree
88
88
  alias children? any?
89
89
 
90
90
  protected
91
+
91
92
  def dirty!
92
93
  @hash = nil
93
94
  end
@@ -8,7 +8,7 @@ module I18n::Tasks::Data::Tree
8
8
  # Siblings represents a subtree sharing a common parent
9
9
  # in case of an empty parent (nil) it represents a forest
10
10
  # siblings' keys are unique
11
- class Siblings < Nodes
11
+ class Siblings < Nodes # rubocop:disable Metrics/ClassLength
12
12
  include ::I18n::Tasks::SplitKey
13
13
 
14
14
  attr_reader :parent, :key_to_node
@@ -17,7 +17,7 @@ module I18n::Tasks::Data::Tree
17
17
  super(nodes: opts[:nodes])
18
18
  @parent = opts[:parent] || first.try(:parent)
19
19
  @list.map! { |node| node.parent == @parent ? node : node.derive(parent: @parent) }
20
- @key_to_node = @list.inject({}) { |h, node| h[node.key] = node; h }
20
+ @key_to_node = @list.each_with_object({}) { |node, h| h[node.key] = node }
21
21
  end
22
22
 
23
23
  def attributes
@@ -53,9 +53,7 @@ module I18n::Tasks::Data::Tree
53
53
  def get(full_key)
54
54
  first_key, rest = split_key(full_key.to_s, 2)
55
55
  node = key_to_node[first_key]
56
- if rest && node
57
- node = node.children.try(:get, rest)
58
- end
56
+ node = node.children.try(:get, rest) if rest && node
59
57
  node
60
58
  end
61
59
 
@@ -63,7 +61,7 @@ module I18n::Tasks::Data::Tree
63
61
 
64
62
  # add or replace node by full key
65
63
  def set(full_key, node)
66
- raise 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)
64
+ fail 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)
67
65
  key_part, rest = split_key(full_key, 2)
68
66
  child = key_to_node[key_part]
69
67
 
@@ -87,7 +85,6 @@ module I18n::Tasks::Data::Tree
87
85
 
88
86
  alias []= set
89
87
 
90
-
91
88
  # methods below change state
92
89
 
93
90
  def remove!(node)
@@ -98,7 +95,7 @@ module I18n::Tasks::Data::Tree
98
95
 
99
96
  def append!(nodes)
100
97
  nodes = nodes.map do |node|
101
- raise "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)
98
+ fail "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)
102
99
  key_to_node[node.key] = (node.parent == parent ? node : node.derive(parent: parent))
103
100
  end
104
101
  super(nodes)
@@ -123,11 +120,11 @@ module I18n::Tasks::Data::Tree
123
120
  end
124
121
 
125
122
  def subtract_keys(keys)
126
- remove_nodes_and_emptied_ancestors(keys.inject(Set.new) { |set, key| (node = get(key)) ? set << node : set })
123
+ remove_nodes_and_emptied_ancestors(find_nodes(keys))
127
124
  end
128
125
 
129
126
  def subtract_keys!(keys)
130
- remove_nodes_and_emptied_ancestors!(keys.inject(Set.new) { |set, key| (node = get(key)) ? set << node : set })
127
+ remove_nodes_and_emptied_ancestors!(find_nodes(keys))
131
128
  end
132
129
 
133
130
  def subtract_by_key(other)
@@ -146,7 +143,7 @@ module I18n::Tasks::Data::Tree
146
143
  end
147
144
 
148
145
  # @param on_leaves_merge [Proc] invoked when a leaf is merged with another leaf
149
- def merge_node!(node, on_leaves_merge: nil)
146
+ def merge_node!(node, on_leaves_merge: nil) # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity
150
147
  if key_to_node.key?(node.key)
151
148
  our = key_to_node[node.key]
152
149
  return if our == node
@@ -182,6 +179,13 @@ module I18n::Tasks::Data::Tree
182
179
 
183
180
  private
184
181
 
182
+ def find_nodes(keys)
183
+ keys.each_with_object(Set.new) do |key, set|
184
+ node = get(key)
185
+ set << node if node
186
+ end
187
+ end
188
+
185
189
  # Adds all the ancestors that only contain the given nodes as descendants to the given nodes.
186
190
  # @param nodes [Set] Modified in-place.
187
191
  def add_ancestors_that_only_contain_nodes!(nodes)
@@ -205,7 +209,7 @@ module I18n::Tasks::Data::Tree
205
209
  opts[:nodes] ||= []
206
210
  parse_parent_opt!(opts)
207
211
  forest = Siblings.new(opts)
208
- block.call(forest) if block
212
+ yield(forest) if block
209
213
  # forest.parent.children = forest
210
214
  forest
211
215
  end
@@ -216,38 +220,39 @@ module I18n::Tasks::Data::Tree
216
220
  build_forest do |forest|
217
221
  key_occurrences.each do |key_occurrence|
218
222
  forest[key_occurrence.key] = ::I18n::Tasks::Data::Tree::Node.new(
219
- key: split_key(key_occurrence.key).last,
220
- data: {occurrences: key_occurrence.occurrences})
223
+ key: split_key(key_occurrence.key).last,
224
+ data: { occurrences: key_occurrence.occurrences }
225
+ )
221
226
  end
222
227
  end
223
228
  end
224
229
 
225
230
  def from_key_attr(key_attrs, opts = {}, &block)
226
- build_forest(opts) { |forest|
227
- key_attrs.each { |(full_key, attr)|
228
- raise "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
231
+ build_forest(opts) do |forest|
232
+ key_attrs.each do |(full_key, attr)|
233
+ fail "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
229
234
  node = ::I18n::Tasks::Data::Tree::Node.new(attr.merge(key: split_key(full_key).last))
230
- block.call(full_key, node) if block
235
+ yield(full_key, node) if block
231
236
  forest[full_key] = node
232
- }
233
- }
237
+ end
238
+ end
234
239
  end
235
240
 
236
241
  def from_key_names(keys, opts = {}, &block)
237
- build_forest(opts) { |forest|
238
- keys.each { |full_key|
242
+ build_forest(opts) do |forest|
243
+ keys.each do |full_key|
239
244
  node = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last)
240
- block.call(full_key, node) if block
245
+ yield(full_key, node) if block
241
246
  forest[full_key] = node
242
- }
243
- }
247
+ end
248
+ end
244
249
  end
245
250
 
246
251
  # build forest from nested hash, e.g. {'es' => { 'common' => { name => 'Nombre', 'age' => 'Edad' } } }
247
252
  # this is the native i18n gem format
248
253
  def from_nested_hash(hash, opts = {})
249
254
  parse_parent_opt!(opts)
250
- raise ::I18n::Tasks::CommandError.new("invalid tree #{hash.inspect}") unless hash.respond_to?(:map)
255
+ fail I18n::Tasks::CommandError, "invalid tree #{hash.inspect}" unless hash.respond_to?(:map)
251
256
  opts[:nodes] = hash.map { |key, value| Node.from_key_value key, value }
252
257
  Siblings.new(opts)
253
258
  end
@@ -257,13 +262,14 @@ module I18n::Tasks::Data::Tree
257
262
  # build forest from [[Full Key, Value]]
258
263
  def from_flat_pairs(pairs)
259
264
  Siblings.new.tap do |siblings|
260
- pairs.each { |full_key, value|
265
+ pairs.each do |full_key, value|
261
266
  siblings[full_key] = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last, value: value)
262
- }
267
+ end
263
268
  end
264
269
  end
265
270
 
266
271
  private
272
+
267
273
  def parse_parent_opt!(opts)
268
274
  if opts[:parent_key]
269
275
  opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(key: opts[:parent_key])
@@ -273,7 +279,8 @@ module I18n::Tasks::Data::Tree
273
279
  end
274
280
  if opts[:parent_locale]
275
281
  opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(
276
- key: opts[:parent_locale], data: {locale: opts[:parent_locale]})
282
+ key: opts[:parent_locale], data: { locale: opts[:parent_locale] }
283
+ )
277
284
  end
278
285
  end
279
286
  end