i18n_flow 0.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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +13 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +45 -0
  8. data/LICENSE +22 -0
  9. data/README.md +103 -0
  10. data/Rakefile +2 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/doc/rules.md +316 -0
  14. data/doc/tags.md +488 -0
  15. data/example/example.en.yml +14 -0
  16. data/example/example.ja.yml +9 -0
  17. data/exe/i18n_flow +11 -0
  18. data/i18n_flow.gemspec +28 -0
  19. data/i18n_flow.yml +8 -0
  20. data/lib/i18n_flow/cli/color.rb +18 -0
  21. data/lib/i18n_flow/cli/command_base.rb +33 -0
  22. data/lib/i18n_flow/cli/copy_command.rb +69 -0
  23. data/lib/i18n_flow/cli/help_command.rb +29 -0
  24. data/lib/i18n_flow/cli/lint_command/ascii.erb +45 -0
  25. data/lib/i18n_flow/cli/lint_command/ascii_renderer.rb +58 -0
  26. data/lib/i18n_flow/cli/lint_command/markdown.erb +49 -0
  27. data/lib/i18n_flow/cli/lint_command/markdown_renderer.rb +55 -0
  28. data/lib/i18n_flow/cli/lint_command.rb +55 -0
  29. data/lib/i18n_flow/cli/read_config_command.rb +20 -0
  30. data/lib/i18n_flow/cli/search_command/default.erb +11 -0
  31. data/lib/i18n_flow/cli/search_command/default_renderer.rb +67 -0
  32. data/lib/i18n_flow/cli/search_command/oneline.erb +5 -0
  33. data/lib/i18n_flow/cli/search_command/oneline_renderer.rb +39 -0
  34. data/lib/i18n_flow/cli/search_command.rb +59 -0
  35. data/lib/i18n_flow/cli/split_command.rb +20 -0
  36. data/lib/i18n_flow/cli/version_command.rb +9 -0
  37. data/lib/i18n_flow/cli.rb +42 -0
  38. data/lib/i18n_flow/configuration.rb +205 -0
  39. data/lib/i18n_flow/parser.rb +34 -0
  40. data/lib/i18n_flow/repository.rb +39 -0
  41. data/lib/i18n_flow/search.rb +176 -0
  42. data/lib/i18n_flow/splitter/merger.rb +60 -0
  43. data/lib/i18n_flow/splitter/strategy.rb +66 -0
  44. data/lib/i18n_flow/splitter.rb +5 -0
  45. data/lib/i18n_flow/util.rb +57 -0
  46. data/lib/i18n_flow/validator/errors.rb +99 -0
  47. data/lib/i18n_flow/validator/file_scope.rb +58 -0
  48. data/lib/i18n_flow/validator/multiplexer.rb +58 -0
  49. data/lib/i18n_flow/validator/symmetry.rb +154 -0
  50. data/lib/i18n_flow/validator.rb +4 -0
  51. data/lib/i18n_flow/version.rb +7 -0
  52. data/lib/i18n_flow/yaml_ast_proxy/mapping.rb +72 -0
  53. data/lib/i18n_flow/yaml_ast_proxy/node.rb +128 -0
  54. data/lib/i18n_flow/yaml_ast_proxy/node_meta_data.rb +86 -0
  55. data/lib/i18n_flow/yaml_ast_proxy/sequence.rb +29 -0
  56. data/lib/i18n_flow/yaml_ast_proxy.rb +57 -0
  57. data/lib/i18n_flow.rb +15 -0
  58. data/spec/lib/i18n_flow/cli/command_base_spec.rb +46 -0
  59. data/spec/lib/i18n_flow/cli/help_command_spec.rb +13 -0
  60. data/spec/lib/i18n_flow/cli/version_command_spec.rb +13 -0
  61. data/spec/lib/i18n_flow/configuration_spec.rb +334 -0
  62. data/spec/lib/i18n_flow/repository_spec.rb +40 -0
  63. data/spec/lib/i18n_flow/splitter/merger_spec.rb +149 -0
  64. data/spec/lib/i18n_flow/util_spec.rb +194 -0
  65. data/spec/lib/i18n_flow/validator/file_scope_spec.rb +74 -0
  66. data/spec/lib/i18n_flow/validator/multiplexer_spec.rb +68 -0
  67. data/spec/lib/i18n_flow/validator/symmetry_spec.rb +511 -0
  68. data/spec/lib/i18n_flow/yaml_ast_proxy/node_spec.rb +151 -0
  69. data/spec/lib/i18n_flow_spec.rb +21 -0
  70. data/spec/spec_helper.rb +16 -0
  71. data/spec/support/repository_examples.rb +60 -0
  72. data/spec/support/util_macro.rb +14 -0
  73. metadata +214 -0
@@ -0,0 +1,57 @@
1
+ require 'psych'
2
+ require_relative 'yaml_ast_proxy/node'
3
+ require_relative 'yaml_ast_proxy/mapping'
4
+ require_relative 'yaml_ast_proxy/sequence'
5
+
6
+ module I18nFlow::YamlAstProxy
7
+ def self.create(node, parent: nil, scopes: [], file_path: nil)
8
+ case node
9
+ when NilClass
10
+ nil
11
+ when Node
12
+ if node.parent == parent \
13
+ && node.scopes == scopes \
14
+ && node.file_path == file_path
15
+ node
16
+ else
17
+ node.class.new(node.node,
18
+ parent: parent,
19
+ scopes: scopes,
20
+ file_path: file_path,
21
+ )
22
+ end
23
+ when Psych::Nodes::Stream, Psych::Nodes::Document
24
+ Node.new(node.children.first,
25
+ parent: node,
26
+ scopes: scopes,
27
+ file_path: file_path,
28
+ )
29
+ when Psych::Nodes::Mapping
30
+ Mapping.new(node,
31
+ parent: parent,
32
+ scopes: scopes,
33
+ file_path: file_path,
34
+ )
35
+ when Psych::Nodes::Sequence
36
+ Sequence.new(node,
37
+ parent: parent,
38
+ scopes: scopes,
39
+ file_path: file_path,
40
+ )
41
+ else
42
+ Node.new(node,
43
+ parent: parent,
44
+ scopes: scopes,
45
+ file_path: file_path,
46
+ )
47
+ end
48
+ end
49
+
50
+ def self.new_root
51
+ doc = Psych::Nodes::Document.new([], [], true)
52
+ doc.children << Psych::Nodes::Mapping.new
53
+ stream = Psych::Nodes::Stream.new
54
+ stream.children << doc
55
+ create(stream)
56
+ end
57
+ end
data/lib/i18n_flow.rb ADDED
@@ -0,0 +1,15 @@
1
+ module I18nFlow
2
+ extend self
3
+
4
+ def config
5
+ @config ||= Configuration.new
6
+ end
7
+
8
+ def configure(&block)
9
+ config.update(&block)
10
+ end
11
+ end
12
+
13
+ require_relative 'i18n_flow/version'
14
+ require_relative 'i18n_flow/configuration'
15
+ require_relative 'i18n_flow/validator'
@@ -0,0 +1,46 @@
1
+ require 'i18n_flow/cli/command_base'
2
+
3
+ describe I18nFlow::CLI::CommandBase do
4
+ let(:command) { I18nFlow::CLI::CommandBase.new([]) }
5
+
6
+ describe '#invoke!' do
7
+ it 'should raise a not implemented error' do
8
+ expect {
9
+ command.invoke!
10
+ }.to raise_error(/implemented/)
11
+ end
12
+ end
13
+
14
+ describe '#exit_with_message' do
15
+ let(:message) { 'a message' }
16
+ let(:message_regexp) { /a message/ }
17
+
18
+ context 'With status code of zero' do
19
+ let(:status) { 0 }
20
+
21
+ it 'should print a message to stdout and exit' do
22
+ expect {
23
+ begin
24
+ command.exit_with_message(status, message)
25
+ rescue SystemExit => e
26
+ expect(e.status).to eq(status)
27
+ end
28
+ }.to output(message_regexp).to_stdout
29
+ end
30
+ end
31
+
32
+ context 'With status code of non-zero' do
33
+ let(:status) { 1 }
34
+
35
+ it 'should print a message to stderr and exit' do
36
+ expect {
37
+ begin
38
+ command.exit_with_message(status, message)
39
+ rescue SystemExit => e
40
+ expect(e.status).to eq(status)
41
+ end
42
+ }.to output(message_regexp).to_stderr
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ require 'i18n_flow/cli/help_command'
2
+
3
+ describe I18nFlow::CLI::HelpCommand do
4
+ let(:command) { I18nFlow::CLI::HelpCommand.new([]) }
5
+
6
+ describe '#invoke!' do
7
+ it 'should print help' do
8
+ expect {
9
+ command.invoke!
10
+ }.to output(/Usage/).to_stdout
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'i18n_flow/cli/version_command'
2
+
3
+ describe I18nFlow::CLI::VersionCommand do
4
+ let(:command) { I18nFlow::CLI::VersionCommand.new([]) }
5
+
6
+ describe '#invoke!' do
7
+ it 'should print gem version' do
8
+ expect {
9
+ command.invoke!
10
+ }.to output(/v\d+\.\d+.\d+/).to_stdout
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,334 @@
1
+ require 'i18n_flow/configuration'
2
+
3
+ describe I18nFlow::Configuration do
4
+ let(:configuration) { I18nFlow::Configuration.new }
5
+
6
+ describe '.new' do
7
+ let(:options) do
8
+ %i[
9
+ base_path
10
+ glob_patterns
11
+ valid_locales
12
+ locale_pairs
13
+ split_max_level
14
+ split_line_threshold
15
+ ]
16
+ end
17
+
18
+ it 'should set default values' do
19
+ options.each do |option|
20
+ expect(configuration.respond_to?(option)).to be(true)
21
+ expect(configuration.send(option)).not_to be_nil
22
+ end
23
+ end
24
+ end
25
+
26
+ describe '#base_path, #base_path=' do
27
+ it 'should return an instance of Pathname' do
28
+ expect(configuration.base_path).to be_a(Pathname)
29
+ end
30
+
31
+ it 'should store an instance of Pathname from a string in the setter' do
32
+ path = 'foo/bar'
33
+
34
+ expect {
35
+ configuration.base_path = path
36
+ }.not_to raise_error
37
+
38
+ expect(configuration.base_path).to be_a(Pathname)
39
+ expect(configuration.base_path.to_s).to eq(path)
40
+ end
41
+ end
42
+
43
+ describe '#glob_patterns, #glob_patterns=' do
44
+ it 'should return an array' do
45
+ expect(configuration.glob_patterns).to be_a(Array)
46
+ end
47
+
48
+ it 'should store the given value as an array of strings in the setter' do
49
+ expect {
50
+ configuration.glob_patterns = [:'foo.yml']
51
+ }.not_to raise_error
52
+
53
+ expect(configuration.glob_patterns).to eq(['foo.yml'])
54
+ end
55
+ end
56
+
57
+ describe '#valid_locales, #valid_locales=' do
58
+ it 'should return an array' do
59
+ expect(configuration.valid_locales).to be_a(Array)
60
+ end
61
+
62
+ it 'should store the given value as an array of strings in the setter' do
63
+ expect {
64
+ configuration.valid_locales = [:en]
65
+ }.not_to raise_error
66
+
67
+ expect(configuration.valid_locales).to eq(['en'])
68
+ end
69
+ end
70
+
71
+ describe '#locale_pairs, #locale_pairs=' do
72
+ it 'should return an array' do
73
+ expect(configuration.locale_pairs).to be_a(Array)
74
+ end
75
+
76
+ it 'should store the given value as an array of strings in the setter' do
77
+ expect {
78
+ configuration.locale_pairs = [[:en, :ja]]
79
+ }.not_to raise_error
80
+
81
+ expect(configuration.locale_pairs).to eq([['en', 'ja']])
82
+ end
83
+ end
84
+
85
+ describe '#linters, #linters=' do
86
+ it 'should return an array' do
87
+ expect(configuration.linters).to be_a(Array)
88
+ end
89
+
90
+ it 'should store the given value as an array of symbols in the setter' do
91
+ expect {
92
+ configuration.linters = ['foo', 'bar']
93
+ }.not_to raise_error
94
+
95
+ expect(configuration.linters).to eq([:foo, :bar])
96
+ end
97
+ end
98
+
99
+ describe '#validate!' do
100
+ context 'base_path' do
101
+ it 'should raise an error if it is a relative path' do
102
+ configuration.base_path = 'relative/path'
103
+
104
+ expect {
105
+ configuration.validate!
106
+ }.to raise_error(/base_path/)
107
+ end
108
+
109
+ it 'should not raise if it is a absolute path' do
110
+ configuration.base_path = '/absolute/path'
111
+
112
+ expect {
113
+ configuration.validate!
114
+ }.not_to raise_error
115
+ end
116
+ end
117
+
118
+ context 'glob_patterns' do
119
+ it 'should raise an error if it is not an array' do
120
+ configuration.glob_patterns = ''
121
+
122
+ expect {
123
+ configuration.validate!
124
+ }.to raise_error(/glob_patterns/)
125
+ end
126
+
127
+ it 'should raise an error if it is empty' do
128
+ configuration.glob_patterns = []
129
+
130
+ expect {
131
+ configuration.validate!
132
+ }.to raise_error(/glob_patterns/)
133
+ end
134
+
135
+ it 'should not raise if it is an array' do
136
+ configuration.glob_patterns = ['*.yml']
137
+
138
+ expect {
139
+ configuration.validate!
140
+ }.not_to raise_error
141
+ end
142
+ end
143
+
144
+ context 'locale_pairs' do
145
+ it 'should raise an error if it is blank' do
146
+ configuration.locale_pairs = ''
147
+
148
+ expect {
149
+ configuration.validate!
150
+ }.to raise_error(/locale_pairs/)
151
+ end
152
+
153
+ it 'should raise if it is not an array of pair' do
154
+ configuration.locale_pairs = [['en']]
155
+
156
+ expect {
157
+ configuration.validate!
158
+ }.to raise_error(/locale_pairs/)
159
+ end
160
+
161
+ it 'should not raise if it is an array' do
162
+ configuration.locale_pairs = [['en', 'ja']]
163
+
164
+ expect {
165
+ configuration.validate!
166
+ }.not_to raise_error
167
+ end
168
+ end
169
+
170
+ context 'linters' do
171
+ it 'should raise an error if it is blank' do
172
+ configuration.linters = ''
173
+
174
+ expect {
175
+ configuration.validate!
176
+ }.to raise_error(/linters/)
177
+ end
178
+
179
+ it 'should raise if the element contains invalid value' do
180
+ configuration.linters = [:foo]
181
+
182
+ expect {
183
+ configuration.validate!
184
+ }.to raise_error(/linters/)
185
+ end
186
+
187
+ it 'should not raise if it is valid' do
188
+ configuration.linters = [:file_scope]
189
+
190
+ expect {
191
+ configuration.validate!
192
+ }.not_to raise_error
193
+ end
194
+ end
195
+
196
+ context 'valid_locales' do
197
+ it 'should raise an error if it is not an array' do
198
+ configuration.valid_locales = ''
199
+
200
+ expect {
201
+ configuration.validate!
202
+ }.to raise_error(/valid_locales/)
203
+ end
204
+
205
+ it 'should raise an error if it is empty' do
206
+ configuration.valid_locales = []
207
+
208
+ expect {
209
+ configuration.validate!
210
+ }.to raise_error(/valid_locales/)
211
+ end
212
+
213
+ it 'should not raise if eligible' do
214
+ configuration.valid_locales = [:en]
215
+
216
+ expect {
217
+ configuration.validate!
218
+ }.not_to raise_error
219
+ end
220
+ end
221
+
222
+ context 'split_max_level' do
223
+ it 'should raise an error if it is not an integer' do
224
+ configuration.split_max_level = 'foo'
225
+
226
+ expect {
227
+ configuration.validate!
228
+ }.to raise_error(/split_max_level/)
229
+ end
230
+
231
+ it 'should not raise if it is an integer' do
232
+ configuration.split_max_level = 123
233
+
234
+ expect {
235
+ configuration.validate!
236
+ }.not_to raise_error
237
+ end
238
+ end
239
+
240
+ context 'split_line_threshold' do
241
+ it 'should raise an error if it is not an integer' do
242
+ configuration.split_line_threshold = 'foo'
243
+
244
+ expect {
245
+ configuration.validate!
246
+ }.to raise_error(/split_line_threshold/)
247
+ end
248
+
249
+ it 'should not raise if it is an integer' do
250
+ configuration.split_line_threshold = 123
251
+
252
+ expect {
253
+ configuration.validate!
254
+ }.not_to raise_error
255
+ end
256
+ end
257
+ end
258
+
259
+ context 'auto config' do
260
+ describe '#auto_configure!' do
261
+ it 'should call `load_from_file!` and `update`' do
262
+ allow(configuration).to receive(:load_from_file!).and_return(true)
263
+ allow(configuration).to receive(:update).and_return(true)
264
+
265
+ expect(configuration).to receive(:load_from_file!).once.ordered
266
+ expect(configuration).to receive(:update).once.ordered
267
+
268
+ configuration.auto_configure!
269
+ end
270
+ end
271
+
272
+ describe '#load_from_file!' do
273
+ let(:pwd) { '/path/to/pwd' }
274
+ let(:yaml_file_path) { '/path/to/i18n_flow.yml' }
275
+
276
+ let(:yaml_file) do
277
+ FakeFS::FakeFile.new.tap do |f|
278
+ f.content = <<-YAML
279
+ glob_patterns:
280
+ - 'config/locales/**/*.yml'
281
+ locale_pairs:
282
+ - ['en', 'ja']
283
+ valid_locales:
284
+ - 'ja'
285
+ - 'en'
286
+ YAML
287
+ end
288
+ end
289
+
290
+ before do
291
+ FakeFS::FileSystem.add(pwd)
292
+ Dir.chdir(pwd)
293
+ end
294
+
295
+ it 'should raise an error if no file is found' do
296
+ expect {
297
+ configuration.send(:load_from_file!)
298
+ }.to raise_error(I18nFlow::Configuration::NoConfigurationFileFoundError)
299
+ end
300
+
301
+ it 'should set `base_path` to the directory of yaml file' do
302
+ FakeFS::FileSystem.add(yaml_file_path, yaml_file)
303
+
304
+ expect {
305
+ configuration.send(:load_from_file!)
306
+ }.not_to raise_error
307
+
308
+ expect(configuration.base_path).to eq(Pathname.new(File.dirname(yaml_file_path)))
309
+ end
310
+
311
+ it 'should set other option values from yaml' do
312
+ FakeFS::FileSystem.add(yaml_file_path, yaml_file)
313
+
314
+ expect {
315
+ configuration.send(:load_from_file!)
316
+ }.not_to raise_error
317
+
318
+ expect(configuration.locale_pairs).to eq([['en', 'ja']])
319
+ expect(configuration.valid_locales).to eq(['ja', 'en'])
320
+ end
321
+
322
+ it 'should raise an error if there is invalid option in yaml' do
323
+ FakeFS::FileSystem.add(yaml_file_path, yaml_file)
324
+ yaml_file.content = <<-YAML
325
+ foo: true
326
+ YAML
327
+
328
+ expect {
329
+ configuration.send(:load_from_file!)
330
+ }.to raise_error(KeyError, /foo/)
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,40 @@
1
+ require 'i18n_flow/repository'
2
+
3
+ describe I18nFlow::Repository do
4
+ include_examples :create_repository
5
+
6
+ describe '#file_paths' do
7
+ it 'should return an array of matched file paths' do
8
+ expect(repository.file_paths).to match_array([
9
+ '/fixtures/models/user.en.yml',
10
+ '/fixtures/models/user.ja.yml',
11
+ '/fixtures/views/profiles/show.en.yml',
12
+ '/fixtures/views/profiles/show.ja.yml',
13
+ '/fixtures/views/profiles/show.fr.yml',
14
+ ])
15
+ end
16
+ end
17
+
18
+ describe '#asts_by_path' do
19
+ it 'should return a hash of tree indexed by (relative) file paths' do
20
+ expect(repository.asts_by_path.keys).to match_array([
21
+ 'models/user.en.yml',
22
+ 'models/user.ja.yml',
23
+ 'views/profiles/show.en.yml',
24
+ 'views/profiles/show.ja.yml',
25
+ 'views/profiles/show.fr.yml',
26
+ ])
27
+ end
28
+ end
29
+
30
+ describe '#asts_by_scope' do
31
+ it 'should return a hash of tree indexed by scopes' do
32
+ expect(repository.asts_by_scope.keys).to match_array([
33
+ 'models.user',
34
+ 'views.profiles.show',
35
+ ])
36
+ expect(repository.asts_by_scope['models.user'].keys).to match_array(['en', 'ja'])
37
+ expect(repository.asts_by_scope['views.profiles.show'].keys).to match_array(['en', 'ja', 'fr'])
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,149 @@
1
+ require 'i18n_flow/splitter/merger'
2
+
3
+ describe I18nFlow::Splitter::Merger do
4
+ let(:merger) { I18nFlow::Splitter::Merger.new([]) }
5
+
6
+ describe '#perform_merge!' do
7
+ it 'should append root chunks' do
8
+ ast_1 = parse_yaml(<<-YAML)
9
+ en:
10
+ map:
11
+ foo_1: 'foo_1'
12
+ bar_1: 'bar_1'
13
+ YAML
14
+ result = parse_yaml(<<-YAML)
15
+ en:
16
+ map:
17
+ foo_1: 'foo_1'
18
+ bar_1: 'bar_1'
19
+ YAML
20
+
21
+ allow(merger).to receive(:chunks).and_return([
22
+ ast_1,
23
+ ])
24
+
25
+ merger.perform_merge!
26
+
27
+ expect(merger.to_yaml).to eq(result.to_yaml)
28
+ end
29
+
30
+ it 'should append partial chunks' do
31
+ ast_1 = parse_yaml(<<-YAML)
32
+ en:
33
+ map:
34
+ foo_1: 'foo_1'
35
+ bar_1: 'bar_1'
36
+ YAML
37
+ result = parse_yaml(<<-YAML)
38
+ en:
39
+ map:
40
+ foo_1: 'foo_1'
41
+ bar_1: 'bar_1'
42
+ YAML
43
+
44
+ allow(merger).to receive(:chunks).and_return([
45
+ ast_1['en']['map'],
46
+ ])
47
+
48
+ merger.perform_merge!
49
+
50
+ expect(merger.to_yaml).to eq(result.to_yaml)
51
+ end
52
+
53
+ it 'should merge root chunks' do
54
+ ast_1 = parse_yaml(<<-YAML)
55
+ en:
56
+ map:
57
+ foo_1: 'foo_1'
58
+ bar: 'bar_1'
59
+ YAML
60
+ ast_2 = parse_yaml(<<-YAML)
61
+ en:
62
+ map:
63
+ foo_2: 'foo_2'
64
+ bar: 'bar_2'
65
+ YAML
66
+ result = parse_yaml(<<-YAML)
67
+ en:
68
+ map:
69
+ foo_1: 'foo_1'
70
+ bar: 'bar_2'
71
+ foo_2: 'foo_2'
72
+ YAML
73
+
74
+ allow(merger).to receive(:chunks).and_return([
75
+ ast_1,
76
+ ast_2,
77
+ ])
78
+
79
+ merger.perform_merge!
80
+
81
+ expect(merger.to_yaml).to eq(result.to_yaml)
82
+ end
83
+
84
+ it 'should merge partial mapping chunks' do
85
+ ast_1 = parse_yaml(<<-YAML)
86
+ en:
87
+ map:
88
+ foo_1: 'foo_1'
89
+ bar: 'bar_1'
90
+ YAML
91
+ ast_2 = parse_yaml(<<-YAML)
92
+ en:
93
+ map:
94
+ foo_2: 'foo_2'
95
+ bar: 'bar_2'
96
+ YAML
97
+ result = parse_yaml(<<-YAML)
98
+ en:
99
+ map:
100
+ foo_1: 'foo_1'
101
+ bar: 'bar_2'
102
+ foo_2: 'foo_2'
103
+ YAML
104
+
105
+ allow(merger).to receive(:chunks).and_return([
106
+ ast_1['en']['map']['foo_1'],
107
+ ast_1['en']['map']['bar'],
108
+ ast_2['en']['map'],
109
+ ])
110
+
111
+ merger.perform_merge!
112
+
113
+ expect(merger.to_yaml).to eq(result.to_yaml)
114
+ end
115
+
116
+ it 'should merge partial sequence chunks' do
117
+ ast_1 = parse_yaml(<<-YAML)
118
+ en:
119
+ seq:
120
+ - 'seq_1_1'
121
+ - 'seq_1_2'
122
+ YAML
123
+ ast_2 = parse_yaml(<<-YAML)
124
+ en:
125
+ seq:
126
+ - 'seq_2_1'
127
+ - 'seq_2_2'
128
+ YAML
129
+ result = parse_yaml(<<-YAML)
130
+ en:
131
+ seq:
132
+ - 'seq_1_1'
133
+ - 'seq_1_2'
134
+ - 'seq_2_1'
135
+ - 'seq_2_2'
136
+ YAML
137
+
138
+ allow(merger).to receive(:chunks).and_return([
139
+ ast_1['en']['seq'][0],
140
+ ast_1['en']['seq'][1],
141
+ ast_2['en']['seq'],
142
+ ])
143
+
144
+ merger.perform_merge!
145
+
146
+ expect(merger.to_yaml).to eq(result.to_yaml)
147
+ end
148
+ end
149
+ end