adornable 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39c5f35488e69b6f4de57d24b3a4867552fdb7e72a59a98017cd59af19dbc7f7
4
- data.tar.gz: 3d9998525bb6393c681cb2688d3ba3d2df321ae5e39f598e9c8ea7a3bed9cd8e
3
+ metadata.gz: ece582a2ce4c7093792eacfa04863a2c71a8a5bee12fceb0f964356b58f997c5
4
+ data.tar.gz: dabd571e4161e633d40d15bdaccee37bf8646ec7f7cdd2d4773feaeb207c5e9d
5
5
  SHA512:
6
- metadata.gz: 9a26ac80096736eaa6e20d6c63250686491b528e915603723f933879dfda9d10ce0e17e73531e7a4c46b7eb4d47efdbb152f9c0da78fab89850740a11fb6f8d2
7
- data.tar.gz: 44ea1ed9f80932ea5214e7287bbbc40c5a385c10eb5b9dce52f34dc5e915fff6ff3d5da854084f0a342d6728657420f4ce940d1e27d94c3c3cb629bddbd9f272
6
+ metadata.gz: b0dbae5d19cd42fe225b054bb9245ff9946c417d75c1decdb23441be527991a6186a90abaa0ce46faa5ad61cc3dfbfa01d5d0fc063620dbc4bb69db94a44a9f7
7
+ data.tar.gz: 58416d66482d8b39ea8ee9b3ac532c6e37b6a2de811542551fe4a857927beb5117bc13ef3a460320f19eaca683bf97939a0e257548fc12a1c81aec39a6c78163
data/.rubocop.yml CHANGED
@@ -3,45 +3,73 @@ require:
3
3
  - rubocop-rspec
4
4
  - rubocop-rake
5
5
 
6
+ # Globals
7
+
8
+ AllCops:
9
+ NewCops: enable
10
+
6
11
  # Layout
7
12
 
8
13
  Layout/LineLength:
9
14
  Max: 120
10
15
  Exclude:
11
16
  - 'spec/**/*_spec.rb'
12
- - 'test/**/*_spec.rb'
13
17
 
14
18
  Layout/EndAlignment:
15
19
  EnforcedStyleAlignWith: variable
16
20
 
21
+ Layout/FirstArrayElementIndentation:
22
+ EnforcedStyle: consistent
23
+
17
24
  # Metrics
18
25
 
19
26
  Metrics/AbcSize:
20
27
  CountRepeatedAttributes: false
21
28
  Exclude:
22
29
  - 'spec/**/*_spec.rb'
23
- - 'test/**/*_spec.rb'
24
30
 
25
31
  Metrics/BlockLength:
26
32
  Exclude:
27
33
  - 'spec/**/*_spec.rb'
28
- - 'test/**/*_spec.rb'
29
34
 
30
35
  Metrics/ClassLength:
36
+ Max: 150
37
+ CountComments: false
38
+ CountAsOne:
39
+ - array
40
+ - hash
41
+ - heredoc
42
+ Exclude:
43
+ - 'spec/**/*_spec.rb'
44
+
45
+ Metrics/MethodLength:
46
+ Max: 20
47
+ CountComments: false
48
+ CountAsOne:
49
+ - array
50
+ - hash
51
+ - heredoc
52
+
53
+ Metrics/ModuleLength:
54
+ Max: 150
55
+ CountComments: false
56
+ CountAsOne:
57
+ - array
58
+ - hash
59
+ - heredoc
31
60
  Exclude:
32
61
  - 'spec/**/*_spec.rb'
33
- - 'test/**/*_spec.rb'
34
62
 
35
63
  # Rspec
36
64
 
37
65
  RSpec/ExampleLength:
38
- Max: 20
66
+ Max: 25
39
67
 
40
68
  RSpec/MessageSpies:
41
69
  Enabled: false
42
70
 
43
71
  RSpec/MultipleExpectations:
44
- Max: 5
72
+ Enabled: false
45
73
 
46
74
  RSpec/NestedGroups:
47
75
  Max: 10
@@ -57,3 +85,12 @@ Style/ExpandPathArguments:
57
85
 
58
86
  Style/StringLiterals:
59
87
  Enabled: false
88
+
89
+ Style/TrailingCommaInArguments:
90
+ EnforcedStyleForMultiline: consistent_comma
91
+
92
+ Style/TrailingCommaInArrayLiteral:
93
+ EnforcedStyleForMultiline: consistent_comma
94
+
95
+ Style/TrailingCommaInHashLiteral:
96
+ EnforcedStyleForMultiline: consistent_comma
data/README.md CHANGED
@@ -90,7 +90,7 @@ class RandomValueGenerator
90
90
  end
91
91
 
92
92
  decorate :log
93
- decorate :memoize_for_arguments
93
+ decorate :memoize
94
94
  def values(max)
95
95
  (1..max).map { rand }
96
96
  end
@@ -149,35 +149,37 @@ class Foo
149
149
 
150
150
  decorate :log
151
151
  def some_method
152
- # ...
152
+ # the method name (Foo#some_method) and arguments will be logged
153
153
  end
154
154
 
155
155
  decorate :memoize
156
156
  def some_other_method
157
- # ...
157
+ # the return value will be cached
158
158
  end
159
159
 
160
- decorate :memoize_for_arguments
160
+ decorate :memoize
161
161
  def yet_another_method(some_arg, some_other_arg = true, key_word_arg:, key_word_arg_with_default: 123)
162
- # ...
162
+ # the return value will be cached based on the arguments the method receives
163
163
  end
164
164
 
165
165
  decorate :log
166
- decorate :memoize_for_arguments
166
+ decorate :memoize, for_any_arguments: true
167
167
  def oh_boy_another_method(some_arg, some_other_arg = true, key_word_arg:, key_word_arg_with_default: 123)
168
- # ...
168
+ # the method name (Foo#oh_boy_another_method) and arguments will be logged
169
+ # the return value will be cached regardless of the arguments received
169
170
  end
170
171
 
171
172
  decorate :log
172
173
  def self.yeah_it_works_on_class_methods_too
173
- # ...
174
+ # the method name (Foo::yeah_it_works_on_class_methods_too) and arguments
175
+ # will be logged
174
176
  end
175
177
  end
176
178
  ```
177
179
 
178
180
  - `decorate :log` logs the method name and any passed arguments to the console
179
- - `decorate :memoize` caches the result of the first call and returns that initial result (and does not execute the method again) for any additional calls
180
- - `decorate :memoize_for_arguments` acts like `decorate :memoize` but it namespaces that cache by the arguments passed, so it will re-compute (and cache the result) only if the arguments change... if the arguments are the same as any previous time the method was called, it will return the cached result instead
181
+ - `decorate :memoize` caches the result of the first call and returns that initial result (and does not execute the method again) for any additional calls. By default, it namespaces the cache by the arguments passed to the method, so it will re-compute only if the arguments change; if the arguments are the same as any previous time the method was called, it will return the cached result instead.
182
+ - pass the `for_any_arguments: true` option (e.g., `decorate :memoize, for_any_arguments: true`) to ignore the arguments in the caching process and simply memoize the result no matter what
181
183
 
182
184
  > **Note:** in the case of multiple decorators decorating a method, each is executed from top to bottom.
183
185
 
@@ -188,17 +190,18 @@ You can reference any decorator method you write, like so:
188
190
  ```rb
189
191
  class FooDecorators
190
192
  # Note: this is a class method
191
- def self.blast_it(method_receiver, method_name, arguments)
193
+ def self.blast_it(context)
192
194
  puts "Blasting it!"
193
195
  value = yield
194
196
  "#{value}!"
195
197
  end
196
198
 
197
199
  # Note: this is an instance method
198
- def wait_for_it(method_receiver, method_name, arguments)
199
- puts "Waiting..."
200
+ def self.wait_for_it(context, dot_count: 3)
201
+ ellipsis = dot_count.times.map { '.' }.join
202
+ puts "Waiting for it#{ellipsis}"
200
203
  value = yield
201
- "#{value}..."
204
+ "#{value}#{ellipsis}"
202
205
  end
203
206
  end
204
207
 
@@ -240,49 +243,57 @@ foo.yet_another_method(123, bloop: "bleep")
240
243
 
241
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.
242
245
 
243
- Every decorator method must take the following arguments:
246
+ Every custom decorator method that you define must take one required argument (`context`) and any number of keyword arguments.
244
247
 
245
- - `method_receiver`: the actual object that the [decorated] method is being called on (an object/class); e.g., `Foo` or an instance of `Foo`
246
- - `method_name`: the name of the [decorated] method being called on `method_receiver` (a symbol); e.g., `:some_method` or `:other_method`
247
- - `arguments`: an array of arguments passed to the [decorated] method, including keyword arguments; e.g., if `:yet_another_method` was called like `Foo.new.yet_another_method(123, bar: true)` then `arguments` would be `[123, {:bar=>true}]`
248
+ The **required argument** is an instance of `Adornable::Context`, which has some useful information about the decorated method being called
248
249
 
249
- > **Note:** 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`.
250
- >
251
- > **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.
250
+ - `Adornable::Context#method_receiver`: the actual object that the [decorated] method is being called on (an object/class; e.g., `Foo` or an instance of `Foo`)
251
+ - `Adornable::Context#method_name`: the name of the [decorated] method being called on `method_receiver` (a symbol; e.g., `:some_method` or `:other_method`)
252
+ - `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}]`)
252
253
 
253
- Contrived example of when you might want to muck around with the return value:
254
+ The **optional keyword arguments** are any parameters you want to be able to pass to the decorator method when decorating a method with `::decorate`:
254
255
 
255
- ```rb
256
- class FooDecorators
257
- def self.coerce_to_int(method_receiver, method_name, arguments)
258
- value = yield
259
- new_value = value.strip.to_i
260
- puts "New value: #{value.inspect} (class: #{value.class})"
261
- new_value
262
- end
263
- end
264
-
265
- class Foo
266
- extend Adornable
267
-
268
- decorate :coerce_to_int, from: FooDecorators
269
- def get_number_from_user
270
- print "Enter a number: "
271
- value = gets
272
- puts "Value: #{value.inspect} (class: #{value.class})"
273
- value
274
- end
275
- end
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`, will receive `123` every time the method it's decorating is called)
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
276
259
 
277
- foo = Foo.new
260
+ > **Note:** Every decorator method should _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`.
278
261
 
279
- foo.get_number_from_user
280
- # Enter a number
281
- # > 123
282
- # Value: "123" (class: String)
283
- # New value: 123 (class: Integer)
284
- #=> 123
285
- ```
262
+ > **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
+ >
264
+ > A contrived example of when you might want to muck around with the return value:
265
+ >
266
+ > ```rb
267
+ > class FooDecorators
268
+ > def self.coerce_to_int(context)
269
+ > value = yield
270
+ > new_value = value.strip.to_i
271
+ > puts "New value: #{value.inspect} (class: #{value.class})"
272
+ > new_value
273
+ > end
274
+ > end
275
+ >
276
+ > class Foo
277
+ > extend Adornable
278
+ >
279
+ > decorate :coerce_to_int, from: FooDecorators
280
+ > def get_number_from_user
281
+ > print "Enter a number: "
282
+ > value = gets
283
+ > puts "Value: #{value.inspect} (class: #{value.class})"
284
+ > value
285
+ > end
286
+ > end
287
+ >
288
+ > foo = Foo.new
289
+ >
290
+ > foo.get_number_from_user
291
+ > # Enter a number
292
+ > # > 123
293
+ > # Value: "123" (class: String)
294
+ > # New value: 123 (class: Integer)
295
+ > #=> 123
296
+ > ```
286
297
 
287
298
  #### Using custom decorators implicitly
288
299
 
@@ -291,7 +302,7 @@ You can also register decorator receivers so that you don't have to reference th
291
302
  ```rb
292
303
  class FooDecorators
293
304
  # Note: this is a class method
294
- def self.blast_it(method_receiver, method_name, arguments)
305
+ def self.blast_it(context)
295
306
  puts "Blasting it!"
296
307
  value = yield
297
308
  "#{value}!"
@@ -300,10 +311,11 @@ end
300
311
 
301
312
  class MoreFooDecorators
302
313
  # Note: this is a class method
303
- def self.wait_for_it(method_receiver, method_name, arguments)
304
- puts "Waiting for it..."
314
+ def self.wait_for_it(context, dot_count: 3)
315
+ ellipsis = dot_count.times.map { '.' }.join
316
+ puts "Waiting for it#{ellipsis}"
305
317
  value = yield
306
- "#{value}..."
318
+ "#{value}#{ellipsis}"
307
319
  end
308
320
  end
309
321
 
@@ -314,7 +326,7 @@ class Foo
314
326
  add_decorators_from MoreFooDecorators
315
327
 
316
328
  decorate :blast_it
317
- decorate :wait_for_it
329
+ decorate :wait_for_it, dot_count: 9
318
330
  def some_method
319
331
  "haha I'm a method"
320
332
  end
@@ -324,12 +336,12 @@ foo = Foo.new
324
336
 
325
337
  foo.some_method
326
338
  # Blasting it!
327
- # Waiting for it...
328
- #=> "haha I'm a method!..."
339
+ # Waiting for it.........
340
+ #=> "haha I'm a method!........."
329
341
  ```
330
342
 
331
- > **Note:** In the case of duplicate decorator methods, later receivers registered with `::add_decorators_from` will override any duplicate decorators from earlier registered receivers.
332
- >
343
+ > **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
+
333
345
  > **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.
334
346
 
335
347
  ## Development
@@ -340,12 +352,18 @@ foo.some_method
340
352
  bin/setup
341
353
  ```
342
354
 
343
- ### Run testss
355
+ ### Run the tests
344
356
 
345
357
  ```bash
346
358
  rake spec
347
359
  ```
348
360
 
361
+ ### Run the linter
362
+
363
+ ```bash
364
+ rubocop
365
+ ```
366
+
349
367
  ### Create release
350
368
 
351
369
  ```
data/adornable.gemspec CHANGED
@@ -25,11 +25,12 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.add_development_dependency "bundler", "~> 1.17"
29
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "bundler", "~> 2.2"
29
+ spec.add_development_dependency "rake", "~> 13.0"
30
30
  spec.add_development_dependency "rspec", "~> 3.0"
31
31
  spec.add_development_dependency "rubocop", "~> 1.10"
32
32
  spec.add_development_dependency "rubocop-performance", "~> 1.9"
33
33
  spec.add_development_dependency "rubocop-rake", "~> 0.5"
34
34
  spec.add_development_dependency "rubocop-rspec", "~> 2.2"
35
+ spec.add_development_dependency "solargraph"
35
36
  end
data/lib/adornable.rb CHANGED
@@ -13,7 +13,7 @@ module Adornable
13
13
  @adornable_machinery ||= Adornable::Machinery.new
14
14
  end
15
15
 
16
- def decorate(decorator_name, from: nil, defer_validation: false)
16
+ def decorate(decorator_name, from: nil, defer_validation: false, **decorator_options)
17
17
  if Adornable::Utils.blank?(name)
18
18
  raise Adornable::Error::InvalidDecoratorArguments, "Decorator name must be provided."
19
19
  end
@@ -21,7 +21,8 @@ module Adornable
21
21
  adornable_machinery.accumulate_decorator!(
22
22
  name: decorator_name,
23
23
  receiver: from,
24
- defer_validation: !!defer_validation
24
+ defer_validation: !!defer_validation,
25
+ decorator_options: decorator_options,
25
26
  )
26
27
  end
27
28
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Adornable
4
+ # A context object is passed to the decorator method, and contains information
5
+ # about the decorated method being called.
6
+ class Context
7
+ attr_reader(*%i[
8
+ method_receiver
9
+ method_name
10
+ method_arguments
11
+ decorator_name
12
+ decorator_options
13
+ ])
14
+
15
+ def initialize(method_receiver:, method_name:, method_arguments:, decorator_name:, decorator_options:)
16
+ @method_receiver = method_receiver
17
+ @method_name = method_name
18
+ @method_arguments = method_arguments
19
+ @decorator_name = decorator_name
20
+ @decorator_options = decorator_options
21
+ end
22
+ end
23
+ end
@@ -1,35 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'adornable/utils'
4
+
3
5
  module Adornable
4
6
  # `Adornable::Decorators` is used as the default namespace for decorator
5
7
  # methods when a decorator method that is neither explicitly sourced (via the
6
8
  # `decorate from: <receiver>` option) nor implicitly sourced (via the
7
9
  # `add_decorators_from <receiver>` macro).
8
10
  class Decorators
9
- def self.log(method_receiver, method_name, arguments)
10
- receiver_name, name_delimiter = if method_receiver.is_a?(Class)
11
- [method_receiver.to_s, '::']
12
- else
13
- [method_receiver.class.to_s, '#']
14
- end
15
- full_name = "`#{receiver_name}#{name_delimiter}#{method_name}`"
16
- arguments_desc = arguments.empty? ? "no arguments" : "arguments `#{arguments.inspect}`"
11
+ def self.log(context)
12
+ method_receiver = context.method_receiver
13
+ method_name = context.method_name
14
+ method_args = context.method_arguments
15
+ full_name = Adornable::Utils.formal_method_name(method_receiver, method_name)
16
+ arguments_desc = method_args.empty? ? "no arguments" : "arguments `#{method_args.inspect}`"
17
17
  puts "Calling method #{full_name} with #{arguments_desc}"
18
18
  yield
19
19
  end
20
20
 
21
- def self.memoize(method_receiver, method_name, _arguments)
21
+ def self.memoize(context, for_any_arguments: false, &block)
22
+ return memoize_for_arguments(context, &block) unless for_any_arguments
23
+
24
+ method_receiver = context.method_receiver
25
+ method_name = context.method_name
22
26
  memo_var_name = :"@adornable_memoized_#{method_receiver.object_id}_#{method_name}"
23
27
  existing = instance_variable_get(memo_var_name)
24
28
  value = existing.nil? ? yield : existing
25
29
  instance_variable_set(memo_var_name, value)
26
30
  end
27
31
 
28
- def self.memoize_for_arguments(method_receiver, method_name, arguments)
32
+ def self.memoize_for_arguments(context)
33
+ method_receiver = context.method_receiver
34
+ method_name = context.method_name
35
+ method_args = context.method_arguments
29
36
  memo_var_name = :"@adornable_memoized_for_arguments_#{method_receiver.object_id}_#{method_name}"
30
37
  memo = instance_variable_get(memo_var_name) || {}
31
38
  instance_variable_set(memo_var_name, memo)
32
- args_key = arguments.inspect
39
+ args_key = method_args.inspect
33
40
  memo[args_key] = yield if memo[args_key].nil?
34
41
  memo[args_key]
35
42
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'adornable/utils'
4
4
  require 'adornable/error'
5
+ require 'adornable/context'
5
6
 
6
7
  module Adornable
7
8
  class Machinery # :nodoc:
@@ -9,12 +10,17 @@ module Adornable
9
10
  registered_decorator_receivers.unshift(receiver)
10
11
  end
11
12
 
12
- def accumulate_decorator!(name:, receiver:, defer_validation:)
13
+ def accumulate_decorator!(name:, receiver:, defer_validation:, decorator_options:)
13
14
  name = name.to_sym
14
15
  receiver ||= find_suitable_receiver_for(name)
15
16
  validate_decorator!(name, receiver) unless defer_validation
16
17
 
17
- decorator = { name: name, receiver: receiver }
18
+ decorator = {
19
+ name: name,
20
+ receiver: receiver,
21
+ options: decorator_options || {},
22
+ }
23
+
18
24
  accumulated_decorators << decorator
19
25
  end
20
26
 
@@ -82,15 +88,31 @@ module Adornable
82
88
  @class_method_decorators[name] = decorators || []
83
89
  end
84
90
 
85
- def run_decorators(decorators, bound_method, *args)
86
- return bound_method.call(*args) if Adornable::Utils.blank?(decorators)
91
+ def run_decorators(decorators, bound_method, *method_arguments)
92
+ return bound_method.call(*method_arguments) if Adornable::Utils.blank?(decorators)
87
93
 
88
94
  decorator, *remaining_decorators = decorators
89
- name = decorator[:name]
90
- receiver = decorator[:receiver]
91
- validate_decorator!(name, receiver, bound_method)
92
- receiver.send(name, bound_method.receiver, bound_method.name, args) do
93
- run_decorators(remaining_decorators, bound_method, *args)
95
+ decorator_name = decorator[:name]
96
+ decorator_receiver = decorator[:receiver]
97
+ decorator_options = decorator[:options]
98
+ validate_decorator!(decorator_name, decorator_receiver, bound_method)
99
+
100
+ context = Adornable::Context.new(
101
+ method_receiver: bound_method.receiver,
102
+ method_name: bound_method.name,
103
+ method_arguments: method_arguments,
104
+ decorator_name: decorator_name,
105
+ decorator_options: decorator_options,
106
+ )
107
+
108
+ send_parameters = if Adornable::Utils.present?(decorator_options)
109
+ [decorator_name, context, decorator_options]
110
+ else
111
+ [decorator_name, context]
112
+ end
113
+
114
+ decorator_receiver.send(*send_parameters) do
115
+ run_decorators(remaining_decorators, bound_method, *method_arguments)
94
116
  end
95
117
  end
96
118
 
@@ -100,15 +122,13 @@ module Adornable
100
122
  end
101
123
  end
102
124
 
103
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Layout/LineLength
125
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Layout/LineLength
104
126
  def validate_decorator!(decorator_name, decorator_receiver, bound_method = nil)
105
127
  return if decorator_receiver.respond_to?(decorator_name)
106
128
 
107
129
  location_hint = if bound_method
108
130
  method_receiver = bound_method.receiver
109
-
110
131
  method_full_name = method_receiver.is_a?(Class) ? "#{method_receiver}::#{method.name}" : "#{method_receiver.class}##{method.name}"
111
-
112
132
  method_location = bound_method.source_location
113
133
  "Cannot decorate `#{method_full_name}` (defined at `#{method_location.first}:#{method_location.second})."
114
134
  end
@@ -126,6 +146,6 @@ module Adornable
126
146
  message = [location_hint, base_message, definition_hint].compact.join(" ")
127
147
  raise Adornable::Error::InvalidDecoratorArguments, message
128
148
  end
129
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Layout/LineLength
149
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Layout/LineLength
130
150
  end
131
151
  end
@@ -14,6 +14,15 @@ module Adornable
14
14
  def presence(value)
15
15
  value if present?(value)
16
16
  end
17
+
18
+ def formal_method_name(method_receiver, method_name)
19
+ receiver_name, name_delimiter = if method_receiver.is_a?(Class)
20
+ [method_receiver.to_s, '::']
21
+ else
22
+ [method_receiver.class.to_s, '#']
23
+ end
24
+ "`#{receiver_name}#{name_delimiter}#{method_name}`"
25
+ end
17
26
  end
18
27
  end
19
28
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Adornable
4
- VERSION = "1.0.3"
4
+ VERSION = "1.1.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adornable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keegan Leitz
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2021-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.17'
19
+ version: '2.2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.17'
26
+ version: '2.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '2.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: solargraph
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Method decorators for Ruby
112
126
  email:
113
127
  - kjleitz@gmail.com
@@ -120,7 +134,6 @@ files:
120
134
  - ".rubocop.yml"
121
135
  - ".travis.yml"
122
136
  - Gemfile
123
- - Gemfile.lock
124
137
  - LICENSE
125
138
  - README.md
126
139
  - Rakefile
@@ -128,6 +141,7 @@ files:
128
141
  - bin/console
129
142
  - bin/setup
130
143
  - lib/adornable.rb
144
+ - lib/adornable/context.rb
131
145
  - lib/adornable/decorators.rb
132
146
  - lib/adornable/error.rb
133
147
  - lib/adornable/machinery.rb
@@ -137,7 +151,7 @@ homepage: https://github.com/kjleitz/adornable
137
151
  licenses:
138
152
  - MIT
139
153
  metadata: {}
140
- post_install_message:
154
+ post_install_message:
141
155
  rdoc_options: []
142
156
  require_paths:
143
157
  - lib
@@ -152,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
166
  - !ruby/object:Gem::Version
153
167
  version: '0'
154
168
  requirements: []
155
- rubygems_version: 3.0.8
156
- signing_key:
169
+ rubygems_version: 3.1.4
170
+ signing_key:
157
171
  specification_version: 4
158
172
  summary: Method decorators for Ruby
159
173
  test_files: []