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.
- 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
@@ -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
|
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
|
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::
|
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,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
|
data/lib/ribbon/version.rb
CHANGED
data/lib/ribbon/wrapper.rb
CHANGED
@@ -2,68 +2,75 @@ require 'ribbon'
|
|
2
2
|
|
3
3
|
class Ribbon < BasicObject
|
4
4
|
|
5
|
-
# Wraps
|
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
|
9
|
-
#
|
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
|
-
#
|
12
|
-
#
|
13
|
-
#
|
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
|
-
#
|
16
|
-
# w = Ribbon::Wrapper.new r
|
15
|
+
# wrapper = Ribbon::Wrapper.new
|
17
16
|
#
|
18
|
-
#
|
19
|
-
#
|
17
|
+
# wrapper.a.b.c
|
18
|
+
# => {}
|
19
|
+
# wrapper.keys
|
20
|
+
# => [:a]
|
20
21
|
#
|
21
|
-
#
|
22
|
+
# Keep in mind that nested ribbons may or may not be wrapped:
|
22
23
|
#
|
23
|
-
#
|
24
|
-
#
|
24
|
+
# wrapper.a.b.c.keys
|
25
|
+
# => {}
|
26
|
+
# wrapper
|
27
|
+
# => {a: {b: {c: {keys: {}}}}}
|
25
28
|
#
|
26
|
-
#
|
27
|
-
# which may not be wrapped:
|
29
|
+
# You can wrap and unwrap all ribbons inside:
|
28
30
|
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
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
|
45
|
-
|
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
|
48
|
-
#
|
49
|
-
#
|
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
|
54
|
+
else Ribbon.new ribbon.to_hash
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
|
-
# Wraps
|
60
|
-
#
|
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
|
-
|
67
|
+
__yield_or_eval__ &block
|
64
68
|
end
|
65
69
|
|
66
|
-
#
|
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
|
-
|
79
|
-
|
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
|
-
|
83
|
-
|
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.
|
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
|
-
#
|
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
|
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.
|
138
|
-
#
|
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.
|
152
|
-
#
|
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
|
-
|
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.
|
164
|
-
#
|
165
|
-
|
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
|