method_man 2.1.5 → 3.0.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +11 -6
- data/.ruby-version +1 -1
- data/README.md +30 -0
- data/lib/method_object.rb +74 -83
- data/lib/method_object/version.rb +4 -2
- data/method_man.gemspec +8 -10
- data/spec/method_man_spec.rb +73 -162
- data/spec/spec_helper.rb +1 -0
- metadata +33 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 27ac0306df7dc6d12ff3eb481fde1a960c1a5356cad96edcc682058536d2150a
|
4
|
+
data.tar.gz: c6b4856e53dc9fd820a32505da6eed2f2da26ba45253f566e735cea9e8aad84b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab1e722b4c5e2bfd01b3e70c4504a14c1bb592918bd8fe048d14045f937113912ae6341fc2cf144cff4de25b8aa9a0f6489847149866c8308d8fdc13a0b5961c
|
7
|
+
data.tar.gz: ffde0b87325abf0f187f4cb712286128151e3e782d027e2f6566bdfd6c5ef58eba9761154b443edd51ceee7c0bebdedda824571b1c84dbfd6d9ccaa52e27edcb
|
data/.rubocop.yml
CHANGED
@@ -1,22 +1,27 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
3
|
-
|
4
|
-
TargetRubyVersion: 2.4
|
2
|
+
NewCops: enable
|
3
|
+
TargetRubyVersion: 2.5
|
5
4
|
|
6
5
|
# We don't care about method length, since we check method cyclomatic
|
7
6
|
# complexity.
|
8
7
|
Metrics/MethodLength:
|
9
8
|
Enabled: false
|
9
|
+
Metrics/BlockLength:
|
10
|
+
Enabled: false
|
10
11
|
Metrics/ClassLength:
|
11
|
-
|
12
|
+
Enabled: false
|
12
13
|
Metrics/ModuleLength:
|
13
|
-
|
14
|
+
Enabled: false
|
15
|
+
Metrics/AbcSize:
|
16
|
+
Enabled: false
|
14
17
|
|
15
18
|
# Trailing commas make for clearer diffs because the last line won't appear
|
16
19
|
# to have been changed, as it would if it lacked a comma and had one added.
|
17
20
|
Style/TrailingCommaInArguments:
|
18
21
|
EnforcedStyleForMultiline: comma
|
19
|
-
Style/
|
22
|
+
Style/TrailingCommaInArrayLiteral:
|
23
|
+
EnforcedStyleForMultiline: comma
|
24
|
+
Style/TrailingCommaInHashLiteral:
|
20
25
|
EnforcedStyleForMultiline: comma
|
21
26
|
|
22
27
|
# Cop supports --auto-correct.
|
data/.ruby-version
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
2.
|
1
|
+
2.7.1
|
2
2
|
|
data/README.md
CHANGED
@@ -64,3 +64,33 @@ Also allows automatic delegation inspired by Go's
|
|
64
64
|
MakeArbitraryArray.call(company: company)
|
65
65
|
=> ['Tyrell Corporation', 'Tyrell Corporation', 'Tyrell Corporation']
|
66
66
|
```
|
67
|
+
|
68
|
+
## Naming
|
69
|
+
|
70
|
+
Why is the class method called `call`? Some people have argued for names like `TaskSender.send_task` instead of `TaskSender.call`. My reasoning is.
|
71
|
+
|
72
|
+
1. `call` is a ubiquitous concept in Ruby, as it's how you invoke `Procs`.
|
73
|
+
2. There's even a syntactic sugar for this, `.()` instead of `.call()`, e.g. `TaskSender.(task)`.
|
74
|
+
3. The name `call` clearly _calls_ out to someone reading the code that "this is an invocation of a method object". I would say this is especially so if you see something like `TaskSender.(task)`.
|
75
|
+
4. Avoiding redundancy. Any custom name will always just match the module/class name, e.g.
|
76
|
+
```ruby
|
77
|
+
TaskSender.send_task # This is redundant
|
78
|
+
```
|
79
|
+
5. Minimizing complexity: adding an option to specify the class method would introduce additional complexity.
|
80
|
+
|
81
|
+
### History
|
82
|
+
In [Refactoring: Ruby Edition](http://www.informit.com/store/refactoring-ruby-edition-9780321603500), we see this at the top of the section on the method object pattern.
|
83
|
+
|
84
|
+
> Stolen shamelessly from Kent Beck’s Smalltalk Best Practices.
|
85
|
+
> 1. Create a new class, name it after the method.
|
86
|
+
|
87
|
+
In the example, the instance method `Account#gamma` is refactored to `Gamma.compute`. Kent Beck's original example refactored `Obligation#sendTask` to `TaskSender.compute`.
|
88
|
+
|
89
|
+
### Noun vs. verb
|
90
|
+
|
91
|
+
Beck uses `TaskSender`. I personally prefer `SendTask`, essentially just preserving the name of whatever method you're converting to a method object. However I don't think this detail is of much import. I might recommend trying a little of both, and seeing which naming seems least confusing when you're coming back to it weeks later.
|
92
|
+
|
93
|
+
## How useful is this pattern?
|
94
|
+
Kent Beck has [raved about it](https://twitter.com/kentbeck/status/195168291134783489), saying:
|
95
|
+
|
96
|
+
> extract method object is such deep deep magic. it brings clarity to the confused and structure to the chaotic.
|
data/lib/method_object.rb
CHANGED
@@ -1,102 +1,95 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require('delegate')
|
3
4
|
require('method_object/version')
|
4
5
|
|
5
|
-
# See gemspec for description
|
6
|
-
class MethodObject
|
6
|
+
# See gemspec for description.
|
7
|
+
class MethodObject < SimpleDelegator
|
7
8
|
class AmbigousMethodError < NameError; end
|
8
9
|
|
9
10
|
class << self
|
10
|
-
def attrs(*attributes)
|
11
|
-
@attributes = attributes
|
12
|
-
Setup.call(attributes: attributes, subclass: self)
|
13
|
-
end
|
14
|
-
|
15
11
|
def call(**args)
|
16
|
-
new(args).call
|
12
|
+
new(__object_factory__&.new(**args)).call
|
17
13
|
end
|
18
14
|
|
19
|
-
attr_reader(:attributes)
|
20
|
-
|
21
15
|
private(:new)
|
22
16
|
|
23
|
-
def
|
24
|
-
|
17
|
+
def attrs(*attributes)
|
18
|
+
self.__object_factory__ = ObjectFactory.create(*attributes)
|
25
19
|
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize(_); end
|
29
20
|
|
30
|
-
|
31
|
-
raise NotImplementedError, 'Define the call method'
|
21
|
+
attr_accessor(:__object_factory__)
|
32
22
|
end
|
33
23
|
|
34
|
-
def
|
35
|
-
|
36
|
-
case candidates.length
|
37
|
-
when 0
|
38
|
-
super
|
39
|
-
when 1
|
40
|
-
delegate = candidates.first
|
41
|
-
define_delegated_method(delegate)
|
42
|
-
public_send(delegate.delegated_method, *args, &block)
|
43
|
-
else
|
44
|
-
handle_ambiguous_missing_method(candidates, name)
|
45
|
-
end
|
24
|
+
def call
|
25
|
+
raise(NotImplementedError, 'define the call method')
|
46
26
|
end
|
47
27
|
|
48
|
-
|
49
|
-
|
50
|
-
|
28
|
+
# Creates instances for delegation and caching method definitions.
|
29
|
+
class ObjectFactory
|
30
|
+
STRUCT_DEFINITION = lambda do |_class|
|
31
|
+
def method_missing(name, *args)
|
32
|
+
candidates = candidates_for_method_missing(name)
|
33
|
+
handle_ambiguous_missing_method(candidates, name) if candidates.length > 1
|
34
|
+
super
|
35
|
+
end
|
51
36
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
self.class.attributes.map do |attribute|
|
62
|
-
PotentialDelegatorWithPrefix.new(
|
63
|
-
attribute,
|
64
|
-
public_send(attribute),
|
65
|
-
method_name,
|
66
|
-
)
|
37
|
+
def respond_to_missing?(name, _include_private)
|
38
|
+
candidates = candidates_for_method_missing(name)
|
39
|
+
case candidates.length
|
40
|
+
when 0
|
41
|
+
return(super)
|
42
|
+
when 1
|
43
|
+
define_delegated_method(candidates.first)
|
44
|
+
end
|
45
|
+
true
|
67
46
|
end
|
68
|
-
potential_candidates.select(&:candidate?)
|
69
|
-
end
|
70
47
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
48
|
+
def candidates_for_method_missing(method_name)
|
49
|
+
potential_candidates =
|
50
|
+
members.map do |attribute|
|
51
|
+
PotentialDelegator.new(
|
52
|
+
attribute,
|
53
|
+
public_send(attribute),
|
54
|
+
method_name,
|
55
|
+
)
|
56
|
+
end +
|
57
|
+
members.map do |attribute|
|
58
|
+
PotentialDelegatorWithPrefix.new(
|
59
|
+
attribute,
|
60
|
+
public_send(attribute),
|
61
|
+
method_name,
|
62
|
+
)
|
77
63
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
64
|
+
potential_candidates.select(&:candidate?)
|
65
|
+
end
|
66
|
+
|
67
|
+
def define_delegated_method(delegate)
|
68
|
+
code = <<~RUBY
|
81
69
|
def #{delegate.delegated_method}(*args, &block)
|
82
70
|
#{delegate.attribute}
|
83
71
|
.#{delegate.method_to_call_on_delegate}(*args, &block)
|
84
72
|
end
|
85
73
|
RUBY
|
74
|
+
self.class.class_eval(code, __FILE__, __LINE__ + 1)
|
86
75
|
end
|
87
|
-
)
|
88
|
-
end
|
89
76
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
77
|
+
def handle_ambiguous_missing_method(candidates, method_name)
|
78
|
+
raise(
|
79
|
+
AmbigousMethodError,
|
80
|
+
"#{method_name} is ambiguous: " +
|
81
|
+
candidates
|
82
|
+
.map do |candidate|
|
83
|
+
"#{candidate.attribute}.#{candidate.method_to_call_on_delegate}"
|
84
|
+
end
|
85
|
+
.join(', '),
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.create(*attributes)
|
91
|
+
Struct.new(*attributes, keyword_init: true, &STRUCT_DEFINITION)
|
92
|
+
end
|
100
93
|
end
|
101
94
|
|
102
95
|
# Represents a possible match of the form:
|
@@ -124,7 +117,7 @@ class MethodObject
|
|
124
117
|
private
|
125
118
|
|
126
119
|
def name_matches?
|
127
|
-
delegated_method.
|
120
|
+
delegated_method.start_with?(prefix)
|
128
121
|
end
|
129
122
|
|
130
123
|
def prefix
|
@@ -132,7 +125,7 @@ class MethodObject
|
|
132
125
|
end
|
133
126
|
end
|
134
127
|
|
135
|
-
# Dynamically defines custom attr_readers and initializer
|
128
|
+
# Dynamically defines custom attr_readers and initializer.
|
136
129
|
class Setup < SimpleDelegator
|
137
130
|
def self.call(attributes:, subclass:)
|
138
131
|
new(attributes, subclass).call
|
@@ -156,18 +149,12 @@ class MethodObject
|
|
156
149
|
__getobj__.send(:attr_reader, *attributes)
|
157
150
|
end
|
158
151
|
|
159
|
-
def attr_accessor(attribute)
|
160
|
-
super
|
161
|
-
end
|
162
|
-
|
163
152
|
def define_initializer
|
164
|
-
class_eval(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
RUBY
|
170
|
-
)
|
153
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
154
|
+
def initialize(#{required_keyword_args_string})
|
155
|
+
#{assignments}
|
156
|
+
end
|
157
|
+
RUBY
|
171
158
|
end
|
172
159
|
|
173
160
|
def required_keyword_args_string
|
@@ -178,4 +165,8 @@ class MethodObject
|
|
178
165
|
attributes.map { |attribute| "@#{attribute} = #{attribute}\n" }.join
|
179
166
|
end
|
180
167
|
end
|
168
|
+
|
169
|
+
def respond_to_missing?(*args)
|
170
|
+
super || __getobj__.respond_to?(*args)
|
171
|
+
end
|
181
172
|
end
|
data/method_man.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
5
|
require 'method_object/version'
|
7
6
|
|
@@ -10,10 +9,8 @@ Gem::Specification.new do |spec|
|
|
10
9
|
spec.version = MethodObject::VERSION
|
11
10
|
spec.authors = ['Clay Shentrup']
|
12
11
|
spec.email = %w[cshentrup@gmail.com]
|
13
|
-
spec.summary =
|
14
|
-
|
15
|
-
spec.description = 'Provides a MethodObject class which implements Kent' +
|
16
|
-
%q(Beck's "method object" pattern.)
|
12
|
+
spec.summary = %(Provides a MethodObject class which implements KentBeck's "method object" pattern.)
|
13
|
+
spec.description = %(Provides a MethodObject class which implements KentBeck's "method object" pattern.)
|
17
14
|
spec.homepage = 'https://github.com/brokenladder/method_man'
|
18
15
|
spec.license = 'MIT'
|
19
16
|
|
@@ -22,9 +19,10 @@ Gem::Specification.new do |spec|
|
|
22
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
20
|
spec.require_paths = %w[lib]
|
24
21
|
|
25
|
-
spec.required_ruby_version = '>= 2.
|
22
|
+
spec.required_ruby_version = '>= 2.5'
|
26
23
|
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
24
|
+
spec.add_development_dependency('bundler')
|
25
|
+
spec.add_development_dependency('rake')
|
26
|
+
spec.add_development_dependency('rspec')
|
27
|
+
spec.add_development_dependency('rubocop')
|
30
28
|
end
|
data/spec/method_man_spec.rb
CHANGED
@@ -1,208 +1,119 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require('method_object')
|
4
|
+
require('ostruct')
|
4
5
|
|
5
6
|
RSpec.describe(MethodObject) do
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
context 'without attrs' do
|
11
|
-
subject do
|
7
|
+
context('with attrs') do
|
8
|
+
let(:method_object) do
|
12
9
|
Class.new(described_class) do
|
10
|
+
attrs(:block, :attr1, :attr2)
|
11
|
+
|
13
12
|
def call
|
14
|
-
|
13
|
+
instance_eval(&block)
|
15
14
|
end
|
16
|
-
end
|
17
|
-
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
Class.new(described_class) do
|
22
|
-
def call
|
23
|
-
undefined_method
|
24
|
-
end
|
16
|
+
def local_method
|
17
|
+
[attr1, attr2]
|
25
18
|
end
|
26
19
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
end
|
21
|
+
let(:attr1) { double('attr1', ambiguous_method: nil, delegated_method: delegated_value) }
|
22
|
+
let(:delegated_value) { 'delegated value' }
|
23
|
+
let(:attr2) do
|
24
|
+
double('attr2', ambiguous_method: nil, attr1_ambiguous_method: nil)
|
31
25
|
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
context 'with attrs' do
|
37
|
-
subject do
|
38
|
-
Class.new(described_class) do
|
39
|
-
attrs(:company, :user)
|
40
|
-
|
41
|
-
def call
|
42
|
-
self.name = 'New Company Name'
|
43
|
-
self.company_name = 'New Company Name 2'
|
44
|
-
{
|
45
|
-
address: address,
|
46
|
-
respond_to_address: respond_to_missing?(:address),
|
47
|
-
company_address: company_address,
|
48
|
-
id_for_joe: company_id_for('Joe'),
|
49
|
-
block_arg: company_run_a_block { |block_arg| block_arg * 2 },
|
50
|
-
respond_to_company_address: respond_to_missing?(:company_address),
|
51
|
-
company: company,
|
52
|
-
respond_to_name: respond_to_missing?(:name),
|
53
|
-
company_name: company_name,
|
54
|
-
respond_to_company_name: respond_to_missing?(:company_name),
|
55
|
-
user: user,
|
56
|
-
user_name: user_name,
|
57
|
-
respond_to_user_name: respond_to_missing?(:user_name),
|
58
|
-
respond_to_missing: respond_to_missing?(:undefined_method),
|
59
|
-
}
|
60
|
-
end
|
61
|
-
end
|
27
|
+
def call(&block)
|
28
|
+
method_object.call(block: block, attr1: attr1, attr2: attr2)
|
62
29
|
end
|
63
30
|
|
64
|
-
|
65
|
-
|
66
|
-
.tap do |company|
|
67
|
-
allow(company).to receive(:id_for).with('Joe').and_return(1234)
|
68
|
-
allow(company).to receive(:run_a_block) do |&block|
|
69
|
-
block.call(4321)
|
70
|
-
end
|
71
|
-
end
|
31
|
+
it('makes .new a private class method') do
|
32
|
+
expect { method_object.new }.to(raise_error(NoMethodError))
|
72
33
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
let(:user_name) { 'Woody' }
|
77
|
-
let(:result) { subject.call(company: company, user: user) }
|
78
|
-
|
79
|
-
specify do
|
80
|
-
expect(company).to receive(:name=).ordered.with('New Company Name')
|
81
|
-
expect(company).to receive(:name=).ordered.with('New Company Name 2')
|
82
|
-
expect(result).to eq(
|
83
|
-
address: company_address,
|
84
|
-
respond_to_address: true,
|
85
|
-
company_address: company_address,
|
86
|
-
id_for_joe: 1234,
|
87
|
-
block_arg: 8642,
|
88
|
-
respond_to_company_address: true,
|
89
|
-
company: company,
|
90
|
-
respond_to_name: false,
|
91
|
-
company_name: company_name,
|
92
|
-
respond_to_company_name: true,
|
93
|
-
user: user,
|
94
|
-
user_name: user_name,
|
95
|
-
respond_to_user_name: true,
|
96
|
-
respond_to_missing: false,
|
97
|
-
)
|
34
|
+
|
35
|
+
it('raises method missing exception for undefined methods') do
|
36
|
+
expect { call { undefined_method } }.to(raise_error(NameError, /undefined_method/))
|
98
37
|
end
|
99
38
|
|
100
|
-
it
|
101
|
-
expect {
|
39
|
+
it('calls its own methods and passed attrs') do
|
40
|
+
expect(call { local_method }).to(eq([attr1, attr2]))
|
102
41
|
end
|
103
42
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
attrs(:company, :user)
|
43
|
+
def delegates?(method)
|
44
|
+
call { respond_to?(method) }
|
45
|
+
end
|
108
46
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
47
|
+
it('delegates to attrs') do
|
48
|
+
expect(delegates?(:delegated_method)).to(be(true))
|
114
49
|
|
115
|
-
|
116
|
-
expect { result }.to raise_error(
|
117
|
-
MethodObject::AmbigousMethodError,
|
118
|
-
a_string_including('company.name, user.name'),
|
119
|
-
)
|
120
|
-
end
|
50
|
+
expect(call { delegated_method }).to(be(delegated_value))
|
121
51
|
end
|
122
52
|
|
123
|
-
|
124
|
-
|
125
|
-
Class.new(described_class) do
|
126
|
-
attrs(:company, :user)
|
53
|
+
it('delegates to attrs with prefix') do
|
54
|
+
expect(delegates?(:attr1_delegated_method)).to(be(true))
|
127
55
|
|
128
|
-
|
129
|
-
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
56
|
+
expect(call { attr1_delegated_method }).to(be(delegated_value))
|
57
|
+
end
|
133
58
|
|
134
|
-
|
59
|
+
it('raises for ambiguity on delegated method names') do
|
60
|
+
expect(delegates?(:ambiguous_method)).to(be(true))
|
135
61
|
|
136
|
-
|
137
|
-
|
62
|
+
expect { call { ambiguous_method } }.to(
|
63
|
+
raise_error(
|
138
64
|
MethodObject::AmbigousMethodError,
|
139
|
-
a_string_including('
|
140
|
-
)
|
141
|
-
|
65
|
+
a_string_including('ambiguous_method is ambiguous: attr1.ambiguous_method, attr2.ambiguous_method'),
|
66
|
+
),
|
67
|
+
)
|
142
68
|
end
|
143
69
|
|
144
|
-
|
145
|
-
|
146
|
-
Class.new(described_class) do
|
147
|
-
attrs(:diary)
|
70
|
+
it('raises for ambiguity on delegated and prefixed delegated method names') do
|
71
|
+
expect(delegates?(:attr1_ambiguous_method)).to(be(true))
|
148
72
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
73
|
+
expect { call { attr1_ambiguous_method } }.to(
|
74
|
+
raise_error(
|
75
|
+
MethodObject::AmbigousMethodError,
|
76
|
+
a_string_including(
|
77
|
+
'attr1_ambiguous_method is ambiguous: ' \
|
78
|
+
'attr2.attr1_ambiguous_method, attr1.ambiguous_method',
|
79
|
+
),
|
80
|
+
),
|
81
|
+
)
|
82
|
+
end
|
157
83
|
|
158
|
-
|
159
|
-
|
160
|
-
end
|
84
|
+
describe('assignments') do
|
85
|
+
let(:attr1) { OpenStruct.new }
|
161
86
|
|
162
|
-
|
163
|
-
|
87
|
+
it('assigns') do
|
88
|
+
call { attr1.foo = 'bar' }
|
89
|
+
expect(attr1.foo).to(eq('bar'))
|
164
90
|
end
|
165
91
|
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context('without attrs') do
|
95
|
+
let(:method_object) do
|
96
|
+
Class.new(described_class) do
|
97
|
+
def call
|
98
|
+
receiver_test
|
99
|
+
end
|
166
100
|
|
167
|
-
|
168
|
-
|
169
|
-
Class.new(described_class) do
|
170
|
-
attrs(:company)
|
171
|
-
@sent_messages = []
|
172
|
-
|
173
|
-
class << self
|
174
|
-
attr_reader(:sent_messages)
|
175
|
-
end
|
176
|
-
|
177
|
-
def call
|
178
|
-
[name, name]
|
179
|
-
end
|
180
|
-
|
181
|
-
# Ensure it defines resolved methods
|
182
|
-
def method_missing(method, *_args)
|
183
|
-
if self.class.sent_messages.include?(method)
|
184
|
-
raise 'method not memoized'
|
185
|
-
end
|
186
|
-
self.class.sent_messages << method
|
187
|
-
super
|
188
|
-
end
|
101
|
+
def receiver_test
|
102
|
+
42
|
189
103
|
end
|
190
104
|
end
|
105
|
+
end
|
191
106
|
|
192
|
-
|
193
|
-
|
194
|
-
.to eq([company_name, company_name])
|
195
|
-
end
|
107
|
+
def call
|
108
|
+
method_object.call
|
196
109
|
end
|
197
|
-
end
|
198
110
|
|
199
|
-
|
200
|
-
|
201
|
-
Class.new(described_class) { attrs(:user_1_age) }
|
111
|
+
it 'makes new a private class method' do
|
112
|
+
expect { method_object.new }.to raise_error(NoMethodError)
|
202
113
|
end
|
203
114
|
|
204
|
-
|
205
|
-
expect {
|
115
|
+
it('calls itself') do
|
116
|
+
expect(call { receiver_test }).to eq(42)
|
206
117
|
end
|
207
118
|
end
|
208
119
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,57 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: method_man
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clay Shentrup
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
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: '
|
26
|
+
version: '0'
|
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: '
|
33
|
+
version: '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: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: Provides a MethodObject class which implements KentBeck's "method object"
|
56
70
|
pattern.
|
57
71
|
email:
|
@@ -79,7 +93,7 @@ homepage: https://github.com/brokenladder/method_man
|
|
79
93
|
licenses:
|
80
94
|
- MIT
|
81
95
|
metadata: {}
|
82
|
-
post_install_message:
|
96
|
+
post_install_message:
|
83
97
|
rdoc_options: []
|
84
98
|
require_paths:
|
85
99
|
- lib
|
@@ -87,16 +101,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
101
|
requirements:
|
88
102
|
- - ">="
|
89
103
|
- !ruby/object:Gem::Version
|
90
|
-
version: '2.
|
104
|
+
version: '2.5'
|
91
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - ">="
|
94
108
|
- !ruby/object:Gem::Version
|
95
109
|
version: '0'
|
96
110
|
requirements: []
|
97
|
-
|
98
|
-
|
99
|
-
signing_key:
|
111
|
+
rubygems_version: 3.1.2
|
112
|
+
signing_key:
|
100
113
|
specification_version: 4
|
101
114
|
summary: Provides a MethodObject class which implements KentBeck's "method object"
|
102
115
|
pattern.
|