i18n-tasks 0.3.11 → 0.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,81 @@
1
+ module I18n::Tasks::Data::Tree
2
+ # Any Enumerable that yields nodes can mix in this module
3
+ module Traversal
4
+
5
+ def nodes(&block)
6
+ walk_depth_first(&block)
7
+ end
8
+
9
+ def leaves(&visitor)
10
+ return to_enum(:leaves) unless visitor
11
+ nodes do |node|
12
+ visitor.yield(node) if node.leaf?
13
+ end
14
+ end
15
+
16
+ # @param root include root in full key
17
+ def keys(root: true, &visitor)
18
+ return to_enum(:keys, root: root) unless visitor
19
+ leaves { |node| visitor.yield(node.full_key(root: root), node) }
20
+ end
21
+
22
+ def levels(&block)
23
+ return to_enum(:levels) unless block
24
+ nodes = to_nodes
25
+ non_null = nodes.reject(&:null?)
26
+ unless non_null.empty?
27
+ block.yield non_null
28
+ Nodes.new(nodes.children).levels(&block)
29
+ end
30
+ end
31
+
32
+ def walk_breadth_first(&visitor)
33
+ return to_enum(:walk_breadth_first) unless visitor
34
+ levels do |nodes|
35
+ nodes.each { |node| visitor.yield(node) unless node.null? }
36
+ end
37
+ end
38
+
39
+ def walk_depth_first(&visitor)
40
+ return to_enum(:walk_depth_first) unless visitor
41
+ each { |node|
42
+ visitor.yield node unless node.null?
43
+ node.children.each do |child|
44
+ child.walk_depth_first(&visitor)
45
+ end if node.children?
46
+ }
47
+ end
48
+
49
+ #-- modify / derive
50
+
51
+ # @return Siblings
52
+ def select_nodes(&block)
53
+ result = Node.new(children: [])
54
+ each do |node|
55
+ if block.yield(node)
56
+ result.append!(
57
+ node.derive(
58
+ parent: result ,
59
+ children: (node.children.select_nodes(&block) if node.children)
60
+ )
61
+ )
62
+ end
63
+ end
64
+ result.children
65
+ end
66
+
67
+ # @return Siblings
68
+ def select_keys(root: true, &block)
69
+ ok = {}
70
+ keys(root: root) do |full_key, node|
71
+ if block.yield(full_key, node)
72
+ node.walk_to_root { |p|
73
+ break if ok[p]
74
+ ok[p] = true
75
+ }
76
+ end
77
+ end
78
+ select_nodes { |node| ok[node] }
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,18 @@
1
+ module I18n::Tasks::FileStructure
2
+ def identify(routes = data.config.read)
3
+
4
+ end
5
+
6
+
7
+ class NonLeafVisitor
8
+ def visit(node)
9
+ puts "non-leaf: #{node}"
10
+ end
11
+ end
12
+
13
+ class LeafVisitor
14
+ def visit(node)
15
+ puts "leaf: #{node}"
16
+ end
17
+ end
18
+ end
@@ -41,11 +41,11 @@ module I18n::Tasks
41
41
  return keys_missing_from_base if locale == base_locale
42
42
  @keys_missing_from_locale ||= {}
43
43
  @keys_missing_from_locale[locale] ||= begin
44
- keys = data[base_locale].traverse_map_if { |key, base_value|
45
- next if ignore_key?(key, :missing)
44
+ keys = data[base_locale].keys(root: false).map { |key, node|
46
45
  key = depluralize_key(key, locale)
47
- key if !key_value?(key, locale)
48
- }.uniq
46
+ next if ignore_key?(key, :missing) || key_value?(key, locale)
47
+ key
48
+ }.compact.uniq
49
49
  KeyGroup.new keys, type: :missing_from_locale, locale: locale
50
50
  end
51
51
  end
@@ -54,9 +54,9 @@ module I18n::Tasks
54
54
  def keys_eq_base(locale)
55
55
  @keys_eq_base ||= {}
56
56
  @keys_eq_base[locale] ||= begin
57
- keys = data[base_locale].traverse_map_if { |key, base_value|
58
- key if base_value == t(key, locale) && !ignore_key?(key, :eq_base, locale)
59
- }
57
+ keys = data[base_locale].keys(root: false).map { |key, node|
58
+ key if node.value == t(key, locale) && !ignore_key?(key, :eq_base, locale)
59
+ }.compact
60
60
  KeyGroup.new keys, type: :eq_base, locale: locale
61
61
  end
62
62
  end
@@ -5,11 +5,11 @@ module I18n::Tasks::PluralKeys
5
5
  # @param [String] locale to pull key data from
6
6
  # @return the base form if the key is a specific plural form (e.g. apple for apple.many), and the key as passed otherwise
7
7
  def depluralize_key(key, locale = base_locale)
8
- return key if key !~ PLURAL_KEY_RE || t(key, locale).is_a?(Hash)
9
- parent_key = key.split('.')[0..-2] * '.'
10
- plural_versions = t(parent_key, locale) || (locale != base_locale && t(parent_key, base_locale))
11
- if plural_versions.is_a?(Hash) && plural_versions.all? { |k, v| !v.is_a?(Hash) && ".#{k}" =~ PLURAL_KEY_RE }
12
- parent_key
8
+ return key if key !~ PLURAL_KEY_RE
9
+ node = node(key, locale)
10
+ nodes = node.try(:siblings).presence || (locale != base_locale && node(key, base_locale).try(:siblings))
11
+ if nodes && nodes.all? { |x| x.leaf? && ".#{x.key}" =~ PLURAL_KEY_RE }
12
+ key.split('.')[0..-2] * '.'
13
13
  else
14
14
  key
15
15
  end
@@ -8,11 +8,11 @@ module I18n
8
8
  def unused_keys(locale = base_locale)
9
9
  @unused_keys ||= {}
10
10
  @unused_keys[locale] ||= begin
11
- keys = data[locale].traverse_map_if { |key, value|
11
+ keys = data[locale].keys(root: false).map { |key, value|
12
12
  next if used_in_expr?(key) || ignore_key?(key, :unused)
13
13
  key = depluralize_key(key, locale)
14
- [key, value] unless used_key?(key)
15
- }.uniq
14
+ key unless used_key?(key)
15
+ }.compact.uniq
16
16
  KeyGroup.new keys, locale: locale, type: :unused
17
17
  end
18
18
  end
@@ -21,10 +21,9 @@ module I18n
21
21
  locales ||= self.locales
22
22
  unused = unused_keys
23
23
  locales.each do |locale|
24
- used_key_values = data[locale].traverse_map_if { |key, value|
25
- [key, value] unless unused.include?(depluralize_key(key, locale))
24
+ data[locale] = data[locale].select_keys(root: false) { |key, value|
25
+ !unused.include?(depluralize_key(key, locale))
26
26
  }
27
- data[locale] = used_key_values
28
27
  end
29
28
  end
30
29
  end
@@ -1,5 +1,5 @@
1
1
  module I18n
2
2
  module Tasks
3
- VERSION = '0.3.11'
3
+ VERSION = '0.4.0.beta1'
4
4
  end
5
5
  end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Conservative router' do
4
+ describe '#available_locales' do
5
+ before do
6
+ TestCodebase.setup(
7
+ 'config/locales/en.yml' => {en: {a: 1}}.to_yaml,
8
+ 'config/locales/other.en.yml' => {en: {b: 1}}.to_yaml,
9
+ 'config/locales/es.yml' => {es: {}}.to_yaml,
10
+ 'config/locales/other.es.yml' => {es: {c: 1}}.to_yaml
11
+ )
12
+ end
13
+ after do
14
+ TestCodebase.teardown
15
+ end
16
+ let(:data) {
17
+ I18n::Tasks::Data::FileSystem.new(
18
+ router: 'conservative_router',
19
+ base_locale: 'en',
20
+ read: 'config/locales/*%{locale}.yml',
21
+ write: ['config/locales/not_found.%{locale}.yml']
22
+ )
23
+ }
24
+
25
+ it 'preserves existing keys' do
26
+ TestCodebase.in_test_app_dir do
27
+ data['es'] = data['es']
28
+ data.reload
29
+ data['es']['es.c'].data[:path].should == 'config/locales/other.es.yml'
30
+ end
31
+ end
32
+
33
+ it 'infers new keys from base locale' do
34
+ TestCodebase.in_test_app_dir do
35
+ data['es'] = data['es'].merge!(build_tree(es: {a: 1, b: 2}))
36
+ data.reload
37
+ data['es']['es.a'].data[:path].should == 'config/locales/es.yml'
38
+ data['es']['es.b'].data[:path].should == 'config/locales/other.es.yml'
39
+ end
40
+ end
41
+
42
+ it 'falls back to pattern_router when the key is new' do
43
+ TestCodebase.in_test_app_dir do
44
+ data['es'] = data['es'].merge!(build_tree(es: {z: 2}))
45
+ data.reload
46
+ data['es']['es.z'].data[:path].should == 'config/locales/not_found.es.yml'
47
+ end
48
+ end
49
+ end
50
+ end
@@ -45,7 +45,8 @@ describe 'File system i18n' do
45
45
  'c.yml' => {en: {c: 1}}.stringify_keys.to_yaml
46
46
  )
47
47
  TestCodebase.in_test_app_dir {
48
- expect(data[:en].data.symbolize_keys).to eq(a: 1, b: 1, c: 1)
48
+ actual = data[:en].to_hash['en'].symbolize_keys
49
+ expect(actual).to eq(a: 1, b: 1, c: 1)
49
50
  }
50
51
  end
51
52
 
@@ -55,7 +56,7 @@ describe 'File system i18n' do
55
56
  locale_data = {'pizza' => keys, 'sushi' => keys}
56
57
  TestCodebase.setup
57
58
  TestCodebase.in_test_app_dir {
58
- data[:en] = locale_data
59
+ data[:en] = data[:en].merge!('en' => locale_data)
59
60
  files = %w(pizza.en.yml sushi.en.yml)
60
61
  Dir['*.yml'].sort.should == files.sort
61
62
  files.each { |f| YAML.load_file(f)['en'].should == {File.basename(f, '.en.yml') => keys} }
@@ -80,7 +81,7 @@ describe 'File system i18n' do
80
81
  'c.json' => {en: {c: 1}}.stringify_keys.to_json
81
82
  )
82
83
  TestCodebase.in_test_app_dir {
83
- expect(data[:en].data.symbolize_keys).to eq(a: 1, b: 1, c: 1)
84
+ expect(data[:en].to_hash['en'].symbolize_keys).to eq(a: 1, b: 1, c: 1)
84
85
  }
85
86
  end
86
87
 
@@ -90,7 +91,7 @@ describe 'File system i18n' do
90
91
  locale_data = {'pizza' => keys, 'sushi' => keys}
91
92
  TestCodebase.setup
92
93
  TestCodebase.in_test_app_dir {
93
- data[:en] = locale_data
94
+ data[:en] = data[:en].merge!('en' => locale_data)
94
95
  files = %w(pizza.en.json sushi.en.json)
95
96
  Dir['*.json'].sort.should == files.sort
96
97
  files.each { |f| JSON.parse(File.read f)['en'].should == {File.basename(f, '.en.json') => keys} }
@@ -33,9 +33,9 @@ describe 'Google Translation' do
33
33
 
34
34
  it 'works' do
35
35
  in_test_app_dir do
36
- task.data[:en] = {'common' => {'hello' => TEST_STRING}}
36
+ task.data[:en] = build_tree('en' => {'common' => {'hello' => TEST_STRING}})
37
37
  cmd.translate_missing
38
- expect(task.data[:es].t('common.hello')).to eq(TEST_RESULT)
38
+ expect(task.t('common.hello', 'es')).to eq(TEST_RESULT)
39
39
  end
40
40
  end
41
41
  end
@@ -9,7 +9,7 @@ describe 'i18n-tasks' do
9
9
  describe 'missing' do
10
10
  let (:expected_missing_keys) {
11
11
  %w( en.used_but_missing.key en.relative.index.missing
12
- es.missing_in_es.a es.blank_in_es.a es.same_in_es.a
12
+ es.missing_in_es.a es.same_in_es.a
13
13
  en.hash.pattern_missing.a en.hash.pattern_missing.b
14
14
  en.missing_symbol_key en.missing_symbol.key_two en.missing_symbol.key_three
15
15
  es.missing_in_es_plural_1.a es.missing_in_es_plural_2.a)
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Tree siblings / forest' do
4
+
5
+ context 'a tree' do
6
+ let(:a_hash) { {a: 1, b: {ba: 1, bb: 2}}.deep_stringify_keys }
7
+
8
+ it '::from_nested_hash' do
9
+ a = build_tree(a_hash)
10
+ expect(a.to_hash).to eq(a_hash)
11
+ end
12
+
13
+ it '#derive' do
14
+ a = build_tree(a_hash)
15
+ b = a.derive.append! build_tree(c: 1)
16
+
17
+ # a was not modified
18
+ expect(a.to_hash).to eq(a_hash)
19
+ # but b was
20
+ expect(b.to_hash).to eq(a_hash.merge('c' => 1))
21
+ end
22
+
23
+ it '#merge' do
24
+ a = build_tree(a_hash)
25
+ b_hash = {b: {bc: 1}, c: 1}.deep_stringify_keys
26
+ expect(a.merge(build_tree(b_hash)).to_hash).to eq(a_hash.deep_merge(b_hash))
27
+ end
28
+ end
29
+ end
@@ -5,7 +5,7 @@ describe 'Plural keys' do
5
5
  before do
6
6
  TestCodebase.setup('config/locales/en.yml' => '')
7
7
  TestCodebase.in_test_app_dir do
8
- task.data['en'] = {
8
+ tree = ::I18n::Tasks::Data::Tree::Siblings.from_nested_hash('en' => {
9
9
  'regular_key' => 'a',
10
10
  'plural_key' => {
11
11
  'one' => 'one', 'other' => '%{count}'
@@ -14,7 +14,8 @@ describe 'Plural keys' do
14
14
  'one' => 'a',
15
15
  'green' => 'b'
16
16
  }
17
- }
17
+ })
18
+ task.data['en'] = tree
18
19
  task.data['en']
19
20
  end
20
21
  end
data/spec/spec_helper.rb CHANGED
@@ -19,4 +19,5 @@ Dir['spec/support/**/*.rb'].each { |f| require "./#{f}" }
19
19
  RSpec.configure do |config|
20
20
  config.include FixturesSupport
21
21
  config.include CaptureStd
22
+ config.include Trees
22
23
  end
@@ -0,0 +1,5 @@
1
+ module Trees
2
+ def build_tree(hash)
3
+ I18n::Tasks::Data::Tree::Siblings.from_nested_hash(hash)
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.11
4
+ version: 0.4.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-20 00:00:00.000000000 Z
11
+ date: 2014-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erubis
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.4.0
47
+ version: 0.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.4.0
54
+ version: 0.5.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: term-ansicolor
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 3.4.7
103
+ version: 3.5.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 3.4.7
110
+ version: 3.5.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: axlsx
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -193,6 +193,7 @@ extra_rdoc_files: []
193
193
  files:
194
194
  - ".coveralls.yml"
195
195
  - ".gitignore"
196
+ - ".jrubyrc"
196
197
  - ".travis.yml"
197
198
  - CHANGES.md
198
199
  - Gemfile
@@ -200,6 +201,8 @@ files:
200
201
  - README.md
201
202
  - Rakefile
202
203
  - bin/i18n-tasks
204
+ - config/locales/en.yml
205
+ - config/locales/es.yml
203
206
  - i18n-tasks.gemspec
204
207
  - lib/i18n/tasks.rb
205
208
  - lib/i18n/tasks/base_task.rb
@@ -212,8 +215,13 @@ files:
212
215
  - lib/i18n/tasks/data/file_formats.rb
213
216
  - lib/i18n/tasks/data/file_system.rb
214
217
  - lib/i18n/tasks/data/file_system_base.rb
215
- - lib/i18n/tasks/data/locale_tree.rb
216
- - lib/i18n/tasks/data/router.rb
218
+ - lib/i18n/tasks/data/router/conservative_router.rb
219
+ - lib/i18n/tasks/data/router/pattern_router.rb
220
+ - lib/i18n/tasks/data/tree/node.rb
221
+ - lib/i18n/tasks/data/tree/nodes.rb
222
+ - lib/i18n/tasks/data/tree/siblings.rb
223
+ - lib/i18n/tasks/data/tree/traversal.rb
224
+ - lib/i18n/tasks/file_structure.rb
217
225
  - lib/i18n/tasks/fill_tasks.rb
218
226
  - lib/i18n/tasks/google_translation.rb
219
227
  - lib/i18n/tasks/ignore_keys.rb
@@ -236,6 +244,7 @@ files:
236
244
  - lib/i18n/tasks/unused_keys.rb
237
245
  - lib/i18n/tasks/used_keys.rb
238
246
  - lib/i18n/tasks/version.rb
247
+ - spec/conservative_router_spec.rb
239
248
  - spec/file_system_data_spec.rb
240
249
  - spec/fixtures/app/assets/javascripts/application.js
241
250
  - spec/fixtures/app/controllers/events_controller.rb
@@ -247,6 +256,7 @@ files:
247
256
  - spec/i18n_tasks_spec.rb
248
257
  - spec/key_group_spec.rb
249
258
  - spec/key_pattern_matching_spec.rb
259
+ - spec/locale_tree/siblings_spec.rb
250
260
  - spec/pattern_scanner_spec.rb
251
261
  - spec/plural_keys_spec.rb
252
262
  - spec/readme_spec.rb
@@ -257,6 +267,7 @@ files:
257
267
  - spec/support/i18n_tasks_output_matcher.rb
258
268
  - spec/support/key_pattern_matcher.rb
259
269
  - spec/support/test_codebase.rb
270
+ - spec/support/trees.rb
260
271
  - spec/used_keys_spec.rb
261
272
  homepage: https://github.com/glebm/i18n-tasks
262
273
  licenses:
@@ -274,17 +285,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
274
285
  version: '0'
275
286
  required_rubygems_version: !ruby/object:Gem::Requirement
276
287
  requirements:
277
- - - ">="
288
+ - - ">"
278
289
  - !ruby/object:Gem::Version
279
- version: '0'
290
+ version: 1.3.1
280
291
  requirements: []
281
292
  rubyforge_project:
282
- rubygems_version: 2.2.0
293
+ rubygems_version: 2.2.2
283
294
  signing_key:
284
295
  specification_version: 4
285
296
  summary: Manage translations in ruby applications with the awesome power of static
286
297
  analysis — Edit
287
298
  test_files:
299
+ - spec/conservative_router_spec.rb
288
300
  - spec/file_system_data_spec.rb
289
301
  - spec/fixtures/app/assets/javascripts/application.js
290
302
  - spec/fixtures/app/controllers/events_controller.rb
@@ -296,6 +308,7 @@ test_files:
296
308
  - spec/i18n_tasks_spec.rb
297
309
  - spec/key_group_spec.rb
298
310
  - spec/key_pattern_matching_spec.rb
311
+ - spec/locale_tree/siblings_spec.rb
299
312
  - spec/pattern_scanner_spec.rb
300
313
  - spec/plural_keys_spec.rb
301
314
  - spec/readme_spec.rb
@@ -306,5 +319,6 @@ test_files:
306
319
  - spec/support/i18n_tasks_output_matcher.rb
307
320
  - spec/support/key_pattern_matcher.rb
308
321
  - spec/support/test_codebase.rb
322
+ - spec/support/trees.rb
309
323
  - spec/used_keys_spec.rb
310
324
  has_rdoc: