functional-ruby 0.7.7 → 1.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 +4 -4
- data/README.md +92 -152
- data/doc/memo.txt +192 -0
- data/doc/pattern_matching.txt +485 -0
- data/doc/protocol.txt +221 -0
- data/doc/record.txt +144 -0
- data/doc/thread_safety.txt +8 -0
- data/lib/functional.rb +48 -18
- data/lib/functional/abstract_struct.rb +161 -0
- data/lib/functional/delay.rb +117 -0
- data/lib/functional/either.rb +222 -0
- data/lib/functional/memo.rb +93 -0
- data/lib/functional/method_signature.rb +72 -0
- data/lib/functional/option.rb +209 -0
- data/lib/functional/pattern_matching.rb +117 -100
- data/lib/functional/protocol.rb +157 -0
- data/lib/functional/protocol_info.rb +193 -0
- data/lib/functional/record.rb +155 -0
- data/lib/functional/type_check.rb +112 -0
- data/lib/functional/union.rb +152 -0
- data/lib/functional/version.rb +3 -1
- data/spec/functional/abstract_struct_shared.rb +154 -0
- data/spec/functional/complex_pattern_matching_spec.rb +205 -0
- data/spec/functional/configuration_spec.rb +17 -0
- data/spec/functional/delay_spec.rb +147 -0
- data/spec/functional/either_spec.rb +237 -0
- data/spec/functional/memo_spec.rb +207 -0
- data/spec/functional/option_spec.rb +292 -0
- data/spec/functional/pattern_matching_spec.rb +279 -276
- data/spec/functional/protocol_info_spec.rb +444 -0
- data/spec/functional/protocol_spec.rb +274 -0
- data/spec/functional/record_spec.rb +175 -0
- data/spec/functional/type_check_spec.rb +103 -0
- data/spec/functional/union_spec.rb +110 -0
- data/spec/spec_helper.rb +6 -4
- metadata +55 -45
- data/lib/functional/behavior.rb +0 -138
- data/lib/functional/behaviour.rb +0 -2
- data/lib/functional/catalog.rb +0 -487
- data/lib/functional/collection.rb +0 -403
- data/lib/functional/inflect.rb +0 -127
- data/lib/functional/platform.rb +0 -120
- data/lib/functional/search.rb +0 -132
- data/lib/functional/sort.rb +0 -41
- data/lib/functional/utilities.rb +0 -189
- data/md/behavior.md +0 -188
- data/md/catalog.md +0 -32
- data/md/collection.md +0 -32
- data/md/inflect.md +0 -32
- data/md/pattern_matching.md +0 -512
- data/md/platform.md +0 -32
- data/md/search.md +0 -32
- data/md/sort.md +0 -32
- data/md/utilities.md +0 -55
- data/spec/functional/behavior_spec.rb +0 -528
- data/spec/functional/catalog_spec.rb +0 -1206
- data/spec/functional/collection_spec.rb +0 -752
- data/spec/functional/inflect_spec.rb +0 -85
- data/spec/functional/integration_spec.rb +0 -205
- data/spec/functional/platform_spec.rb +0 -501
- data/spec/functional/search_spec.rb +0 -187
- data/spec/functional/sort_spec.rb +0 -61
- data/spec/functional/utilities_spec.rb +0 -277
@@ -0,0 +1,444 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Functional
|
4
|
+
|
5
|
+
describe ProtocolInfo do
|
6
|
+
|
7
|
+
let!(:kitchen_sink) do
|
8
|
+
ProtocolInfo.new(:Everything) do
|
9
|
+
instance_method :instance_method
|
10
|
+
class_method :class_method
|
11
|
+
attr_accessor :attr_accessor
|
12
|
+
attr_reader :attr_reader
|
13
|
+
attr_writer :attr_writer
|
14
|
+
class_attr_accessor :class_attr_accessor
|
15
|
+
class_attr_reader :class_attr_reader
|
16
|
+
class_attr_writer :class_attr_writer
|
17
|
+
constant :CONSTANT
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context '#initialize' do
|
22
|
+
|
23
|
+
it 'raises an exception when no block is given' do
|
24
|
+
expect {
|
25
|
+
ProtocolInfo.new(:Foo)
|
26
|
+
}.to raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises an exception when the name is nil' do
|
30
|
+
expect {
|
31
|
+
ProtocolInfo.new(nil){ nil }
|
32
|
+
}.to raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises an exception when the name is blank' do
|
36
|
+
expect {
|
37
|
+
ProtocolInfo.new(''){ nil }
|
38
|
+
}.to raise_error(ArgumentError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'specifies an instance method with no arity given' do
|
42
|
+
info = ProtocolInfo.new(:Foo) do
|
43
|
+
instance_method :foo
|
44
|
+
end
|
45
|
+
|
46
|
+
expect(info.instance_methods[:foo]).to be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'specifies an instance method with a given arity' do
|
50
|
+
info = ProtocolInfo.new(:Foo) do
|
51
|
+
instance_method :foo, 2
|
52
|
+
end
|
53
|
+
|
54
|
+
expect(info.instance_methods[:foo]).to eq 2
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'specifies a class method with any arity' do
|
58
|
+
info = ProtocolInfo.new(:Foo) do
|
59
|
+
class_method :foo
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(info.class_methods[:foo]).to be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'specifies a class method with a given arity' do
|
66
|
+
info = ProtocolInfo.new(:Foo) do
|
67
|
+
class_method :foo, 2
|
68
|
+
end
|
69
|
+
|
70
|
+
expect(info.class_methods[:foo]).to eq 2
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'specifies an instance attribute reader' do
|
74
|
+
info = ProtocolInfo.new(:Foo) do
|
75
|
+
attr_reader :foo
|
76
|
+
end
|
77
|
+
|
78
|
+
expect(info.instance_methods[:foo]).to eq 0
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'specifies an instance attribute writer' do
|
82
|
+
info = ProtocolInfo.new(:Foo) do
|
83
|
+
attr_writer :foo
|
84
|
+
end
|
85
|
+
|
86
|
+
expect(info.instance_methods[:foo=]).to eq 1
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'specifies an instance attribute accessor' do
|
90
|
+
info = ProtocolInfo.new(:Foo) do
|
91
|
+
attr_accessor :foo
|
92
|
+
end
|
93
|
+
|
94
|
+
expect(info.instance_methods[:foo]).to eq 0
|
95
|
+
expect(info.instance_methods[:foo=]).to eq 1
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'specifies a class attribute reader' do
|
99
|
+
info = ProtocolInfo.new(:Foo) do
|
100
|
+
class_attr_reader :foo
|
101
|
+
end
|
102
|
+
|
103
|
+
expect(info.class_methods[:foo]).to eq 0
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'specifies a class attribute writer' do
|
107
|
+
info = ProtocolInfo.new(:Foo) do
|
108
|
+
class_attr_writer :foo
|
109
|
+
end
|
110
|
+
|
111
|
+
expect(info.class_methods[:foo=]).to eq 1
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'specifies a class attribute accessor' do
|
115
|
+
info = ProtocolInfo.new(:Foo) do
|
116
|
+
class_attr_accessor :foo
|
117
|
+
end
|
118
|
+
|
119
|
+
expect(info.class_methods[:foo]).to eq 0
|
120
|
+
expect(info.class_methods[:foo=]).to eq 1
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'specifies a constant' do
|
124
|
+
info = ProtocolInfo.new(:Foo) do
|
125
|
+
constant :FOO
|
126
|
+
end
|
127
|
+
|
128
|
+
expect(info.constants).to include :FOO
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context '#satisfies?' do
|
133
|
+
|
134
|
+
it 'validates methods with no arity given' do
|
135
|
+
info = ProtocolInfo.new(:Foo) do
|
136
|
+
instance_method(:bar)
|
137
|
+
class_method(:baz)
|
138
|
+
end
|
139
|
+
|
140
|
+
clazz = Class.new do
|
141
|
+
def bar(a, b, c=1, d=2, *args); nil; end
|
142
|
+
def self.baz(); nil; end
|
143
|
+
end
|
144
|
+
|
145
|
+
expect(info.satisfies?(clazz.new)).to be true
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'validates methods with no parameters' do
|
149
|
+
info = ProtocolInfo.new(:Foo) do
|
150
|
+
instance_method(:bar, 0)
|
151
|
+
class_method(:baz, 0)
|
152
|
+
end
|
153
|
+
|
154
|
+
clazz = Class.new do
|
155
|
+
def bar(); nil; end
|
156
|
+
def self.baz(); nil; end
|
157
|
+
end
|
158
|
+
|
159
|
+
expect(info.satisfies?(clazz.new)).to be true
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'validates methods with a fixed number of parameters' do
|
163
|
+
info = ProtocolInfo.new(:Foo) do
|
164
|
+
instance_method(:bar, 3)
|
165
|
+
class_method(:baz, 3)
|
166
|
+
end
|
167
|
+
|
168
|
+
clazz = Class.new do
|
169
|
+
def bar(a,b,c); nil; end
|
170
|
+
def self.baz(a,b,c); nil; end
|
171
|
+
end
|
172
|
+
|
173
|
+
expect(info.satisfies?(clazz.new)).to be true
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'validates methods with optional parameters' do
|
177
|
+
info = ProtocolInfo.new(:Foo) do
|
178
|
+
instance_method(:bar, -2)
|
179
|
+
class_method(:baz, -2)
|
180
|
+
end
|
181
|
+
|
182
|
+
clazz = Class.new do
|
183
|
+
def bar(a, b=1); nil; end
|
184
|
+
def self.baz(a, b=1, c=2); nil; end
|
185
|
+
end
|
186
|
+
|
187
|
+
expect(info.satisfies?(clazz.new)).to be true
|
188
|
+
end
|
189
|
+
|
190
|
+
##NOTE: Syntax error on JRuby and Rbx
|
191
|
+
#it 'validates methods with keyword parameters' do
|
192
|
+
# info = ProtocolInfo.new(:Foo) do
|
193
|
+
# instance_method(:bar, -2)
|
194
|
+
# class_method(:baz, -3)
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# clazz = Class.new do
|
198
|
+
# def bar(a, foo: 'foo', baz: 'baz'); nil; end
|
199
|
+
# def self.baz(a, b, foo: 'foo', baz: 'baz'); nil; end
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# expect(info.satisfies?(clazz.new)).to be true
|
203
|
+
#end
|
204
|
+
|
205
|
+
it 'validates methods with variable length argument lists' do
|
206
|
+
info = ProtocolInfo.new(:Foo) do
|
207
|
+
instance_method(:bar, -2)
|
208
|
+
class_method(:baz, -3)
|
209
|
+
end
|
210
|
+
|
211
|
+
clazz = Class.new do
|
212
|
+
def bar(a, *args); nil; end
|
213
|
+
def self.baz(a, b, *args); nil; end
|
214
|
+
end
|
215
|
+
|
216
|
+
expect(info.satisfies?(clazz.new)).to be true
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'validates methods with arity -1' do
|
220
|
+
info = ProtocolInfo.new(:Foo) do
|
221
|
+
instance_method(:bar, -1)
|
222
|
+
class_method(:baz, -1)
|
223
|
+
end
|
224
|
+
|
225
|
+
clazz = Class.new do
|
226
|
+
def bar(*args); nil; end
|
227
|
+
def self.baz(*args); nil; end
|
228
|
+
end
|
229
|
+
|
230
|
+
expect(info.satisfies?(clazz.new)).to be true
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'validates instance attribute accessors' do
|
234
|
+
info = ProtocolInfo.new(:Foo) do
|
235
|
+
attr_accessor :foo
|
236
|
+
end
|
237
|
+
|
238
|
+
accessor_clazz = Class.new do
|
239
|
+
attr_accessor :foo
|
240
|
+
end
|
241
|
+
|
242
|
+
manual_clazz = Class.new do
|
243
|
+
def foo() true; end
|
244
|
+
def foo=(value) true; end
|
245
|
+
end
|
246
|
+
|
247
|
+
expect(info.satisfies?(accessor_clazz.new)).to be true
|
248
|
+
expect(info.satisfies?(manual_clazz.new)).to be true
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'validates class attribute accessors' do
|
252
|
+
info = ProtocolInfo.new(:Foo) do
|
253
|
+
class_attr_accessor :foo
|
254
|
+
end
|
255
|
+
|
256
|
+
accessor_clazz = Class.new do
|
257
|
+
class << self
|
258
|
+
attr_accessor :foo
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
manual_clazz = Class.new do
|
263
|
+
def self.foo() true; end
|
264
|
+
def self.foo=(value) true; end
|
265
|
+
end
|
266
|
+
|
267
|
+
expect(info.satisfies?(accessor_clazz.new)).to be true
|
268
|
+
expect(info.satisfies?(manual_clazz.new)).to be true
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'validates constants' do
|
272
|
+
info = ProtocolInfo.new(:Foo) do
|
273
|
+
constant :FOO
|
274
|
+
end
|
275
|
+
|
276
|
+
clazz = Class.new do
|
277
|
+
FOO = 42
|
278
|
+
end
|
279
|
+
|
280
|
+
expect(info.satisfies?(clazz.new)).to be false
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'always accepts methods when arity not given' do
|
284
|
+
info = ProtocolInfo.new(:Foo) do
|
285
|
+
instance_method(:foo)
|
286
|
+
instance_method(:bar)
|
287
|
+
instance_method(:baz)
|
288
|
+
class_method(:foo)
|
289
|
+
class_method(:bar)
|
290
|
+
class_method(:baz)
|
291
|
+
end
|
292
|
+
|
293
|
+
clazz = Class.new do
|
294
|
+
def foo(); nil; end
|
295
|
+
def bar(a, b, c); nil; end
|
296
|
+
def baz(a, b, *args); nil; end
|
297
|
+
def self.foo(); nil; end
|
298
|
+
def self.bar(a, b, c); nil; end
|
299
|
+
def self.baz(a, b, *args); nil; end
|
300
|
+
end
|
301
|
+
|
302
|
+
expect(info.satisfies?(clazz.new)).to be true
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'always accepts methods with arity -1' do
|
306
|
+
info = ProtocolInfo.new(:Foo) do
|
307
|
+
instance_method(:foo, 0)
|
308
|
+
instance_method(:bar, 2)
|
309
|
+
instance_method(:baz, -2)
|
310
|
+
class_method(:foo, 0)
|
311
|
+
class_method(:bar, -2)
|
312
|
+
class_method(:baz, 2)
|
313
|
+
end
|
314
|
+
|
315
|
+
clazz = Class.new do
|
316
|
+
def foo(*args); nil; end
|
317
|
+
def bar(*args); nil; end
|
318
|
+
def baz(*args); nil; end
|
319
|
+
def self.foo(*args); nil; end
|
320
|
+
def self.bar(*args); nil; end
|
321
|
+
def self.baz(*args); nil; end
|
322
|
+
end
|
323
|
+
|
324
|
+
expect(info.satisfies?(clazz.new)).to be true
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'returns false if one or more instance methods do not match' do
|
328
|
+
info = ProtocolInfo.new(:Foo) do
|
329
|
+
instance_method(:bar, 0)
|
330
|
+
end
|
331
|
+
|
332
|
+
clazz = Class.new do
|
333
|
+
def bar(a, b, *args); nil; end
|
334
|
+
end
|
335
|
+
|
336
|
+
expect(info.satisfies?(clazz.new)).to be false
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'returns false if one or more class methods do not match' do
|
340
|
+
info = ProtocolInfo.new(:Foo) do
|
341
|
+
class_method(:bar, 0)
|
342
|
+
end
|
343
|
+
|
344
|
+
clazz = Class.new do
|
345
|
+
def self.bar(a, b, *args); nil; end
|
346
|
+
end
|
347
|
+
|
348
|
+
expect(info.satisfies?(clazz.new)).to be false
|
349
|
+
end
|
350
|
+
|
351
|
+
it 'returns false if one or more instance attributes does not match' do
|
352
|
+
info = ProtocolInfo.new(:Foo) do
|
353
|
+
attr_accessor :foo
|
354
|
+
end
|
355
|
+
|
356
|
+
reader_clazz = Class.new do
|
357
|
+
def foo() true; end
|
358
|
+
def foo=() false; end
|
359
|
+
end
|
360
|
+
|
361
|
+
writer_clazz = Class.new do
|
362
|
+
def foo(value) false; end
|
363
|
+
def foo=(value) true; end
|
364
|
+
end
|
365
|
+
|
366
|
+
expect(info.satisfies?(reader_clazz.new)).to be false
|
367
|
+
expect(info.satisfies?(writer_clazz.new)).to be false
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'returns false if one or more class attributes does not match' do
|
371
|
+
info = ProtocolInfo.new(:Foo) do
|
372
|
+
class_attr_accessor :foo
|
373
|
+
end
|
374
|
+
|
375
|
+
reader_clazz = Class.new do
|
376
|
+
def self.foo() true; end
|
377
|
+
def self.foo=() false; end
|
378
|
+
end
|
379
|
+
|
380
|
+
writer_clazz = Class.new do
|
381
|
+
def self.foo(value) false; end
|
382
|
+
def self.foo=(value) true; end
|
383
|
+
end
|
384
|
+
|
385
|
+
expect(info.satisfies?(reader_clazz.new)).to be false
|
386
|
+
expect(info.satisfies?(writer_clazz.new)).to be false
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'returns false if one or more constants has not been defined' do
|
390
|
+
info = ProtocolInfo.new(:Foo) do
|
391
|
+
constant :FOO
|
392
|
+
end
|
393
|
+
|
394
|
+
clazz = Class.new do
|
395
|
+
BAR = 42
|
396
|
+
end
|
397
|
+
|
398
|
+
expect(info.satisfies?(clazz.new)).to be false
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'supports all specifiable characteristics on classes' do
|
402
|
+
clazz = Class.new do
|
403
|
+
attr_accessor :attr_accessor
|
404
|
+
attr_reader :attr_reader
|
405
|
+
attr_writer :attr_writer
|
406
|
+
def instance_method() 42; end
|
407
|
+
|
408
|
+
class << self
|
409
|
+
attr_accessor :class_attr_accessor
|
410
|
+
attr_reader :class_attr_reader
|
411
|
+
attr_writer :class_attr_writer
|
412
|
+
def class_method() 42; end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
clazz.const_set(:CONSTANT, 42)
|
416
|
+
|
417
|
+
expect(
|
418
|
+
kitchen_sink.satisfies?(clazz)
|
419
|
+
).to be true
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'supports all specifiable characteristics on modules' do
|
423
|
+
mod = Module.new do
|
424
|
+
attr_accessor :attr_accessor
|
425
|
+
attr_reader :attr_reader
|
426
|
+
attr_writer :attr_writer
|
427
|
+
def instance_method() 42; end
|
428
|
+
|
429
|
+
class << self
|
430
|
+
attr_accessor :class_attr_accessor
|
431
|
+
attr_reader :class_attr_reader
|
432
|
+
attr_writer :class_attr_writer
|
433
|
+
def class_method() 42; end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
mod.const_set(:CONSTANT, 42)
|
437
|
+
|
438
|
+
expect(
|
439
|
+
kitchen_sink.satisfies?(mod)
|
440
|
+
).to be true
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'protocol specification' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@protocol_info = Functional::Protocol.class_variable_get(:@@info)
|
7
|
+
Functional::Protocol.class_variable_set(:@@info, {})
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
Functional::Protocol.class_variable_set(:@@info, @protocol_info)
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'SpecifyProtocol method' do
|
15
|
+
|
16
|
+
context 'without a block' do
|
17
|
+
|
18
|
+
it 'returns the specified protocol when defined' do
|
19
|
+
Functional::SpecifyProtocol(:Foo){ nil }
|
20
|
+
expect(Functional::SpecifyProtocol(:Foo)).to_not be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns nil when not defined' do
|
24
|
+
expect(Functional::SpecifyProtocol(:Foo)).to be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with a block' do
|
29
|
+
|
30
|
+
it 'raises an exception if the protocol has already been specified' do
|
31
|
+
Functional::SpecifyProtocol(:Foo){ nil }
|
32
|
+
|
33
|
+
expect {
|
34
|
+
Functional::SpecifyProtocol(:Foo){ nil }
|
35
|
+
}.to raise_error(Functional::ProtocolError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns the specified protocol once defined' do
|
39
|
+
expect(Functional::SpecifyProtocol(:Foo){ nil }).to be_a Functional::ProtocolInfo
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe Functional::Protocol do
|
45
|
+
|
46
|
+
context 'Satisfy?' do
|
47
|
+
|
48
|
+
it 'accepts and checks multiple protocols' do
|
49
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
50
|
+
Functional::SpecifyProtocol(:bar){ instance_method(:foo) }
|
51
|
+
Functional::SpecifyProtocol(:baz){ instance_method(:foo) }
|
52
|
+
|
53
|
+
clazz = Class.new do
|
54
|
+
def foo(); nil; end
|
55
|
+
end
|
56
|
+
|
57
|
+
expect(
|
58
|
+
Functional::Protocol.Satisfy?(clazz.new, :foo, :bar, :baz)
|
59
|
+
).to be true
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns false if one or more protocols have not been defined' do
|
63
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
64
|
+
|
65
|
+
expect(
|
66
|
+
Functional::Protocol.Satisfy?('object', :foo, :bar)
|
67
|
+
).to be false
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'raises an exception if no protocols are listed' do
|
71
|
+
expect {
|
72
|
+
Functional::Protocol::Satisfy?('object')
|
73
|
+
}.to raise_error(ArgumentError)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns true on success' do
|
77
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
78
|
+
|
79
|
+
clazz = Class.new do
|
80
|
+
def foo(); nil; end
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(
|
84
|
+
Functional::Protocol.Satisfy?(clazz.new, :foo)
|
85
|
+
).to be true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns false on failure' do
|
89
|
+
Functional::SpecifyProtocol(:foo) do
|
90
|
+
instance_method(:foo, 0)
|
91
|
+
class_method(:bar, 0)
|
92
|
+
end
|
93
|
+
|
94
|
+
clazz = Class.new do
|
95
|
+
def foo(); nil; end
|
96
|
+
end
|
97
|
+
|
98
|
+
expect(
|
99
|
+
Functional::Protocol.Satisfy?('object', :foo)
|
100
|
+
).to be false
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'validates classes' do
|
104
|
+
Functional::SpecifyProtocol(:foo) do
|
105
|
+
instance_method(:foo)
|
106
|
+
class_method(:bar)
|
107
|
+
end
|
108
|
+
|
109
|
+
clazz = Class.new do
|
110
|
+
def foo(); nil; end
|
111
|
+
def self.bar(); nil; end
|
112
|
+
end
|
113
|
+
|
114
|
+
expect(
|
115
|
+
Functional::Protocol.Satisfy?(clazz, :foo)
|
116
|
+
).to be true
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'validates modules' do
|
120
|
+
Functional::SpecifyProtocol(:foo) do
|
121
|
+
instance_method(:foo)
|
122
|
+
class_method(:bar)
|
123
|
+
end
|
124
|
+
|
125
|
+
mod = Module.new do
|
126
|
+
def foo(); nil; end
|
127
|
+
def self.bar(); nil; end
|
128
|
+
end
|
129
|
+
|
130
|
+
expect(
|
131
|
+
Functional::Protocol.Satisfy?(mod, :foo)
|
132
|
+
).to be true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'Satisfy!' do
|
137
|
+
|
138
|
+
it 'accepts and checks multiple protocols' do
|
139
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
140
|
+
Functional::SpecifyProtocol(:bar){ instance_method(:foo) }
|
141
|
+
Functional::SpecifyProtocol(:baz){ instance_method(:foo) }
|
142
|
+
|
143
|
+
clazz = Class.new do
|
144
|
+
def foo(); nil; end
|
145
|
+
end
|
146
|
+
|
147
|
+
target = clazz.new
|
148
|
+
expect(
|
149
|
+
Functional::Protocol.Satisfy!(target, :foo, :bar, :baz)
|
150
|
+
).to eq target
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'raises an exception if one or more protocols have not been defined' do
|
154
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
155
|
+
|
156
|
+
expect{
|
157
|
+
Functional::Protocol.Satisfy!('object', :foo, :bar)
|
158
|
+
}.to raise_error(Functional::ProtocolError)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'raises an exception if no protocols are listed' do
|
162
|
+
expect {
|
163
|
+
Functional::Protocol::Satisfy!('object')
|
164
|
+
}.to raise_error(ArgumentError)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'returns the target on success' do
|
168
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
169
|
+
|
170
|
+
clazz = Class.new do
|
171
|
+
def foo(); nil; end
|
172
|
+
end
|
173
|
+
|
174
|
+
target = clazz.new
|
175
|
+
expect(
|
176
|
+
Functional::Protocol.Satisfy!(target, :foo)
|
177
|
+
).to eq target
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'raises an exception on failure' do
|
181
|
+
Functional::SpecifyProtocol(:foo){ instance_method(:foo) }
|
182
|
+
|
183
|
+
expect{
|
184
|
+
Functional::Protocol.Satisfy!('object', :foo)
|
185
|
+
}.to raise_error(Functional::ProtocolError)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'validates classes' do
|
189
|
+
Functional::SpecifyProtocol(:foo) do
|
190
|
+
instance_method(:foo)
|
191
|
+
class_method(:bar)
|
192
|
+
end
|
193
|
+
|
194
|
+
clazz = Class.new do
|
195
|
+
def foo(); nil; end
|
196
|
+
def self.bar(); nil; end
|
197
|
+
end
|
198
|
+
|
199
|
+
expect{
|
200
|
+
Functional::Protocol.Satisfy!(clazz, :foo)
|
201
|
+
}.to_not raise_exception
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'validates modules' do
|
205
|
+
Functional::SpecifyProtocol(:foo) do
|
206
|
+
instance_method(:foo)
|
207
|
+
class_method(:bar)
|
208
|
+
end
|
209
|
+
|
210
|
+
mod = Module.new do
|
211
|
+
def foo(); nil; end
|
212
|
+
def self.bar(); nil; end
|
213
|
+
end
|
214
|
+
|
215
|
+
expect{
|
216
|
+
Functional::Protocol.Satisfy!(mod, :foo)
|
217
|
+
}.to_not raise_exception
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'Specified?' do
|
222
|
+
|
223
|
+
it 'returns true when all protocols have been defined' do
|
224
|
+
Functional::SpecifyProtocol(:foo){ nil }
|
225
|
+
Functional::SpecifyProtocol(:bar){ nil }
|
226
|
+
Functional::SpecifyProtocol(:baz){ nil }
|
227
|
+
|
228
|
+
expect(Functional::Protocol.Specified?(:foo, :bar, :baz)).to be true
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'returns false when one or more of the protocols have not been defined' do
|
232
|
+
Functional::SpecifyProtocol(:foo){ nil }
|
233
|
+
Functional::SpecifyProtocol(:bar){ nil }
|
234
|
+
|
235
|
+
expect(Functional::Protocol.Specified?(:foo, :bar, :baz)).to be false
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'raises an exception when no protocols are given' do
|
239
|
+
expect {
|
240
|
+
Functional::Protocol.Specified?
|
241
|
+
}.to raise_error(ArgumentError)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'Specified!' do
|
246
|
+
|
247
|
+
it 'returns true when all protocols have been defined' do
|
248
|
+
Functional::SpecifyProtocol(:foo){ nil }
|
249
|
+
Functional::SpecifyProtocol(:bar){ nil }
|
250
|
+
Functional::SpecifyProtocol(:baz){ nil }
|
251
|
+
|
252
|
+
expect(Functional::Protocol.Specified!(:foo, :bar, :baz)).to be true
|
253
|
+
expect {
|
254
|
+
Functional::Protocol.Specified!(:foo, :bar, :baz)
|
255
|
+
}.to_not raise_error
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'raises an exception when one or more of the protocols have not been defined' do
|
259
|
+
Functional::SpecifyProtocol(:foo){ nil }
|
260
|
+
Functional::SpecifyProtocol(:bar){ nil }
|
261
|
+
|
262
|
+
expect {
|
263
|
+
Functional::Protocol.Specified!(:foo, :bar, :baz)
|
264
|
+
}.to raise_error(Functional::ProtocolError)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'raises an exception when no protocols are given' do
|
268
|
+
expect {
|
269
|
+
Functional::Protocol.Specified!
|
270
|
+
}.to raise_error(ArgumentError)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|