adornable 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +32 -46
- data/adornable.gemspec +1 -1
- data/lib/adornable/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b916559874ffdc52baa8f1b2a75a7e550ad600c501d45adeaf4c53aa0796c97
|
4
|
+
data.tar.gz: b7fd7d3eeaaae6b706fbe9f9b9f0d24770351a5ebbbd18759bd96d014466b001
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3d49e5efb60aec78d2b416c6d36c8c02844151a6824503f9301db45a4cd392ccea9f316500723e84a07d7ecb200b86a31c71bbc571e3294adfa637a7b92956f
|
7
|
+
data.tar.gz: a97a7142ccc356e8657421e32de71f30c6a9070e73a618e5fbaa238ae2b7e3e7193ce11782a942f75b0606d14af54f79a4fd772de83526f200c2da504f353140
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Adornable
|
2
2
|
|
3
|
-
Adornable provides
|
3
|
+
Adornable provides the ability to cleanly decorate methods in Ruby. You can make and use your own decorators, and you can also use some of the built-in ones that the gem provides. _Decorating_ methods is as simple as slapping a `decorate :some_decorator` above your method definition. _Defining_ decorators can be as simple as defining a method that yields to a block, or as complex as manipulating the decorated method's receiver and arguments, and/or changing the functionality of the decorator based on custom options supplied to it when initially applying the decorator.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -26,8 +26,6 @@ Alternatively, install it globally:
|
|
26
26
|
gem install adornable
|
27
27
|
```
|
28
28
|
|
29
|
-
...but why would you do that?
|
30
|
-
|
31
29
|
## Usage
|
32
30
|
|
33
31
|
### The basics
|
@@ -75,9 +73,9 @@ value2 = random_value_generator.value
|
|
75
73
|
#=> 0.4196007135344746
|
76
74
|
```
|
77
75
|
|
78
|
-
|
76
|
+
However, you have a million more methods to write, and if you refactor, you'll have to screw around with a slew of method definitions across your app.
|
79
77
|
|
80
|
-
|
78
|
+
What if you could do this, instead, to achieve the same result?
|
81
79
|
|
82
80
|
```rb
|
83
81
|
class RandomValueGenerator
|
@@ -95,28 +93,6 @@ class RandomValueGenerator
|
|
95
93
|
(1..max).map { rand }
|
96
94
|
end
|
97
95
|
end
|
98
|
-
|
99
|
-
random_value_generator = RandomValueGenerator.new
|
100
|
-
|
101
|
-
values1 = random_value_generator.values(1000)
|
102
|
-
# Calling method `RandomValueGenerator#values` with arguments `[1000]`
|
103
|
-
#=> [0.7044444114998132, 0.401953296596267, 0.3023797513191562, ...]
|
104
|
-
|
105
|
-
values1 = random_value_generator.values(1000)
|
106
|
-
# Calling method `RandomValueGenerator#values` with arguments `[1000]`
|
107
|
-
#=> [0.7044444114998132, 0.401953296596267, 0.3023797513191562, ...]
|
108
|
-
|
109
|
-
values3 = random_value_generator.values(5000)
|
110
|
-
# Calling method `RandomValueGenerator#values` with arguments `[5000]`
|
111
|
-
#=> [0.9916088057511011, 0.04466750434972333, 0.6073659341272127]
|
112
|
-
|
113
|
-
value1 = random_value_generator.value
|
114
|
-
# Calling method `RandomValueGenerator#value` with no arguments
|
115
|
-
#=> 0.4196007135344746
|
116
|
-
|
117
|
-
value2 = random_value_generator.value
|
118
|
-
# Calling method `RandomValueGenerator#value` with no arguments
|
119
|
-
#=> 0.4196007135344746
|
120
96
|
```
|
121
97
|
|
122
98
|
Nice, right?
|
@@ -141,7 +117,7 @@ Use the `decorate` macro to decorate methods.
|
|
141
117
|
|
142
118
|
#### Using built-in decorators
|
143
119
|
|
144
|
-
There are a
|
120
|
+
There are a couple of built-in decorators for common use-cases (these can be overridden if you so choose):
|
145
121
|
|
146
122
|
```rb
|
147
123
|
class Foo
|
@@ -183,21 +159,25 @@ end
|
|
183
159
|
|
184
160
|
> **Note:** in the case of multiple decorators decorating a method, each is executed from top to bottom.
|
185
161
|
|
186
|
-
####
|
162
|
+
#### Writing custom decorators and using them _explicitly_
|
187
163
|
|
188
164
|
You can reference any decorator method you write, like so:
|
189
165
|
|
190
166
|
```rb
|
191
167
|
class FooDecorators
|
192
|
-
# Note: this is a
|
168
|
+
# Note: this is defined as a CLASS method, but it can be applied to both class
|
169
|
+
# and instance methods. The only difference is in how you source the
|
170
|
+
# decorator when doing the decoration; see below for more info.
|
193
171
|
def self.blast_it(context)
|
194
172
|
puts "Blasting it!"
|
195
173
|
value = yield
|
196
174
|
"#{value}!"
|
197
175
|
end
|
198
176
|
|
199
|
-
# Note: this is an
|
200
|
-
|
177
|
+
# Note: this is defined as an INSTANCE method, but it can be applied to both
|
178
|
+
# class and instance methods. The only difference is in how you source
|
179
|
+
# the decorator when doing the decoration; see below for more info.
|
180
|
+
def wait_for_it(context, dot_count: 3)
|
201
181
|
ellipsis = dot_count.times.map { '.' }.join
|
202
182
|
puts "Waiting for it#{ellipsis}"
|
203
183
|
value = yield
|
@@ -241,23 +221,29 @@ foo.yet_another_method(123, bloop: "bleep")
|
|
241
221
|
#=> "haha I'm yet another method"
|
242
222
|
```
|
243
223
|
|
244
|
-
Use the `from:` option to specify what should receive the decorator method. Keep in mind that the decorator method will be called on the thing specified by `from:`... so, if you provide a class, it better be a class method, and if you supply an instance, it better be an instance method.
|
224
|
+
Use the `from:` option to specify what should receive the decorator method. Keep in mind that the decorator method will be called on the thing specified by `from:`... so, if you provide a class, it better be a class method on that thing, and if you supply an instance, it better be an instance method on that thing.
|
225
|
+
|
226
|
+
Every custom decorator method that you define must take one required argument (`context`) and any number of keyword arguments. It should also `yield` (or take a block argument and invoke it) at some point in the body of the method. The point at which you `yield` will be the point at which the decorated method will execute (or, if there are multiple decorators on the method, each following decorator will be invoked until the decorators have been exhausted and the decorated method is finally executed).
|
245
227
|
|
246
|
-
|
228
|
+
##### The required argument (`context`)
|
247
229
|
|
248
230
|
The **required argument** is an instance of `Adornable::Context`, which has some useful information about the decorated method being called
|
249
231
|
|
250
|
-
- `Adornable::Context#
|
251
|
-
- `Adornable::Context#
|
252
|
-
- `Adornable::Context#method_arguments`: an array of arguments passed to the
|
232
|
+
- `Adornable::Context#method_name`: the name of the decorated method being called (a symbol; e.g., `:some_method` or `:other_method`)
|
233
|
+
- `Adornable::Context#method_receiver`: the actual object that the decorated method (the `#method_name`) belongs to/is being called on (an object/class; e.g., the class `Foo` if it's a decorated class method, or an instance of `Foo` if it's a decorated instance method)
|
234
|
+
- `Adornable::Context#method_arguments`: an array of arguments passed to the decorated method, including keyword arguments as a final hash (e.g., if `:yet_another_method` was called like `Foo.new.yet_another_method(123, bar: true)` then `arguments` would be `[123, {:bar=>true}]`)
|
235
|
+
|
236
|
+
##### Custom keyword arguments (optional)
|
253
237
|
|
254
238
|
The **optional keyword arguments** are any parameters you want to be able to pass to the decorator method when decorating a method with `::decorate`:
|
255
239
|
|
256
|
-
- If you define a decorator like `def self.some_decorator(context)` then it takes no options when it is used: `decorate :some_decorator
|
257
|
-
- If you define a decorator like `def self.some_decorator(context, some_option:)` then it takes one _required_ keyword argument when it is used: `decorate :some_decorator, some_option: 123` (`::some_decorator
|
258
|
-
- Similarly, if you define a decorator like `def self.some_decorator(context, some_option: 456)`, then it takes one _optional_ keyword argument when it is used: `decorate :some_decorator` is valid (and implies `some_option: 456` since it has a default), and `decorate :some_decorator, some_option: 789` is valid as well
|
240
|
+
- If you define a decorator like `def self.some_decorator(context)` then it takes no options when it is used: `decorate :some_decorator`.
|
241
|
+
- If you define a decorator like `def self.some_decorator(context, some_option:)` then it takes one _required_ keyword argument when it is used: `decorate :some_decorator, some_option: 123` (so that `::some_decorator` will receive `123` as the `some_option` parameter every time the decorated method is called). You can customize functionality of the decorator this way.
|
242
|
+
- Similarly, if you define a decorator like `def self.some_decorator(context, some_option: 456)`, then it takes one _optional_ keyword argument when it is used: `decorate :some_decorator` is valid (and implies `some_option: 456` since it has a default), and `decorate :some_decorator, some_option: 789` is valid as well.
|
243
|
+
|
244
|
+
##### Yielding to the next decorator/decorated method
|
259
245
|
|
260
|
-
|
246
|
+
Every decorator method **should also probably `yield`** at some point in the method body. I say _"should"_ because, technically, you don't have to, but if you don't then the original method will never be called. That's a valid use-case, but 99% of the time you're gonna want to `yield`.
|
261
247
|
|
262
248
|
> **Note:** the return value of your decorator **will replace the return value of the decorated method,** so _also_ you should probably return whatever value `yield` returned. Again, it is a valid use case to return something _else,_ but 99% of the time you probably want to return the value returned by the wrapped method.
|
263
249
|
>
|
@@ -295,13 +281,12 @@ The **optional keyword arguments** are any parameters you want to be able to pas
|
|
295
281
|
> #=> 123
|
296
282
|
> ```
|
297
283
|
|
298
|
-
####
|
284
|
+
#### Writing custom decorators and using them _implicitly_
|
299
285
|
|
300
286
|
You can also register decorator receivers so that you don't have to reference them with the `from:` option:
|
301
287
|
|
302
288
|
```rb
|
303
289
|
class FooDecorators
|
304
|
-
# Note: this is a class method
|
305
290
|
def self.blast_it(context)
|
306
291
|
puts "Blasting it!"
|
307
292
|
value = yield
|
@@ -310,8 +295,7 @@ class FooDecorators
|
|
310
295
|
end
|
311
296
|
|
312
297
|
class MoreFooDecorators
|
313
|
-
|
314
|
-
def self.wait_for_it(context, dot_count: 3)
|
298
|
+
def wait_for_it(context, dot_count: 3)
|
315
299
|
ellipsis = dot_count.times.map { '.' }.join
|
316
300
|
puts "Waiting for it#{ellipsis}"
|
317
301
|
value = yield
|
@@ -323,7 +307,7 @@ class Foo
|
|
323
307
|
extend Adornable
|
324
308
|
|
325
309
|
add_decorators_from FooDecorators
|
326
|
-
add_decorators_from MoreFooDecorators
|
310
|
+
add_decorators_from MoreFooDecorators.new
|
327
311
|
|
328
312
|
decorate :blast_it
|
329
313
|
decorate :wait_for_it, dot_count: 9
|
@@ -340,6 +324,8 @@ foo.some_method
|
|
340
324
|
#=> "haha I'm a method!........."
|
341
325
|
```
|
342
326
|
|
327
|
+
> **Note:** All the rest of the stuff from the previous section (using decorators explicitly) also applies here (using decorators implicitly).
|
328
|
+
|
343
329
|
> **Note:** In the case of duplicate decorator methods, later receivers registered with `::add_decorators_from` will override any decorators by the same name from earlier registered receivers.
|
344
330
|
|
345
331
|
> **Note:** in the case of multiple decorators decorating a method, each is executed from top to bottom; i.e., the top wraps the next, which wraps the next, and so on, until the method itself is wrapped.
|
data/adornable.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ["kjleitz@gmail.com"]
|
12
12
|
|
13
13
|
spec.summary = "Method decorators for Ruby"
|
14
|
-
spec.description = "
|
14
|
+
spec.description = "Adornable provides the ability to cleanly decorate methods in Ruby. You can make and use your own decorators, and you can also use some of the built-in ones that the gem provides. _Decorating_ methods is as simple as slapping a `decorate :some_decorator` above your method definition. _Defining_ decorators can be as simple as defining a method that yields to a block, or as complex as manipulating the decorated method's receiver and arguments, and/or changing the functionality of the decorator based on custom options supplied to it when initially applying the decorator."
|
15
15
|
spec.homepage = "https://github.com/kjleitz/adornable"
|
16
16
|
spec.license = "MIT"
|
17
17
|
spec.required_ruby_version = ">= 2.4.7"
|
data/lib/adornable/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adornable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keegan Leitz
|
@@ -122,7 +122,13 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
-
description:
|
125
|
+
description: Adornable provides the ability to cleanly decorate methods in Ruby. You
|
126
|
+
can make and use your own decorators, and you can also use some of the built-in
|
127
|
+
ones that the gem provides. _Decorating_ methods is as simple as slapping a `decorate
|
128
|
+
:some_decorator` above your method definition. _Defining_ decorators can be as simple
|
129
|
+
as defining a method that yields to a block, or as complex as manipulating the decorated
|
130
|
+
method's receiver and arguments, and/or changing the functionality of the decorator
|
131
|
+
based on custom options supplied to it when initially applying the decorator.
|
126
132
|
email:
|
127
133
|
- kjleitz@gmail.com
|
128
134
|
executables: []
|