ribbon 0.4.4 → 0.4.6

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/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