i18n-js 3.9.2 → 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +4 -0
  3. data/.github/FUNDING.yml +1 -1
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  5. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
  8. data/.github/dependabot.yml +15 -0
  9. data/.github/workflows/ruby-tests.yml +73 -0
  10. data/.gitignore +13 -7
  11. data/.rubocop.yml +19 -0
  12. data/CHANGELOG.md +45 -561
  13. data/CODE_OF_CONDUCT.md +74 -0
  14. data/CONTRIBUTING.md +79 -0
  15. data/Gemfile +3 -0
  16. data/LICENSE.md +20 -0
  17. data/MIGRATING_FROM_V3_TO_V4.md +191 -0
  18. data/README.md +425 -951
  19. data/Rakefile +10 -20
  20. data/bin/release +81 -0
  21. data/exe/i18n +5 -0
  22. data/i18n-js.gemspec +51 -29
  23. data/lib/guard/i18n-js/templates/Guardfile +10 -0
  24. data/lib/guard/i18n-js/version.rb +13 -0
  25. data/lib/guard/i18n-js.rb +95 -0
  26. data/lib/i18n-js/clean_hash.rb +13 -0
  27. data/lib/i18n-js/cli/check_command.rb +17 -0
  28. data/lib/i18n-js/cli/command.rb +79 -0
  29. data/lib/i18n-js/cli/export_command.rb +95 -0
  30. data/lib/i18n-js/cli/init_command.rb +52 -0
  31. data/lib/i18n-js/cli/lint_scripts_command.rb +157 -0
  32. data/lib/i18n-js/cli/lint_translations_command.rb +155 -0
  33. data/lib/i18n-js/cli/plugins_command.rb +67 -0
  34. data/lib/i18n-js/cli/ui.rb +64 -0
  35. data/lib/i18n-js/cli/version_command.rb +18 -0
  36. data/lib/i18n-js/cli.rb +66 -0
  37. data/lib/i18n-js/embed_fallback_translations_plugin.rb +70 -0
  38. data/lib/i18n-js/export_files_plugin.rb +103 -0
  39. data/lib/i18n-js/lint.js +150645 -0
  40. data/lib/i18n-js/lint.ts +196 -0
  41. data/lib/i18n-js/listen.rb +96 -0
  42. data/lib/i18n-js/plugin.rb +103 -0
  43. data/lib/i18n-js/schema.rb +216 -0
  44. data/lib/i18n-js/sort_hash.rb +12 -0
  45. data/lib/i18n-js/version.rb +5 -0
  46. data/lib/i18n-js.rb +107 -1
  47. data/package.json +5 -20
  48. metadata +152 -198
  49. data/.editorconfig +0 -24
  50. data/.github/workflows/tests.yaml +0 -106
  51. data/.npmignore +0 -27
  52. data/Appraisals +0 -52
  53. data/app/assets/javascripts/i18n/filtered.js.erb +0 -23
  54. data/app/assets/javascripts/i18n/shims.js +0 -240
  55. data/app/assets/javascripts/i18n/translations.js +0 -3
  56. data/app/assets/javascripts/i18n.js +0 -1095
  57. data/gemfiles/i18n_0_6.gemfile +0 -7
  58. data/gemfiles/i18n_0_7.gemfile +0 -7
  59. data/gemfiles/i18n_0_8.gemfile +0 -7
  60. data/gemfiles/i18n_0_9.gemfile +0 -7
  61. data/gemfiles/i18n_1_0.gemfile +0 -7
  62. data/gemfiles/i18n_1_1.gemfile +0 -7
  63. data/gemfiles/i18n_1_10.gemfile +0 -7
  64. data/gemfiles/i18n_1_2.gemfile +0 -7
  65. data/gemfiles/i18n_1_3.gemfile +0 -7
  66. data/gemfiles/i18n_1_4.gemfile +0 -7
  67. data/gemfiles/i18n_1_5.gemfile +0 -7
  68. data/gemfiles/i18n_1_6.gemfile +0 -7
  69. data/gemfiles/i18n_1_7.gemfile +0 -7
  70. data/gemfiles/i18n_1_8.gemfile +0 -7
  71. data/gemfiles/i18n_1_9.gemfile +0 -7
  72. data/i18njs.png +0 -0
  73. data/lib/i18n/js/dependencies.rb +0 -67
  74. data/lib/i18n/js/engine.rb +0 -87
  75. data/lib/i18n/js/fallback_locales.rb +0 -70
  76. data/lib/i18n/js/formatters/base.rb +0 -25
  77. data/lib/i18n/js/formatters/js.rb +0 -39
  78. data/lib/i18n/js/formatters/json.rb +0 -13
  79. data/lib/i18n/js/middleware.rb +0 -82
  80. data/lib/i18n/js/private/config_store.rb +0 -31
  81. data/lib/i18n/js/private/hash_with_symbol_keys.rb +0 -36
  82. data/lib/i18n/js/segment.rb +0 -81
  83. data/lib/i18n/js/utils.rb +0 -91
  84. data/lib/i18n/js/version.rb +0 -7
  85. data/lib/i18n/js.rb +0 -274
  86. data/lib/rails/generators/i18n/js/config/config_generator.rb +0 -19
  87. data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +0 -27
  88. data/lib/tasks/export.rake +0 -8
  89. data/spec/fixtures/custom_path.yml +0 -5
  90. data/spec/fixtures/default.yml +0 -5
  91. data/spec/fixtures/erb.yml +0 -5
  92. data/spec/fixtures/except_condition.yml +0 -7
  93. data/spec/fixtures/js_available_locales_custom.yml +0 -1
  94. data/spec/fixtures/js_export_dir_custom.yml +0 -7
  95. data/spec/fixtures/js_export_dir_none.yml +0 -6
  96. data/spec/fixtures/js_extend_parent.yml +0 -6
  97. data/spec/fixtures/js_extend_segment.yml +0 -6
  98. data/spec/fixtures/js_file_per_locale.yml +0 -7
  99. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml +0 -4
  100. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_hash.yml +0 -6
  101. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale.yml +0 -4
  102. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml +0 -4
  103. data/spec/fixtures/js_file_per_locale_with_fallbacks_enabled.yml +0 -4
  104. data/spec/fixtures/js_file_per_locale_without_fallbacks.yml +0 -4
  105. data/spec/fixtures/js_file_with_namespace_prefix_and_pretty_print.yml +0 -9
  106. data/spec/fixtures/js_sort_translation_keys_false.yml +0 -6
  107. data/spec/fixtures/js_sort_translation_keys_true.yml +0 -6
  108. data/spec/fixtures/json_only.yml +0 -18
  109. data/spec/fixtures/locales.yml +0 -133
  110. data/spec/fixtures/merge_plurals.yml +0 -6
  111. data/spec/fixtures/merge_plurals_with_no_overrides.yml +0 -4
  112. data/spec/fixtures/merge_plurals_with_partial_overrides.yml +0 -4
  113. data/spec/fixtures/millions.yml +0 -4
  114. data/spec/fixtures/multiple_conditions.yml +0 -7
  115. data/spec/fixtures/multiple_conditions_per_locale.yml +0 -7
  116. data/spec/fixtures/multiple_files.yml +0 -7
  117. data/spec/fixtures/no_config.yml +0 -2
  118. data/spec/fixtures/no_scope.yml +0 -4
  119. data/spec/fixtures/simple_scope.yml +0 -5
  120. data/spec/js/currency.spec.js +0 -62
  121. data/spec/js/current_locale.spec.js +0 -19
  122. data/spec/js/dates.spec.js +0 -276
  123. data/spec/js/defaults.spec.js +0 -31
  124. data/spec/js/extend.spec.js +0 -110
  125. data/spec/js/interpolation.spec.js +0 -124
  126. data/spec/js/jasmine/MIT.LICENSE +0 -20
  127. data/spec/js/jasmine/jasmine-html.js +0 -190
  128. data/spec/js/jasmine/jasmine.css +0 -166
  129. data/spec/js/jasmine/jasmine.js +0 -2476
  130. data/spec/js/jasmine/jasmine_favicon.png +0 -0
  131. data/spec/js/json_parsable.spec.js +0 -14
  132. data/spec/js/locales.spec.js +0 -31
  133. data/spec/js/localization.spec.js +0 -78
  134. data/spec/js/numbers.spec.js +0 -174
  135. data/spec/js/placeholder.spec.js +0 -24
  136. data/spec/js/pluralization.spec.js +0 -228
  137. data/spec/js/prepare_options.spec.js +0 -41
  138. data/spec/js/require.js +0 -2083
  139. data/spec/js/specs.html +0 -49
  140. data/spec/js/specs_requirejs.html +0 -72
  141. data/spec/js/translate.spec.js +0 -304
  142. data/spec/js/translations.js +0 -188
  143. data/spec/js/utility_functions.spec.js +0 -20
  144. data/spec/ruby/i18n/js/fallback_locales_spec.rb +0 -84
  145. data/spec/ruby/i18n/js/segment_spec.rb +0 -286
  146. data/spec/ruby/i18n/js/utils_spec.rb +0 -138
  147. data/spec/ruby/i18n/js_spec.rb +0 -797
  148. data/spec/spec_helper.rb +0 -80
  149. data/yarn.lock +0 -138
@@ -1,84 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe I18n::JS::FallbackLocales do
4
- let(:locale) { :fr }
5
- let(:default_locale) { :en }
6
-
7
- describe "#locales" do
8
- let(:fallbacks_locales) { described_class.new(fallbacks, locale) }
9
- subject { fallbacks_locales.locales }
10
-
11
- let(:fetching_locales) { proc do fallbacks_locales.locales end }
12
-
13
- context "when given true as fallbacks" do
14
- let(:fallbacks) { true }
15
- it { should eq([default_locale]) }
16
- end
17
-
18
- context "when given false as fallbacks" do
19
- let(:fallbacks) { false }
20
- it { expect(fetching_locales).to raise_error(ArgumentError) }
21
- end
22
-
23
- context "when given a valid locale as fallbacks" do
24
- let(:fallbacks) { :de }
25
- it { should eq([:de]) }
26
- end
27
-
28
- context "when given a valid Array as fallbacks" do
29
- let(:fallbacks) { [:de, :en] }
30
- it { should eq([:de, :en]) }
31
- end
32
-
33
- context "when given a valid Hash with current locale as key as fallbacks" do
34
- let(:fallbacks) do { :fr => [:de, :en] } end
35
- it { should eq([:de, :en]) }
36
- end
37
-
38
- context "when given a valid Hash without current locale as key as fallbacks" do
39
- let(:fallbacks) do { :de => [:fr, :en] } end
40
- it { should eq([default_locale]) }
41
- end
42
-
43
- context "when given a invalid locale as fallbacks" do
44
- let(:fallbacks) { :invalid_locale }
45
- it { should eq([:invalid_locale]) }
46
- end
47
-
48
- context "when given a invalid type as fallbacks" do
49
- let(:fallbacks) { 42 }
50
- it { expect(fetching_locales).to raise_error(ArgumentError) }
51
- end
52
-
53
- # I18n::Backend::Fallbacks
54
- context "when I18n::Backend::Fallbacks is used" do
55
- let(:backend_with_fallbacks) { backend_class_with_fallbacks.new }
56
-
57
- before do
58
- I18n::JS.backend = backend_with_fallbacks
59
- I18n.fallbacks[:fr] = [:de, :en]
60
- end
61
- after { I18n::JS.backend = I18n::Backend::Simple.new }
62
-
63
- context "given true as fallbacks" do
64
- let(:fallbacks) { true }
65
- it { should eq([:de, :en]) }
66
- end
67
-
68
- context "given :default_locale as fallbacks" do
69
- let(:fallbacks) { :default_locale }
70
- it { should eq([:en]) }
71
- end
72
-
73
- context "given a Hash with current locale as fallbacks" do
74
- let(:fallbacks) do { :fr => [:en] } end
75
- it { should eq([:en]) }
76
- end
77
-
78
- context "given a Hash without current locale as fallbacks" do
79
- let(:fallbacks) do { :de => [:en] } end
80
- it { should eq([:de, :en]) }
81
- end
82
- end
83
- end
84
- end
@@ -1,286 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe I18n::JS::Segment do
4
-
5
- let(:file) { "tmp/i18n-js/segment.js" }
6
- let(:translations){ { en: { "test" => "Test" }, fr: { "test" => "Test2" } } }
7
- let(:namespace) { "MyNamespace" }
8
- let(:pretty_print){ nil }
9
- let(:json_only) { nil }
10
- let(:js_extend) { nil }
11
- let(:sort_translation_keys){ nil }
12
- let(:options) { { namespace: namespace,
13
- pretty_print: pretty_print,
14
- json_only: json_only,
15
- js_extend: js_extend,
16
- sort_translation_keys: sort_translation_keys }.delete_if{|k,v| v.nil?} }
17
- subject { I18n::JS::Segment.new(file, translations, options) }
18
-
19
- describe ".new" do
20
-
21
- it "should persist the file path variable" do
22
- expect(subject.file).to eql("tmp/i18n-js/segment.js")
23
- end
24
-
25
- it "should persist the translations variable" do
26
- expect(subject.translations).to eql(translations)
27
- end
28
-
29
- it "should persist the namespace variable" do
30
- expect(subject.namespace).to eql("MyNamespace")
31
- end
32
-
33
- context "when namespace is nil" do
34
- let(:namespace){ nil }
35
-
36
- it "should default namespace to `I18n`" do
37
- expect(subject.namespace).to eql("I18n")
38
- end
39
- end
40
-
41
- context "when namespace is not set" do
42
- subject { I18n::JS::Segment.new(file, translations) }
43
-
44
- it "should default namespace to `I18n`" do
45
- expect(subject.namespace).to eql("I18n")
46
- end
47
- end
48
-
49
- context "when pretty_print is nil" do
50
- it "should set pretty_print to false" do
51
- expect(subject.pretty_print).to be false
52
- end
53
- end
54
-
55
- context "when pretty_print is truthy" do
56
- let(:pretty_print){ 1 }
57
-
58
- it "should set pretty_print to true" do
59
- expect(subject.pretty_print).to be true
60
- end
61
- end
62
- end
63
-
64
- describe "#saving!" do
65
- before { allow(I18n::JS).to receive(:export_i18n_js_dir_path).and_return(temp_path) }
66
-
67
- context "when json_only is true with locale" do
68
- let(:file){ "tmp/i18n-js/%{locale}.js" }
69
- let(:json_only){ true }
70
-
71
- it 'should output JSON files per locale' do
72
- subject.save!
73
- file_should_exist "en.js"
74
- file_should_exist "fr.js"
75
-
76
- expect(File.read(File.join(temp_path, "en.js"))).to eql(
77
- %Q({"en":{"test":"Test"}})
78
- )
79
-
80
- expect(File.read(File.join(temp_path, "fr.js"))).to eql(
81
- %Q({"fr":{"test":"Test2"}})
82
- )
83
- end
84
- end
85
-
86
- context "when json_only is true without locale" do
87
- let(:file){ "tmp/i18n-js/segment.js" }
88
- let(:json_only){ true }
89
-
90
- it 'should output one JSON file for all locales' do
91
- subject.save!
92
- file_should_exist "segment.js"
93
-
94
- expect(File.read(File.join(temp_path, "segment.js"))).to eql(
95
- %Q({"en":{"test":"Test"},"fr":{"test":"Test2"}})
96
- )
97
- end
98
- end
99
-
100
- context "when json_only and pretty print are true" do
101
- let(:file){ "tmp/i18n-js/segment.js" }
102
- let(:json_only){ true }
103
- let(:pretty_print){ true }
104
-
105
- it 'should output one JSON file for all locales' do
106
- subject.save!
107
- file_should_exist "segment.js"
108
-
109
- expect(File.read(File.join(temp_path, "segment.js"))).to eql <<-EOS
110
- {
111
- "en": {
112
- "test": "Test"
113
- },
114
- "fr": {
115
- "test": "Test2"
116
- }
117
- }
118
- EOS
119
- .chomp
120
- end
121
- end
122
- end
123
-
124
- describe "#save!" do
125
- before { allow(I18n::JS).to receive(:export_i18n_js_dir_path).and_return(temp_path) }
126
- before { subject.save! }
127
-
128
- context "when file does not include %{locale}" do
129
- it "should write the file" do
130
- file_should_exist "segment.js"
131
-
132
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
133
- MyNamespace.translations || (MyNamespace.translations = {});
134
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"test":"Test"}'));
135
- MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"test":"Test2"}'));
136
- EOF
137
- end
138
- end
139
-
140
- context "when file includes %{locale}" do
141
- let(:file){ "tmp/i18n-js/%{locale}.js" }
142
-
143
- it "should write files" do
144
- file_should_exist "en.js"
145
- file_should_exist "fr.js"
146
-
147
- expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
148
- MyNamespace.translations || (MyNamespace.translations = {});
149
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"test":"Test"}'));
150
- EOF
151
-
152
- expect(File.open(File.join(temp_path, "fr.js")){|f| f.read}).to eql <<-EOF
153
- MyNamespace.translations || (MyNamespace.translations = {});
154
- MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"test":"Test2"}'));
155
- EOF
156
- end
157
- end
158
-
159
- context "when file includes single quote" do
160
- let(:file){ "tmp/i18n-js/%{locale}.js" }
161
- let(:translations){ { en: { "a" => "Test's" } } }
162
-
163
- it "should write files" do
164
- file_should_exist "en.js"
165
-
166
- expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
167
- MyNamespace.translations || (MyNamespace.translations = {});
168
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test\\'s"}'));
169
- EOF
170
- end
171
- end
172
-
173
- context "when file includes escaped double quote" do
174
- let(:file){ "tmp/i18n-js/%{locale}.js" }
175
- let(:translations){ { en: { "a" => 'say "hello"' } } }
176
-
177
- it "should escape double quote" do
178
- file_should_exist "en.js"
179
-
180
- expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
181
- MyNamespace.translations || (MyNamespace.translations = {});
182
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"say \\\\"hello\\\\""}'));
183
- EOF
184
- end
185
- end
186
-
187
- context "when file includes backslash in double quote" do
188
- let(:file){ "tmp/i18n-js/%{locale}.js" }
189
- let(:translations){ { en: { "double-backslash-in-double-quote" => '"\\\\"' } } }
190
-
191
- it "should escape backslash" do
192
- file_should_exist "en.js"
193
-
194
- expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
195
- MyNamespace.translations || (MyNamespace.translations = {});
196
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"double-backslash-in-double-quote":"\\\\"\\\\\\\\\\\\\\\\\\\\""}'));
197
- EOF
198
- end
199
- end
200
-
201
- context "when js_extend is true" do
202
- let(:js_extend){ true }
203
-
204
- let(:translations){ { en: { "b" => "Test", "a" => "Test" } } }
205
-
206
- it 'should output the keys as sorted' do
207
- file_should_exist "segment.js"
208
-
209
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
210
- MyNamespace.translations || (MyNamespace.translations = {});
211
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test","b":"Test"}'));
212
- EOF
213
- end
214
- end
215
-
216
- context "when js_extend is false" do
217
- let(:js_extend){ false }
218
-
219
- let(:translations){ { en: { "b" => "Test", "a" => "Test" } } }
220
-
221
- it 'should output the keys as sorted' do
222
- file_should_exist "segment.js"
223
-
224
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
225
- MyNamespace.translations || (MyNamespace.translations = {});
226
- MyNamespace.translations["en"] = JSON.parse('{"a":"Test","b":"Test"}');
227
- EOF
228
- end
229
- end
230
-
231
- context "when sort_translation_keys is true" do
232
- let(:sort_translation_keys){ true }
233
-
234
- let(:translations){ { en: { "b" => "Test", "a" => "Test" } } }
235
-
236
- it 'should output the keys as sorted' do
237
- file_should_exist "segment.js"
238
-
239
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
240
- MyNamespace.translations || (MyNamespace.translations = {});
241
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test","b":"Test"}'));
242
- EOF
243
- end
244
- end
245
-
246
- context "when sort_translation_keys is false" do
247
- let(:sort_translation_keys){ false }
248
-
249
- let(:translations){ { en: { "b" => "Test", "a" => "Test" } } }
250
-
251
- it 'should output the keys as sorted' do
252
- file_should_exist "segment.js"
253
-
254
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
255
- MyNamespace.translations || (MyNamespace.translations = {});
256
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"b":"Test","a":"Test"}'));
257
- EOF
258
- end
259
- end
260
-
261
- context "when translation entries contain procs" do
262
- let(:translations) do
263
- {
264
- en: {
265
- "test" => "Test",
266
- "i18n" => {"plural" => {"rule" => proc {} }},
267
- },
268
- fr: {
269
- "test" => "Test2",
270
- "i18n" => {"plural" => {"rule" => proc {} }},
271
- },
272
- }
273
- end
274
-
275
- it "should write files without procs or their string representations" do
276
- file_should_exist "segment.js"
277
-
278
- expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
279
- MyNamespace.translations || (MyNamespace.translations = {});
280
- MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"i18n":{"plural":{}},"test":"Test"}'));
281
- MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"i18n":{"plural":{}},"test":"Test2"}'));
282
- EOF
283
- end
284
- end
285
- end
286
- end
@@ -1,138 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe I18n::JS::Utils do
4
-
5
- describe ".strip_keys_with_nil_values" do
6
- subject { described_class.strip_keys_with_nil_values(input_hash) }
7
-
8
- context 'when input_hash does NOT contain nil value' do
9
- let(:input_hash) { {a: 1, b: { c: 2 }} }
10
- let(:expected_hash) { input_hash }
11
-
12
- it 'returns the original input' do
13
- is_expected.to eq expected_hash
14
- end
15
- end
16
- context 'when input_hash does contain nil value' do
17
- let(:input_hash) { {a: 1, b: { c: 2, d: nil }, e: { f: nil }} }
18
- let(:expected_hash) { {a: 1, b: { c: 2 }, e: {}} }
19
-
20
- it 'returns the original input with nil values removed' do
21
- is_expected.to eq expected_hash
22
- end
23
- end
24
- end
25
-
26
- context "hash merging" do
27
- it "performs a deep merge" do
28
- target = {:a => {:b => 1}}
29
- result = described_class.deep_merge(target, {:a => {:c => 2}})
30
-
31
- expect(result[:a]).to eql({:b => 1, :c => 2})
32
- end
33
-
34
- it "performs a banged deep merge" do
35
- target = {:a => {:b => 1}}
36
- described_class.deep_merge!(target, {:a => {:c => 2}})
37
-
38
- expect(target[:a]).to eql({:b => 1, :c => 2})
39
- end
40
- end
41
-
42
- describe ".deep_reject" do
43
- it "performs a deep keys rejection" do
44
- hash = {:a => {:b => 1}}
45
-
46
- result = described_class.deep_reject(hash) { |k, v| k == :b }
47
-
48
- expect(result).to eql({:a => {}})
49
- end
50
-
51
- it "performs a deep keys rejection prunning the whole tree if necessary" do
52
- hash = {:a => {:b => {:c => {:d => 1, :e => 2}}}}
53
-
54
- result = described_class.deep_reject(hash) { |k, v| k == :b }
55
-
56
- expect(result).to eql({:a => {}})
57
- end
58
-
59
-
60
- it "performs a deep keys rejection without changing the original hash" do
61
- hash = {:a => {:b => 1, :c => 2}}
62
-
63
- result = described_class.deep_reject(hash) { |k, v| k == :b }
64
-
65
- expect(result).to eql({:a => {:c => 2}})
66
- expect(hash).to eql({:a => {:b => 1, :c => 2}})
67
- end
68
- end
69
-
70
- describe ".deep_key_sort" do
71
- let(:unsorted_hash) { {:z => {:b => 1, :a => 2}, :y => 3} }
72
- subject(:sorting) { described_class.deep_key_sort(unsorted_hash) }
73
-
74
- it "performs a deep keys sort without changing the original hash" do
75
- should eql({:y => 3, :z => {:a => 2, :b => 1}})
76
- expect(unsorted_hash).to eql({:z => {:b => 1, :a => 2}, :y => 3})
77
- end
78
-
79
- # Idea from gem `rails_admin`
80
- context "when hash contain non-Symbol as key" do
81
- let(:unsorted_hash) { {:z => {1 => 1, true => 2}, :y => 3} }
82
-
83
- it "performs a deep keys sort without error" do
84
- expect{ sorting }.to_not raise_error
85
- end
86
- it "converts keys to symbols" do
87
- should eql({:y => 3, :z => {1 => 1, true => 2}})
88
- end
89
- end
90
- end
91
-
92
- describe ".scopes_match?" do
93
- it "performs a comparison of literal scopes" do
94
- expect(described_class.scopes_match?([:a, :b], [:a, :b, :c])).to_not eql true
95
- expect(described_class.scopes_match?([:a, :b, :c], [:a, :b, :c])).to eql true
96
- expect(described_class.scopes_match?([:a, :b, :c], [:a, :b, :d])).to_not eql true
97
- end
98
-
99
- it "performs a comparison of wildcard scopes" do
100
- expect(described_class.scopes_match?([:a, '*'], [:a, :b, :c])).to_not eql true
101
- expect(described_class.scopes_match?([:a, '*', :c], [:a, :b, :c])).to eql true
102
- expect(described_class.scopes_match?([:a, :b, :c], [:a, '*', :c])).to eql true
103
- expect(described_class.scopes_match?([:a, :b, :c], [:a, '*', '*'])).to eql true
104
- end
105
- end
106
-
107
- describe ".deep_remove_procs" do
108
- let(:proc_obj) { proc {} }
109
- let(:hash_with_proc) do
110
- {
111
- :a => :b,
112
- :c => proc_obj,
113
- :d => {
114
- :e => proc_obj,
115
- :f => :g,
116
- }
117
- }
118
- end
119
- subject { described_class.deep_remove_procs(hash_with_proc) }
120
-
121
- it "performs a deep keys sort without changing the original hash" do
122
- should eql({
123
- :a => :b,
124
- :d => {
125
- :f => :g,
126
- }
127
- })
128
- expect(hash_with_proc).to eql({
129
- :a => :b,
130
- :c => proc_obj,
131
- :d => {
132
- :e => proc_obj,
133
- :f => :g,
134
- }
135
- })
136
- end
137
- end
138
- end