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.
@@ -0,0 +1,13 @@
1
+ class Ribbon < BasicObject
2
+
3
+ # Extensions to the standard library.
4
+ #
5
+ # @author Matheus Afonso Martins Moreira
6
+ # @since 0.6.0
7
+ module CoreExtensions; end
8
+
9
+ end
10
+
11
+ %w(array basic_object hash object).each do |file|
12
+ require file.prepend 'ribbon/core_extensions/'
13
+ end
@@ -1,13 +1,18 @@
1
1
  require 'ribbon'
2
2
 
3
3
  class Ribbon < BasicObject
4
- module CoreExt
4
+ module CoreExtensions
5
5
 
6
6
  # Methods to work with ribbons in arrays.
7
+ #
8
+ # @author Matheus Afonso Martins Moreira
9
+ # @since 0.6.0
7
10
  module Array
8
11
 
9
12
  # If the last argument is a hash, removes and converts it to a ribbon,
10
13
  # otherwise returns an empty ribbon.
14
+ #
15
+ # @return [Ribbon] the Ribbon at the end of this array
11
16
  def extract_ribbon!
12
17
  case last
13
18
  when Hash then Ribbon.new pop
@@ -19,19 +24,26 @@ class Ribbon < BasicObject
19
24
 
20
25
  # Extracts the last argument as a wrapped ribbon, or returns an empty one.
21
26
  # See #extract_ribbon! for details.
27
+ #
28
+ # @return [Ribbon::Wrapper] the wrapped Ribbon at the end of this array
22
29
  def extract_wrapped_ribbon!
23
- Ribbon.wrap extract_options_as_ribbon!
30
+ Ribbon.wrap extract_ribbon!
24
31
  end
25
32
 
26
33
  # Same as #extract_ribbon!
34
+ #
35
+ #
36
+ # @return [Ribbon] the Ribbon at the end of this array
27
37
  alias extract_options_as_ribbon! extract_ribbon!
28
38
 
29
39
  # Same as #extract_wrapped_ribbon!
40
+ #
41
+ # @return [Ribbon::Wrapper] the wrapped Ribbon at the end of this array
30
42
  alias extract_options_as_wrapped_ribbon! extract_wrapped_ribbon!
31
43
 
32
44
  end
33
45
 
34
- ::Array.send :include, ::Ribbon::CoreExt::Array
46
+ ::Array.send :include, ::Ribbon::CoreExtensions::Array
35
47
 
36
48
  end
37
49
  end
@@ -0,0 +1,24 @@
1
+ class Ribbon < BasicObject
2
+ module CoreExtensions
3
+
4
+ # Some useful methods.
5
+ #
6
+ # @author Matheus Afonso Martins Moreira
7
+ # @since 0.6.0
8
+ module BasicObject
9
+
10
+ # Evaluates the block using +instance_eval+ if it takes no arguments;
11
+ # yields +self+ to it otherwise.
12
+ #
13
+ # @yieldparam [self] object this instance
14
+ # @return [Object, nil] the result of the block or nil if not given one
15
+ def __yield_or_eval__(&block)
16
+ if block.arity.zero? then instance_eval &block else block.call self end if block
17
+ end
18
+
19
+ end
20
+
21
+ ::BasicObject.send :include, ::Ribbon::CoreExtensions::BasicObject
22
+
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ require 'ribbon'
2
+
3
+ class Ribbon < BasicObject
4
+ module CoreExtensions
5
+
6
+ # Includes methods to convert hashes to ribbons.
7
+ #
8
+ # @author Matheus Afonso Martins Moreira
9
+ # @since 0.6.0
10
+ module Hash
11
+
12
+ # Converts this hash to a Ribbon.
13
+ #
14
+ # @return a new Ribbon with the contents of this hash
15
+ def to_ribbon
16
+ Ribbon.new self
17
+ end
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
+ alias to_rbon to_ribbon
30
+
31
+ # Same as #to_ribbon_wrapper.
32
+ #
33
+ # @return a new wrapped Ribbon with the contents of this hash
34
+ alias to_wrapped_ribbon to_ribbon_wrapper
35
+
36
+ end
37
+
38
+ ::Hash.send :include, ::Ribbon::CoreExtensions::Hash
39
+
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ class Ribbon < BasicObject
2
+ module CoreExtensions
3
+
4
+ # Methods available to all objects.
5
+ #
6
+ # @author Matheus Afonso Martins Moreira
7
+ # @since 0.6.0
8
+ module Object
9
+ end
10
+
11
+ ::Object.send :include, ::Ribbon::CoreExtensions::Object
12
+
13
+ end
14
+ end
15
+
16
+ %w(option_scope yield_or_eval).each do |file|
17
+ require file.prepend 'ribbon/core_extensions/object/'
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'ribbon/options'
2
+
3
+ class Ribbon < BasicObject
4
+ module CoreExtensions
5
+
6
+ module Object
7
+
8
+ # Applies an option scope to this object, where all methods called in the
9
+ # block receive the specified options.
10
+ #
11
+ # @see Ribbon::Options
12
+ def option_scope(options = {}, &block)
13
+ Ribbon::Options.apply_to self, options, &block
14
+ end
15
+
16
+ end
17
+
18
+ ::Object.send :include, ::Ribbon::CoreExtensions::Object
19
+
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'ribbon/core_extensions/basic_object'
2
+
3
+ class Ribbon < BasicObject
4
+ module CoreExtensions
5
+
6
+ module Object
7
+
8
+ alias yield_or_eval __yield_or_eval__
9
+
10
+ end
11
+
12
+ ::Object.send :include, ::Ribbon::CoreExtensions::Object
13
+
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ require 'ribbon'
2
+ require 'ribbon/core_extensions/array'
3
+
4
+ class Ribbon < BasicObject
5
+
6
+ # Applies options to all method calls.
7
+ #
8
+ # Ribbon::Options.new(object, option: :value) do
9
+ # method_with some: :settings # equivalent to { some: :settings, option: :value }
10
+ # overrides option: { with: :another_value }
11
+ # end
12
+ #
13
+ # Ribbon::Options.apply_to(Ribbon.new, separator: '->') do |ribbon|
14
+ # ribbon.to_s
15
+ # ribbon.inspect
16
+ # end
17
+ #
18
+ # @author Matheus Afonso Martins Moreira
19
+ # @since 0.6.0
20
+ class Options < BasicObject
21
+
22
+ # Applies the given options to all methods sent to the receiver. Will apply
23
+ # the block immediately, if given one.
24
+ #
25
+ # @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
+ def initialize(receiver, options = {}, &block)
31
+ @receiver, @options = receiver, options
32
+ __yield_or_eval__ &block
33
+ end
34
+
35
+ # Merges the options given to the method with the options associated with
36
+ # this instance and sends the method to the receiver as normal.
37
+ def method_missing(method, *arguments, &block)
38
+ options = arguments.extract_options_as_ribbon!
39
+ arguments << ::Ribbon.deep_merge(@options, options)
40
+ @receiver.__send__ method, *arguments, &block
41
+ end
42
+
43
+ end
44
+
45
+ class << Options
46
+
47
+ # Applies options to all method calls.
48
+ #
49
+ # @see #initialize
50
+ alias apply_to new
51
+
52
+ end
53
+
54
+ end
@@ -11,7 +11,7 @@ class Ribbon < BasicObject
11
11
  # Minor version.
12
12
  #
13
13
  # Increments denote backward-compatible changes and additions.
14
- MINOR = 5
14
+ MINOR = 6
15
15
 
16
16
  # Patch version.
17
17
  #
@@ -2,68 +2,75 @@ require 'ribbon'
2
2
 
3
3
  class Ribbon < BasicObject
4
4
 
5
- # Wraps around a Ribbon in order to provide general-purpose methods.
5
+ # Wraps a Ribbon in order to provide general-purpose methods.
6
6
  #
7
- # Ribbons are designed to use methods as hash keys. In order to maximize
8
- # possibilities, many useful methods were left out of the ribbon class and
9
- # implemented in this wrapper class instead.
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
10
  #
11
- # This class enables you to use ribbons like an ordinary hash. Any undefined
12
- # methods called on a wrapped ribbon will be sent to its hash, or to the
13
- # ribbon itself if the hash doesn't respond to the method.
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
14
  #
15
- # r = Ribbon.new
16
- # w = Ribbon::Wrapper.new r
15
+ # wrapper = Ribbon::Wrapper.new
17
16
  #
18
- # w.a.b.c
19
- # w[:a][:b][:c]
17
+ # wrapper.a.b.c
18
+ # => {}
19
+ # wrapper.keys
20
+ # => [:a]
20
21
  #
21
- # Wrapped ribbons talk directly to their ribbon's hash:
22
+ # Keep in mind that nested ribbons may or may not be wrapped:
22
23
  #
23
- # w[:k]
24
- # => nil
24
+ # wrapper.a.b.c.keys
25
+ # => {}
26
+ # wrapper
27
+ # => {a: {b: {c: {keys: {}}}}}
25
28
  #
26
- # However, keep in mind that the wrapped hash may contain other ribbons,
27
- # which may not be wrapped:
29
+ # You can wrap and unwrap all ribbons inside:
28
30
  #
29
- # w.a.b.c[:d]
30
- # => {}
31
- #
32
- # You can automatically wrap and unwrap all ribbons inside the wrapped one:
33
- #
34
- # w.wrap_all!
35
- # w.unwrap_all!
36
- #
37
- # The wrapped ribbon receives all undefined methods that hashes won't take:
38
- #
39
- # w.x = 10
40
- # w.ribbon.x
41
- # => 10
31
+ # wrapper.wrap_all!
32
+ # wrapper.unwrap_all!
33
+ # @author Matheus Afonso Martins Moreira
34
+ # @since 0.2.0
35
+ # @see Ribbon
42
36
  class Wrapper
43
37
 
44
- # The wrapped Ribbon object.
45
- attr :ribbon
38
+ # The wrapped Ribbon.
39
+ #
40
+ # @return [Ribbon] the ribbon wrapped by this instance
41
+ def ribbon
42
+ @ribbon ||= Ribbon.new
43
+ end
46
44
 
47
- # Wraps +ribbon+. If it is already wrapped, uses the wrapped ribbon as this
48
- # wrapper's ribbon. If it is a hash, creates a new Ribbon with its data. If
49
- # it is something else, an ArgumentError will be raised.
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
50
  def ribbon=(ribbon)
51
51
  @ribbon = case ribbon
52
52
  when Wrapper then ribbon.ribbon
53
- when Hash then Ribbon.new ribbon
54
53
  when Ribbon then ribbon
55
- else raise ArgumentError, "Can't wrap #{ribbon.class}"
54
+ else Ribbon.new ribbon.to_hash
56
55
  end
57
56
  end
58
57
 
59
- # Wraps a Ribbon object, providing many general-purpose methods that were
60
- # not defined in the Ribbon itself.
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
61
65
  def initialize(ribbon = Ribbon.new, &block)
62
66
  self.ribbon = ribbon
63
- if block.arity.zero? then instance_eval &block else block.call self end if block
67
+ __yield_or_eval__ &block
64
68
  end
65
69
 
66
- # Returns the hash of the wrapped ribbon.
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
67
74
  def internal_hash
68
75
  ribbon.__hash__
69
76
  end
@@ -75,67 +82,85 @@ class Ribbon < BasicObject
75
82
  else ribbon end.__send__ method, *args, &block
76
83
  end
77
84
 
78
- def deep_merge(ribbon)
79
- Ribbon.deep_merge self, ribbon
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)
80
101
  end
81
102
 
82
- def deep_merge!(ribbon)
83
- Ribbon.deep_merge! self, ribbon
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
84
117
  end
85
118
 
86
119
  # Wraps all ribbons contained by this wrapper's ribbon.
120
+ #
121
+ # @return [self] this Ribbon::Wrapper instance
122
+ # @since 0.3.0
87
123
  def wrap_all!
88
124
  wrap_all_recursive!
89
125
  end
90
126
 
91
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
92
131
  def unwrap_all!
93
132
  unwrap_all_recursive!
94
133
  end
95
134
 
96
135
  # Converts the wrapped Ribbon and all ribbons inside into hashes.
136
+ #
137
+ # @return [Hash] the converted contents of this wrapped Ribbon
97
138
  def to_hash
98
139
  to_hash_recursive
99
140
  end
100
141
 
101
- # Converts the wrapped ribbon to a hash and serializes it with YAML. To get
102
- # a Ribbon back from the serialized hash, you can simply load the hash and
103
- # pass it to the Ribbon constructor:
142
+ # Converts the wrapped ribbon to a hash and serializes it with YAML.
104
143
  #
105
- # ribbon = Ribbon.new YAML.load(str)
106
- #
107
- # Alternatively, you can pass a YAML string to the Wrapper::from_yaml
108
- # method.
144
+ # @return [String] the YAML string that represents this Ribbon
145
+ # @see from_yaml
109
146
  def to_yaml
110
147
  to_hash.to_yaml
111
148
  end
112
149
 
113
- # Delegates to Ribbon#to_s.
150
+ # Delegates to the wrapped Ribbon.
151
+ #
152
+ # @return [String] the string representation of this Ribbon::Wrapper
153
+ # @see Ribbon#to_s
114
154
  def to_s
115
155
  ribbon.to_s
116
156
  end
117
157
 
118
- # The class methods.
119
- class << self
120
-
121
- # Wraps a Ribbon instance.
122
- #
123
- # Ribbon::Wrapper[ribbon]
124
- alias [] new
125
-
126
- # Deserializes the hash from the +string+ using YAML and uses it to
127
- # construct a new wrapped ribbon.
128
- def from_yaml(string)
129
- Ribbon::Wrapper.new YAML.load(string)
130
- end
131
-
132
- end
133
-
134
158
  private
135
159
 
136
160
  # Converts the wrapped ribbon and all ribbons inside into hashes using
137
- # recursion. This implementation avoids the creation of additional ribbon or
138
- # wrapper objects.
161
+ # recursion.
162
+ #
163
+ # @return [Hash] the converted contents of the wrapped Ribbon
139
164
  def to_hash_recursive(ribbon = self.ribbon)
140
165
  {}.tap do |hash|
141
166
  ribbon.__hash__.each do |key, value|
@@ -148,21 +173,25 @@ class Ribbon < BasicObject
148
173
  end
149
174
  end
150
175
 
151
- # Recursively wraps all ribbons inside. This implementation avoids the
152
- # creation of additional ribbon or wrapper objects.
176
+ # Recursively wraps all ribbons and hashes inside.
177
+ #
178
+ # @return [self] this Ribbon::Wrapper instance
179
+ # @since 0.3.0
153
180
  def wrap_all_recursive!(wrapper = self)
154
- wrapper.internal_hash.each do |key, value|
155
- wrapper.internal_hash[key] = case value
156
- when Ribbon then wrap_all_recursive! Ribbon::Wrapper[value]
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]
157
184
  else value
158
185
  end
159
186
  end
160
187
  wrapper
161
188
  end
162
189
 
163
- # Recursively unwraps all ribbons inside. This implementation avoids the
164
- # creation of additional ribbon or wrapper objects.
165
- def unwrap_all_recursive!(ribbon = self)
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)
166
195
  ribbon.__hash__.each do |key, value|
167
196
  ribbon[key] = case value
168
197
  when Ribbon::Wrapper then unwrap_all_recursive! value.ribbon
@@ -173,4 +202,23 @@ class Ribbon < BasicObject
173
202
  end
174
203
 
175
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
176
224
  end