yml_merger 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/yml_merger.rb +342 -318
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49e76145d789966d34bccbca72e2e6a7dc1a5e03
4
- data.tar.gz: b31dac2229ba5d425c31c66f958337446bd7fbdd
3
+ metadata.gz: ee8fc229ad3ece250642e1723e3897d1494bf70c
4
+ data.tar.gz: 4e7d8ee189c605791c86130f7d2562dc7ef3b03b
5
5
  SHA512:
6
- metadata.gz: b95b020415c2f0e2a4f95ae4d9aa002aaa1c0a180a84f2741d6e47df9496da78164dbc90c34766a8c9e9fa553cf107012832f60e62381cbc67f6d5be4707d712
7
- data.tar.gz: 1b7ab34abc0f7090f5083b545cae32a321b99ff646e44b0875945e208c107bddb194531fb0363d055ff7985a64316b04c9184a41e992e6d8c8595b1de0bf6be5
6
+ metadata.gz: 943f1609f38ae057f30539d1be50a01fac1b5c7a0608553ba2cde890760fd21daab4a6e7da035b96461a967210644093ae7ec30e7e5bf5fd53b717cdc916f547
7
+ data.tar.gz: e4b408e75ca07309ddb8a6c968f72cf65b6ca021e51a3ab38eb6960d79b90a4baaaacf25c413c9027948cf9ae8fe6313dc0ed41c026925316306cdb06559d625
data/lib/yml_merger.rb CHANGED
@@ -1,318 +1,342 @@
1
- require 'rubygems'
2
- require "yaml"
3
- require "deep_merge"
4
- require 'fileutils'
5
- require 'open-uri'
6
- require 'uri'
7
- require 'logger'
8
-
9
-
10
- # implement of deep merge for nested hash and array of hash
11
- class YML_Merger
12
- attr_accessor :filestructure, :filestack, :ENTRY_YML, :search_paths
13
-
14
- # initialize YML merge
15
- # Params:
16
- # - filepath: the entry file name
17
- # - seatch_paths: rootpath to search all the needed YML files
18
- def initialize(filename, search_paths, logger: nil)
19
- @logger = logger
20
- unless (logger)
21
- @logger = Logger.new(STDOUT)
22
- @logger.level = Logger::INFO
23
- end
24
- @ENTRY_YML = search_paths + '/' + filename
25
- @search_paths = search_paths
26
- @filestructure = Hash.new()
27
- @filestack = Array.new()
28
- @KEY_LIST = ['__remove__','__load__', '__common__', '__hierarchy__', '__replace__', '__add__']
29
- end
30
-
31
- # process the YMLs
32
- def process
33
- @filestructure = process_file(@ENTRY_YML)
34
- merge_by_add(@filestructure)
35
- merge_by_common(@filestructure)
36
- delete_node(@filestructure,'__common__')
37
- delete_node(@filestructure,'__load__')
38
- #delete_node(@filestructure,'__add__')
39
- post_process(@filestructure)
40
- end
41
-
42
- private
43
-
44
- # post process nodes with strong condition
45
- # execute post-process-lib and post-process-app
46
- # clean the pre-process-merge node
47
- # Params:
48
- # - struct: the hash to be processed
49
- def post_process(struct)
50
- return if struct.class != Hash
51
- merge_by_replace!(struct)
52
- merge_by_remove!(struct)
53
- struct.each_key do |key|
54
- if Hash == struct[key].class
55
- if struct.key?("mode") and struct["mode"] == "post-process-lib"
56
- if struct[key].has_key?("attribute")
57
- if struct[key]["attribute"] == "required"
58
- @logger.debug "keep #{key}"
59
- else
60
- struct.delete(key)
61
- @logger.debug "deletes #{key}"
62
- next
63
- end
64
- else
65
- @logger.debug "delete #{key}"
66
- struct.delete(key)
67
- next
68
- end
69
- end
70
- if struct[key].key?("mode") and struct[key]["mode"] == "post-process-app"
71
- if struct[key].has_key?("attribute")
72
- if struct[key]["attribute"] == "required"
73
- @logger.debug "keep #{key}"
74
- else
75
- struct.delete(key)
76
- @logger.debug "deletes #{key}"
77
- next
78
- end
79
- else
80
- @logger.debug "delete #{key}"
81
- struct.delete(key)
82
- next
83
- end
84
- end
85
- if struct[key].key?("mode") and struct[key]["mode"] == "pre-process-merge"
86
- struct.delete(key)
87
- @logger.debug "deletes #{key}"
88
- next
89
- end
90
- post_process(struct[key])
91
- end
92
- end
93
- end
94
-
95
-
96
- # load and process yml files
97
- # recursive load and process all files in '__load__' section
98
- # Params:
99
- # - file: the path to the yml file
100
- def process_file(file)
101
- #check if file is loaded yet
102
- return if @filestack.include?(file)
103
- #if not loaded,push to stack
104
- @filestack.push(file)
105
- #add globals.yml before load file
106
- @logger.info file
107
- content = open(file.gsub("\\","/")){|f| f.read}
108
- content = YAML::load(content)
109
- return if content.class == FalseClass
110
- #if has file dependence load it
111
- if content['__load__'] != nil
112
- #load file in reversed sequence
113
- content['__load__'].reverse_each do |loadfile|
114
- if loadfile =~ URI::regexp
115
- structure = process_file(loadfile)
116
- else
117
- structure = process_file(@search_paths + loadfile.gsub("\\","/"))
118
- end
119
- content = content.deep_merge(deep_copy(structure))
120
- pre_process(content)
121
- merge_by_hierarchy(content)
122
- #content = content.deep_merge(structure)
123
- end
124
- end
125
- pre_process(content)
126
- merge_by_hierarchy(content)
127
- delete_node(content, '__hierarchy__')
128
- return content
129
- end
130
-
131
- # load and process yml files
132
- # recursive load and process all files in '__load__' section
133
- # Params:
134
- # - file: the path to the yml file
135
- def pre_process(struct)
136
- return if struct.class != Hash
137
- struct.each_key do |key|
138
- next if struct[key].class != Hash
139
- if struct[key].has_key?('mode') and struct[key]['mode'] == "pre-process-merge"
140
- if struct[key]['attribute'] == "required"
141
- struct[key].each_key do |subkey|
142
- if struct.has_key?(subkey) and struct[subkey].class == Hash
143
- @logger.debug "pre process #{key} -> #{subkey}"
144
- struct[subkey] = struct[subkey].deep_merge(deep_copy(struct[key][subkey]))
145
- #struct[subkey] = struct[subkey].deep_merge(struct[key][subkey])
146
- #puts struct[subkey].to_yaml
147
- end
148
- end
149
- end
150
- end
151
- pre_process(struct[key])
152
- end
153
- end
154
-
155
-
156
- # delete all node/subnode which key name is 'key' in 'hash'
157
- # Params:
158
- # - struct: the hash
159
- # - type: the key to delete
160
- def delete_node(struct, key)
161
- struct.each_key do |subnode|
162
- next if struct[subnode] == nil
163
- struct.delete(key)
164
- delete_node(struct[subnode],key) if Hash == struct[subnode].class
165
- end
166
- end
167
-
168
- # perform merge by "__hierarchy__" struct
169
- # Params:
170
- # - struct: the hash
171
- def merge_by_hierarchy(struct)
172
- return if Hash != struct.class
173
- if struct['__hierarchy__'] != nil
174
- struct.each_key do |subnode|
175
- next if subnode =~ /^__/ or @KEY_LIST.include?(subnode)
176
- next if struct[subnode].class != Hash or struct['__hierarchy__'].class != Hash
177
- struct[subnode] = struct[subnode].deep_merge(deep_copy(struct['__hierarchy__']))
178
- #struct[subnode] = struct[subnode].deep_merge(struct["__hierarchy__"])
179
- end
180
- #struct.delete('__hierarchy__')
181
- end
182
- struct.each_key do |subnode|
183
- merge_by_hierarchy(struct[subnode])
184
- end
185
- end
186
-
187
- # perform merge by "__common__" node
188
- # Params:
189
- # - struct: the hash
190
- def merge_by_common(struct)
191
- return if Hash != struct.class
192
- if struct['__common__'] != nil
193
- struct.each_key do |subnode|
194
- next if @KEY_LIST.include?(subnode)
195
- next if struct[subnode].class != Hash or struct['__common__'].class != Hash
196
- struct[subnode] = struct[subnode].deep_merge(deep_copy(struct['__common__']))
197
- #struct[subnode] = struct[subnode].deep_merge(struct['__common__'])
198
- end
199
- struct.delete('__common__')
200
- end
201
- struct.each_key do |subnode|
202
- merge_by_common(struct[subnode])
203
- end
204
- end
205
-
206
- # hash deep merge with __add__ recursively
207
- # Params:
208
- # - struct: the hash
209
- # - subnode: the subnode key to be add
210
- # - addon: the key that idetify the addon module
211
- def deep_add_merge(struct, subnode, addon)
212
- return if Hash != struct.class
213
- return if struct[addon].nil?
214
- if struct[addon]['__add__'].nil?
215
- #we do not want the addon module to change the status
216
- struct[addon]['attribute'] = ""
217
- #struct[subnode] = struct[subnode].deep_merge(deep_copy(struct[addon]))
218
- struct[addon]['attribute'] = 'required'
219
- return
220
- end
221
- #if has more addon
222
- if struct[addon]['__add__'].count != 0
223
- struct[addon]['__add__'].each do |submodule|
224
- deep_add_merge(struct, addon, submodule)
225
- end
226
- else
227
- #puts "add #{addon}"
228
- struct[addon]['attribute'] = ""
229
- #struct[subnode] = struct[subnode].deep_merge(deep_copy(struct[addon]))
230
- struct[addon]['attribute'] = 'required'
231
- end
232
- end
233
-
234
- # perform merge by "__add__" node only applys to application type
235
- # Params:
236
- # - struct: the hash to be processed
237
- def merge_by_add(struct)
238
- #only scan the top level
239
- return if Hash != struct.class
240
- struct.each_key do |subnode|
241
- next if @KEY_LIST.include?(subnode)
242
- next if struct[subnode].nil?
243
- if struct[subnode]['__add__'] != nil
244
- struct[subnode]['__add__'].each do |addon|
245
- next if struct[addon].class != Hash
246
- begin
247
- next if struct[subnode]['configuration']['section-type'] != "application"
248
- if struct[addon]['configuration']['section-type'] != "component"
249
- puts "WARNING #{addon} is required as component but has not a component attribute"
250
- end
251
- rescue
252
- puts "error with the merge_by_add with #{subnode} add #{addon}"
253
- end
254
- deep_add_merge(struct, subnode, addon)
255
- end
256
- #struct[subnode].delete('__add__')
257
- end
258
- end
259
- end
260
-
261
- # prepare merge by "__replace__" node
262
- # Params:
263
- # - struct: the hash to be processed
264
- def merge_by_replace!(struct)
265
- return if Hash != struct.class
266
- #get the replace hash
267
- return if ! struct.has_key?("__replace__")
268
- temp = Hash.new
269
- temp = temp.deep_merge(deep_copy(struct["__replace__"]))
270
- temp.each_key do |key|
271
- next if ! struct.has_key?(key)
272
- delete_node(struct, key)
273
- struct[key] = temp[key]
274
- end
275
- struct.delete('__replace__')
276
- end
277
-
278
- # perform merge by "__remove__" node
279
- # Params:
280
- # - struct: the hash to be processed
281
- def merge_by_remove!(struct)
282
- return if Hash != struct.class
283
- #get the replace hash
284
- return if ! struct.has_key?("__remove__")
285
- temp = Hash.new
286
- temp = temp.deep_merge(deep_copy(struct["__remove__"]))
287
- temp.each_key do |key|
288
- next if ! struct.has_key?(key)
289
- if struct["__remove__"][key] == nil
290
- delete_node(struct, key)
291
- else
292
- if struct["__remove__"][key].class == Array
293
- arr = Array.new
294
- arr = deep_copy(struct["__remove__"][key])
295
- arr.each do |item|
296
- next if ! struct[key].include?(item)
297
- struct[key].delete(item)
298
- end
299
- elsif struct["__remove__"][key].class == Hash
300
- hash = Hash.new
301
- hash = hash.deep_merge(deep_copy(struct["__remove__"][key]))
302
- hash.each_key do |subkey|
303
- next if ! struct[key].has_key?(subkey)
304
- delete_node(struct[key], subkey)
305
- end
306
- end
307
- end
308
- end
309
- struct.delete('__remove__')
310
- end
311
-
312
- # deep copy the hash in compare the shallow copy
313
- # Params:
314
- # -o: the hash to be copied
315
- def deep_copy(o)
316
- Marshal.load(Marshal.dump(o))
317
- end
318
- end
1
+ require 'rubygems'
2
+ require "yaml"
3
+ require "deep_merge"
4
+ require 'fileutils'
5
+ require 'open-uri'
6
+ require 'uri'
7
+ require 'logger'
8
+
9
+
10
+ # implement of deep merge for nested hash and array of hash
11
+ class YML_Merger
12
+ attr_accessor :filestructure, :filestack, :ENTRY_YML, :search_paths
13
+
14
+ # initialize YML merge
15
+ # Params:
16
+ # - filepath: the entry file name
17
+ # - seatch_paths: rootpath to search all the needed YML files
18
+ def initialize(filename, search_paths, logger: nil)
19
+ @logger = logger
20
+ unless (logger)
21
+ @logger = Logger.new(STDOUT)
22
+ @logger.level = Logger::INFO
23
+ end
24
+ @ENTRY_YML = search_paths + '/' + filename
25
+ @search_paths = search_paths
26
+ @filestructure = Hash.new()
27
+ @filestack = Array.new()
28
+ @KEY_LIST = ['__remove__','__load__', '__common__', '__hierarchy__', '__replace__', '__add__']
29
+ end
30
+
31
+ # process the YMLs
32
+ def process
33
+ @filestructure = process_file(@ENTRY_YML)
34
+ merge_by_add(@filestructure)
35
+ merge_by_common(@filestructure)
36
+ delete_node(@filestructure,'__common__')
37
+ delete_node(@filestructure,'__load__')
38
+ #delete_node(@filestructure,'__add__')
39
+ post_process(@filestructure)
40
+ end
41
+
42
+ private
43
+
44
+ # post process nodes with strong condition
45
+ # execute post-process-lib and post-process-app
46
+ # clean the pre-process-merge node
47
+ # Params:
48
+ # - struct: the hash to be processed
49
+ def post_process(struct)
50
+ return if struct.class != Hash
51
+ merge_by_replace!(struct)
52
+ merge_by_remove!(struct)
53
+ struct.each_key do |key|
54
+ if Hash == struct[key].class
55
+ if struct.key?("mode") and struct["mode"] == "post-process-lib"
56
+ if struct[key].has_key?("attribute")
57
+ if struct[key]["attribute"] == "required"
58
+ @logger.debug "keep #{key}"
59
+ else
60
+ struct.delete(key)
61
+ @logger.debug "deletes #{key}"
62
+ next
63
+ end
64
+ else
65
+ @logger.debug "delete #{key}"
66
+ struct.delete(key)
67
+ next
68
+ end
69
+ end
70
+ if struct[key].key?("mode") and struct[key]["mode"] == "post-process-app"
71
+ if struct[key].has_key?("attribute")
72
+ if struct[key]["attribute"] == "required"
73
+ @logger.debug "keep #{key}"
74
+ else
75
+ struct.delete(key)
76
+ @logger.debug "deletes #{key}"
77
+ next
78
+ end
79
+ else
80
+ @logger.debug "delete #{key}"
81
+ struct.delete(key)
82
+ next
83
+ end
84
+ end
85
+ if struct[key].key?("mode") and struct[key]["mode"] == "pre-process-merge"
86
+ struct.delete(key)
87
+ @logger.debug "deletes #{key}"
88
+ next
89
+ end
90
+ post_process(struct[key])
91
+ end
92
+ end
93
+ end
94
+
95
+ def load_file(path)
96
+ if path =~ URI::regexp
97
+ structure = process_file(path)
98
+ else
99
+ structure = process_file(@search_paths + path.gsub("\\","/"))
100
+ end
101
+ return structure
102
+ end
103
+
104
+ # load and process yml files
105
+ # recursive load and process all files in '__load__' section
106
+ # Params:
107
+ # - file: the path to the yml file
108
+ def process_file(file)
109
+ #check if file is loaded yet
110
+ return if @filestack.include?(file)
111
+ #if not loaded,push to stack
112
+ @filestack.push(file)
113
+ #add globals.yml before load file
114
+ @logger.info file
115
+ content = open(file.gsub("\\","/")){|f| f.read}
116
+ content = YAML::load(content)
117
+ return if content.class == FalseClass
118
+ #if has file dependence load it
119
+ if content['__load__'] != nil
120
+ #load file in reversed sequence
121
+ content['__load__'].reverse_each do |loadfile|
122
+ if loadfile.class == Hash
123
+ structure = Hash.new
124
+ temp_structure = load_file(loadfile.keys[0])
125
+ loadfile.each do |key, value|
126
+ if value.class == Array
127
+ value.each do |vt|
128
+ t = Hash.new
129
+ t[vt] = Hash.new
130
+ t[vt].deep_merge(temp_structure[vt])
131
+ structure.deep_merge(t)
132
+ end
133
+ end
134
+ end
135
+ else
136
+ if loadfile =~ URI::regexp
137
+ structure = process_file(loadfile)
138
+ else
139
+ structure = process_file(@search_paths + loadfile.gsub("\\","/"))
140
+ end
141
+ end
142
+ content = content.deep_merge(deep_copy(structure))
143
+ pre_process(content)
144
+ merge_by_hierarchy(content)
145
+ #content = content.deep_merge(structure)
146
+ end
147
+ end
148
+ pre_process(content)
149
+ merge_by_hierarchy(content)
150
+ delete_node(content, '__hierarchy__')
151
+ return content
152
+ end
153
+
154
+ # load and process yml files
155
+ # recursive load and process all files in '__load__' section
156
+ # Params:
157
+ # - file: the path to the yml file
158
+ def pre_process(struct)
159
+ return if struct.class != Hash
160
+ struct.each_key do |key|
161
+ next if struct[key].class != Hash
162
+ if struct[key].has_key?('mode') and struct[key]['mode'] == "pre-process-merge"
163
+ if struct[key]['attribute'] == "required"
164
+ struct[key].each_key do |subkey|
165
+ if struct.has_key?(subkey) and struct[subkey].class == Hash
166
+ @logger.debug "pre process #{key} -> #{subkey}"
167
+ struct[subkey] = struct[subkey].deep_merge(deep_copy(struct[key][subkey]))
168
+ #struct[subkey] = struct[subkey].deep_merge(struct[key][subkey])
169
+ #puts struct[subkey].to_yaml
170
+ end
171
+ end
172
+ end
173
+ end
174
+ pre_process(struct[key])
175
+ end
176
+ end
177
+
178
+
179
+ # delete all node/subnode which key name is 'key' in 'hash'
180
+ # Params:
181
+ # - struct: the hash
182
+ # - type: the key to delete
183
+ def delete_node(struct, key)
184
+ struct.each_key do |subnode|
185
+ next if struct[subnode] == nil
186
+ struct.delete(key)
187
+ delete_node(struct[subnode],key) if Hash == struct[subnode].class
188
+ end
189
+ end
190
+
191
+ # perform merge by "__hierarchy__" struct
192
+ # Params:
193
+ # - struct: the hash
194
+ def merge_by_hierarchy(struct)
195
+ return if Hash != struct.class
196
+ if struct['__hierarchy__'] != nil
197
+ struct.each_key do |subnode|
198
+ next if subnode =~ /^__/ or @KEY_LIST.include?(subnode)
199
+ next if struct[subnode].class != Hash or struct['__hierarchy__'].class != Hash
200
+ struct[subnode] = struct[subnode].deep_merge(deep_copy(struct['__hierarchy__']))
201
+ #struct[subnode] = struct[subnode].deep_merge(struct["__hierarchy__"])
202
+ end
203
+ #struct.delete('__hierarchy__')
204
+ end
205
+ struct.each_key do |subnode|
206
+ merge_by_hierarchy(struct[subnode])
207
+ end
208
+ end
209
+
210
+ # perform merge by "__common__" node
211
+ # Params:
212
+ # - struct: the hash
213
+ def merge_by_common(struct)
214
+ return if Hash != struct.class
215
+ if struct['__common__'] != nil
216
+ struct.each_key do |subnode|
217
+ next if @KEY_LIST.include?(subnode)
218
+ next if struct[subnode].class != Hash or struct['__common__'].class != Hash
219
+ struct[subnode] = struct[subnode].deep_merge(deep_copy(struct['__common__']))
220
+ #struct[subnode] = struct[subnode].deep_merge(struct['__common__'])
221
+ end
222
+ struct.delete('__common__')
223
+ end
224
+ struct.each_key do |subnode|
225
+ merge_by_common(struct[subnode])
226
+ end
227
+ end
228
+
229
+ # hash deep merge with __add__ recursively
230
+ # Params:
231
+ # - struct: the hash
232
+ # - subnode: the subnode key to be add
233
+ # - addon: the key that idetify the addon module
234
+ def deep_add_merge(struct, subnode, addon)
235
+ return if Hash != struct.class
236
+ return if struct[addon].nil?
237
+ if struct[addon]['__add__'].nil?
238
+ #we do not want the addon module to change the status
239
+ struct[addon]['attribute'] = ""
240
+ #struct[subnode] = struct[subnode].deep_merge(deep_copy(struct[addon]))
241
+ struct[addon]['attribute'] = 'required'
242
+ return
243
+ end
244
+ #if has more addon
245
+ if struct[addon]['__add__'].count != 0
246
+ struct[addon]['__add__'].each do |submodule|
247
+ deep_add_merge(struct, addon, submodule)
248
+ end
249
+ else
250
+ #puts "add #{addon}"
251
+ struct[addon]['attribute'] = ""
252
+ #struct[subnode] = struct[subnode].deep_merge(deep_copy(struct[addon]))
253
+ struct[addon]['attribute'] = 'required'
254
+ end
255
+ end
256
+
257
+ # perform merge by "__add__" node only applys to application type
258
+ # Params:
259
+ # - struct: the hash to be processed
260
+ def merge_by_add(struct)
261
+ #only scan the top level
262
+ return if Hash != struct.class
263
+ struct.each_key do |subnode|
264
+ next if @KEY_LIST.include?(subnode)
265
+ next if struct[subnode].nil?
266
+ next if struct[subnode].class != Hash
267
+ if struct[subnode].has_key?('__add__')
268
+ struct[subnode]['__add__'].each do |addon|
269
+ next if struct[addon].class != Hash
270
+ begin
271
+ next if struct[subnode]['configuration']['section-type'] != "application"
272
+ if struct[addon]['configuration']['section-type'] != "component"
273
+ @logger.warn "WARNING #{addon} is required as component but has not a component attribute"
274
+ end
275
+ rescue
276
+ @logger.warn "no full configuration/section-type with the merge_by_add with #{subnode} add #{addon}"
277
+ end
278
+ deep_add_merge(struct, subnode, addon)
279
+ end
280
+ #struct[subnode].delete('__add__')
281
+ end
282
+ end
283
+ end
284
+
285
+ # prepare merge by "__replace__" node
286
+ # Params:
287
+ # - struct: the hash to be processed
288
+ def merge_by_replace!(struct)
289
+ return if Hash != struct.class
290
+ #get the replace hash
291
+ return if ! struct.has_key?("__replace__")
292
+ temp = Hash.new
293
+ temp = temp.deep_merge(deep_copy(struct["__replace__"]))
294
+ temp.each_key do |key|
295
+ next if ! struct.has_key?(key)
296
+ delete_node(struct, key)
297
+ struct[key] = temp[key]
298
+ end
299
+ struct.delete('__replace__')
300
+ end
301
+
302
+ # perform merge by "__remove__" node
303
+ # Params:
304
+ # - struct: the hash to be processed
305
+ def merge_by_remove!(struct)
306
+ return if Hash != struct.class
307
+ #get the replace hash
308
+ return if ! struct.has_key?("__remove__")
309
+ temp = Hash.new
310
+ temp = temp.deep_merge(deep_copy(struct["__remove__"]))
311
+ temp.each_key do |key|
312
+ next if ! struct.has_key?(key)
313
+ if struct["__remove__"][key] == nil
314
+ delete_node(struct, key)
315
+ else
316
+ if struct["__remove__"][key].class == Array
317
+ arr = Array.new
318
+ arr = deep_copy(struct["__remove__"][key])
319
+ arr.each do |item|
320
+ next if ! struct[key].include?(item)
321
+ struct[key].delete(item)
322
+ end
323
+ elsif struct["__remove__"][key].class == Hash
324
+ hash = Hash.new
325
+ hash = hash.deep_merge(deep_copy(struct["__remove__"][key]))
326
+ hash.each_key do |subkey|
327
+ next if ! struct[key].has_key?(subkey)
328
+ delete_node(struct[key], subkey)
329
+ end
330
+ end
331
+ end
332
+ end
333
+ struct.delete('__remove__')
334
+ end
335
+
336
+ # deep copy the hash in compare the shallow copy
337
+ # Params:
338
+ # -o: the hash to be copied
339
+ def deep_copy(o)
340
+ Marshal.load(Marshal.dump(o))
341
+ end
342
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yml_merger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hake Huang
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-11-18 00:00:00.000000000 Z
12
+ date: 2016-12-20 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: yaml extension for heiarchy merge
15
15
  email: hakehuang@gmail.com
@@ -38,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
38
  version: '0'
39
39
  requirements: []
40
40
  rubyforge_project:
41
- rubygems_version: 2.6.6
41
+ rubygems_version: 2.6.7
42
42
  signing_key:
43
43
  specification_version: 4
44
44
  summary: yaml_merger