i18n_yaml_editor 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 59360f083d7e5071393e6605905f034df8340f64
4
- data.tar.gz: 422e871b2b24a8061dc75f12721478e6c3e9c4a7
2
+ SHA256:
3
+ metadata.gz: ad480bea1096f76fac7b6bb42adc82c7ea60c956f4d8c0806e6e5856475acac0
4
+ data.tar.gz: 2cc8b7ab2f39c9637fa8b5396d8ff968c0951b433e4f037589b3ab35a5be1e26
5
5
  SHA512:
6
- metadata.gz: 469c35174ee3ad8f52526830da4ed069fbdb5e4ad37de79dc770d0a5daaf58efc351c98b4e1622f85e24f64a283af1b49f1b49a4d87aa82c49e71e96ef15a436
7
- data.tar.gz: e50602ce147daf56bb1837c13678670e86dc46e5848b2cc6824293bb267e4d5ac4b8036579f3c6204836c174aa8dd2e9fc75c798ce1a8ac10841b5cb75067cec
6
+ metadata.gz: bdffd81d20c4651ba5918972ce5d849c13b7bb6f9e994cb283d1445fddfc684a16dea65c14c2dd5f5ab30fc22a315e359cdb9e62e30764351cacc5c427d8a243
7
+ data.tar.gz: fa83700132f54985f86f6fec20c76e7a1e547eeb3a295ba4df1b3b2cee0bb53ddeb77f18a3e086abe1fc44c48ab0e8db763b73c02512b1744bdaf72f12a3285e
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ lib = File.expand_path('../lib', __dir__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require 'i18n_yaml_editor'
5
7
 
6
8
  i18n_yaml_editor = I18nYamlEditor::App.new(*ARGV)
@@ -3,49 +3,53 @@
3
3
  # rubocop:disable Metrics/BlockLength
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'i18n_yaml_editor'
6
- s.version = '2.0.0'
7
- s.date = '2015-10-07'
6
+ s.version = '2.1.0'
7
+ s.date = '2018-05-04'
8
8
  s.summary = 'I18n Yaml Editor'
9
9
  s.email = 'wolfgang.teuber@sage.com'
10
10
  s.homepage = 'http://github.com/Sage/i18n_yaml_editor'
11
11
  s.description = 'I18n Yaml Editor'
12
12
  s.authors = ['Harry Vangberg', 'Wolfgang Teuber']
13
13
  s.executables << 'i18n_yaml_editor'
14
- s.files = [
15
- 'README.md',
16
- 'Rakefile',
17
- 'i18n_yaml_editor.gemspec',
18
- 'bin/i18n_yaml_editor',
19
- 'lib/i18n_yaml_editor.rb',
20
- 'lib/i18n_yaml_editor/app.rb',
21
- 'lib/i18n_yaml_editor/category.rb',
22
- 'lib/i18n_yaml_editor/core_ext.rb',
23
- 'lib/i18n_yaml_editor/key.rb',
24
- 'lib/i18n_yaml_editor/store.rb',
25
- 'lib/i18n_yaml_editor/filter.rb',
26
- 'lib/i18n_yaml_editor/update.rb',
27
- 'lib/i18n_yaml_editor/cast.rb',
28
- 'lib/i18n_yaml_editor/transformation.rb',
29
- 'lib/i18n_yaml_editor/translation.rb',
30
- 'lib/i18n_yaml_editor/web.rb',
31
- 'views/categories.html.erb',
32
- 'views/debug.html.erb',
33
- 'views/layout.erb',
34
- 'views/translations.html.erb'
14
+ s.files = %w[
15
+ README.md
16
+ Rakefile
17
+ i18n_yaml_editor.gemspec
18
+ bin/i18n_yaml_editor
19
+ lib/i18n_yaml_editor.rb
20
+ lib/i18n_yaml_editor/app.rb
21
+ lib/i18n_yaml_editor/category.rb
22
+ lib/i18n_yaml_editor/key.rb
23
+ lib/i18n_yaml_editor/store.rb
24
+ lib/i18n_yaml_editor/filter.rb
25
+ lib/i18n_yaml_editor/update.rb
26
+ lib/i18n_yaml_editor/cast.rb
27
+ lib/i18n_yaml_editor/translation.rb
28
+ lib/i18n_yaml_editor/web.rb
29
+ views/categories.html.erb
30
+ views/debug.html.erb
31
+ views/layout.erb
32
+ views/translations.html.erb
35
33
  ]
36
- s.test_files = [
37
- 'test/test_helper.rb',
38
- 'test/unit/test_app.rb',
39
- 'test/unit/test_category.rb',
40
- 'test/unit/test_key.rb',
41
- 'test/unit/test_store.rb',
42
- 'test/unit/test_transformation.rb',
43
- 'test/unit/test_translation.rb'
34
+ s.test_files = %w[
35
+ test/test_helper.rb
36
+ test/unit/test_app.rb
37
+ test/unit/test_app_load_translations.rb
38
+ test/unit/test_app_new.rb
39
+ test/unit/test_app_start.rb
40
+ test/unit/test_category.rb
41
+ test/unit/test_key.rb
42
+ test/unit/test_store.rb
43
+ test/unit/test_store_data.rb
44
+ test/unit/test_store_filter.rb
45
+ test/unit/test_translation.rb
46
+ test/unit/test_web.rb
44
47
  ]
45
48
  s.add_dependency 'activesupport', '>= 4.0.2'
46
49
  s.add_dependency 'cuba', '>= 3'
47
50
  s.add_dependency 'psych', '>= 1.3.4'
48
51
  s.add_dependency 'tilt', '>= 1.3'
52
+ s.add_dependency 'yaml_normalizer', '>= 0'
49
53
 
50
54
  s.add_development_dependency 'awesome_print'
51
55
  s.add_development_dependency 'cane'
@@ -11,6 +11,5 @@ require 'i18n_yaml_editor/app'
11
11
  require 'i18n_yaml_editor/category'
12
12
  require 'i18n_yaml_editor/key'
13
13
  require 'i18n_yaml_editor/store'
14
- require 'i18n_yaml_editor/transformation'
15
14
  require 'i18n_yaml_editor/translation'
16
15
  require 'i18n_yaml_editor/web'
@@ -6,7 +6,6 @@ require 'active_support/all'
6
6
 
7
7
  require 'i18n_yaml_editor/web'
8
8
  require 'i18n_yaml_editor/store'
9
- require 'i18n_yaml_editor/core_ext'
10
9
 
11
10
  module I18nYamlEditor
12
11
  # App provides I18n Yaml Editor's top-level functionality:
@@ -58,8 +57,9 @@ module I18nYamlEditor
58
57
  store.update(translations)
59
58
  changes = files(translations: translations)
60
59
  changes.each do |file, yaml|
60
+ yaml.extend(YamlNormalizer::Ext::SortByKey)
61
61
  File.open(file, 'w', encoding: 'utf-8') do |f|
62
- f.puts normalize(yaml)
62
+ f.puts yaml.sort_by_key.to_yaml
63
63
  end
64
64
  end
65
65
  end
@@ -99,27 +99,5 @@ module I18nYamlEditor
99
99
  end
100
100
  end.nil?
101
101
  end
102
-
103
- def normalize(yaml)
104
- i18n_yaml = yaml.with_indifferent_access.to_hash.to_yaml
105
- i18n_yaml_lines = i18n_yaml.split(/\n/).reject { |e| e == '' }[1..-1]
106
- normalize_empty_lines(i18n_yaml_lines) * "\n"
107
- end
108
-
109
- def normalize_empty_lines(i18n_yaml_lines)
110
- yaml_ary = []
111
- i18n_yaml_lines.each_with_index do |line, idx|
112
- yaml_ary << line
113
- yaml_ary << '' if add_empty_line?(i18n_yaml_lines, line, idx)
114
- end
115
- yaml_ary
116
- end
117
-
118
- def add_empty_line?(process, line, idx)
119
- return if process[idx + 1].nil?
120
- this_line_spcs = line[/\A\s*/].length
121
- next_line_spcs = process[idx + 1][/\A\s*/].length
122
- this_line_spcs - next_line_spcs > 2
123
- end
124
102
  end
125
103
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'set'
4
4
  require 'pathname'
5
+ require 'yaml_normalizer'
5
6
 
6
- require 'i18n_yaml_editor/transformation'
7
7
  require 'i18n_yaml_editor/filter'
8
8
  require 'i18n_yaml_editor/update'
9
9
  require 'i18n_yaml_editor/category'
@@ -16,7 +16,6 @@ module I18nYamlEditor
16
16
 
17
17
  # Store keeps all i18n data
18
18
  class Store
19
- include Transformation
20
19
  include Filter
21
20
  include Update
22
21
 
@@ -74,7 +73,7 @@ module I18nYamlEditor
74
73
 
75
74
  # Adds a translation for every entry in a given yaml hash
76
75
  def from_yaml(yaml, file = nil)
77
- translations = flatten_hash(yaml)
76
+ translations = yaml.extend(YamlNormalizer::Ext::Namespaced).namespaced
78
77
  translations.each do |name, text|
79
78
  translation = Translation.new(name: name, text: text, file: file)
80
79
  add_translation(translation)
@@ -90,7 +89,7 @@ module I18nYamlEditor
90
89
  translations.each do |translation|
91
90
  file_result[translation.name] = translation.text
92
91
  end
93
- result[file] = nest_hash(file_result)
92
+ result[file] = file_result.extend(YamlNormalizer::Ext::Nested).nested
94
93
  end
95
94
  result
96
95
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/app'
5
+
6
+ class TestApp < Minitest::Test
7
+ def test_load_translations_error
8
+ Dir.mktmpdir do |dir|
9
+ file = dir + '/does_not_exist.yml'
10
+ assert_output('', "No valid translation file given\n") do
11
+ App.new(file).load_translations
12
+ end
13
+ end
14
+ end
15
+
16
+ def test_load_translations_dir
17
+ store_from_yaml = lambda do |yaml, file|
18
+ assert_equal(yaml['en']['session']['create']['logged_in'], 'Welcome!')
19
+ assert_match(%r{/session\.en\.yml\z}, file)
20
+ end
21
+
22
+ Dir.mktmpdir do |dir|
23
+ FileUtils.copy './example/session.en.yml', dir
24
+ @app = App.new(dir)
25
+ @app.store.stub(:from_yaml, store_from_yaml) { @app.load_translations }
26
+ end
27
+ end
28
+
29
+ def test_load_translations_file_list
30
+ Dir.mktmpdir do |dir|
31
+ FileUtils.copy './example/session.en.yml', dir
32
+ list_path = File.join(dir, 'file_list')
33
+ File.open(list_path, 'w') { |f| f.write(Dir[dir + '/*.yml'] * "\n") }
34
+ @app = App.new(list_path)
35
+ @app.load_translations
36
+ end
37
+ assert @app.store.translations.key?('en.session.create.logged_in')
38
+ end
39
+
40
+ def test_load_translations_translation_file
41
+ store_from_yaml = lambda do |yaml, file|
42
+ assert_equal(yaml['en']['session']['create']['logged_in'], 'Welcome!')
43
+ assert_match(%r{/session\.en\.yml\z}, file)
44
+ end
45
+
46
+ Dir.mktmpdir do |dir|
47
+ FileUtils.copy './example/session.en.yml', dir
48
+ @app = App.new(dir + '/session.en.yml')
49
+ @app.store.stub(:from_yaml, store_from_yaml) { @app.load_translations }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/app'
5
+
6
+ class TestApp < Minitest::Test
7
+ def test_new_no_path_given
8
+ assert_raises(ArgumentError) { App.new }
9
+ end
10
+
11
+ def test_new_given_path
12
+ app = App.new('my_path')
13
+ assert_match(/my_path\z/, app.instance_variable_get(:@path))
14
+ end
15
+
16
+ def test_new_default_port
17
+ app = App.new('')
18
+ assert_equal 5050, app.instance_variable_get(:@port)
19
+ end
20
+
21
+ def test_new_given_port
22
+ app = App.new('', 3333)
23
+ assert_equal 3333, app.instance_variable_get(:@port)
24
+ end
25
+
26
+ def test_new_store
27
+ app = App.new('')
28
+ refute_nil app.instance_variable_get(:@store)
29
+ end
30
+
31
+ def test_new_store_accessor
32
+ app = App.new('')
33
+ assert_equal app.store, app.instance_variable_get(:@store)
34
+ end
35
+
36
+ def test_new_exposure
37
+ app = App.new('')
38
+ assert_equal(I18nYamlEditor.app, app)
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/app'
5
+
6
+ class TestApp < Minitest::Test
7
+ def setup
8
+ @app = App.new('.')
9
+ @fake_load_translations = -> { raise 'called load_translations' }
10
+ @fake_store_create_missing_keys = -> { raise 'called create_missing_keys' }
11
+ @fake_rack_server_start = lambda do |options|
12
+ assert_equal({ app: I18nYamlEditor::Web, Port: 5050 }, options)
13
+ raise 'called rack_server_start'
14
+ end
15
+ end
16
+
17
+ def test_start_file_not_found
18
+ Dir.mktmpdir do |dir|
19
+ file = dir + '/does_not_exist.yml'
20
+ @app.stub :load_translations, @fake_load_translations do
21
+ @app = App.new(file)
22
+ assert_raises("File #{file} not found.") do
23
+ @app.start
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def test_start_load_translations
30
+ assert_output(/ \* Loading translations from/, '') do
31
+ @app.stub :load_translations, @fake_load_translations do
32
+ assert_raises('called load_translations') { @app.start }
33
+ end
34
+ end
35
+ end
36
+
37
+ def test_store_create_missing_keys
38
+ assert_output(/ \* Creating missing translations/, '') do
39
+ @app.stub :load_translations, nil do
40
+ @app.store.stub :create_missing_keys, @fake_store_create_missing_keys do
41
+ assert_raises('called create_missing_keys') { @app.start }
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def test_server_start
48
+ assert_output(/ \* Starting I18n Yaml Editor at port /, '') do
49
+ @app.stub :load_translations, nil do
50
+ @app.store.stub :create_missing_keys, nil do
51
+ Rack::Server.stub :start, @fake_rack_server_start do
52
+ assert_raises('called rack_server_start') { @app.start }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/store'
5
+
6
+ module TestStoreData
7
+ def self.included(_base)
8
+ include I18nYamlEditor
9
+ end
10
+
11
+ def init_test_store_1
12
+ store = Store.new
13
+ store.add_translation tmp_translation_1
14
+ store.locales.add('en')
15
+ store
16
+ end
17
+
18
+ def init_test_store_0
19
+ store = Store.new
20
+ store.add_translation tmp_translation_0
21
+ store.locales.add('en')
22
+ store
23
+ end
24
+
25
+ def tmp_translation_1
26
+ Translation.new(
27
+ name: 'da.app_name',
28
+ text: 'Oversætter',
29
+ file: '/tmp/da.yml'
30
+ )
31
+ end
32
+
33
+ def tmp_translation_0
34
+ Translation.new(
35
+ name: 'da.session.login',
36
+ text: 'Log ind',
37
+ file: '/tmp/session.da.yml'
38
+ )
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/store'
5
+
6
+ class TestStore < Minitest::Test
7
+ def test_filter_keys_on_key
8
+ store = Store.new
9
+ store.add_key(Key.new(name: 'session.login'))
10
+ store.add_key(Key.new(name: 'session.logout'))
11
+
12
+ result = store.filter_keys(key: /login/)
13
+
14
+ assert_equal 1, result.size
15
+ assert_equal %w[session.login], result.keys
16
+ end
17
+
18
+ def test_filter_keys_on_complete
19
+ store = Store.new
20
+ [{ name: 'da.session.login', text: 'Log ind' },
21
+ { name: 'en.session.login' },
22
+ { name: 'da.session.logout', text: 'Log ud' }].each do |translation|
23
+ store.add_translation Translation.new(translation)
24
+ end
25
+
26
+ result = store.filter_keys(complete: false)
27
+
28
+ assert_equal 1, result.size
29
+ assert_equal %w[session.login], result.keys
30
+ end
31
+
32
+ def test_filter_keys_on_empty
33
+ store = Store.new
34
+ store.add_translation Translation.new(name: 'da.session.login',
35
+ text: 'Log ind')
36
+ store.add_translation Translation.new(name: 'da.session.logout')
37
+
38
+ result = store.filter_keys(empty: true)
39
+
40
+ assert_equal 1, result.size
41
+ assert_equal %w[session.logout], result.keys
42
+ end
43
+
44
+ def test_filter_keys_on_text
45
+ store = Store.new
46
+ store.add_translation Translation.new(name: 'da.session.login',
47
+ text: 'Log ind')
48
+ store.add_translation Translation.new(name: 'da.session.logout',
49
+ text: 'Log ud')
50
+ store.add_translation Translation.new(name: 'da.app.name',
51
+ text: 'I18n Yaml Editor')
52
+
53
+ result = store.filter_keys(text: /Log/)
54
+
55
+ assert_equal 2, result.size
56
+ assert_equal %w[session.login session.logout].sort, result.keys.sort
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'i18n_yaml_editor/web'
5
+
6
+ # TODO: imprive tests in TestWeb
7
+ class TestWeb < Minitest::Test
8
+ include Rack::Test::Methods
9
+
10
+ def setup
11
+ app = nil
12
+ capture_io { app = App.new('examples') }
13
+
14
+ app.load_translations
15
+ app.store.create_missing_keys
16
+ I18nYamlEditor.app = app
17
+ end
18
+
19
+ def app
20
+ Rack::Builder.new Web
21
+ end
22
+
23
+ def test_get_root
24
+ capture_io { get '/' }
25
+
26
+ refute_nil last_response
27
+ end
28
+
29
+ def test_get_root_filter
30
+ capture_io { get '/', filters: { key: '^app_name' } }
31
+
32
+ refute_nil last_response
33
+ end
34
+
35
+ def test_get_debug
36
+ capture_io { get '/debug' }
37
+
38
+ refute_nil last_response
39
+ end
40
+
41
+ def test_get_update
42
+ capture_io do
43
+ post '/update', 'filters' => { 'key' => '^day_names' },
44
+ 'translations' => {
45
+ 'da.day_names' => "søndag\r\nmandag\r\nonsdag\r\n"\
46
+ "torsdag\r\nfredag\r\nlørdag",
47
+ 'en.day_names' => 'lol'
48
+ }
49
+ end
50
+ refute_nil last_response
51
+ end
52
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n_yaml_editor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Vangberg
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-07 00:00:00.000000000 Z
12
+ date: 2018-05-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -67,6 +67,20 @@ dependencies:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '1.3'
70
+ - !ruby/object:Gem::Dependency
71
+ name: yaml_normalizer
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
70
84
  - !ruby/object:Gem::Dependency
71
85
  name: awesome_print
72
86
  requirement: !ruby/object:Gem::Requirement
@@ -348,21 +362,24 @@ files:
348
362
  - lib/i18n_yaml_editor/app.rb
349
363
  - lib/i18n_yaml_editor/cast.rb
350
364
  - lib/i18n_yaml_editor/category.rb
351
- - lib/i18n_yaml_editor/core_ext.rb
352
365
  - lib/i18n_yaml_editor/filter.rb
353
366
  - lib/i18n_yaml_editor/key.rb
354
367
  - lib/i18n_yaml_editor/store.rb
355
- - lib/i18n_yaml_editor/transformation.rb
356
368
  - lib/i18n_yaml_editor/translation.rb
357
369
  - lib/i18n_yaml_editor/update.rb
358
370
  - lib/i18n_yaml_editor/web.rb
359
371
  - test/test_helper.rb
360
372
  - test/unit/test_app.rb
373
+ - test/unit/test_app_load_translations.rb
374
+ - test/unit/test_app_new.rb
375
+ - test/unit/test_app_start.rb
361
376
  - test/unit/test_category.rb
362
377
  - test/unit/test_key.rb
363
378
  - test/unit/test_store.rb
364
- - test/unit/test_transformation.rb
379
+ - test/unit/test_store_data.rb
380
+ - test/unit/test_store_filter.rb
365
381
  - test/unit/test_translation.rb
382
+ - test/unit/test_web.rb
366
383
  - views/categories.html.erb
367
384
  - views/debug.html.erb
368
385
  - views/layout.erb
@@ -386,16 +403,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
386
403
  version: '0'
387
404
  requirements: []
388
405
  rubyforge_project:
389
- rubygems_version: 2.5.1
406
+ rubygems_version: 2.7.6
390
407
  signing_key:
391
408
  specification_version: 4
392
409
  summary: I18n Yaml Editor
393
410
  test_files:
394
411
  - test/test_helper.rb
395
412
  - test/unit/test_app.rb
413
+ - test/unit/test_app_load_translations.rb
414
+ - test/unit/test_app_new.rb
415
+ - test/unit/test_app_start.rb
396
416
  - test/unit/test_category.rb
397
417
  - test/unit/test_key.rb
398
418
  - test/unit/test_store.rb
399
- - test/unit/test_transformation.rb
419
+ - test/unit/test_store_data.rb
420
+ - test/unit/test_store_filter.rb
400
421
  - test/unit/test_translation.rb
401
- has_rdoc:
422
+ - test/unit/test_web.rb
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Extend Hash with sort_by_key method
4
- class Hash
5
- # Sorts entries alphabetically by key
6
- def sort_by_key(recursive = false, &block)
7
- keys.sort(&block).each_with_object({}) do |key, seed|
8
- seed[key] = self[key]
9
- if recursive && seed[key].is_a?(Hash)
10
- seed[key] = seed[key].sort_by_key(true, &block)
11
- end
12
- end
13
- end
14
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module I18nYamlEditor
4
- # Raised when nesting of I18n keys to a Hash fails
5
- class TransformationError < StandardError; end
6
-
7
- # Transformation provides
8
- module Transformation
9
- # Public: Converts a deep hash to one level by generating new keys
10
- # by joining the previous key path to the value with a '.'
11
- #
12
- # hash - The original Hash.
13
- # namespace - An optional namespace, default: [].
14
- # tree - An optional tree to add values to, default: {}.
15
- #
16
- # Examples
17
- # flatten_hash({da: {session: { login: 'Log ind', logout: 'Log ud' }}})
18
- # # => {"da.session.login"=>"Log ind", "da.session.logout"=>"Log ud"}
19
- #
20
- # Returns the generated Hash.
21
- def flatten_hash(hash, namespace = [], tree = {})
22
- hash.each do |key, value|
23
- child_ns = namespace.dup << key
24
- if value.is_a?(Hash)
25
- flatten_hash value, child_ns, tree
26
- else
27
- tree[child_ns.join('.')] = value
28
- end
29
- end
30
- tree
31
- end
32
- module_function :flatten_hash
33
-
34
- # Public: Converts a flat hash with key path to the value joined
35
- # with a '.' to a one level Hash, it's the reverse of flatten_hash
36
- #
37
- # hash - Hash with keys that represent the path to the value in the new Hash
38
- #
39
- # Examples
40
- # nest_hash({"da.session.login"=>"Log ind", "da.session.logout"=>"Log ud"})
41
- # # => {"da"=>{"session"=>{"login"=>"Log ind", "logout"=>"Log ud"}}}
42
- #
43
- # Returns the generated Hash.
44
- def nest_hash(hash)
45
- result = {}
46
- hash.each do |key, value|
47
- begin
48
- nest_key result, key, value
49
- rescue StandardError
50
- raise TransformationError,
51
- "Failed to nest key: #{key.inspect} with #{value.inspect}"
52
- end
53
- end
54
- result
55
- end
56
- module_function :nest_hash
57
-
58
- private
59
-
60
- # Recursively nests point-separated keys from a string in a hash and
61
- # assigns the given value to this new hash entry
62
- def nest_key(result, key, value)
63
- sub_result = result
64
- keys = key.split('.')
65
- keys.each_with_index do |k, idx|
66
- if keys.size - 1 == idx
67
- sub_result[k] = value
68
- else
69
- sub_result = (sub_result[k] ||= {})
70
- end
71
- end
72
- end
73
- module_function :nest_key
74
- end
75
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'i18n_yaml_editor/transformation'
5
-
6
- class TestTransformation < Minitest::Test
7
- I18N_HASH = {
8
- 'da.session.login' => 'Log ind',
9
- 'da.session.logout' => 'Log ud',
10
- 'en.session.login' => 'Log in',
11
- 'en.session.logout' => 'Log out'
12
- }.freeze
13
-
14
- def test_flatten_hash
15
- input = {
16
- da: {
17
- session: { login: 'Log ind', logout: 'Log ud' }
18
- },
19
- en: {
20
- session: { login: 'Log in', logout: 'Log out' }
21
- }
22
- }
23
-
24
- assert_equal I18N_HASH, Transformation.flatten_hash(input)
25
- end
26
-
27
- def test_nest_hash
28
- expected = {
29
- da: {
30
- session: { login: 'Log ind', logout: 'Log ud' }
31
- },
32
- en: {
33
- session: { login: 'Log in', logout: 'Log out' }
34
- }
35
- }.with_indifferent_access
36
-
37
- assert_equal expected, Transformation.nest_hash(I18N_HASH)
38
- end
39
-
40
- def test_nest_hash_transformation_error
41
- assert_raises(TransformationError) do
42
- Transformation.nest_hash(error: 'value')
43
- end
44
- end
45
- end