ribbon 0.5.0 → 0.6.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.
- data/.gitignore +1 -0
- data/.yardopts +1 -0
- data/LICENSE.MPL2 +3 -0
- data/Rakefile +1 -1
- data/lib/ribbon.rb +304 -176
- data/lib/ribbon/core_extensions.rb +13 -0
- data/lib/ribbon/{core_ext → core_extensions}/array.rb +15 -3
- data/lib/ribbon/core_extensions/basic_object.rb +24 -0
- data/lib/ribbon/core_extensions/hash.rb +41 -0
- data/lib/ribbon/core_extensions/object.rb +18 -0
- data/lib/ribbon/core_extensions/object/option_scope.rb +21 -0
- data/lib/ribbon/core_extensions/object/yield_or_eval.rb +15 -0
- data/lib/ribbon/options.rb +54 -0
- data/lib/ribbon/version.rb +1 -1
- data/lib/ribbon/wrapper.rb +126 -78
- data/ribbon.gemspec +4 -2
- metadata +56 -13
- data/LICENSE.GPLv3 +0 -14
- data/lib/ribbon/core_ext.rb +0 -9
- data/lib/ribbon/core_ext/hash.rb +0 -22
data/.gitignore
CHANGED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--protected --no-private
|
data/LICENSE.MPL2
ADDED
data/Rakefile
CHANGED
data/lib/ribbon.rb
CHANGED
@@ -1,83 +1,114 @@
|
|
1
|
-
|
2
|
-
require 'ribbon/
|
1
|
+
%w(core_extensions/basic_object options version wrapper).each do |file|
|
2
|
+
require file.prepend 'ribbon/'
|
3
|
+
end
|
3
4
|
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# ==== Inspired by JSON and OpenStruct.
|
5
|
+
# Ribbons are essentially hashes that use method names as keys.
|
7
6
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# general-purpose hash, since the <tt>[key]</tt> and <tt>[key] = value</tt>
|
11
|
-
# methods are defined.
|
7
|
+
# r = Ribbon.new
|
8
|
+
# r.key = :value
|
12
9
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# continue your calls:
|
10
|
+
# If you access a property that hasn't been set, a new ribbon will be returned.
|
11
|
+
# This allows you to easily work with nested structures:
|
16
12
|
#
|
17
|
-
# r = Ribbon.new
|
18
13
|
# r.a.b.c = 10
|
19
14
|
#
|
20
15
|
# You can also assign properties by passing an argument to the method:
|
21
16
|
#
|
22
|
-
# r.a.b.c
|
17
|
+
# r.a.b.c 20
|
23
18
|
#
|
24
19
|
# If you pass a block, the value will be yielded:
|
25
20
|
#
|
26
|
-
# r.a
|
21
|
+
# r.a do |a|
|
22
|
+
# a.b do |b|
|
23
|
+
# b.c 30
|
24
|
+
# end
|
25
|
+
# end
|
27
26
|
#
|
28
|
-
# If the block passed takes no arguments, it will be <tt>instance_eval</tt>
|
29
|
-
# the value instead:
|
27
|
+
# If the block passed takes no arguments, it will be <tt>instance_eval</tt>uated
|
28
|
+
# in the context of the value instead:
|
30
29
|
#
|
31
|
-
# r.a
|
30
|
+
# r.a do
|
31
|
+
# b do
|
32
|
+
# c 40
|
33
|
+
# end
|
34
|
+
# end
|
32
35
|
#
|
33
|
-
# Appending a <tt>!</tt> to the end of the property sets the value and
|
34
|
-
# the receiver:
|
36
|
+
# Appending a bang (<tt>!</tt>) to the end of the property sets the value and
|
37
|
+
# returns the receiver:
|
35
38
|
#
|
36
|
-
#
|
39
|
+
# Ribbon.new.x!(10).y!(20).z!(30)
|
37
40
|
# => {x: 10, y: 20, z: 30}
|
38
41
|
#
|
39
|
-
# Appending a <tt>?</tt> to the end of the property
|
42
|
+
# Appending a question mark (<tt>?</tt>) to the end of the property returns the
|
40
43
|
# contents of the property without creating a new ribbon if it is missing:
|
41
44
|
#
|
42
|
-
# r.
|
45
|
+
# r.unknown_property?
|
43
46
|
# => nil
|
44
47
|
#
|
45
|
-
#
|
46
|
-
# <tt>[key]</tt> and <tt>[key] = value</tt> operators, which allow you to
|
47
|
-
# directly manipulate the internal hash:
|
48
|
+
# You can use any object as key with the <tt>[]</tt> and <tt>[]=</tt> operators:
|
48
49
|
#
|
49
|
-
# r[
|
50
|
+
# r['/some/path'].entries = []
|
50
51
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
# the underlying hash.
|
52
|
+
# @author Matheus Afonso Martins Moreira
|
53
|
+
# @since 0.1.0
|
54
|
+
# @see Ribbon::Wrapper
|
55
55
|
class Ribbon < BasicObject
|
56
56
|
|
57
|
-
# The
|
57
|
+
# The hash used internally.
|
58
|
+
#
|
59
|
+
# @return [Hash] the hash used by this Ribbon instance to store data
|
60
|
+
# @api private
|
58
61
|
def __hash__
|
59
62
|
@hash ||= (::Hash.new &::Ribbon.default_value_proc)
|
60
63
|
end
|
61
64
|
|
62
|
-
# Initializes
|
63
|
-
#
|
65
|
+
# Initializes a new ribbon.
|
66
|
+
#
|
67
|
+
# If given a block, the ribbon will be yielded to it. If the block doesn't
|
68
|
+
# take any arguments, it will be evaluated in the context of the ribbon.
|
69
|
+
#
|
70
|
+
# All objects inside the hash will be converted.
|
71
|
+
#
|
72
|
+
# @param [#to_hash, Ribbon, Ribbon::Wrapper] hash the hash with the initial
|
73
|
+
# values
|
74
|
+
# @see CoreExt::BasicObject#__yield_or_eval__
|
75
|
+
# @see convert_all!
|
64
76
|
def initialize(hash = {}, &block)
|
65
|
-
__hash__.merge! hash
|
66
|
-
|
77
|
+
__hash__.merge! ::Ribbon.extract_hash_from(hash)
|
78
|
+
__yield_or_eval__ &block
|
67
79
|
::Ribbon.convert_all! self
|
68
80
|
end
|
69
81
|
|
70
|
-
#
|
82
|
+
# Fetches the value associated with the given key.
|
83
|
+
#
|
84
|
+
# If given a block, the value will be yielded to it. If the block doesn't take
|
85
|
+
# any arguments, it will be evaluated in the context of the value.
|
86
|
+
#
|
87
|
+
# @param key the key which identifies the value
|
88
|
+
# @return the value associated with the given key
|
89
|
+
# @see CoreExt::BasicObject#__yield_or_eval__
|
71
90
|
def [](key, &block)
|
72
91
|
value = ::Ribbon.convert __hash__[key]
|
73
|
-
|
74
|
-
else block.call value end if block
|
92
|
+
value.__yield_or_eval__ &block
|
75
93
|
self[key] = value
|
76
94
|
end
|
77
95
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
96
|
+
# Associates the given values with the given key.
|
97
|
+
#
|
98
|
+
# @param key the key that will identify the values
|
99
|
+
# @param values the values that will be associated with the key
|
100
|
+
# @example
|
101
|
+
# ribbon = Ribbon.new
|
102
|
+
#
|
103
|
+
# ribbon[:key] = :value
|
104
|
+
# ribbon[:key]
|
105
|
+
# # => :value
|
106
|
+
#
|
107
|
+
# ribbon[:key] = :multiple, :values
|
108
|
+
# ribbon[:key]
|
109
|
+
# # => [:multiple, :values]
|
110
|
+
def []=(key, *values)
|
111
|
+
__hash__[key] = if values.size == 1 then values.first else values end
|
81
112
|
end
|
82
113
|
|
83
114
|
# Handles the following cases:
|
@@ -87,181 +118,278 @@ class Ribbon < BasicObject
|
|
87
118
|
# ribbon.method &block => ribbon[method, &block]
|
88
119
|
# ribbon.method value, &block => ribbon[method] = value
|
89
120
|
# ribbon[method, &block]
|
121
|
+
#
|
90
122
|
# ribbon.method = value => ribbon[method] = value
|
123
|
+
#
|
91
124
|
# ribbon.method! value => ribbon[method] = value
|
92
125
|
# self
|
126
|
+
# ribbon.method! &block => ribbon[method, &block]
|
127
|
+
# self
|
128
|
+
# ribbon.method! value, &block => ribbon[method] = value
|
129
|
+
# ribbon[method, &block]
|
130
|
+
# self
|
131
|
+
#
|
93
132
|
# ribbon.method? => ribbon.__hash__.fetch method
|
94
133
|
# ribbon.method? value => ribbon.__hash__.fetch method, value
|
95
134
|
# ribbon.method? &block => ribbon.__hash__.fetch method, &block
|
135
|
+
# ribbon.method? value, &block => ribbon.__hash__.fetch method, value, &block
|
96
136
|
def method_missing(method, *args, &block)
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
137
|
+
method_string = method.to_s
|
138
|
+
key = method_string.strip.gsub(/[=?!]$/, '').strip.intern
|
139
|
+
case method_string[-1]
|
140
|
+
when ?=
|
141
|
+
__send__ :[]=, key, *args
|
142
|
+
when ?!
|
143
|
+
__send__ :[]=, key, *args unless args.empty?
|
144
|
+
self[key, &block]
|
145
|
+
self
|
146
|
+
when ??
|
147
|
+
begin self.__hash__.fetch key, *args, &block
|
105
148
|
rescue ::KeyError; nil end
|
106
149
|
else
|
107
|
-
|
108
|
-
self[
|
150
|
+
__send__ :[]=, key, *args unless args.empty?
|
151
|
+
self[key, &block]
|
109
152
|
end
|
110
153
|
end
|
111
154
|
|
112
|
-
#
|
155
|
+
# Generates a simple <tt>key: value</tt> string representation of this ribbon.
|
113
156
|
#
|
114
|
-
#
|
115
|
-
# is
|
116
|
-
#
|
117
|
-
#
|
118
|
-
# [
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
157
|
+
# @option opts [String] :separator Separates the key/value pair.
|
158
|
+
# Default is <tt>': '</tt>.
|
159
|
+
# @option opts [Symbol] :key Will be sent to the key in order to convert
|
160
|
+
# it to a string. Default is <tt>:to_s</tt>.
|
161
|
+
# @option opts [Symbol] :value Will be sent to the value in order to
|
162
|
+
# convert it to a string. Default is
|
163
|
+
# <tt>:inspect</tt>.
|
164
|
+
# @return [String] the string representation of this ribbon
|
122
165
|
def to_s(opts = {})
|
123
|
-
|
166
|
+
__to_s_recursive__ ::Ribbon.extract_hash_from(opts)
|
124
167
|
end
|
125
168
|
|
126
|
-
# Same as #to_s.
|
127
169
|
alias inspect to_s
|
128
170
|
|
129
|
-
|
130
|
-
class << self
|
171
|
+
private
|
131
172
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
173
|
+
# Computes a string value recursively for the given ribbon, and all ribbons
|
174
|
+
# inside it, using the given options.
|
175
|
+
#
|
176
|
+
# @since 0.3.0
|
177
|
+
# @see #to_s
|
178
|
+
def __to_s_recursive__(opts = {}, ribbon = self)
|
179
|
+
ksym = opts.fetch(:key, :to_s).to_sym
|
180
|
+
vsym = opts.fetch(:value, :inspect).to_sym
|
181
|
+
separator = opts.fetch(:separator, ': ').to_s
|
182
|
+
values = ribbon.__hash__.map do |k, v|
|
183
|
+
k = k.ribbon if ::Ribbon.wrapped? k
|
184
|
+
v = v.ribbon if ::Ribbon.wrapped? v
|
185
|
+
k = if ::Ribbon.instance? k then __to_s_recursive__ opts, k else k.__send__ ksym end
|
186
|
+
v = if ::Ribbon.instance? v then __to_s_recursive__ opts, v else v.__send__ vsym end
|
187
|
+
"#{k}#{separator}#{v}"
|
188
|
+
end.join ', '
|
189
|
+
"{#{values}}"
|
190
|
+
end
|
137
191
|
|
138
|
-
|
139
|
-
# converts any hashes inside.
|
140
|
-
def convert(object)
|
141
|
-
case object
|
142
|
-
when Hash then Ribbon.new object
|
143
|
-
when Array then object.map { |element| convert element }
|
144
|
-
else object
|
145
|
-
end
|
146
|
-
end
|
192
|
+
end
|
147
193
|
|
148
|
-
|
149
|
-
def convert_all!(ribbon)
|
150
|
-
ribbon.__hash__.each do |key, value|
|
151
|
-
ribbon[key] = case value
|
152
|
-
when Ribbon then convert_all! value
|
153
|
-
else convert value
|
154
|
-
end
|
155
|
-
end
|
156
|
-
ribbon
|
157
|
-
end
|
194
|
+
class << Ribbon
|
158
195
|
|
159
|
-
|
160
|
-
# new ribbon in the process.
|
161
|
-
def merge(old_ribbon, new_ribbon, &block)
|
162
|
-
old_hash = extract_hash_from old_ribbon
|
163
|
-
new_hash = extract_hash_from new_ribbon
|
164
|
-
merged_hash = old_hash.merge new_hash, &block
|
165
|
-
Ribbon.new merged_hash
|
166
|
-
end
|
196
|
+
alias [] new
|
167
197
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
198
|
+
# Proc used to store a new Ribbon instance as the value of a missing key.
|
199
|
+
#
|
200
|
+
# @return [Proc] the proc used when constructing new hashes
|
201
|
+
# @since 0.4.6
|
202
|
+
def default_value_proc
|
203
|
+
@default_value_proc ||= (proc { |hash, key| hash[key] = Ribbon.new })
|
204
|
+
end
|
176
205
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
206
|
+
# Converts hashes to ribbons. Will look inside arrays.
|
207
|
+
#
|
208
|
+
# @param object the object to convert
|
209
|
+
# @return the converted value
|
210
|
+
# @since 0.2.0
|
211
|
+
def convert(object)
|
212
|
+
case object
|
213
|
+
when Hash then Ribbon.new object
|
214
|
+
when Array then object.map { |element| convert element }
|
215
|
+
else object
|
181
216
|
end
|
217
|
+
end
|
182
218
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
219
|
+
# Converts all values inside the given ribbon.
|
220
|
+
#
|
221
|
+
# @param [Ribbon, Ribbon::Wrapper] ribbon the ribbon whose values are to be
|
222
|
+
# converted
|
223
|
+
# @return [Ribbon, Ribbon::Wrapper] the ribbon with all values converted
|
224
|
+
# @since 0.2.0
|
225
|
+
# @see convert
|
226
|
+
def convert_all!(ribbon)
|
227
|
+
ribbon.__hash__.each do |key, value|
|
228
|
+
ribbon[key] = case value
|
229
|
+
when Ribbon then convert_all! value
|
230
|
+
when Ribbon::Wrapper then convert_all! value.ribbon
|
231
|
+
else convert value
|
232
|
+
end
|
187
233
|
end
|
234
|
+
ribbon
|
235
|
+
end
|
188
236
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
237
|
+
# Merges the hashes of the given ribbons.
|
238
|
+
#
|
239
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
|
240
|
+
# values
|
241
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
|
242
|
+
# values
|
243
|
+
# @return [Ribbon] a new ribbon containing the results of the merge
|
244
|
+
# @yieldparam key the key which identifies both values
|
245
|
+
# @yieldparam old_value the value from old_ribbon
|
246
|
+
# @yieldparam new_value the value from new_ribbon
|
247
|
+
# @yieldreturn the object that will be used as the new value
|
248
|
+
# @since 0.3.0
|
249
|
+
# @see merge!
|
250
|
+
# @see extract_hash_from
|
251
|
+
def merge(old_ribbon, new_ribbon, &block)
|
252
|
+
old_hash = extract_hash_from old_ribbon
|
253
|
+
new_hash = extract_hash_from new_ribbon
|
254
|
+
merged_hash = old_hash.merge new_hash, &block
|
255
|
+
Ribbon.new merged_hash
|
256
|
+
end
|
193
257
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
258
|
+
# Merges the hashes of the given ribbons in place.
|
259
|
+
#
|
260
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
|
261
|
+
# values
|
262
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
|
263
|
+
# values
|
264
|
+
# @return [Ribbon, Ribbon::Wrapper, Hash] old_ribbon, which will contain the
|
265
|
+
# results of the merge
|
266
|
+
# @yieldparam key the key which identifies both values
|
267
|
+
# @yieldparam old_value the value from old_ribbon
|
268
|
+
# @yieldparam new_value the value from new_ribbon
|
269
|
+
# @yieldreturn the object that will be used as the new value
|
270
|
+
# @since 0.3.0
|
271
|
+
# @see merge
|
272
|
+
# @see extract_hash_from
|
273
|
+
def merge!(old_ribbon, new_ribbon, &block)
|
274
|
+
old_hash = extract_hash_from old_ribbon
|
275
|
+
new_hash = extract_hash_from new_ribbon
|
276
|
+
old_hash.merge! new_hash, &block
|
277
|
+
old_ribbon
|
278
|
+
end
|
198
279
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
280
|
+
# Merges everything inside the given ribbons.
|
281
|
+
#
|
282
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
|
283
|
+
# values
|
284
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
|
285
|
+
# values
|
286
|
+
# @return [Ribbon] a new ribbon containing the results of the merge
|
287
|
+
# @yieldparam key the key which identifies both values
|
288
|
+
# @yieldparam old_value the value from old_ribbon
|
289
|
+
# @yieldparam new_value the value from new_ribbon
|
290
|
+
# @yieldreturn the object that will be used as the new value
|
291
|
+
# @since 0.4.5
|
292
|
+
# @see merge
|
293
|
+
# @see deep_merge!
|
294
|
+
# @see extract_hash_from
|
295
|
+
def deep_merge(old_ribbon, new_ribbon, &block)
|
296
|
+
deep :merge, old_ribbon, new_ribbon, &block
|
297
|
+
end
|
203
298
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
299
|
+
# Merges everything inside the given ribbons in place.
|
300
|
+
#
|
301
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
|
302
|
+
# values
|
303
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
|
304
|
+
# values
|
305
|
+
# @return [Ribbon, Ribbon::Wrapper, Hash] old_ribbon, which will contain the
|
306
|
+
# results of the merge
|
307
|
+
# @yieldparam key the key which identifies both values
|
308
|
+
# @yieldparam old_value the value from old_ribbon
|
309
|
+
# @yieldparam new_value the value from new_ribbon
|
310
|
+
# @yieldreturn the object that will be used as the new value
|
311
|
+
# @since 0.4.5
|
312
|
+
# @see merge!
|
313
|
+
# @see deep_merge
|
314
|
+
# @see extract_hash_from
|
315
|
+
def deep_merge!(old_ribbon, new_ribbon, &block)
|
316
|
+
deep :merge!, old_ribbon, new_ribbon, &block
|
317
|
+
end
|
214
318
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
319
|
+
# Tests whether the given object is an instance of Ribbon.
|
320
|
+
#
|
321
|
+
# @param object the object to be tested
|
322
|
+
# @return [true, false] whether the object is an instance of Ribbon
|
323
|
+
# @since 0.2.0
|
324
|
+
def instance?(object)
|
325
|
+
Ribbon === object
|
326
|
+
end
|
220
327
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
328
|
+
# Tests whether the given object is an instance of {Ribbon::Wrapper}.
|
329
|
+
#
|
330
|
+
# @param object the object to be tested
|
331
|
+
# @return [true, false] whether the object is an instance of {Ribbon::Wrapper}
|
332
|
+
# @since 0.2.0
|
333
|
+
def wrapped?(ribbon)
|
334
|
+
Ribbon::Wrapper === ribbon
|
335
|
+
end
|
225
336
|
|
226
|
-
|
337
|
+
# Wraps an object in a {Ribbon::Wrapper}.
|
338
|
+
#
|
339
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] object the object to be wrapped
|
340
|
+
# @return [Ribbon::Wrapper] a new wrapped ribbon
|
341
|
+
# @since 0.2.0
|
342
|
+
def wrap(object = ::Ribbon.new)
|
343
|
+
Ribbon::Wrapper.new object
|
344
|
+
end
|
227
345
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
deep merge_method, old_value, new_value, &block
|
239
|
-
else
|
240
|
-
if block.respond_to? :call then block.call key, old_value, new_value
|
241
|
-
else new_value end
|
242
|
-
end
|
243
|
-
end
|
346
|
+
# Returns the hash of a Ribbon. Will attempt to convert other objects.
|
347
|
+
#
|
348
|
+
# @param [Ribbon, Ribbon::Wrapper, #to_hash] parameter the object to convert
|
349
|
+
# @return [Hash] the resulting hash
|
350
|
+
# @since 0.2.1
|
351
|
+
def extract_hash_from(parameter)
|
352
|
+
case parameter
|
353
|
+
when Ribbon::Wrapper then parameter.internal_hash
|
354
|
+
when Ribbon then parameter.__hash__
|
355
|
+
else parameter.to_hash
|
244
356
|
end
|
357
|
+
end
|
245
358
|
|
359
|
+
# Deserializes the hash from the string using YAML and uses it to construct a
|
360
|
+
# new ribbon.
|
361
|
+
#
|
362
|
+
# @param [String] string a valid YAML string
|
363
|
+
# @return [Ribbon] a new Ribbon
|
364
|
+
# @since 0.4.7
|
365
|
+
def from_yaml(string)
|
366
|
+
Ribbon.new YAML.load(string)
|
246
367
|
end
|
247
368
|
|
248
369
|
private
|
249
370
|
|
250
|
-
#
|
251
|
-
#
|
252
|
-
#
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
371
|
+
# Common logic for deep merge methods. +merge_method+ should be either
|
372
|
+
# +:merge+ or +:merge!+, and denotes which method will be used to merge
|
373
|
+
# recursively.
|
374
|
+
#
|
375
|
+
# @yieldparam key the key which identifies both values
|
376
|
+
# @yieldparam old_value the value from old_ribbon
|
377
|
+
# @yieldparam new_value the value from new_ribbon
|
378
|
+
# @yieldreturn the object that will be used as the new value
|
379
|
+
# @since 0.4.5
|
380
|
+
# @see merge!
|
381
|
+
# @see merge
|
382
|
+
# @see deep_merge
|
383
|
+
# @see deep_merge!
|
384
|
+
def deep(merge_method, old_ribbon, new_ribbon, &block)
|
385
|
+
send merge_method, old_ribbon, new_ribbon do |key, old_value, new_value|
|
386
|
+
if instance?(old_value) and instance?(new_value)
|
387
|
+
deep merge_method, old_value, new_value, &block
|
388
|
+
else
|
389
|
+
if block then block.call key, old_value, new_value
|
390
|
+
else new_value end
|
391
|
+
end
|
392
|
+
end
|
265
393
|
end
|
266
394
|
|
267
395
|
end
|