ribbon 0.4.4 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -46,8 +46,8 @@ context of the value instance. The above example could be rewritten as:
46
46
 
47
47
  > Ribbon.new.tap do |config|
48
48
  config.music do
49
- music.file do
50
- file.extensions %w(flac mp3 ogg wma)
49
+ file do
50
+ extensions %w(flac mp3 ogg wma)
51
51
  end
52
52
  end
53
53
  end
@@ -16,7 +16,7 @@ class Ribbon < BasicObject
16
16
  # Patch version.
17
17
  #
18
18
  # Increments denote changes in implementation.
19
- PATCH = 4
19
+ PATCH = 6
20
20
 
21
21
  # Build version.
22
22
  #
@@ -83,6 +83,14 @@ class Ribbon < BasicObject
83
83
  else ribbon end.__send__ method, *args, &block
84
84
  end
85
85
 
86
+ def deep_merge(ribbon)
87
+ ::Ribbon.deep_merge self, ribbon
88
+ end
89
+
90
+ def deep_merge!(ribbon)
91
+ ::Ribbon.deep_merge! self, ribbon
92
+ end
93
+
86
94
  # Wraps all ribbons contained by this wrapper's ribbon.
87
95
  def wrap_all!
88
96
  wrap_all_recursive!
data/lib/ribbon.rb CHANGED
@@ -56,7 +56,7 @@ class Ribbon < BasicObject
56
56
 
57
57
  # The internal Hash.
58
58
  def __hash__
59
- @hash ||= {}
59
+ @hash ||= (::Hash.new &::Ribbon.default_value_proc)
60
60
  end
61
61
 
62
62
  # Initializes the new ribbon, merging the internal hash with the given one and
@@ -68,8 +68,7 @@ class Ribbon < BasicObject
68
68
 
69
69
  # Gets a value by key.
70
70
  def [](key, &block)
71
- value = if __hash__.has_key? key then ::Ribbon.convert __hash__[key]
72
- else ::Ribbon.new end
71
+ value = ::Ribbon.convert __hash__[key]
73
72
  if block.arity.zero? then value.instance_eval &block
74
73
  else block.call value end if block
75
74
  self[key] = value
@@ -101,7 +100,8 @@ class Ribbon < BasicObject
101
100
  when '!'
102
101
  self[m] = args.first; self
103
102
  when '?'
104
- self.__hash__.fetch m, *args, &block
103
+ begin self.__hash__.fetch m, *args, &block
104
+ rescue ::KeyError; nil end
105
105
  else
106
106
  self[method] = args.first unless args.empty?
107
107
  self[method, &block]
@@ -125,72 +125,117 @@ class Ribbon < BasicObject
125
125
  # Same as #to_s.
126
126
  alias inspect to_s
127
127
 
128
- # If <tt>object</tt> is a hash, converts it to a ribbon. If it is an array,
129
- # converts any hashes inside.
130
- def self.convert(object)
131
- case object
132
- when ::Hash then self.new object
133
- when ::Array then object.map { |element| convert element }
134
- else object
128
+ # The class methods.
129
+ class << self
130
+
131
+ # A Proc which returns a new ribbon as the default value for the given hash
132
+ # key.
133
+ def default_value_proc
134
+ @default_value_proc ||= (proc { |hash, key| hash[key] = Ribbon.new })
135
135
  end
136
- end
137
136
 
138
- # Converts all values in the given ribbon.
139
- def self.convert_all!(ribbon)
140
- ribbon.__hash__.each do |key, value|
141
- ribbon[key] = case value
142
- when self then convert_all! value
143
- else convert value
137
+ # If <tt>object</tt> is a hash, converts it to a ribbon. If it is an array,
138
+ # converts any hashes inside.
139
+ def convert(object)
140
+ case object
141
+ when Hash then Ribbon.new object
142
+ when Array then object.map { |element| convert element }
143
+ else object
144
144
  end
145
145
  end
146
- ribbon
147
- end
148
146
 
149
- # Merges the hash of +new+ with the hash of +old+, creating a new ribbon in
150
- # the process.
151
- def self.merge(old, new, &block)
152
- new extract_hash_from(old).merge(extract_hash_from(new), &block)
153
- end
147
+ # Converts all values in the given ribbon.
148
+ def convert_all!(ribbon)
149
+ ribbon.__hash__.each do |key, value|
150
+ ribbon[key] = case value
151
+ when Ribbon then convert_all! value
152
+ else convert value
153
+ end
154
+ end
155
+ ribbon
156
+ end
154
157
 
155
- # Merges the hash of +new+ with the hash of +old+, modifying +old+'s hash in
156
- # the process.
157
- def self.merge!(old, new, &block)
158
- extract_hash_from(old).merge! extract_hash_from(new), &block
159
- end
158
+ # Merges the hash of +new_ribbon+ with the hash of +old_ribbon+, creating a
159
+ # new ribbon in the process.
160
+ def merge(old_ribbon, new_ribbon, &block)
161
+ old_hash = extract_hash_from old_ribbon
162
+ new_hash = extract_hash_from new_ribbon
163
+ merged_hash = old_hash.merge new_hash, &block
164
+ Ribbon.new merged_hash
165
+ end
160
166
 
161
- # Returns +true+ if the given +object+ is a ribbon.
162
- def self.instance?(object)
163
- self === object
164
- end
167
+ # Merges the hash of +new_ribbon+ with the hash of +old_ribbon+, modifying
168
+ # +old_ribbon+'s hash in the process.
169
+ def merge!(old_ribbon, new_ribbon, &block)
170
+ old_hash = extract_hash_from old_ribbon
171
+ new_hash = extract_hash_from new_ribbon
172
+ old_hash.merge! new_hash, &block
173
+ old_ribbon
174
+ end
165
175
 
166
- # Returns +true+ if the given ribbon is wrapped.
167
- def self.wrapped?(ribbon)
168
- ::Ribbon::Wrapper === ribbon
169
- end
176
+ # Merges the +new_ribbon+ and all nested ribbons with the +old_ribbon+
177
+ # recursively, returning a new ribbon.
178
+ def deep_merge(old_ribbon, new_ribbon, &block)
179
+ deep :merge, old_ribbon, new_ribbon, &block
180
+ end
170
181
 
171
- # Wraps a ribbon instance in a Ribbon::Wrapper.
172
- def self.wrap(ribbon = ::Ribbon.new)
173
- ::Ribbon::Wrapper.new ribbon
174
- end
182
+ # Merges the +new_ribbon+ and all nested ribbons with the +old_ribbon+
183
+ # recursively, modifying all ribbons in place.
184
+ def deep_merge!(old_ribbon, new_ribbon, &block)
185
+ deep :merge!, old_ribbon, new_ribbon, &block
186
+ end
175
187
 
176
- # Unwraps the +ribbon+ if it is wrapped and returns its hash. Returns +nil+ in
177
- # any other case.
178
- def self.extract_hash_from(ribbon)
179
- case ribbon
180
- when ::Ribbon::Wrapper then ribbon.hash
181
- when ::Ribbon then ribbon.__hash__
182
- when ::Hash then ribbon
183
- else nil
188
+ # Returns +true+ if the given +object+ is a ribbon.
189
+ def instance?(object)
190
+ Ribbon === object
184
191
  end
185
- end
186
192
 
187
- class << self
193
+ # Returns +true+ if the given ribbon is wrapped.
194
+ def wrapped?(ribbon)
195
+ Ribbon::Wrapper === ribbon
196
+ end
197
+
198
+ # Wraps a ribbon instance in a Ribbon::Wrapper.
199
+ def wrap(ribbon = ::Ribbon.new)
200
+ Ribbon::Wrapper.new ribbon
201
+ end
202
+
203
+ # Unwraps the +ribbon+ if it is wrapped and returns its hash. Returns +nil+
204
+ # in any other case.
205
+ def extract_hash_from(ribbon)
206
+ case ribbon
207
+ when Ribbon::Wrapper then ribbon.hash
208
+ when Ribbon then ribbon.__hash__
209
+ when Hash then ribbon
210
+ else nil
211
+ end
212
+ end
188
213
 
189
214
  # Wraps a ribbon instance in a Ribbon::Wrapper.
190
215
  #
191
216
  # Ribbon[ribbon].keys
192
217
  alias [] wrap
193
218
 
219
+ private
220
+
221
+ # Common logic for deep merge functions. +merge_func+ should be either
222
+ # +merge+ or +merge!+, and denotes which function will be used to merge
223
+ # recursively. +args+ will be forwarded to the merge function.
224
+ #
225
+ # If given a block, it will be called with the key, the old value and the
226
+ # new value as parameters and its return value will be used. The value of
227
+ # the new hash will be used, otherwise.
228
+ def deep(merge_method, old_ribbon, new_ribbon, &block)
229
+ send merge_method, old_ribbon, new_ribbon do |key, old_value, new_value|
230
+ if instance?(old_value) and instance?(new_value)
231
+ deep merge_method, old_value, new_value, &block
232
+ else
233
+ if block.respond_to? :call then block.call key, old_value, new_value
234
+ else new_value end
235
+ end
236
+ end
237
+ end
238
+
194
239
  end
195
240
 
196
241
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ribbon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-03 00:00:00.000000000 Z
12
+ date: 2012-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rookie
16
- requirement: &18087600 !ruby/object:Gem::Requirement
16
+ requirement: &14094740 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *18087600
24
+ version_requirements: *14094740
25
25
  description: Ruby Object Notation. Inspired by JSON and OpenStruct.
26
26
  email: matheus.a.m.moreira@gmail.com
27
27
  executables: []
@@ -55,7 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
55
  version: '0'
56
56
  segments:
57
57
  - 0
58
- hash: -3618044830386511159
58
+ hash: -2764903379968974603
59
59
  required_rubygems_version: !ruby/object:Gem::Requirement
60
60
  none: false
61
61
  requirements:
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  version: '0'
65
65
  segments:
66
66
  - 0
67
- hash: -3618044830386511159
67
+ hash: -2764903379968974603
68
68
  requirements: []
69
69
  rubyforge_project:
70
70
  rubygems_version: 1.8.10