functional-ruby 0.7.1 → 0.7.2
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/LICENSE +21 -21
- data/README.md +193 -193
- data/lib/functional.rb +4 -4
- data/lib/functional/behavior.rb +132 -124
- data/lib/functional/behaviour.rb +2 -2
- data/lib/functional/pattern_matching.rb +133 -133
- data/lib/functional/utilities.rb +192 -192
- data/lib/functional/version.rb +3 -3
- data/lib/functional_ruby.rb +1 -1
- data/md/behavior.md +188 -188
- data/md/pattern_matching.md +512 -512
- data/md/utilities.md +55 -55
- data/spec/functional/behavior_spec.rb +464 -369
- data/spec/functional/integration_spec.rb +205 -205
- data/spec/functional/pattern_matching_spec.rb +418 -418
- data/spec/functional/utilities_spec.rb +271 -271
- data/spec/spec_helper.rb +18 -18
- metadata +20 -21
- checksums.yaml +0 -7
@@ -1,271 +1,271 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'fakefs/safe'
|
3
|
-
require 'rbconfig'
|
4
|
-
|
5
|
-
describe 'utilities' do
|
6
|
-
|
7
|
-
context '#delta' do
|
8
|
-
|
9
|
-
it 'computes the delta of two positive values' do
|
10
|
-
delta(10.5, 5.0).should be_within(0.01).of(5.5)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'computes the delta of two negative values' do
|
14
|
-
delta(-10.5, -5.0).should be_within(0.01).of(5.5)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'computes the delta of a positive and negative value' do
|
18
|
-
delta(10.5, -5.0).should be_within(0.01).of(15.5)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'computes the delta of two positive values with a block' do
|
22
|
-
v1 = {:count => 10.5}
|
23
|
-
v2 = {:count => 5.0}
|
24
|
-
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'computes the delta of two negative values with a block' do
|
28
|
-
v1 = {:count => -10.5}
|
29
|
-
v2 = {:count => -5.0}
|
30
|
-
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'computes the delta of a positive and negative value with a block' do
|
34
|
-
v1 = {:count => 10.5}
|
35
|
-
v2 = {:count => -5.0}
|
36
|
-
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(15.5)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context '#repeatedly' do
|
41
|
-
|
42
|
-
it 'returns an empty array when requested times is zero' do
|
43
|
-
expected = repeatedly(0){ 1 }
|
44
|
-
expected.should be_empty
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'returns an array with all nil values when no block is given' do
|
48
|
-
expected = repeatedly(10)
|
49
|
-
expected.length.should eq 10
|
50
|
-
expected.each do |elem|
|
51
|
-
elem.should be_nil
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'iterates the requested number of times and puts the results into an array' do
|
56
|
-
expected = repeatedly(10){ 5 }
|
57
|
-
expected.length.should eq 10
|
58
|
-
expected.each do |elem|
|
59
|
-
elem.should eq 5
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'passes the initial value to the first iteration' do
|
64
|
-
@expected = nil
|
65
|
-
repeatedly(1,100){|previous| @expected = previous }
|
66
|
-
@expected.should eq 100
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'passes the result of each iteration to the next iteration' do
|
70
|
-
expected = repeatedly(10, 1){|previous| previous * 2 }
|
71
|
-
expected.should eq [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
context '#retro' do
|
76
|
-
|
77
|
-
it 'does not run the block if requested times is zero' do
|
78
|
-
@expected = true
|
79
|
-
retro(0){ @expected = false }
|
80
|
-
@expected.should be_true
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'passes all arguments to the block' do
|
84
|
-
@expected = nil
|
85
|
-
retro(1, ?a, ?b, ?c){|*args| @expected = args }
|
86
|
-
@expected.should eq [?a, ?b, ?c]
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'calls the block once if the first pass is successful' do
|
90
|
-
@expected = 0
|
91
|
-
retro(5){ @expected += 1 }
|
92
|
-
@expected.should eq 1
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'calls the block more than once if the first pass fails' do
|
96
|
-
@expected = 0
|
97
|
-
retro(5) do
|
98
|
-
@expected += 1
|
99
|
-
raise StandardError if @expected < 3
|
100
|
-
end
|
101
|
-
@expected.should eq 3
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'calls the block no more than the requested number of times' do
|
105
|
-
@expected = 0
|
106
|
-
retro(5) do
|
107
|
-
@expected += 1
|
108
|
-
raise StandardError
|
109
|
-
end
|
110
|
-
@expected.should eq 5
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'returns true if any attempt succeeds' do
|
114
|
-
expected = retro(1){ nil }
|
115
|
-
expected.should be_true
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'returns false if all attempts fail' do
|
119
|
-
expected = retro(1){ raise StandardError }
|
120
|
-
expected.should be_false
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'returns false if no block is given' do
|
124
|
-
expected = retro(10)
|
125
|
-
expected.should eq false
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
if RbConfig::CONFIG['ruby_install_name'] =~ /^ruby$/i
|
130
|
-
context '#safe' do
|
131
|
-
|
132
|
-
it 'allows safe operations' do
|
133
|
-
lambda {
|
134
|
-
safe{ 1 + 1 }
|
135
|
-
}.should_not raise_error
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'returns the value of the block when safe' do
|
139
|
-
safe{ 1 + 1 }.should eq 2
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'passes all arguments to the block' do
|
143
|
-
safe(1, 2, 3){|x, y, z| x + y + z }.should eq 6
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'rejects unsafe operations on tainted objects' do
|
147
|
-
lambda {
|
148
|
-
safe{ Signal.trap('INT'.taint) }
|
149
|
-
}.should raise_error(SecurityError)
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'rejects the use of #eval' do
|
153
|
-
lambda {
|
154
|
-
safe{ eval 'puts 1' }
|
155
|
-
}.should raise_error(SecurityError)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
context '#slurp' do
|
161
|
-
|
162
|
-
before(:all) { FakeFS.activate! }
|
163
|
-
after(:all) { FakeFS.deactivate! }
|
164
|
-
|
165
|
-
let!(:path){ 'slurp.txt' }
|
166
|
-
let!(:text){ 'Hello, world!' }
|
167
|
-
|
168
|
-
it 'returns the contents of the file' do
|
169
|
-
File.open(path, 'w+') {|f| f.write(text) }
|
170
|
-
slurp(path).should eq text
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'raises an exception when the file does not exist' do
|
174
|
-
lambda {
|
175
|
-
slurp('path/does/not/exist')
|
176
|
-
}.should raise_error(Errno::ENOENT)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
context '#slurpee' do
|
181
|
-
|
182
|
-
before(:all) { FakeFS.activate! }
|
183
|
-
after(:all) { FakeFS.deactivate! }
|
184
|
-
|
185
|
-
let!(:path){ 'slurp.txt' }
|
186
|
-
let!(:text){ 'You are number 6.' }
|
187
|
-
let!(:erb) { 'You are number <%= 2 * 3 %>.' }
|
188
|
-
|
189
|
-
it 'returns the processed contents of the file' do
|
190
|
-
File.open(path, 'w+') {|f| f.write(erb) }
|
191
|
-
slurpee(path).should eq text
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'raises an exception when the file does not exist' do
|
195
|
-
lambda {
|
196
|
-
slurpee('path/does/not/exist')
|
197
|
-
}.should raise_error(Errno::ENOENT)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
context '#repl?' do
|
202
|
-
|
203
|
-
before(:each) do
|
204
|
-
@dollar_zero = $0
|
205
|
-
end
|
206
|
-
|
207
|
-
after(:each) do
|
208
|
-
$0 = @dollar_zero
|
209
|
-
end
|
210
|
-
|
211
|
-
def set_dollar_zero(val)
|
212
|
-
$0 = val
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'recognizes IRB' do
|
216
|
-
set_dollar_zero('irb')
|
217
|
-
repl?.should be_true
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'recognizes Pry' do
|
221
|
-
set_dollar_zero('pry')
|
222
|
-
repl?.should be_true
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'recognizes Rails Console' do
|
226
|
-
set_dollar_zero('script/rails')
|
227
|
-
repl?.should be_true
|
228
|
-
end
|
229
|
-
|
230
|
-
it 'recognizes Bundle Console' do
|
231
|
-
set_dollar_zero('bin/bundle')
|
232
|
-
repl?.should be_true
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'returns false when not in a REPL' do
|
236
|
-
set_dollar_zero(__FILE__)
|
237
|
-
repl?.should be_false
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context '#timer' do
|
242
|
-
|
243
|
-
it 'returns [0, nil] if no block is given' do
|
244
|
-
duration, result = timer()
|
245
|
-
duration.should eq 0
|
246
|
-
result.should be_nil
|
247
|
-
end
|
248
|
-
|
249
|
-
it 'yields to the block' do
|
250
|
-
@expected = false
|
251
|
-
duration, result = timer{ @expected = true }
|
252
|
-
@expected.should be_true
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'passes all arguments to the block' do
|
256
|
-
@expected = nil
|
257
|
-
duration, result = timer(1,2,3){|a,b,c| @expected = [a,b,c]}
|
258
|
-
@expected.should eq [1,2,3]
|
259
|
-
end
|
260
|
-
|
261
|
-
it 'returns the duration as the first return value' do
|
262
|
-
duration, result = timer{ sleep(0.1) }
|
263
|
-
duration.should > 0
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'returns the block result as the second return value' do
|
267
|
-
duration, result = timer{ 42 }
|
268
|
-
result.should eq 42
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fakefs/safe'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
describe 'utilities' do
|
6
|
+
|
7
|
+
context '#delta' do
|
8
|
+
|
9
|
+
it 'computes the delta of two positive values' do
|
10
|
+
delta(10.5, 5.0).should be_within(0.01).of(5.5)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'computes the delta of two negative values' do
|
14
|
+
delta(-10.5, -5.0).should be_within(0.01).of(5.5)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'computes the delta of a positive and negative value' do
|
18
|
+
delta(10.5, -5.0).should be_within(0.01).of(15.5)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'computes the delta of two positive values with a block' do
|
22
|
+
v1 = {:count => 10.5}
|
23
|
+
v2 = {:count => 5.0}
|
24
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'computes the delta of two negative values with a block' do
|
28
|
+
v1 = {:count => -10.5}
|
29
|
+
v2 = {:count => -5.0}
|
30
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'computes the delta of a positive and negative value with a block' do
|
34
|
+
v1 = {:count => 10.5}
|
35
|
+
v2 = {:count => -5.0}
|
36
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(15.5)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context '#repeatedly' do
|
41
|
+
|
42
|
+
it 'returns an empty array when requested times is zero' do
|
43
|
+
expected = repeatedly(0){ 1 }
|
44
|
+
expected.should be_empty
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns an array with all nil values when no block is given' do
|
48
|
+
expected = repeatedly(10)
|
49
|
+
expected.length.should eq 10
|
50
|
+
expected.each do |elem|
|
51
|
+
elem.should be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'iterates the requested number of times and puts the results into an array' do
|
56
|
+
expected = repeatedly(10){ 5 }
|
57
|
+
expected.length.should eq 10
|
58
|
+
expected.each do |elem|
|
59
|
+
elem.should eq 5
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'passes the initial value to the first iteration' do
|
64
|
+
@expected = nil
|
65
|
+
repeatedly(1,100){|previous| @expected = previous }
|
66
|
+
@expected.should eq 100
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'passes the result of each iteration to the next iteration' do
|
70
|
+
expected = repeatedly(10, 1){|previous| previous * 2 }
|
71
|
+
expected.should eq [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context '#retro' do
|
76
|
+
|
77
|
+
it 'does not run the block if requested times is zero' do
|
78
|
+
@expected = true
|
79
|
+
retro(0){ @expected = false }
|
80
|
+
@expected.should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'passes all arguments to the block' do
|
84
|
+
@expected = nil
|
85
|
+
retro(1, ?a, ?b, ?c){|*args| @expected = args }
|
86
|
+
@expected.should eq [?a, ?b, ?c]
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'calls the block once if the first pass is successful' do
|
90
|
+
@expected = 0
|
91
|
+
retro(5){ @expected += 1 }
|
92
|
+
@expected.should eq 1
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'calls the block more than once if the first pass fails' do
|
96
|
+
@expected = 0
|
97
|
+
retro(5) do
|
98
|
+
@expected += 1
|
99
|
+
raise StandardError if @expected < 3
|
100
|
+
end
|
101
|
+
@expected.should eq 3
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'calls the block no more than the requested number of times' do
|
105
|
+
@expected = 0
|
106
|
+
retro(5) do
|
107
|
+
@expected += 1
|
108
|
+
raise StandardError
|
109
|
+
end
|
110
|
+
@expected.should eq 5
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns true if any attempt succeeds' do
|
114
|
+
expected = retro(1){ nil }
|
115
|
+
expected.should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'returns false if all attempts fail' do
|
119
|
+
expected = retro(1){ raise StandardError }
|
120
|
+
expected.should be_false
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'returns false if no block is given' do
|
124
|
+
expected = retro(10)
|
125
|
+
expected.should eq false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
if RbConfig::CONFIG['ruby_install_name'] =~ /^ruby$/i
|
130
|
+
context '#safe' do
|
131
|
+
|
132
|
+
it 'allows safe operations' do
|
133
|
+
lambda {
|
134
|
+
safe{ 1 + 1 }
|
135
|
+
}.should_not raise_error
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'returns the value of the block when safe' do
|
139
|
+
safe{ 1 + 1 }.should eq 2
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'passes all arguments to the block' do
|
143
|
+
safe(1, 2, 3){|x, y, z| x + y + z }.should eq 6
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'rejects unsafe operations on tainted objects' do
|
147
|
+
lambda {
|
148
|
+
safe{ Signal.trap('INT'.taint) }
|
149
|
+
}.should raise_error(SecurityError)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'rejects the use of #eval' do
|
153
|
+
lambda {
|
154
|
+
safe{ eval 'puts 1' }
|
155
|
+
}.should raise_error(SecurityError)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context '#slurp' do
|
161
|
+
|
162
|
+
before(:all) { FakeFS.activate! }
|
163
|
+
after(:all) { FakeFS.deactivate! }
|
164
|
+
|
165
|
+
let!(:path){ 'slurp.txt' }
|
166
|
+
let!(:text){ 'Hello, world!' }
|
167
|
+
|
168
|
+
it 'returns the contents of the file' do
|
169
|
+
File.open(path, 'w+') {|f| f.write(text) }
|
170
|
+
slurp(path).should eq text
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'raises an exception when the file does not exist' do
|
174
|
+
lambda {
|
175
|
+
slurp('path/does/not/exist')
|
176
|
+
}.should raise_error(Errno::ENOENT)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context '#slurpee' do
|
181
|
+
|
182
|
+
before(:all) { FakeFS.activate! }
|
183
|
+
after(:all) { FakeFS.deactivate! }
|
184
|
+
|
185
|
+
let!(:path){ 'slurp.txt' }
|
186
|
+
let!(:text){ 'You are number 6.' }
|
187
|
+
let!(:erb) { 'You are number <%= 2 * 3 %>.' }
|
188
|
+
|
189
|
+
it 'returns the processed contents of the file' do
|
190
|
+
File.open(path, 'w+') {|f| f.write(erb) }
|
191
|
+
slurpee(path).should eq text
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'raises an exception when the file does not exist' do
|
195
|
+
lambda {
|
196
|
+
slurpee('path/does/not/exist')
|
197
|
+
}.should raise_error(Errno::ENOENT)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context '#repl?' do
|
202
|
+
|
203
|
+
before(:each) do
|
204
|
+
@dollar_zero = $0
|
205
|
+
end
|
206
|
+
|
207
|
+
after(:each) do
|
208
|
+
$0 = @dollar_zero
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_dollar_zero(val)
|
212
|
+
$0 = val
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'recognizes IRB' do
|
216
|
+
set_dollar_zero('irb')
|
217
|
+
repl?.should be_true
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'recognizes Pry' do
|
221
|
+
set_dollar_zero('pry')
|
222
|
+
repl?.should be_true
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'recognizes Rails Console' do
|
226
|
+
set_dollar_zero('script/rails')
|
227
|
+
repl?.should be_true
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'recognizes Bundle Console' do
|
231
|
+
set_dollar_zero('bin/bundle')
|
232
|
+
repl?.should be_true
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'returns false when not in a REPL' do
|
236
|
+
set_dollar_zero(__FILE__)
|
237
|
+
repl?.should be_false
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context '#timer' do
|
242
|
+
|
243
|
+
it 'returns [0, nil] if no block is given' do
|
244
|
+
duration, result = timer()
|
245
|
+
duration.should eq 0
|
246
|
+
result.should be_nil
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'yields to the block' do
|
250
|
+
@expected = false
|
251
|
+
duration, result = timer{ @expected = true }
|
252
|
+
@expected.should be_true
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'passes all arguments to the block' do
|
256
|
+
@expected = nil
|
257
|
+
duration, result = timer(1,2,3){|a,b,c| @expected = [a,b,c]}
|
258
|
+
@expected.should eq [1,2,3]
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'returns the duration as the first return value' do
|
262
|
+
duration, result = timer{ sleep(0.1) }
|
263
|
+
duration.should > 0
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'returns the block result as the second return value' do
|
267
|
+
duration, result = timer{ 42 }
|
268
|
+
result.should eq 42
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|