i18n_yaml_editor 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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