functional-ruby 0.7.2 → 0.7.3

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/md/utilities.md CHANGED
@@ -1,55 +1,55 @@
1
- # Utility Functions
2
-
3
- Convenience functions are not imported by default. They need a separate `require` statement:
4
-
5
- ```ruby
6
- require 'functional/utilities'
7
- ```
8
-
9
- This gives you access to a few constants and functions:
10
-
11
- ```ruby
12
- Infinity #=> Infinity
13
- NaN #=> NaN
14
-
15
- repl? #=> true when called under irb, pry, bundle console, or rails console
16
-
17
- safe(1, 2){|a, b| a + b} #=> 3
18
- safe{ eval 'puts "Hello World!"' } #=> SecurityError: Insecure operation
19
-
20
- pp_s [1,2,3,4] #=> "[1, 2, 3, 4]\n" props to Rha7
21
-
22
- delta(-1, 1) #=> 2
23
- delta({count: -1}, {count: 1}){|item| item[:count]} #=> 2
24
-
25
- repeatedly(10, 1){|previous| previous * 2 } #=> [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
26
- ```
27
-
28
- ## Copyright
29
-
30
- *Functional Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
31
- It is free software and may be redistributed under the terms specified in the LICENSE file.
32
-
33
- ## License
34
-
35
- Released under the MIT license.
36
-
37
- http://www.opensource.org/licenses/mit-license.php
38
-
39
- > Permission is hereby granted, free of charge, to any person obtaining a copy
40
- > of this software and associated documentation files (the "Software"), to deal
41
- > in the Software without restriction, including without limitation the rights
42
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
- > copies of the Software, and to permit persons to whom the Software is
44
- > furnished to do so, subject to the following conditions:
45
- >
46
- > The above copyright notice and this permission notice shall be included in
47
- > all copies or substantial portions of the Software.
48
- >
49
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55
- > THE SOFTWARE.
1
+ # Utility Functions
2
+
3
+ Convenience functions are not imported by default. They need a separate `require` statement:
4
+
5
+ ```ruby
6
+ require 'functional/utilities'
7
+ ```
8
+
9
+ This gives you access to a few constants and functions:
10
+
11
+ ```ruby
12
+ Infinity #=> Infinity
13
+ NaN #=> NaN
14
+
15
+ repl? #=> true when called under irb, pry, bundle console, or rails console
16
+
17
+ safe(1, 2){|a, b| a + b} #=> 3
18
+ safe{ eval 'puts "Hello World!"' } #=> SecurityError: Insecure operation
19
+
20
+ pp_s [1,2,3,4] #=> "[1, 2, 3, 4]\n" props to Rha7
21
+
22
+ delta(-1, 1) #=> 2
23
+ delta({count: -1}, {count: 1}){|item| item[:count]} #=> 2
24
+
25
+ repeatedly(10, 1){|previous| previous * 2 } #=> [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
26
+ ```
27
+
28
+ ## Copyright
29
+
30
+ *Functional Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
31
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
32
+
33
+ ## License
34
+
35
+ Released under the MIT license.
36
+
37
+ http://www.opensource.org/licenses/mit-license.php
38
+
39
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
40
+ > of this software and associated documentation files (the "Software"), to deal
41
+ > in the Software without restriction, including without limitation the rights
42
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
+ > copies of the Software, and to permit persons to whom the Software is
44
+ > furnished to do so, subject to the following conditions:
45
+ >
46
+ > The above copyright notice and this permission notice shall be included in
47
+ > all copies or substantial portions of the Software.
48
+ >
49
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55
+ > THE SOFTWARE.
@@ -1,464 +1,508 @@
1
- require 'spec_helper'
2
-
3
- describe '-behavior' do
4
-
5
- before(:each) do
6
- @__behavior_info__ = $__behavior_info__
7
- $__behavior_info__ = {}
8
- end
9
-
10
- after(:each) do
11
- $__behavior_info__ = @__behavior_info__
12
- end
13
-
14
- context 'behavior_info/2' do
15
-
16
- it 'accepts a symbol name' do
17
- behavior_info(:gen_foo, foo: 0)
18
- $__behavior_info__.keys.first.should eq :gen_foo
19
- end
20
-
21
- it 'accepts a string name' do
22
- behavior_info('gen_foo', foo: 0)
23
- $__behavior_info__.keys.first.should eq :gen_foo
24
- end
25
-
26
- it 'accepts zero function names' do
27
- behavior_info(:gen_foo)
28
- $__behavior_info__.keys.first.should eq :gen_foo
29
- end
30
-
31
- it 'accepts symbols for function names' do
32
- behavior_info(:gen_foo, foo: 0)
33
- $__behavior_info__.values.first.should == {foo: 0}
34
- end
35
-
36
- it 'accepts strings as function names' do
37
- behavior_info(:gen_foo, 'foo' => 0)
38
- $__behavior_info__.values.first.should == {foo: 0}
39
- end
40
-
41
- it 'accepts numeric arity values' do
42
- behavior_info(:gen_foo, foo: 0)
43
- $__behavior_info__.values.first.should == {foo: 0}
44
- end
45
-
46
- it 'accepts :any as an arity value' do
47
- behavior_info(:gen_foo, foo: :any)
48
- $__behavior_info__.values.first.should == {foo: :any}
49
- end
50
- end
51
-
52
- context 'behavior/1' do
53
-
54
- it 'raises an exception if the behavior has not been defined' do
55
- lambda {
56
- Class.new{
57
- behavior(:gen_foo)
58
- }
59
- }.should raise_error(BehaviorError)
60
- end
61
-
62
- it 'can be called multiple times for one class' do
63
- behavior_info(:gen_foo, foo: 0)
64
- behavior_info(:gen_bar, bar: 0)
65
-
66
- lambda {
67
- Class.new{
68
- behavior(:gen_foo)
69
- behavior(:gen_bar)
70
- }
71
- }.should_not raise_error
72
- end
73
- end
74
-
75
- context 'object creation' do
76
-
77
- it 'checks all required behaviors' do
78
- behavior_info(:gen_foo, foo: 0)
79
- behavior_info(:gen_bar, bar: 1)
80
-
81
- clazz = Class.new {
82
- behavior(:gen_foo)
83
- behavior(:gen_bar)
84
- def foo() nil; end
85
- }
86
- lambda{ clazz.new }.should raise_error(BehaviorError)
87
-
88
- clazz = Class.new {
89
- behavior(:gen_foo)
90
- behavior(:gen_bar)
91
- def bar() nil; end
92
- }
93
- lambda{ clazz.new }.should raise_error(BehaviorError)
94
-
95
- clazz = Class.new {
96
- behavior(:gen_foo)
97
- behavior(:gen_bar)
98
- }
99
- lambda{ clazz.new }.should raise_error(BehaviorError)
100
- end
101
-
102
- context 'instance methods' do
103
-
104
- it 'raises an exception when one or more function definitions are missing' do
105
- behavior_info(:gen_foo, foo: 0, bar: 1)
106
- clazz = Class.new {
107
- behavior(:gen_foo)
108
- def foo() nil; end
109
- }
110
-
111
- lambda {
112
- clazz.new
113
- }.should raise_error(BehaviorError)
114
- end
115
-
116
- it 'raises an exception when one or more functions do not have proper arity' do
117
- behavior_info(:gen_foo, foo: 0)
118
- clazz = Class.new {
119
- behavior(:gen_foo)
120
- def foo(broken) nil; end
121
- }
122
-
123
- lambda {
124
- clazz.new
125
- }.should raise_error(BehaviorError)
126
- end
127
-
128
- it 'accepts any arity when function arity is set to :any' do
129
- behavior_info(:gen_foo, foo: :any)
130
- clazz = Class.new {
131
- behavior(:gen_foo)
132
- def foo(first) nil; end
133
- }
134
-
135
- lambda {
136
- clazz.new
137
- }.should_not raise_error
138
- end
139
-
140
- it 'creates the object when function definitions match' do
141
- behavior_info(:gen_foo, foo: 0, bar: 1)
142
- clazz = Class.new {
143
- behavior(:gen_foo)
144
- def foo() nil; end
145
- def bar(first) nil; end
146
- }
147
-
148
- lambda {
149
- clazz.new
150
- }.should_not raise_error
151
- end
152
- end
153
-
154
- context 'class methods' do
155
-
156
- it 'raises an exception when one or more function definitions are missing' do
157
- behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
158
- clazz = Class.new {
159
- behavior(:gen_foo)
160
- def self.foo() nil; end
161
- }
162
-
163
- lambda {
164
- clazz.new
165
- }.should raise_error(BehaviorError)
166
- end
167
-
168
- it 'raises an exception when one or more functions do not have proper arity' do
169
- behavior_info(:gen_foo, self_foo: 0)
170
- clazz = Class.new {
171
- behavior(:gen_foo)
172
- def self.foo(broken) nil; end
173
- }
174
-
175
- lambda {
176
- clazz.new
177
- }.should raise_error(BehaviorError)
178
- end
179
-
180
- it 'accepts any arity when function arity is set to :any' do
181
- behavior_info(:gen_foo, self_foo: :any)
182
- clazz = Class.new {
183
- behavior(:gen_foo)
184
- def self.foo(first) nil; end
185
- }
186
-
187
- lambda {
188
- clazz.new
189
- }.should_not raise_error
190
- end
191
-
192
- it 'creates the object when function definitions match' do
193
- behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
194
- clazz = Class.new {
195
- behavior(:gen_foo)
196
- def self.foo() nil; end
197
- def self.bar(first) nil; end
198
- }
199
-
200
- lambda {
201
- clazz.new
202
- }.should_not raise_error
203
- end
204
- end
205
-
206
- context 'inheritance' do
207
-
208
- it 'raises an exception if a superclass includes a behavior the subclass does not support' do
209
- behavior_info(:gen_foo, foo: 0)
210
- superclass = Class.new{
211
- behavior(:gen_foo)
212
- }
213
- subclass = Class.new(superclass)
214
-
215
- lambda {
216
- subclass.new
217
- }.should raise_error(BehaviorError)
218
- end
219
-
220
- it 'raises an exception if a module includes a behavior the containing class does not support' do
221
- behavior_info(:gen_foo, foo: 0)
222
- mod = Module.new{
223
- behavior(:gen_foo)
224
- }
225
- subclass = Class.new{
226
- include mod
227
- }
228
-
229
- lambda {
230
- subclass.new
231
- }.should raise_error(BehaviorError)
232
- end
233
-
234
- it 'supports behaviors from multiple ancestors' do
235
- behavior_info(:gen_foo, foo: 0)
236
- behavior_info(:gen_bar, bar: 0)
237
- behavior_info(:gen_baz, baz: 0)
238
-
239
- rootclass = Class.new{ behavior(:gen_foo) }
240
- superclass = Class.new(rootclass){ behavior(:gen_bar) }
241
-
242
- subclass = Class.new(superclass){
243
- behavior(:gen_baz)
244
- def bar() nil; end
245
- def baz() nil; end
246
- }
247
- lambda {
248
- subclass.new
249
- }.should raise_error(BehaviorError)
250
-
251
- subclass = Class.new(superclass){
252
- behavior(:gen_baz)
253
- def foo() nil; end
254
- def baz() nil; end
255
- }
256
- lambda {
257
- subclass.new
258
- }.should raise_error(BehaviorError)
259
-
260
- subclass = Class.new(superclass){
261
- behavior(:gen_baz)
262
- def foo() nil; end
263
- def bar() nil; end
264
- }
265
- lambda {
266
- subclass.new
267
- }.should raise_error(BehaviorError)
268
-
269
- subclass = Class.new(superclass){
270
- behavior(:gen_baz)
271
- def foo() nil; end
272
- def bar() nil; end
273
- def baz() nil; end
274
- }
275
- lambda {
276
- subclass.new
277
- }.should_not raise_error
278
- end
279
-
280
- it 'supports multiple behaviors in an included module' do
281
- behavior_info(:gen_foo, foo: 0)
282
- behavior_info(:gen_bar, bar: 0)
283
- behavior_info(:gen_baz, baz: 0)
284
-
285
- mod = Module.new{
286
- behavior(:gen_foo)
287
- behavior(:gen_bar)
288
- behavior(:gen_baz)
289
- }
290
-
291
- subclass = Class.new{
292
- include mod
293
- def bar() nil; end
294
- def baz() nil; end
295
- }
296
- lambda {
297
- subclass.new
298
- }.should raise_error(BehaviorError)
299
-
300
- subclass = Class.new{
301
- include mod
302
- def foo() nil; end
303
- def baz() nil; end
304
- }
305
- lambda {
306
- subclass.new
307
- }.should raise_error(BehaviorError)
308
-
309
- subclass = Class.new{
310
- include mod
311
- def foo() nil; end
312
- def bar() nil; end
313
- }
314
- lambda {
315
- subclass.new
316
- }.should raise_error(BehaviorError)
317
-
318
- subclass = Class.new{
319
- include mod
320
- def foo() nil; end
321
- def bar() nil; end
322
- def baz() nil; end
323
- }
324
- lambda {
325
- subclass.new
326
- }.should_not raise_error
327
- end
328
- end
329
- end
330
-
331
- context '#behaves_as?' do
332
-
333
- it 'returns false when the behavior does not exist' do
334
- clazz = Class.new { }
335
- clazz.new.behaves_as?(:gen_foo).should be_false
336
- end
337
-
338
- it 'accepts behavior name as a symbol' do
339
- behavior_info(:gen_foo)
340
- clazz = Class.new { }
341
- clazz.new.behaves_as?(:gen_foo).should be_true
342
- end
343
-
344
- it 'accepts behavior name as a string' do
345
- behavior_info(:gen_foo)
346
- clazz = Class.new { }
347
- clazz.new.behaves_as?('gen_foo').should be_true
348
- end
349
-
350
- context 'Object' do
351
-
352
- it 'returns true when the behavior is fully suported' do
353
- behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
354
- clazz = Class.new {
355
- def foo() nil; end
356
- def bar(first) nil; end
357
- def baz(first, second) nil; end
358
- }
359
-
360
- clazz.new.behaves_as?(:gen_foo).should be_true
361
- end
362
-
363
- it 'accepts any arity when function arity is set to :any' do
364
- behavior_info(:gen_foo, foo: :any)
365
- clazz = Class.new {
366
- def foo(*args, &block) nil; end
367
- }
368
-
369
- clazz.new.behaves_as?(:gen_foo).should be_true
370
- end
371
-
372
- it 'returns false when the behavior is partially supported' do
373
- behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
374
- clazz = Class.new {
375
- def foo() nil; end
376
- def bar(first) nil; end
377
- }
378
-
379
- clazz.new.behaves_as?(:gen_foo).should be_false
380
- end
381
-
382
- it 'returns false when the behavior is not supported at all' do
383
- behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
384
- clazz = Class.new { }
385
- clazz.new.behaves_as?(:gen_foo).should be_false
386
- end
387
- end
388
-
389
- context 'Class' do
390
-
391
- it 'returns true when the behavior is fully suported' do
392
- behavior_info(:gen_foo, self_foo: 0, self_bar: 1, baz: 2)
393
- clazz = Class.new {
394
- def self.foo() nil; end
395
- def self.bar(first) nil; end
396
- def baz(first, second) nil; end
397
- }
398
-
399
- clazz.behaves_as?(:gen_foo).should be_true
400
- clazz.new.behaves_as?(:gen_foo).should be_true
401
- end
402
-
403
- it 'accepts any arity when function arity is set to :any' do
404
- behavior_info(:gen_foo, self_foo: :any)
405
- clazz = Class.new {
406
- def self.foo(*args, &block) nil; end
407
- }
408
-
409
- clazz.behaves_as?(:gen_foo).should be_true
410
- clazz.new.behaves_as?(:gen_foo).should be_true
411
- end
412
-
413
- it 'returns false when the behavior is partially supported' do
414
- behavior_info(:gen_foo, self_foo: 0, bar: 1, self_baz: 2)
415
- clazz = Class.new {
416
- def self.foo() nil; end
417
- def self(first) nil; end
418
- }
419
-
420
- clazz.behaves_as?(:gen_foo).should be_false
421
- clazz.new.behaves_as?(:gen_foo).should be_false
422
- end
423
-
424
- it 'returns false when the behavior is not supported at all' do
425
- behavior_info(:gen_foo, self_foo: 0, self_bar: 1, self_baz: 2)
426
- clazz = Class.new { }
427
- clazz.new.behaves_as?(:gen_foo).should be_false
428
- end
429
- end
430
- end
431
-
432
- context 'aliases' do
433
-
434
- it 'aliases behaviour_info for behavior_info' do
435
- behaviour_info(:gen_foo)
436
- clazz = Class.new { }
437
- clazz.new.behaves_as?(:gen_foo).should be_true
438
- end
439
-
440
- it 'aliases interface for behavior_info' do
441
- interface(:gen_foo)
442
- clazz = Class.new { }
443
- clazz.new.behaves_as?(:gen_foo).should be_true
444
- end
445
-
446
- it 'aliases behaviour for behavior' do
447
- behavior_info(:gen_foo, foo: 0)
448
- clazz = Class.new {
449
- behaviour(:gen_foo)
450
- def foo() nil; end
451
- }
452
- clazz.new.behaves_as?(:gen_foo).should be_true
453
- end
454
-
455
- it 'aliases behaves_as for behavior' do
456
- behavior_info(:gen_foo, foo: 0)
457
- clazz = Class.new {
458
- behaves_as :gen_foo
459
- def foo() nil; end
460
- }
461
- clazz.new.behaves_as?(:gen_foo).should be_true
462
- end
463
- end
464
- end
1
+ require 'spec_helper'
2
+
3
+ describe '-behavior' do
4
+
5
+ before(:each) do
6
+ @__behavior_info__ = $__behavior_info__
7
+ $__behavior_info__ = {}
8
+ end
9
+
10
+ after(:each) do
11
+ $__behavior_info__ = @__behavior_info__
12
+ end
13
+
14
+ context 'behavior_info/2' do
15
+
16
+ it 'accepts a symbol name' do
17
+ behavior_info(:gen_foo, foo: 0)
18
+ $__behavior_info__.keys.first.should eq :gen_foo
19
+ end
20
+
21
+ it 'accepts a string name' do
22
+ behavior_info('gen_foo', foo: 0)
23
+ $__behavior_info__.keys.first.should eq :gen_foo
24
+ end
25
+
26
+ it 'accepts zero function names' do
27
+ behavior_info(:gen_foo)
28
+ $__behavior_info__.keys.first.should eq :gen_foo
29
+ end
30
+
31
+ it 'accepts symbols for function names' do
32
+ behavior_info(:gen_foo, foo: 0)
33
+ $__behavior_info__.values.first.should == {foo: 0}
34
+ end
35
+
36
+ it 'accepts strings as function names' do
37
+ behavior_info(:gen_foo, 'foo' => 0)
38
+ $__behavior_info__.values.first.should == {foo: 0}
39
+ end
40
+
41
+ it 'accepts numeric arity values' do
42
+ behavior_info(:gen_foo, foo: 0)
43
+ $__behavior_info__.values.first.should == {foo: 0}
44
+ end
45
+
46
+ it 'accepts :any as an arity value' do
47
+ behavior_info(:gen_foo, foo: :any)
48
+ $__behavior_info__.values.first.should == {foo: :any}
49
+ end
50
+ end
51
+
52
+ context 'behavior/1' do
53
+
54
+ it 'raises an exception if the behavior has not been defined' do
55
+ lambda {
56
+ Class.new{
57
+ behavior(:gen_foo)
58
+ }
59
+ }.should raise_error(BehaviorError)
60
+ end
61
+
62
+ it 'can be called multiple times for one class' do
63
+ behavior_info(:gen_foo, foo: 0)
64
+ behavior_info(:gen_bar, bar: 0)
65
+
66
+ lambda {
67
+ Class.new{
68
+ behavior(:gen_foo)
69
+ behavior(:gen_bar)
70
+ }
71
+ }.should_not raise_error
72
+ end
73
+ end
74
+
75
+ context 'object creation' do
76
+
77
+ it 'checks all required behaviors' do
78
+ behavior_info(:gen_foo, foo: 0)
79
+ behavior_info(:gen_bar, bar: 1)
80
+
81
+ clazz = Class.new {
82
+ behavior(:gen_foo)
83
+ behavior(:gen_bar)
84
+ def foo() nil; end
85
+ }
86
+ lambda{ clazz.new }.should raise_error(BehaviorError)
87
+
88
+ clazz = Class.new {
89
+ behavior(:gen_foo)
90
+ behavior(:gen_bar)
91
+ def bar() nil; end
92
+ }
93
+ lambda{ clazz.new }.should raise_error(BehaviorError)
94
+
95
+ clazz = Class.new {
96
+ behavior(:gen_foo)
97
+ behavior(:gen_bar)
98
+ }
99
+ lambda{ clazz.new }.should raise_error(BehaviorError)
100
+ end
101
+
102
+ context 'instance methods' do
103
+
104
+ it 'raises an exception when one or more function definitions are missing' do
105
+ behavior_info(:gen_foo, foo: 0, bar: 1)
106
+ clazz = Class.new {
107
+ behavior(:gen_foo)
108
+ def foo() nil; end
109
+ }
110
+
111
+ lambda {
112
+ clazz.new
113
+ }.should raise_error(BehaviorError)
114
+ end
115
+
116
+ it 'raises an exception when one or more functions do not have proper arity' do
117
+ behavior_info(:gen_foo, foo: 0)
118
+ clazz = Class.new {
119
+ behavior(:gen_foo)
120
+ def foo(broken) nil; end
121
+ }
122
+
123
+ lambda {
124
+ clazz.new
125
+ }.should raise_error(BehaviorError)
126
+ end
127
+
128
+ it 'accepts any arity when function arity is set to :any' do
129
+ behavior_info(:gen_foo, foo: :any)
130
+ clazz = Class.new {
131
+ behavior(:gen_foo)
132
+ def foo(first) nil; end
133
+ }
134
+
135
+ lambda {
136
+ clazz.new
137
+ }.should_not raise_error
138
+ end
139
+
140
+ it 'creates the object when function definitions match' do
141
+ behavior_info(:gen_foo, foo: 0, bar: 1)
142
+ clazz = Class.new {
143
+ behavior(:gen_foo)
144
+ def foo() nil; end
145
+ def bar(first) nil; end
146
+ }
147
+
148
+ lambda {
149
+ clazz.new
150
+ }.should_not raise_error
151
+ end
152
+ end
153
+
154
+ context 'class methods' do
155
+
156
+ it 'raises an exception when one or more function definitions are missing' do
157
+ behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
158
+ clazz = Class.new {
159
+ behavior(:gen_foo)
160
+ def self.foo() nil; end
161
+ }
162
+
163
+ lambda {
164
+ clazz.new
165
+ }.should raise_error(BehaviorError)
166
+ end
167
+
168
+ it 'raises an exception when one or more functions do not have proper arity' do
169
+ behavior_info(:gen_foo, self_foo: 0)
170
+ clazz = Class.new {
171
+ behavior(:gen_foo)
172
+ def self.foo(broken) nil; end
173
+ }
174
+
175
+ lambda {
176
+ clazz.new
177
+ }.should raise_error(BehaviorError)
178
+ end
179
+
180
+ it 'accepts any arity when function arity is set to :any' do
181
+ behavior_info(:gen_foo, self_foo: :any)
182
+ clazz = Class.new {
183
+ behavior(:gen_foo)
184
+ def self.foo(first) nil; end
185
+ }
186
+
187
+ lambda {
188
+ clazz.new
189
+ }.should_not raise_error
190
+ end
191
+
192
+ it 'creates the object when function definitions match' do
193
+ behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
194
+ clazz = Class.new {
195
+ behavior(:gen_foo)
196
+ def self.foo() nil; end
197
+ def self.bar(first) nil; end
198
+ }
199
+
200
+ lambda {
201
+ clazz.new
202
+ }.should_not raise_error
203
+ end
204
+ end
205
+
206
+ context 'inheritance' do
207
+
208
+ it 'raises an exception if a superclass includes a behavior the subclass does not support' do
209
+ behavior_info(:gen_foo, foo: 0)
210
+ superclass = Class.new{
211
+ behavior(:gen_foo)
212
+ }
213
+ subclass = Class.new(superclass)
214
+
215
+ lambda {
216
+ subclass.new
217
+ }.should raise_error(BehaviorError)
218
+ end
219
+
220
+ it 'raises an exception if a module includes a behavior the containing class does not support' do
221
+ behavior_info(:gen_foo, foo: 0)
222
+ mod = Module.new{
223
+ behavior(:gen_foo)
224
+ }
225
+ subclass = Class.new{
226
+ include mod
227
+ }
228
+
229
+ lambda {
230
+ subclass.new
231
+ }.should raise_error(BehaviorError)
232
+ end
233
+
234
+ it 'supports behaviors from multiple ancestors' do
235
+ behavior_info(:gen_foo, foo: 0)
236
+ behavior_info(:gen_bar, bar: 0)
237
+ behavior_info(:gen_baz, baz: 0)
238
+
239
+ rootclass = Class.new{ behavior(:gen_foo) }
240
+ superclass = Class.new(rootclass){ behavior(:gen_bar) }
241
+
242
+ subclass = Class.new(superclass){
243
+ behavior(:gen_baz)
244
+ def bar() nil; end
245
+ def baz() nil; end
246
+ }
247
+ lambda {
248
+ subclass.new
249
+ }.should raise_error(BehaviorError)
250
+
251
+ subclass = Class.new(superclass){
252
+ behavior(:gen_baz)
253
+ def foo() nil; end
254
+ def baz() nil; end
255
+ }
256
+ lambda {
257
+ subclass.new
258
+ }.should raise_error(BehaviorError)
259
+
260
+ subclass = Class.new(superclass){
261
+ behavior(:gen_baz)
262
+ def foo() nil; end
263
+ def bar() nil; end
264
+ }
265
+ lambda {
266
+ subclass.new
267
+ }.should raise_error(BehaviorError)
268
+
269
+ subclass = Class.new(superclass){
270
+ behavior(:gen_baz)
271
+ def foo() nil; end
272
+ def bar() nil; end
273
+ def baz() nil; end
274
+ }
275
+ lambda {
276
+ subclass.new
277
+ }.should_not raise_error
278
+ end
279
+
280
+ it 'supports multiple behaviors in an included module' do
281
+ behavior_info(:gen_foo, foo: 0)
282
+ behavior_info(:gen_bar, bar: 0)
283
+ behavior_info(:gen_baz, baz: 0)
284
+
285
+ mod = Module.new{
286
+ behavior(:gen_foo)
287
+ behavior(:gen_bar)
288
+ behavior(:gen_baz)
289
+ }
290
+
291
+ subclass = Class.new{
292
+ include mod
293
+ def bar() nil; end
294
+ def baz() nil; end
295
+ }
296
+ lambda {
297
+ subclass.new
298
+ }.should raise_error(BehaviorError)
299
+
300
+ subclass = Class.new{
301
+ include mod
302
+ def foo() nil; end
303
+ def baz() nil; end
304
+ }
305
+ lambda {
306
+ subclass.new
307
+ }.should raise_error(BehaviorError)
308
+
309
+ subclass = Class.new{
310
+ include mod
311
+ def foo() nil; end
312
+ def bar() nil; end
313
+ }
314
+ lambda {
315
+ subclass.new
316
+ }.should raise_error(BehaviorError)
317
+
318
+ subclass = Class.new{
319
+ include mod
320
+ def foo() nil; end
321
+ def bar() nil; end
322
+ def baz() nil; end
323
+ }
324
+ lambda {
325
+ subclass.new
326
+ }.should_not raise_error
327
+ end
328
+ end
329
+ end
330
+
331
+ context '#behaves_as?' do
332
+
333
+ it 'returns false when the behavior does not exist' do
334
+ clazz = Class.new { }
335
+ clazz.new.behaves_as?(:gen_foo).should be_false
336
+ end
337
+
338
+ it 'accepts behavior name as a symbol' do
339
+ behavior_info(:gen_foo)
340
+ clazz = Class.new { }
341
+ clazz.new.behaves_as?(:gen_foo).should be_true
342
+ end
343
+
344
+ it 'accepts behavior name as a string' do
345
+ behavior_info(:gen_foo)
346
+ clazz = Class.new { }
347
+ clazz.new.behaves_as?('gen_foo').should be_true
348
+ end
349
+
350
+ context 'Object' do
351
+
352
+ it 'returns true when the behavior is fully suported' do
353
+ behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
354
+ clazz = Class.new {
355
+ def foo() nil; end
356
+ def bar(first) nil; end
357
+ def baz(first, second) nil; end
358
+ }
359
+
360
+ clazz.new.behaves_as?(:gen_foo).should be_true
361
+ end
362
+
363
+ it 'accepts any arity when function arity is set to :any' do
364
+ behavior_info(:gen_foo, foo: :any)
365
+ clazz = Class.new {
366
+ def foo(*args, &block) nil; end
367
+ }
368
+
369
+ clazz.new.behaves_as?(:gen_foo).should be_true
370
+ end
371
+
372
+ it 'returns false when the behavior is partially supported' do
373
+ behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
374
+ clazz = Class.new {
375
+ def foo() nil; end
376
+ def bar(first) nil; end
377
+ }
378
+
379
+ clazz.new.behaves_as?(:gen_foo).should be_false
380
+ end
381
+
382
+ it 'returns false when the behavior is not supported at all' do
383
+ behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
384
+ clazz = Class.new { }
385
+ clazz.new.behaves_as?(:gen_foo).should be_false
386
+ end
387
+
388
+ it 'raises an exception on failure when abend is true' do
389
+ behavior_info(:gen_foo, foo: 0)
390
+ behavior_info(:gen_bar, self_bar: 1)
391
+ behavior_info(:gen_baz, baz: :any)
392
+ clazz = Class.new { }
393
+
394
+ lambda {
395
+ clazz.new.behaves_as?(:gen_foo, true)
396
+ }.should raise_error(BehaviorError)
397
+
398
+ lambda {
399
+ clazz.new.behaves_as?(:gen_bar, true)
400
+ }.should raise_error(BehaviorError)
401
+
402
+ lambda {
403
+ clazz.new.behaves_as?(:gen_baz, true)
404
+ }.should raise_error(BehaviorError)
405
+ end
406
+
407
+ it 'exception includes the name and arity of the first missing function' do
408
+ behavior_info(:gen_foo, foo: 0)
409
+ behavior_info(:gen_bar, self_bar: 1)
410
+ behavior_info(:gen_baz, baz: :any)
411
+ clazz = Class.new { }
412
+
413
+ begin
414
+ clazz.new.behaves_as?(:gen_foo, true)
415
+ rescue BehaviorError => ex
416
+ ex.message.should =~ /foo\/0/
417
+ end
418
+
419
+ begin
420
+ clazz.new.behaves_as?(:gen_bar, true)
421
+ rescue BehaviorError => ex
422
+ ex.message.should =~ /#self\.bar\/1/
423
+ end
424
+
425
+ begin
426
+ clazz.new.behaves_as?(:gen_baz, true)
427
+ rescue BehaviorError => ex
428
+ ex.message.should =~ /#baz\/:any/
429
+ end
430
+ end
431
+ end
432
+
433
+ context 'Class' do
434
+
435
+ it 'returns true when the behavior is fully suported' do
436
+ behavior_info(:gen_foo, self_foo: 0, self_bar: 1, baz: 2)
437
+ clazz = Class.new {
438
+ def self.foo() nil; end
439
+ def self.bar(first) nil; end
440
+ def baz(first, second) nil; end
441
+ }
442
+
443
+ clazz.behaves_as?(:gen_foo).should be_true
444
+ clazz.new.behaves_as?(:gen_foo).should be_true
445
+ end
446
+
447
+ it 'accepts any arity when function arity is set to :any' do
448
+ behavior_info(:gen_foo, self_foo: :any)
449
+ clazz = Class.new {
450
+ def self.foo(*args, &block) nil; end
451
+ }
452
+
453
+ clazz.behaves_as?(:gen_foo).should be_true
454
+ clazz.new.behaves_as?(:gen_foo).should be_true
455
+ end
456
+
457
+ it 'returns false when the behavior is partially supported' do
458
+ behavior_info(:gen_foo, self_foo: 0, bar: 1, self_baz: 2)
459
+ clazz = Class.new {
460
+ def self.foo() nil; end
461
+ def self(first) nil; end
462
+ }
463
+
464
+ clazz.behaves_as?(:gen_foo).should be_false
465
+ clazz.new.behaves_as?(:gen_foo).should be_false
466
+ end
467
+
468
+ it 'returns false when the behavior is not supported at all' do
469
+ behavior_info(:gen_foo, self_foo: 0, self_bar: 1, self_baz: 2)
470
+ clazz = Class.new { }
471
+ clazz.new.behaves_as?(:gen_foo).should be_false
472
+ end
473
+ end
474
+ end
475
+
476
+ context 'aliases' do
477
+
478
+ it 'aliases behaviour_info for behavior_info' do
479
+ behaviour_info(:gen_foo)
480
+ clazz = Class.new { }
481
+ clazz.new.behaves_as?(:gen_foo).should be_true
482
+ end
483
+
484
+ it 'aliases interface for behavior_info' do
485
+ interface(:gen_foo)
486
+ clazz = Class.new { }
487
+ clazz.new.behaves_as?(:gen_foo).should be_true
488
+ end
489
+
490
+ it 'aliases behaviour for behavior' do
491
+ behavior_info(:gen_foo, foo: 0)
492
+ clazz = Class.new {
493
+ behaviour(:gen_foo)
494
+ def foo() nil; end
495
+ }
496
+ clazz.new.behaves_as?(:gen_foo).should be_true
497
+ end
498
+
499
+ it 'aliases behaves_as for behavior' do
500
+ behavior_info(:gen_foo, foo: 0)
501
+ clazz = Class.new {
502
+ behaves_as :gen_foo
503
+ def foo() nil; end
504
+ }
505
+ clazz.new.behaves_as?(:gen_foo).should be_true
506
+ end
507
+ end
508
+ end