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