ribbon 0.7.0 → 0.8.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.
@@ -1,9 +1,8 @@
1
1
  %w(
2
2
 
3
- ribbon/core_extensions/basic_object
4
3
  ribbon/gem
5
4
  ribbon/options
6
- ribbon/wrapper
5
+ ribbon/raw
7
6
 
8
7
  ).each { |file| require file }
9
8
 
@@ -56,142 +55,127 @@ ribbon/wrapper
56
55
  #
57
56
  # @author Matheus Afonso Martins Moreira
58
57
  # @since 0.1.0
59
- # @see Ribbon::Wrapper
60
- class Ribbon < BasicObject
58
+ # @see Ribbon::Raw
59
+ class Ribbon
61
60
 
62
- # The hash used internally.
61
+ # The raw ribbon.
63
62
  #
64
- # @return [Hash] the hash used by this Ribbon instance to store data
65
- # @api private
66
- def __hash__
67
- @hash ||= (::Hash.new &::Ribbon.default_value_proc)
63
+ # @return [Ribbon::Raw] this ribbon's raw ribbon
64
+ # @since 0.8.0
65
+ def raw
66
+ @raw ||= Ribbon::Raw.new
68
67
  end
69
68
 
70
- # Initializes a new ribbon.
69
+ # Sets this ribbon's raw ribbon.
70
+ #
71
+ # @param [Ribbon, Ribbon::Raw, #to_hash] object the hash-like object
72
+ # @return [Ribbon::Raw] the raw ribbon
73
+ # @since 0.8.0
74
+ def raw=(object)
75
+ @raw = Ribbon.extract_raw_from object
76
+ end
77
+
78
+ # Initializes a new ribbon with the given values.
71
79
  #
72
80
  # If given a block, the ribbon will be yielded to it. If the block doesn't
73
81
  # take any arguments, it will be evaluated in the context of the ribbon.
74
82
  #
75
- # All objects inside the hash will be converted.
76
- #
77
- # @param [#to_hash, Ribbon, Ribbon::Wrapper] hash the hash with the initial
78
- # values
79
- # @see CoreExt::BasicObject#__yield_or_eval__
80
- # @see convert_all!
81
- def initialize(hash = {}, &block)
82
- __hash__.merge! ::Ribbon.extract_hash_from(hash)
83
+ # @param [Ribbon, Ribbon::Raw, #to_hash] initial_values the initial values
84
+ # @see #raw=
85
+ # @see Ribbon::Raw#initialize
86
+ def initialize(initial_values = Ribbon::Raw.new, &block)
87
+ self.raw = initial_values
83
88
  __yield_or_eval__ &block
84
- ::Ribbon.convert_all! self
85
89
  end
86
90
 
87
- # Fetches the value associated with the given key.
88
- #
89
- # If given a block, the value will be yielded to it. If the block doesn't take
90
- # any arguments, it will be evaluated in the context of the value.
91
+ # The hash used by the raw ribbon.
91
92
  #
92
- # @param key the key which identifies the value
93
- # @return the value associated with the given key
94
- # @see CoreExt::BasicObject#__yield_or_eval__
95
- def [](key, &block)
96
- value = ::Ribbon.convert __hash__[key]
97
- value.__yield_or_eval__ &block
98
- self[key] = value
93
+ # @return [Hash] the internal hash of the raw ribbon
94
+ # @since 0.8.0
95
+ def internal_hash
96
+ raw.__hash__
99
97
  end
100
98
 
101
- # Associates the given values with the given key.
102
- #
103
- # @param key the key that will identify the values
104
- # @param values the values that will be associated with the key
105
- # @example
106
- # ribbon = Ribbon.new
107
- #
108
- # ribbon[:key] = :value
109
- # ribbon[:key]
110
- # # => :value
111
- #
112
- # ribbon[:key] = :multiple, :values
113
- # ribbon[:key]
114
- # # => [:multiple, :values]
115
- def []=(key, *values)
116
- __hash__[key] = if values.size == 1 then values.first else values end
99
+ # Forwards the method, arguments and block to the raw ribbon's hash, if it
100
+ # responds to the method, or to the raw ribbon itself otherwise.
101
+ def method_missing(method, *arguments, &block)
102
+ if (hash = internal_hash).respond_to? method then hash
103
+ else raw end.__send__ method, *arguments, &block
117
104
  end
118
105
 
119
- # Handles the following cases:
106
+ # Merges everything inside this ribbon with everything inside the given
107
+ # ribbon, creating a new instance in the process.
120
108
  #
121
- # ribbon.method => ribbon[method]
122
- # ribbon.method value => ribbon[method] = value
123
- # ribbon.method &block => ribbon[method, &block]
124
- # ribbon.method value, &block => ribbon[method] = value
125
- # ribbon[method, &block]
109
+ # @param [Ribbon, Ribbon::Raw, #to_hash] ribbon the ribbon with new values
110
+ # @return [Ribbon] a new ribbon containing the results of the deep merge
111
+ # @yieldparam key the key which identifies both values
112
+ # @yieldparam old_value the value from this ribbon
113
+ # @yieldparam new_value the value from the given ribbon
114
+ # @yieldreturn the object that will be used as the new value
115
+ # @since 0.8.0
116
+ # @see #deep_merge!
117
+ # @see deep_merge
118
+ def deep_merge(ribbon, &block)
119
+ Ribbon.new Ribbon.deep_merge(self, ribbon, &block)
120
+ end
121
+
122
+ # Merges everything inside this ribbon with the given ribbon in place.
126
123
  #
127
- # ribbon.method = value => ribbon[method] = value
124
+ # @param [Ribbon, Ribbon::Raw, #to_hash] ribbon the ribbon with new values
125
+ # @return [self] this ribbon
126
+ # @yieldparam key the key which identifies both values
127
+ # @yieldparam old_value the value from this ribbon
128
+ # @yieldparam new_value the value from the given ribbon
129
+ # @yieldreturn the object that will be used as the new value
130
+ # @since 0.8.0
131
+ # @see #deep_merge
132
+ # @see deep_merge!
133
+ def deep_merge!(ribbon, &block)
134
+ Ribbon.deep_merge! self, ribbon, &block
135
+ end
136
+
137
+ # Converts this ribbon and all ribbons inside into hashes.
128
138
  #
129
- # ribbon.method! value => ribbon[method] = value
130
- # self
131
- # ribbon.method! &block => ribbon[method, &block]
132
- # self
133
- # ribbon.method! value, &block => ribbon[method] = value
134
- # ribbon[method, &block]
135
- # self
139
+ # @return [Hash] the converted contents of this wrapped ribbon
140
+ # @since 0.8.0
141
+ def to_hash
142
+ to_hash_recursive
143
+ end
144
+
145
+ # Converts this ribbon to a hash and serializes it with YAML.
136
146
  #
137
- # ribbon.method? => ribbon.__hash__.fetch method
138
- # ribbon.method? value => ribbon.__hash__.fetch method, value
139
- # ribbon.method? &block => ribbon.__hash__.fetch method, &block
140
- # ribbon.method? value, &block => ribbon.__hash__.fetch method, value, &block
141
- def method_missing(method, *args, &block)
142
- method_string = method.to_s
143
- key = method_string.strip.gsub(/[=?!]$/, '').strip.intern
144
- case method_string[-1]
145
- when ?=
146
- __send__ :[]=, key, *args
147
- when ?!
148
- __send__ :[]=, key, *args unless args.empty?
149
- self[key, &block]
150
- self
151
- when ??
152
- begin self.__hash__.fetch key, *args, &block
153
- rescue ::KeyError; nil end
154
- else
155
- __send__ :[]=, key, *args unless args.empty?
156
- self[key, &block]
157
- end
147
+ # @return [String] the YAML string that represents this ribbon
148
+ # @since 0.8.0
149
+ # @see from_yaml
150
+ def to_yaml
151
+ to_hash.to_yaml
158
152
  end
159
153
 
160
- # Generates a simple <tt>key: value</tt> string representation of this ribbon.
154
+ # Delegates to the raw ribbon.
161
155
  #
162
- # @option opts [String] :separator Separates the key/value pair.
163
- # Default is <tt>': '</tt>.
164
- # @option opts [Symbol] :key Will be sent to the key in order to convert
165
- # it to a string. Default is <tt>:to_s</tt>.
166
- # @option opts [Symbol] :value Will be sent to the value in order to
167
- # convert it to a string. Default is
168
- # <tt>:inspect</tt>.
169
156
  # @return [String] the string representation of this ribbon
170
- def to_s(opts = {})
171
- __to_s_recursive__ ::Ribbon.extract_hash_from(opts)
157
+ # @see Ribbon::Raw#to_s
158
+ def to_s(*arguments, &block)
159
+ raw.to_s *arguments, &block
172
160
  end
173
161
 
174
162
  alias inspect to_s
175
163
 
176
164
  private
177
165
 
178
- # Computes a string value recursively for the given ribbon, and all ribbons
179
- # inside it, using the given options.
166
+ # Converts this ribbon and all ribbons inside into hashes using recursion.
180
167
  #
181
- # @since 0.3.0
182
- # @see #to_s
183
- def __to_s_recursive__(opts = {}, ribbon = self)
184
- ksym = opts.fetch(:key, :to_s).to_sym
185
- vsym = opts.fetch(:value, :inspect).to_sym
186
- separator = opts.fetch(:separator, ': ').to_s
187
- values = ribbon.__hash__.map do |k, v|
188
- k = k.ribbon if ::Ribbon.wrapped? k
189
- v = v.ribbon if ::Ribbon.wrapped? v
190
- k = if ::Ribbon.instance? k then __to_s_recursive__ opts, k else k.__send__ ksym end
191
- v = if ::Ribbon.instance? v then __to_s_recursive__ opts, v else v.__send__ vsym end
192
- "#{k}#{separator}#{v}"
193
- end.join ', '
194
- "{#{values}}"
168
+ # @return [Hash] the converted contents of this ribbon
169
+ def to_hash_recursive(raw_ribbon = self.raw)
170
+ {}.tap do |hash|
171
+ raw_ribbon.__hash__.each do |key, value|
172
+ hash[key] = case value
173
+ when Ribbon then to_hash_recursive value.raw
174
+ when Ribbon::Raw then to_hash_recursive value
175
+ else value
176
+ end
177
+ end
178
+ end
195
179
  end
196
180
 
197
181
  end
@@ -200,57 +184,70 @@ class << Ribbon
200
184
 
201
185
  alias [] new
202
186
 
203
- # Proc used to store a new Ribbon instance as the value of a missing key.
187
+ # Whether the given object is a {Ribbon::Raw raw ribbon}.
204
188
  #
205
- # @return [Proc] the proc used when constructing new hashes
206
- # @since 0.4.6
207
- def default_value_proc
208
- @default_value_proc ||= (proc { |hash, key| hash[key] = Ribbon.new })
189
+ # @param object the object to be tested
190
+ # @return [true, false] whether the object is a raw ribbon
191
+ # @since 0.8.0
192
+ def raw?(object)
193
+ Ribbon::Raw === object
209
194
  end
210
195
 
211
- # Converts hashes to ribbons. Will look inside arrays.
196
+ # Whether the object is compatible with methods that take hashes or ribbons as
197
+ # arguments.
212
198
  #
213
- # @param object the object to convert
214
- # @return the converted value
215
- # @since 0.2.0
216
- def convert(object)
199
+ # @param object the object to be tested
200
+ # @return [true, false] whether the object is a raw ribbon
201
+ # @since 0.8.0
202
+ def compatible?(object)
203
+ [Ribbon, Ribbon::Raw, Hash].any? { |type| type === object }
204
+ end
205
+
206
+ # Extracts the hash of a ribbon. Will attempt to convert other objects.
207
+ #
208
+ # @param [Ribbon, Ribbon::Raw, #to_hash] object the object to convert
209
+ # @return [Hash] the resulting hash
210
+ # @since 0.2.1
211
+ def extract_hash_from(object)
217
212
  case object
218
- when Hash then Ribbon.new object
219
- when Array then object.map { |element| convert element }
220
- else object
213
+ when Ribbon, Ribbon::Raw then object.__hash__
214
+ else object.to_hash
221
215
  end
222
216
  end
223
217
 
224
- # Converts all values inside the given ribbon.
218
+ # Extracts a raw ribbon from the given object.
225
219
  #
226
- # @param [Ribbon, Ribbon::Wrapper] ribbon the ribbon whose values are to be
227
- # converted
228
- # @return [Ribbon, Ribbon::Wrapper] the ribbon with all values converted
229
- # @since 0.2.0
230
- # @see convert
231
- def convert_all!(ribbon)
232
- ribbon.__hash__.each do |key, value|
233
- ribbon[key] = case value
234
- when Ribbon then convert_all! value
235
- when Ribbon::Wrapper then convert_all! value.ribbon
236
- else convert value
237
- end
220
+ # @param [Ribbon, Ribbon::Raw, #to_hash] object the hash-like object
221
+ # @return [Ribbon::Raw] the raw ribbon
222
+ # @since 0.8.0
223
+ def extract_raw_from(object)
224
+ case object
225
+ when Ribbon then object.raw
226
+ when Ribbon::Raw then object
227
+ else Ribbon::Raw.new object.to_hash
238
228
  end
239
- ribbon
229
+ end
230
+
231
+ # Deserializes the hash from the string using YAML and uses it to construct a
232
+ # new ribbon.
233
+ #
234
+ # @param [String] string a valid YAML string
235
+ # @return [Ribbon] a new Ribbon
236
+ # @since 0.4.7
237
+ def from_yaml(string)
238
+ Ribbon.new YAML.load(string)
240
239
  end
241
240
 
242
241
  # Merges the hashes of the given ribbons.
243
242
  #
244
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
245
- # values
246
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
247
- # values
243
+ # @param [Ribbon, Ribbon::Raw, #to_hash] old_ribbon the ribbon with old values
244
+ # @param [Ribbon, Ribbon::Raw, #to_hash] new_ribbon the ribbon with new values
248
245
  # @return [Ribbon] a new ribbon containing the results of the merge
249
246
  # @yieldparam key the key which identifies both values
250
247
  # @yieldparam old_value the value from old_ribbon
251
248
  # @yieldparam new_value the value from new_ribbon
252
249
  # @yieldreturn the object that will be used as the new value
253
- # @since 0.3.0
250
+ # @since 0.8.0
254
251
  # @see merge!
255
252
  # @see extract_hash_from
256
253
  def merge(old_ribbon, new_ribbon, &block)
@@ -262,17 +259,15 @@ class << Ribbon
262
259
 
263
260
  # Merges the hashes of the given ribbons in place.
264
261
  #
265
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
266
- # values
267
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
268
- # values
269
- # @return [Ribbon, Ribbon::Wrapper, Hash] old_ribbon, which will contain the
270
- # results of the merge
262
+ # @param [Ribbon, Ribbon::Raw, #to_hash] old_ribbon the ribbon with old values
263
+ # @param [Ribbon, Ribbon::Raw, #to_hash] new_ribbon the ribbon with new values
264
+ # @return [Ribbon, Ribbon::Raw, Hash] old_ribbon, which will contain the
265
+ # results of the merge
271
266
  # @yieldparam key the key which identifies both values
272
267
  # @yieldparam old_value the value from old_ribbon
273
268
  # @yieldparam new_value the value from new_ribbon
274
269
  # @yieldreturn the object that will be used as the new value
275
- # @since 0.3.0
270
+ # @since 0.8.0
276
271
  # @see merge
277
272
  # @see extract_hash_from
278
273
  def merge!(old_ribbon, new_ribbon, &block)
@@ -284,16 +279,14 @@ class << Ribbon
284
279
 
285
280
  # Merges everything inside the given ribbons.
286
281
  #
287
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
288
- # values
289
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
290
- # values
282
+ # @param [Ribbon, Ribbon::Raw, #to_hash] old_ribbon the ribbon with old values
283
+ # @param [Ribbon, Ribbon::Raw, #to_hash] new_ribbon the ribbon with new values
291
284
  # @return [Ribbon] a new ribbon containing the results of the merge
292
285
  # @yieldparam key the key which identifies both values
293
286
  # @yieldparam old_value the value from old_ribbon
294
287
  # @yieldparam new_value the value from new_ribbon
295
288
  # @yieldreturn the object that will be used as the new value
296
- # @since 0.4.5
289
+ # @since 0.8.0
297
290
  # @see merge
298
291
  # @see deep_merge!
299
292
  # @see extract_hash_from
@@ -303,17 +296,15 @@ class << Ribbon
303
296
 
304
297
  # Merges everything inside the given ribbons in place.
305
298
  #
306
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] old_ribbon the ribbon with old
307
- # values
308
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] new_ribbon the ribbon with new
309
- # values
310
- # @return [Ribbon, Ribbon::Wrapper, Hash] old_ribbon, which will contain the
311
- # results of the merge
299
+ # @param [Ribbon, Ribbon::Raw, #to_hash] old_ribbon the ribbon with old values
300
+ # @param [Ribbon, Ribbon::Raw, #to_hash] new_ribbon the ribbon with new values
301
+ # @return [Ribbon, Ribbon::Raw, Hash] old_ribbon, which will contain the
302
+ # results of the merge
312
303
  # @yieldparam key the key which identifies both values
313
304
  # @yieldparam old_value the value from old_ribbon
314
305
  # @yieldparam new_value the value from new_ribbon
315
306
  # @yieldreturn the object that will be used as the new value
316
- # @since 0.4.5
307
+ # @since 0.8.0
317
308
  # @see merge!
318
309
  # @see deep_merge
319
310
  # @see extract_hash_from
@@ -321,74 +312,26 @@ class << Ribbon
321
312
  deep :merge!, old_ribbon, new_ribbon, &block
322
313
  end
323
314
 
324
- # Tests whether the given object is an instance of Ribbon.
325
- #
326
- # @param object the object to be tested
327
- # @return [true, false] whether the object is an instance of Ribbon
328
- # @since 0.2.0
329
- def instance?(object)
330
- Ribbon === object
331
- end
332
-
333
- # Tests whether the given object is an instance of {Ribbon::Wrapper}.
334
- #
335
- # @param object the object to be tested
336
- # @return [true, false] whether the object is an instance of {Ribbon::Wrapper}
337
- # @since 0.2.0
338
- def wrapped?(ribbon)
339
- Ribbon::Wrapper === ribbon
340
- end
341
-
342
- # Wraps an object in a {Ribbon::Wrapper}.
343
- #
344
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] object the object to be wrapped
345
- # @return [Ribbon::Wrapper] a new wrapped ribbon
346
- # @since 0.2.0
347
- def wrap(object = ::Ribbon.new, &block)
348
- Ribbon::Wrapper.new object, &block
349
- end
350
-
351
- # Returns the hash of a Ribbon. Will attempt to convert other objects.
352
- #
353
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] parameter the object to convert
354
- # @return [Hash] the resulting hash
355
- # @since 0.2.1
356
- def extract_hash_from(parameter)
357
- case parameter
358
- when Ribbon::Wrapper then parameter.internal_hash
359
- when Ribbon then parameter.__hash__
360
- else parameter.to_hash
361
- end
362
- end
363
-
364
- # Deserializes the hash from the string using YAML and uses it to construct a
365
- # new ribbon.
366
- #
367
- # @param [String] string a valid YAML string
368
- # @return [Ribbon] a new Ribbon
369
- # @since 0.4.7
370
- def from_yaml(string)
371
- Ribbon.new YAML.load(string)
372
- end
373
-
374
315
  private
375
316
 
376
- # Common logic for deep merge methods. +merge_method+ should be either
377
- # +:merge+ or +:merge!+, and denotes which method will be used to merge
378
- # recursively.
317
+ # Common logic for deep merge methods.
379
318
  #
319
+ # @param [:merge, :merge!] merge_method the method that will be used to merge
320
+ # recursively
321
+ # @param [Ribbon, Ribbon::Raw, #to_hash] old_ribbon the ribbon with old values
322
+ # @param [Ribbon, Ribbon::Raw, #to_hash] new_ribbon the ribbon with new values
380
323
  # @yieldparam key the key which identifies both values
381
324
  # @yieldparam old_value the value from old_ribbon
382
325
  # @yieldparam new_value the value from new_ribbon
383
326
  # @yieldreturn the object that will be used as the new value
384
- # @since 0.4.5
327
+ # @since 0.8.0
385
328
  # @see merge!
386
329
  # @see merge
387
330
  # @see deep_merge
388
331
  # @see deep_merge!
389
332
  def deep(merge_method, old_ribbon, new_ribbon, &block)
390
333
  send merge_method, old_ribbon, new_ribbon do |key, old_value, new_value|
391
- if instance?(old_value) and instance?(new_value)
334
+ if [old_value, new_value].all? { |value| compatible? value }
392
335
  deep merge_method, old_value, new_value, &block
393
336
  else
394
337
  if block then block.call key, old_value, new_value
@@ -1,4 +1,4 @@
1
- class Ribbon < BasicObject
1
+ class Ribbon
2
2
 
3
3
  # Extensions to the standard library.
4
4
  #
@@ -8,6 +8,11 @@ class Ribbon < BasicObject
8
8
 
9
9
  end
10
10
 
11
- %w(array basic_object hash object).each do |file|
12
- require file.prepend 'ribbon/core_extensions/'
13
- end
11
+ %w(
12
+
13
+ ribbon/core_extensions/array
14
+ ribbon/core_extensions/basic_object
15
+ ribbon/core_extensions/hash
16
+ ribbon/core_extensions/object
17
+
18
+ ).each { |file| require file }
@@ -1,6 +1,6 @@
1
1
  require 'ribbon'
2
2
 
3
- class Ribbon < BasicObject
3
+ class Ribbon
4
4
  module CoreExtensions
5
5
 
6
6
  # Methods to work with ribbons in arrays.
@@ -9,37 +9,30 @@ class Ribbon < BasicObject
9
9
  # @since 0.6.0
10
10
  module Array
11
11
 
12
- # If the last argument is a hash, removes and converts it to a ribbon,
13
- # otherwise returns an empty ribbon.
12
+ # Extracts the last argument as a ribbon or returns an empty one.
14
13
  #
15
- # @return [Ribbon] the Ribbon at the end of this array
14
+ # @return [Ribbon] the ribbon at the end of this array
15
+ # @see #extract_raw_ribbon
16
16
  def extract_ribbon!
17
17
  case last
18
- when Hash then Ribbon.new pop
18
+ when Hash, Ribbon::Raw then Ribbon.new pop
19
19
  when Ribbon then pop
20
- when Ribbon::Wrapper then pop.ribbon
21
20
  else Ribbon.new
22
21
  end
23
22
  end
24
23
 
25
- # Extracts the last argument as a wrapped ribbon, or returns an empty one.
26
- # See #extract_ribbon! for details.
27
- #
28
- # @return [Ribbon::Wrapper] the wrapped Ribbon at the end of this array
29
- def extract_wrapped_ribbon!
30
- Ribbon.wrap extract_ribbon!
31
- end
32
-
33
- # Same as #extract_ribbon!
34
- #
35
- #
36
- # @return [Ribbon] the Ribbon at the end of this array
37
24
  alias extract_options_as_ribbon! extract_ribbon!
38
25
 
39
- # Same as #extract_wrapped_ribbon!
26
+ # Extracts the last argument as a raw ribbon or returns an empty one.
40
27
  #
41
- # @return [Ribbon::Wrapper] the wrapped Ribbon at the end of this array
42
- alias extract_options_as_wrapped_ribbon! extract_wrapped_ribbon!
28
+ # @return [Ribbon::Raw] the raw ribbon at the end of this array
29
+ # @since 0.8.0
30
+ # @see #extract_ribbon!
31
+ def extract_raw_ribbon!
32
+ Ribbon::Raw.new extract_ribbon!
33
+ end
34
+
35
+ alias extract_options_as_raw_ribbon! extract_raw_ribbon!
43
36
 
44
37
  end
45
38
 
@@ -1,4 +1,4 @@
1
- class Ribbon < BasicObject
1
+ class Ribbon
2
2
  module CoreExtensions
3
3
 
4
4
  # Some useful methods.
@@ -8,12 +8,16 @@ class Ribbon < BasicObject
8
8
  module BasicObject
9
9
 
10
10
  # Evaluates the block using +instance_eval+ if it takes no arguments;
11
- # yields +self+ to it otherwise.
11
+ # yields this object to it otherwise.
12
12
  #
13
- # @yieldparam [self] object this instance
14
- # @return [Object, nil] the result of the block or nil if not given one
13
+ # @yieldparam [self] object this object
14
+ # @return [::Object, nil] the result of the block or nil if not given one
15
15
  def __yield_or_eval__(&block)
16
- if block.arity.zero? then instance_eval &block else block.call self end if block
16
+ if block.arity.zero?
17
+ instance_eval &block
18
+ else
19
+ block.call self
20
+ end unless block.nil?
17
21
  end
18
22
 
19
23
  end
@@ -1,6 +1,6 @@
1
1
  require 'ribbon'
2
2
 
3
- class Ribbon < BasicObject
3
+ class Ribbon
4
4
  module CoreExtensions
5
5
 
6
6
  # Includes methods to convert hashes to ribbons.
@@ -9,29 +9,22 @@ class Ribbon < BasicObject
9
9
  # @since 0.6.0
10
10
  module Hash
11
11
 
12
- # Converts this hash to a Ribbon.
12
+ # Converts this hash to a ribbon.
13
13
  #
14
- # @return a new Ribbon with the contents of this hash
14
+ # @return [Ribbon] a new ribbon with the contents of this hash
15
15
  def to_ribbon
16
16
  Ribbon.new self
17
17
  end
18
18
 
19
- # Converts this hash to a Ribbon::Wrapper.
20
- #
21
- # @return a new wrapped Ribbon with the contents of this hash
22
- def to_ribbon_wrapper
23
- Ribbon.wrap self
24
- end
25
-
26
- # Same as #to_ribbon.
27
- #
28
- # @return a new Ribbon with the contents of this hash
29
19
  alias to_rbon to_ribbon
30
20
 
31
- # Same as #to_ribbon_wrapper.
21
+ # Converts this hash to a raw ribbon.
32
22
  #
33
- # @return a new wrapped Ribbon with the contents of this hash
34
- alias to_wrapped_ribbon to_ribbon_wrapper
23
+ # @return [Ribbon::Raw] a new raw ribbon with the contents of this hash
24
+ # @since 0.8.0
25
+ def to_raw_ribbon
26
+ Ribbon.wrap self
27
+ end
35
28
 
36
29
  end
37
30
 
@@ -1,4 +1,4 @@
1
- class Ribbon < BasicObject
1
+ class Ribbon
2
2
  module CoreExtensions
3
3
 
4
4
  # Methods available to all objects.
@@ -13,6 +13,9 @@ class Ribbon < BasicObject
13
13
  end
14
14
  end
15
15
 
16
- %w(option_scope yield_or_eval).each do |file|
17
- require file.prepend 'ribbon/core_extensions/object/'
18
- end
16
+ %w(
17
+
18
+ ribbon/core_extensions/object/option_scope
19
+ ribbon/core_extensions/object/yield_or_eval
20
+
21
+ ).each { |file| require file }
@@ -1,6 +1,6 @@
1
1
  require 'ribbon/options'
2
2
 
3
- class Ribbon < BasicObject
3
+ class Ribbon
4
4
  module CoreExtensions
5
5
 
6
6
  module Object
@@ -1,6 +1,6 @@
1
1
  require 'ribbon/core_extensions/basic_object'
2
2
 
3
- class Ribbon < BasicObject
3
+ class Ribbon
4
4
  module CoreExtensions
5
5
 
6
6
  module Object
@@ -1,6 +1,6 @@
1
1
  require 'jewel'
2
2
 
3
- class Ribbon < BasicObject
3
+ class Ribbon
4
4
 
5
5
  # Ribbon gem information and metadata.
6
6
  #
@@ -1,7 +1,11 @@
1
- require 'ribbon'
2
- require 'ribbon/core_extensions/array'
1
+ %w(
3
2
 
4
- class Ribbon < BasicObject
3
+ ribbon
4
+ ribbon/core_extensions/array
5
+
6
+ ).each { |file| require file }
7
+
8
+ class Ribbon
5
9
 
6
10
  # Applies options to all method calls.
7
11
  #
@@ -23,10 +27,9 @@ class Ribbon < BasicObject
23
27
  # the block immediately, if given one.
24
28
  #
25
29
  # @param receiver the object that will be receiving the methods
26
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] options the options that will
27
- # be applied to all
28
- # methods
29
- # @see CoreExt::BasicObject#__yield_or_eval__
30
+ # @param [Ribbon, Ribbon::Raw, #to_hash] options the options that will be
31
+ # applied to all methods
32
+ # @see CoreExtensions::BasicObject#__yield_or_eval__
30
33
  def initialize(receiver, options = {}, &block)
31
34
  @receiver, @options = receiver, options
32
35
  __yield_or_eval__ &block
@@ -0,0 +1,195 @@
1
+ %w(
2
+
3
+ ribbon
4
+ ribbon/core_extensions/basic_object
5
+
6
+ ).each { |file| require file }
7
+
8
+ class Ribbon
9
+
10
+ # Ribbon with the least amount of helper methods defined.
11
+ #
12
+ # @author Matheus Afonso Martins Moreira
13
+ # @since 0.8.0
14
+ # @see Ribbon
15
+ class Raw < BasicObject
16
+
17
+ # The hash used internally.
18
+ #
19
+ # @return [Hash] the hash used by this Ribbon instance to store data
20
+ # @api private
21
+ def __hash__
22
+ @hash ||= (::Hash.new &::Ribbon::Raw.default_value_proc)
23
+ end
24
+
25
+ # Initializes a new raw ribbon with the given values.
26
+ #
27
+ # If given a block, the raw ribbon will be yielded to it. If the block
28
+ # doesn't take any arguments, it will be evaluated in the context of the raw
29
+ # ribbon.
30
+ #
31
+ # All objects inside the hash will be {convert_all! converted}.
32
+ #
33
+ # @param [Ribbon, Ribbon::Raw, #to_hash] hash the hash with initial values
34
+ # @see CoreExtensions::BasicObject#__yield_or_eval__
35
+ def initialize(hash = {}, &block)
36
+ __hash__.merge! ::Ribbon.extract_hash_from hash
37
+ __yield_or_eval__ &block
38
+ ::Ribbon::Raw.convert_all! self
39
+ end
40
+
41
+ # Fetches the value associated with the given key.
42
+ #
43
+ # If given a block, the value will be yielded to it. If the block doesn't take
44
+ # any arguments, it will be evaluated in the context of the value.
45
+ #
46
+ # @param key the key which identifies the value
47
+ # @return the value associated with the given key
48
+ # @see CoreExtensions::BasicObject#__yield_or_eval__
49
+ def [](key, &block)
50
+ value = ::Ribbon::Raw.convert __hash__[key]
51
+ value.__yield_or_eval__ &block
52
+ self[key] = value
53
+ end
54
+
55
+ # Associates the given values with the given key.
56
+ #
57
+ # @param key the key that will identify the values
58
+ # @param values the values that will be associated with the key
59
+ # @raise [ArgumentError] if the given key is a raw ribbon
60
+ # @example
61
+ # ribbon = Ribbon.new
62
+ #
63
+ # ribbon[:key] = :value
64
+ # ribbon[:key]
65
+ # # => :value
66
+ #
67
+ # ribbon[:key] = :multiple, :values
68
+ # ribbon[:key]
69
+ # # => [:multiple, :values]
70
+ def []=(key, *values)
71
+ raise ArgumentError, 'Raw Ribbons can not be used as hash keys' if ::Ribbon.raw? key
72
+ __hash__[key] = if values.size == 1 then values.first else values end
73
+ end
74
+
75
+ # Handles the following cases:
76
+ #
77
+ # ribbon.method => ribbon[:method]
78
+ # ribbon.method value => ribbon[:method] = value
79
+ # ribbon.method &block => ribbon[:method, &block]
80
+ # ribbon.method value, &block => ribbon[:method] = value
81
+ # ribbon[:method, &block]
82
+ #
83
+ # ribbon.method = value => ribbon[:method] = value
84
+ #
85
+ # ribbon.method! value => ribbon[:method] = value
86
+ # self
87
+ # ribbon.method! &block => block.call ribbon[:method] if ribbon.__hash__.include? :method
88
+ # self
89
+ # ribbon.method! value, &block => ribbon[:method] = value
90
+ # block.call ribbon[:method]
91
+ # self
92
+ #
93
+ # ribbon.method? => ribbon.__hash__.fetch :method
94
+ # ribbon.method? value => ribbon.__hash__.fetch :method, value
95
+ # ribbon.method? &block => ribbon.__hash__.fetch :method, &block
96
+ # ribbon.method? value, &block => ribbon.__hash__.fetch :method, value, &block
97
+ def method_missing(method, *arguments, &block)
98
+ method_name = method.to_s
99
+ key = method_name.strip.gsub(/[=?!]$/, '').strip.intern
100
+ case method_name[-1]
101
+ when ?=
102
+ __send__ :[]=, key, *arguments
103
+ when ?!
104
+ __send__ :[]=, key, *arguments unless arguments.empty?
105
+ block.call self[key] if block and __hash__.include? key
106
+ self
107
+ when ??
108
+ begin __hash__.fetch key, *arguments, &block
109
+ rescue ::KeyError; nil end
110
+ else
111
+ __send__ :[]=, key, *arguments unless arguments.empty?
112
+ self[key, &block]
113
+ end
114
+ end
115
+
116
+ # Generates a simple and customizable human-readable string representation
117
+ # of this raw ribbon.
118
+ #
119
+ # @option options [#to_s] :separator (': ') separates the key/value pair
120
+ # @option options [#to_sym] :key (:to_s) will be sent to the key in order to
121
+ # convert it to a string.
122
+ # @option options [#to_sym] :value (:inspect) will be sent to the value in
123
+ # order to convert it to a string.
124
+ # @return [String] the string representation of this raw ribbon
125
+ def to_s(options = {})
126
+ __to_s_recursive__ ::Ribbon.extract_hash_from(options)
127
+ end
128
+
129
+ alias inspect to_s
130
+
131
+ private
132
+
133
+ # Computes a string value recursively for the given ribbon, and all ribbons
134
+ # inside it, using the given options.
135
+ #
136
+ # @see #to_s
137
+ def __to_s_recursive__(options = {}, ribbon = self)
138
+ ksym = options.fetch(:key, :to_s).to_sym
139
+ vsym = options.fetch(:value, :inspect).to_sym
140
+ separator = options.fetch(:separator, ': ').to_s
141
+ '{%s}' % ribbon.__hash__.map do |k, v|
142
+ k = k.__send__ ksym
143
+ v = v.raw if ::Ribbon === v
144
+ v = if ::Ribbon.raw? v then __to_s_recursive__ options, v
145
+ else v.__send__ vsym end
146
+ '%s%s%s' % [ k, separator, v ]
147
+ end.join(', ')
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+
154
+ class << Ribbon::Raw
155
+
156
+ alias [] new
157
+
158
+ # Proc used to store a new {Ribbon ribbon} instance as the value of a missing
159
+ # key.
160
+ #
161
+ # @return [Proc] the proc used when constructing new hashes
162
+ def default_value_proc
163
+ @default_value_proc ||= (proc { |hash, key| hash[key] = Ribbon.new })
164
+ end
165
+
166
+ # Converts hashes to ribbons. Will look inside arrays.
167
+ #
168
+ # @param object the object to convert
169
+ # @return the converted value
170
+ def convert(object)
171
+ case object
172
+ when Hash then Ribbon.new object
173
+ when Array then object.map { |element| convert element }
174
+ else object
175
+ end
176
+ end
177
+
178
+ # Converts all values inside the given ribbon.
179
+ #
180
+ # @param [Ribbon, Ribbon::Raw] ribbon the ribbon whose values are to be
181
+ # converted
182
+ # @return [Ribbon, Ribbon::Raw] the ribbon with all values converted
183
+ # @see convert
184
+ def convert_all!(ribbon)
185
+ ribbon.__hash__.each do |key, value|
186
+ ribbon[key] = case value
187
+ when Ribbon then convert_all! value.raw
188
+ when Ribbon::Raw then convert_all! value
189
+ else convert value
190
+ end
191
+ end
192
+ ribbon
193
+ end
194
+
195
+ end
@@ -1 +1 @@
1
- 0.7.0
1
+ 0.8.0
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.7.0
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-24 00:00:00.000000000 Z
12
+ date: 2012-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jewel
@@ -98,7 +98,7 @@ files:
98
98
  - lib/ribbon/core_extensions/object/yield_or_eval.rb
99
99
  - lib/ribbon/gem.rb
100
100
  - lib/ribbon/options.rb
101
- - lib/ribbon/wrapper.rb
101
+ - lib/ribbon/raw.rb
102
102
  - ribbon.gemspec
103
103
  - ribbon.version
104
104
  homepage: https://github.com/matheusmoreira/ribbon
@@ -115,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
115
  version: '0'
116
116
  segments:
117
117
  - 0
118
- hash: -1868364444812272642
118
+ hash: 834480014355200814
119
119
  required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  none: false
121
121
  requirements:
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  version: '0'
125
125
  segments:
126
126
  - 0
127
- hash: -1868364444812272642
127
+ hash: 834480014355200814
128
128
  requirements: []
129
129
  rubyforge_project:
130
130
  rubygems_version: 1.8.24
@@ -1,224 +0,0 @@
1
- require 'ribbon'
2
-
3
- class Ribbon < BasicObject
4
-
5
- # Wraps a Ribbon in order to provide general-purpose methods.
6
- #
7
- # Ribbons are designed to use methods as hash keys. In order to maximize the
8
- # number of possibilities, many useful methods, including methods from Object,
9
- # were left out and included in this class instead.
10
- #
11
- # You can use wrapped ribbons like an ordinary hash. Any undefined methods
12
- # will be sent to the ribbon's hash. If the hash doesn't respond to the
13
- # method, it will be sent to the ribbon itself.
14
- #
15
- # wrapper = Ribbon::Wrapper.new
16
- #
17
- # wrapper.a.b.c
18
- # => {}
19
- # wrapper.keys
20
- # => [:a]
21
- #
22
- # Keep in mind that nested ribbons may or may not be wrapped:
23
- #
24
- # wrapper.a.b.c.keys
25
- # => {}
26
- # wrapper
27
- # => {a: {b: {c: {keys: {}}}}}
28
- #
29
- # You can wrap and unwrap all ribbons inside:
30
- #
31
- # wrapper.wrap_all!
32
- # wrapper.unwrap_all!
33
- # @author Matheus Afonso Martins Moreira
34
- # @since 0.2.0
35
- # @see Ribbon
36
- class Wrapper
37
-
38
- # The wrapped Ribbon.
39
- #
40
- # @return [Ribbon] the ribbon wrapped by this instance
41
- def ribbon
42
- @ribbon ||= Ribbon.new
43
- end
44
-
45
- # Wraps a Ribbon, another Wrapper's Ribbon or a hash.
46
- #
47
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] ribbon the ribbon that will be
48
- # wrapped
49
- # @return [Ribbon] the wrapped Ribbon
50
- def ribbon=(ribbon)
51
- @ribbon = case ribbon
52
- when Wrapper then ribbon.ribbon
53
- when Ribbon then ribbon
54
- else Ribbon.new ribbon.to_hash
55
- end
56
- end
57
-
58
- # Wraps the given Ribbon, another Wrapper's Ribbon or a hash.
59
- #
60
- # If given a block, the wrapper will be yielded to it. If the block doesn't
61
- # take any arguments, it will be evaluated in the context of the wrapper.
62
- #
63
- # @see #ribbon=
64
- # @see Ribbon#initialize
65
- def initialize(ribbon = Ribbon.new, &block)
66
- self.ribbon = ribbon
67
- __yield_or_eval__ &block
68
- end
69
-
70
- # The hash used by the wrapped Ribbon.
71
- #
72
- # @return [Hash] the internal hash of the Ribbon wrapped by this instance
73
- # @since 0.5.0
74
- def internal_hash
75
- ribbon.__hash__
76
- end
77
-
78
- # Forwards the method, arguments and block to the wrapped Ribbon's hash, if
79
- # it responds to the method, or to the ribbon itself otherwise.
80
- def method_missing(method, *args, &block)
81
- if (hash = internal_hash).respond_to? method then hash
82
- else ribbon end.__send__ method, *args, &block
83
- end
84
-
85
- # Merges the contents of this wrapped Ribbon with the contents of the given
86
- # Ribbon into a new Ribbon::Wrapper instance.
87
- #
88
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] ribbon the ribbon with new
89
- # values
90
- # @return [Ribbon::Wrapper] a new wrapped ribbon containing the results of
91
- # the merge
92
- # @yieldparam key the key which identifies both values
93
- # @yieldparam old_value the value from this wrapped Ribbon
94
- # @yieldparam new_value the value from the given ribbon
95
- # @yieldreturn the object that will be used as the new value
96
- # @since 0.4.5
97
- # @see #deep_merge!
98
- # @see Ribbon.deep_merge
99
- def deep_merge(ribbon, &block)
100
- Ribbon.wrap Ribbon.deep_merge(self, ribbon, &block)
101
- end
102
-
103
- # Merges this wrapped Ribbon with the given Ribbon.
104
- #
105
- # @param [Ribbon, Ribbon::Wrapper, #to_hash] ribbon the ribbon with new
106
- # values
107
- # @return [self] this Ribbon::Wrapper instance
108
- # @yieldparam key the key which identifies both values
109
- # @yieldparam old_value the value from this wrapped Ribbon
110
- # @yieldparam new_value the value from the given ribbon
111
- # @yieldreturn the object that will be used as the new value
112
- # @since 0.4.5
113
- # @see #deep_merge
114
- # @see Ribbon.deep_merge!
115
- def deep_merge!(ribbon, &block)
116
- Ribbon.deep_merge! self, ribbon, &block
117
- end
118
-
119
- # Wraps all ribbons contained by this wrapper's ribbon.
120
- #
121
- # @return [self] this Ribbon::Wrapper instance
122
- # @since 0.3.0
123
- def wrap_all!
124
- wrap_all_recursive!
125
- end
126
-
127
- # Unwraps all ribbons contained by this wrapper's ribbon.
128
- #
129
- # @return [Ribbon] the Ribbon wrapped by this instance
130
- # @since 0.3.0
131
- def unwrap_all!
132
- unwrap_all_recursive!
133
- end
134
-
135
- # Converts the wrapped Ribbon and all ribbons inside into hashes.
136
- #
137
- # @return [Hash] the converted contents of this wrapped Ribbon
138
- def to_hash
139
- to_hash_recursive
140
- end
141
-
142
- # Converts the wrapped ribbon to a hash and serializes it with YAML.
143
- #
144
- # @return [String] the YAML string that represents this Ribbon
145
- # @see from_yaml
146
- def to_yaml
147
- to_hash.to_yaml
148
- end
149
-
150
- # Delegates to the wrapped Ribbon.
151
- #
152
- # @return [String] the string representation of this Ribbon::Wrapper
153
- # @see Ribbon#to_s
154
- def to_s
155
- ribbon.to_s
156
- end
157
-
158
- private
159
-
160
- # Converts the wrapped ribbon and all ribbons inside into hashes using
161
- # recursion.
162
- #
163
- # @return [Hash] the converted contents of the wrapped Ribbon
164
- def to_hash_recursive(ribbon = self.ribbon)
165
- {}.tap do |hash|
166
- ribbon.__hash__.each do |key, value|
167
- hash[key] = case value
168
- when Ribbon then to_hash_recursive value
169
- when Ribbon::Wrapper then to_hash_recursive value.ribbon
170
- else value
171
- end
172
- end
173
- end
174
- end
175
-
176
- # Recursively wraps all ribbons and hashes inside.
177
- #
178
- # @return [self] this Ribbon::Wrapper instance
179
- # @since 0.3.0
180
- def wrap_all_recursive!(wrapper = self)
181
- (hash = wrapper.internal_hash).each do |key, value|
182
- hash[key] = case value
183
- when Ribbon, Hash then wrap_all_recursive! Ribbon::Wrapper[value]
184
- else value
185
- end
186
- end
187
- wrapper
188
- end
189
-
190
- # Recursively unwraps all wrapped ribbons inside.
191
- #
192
- # @return [Ribbon] the Ribbon wrapped by this instance
193
- # @since 0.3.0
194
- def unwrap_all_recursive!(ribbon = self.ribbon)
195
- ribbon.__hash__.each do |key, value|
196
- ribbon[key] = case value
197
- when Ribbon::Wrapper then unwrap_all_recursive! value.ribbon
198
- else value
199
- end
200
- end
201
- ribbon
202
- end
203
-
204
- end
205
-
206
- class << Wrapper
207
-
208
- # Wraps a Ribbon instance.
209
- #
210
- # @see #initialize
211
- alias [] new
212
-
213
- # Deserializes the hash from the +string+ using YAML and uses it to
214
- # construct a new wrapped ribbon.
215
- #
216
- # @return [Ribbon::Wrapper] a new wrapped Ribbon
217
- # @since 0.4.4
218
- # @see #to_yaml
219
- def from_yaml(string)
220
- ::Ribbon::Wrapper.new YAML.load(string)
221
- end
222
-
223
- end
224
- end