accord 0.1.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 +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +43 -0
- data/accord.gemspec +20 -0
- data/lib/accord.rb +4 -0
- data/lib/accord/adapter_registry.rb +106 -0
- data/lib/accord/base_registry.rb +73 -0
- data/lib/accord/declarations.rb +131 -0
- data/lib/accord/exceptions.rb +22 -0
- data/lib/accord/extendor.rb +36 -0
- data/lib/accord/extendor_container.rb +43 -0
- data/lib/accord/interface.rb +189 -0
- data/lib/accord/interface_body.rb +73 -0
- data/lib/accord/interface_members.rb +31 -0
- data/lib/accord/interface_method.rb +27 -0
- data/lib/accord/interfaces.rb +471 -0
- data/lib/accord/nested_key_hash.rb +66 -0
- data/lib/accord/ro.rb +65 -0
- data/lib/accord/signature_info.rb +76 -0
- data/lib/accord/specification.rb +83 -0
- data/lib/accord/subscription_registry.rb +76 -0
- data/lib/accord/tags.rb +25 -0
- data/lib/accord/version.rb +3 -0
- data/spec/adapter_registry_spec.rb +296 -0
- data/spec/declarations_spec.rb +144 -0
- data/spec/extendor_container_spec.rb +101 -0
- data/spec/extendor_spec.rb +203 -0
- data/spec/integration/adaptation_spec.rb +86 -0
- data/spec/integration/adapter_for_class_declaration_spec.rb +22 -0
- data/spec/integration/adapter_hook_spec.rb +41 -0
- data/spec/integration/default_adapters_spec.rb +81 -0
- data/spec/integration/hash_adapters_spec.rb +20 -0
- data/spec/integration/interface_declaration_spec.rb +258 -0
- data/spec/integration/multi_adapters_spec.rb +83 -0
- data/spec/integration/named_adapters_spec.rb +54 -0
- data/spec/integration/single_adapters_spec.rb +93 -0
- data/spec/integration/subscriptions_spec.rb +245 -0
- data/spec/integration/verification_spec.rb +215 -0
- data/spec/interface_body_spec.rb +157 -0
- data/spec/interface_members_spec.rb +57 -0
- data/spec/interface_spec.rb +147 -0
- data/spec/nested_key_hash_spec.rb +140 -0
- data/spec/signature_info_spec.rb +65 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/specification_spec.rb +246 -0
- data/spec/subscription_registry_spec.rb +206 -0
- data/spec/tags_spec.rb +38 -0
- metadata +134 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'accord'
|
3
|
+
|
4
|
+
describe "Named adapters" do
|
5
|
+
let(:registry) { Accord::AdapterRegistry.new }
|
6
|
+
|
7
|
+
context "single" do
|
8
|
+
let(:ip1) { Accord::InterfaceClass.new(:ip1, [Accord::Interface]) }
|
9
|
+
let(:ir1) { Accord::InterfaceClass.new(:ir1, [Accord::Interface]) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
registry.register([ir1], ip1, '') { 1 }
|
13
|
+
registry.register([ir1], ip1, 'bob') { 2 }
|
14
|
+
end
|
15
|
+
|
16
|
+
subject do
|
17
|
+
registry.lookup_all([ir1], ip1).map { |name, fac| [name, fac.call] }
|
18
|
+
end
|
19
|
+
|
20
|
+
it { should eq [['', 1], ['bob', 2]] }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "multi" do
|
24
|
+
let(:ip1) { Accord::InterfaceClass.new(:ip1, [Accord::Interface]) }
|
25
|
+
let(:ir1) { Accord::InterfaceClass.new(:ir1, [Accord::Interface]) }
|
26
|
+
let(:ir2) { Accord::InterfaceClass.new(:ir2, [Accord::Interface]) }
|
27
|
+
|
28
|
+
before do
|
29
|
+
registry.register([ir1, ir2], ip1, '') { 1 }
|
30
|
+
registry.register([ir1, ir2], ip1, 'bob') { 2 }
|
31
|
+
end
|
32
|
+
|
33
|
+
subject do
|
34
|
+
registry.lookup_all([ir1, ir2], ip1).map { |name, fac| [name, fac.call] }
|
35
|
+
end
|
36
|
+
|
37
|
+
it { should eq [['', 1], ['bob', 2]] }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "null" do
|
41
|
+
let(:ip1) { Accord::InterfaceClass.new(:ip1, [Accord::Interface]) }
|
42
|
+
|
43
|
+
before do
|
44
|
+
registry.register([], ip1, '') { 1 }
|
45
|
+
registry.register([], ip1, 'bob') { 2 }
|
46
|
+
end
|
47
|
+
|
48
|
+
subject do
|
49
|
+
registry.lookup_all([], ip1).map { |name, fac| [name, fac.call] }
|
50
|
+
end
|
51
|
+
|
52
|
+
it { should eq [['', 1], ['bob', 2]] }
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'accord'
|
3
|
+
|
4
|
+
describe "Single adapters" do
|
5
|
+
let(:registry) { Accord::AdapterRegistry.new }
|
6
|
+
let(:ir1) { Accord::InterfaceClass.new(:ir1, [Accord::Interface]) }
|
7
|
+
let(:ir2) { Accord::InterfaceClass.new(:ir2, [ir1]) }
|
8
|
+
let(:ip1) { Accord::InterfaceClass.new(:ip1, [Accord::Interface]) }
|
9
|
+
let(:ip2) { Accord::InterfaceClass.new(:ip2, [ip1]) }
|
10
|
+
let(:ip3) { Accord::InterfaceClass.new(:ip3, [ip2]) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
registry.register([ir1], ip2, '') { 12 }
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "exact lookup" do
|
17
|
+
expect(registry.lookup([ir1], ip2, '').call).to eq 12
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "lookup using an extension of a previously registered adapter" do
|
21
|
+
expect(registry.lookup([ir2], ip2, '').call).to eq 12
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "lookup by class implementation" do
|
25
|
+
cls = Class.new
|
26
|
+
Accord::Declarations.implements(cls, ir2)
|
27
|
+
expect(registry.lookup([ir2], ip2, '').call).to eq 12
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "lookup for interface whose registration's provided extends" do
|
31
|
+
expect(registry.lookup([ir2], ip1, '').call).to eq 12
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "lookup for spec not extending registered one" do
|
35
|
+
expect(registry.lookup([Accord::Interface], ip1, '')).to be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "lookup for spec not extending registered one, with default" do
|
39
|
+
expect(registry.lookup([Accord::Interface], ip1, '',
|
40
|
+
default: lambda { 42 }).call).to eq 42
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "lookup for interface not provided by any registration" do
|
44
|
+
expect(registry.lookup([ir1], ip3, '')).to be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "lookup by name" do
|
48
|
+
expect(registry.lookup([ir1], ip1, 'bob')).to be_nil
|
49
|
+
registry.register([ir1], ip2, 'bob') { "Bob's 12" }
|
50
|
+
expect(registry.lookup([ir1], ip1, 'bob').call).to eq "Bob's 12"
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "lookup omitting name" do
|
54
|
+
expect(registry.lookup([ir1], ip1).call).to eq 12
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "lookup for adapter providing more appropriated spec" do
|
58
|
+
registry.register([ir1], ip1, '') { 11 }
|
59
|
+
expect(registry.lookup([ir1], ip1, '').call).to eq 11
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "lookup for more specific adapter" do
|
63
|
+
registry.register([ir2], ip2, '') { 21 }
|
64
|
+
expect(registry.lookup([ir2], ip1, '').call).to eq 21
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "detecting exactly matches" do
|
68
|
+
specify "getting less specific" do
|
69
|
+
registry.register([ir1], ip1, '') { 11 }
|
70
|
+
expect(registry.first(required: [ir1], provided: ip1).call).to eq 11
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "getting more specific" do
|
74
|
+
expect(registry.first(required: [ir1], provided: ip2).call).to eq 12
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "getting more specific with name" do
|
78
|
+
registry.register([ir1], ip2, 'bob') { "Bob's 12" }
|
79
|
+
expect(
|
80
|
+
registry.first(required: [ir1], provided: ip2, name: 'bob').call
|
81
|
+
).to eq "Bob's 12"
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "using more specific required interface" do
|
85
|
+
registry.register([ir2], ip2, '') { 21 }
|
86
|
+
expect(registry.first(required: [ir2], provided: ip2).call).to eq 21
|
87
|
+
end
|
88
|
+
|
89
|
+
specify "missing by trying to get a unregistered adapter" do
|
90
|
+
expect(registry.first(required: [ir2], provided: ip2)).to be_nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'accord'
|
3
|
+
|
4
|
+
describe "Subscriptions" do
|
5
|
+
let(:registry) { Accord::SubscriptionRegistry.new }
|
6
|
+
let(:ip1) { Accord::InterfaceClass.new(:ip1, [Accord::Interface]) }
|
7
|
+
let(:ir1) { Accord::InterfaceClass.new(:ir1, [Accord::Interface]) }
|
8
|
+
|
9
|
+
context "single" do
|
10
|
+
context "registrations for same interface" do
|
11
|
+
before do
|
12
|
+
registry.subscribe([ir1], ip1) { 'sub1' }
|
13
|
+
registry.subscribe([ir1], ip1) { 'sub2' }
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "are returned by order of definition" do
|
17
|
+
items = registry.lookup([ir1], ip1).map do |sub|
|
18
|
+
sub.call
|
19
|
+
end
|
20
|
+
expect(items).to eq ['sub1', 'sub2']
|
21
|
+
end
|
22
|
+
|
23
|
+
context "and also for all interfaces" do
|
24
|
+
before do
|
25
|
+
registry.subscribe([nil], ip1) { 'general' }
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "are returned first" do
|
29
|
+
items = registry.lookup([ir1], ip1).map do |sub|
|
30
|
+
sub.call
|
31
|
+
end
|
32
|
+
expect(items).to eq ['general', 'sub1', 'sub2']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "multi" do
|
39
|
+
let(:ir2) { Accord::InterfaceClass.new(:ir2, [Accord::Interface]) }
|
40
|
+
|
41
|
+
before do
|
42
|
+
registry.subscribe([ir1, ir2], ip1) { 'sub1' }
|
43
|
+
registry.subscribe([ir1, ir2], ip1) { 'sub2' }
|
44
|
+
end
|
45
|
+
|
46
|
+
specify "are returned by order of definition" do
|
47
|
+
items = registry.lookup([ir1, ir2], ip1).map do |sub|
|
48
|
+
sub.call
|
49
|
+
end
|
50
|
+
expect(items).to eq ['sub1', 'sub2']
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with a registration for all interfaces as first discriminator" do
|
54
|
+
before do
|
55
|
+
registry.subscribe([nil, ir2], ip1) { 'general' }
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns that registration first" do
|
59
|
+
items = registry.lookup([ir1, ir2], ip1).map do |sub|
|
60
|
+
sub.call
|
61
|
+
end
|
62
|
+
expect(items).to eq ['general', 'sub1', 'sub2']
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "null" do
|
68
|
+
before do
|
69
|
+
registry.subscribe([], ip1) { 'sub1' }
|
70
|
+
registry.subscribe([], ip1) { 'sub2' }
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "are returned by order of definition" do
|
74
|
+
items = registry.lookup([], ip1).map do |sub|
|
75
|
+
sub.call
|
76
|
+
end
|
77
|
+
expect(items).to eq ['sub1', 'sub2']
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "unregistration" do
|
82
|
+
let(:subscriber1) { Proc.new { 'sub1' } }
|
83
|
+
let(:subscriber2) { Proc.new { 'sub2' } }
|
84
|
+
|
85
|
+
before do
|
86
|
+
registry.subscribe([ir1], ip1, &subscriber1)
|
87
|
+
registry.subscribe([ir1], ip1, &subscriber2)
|
88
|
+
end
|
89
|
+
|
90
|
+
subject { registry.lookup([ir1], ip1).map { |sub| sub.call } }
|
91
|
+
|
92
|
+
context "when a specific subscriber is specified" do
|
93
|
+
before do
|
94
|
+
registry.unsubscribe([ir1], ip1, subscriber1)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "unregisters only it" do
|
98
|
+
expect(subject).to eq ['sub2']
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when no subscriber is specified" do
|
103
|
+
before do
|
104
|
+
registry.unsubscribe([ir1], ip1)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "unregisters all" do
|
108
|
+
expect(subject).to be_empty
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "Subscription adapters" do
|
114
|
+
let(:cls) { Class.new { Accord::Declarations.implements(self, IR1) } }
|
115
|
+
let(:obj) { cls.new }
|
116
|
+
|
117
|
+
before { stub_const('IR1', ir1) }
|
118
|
+
|
119
|
+
context "single" do
|
120
|
+
let(:calls) { [] }
|
121
|
+
let(:s1) { Proc.new { |o| calls << ['sub1', o]; ['sub1', o] } }
|
122
|
+
let(:s2) { Proc.new { |o| calls << ['sub2', o]; ['sub2', o] } }
|
123
|
+
|
124
|
+
before do
|
125
|
+
registry.subscribe([ir1], ip1, &s1)
|
126
|
+
registry.subscribe([ir1], ip1, &s2)
|
127
|
+
end
|
128
|
+
|
129
|
+
specify "are get in the order they are subscribed" do
|
130
|
+
items = registry.get([obj], ip1)
|
131
|
+
expect(items).to eq [['sub1', obj], ['sub2', obj]]
|
132
|
+
end
|
133
|
+
|
134
|
+
specify "are called in the order they are subscribed" do
|
135
|
+
registry.call([obj], ip1)
|
136
|
+
expect(calls).to eq [['sub1', obj], ['sub2', obj]]
|
137
|
+
end
|
138
|
+
|
139
|
+
context "when a nil is returned by the subscriber" do
|
140
|
+
before do
|
141
|
+
registry.subscribe([ir1], ip1) { nil }
|
142
|
+
end
|
143
|
+
|
144
|
+
specify "#get doesn't return it" do
|
145
|
+
items = registry.get([obj], ip1)
|
146
|
+
expect(items).to eq [['sub1', obj], ['sub2', obj]]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "multiple" do
|
152
|
+
let(:ir2) { Accord::InterfaceClass.new(:ir2, [Accord::Interface]) }
|
153
|
+
let(:cls2) { Class.new { Accord::Declarations.implements(self, IR2) } }
|
154
|
+
let(:obj2) { cls2.new }
|
155
|
+
|
156
|
+
let(:calls) { [] }
|
157
|
+
let(:s1) { Proc.new { |r1, r2| calls << [1, r1, r2]; [1, r1, r2] } }
|
158
|
+
let(:s2) { Proc.new { |r1, r2| calls << [2, r1, r2]; [2, r1, r2] } }
|
159
|
+
|
160
|
+
before do
|
161
|
+
stub_const('IR2', ir2)
|
162
|
+
registry.subscribe([ir1, ir2], ip1, &s1)
|
163
|
+
registry.subscribe([ir1, ir2], ip1, &s2)
|
164
|
+
end
|
165
|
+
|
166
|
+
specify "are get in the order they are subscribed" do
|
167
|
+
items = registry.get([obj, obj2], ip1)
|
168
|
+
expect(items).to eq [[1, obj, obj2], [2, obj, obj2]]
|
169
|
+
end
|
170
|
+
|
171
|
+
specify "are called in the order they are subscribed" do
|
172
|
+
registry.call([obj, obj2], ip1)
|
173
|
+
expect(calls).to eq [[1, obj, obj2], [2, obj, obj2]]
|
174
|
+
end
|
175
|
+
|
176
|
+
context "when a nil is returned by the subscriber" do
|
177
|
+
before do
|
178
|
+
registry.subscribe([ir1, ir2], ip1) { nil }
|
179
|
+
end
|
180
|
+
|
181
|
+
specify "#get doesn't return it" do
|
182
|
+
items = registry.get([obj, obj2], ip1)
|
183
|
+
expect(items).to eq [[1, obj, obj2], [2, obj, obj2]]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "null" do
|
189
|
+
let(:calls) { [] }
|
190
|
+
|
191
|
+
before do
|
192
|
+
registry.subscribe([], ip1) { |*args| calls << [1, args]; 1 }
|
193
|
+
registry.subscribe([], ip1) { |*args| calls << [2, args]; 2 }
|
194
|
+
end
|
195
|
+
|
196
|
+
specify "are get in the order they are subscribed" do
|
197
|
+
items = registry.get([], ip1)
|
198
|
+
expect(items).to eq [1, 2]
|
199
|
+
end
|
200
|
+
|
201
|
+
specify "are called in the order they are subscribed" do
|
202
|
+
registry.call([], ip1)
|
203
|
+
expect(calls).to eq [[1, []], [2, []]]
|
204
|
+
end
|
205
|
+
|
206
|
+
context "when a nil is returned by the subscriber" do
|
207
|
+
before do
|
208
|
+
registry.subscribe([], ip1) { nil }
|
209
|
+
end
|
210
|
+
|
211
|
+
specify "#get doesn't return it" do
|
212
|
+
items = registry.get([], ip1)
|
213
|
+
expect(items).to eq [1, 2]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "Handlers" do
|
220
|
+
let(:arguments) { [] }
|
221
|
+
let(:obj) { Object.new }
|
222
|
+
|
223
|
+
before do
|
224
|
+
registry.subscribe([ir1], nil) { |*args| arguments.concat(args) }
|
225
|
+
end
|
226
|
+
|
227
|
+
context "when required objects are satisfied" do
|
228
|
+
before do
|
229
|
+
Accord::Declarations.also_provides(obj, ir1)
|
230
|
+
end
|
231
|
+
|
232
|
+
specify "are called in the order they are defined" do
|
233
|
+
registry.call([obj], nil)
|
234
|
+
expect(arguments).to eq [obj]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context "when required objects are not satisfied" do
|
239
|
+
specify "are not called" do
|
240
|
+
registry.call([obj], nil)
|
241
|
+
expect(arguments).to be_empty
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'accord'
|
3
|
+
|
4
|
+
describe "Verification" do
|
5
|
+
before do
|
6
|
+
stub_const('TestModule', Module.new)
|
7
|
+
|
8
|
+
Accord::Interface(TestModule, :B1) do
|
9
|
+
responds_to :method1
|
10
|
+
end
|
11
|
+
|
12
|
+
Accord::Interface(TestModule, :B2) do
|
13
|
+
responds_to :method2, params: :arg
|
14
|
+
end
|
15
|
+
|
16
|
+
Accord::Interface(TestModule, :B3) do
|
17
|
+
responds_to :method3, params: [ :arg1, :arg2 ]
|
18
|
+
end
|
19
|
+
|
20
|
+
Accord::Interface(TestModule, :B4) do
|
21
|
+
responds_to :method4, params: [ :arg1, { arg2: :default } ]
|
22
|
+
end
|
23
|
+
|
24
|
+
Accord::Interface(TestModule, :B5) do
|
25
|
+
responds_to :method5, params: [ :arg1, :"*arg2", :"&block" ]
|
26
|
+
end
|
27
|
+
|
28
|
+
Accord::Interface(TestModule, :I) do
|
29
|
+
extends TestModule::B1
|
30
|
+
extends TestModule::B2
|
31
|
+
extends TestModule::B3
|
32
|
+
extends TestModule::B4
|
33
|
+
extends TestModule::B5
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "objects" do
|
38
|
+
let(:candidate) { Object.new }
|
39
|
+
|
40
|
+
context "when candidate not even provides the interface" do
|
41
|
+
it "raises DoesNotImplement" do
|
42
|
+
expect {
|
43
|
+
TestModule::I.verify_object(candidate)
|
44
|
+
}.to raise_error(Accord::DoesNotImplement)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when candidate at least provides the interface" do
|
49
|
+
before do
|
50
|
+
Accord::Declarations.also_provides(candidate, TestModule::I)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when candidate has none of the methods" do
|
54
|
+
it "raises BrokenImplementation" do
|
55
|
+
expect {
|
56
|
+
TestModule::I.verify_object(candidate)
|
57
|
+
}.to raise_error(Accord::BrokenImplementation)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when candidate is missing one of the methods" do
|
62
|
+
it "raises BrokenImplementation" do
|
63
|
+
def candidate.method1; end
|
64
|
+
def candidate.method2(a1, a2); end
|
65
|
+
def candidate.method3(a1, a2=:any); end
|
66
|
+
expect {
|
67
|
+
TestModule::I.verify_object(candidate)
|
68
|
+
}.to raise_error(Accord::BrokenImplementation)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when the candidate has all methods, but signatures don't "\
|
73
|
+
"match" do
|
74
|
+
it "raises BrokenImplementation" do
|
75
|
+
def candidate.method1; end
|
76
|
+
def candidate.method2(a1); end
|
77
|
+
def candidate.method3(a1, a2); end
|
78
|
+
def candidate.method4(a1, a2); end
|
79
|
+
def candidate.method5; end
|
80
|
+
expect {
|
81
|
+
TestModule::I.verify_object(candidate)
|
82
|
+
}.to raise_error(Accord::BrokenImplementation)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when all methods match signature" do
|
87
|
+
it "doesn't raise" do
|
88
|
+
def candidate.method1; end
|
89
|
+
def candidate.method2(a1); end
|
90
|
+
def candidate.method3(a1, a2); end
|
91
|
+
def candidate.method4(a1, a2=:any); end
|
92
|
+
def candidate.method5(a1, *a2, &block); end
|
93
|
+
expect {
|
94
|
+
TestModule::I.verify_object(candidate)
|
95
|
+
}.to_not raise_error(Accord::BrokenImplementation)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when a method has a default as last argument" do
|
100
|
+
it "doesn't raise if it still can be called with that argument" do
|
101
|
+
def candidate.method1(a1=nil); end
|
102
|
+
def candidate.method2(a1, a2=nil); end
|
103
|
+
def candidate.method3(a1, a2=nil); end
|
104
|
+
def candidate.method4(a1, a2=:any); end
|
105
|
+
def candidate.method5(a1, *a2, &block); end
|
106
|
+
expect {
|
107
|
+
TestModule::I.verify_object(candidate)
|
108
|
+
}.to_not raise_error(Accord::BrokenImplementation)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "module" do
|
115
|
+
let(:candidate) { Module.new }
|
116
|
+
|
117
|
+
context "when candidate not even implements the interface" do
|
118
|
+
it "raises DoesNotImplement" do
|
119
|
+
expect {
|
120
|
+
TestModule::I.verify_module(candidate)
|
121
|
+
}.to raise_error(Accord::DoesNotImplement)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when candidate at least implements the interface" do
|
126
|
+
before do
|
127
|
+
Accord::Declarations.implements(candidate, TestModule::I)
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when candidate has none of the methods" do
|
131
|
+
it "raises BrokenImplementation" do
|
132
|
+
expect {
|
133
|
+
TestModule::I.verify_module(candidate)
|
134
|
+
}.to raise_error(Accord::BrokenImplementation)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when candidate is missing one of the methods" do
|
139
|
+
it "raises BrokenImplementation" do
|
140
|
+
candidate.module_eval do
|
141
|
+
def method1; end
|
142
|
+
def method2(a1, a2); end
|
143
|
+
def method3(a1, a2=:any); end
|
144
|
+
end
|
145
|
+
expect {
|
146
|
+
TestModule::I.verify_module(candidate)
|
147
|
+
}.to raise_error(Accord::BrokenImplementation)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when the candidate has all methods, but signatures don't "\
|
152
|
+
"match" do
|
153
|
+
it "raises BrokenImplementation" do
|
154
|
+
candidate.module_eval do
|
155
|
+
def method1; end
|
156
|
+
def method2(a1); end
|
157
|
+
def method3(a1, a2); end
|
158
|
+
def method4(a1, a2); end
|
159
|
+
def method5; end
|
160
|
+
end
|
161
|
+
expect {
|
162
|
+
TestModule::I.verify_module(candidate)
|
163
|
+
}.to raise_error(Accord::BrokenImplementation)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when all methods match signature" do
|
168
|
+
it "doesn't raise" do
|
169
|
+
candidate.module_eval do
|
170
|
+
def method1; end
|
171
|
+
def method2(a1); end
|
172
|
+
def method3(a1, a2); end
|
173
|
+
def method4(a1, a2=:any); end
|
174
|
+
def method5(a1, *a2, &block); end
|
175
|
+
end
|
176
|
+
expect {
|
177
|
+
TestModule::I.verify_module(candidate)
|
178
|
+
}.to_not raise_error(Accord::BrokenImplementation)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "when a method has a default as last argument" do
|
183
|
+
it "doesn't raise if it still can be called with that argument" do
|
184
|
+
candidate.module_eval do
|
185
|
+
def method1(a1=nil); end
|
186
|
+
def method2(a1, a2=nil); end
|
187
|
+
def method3(a1, a2=nil); end
|
188
|
+
def method4(a1, a2=:any); end
|
189
|
+
def method5(a1, *a2, &block); end
|
190
|
+
end
|
191
|
+
expect {
|
192
|
+
TestModule::I.verify_module(candidate)
|
193
|
+
}.to_not raise_error(Accord::BrokenImplementation)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
module Accord
|
200
|
+
describe "implementations" do
|
201
|
+
specify "interfaces should be implemented" do
|
202
|
+
Interfaces::Tags.verify_module(Tags)
|
203
|
+
Interfaces::SignatureInfo.verify_module(SignatureInfo)
|
204
|
+
Interfaces::Method.verify_module(InterfaceMethod)
|
205
|
+
Interfaces::Specification.verify_module(Specification)
|
206
|
+
Interfaces::Interface.verify_module(InterfaceClass)
|
207
|
+
Interfaces::Declaration.verify_module(Declarations::Declaration)
|
208
|
+
Interfaces::InterfaceDeclarations.verify_object(Declarations)
|
209
|
+
Interfaces::AdapterRegistry.verify_module(AdapterRegistry)
|
210
|
+
Interfaces::SubscriptionRegistry.verify_module(SubscriptionRegistry)
|
211
|
+
Interfaces::InterfaceBody.verify_module(InterfaceBody)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|