functional-ruby 0.6.0 → 0.7.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -126
  3. data/lib/functional.rb +4 -1
  4. data/lib/functional/utilities.rb +46 -0
  5. data/lib/functional/version.rb +1 -1
  6. data/lib/functional_ruby.rb +1 -1
  7. data/md/utilities.md +2 -0
  8. data/spec/functional/behavior_spec.rb +2 -2
  9. data/spec/functional/pattern_matching_spec.rb +2 -2
  10. data/spec/functional/utilities_spec.rb +131 -43
  11. data/spec/spec_helper.rb +1 -3
  12. metadata +3 -40
  13. data/lib/functional/agent.rb +0 -130
  14. data/lib/functional/all.rb +0 -13
  15. data/lib/functional/cached_thread_pool.rb +0 -122
  16. data/lib/functional/concurrency.rb +0 -35
  17. data/lib/functional/core.rb +0 -2
  18. data/lib/functional/event.rb +0 -53
  19. data/lib/functional/event_machine_defer_proxy.rb +0 -23
  20. data/lib/functional/fixed_thread_pool.rb +0 -89
  21. data/lib/functional/future.rb +0 -42
  22. data/lib/functional/global_thread_pool.rb +0 -3
  23. data/lib/functional/obligation.rb +0 -121
  24. data/lib/functional/promise.rb +0 -194
  25. data/lib/functional/thread_pool.rb +0 -61
  26. data/md/concurrency.md +0 -465
  27. data/md/future.md +0 -32
  28. data/md/obligation.md +0 -32
  29. data/md/promise.md +0 -220
  30. data/spec/functional/agent_spec.rb +0 -405
  31. data/spec/functional/cached_thread_pool_spec.rb +0 -112
  32. data/spec/functional/concurrency_spec.rb +0 -55
  33. data/spec/functional/event_machine_defer_proxy_spec.rb +0 -246
  34. data/spec/functional/event_spec.rb +0 -114
  35. data/spec/functional/fixed_thread_pool_spec.rb +0 -84
  36. data/spec/functional/future_spec.rb +0 -115
  37. data/spec/functional/obligation_shared.rb +0 -121
  38. data/spec/functional/promise_spec.rb +0 -310
  39. data/spec/functional/thread_pool_shared.rb +0 -209
@@ -1,112 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'thread_pool_shared'
3
-
4
- module Functional
5
-
6
- describe CachedThreadPool do
7
-
8
- subject { CachedThreadPool.new }
9
-
10
- it_should_behave_like 'Thread Pool'
11
-
12
- context '#initialize' do
13
- it 'aliases Functional#new_cached_thread_pool' do
14
- pool = Functional.new_cached_thread_pool
15
- pool.should be_a(CachedThreadPool)
16
- pool.size.should eq 0
17
- end
18
- end
19
-
20
- context '#kill' do
21
-
22
- it 'kills all threads' do
23
- Thread.should_receive(:kill).exactly(5).times
24
- pool = CachedThreadPool.new
25
- 5.times{ sleep(0.1); pool << proc{ sleep(1) } }
26
- sleep(1)
27
- pool.kill
28
- sleep(0.1)
29
- end
30
- end
31
-
32
- context '#size' do
33
-
34
- it 'returns zero for a new thread pool' do
35
- subject.size.should eq 0
36
- end
37
-
38
- it 'returns the size of the subject when running' do
39
- 5.times{ sleep(0.1); subject << proc{ sleep(1) } }
40
- subject.size.should eq 5
41
- end
42
-
43
- it 'returns zero once shut down' do
44
- subject.shutdown
45
- subject.size.should eq 0
46
- end
47
- end
48
-
49
- context 'worker creation and caching' do
50
-
51
- it 'creates new workers when there are none available' do
52
- subject.size.should eq 0
53
- 5.times{ sleep(0.1); subject << proc{ sleep(1000) } }
54
- sleep(1)
55
- subject.size.should eq 5
56
- end
57
-
58
- it 'uses existing idle threads' do
59
- 5.times{ sleep(0.05); subject << proc{ sleep(0.5) } }
60
- sleep(1)
61
- 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
62
- subject.size.should eq 5
63
- end
64
- end
65
-
66
- context 'garbage collection' do
67
-
68
- subject{ CachedThreadPool.new(gc_interval: 1, thread_idleime: 1) }
69
-
70
- it 'starts when the first thread is added to the pool' do
71
- subject.should_receive(:collect_garbage)
72
- subject << proc{ nil }
73
- sleep(0.1)
74
- end
75
-
76
- it 'removes from pool any thread that has been idle too long' do
77
- subject << proc{ nil }
78
- subject.size.should eq 1
79
- sleep(1.5)
80
- subject.size.should eq 0
81
- end
82
-
83
- it 'removed from pool any dead thread' do
84
- subject << proc{ raise StandardError }
85
- subject.size.should eq 1
86
- sleep(1.5)
87
- subject.size.should eq 0
88
- end
89
-
90
- it 'resets the working count appropriately' do
91
- subject << proc{ sleep(1000) }
92
- sleep(0.1)
93
- subject << proc{ raise StandardError }
94
- sleep(0.1)
95
- subject << proc{ nil }
96
-
97
- sleep(0.1)
98
- subject.working.should eq 2
99
-
100
- sleep(1.5)
101
- subject.working.should eq 1
102
- end
103
-
104
- it 'stops collection when the pool size becomes zero' do
105
- 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
106
- subject.instance_variable_get(:@collector).status.should eq 'sleep'
107
- sleep(1.5)
108
- subject.instance_variable_get(:@collector).status.should be_false
109
- end
110
- end
111
- end
112
- end
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Functional
4
-
5
- describe 'concurrency' do
6
-
7
- context '#go' do
8
-
9
- before(:each) do
10
- $GLOBAL_THREAD_POOL = CachedThreadPool.new
11
- end
12
-
13
- it 'passes all arguments to the block' do
14
- @expected = nil
15
- go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
16
- sleep(0.1)
17
- @expected.should eq [3, 2, 1]
18
- end
19
-
20
- it 'returns true if the thread is successfully created' do
21
- $GLOBAL_THREAD_POOL.should_receive(:post).and_return(true)
22
- go{ nil }.should be_true
23
- end
24
-
25
- it 'returns false if the thread cannot be created' do
26
- $GLOBAL_THREAD_POOL.should_receive(:post).and_return(false)
27
- go{ nil }.should be_false
28
- end
29
-
30
- it 'immediately returns false if no block is given' do
31
- go().should be_false
32
- end
33
-
34
- it 'does not create a thread if no block is given' do
35
- $GLOBAL_THREAD_POOL.should_not_receive(:post)
36
- go()
37
- sleep(0.1)
38
- end
39
-
40
- it 'supresses exceptions on the thread' do
41
- lambda{
42
- go{ raise StandardError }
43
- sleep(0.1)
44
- }.should_not raise_error
45
- end
46
-
47
- it 'processes the block' do
48
- @expected = false
49
- go(1,2,3){|*args| @expected = args }
50
- sleep(0.1)
51
- @expected.should eq [1,2,3]
52
- end
53
- end
54
- end
55
- end
@@ -1,246 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'functional/agent'
4
- require 'functional/future'
5
- require 'functional/promise'
6
-
7
- module Functional
8
-
9
- describe EventMachineDeferProxy do
10
-
11
- subject { EventMachineDeferProxy.new }
12
-
13
- context '#post' do
14
-
15
- it 'proxies a call without arguments' do
16
- @expected = false
17
- EventMachine.run do
18
- subject.post{ @expected = true }
19
- sleep(0.1)
20
- EventMachine.stop
21
- end
22
- @expected.should eq true
23
- end
24
-
25
- it 'proxies a call with arguments' do
26
- @expected = []
27
- EventMachine.run do
28
- subject.post(1,2,3){|*args| @expected = args }
29
- sleep(0.1)
30
- EventMachine.stop
31
- end
32
- @expected.should eq [1,2,3]
33
- end
34
-
35
- it 'aliases #<<' do
36
- @expected = false
37
- EventMachine.run do
38
- subject << proc{ @expected = true }
39
- sleep(0.1)
40
- EventMachine.stop
41
- end
42
- @expected.should eq true
43
- end
44
- end
45
-
46
- context 'operation' do
47
-
48
- context 'goroutine' do
49
-
50
- it 'passes all arguments to the block' do
51
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
52
-
53
- EventMachine.run do
54
-
55
- @expected = nil
56
- go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
57
- sleep(0.1)
58
- @expected.should eq [3, 2, 1]
59
-
60
- EventMachine.stop
61
- end
62
- end
63
- end
64
-
65
- context Agent do
66
-
67
- subject { Agent.new(0) }
68
-
69
- it 'supports fulfillment' do
70
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
71
-
72
- EventMachine.run do
73
-
74
- @expected = []
75
- subject.post{ @expected << 1 }
76
- subject.post{ @expected << 2 }
77
- subject.post{ @expected << 3 }
78
- sleep(0.1)
79
- @expected.should eq [1,2,3]
80
-
81
- EventMachine.stop
82
- end
83
- end
84
-
85
- it 'supports validation' do
86
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
87
-
88
- EventMachine.run do
89
-
90
- @expected = nil
91
- subject.validate{ @expected = 10; true }
92
- subject.post{ nil }
93
- sleep(0.1)
94
- @expected.should eq 10
95
-
96
- EventMachine.stop
97
- end
98
- end
99
-
100
- it 'supports rejection' do
101
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
102
-
103
- EventMachine.run do
104
-
105
- @expected = nil
106
- subject.
107
- on_error(StandardError){|ex| @expected = 1 }.
108
- on_error(StandardError){|ex| @expected = 2 }.
109
- on_error(StandardError){|ex| @expected = 3 }
110
- subject.post{ raise StandardError }
111
- sleep(0.1)
112
- @expected.should eq 1
113
-
114
- EventMachine.stop
115
- end
116
- end
117
- end
118
-
119
- context Future do
120
-
121
- it 'supports fulfillment' do
122
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
123
-
124
- EventMachine.run do
125
-
126
- @a = @b = @c = nil
127
- f = Future.new(1, 2, 3) do |a, b, c|
128
- @a, @b, @c = a, b, c
129
- end
130
- sleep(0.1)
131
- [@a, @b, @c].should eq [1, 2, 3]
132
-
133
- sleep(0.1)
134
- EventMachine.stop
135
- end
136
- end
137
- end
138
-
139
- context Promise do
140
-
141
- context 'fulfillment' do
142
-
143
- it 'passes all arguments to the first promise in the chain' do
144
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
145
-
146
- EventMachine.run do
147
-
148
- @a = @b = @c = nil
149
- p = Promise.new(1, 2, 3) do |a, b, c|
150
- @a, @b, @c = a, b, c
151
- end
152
- sleep(0.1)
153
- [@a, @b, @c].should eq [1, 2, 3]
154
-
155
- sleep(0.1)
156
- EventMachine.stop
157
- end
158
- end
159
-
160
- it 'passes the result of each block to all its children' do
161
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
162
-
163
- EventMachine.run do
164
- @expected = nil
165
- Promise.new(10){|a| a * 2 }.then{|result| @expected = result}
166
- sleep(0.1)
167
- @expected.should eq 20
168
-
169
- sleep(0.1)
170
- EventMachine.stop
171
- end
172
- end
173
-
174
- it 'sets the promise value to the result if its block' do
175
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
176
-
177
- EventMachine.run do
178
-
179
- p = Promise.new(10){|a| a * 2 }.then{|result| result * 2}
180
- sleep(0.1)
181
- p.value.should eq 40
182
-
183
- sleep(0.1)
184
- EventMachine.stop
185
- end
186
- end
187
- end
188
-
189
- context 'rejection' do
190
-
191
- it 'sets the promise reason and error on exception' do
192
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
193
-
194
- EventMachine.run do
195
-
196
- p = Promise.new{ raise StandardError.new('Boom!') }
197
- sleep(0.1)
198
- p.reason.should be_a(Exception)
199
- p.reason.should.to_s =~ /Boom!/
200
- p.should be_rejected
201
-
202
- sleep(0.1)
203
- EventMachine.stop
204
- end
205
- end
206
-
207
- it 'calls the first exception block with a matching class' do
208
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
209
-
210
- EventMachine.run do
211
-
212
- @expected = nil
213
- Promise.new{ raise StandardError }.
214
- on_error(StandardError){|ex| @expected = 1 }.
215
- on_error(StandardError){|ex| @expected = 2 }.
216
- on_error(StandardError){|ex| @expected = 3 }
217
- sleep(0.1)
218
- @expected.should eq 1
219
-
220
- sleep(0.1)
221
- EventMachine.stop
222
- end
223
- end
224
-
225
- it 'passes the exception object to the matched block' do
226
- $GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
227
-
228
- EventMachine.run do
229
-
230
- @expected = nil
231
- Promise.new{ raise StandardError }.
232
- on_error(ArgumentError){|ex| @expected = ex }.
233
- on_error(LoadError){|ex| @expected = ex }.
234
- on_error(Exception){|ex| @expected = ex }
235
- sleep(0.1)
236
- @expected.should be_a(StandardError)
237
-
238
- sleep(0.1)
239
- EventMachine.stop
240
- end
241
- end
242
- end
243
- end
244
- end
245
- end
246
- end
@@ -1,114 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Functional
4
-
5
- describe Event do
6
-
7
- subject{ Event.new }
8
-
9
- context '#initialize' do
10
-
11
- it 'sets the state to unset' do
12
- subject.should_not be_set
13
- end
14
- end
15
-
16
- context '#set?' do
17
-
18
- it 'returns true when the event has been set' do
19
- subject.set
20
- subject.should be_set
21
- end
22
-
23
- it 'returns false if the event is unset' do
24
- subject.reset
25
- subject.should_not be_set
26
- end
27
- end
28
-
29
- context '#set' do
30
-
31
- it 'triggers the event' do
32
- subject.reset
33
- @expected = false
34
- Thread.new{ sleep(0.5); subject.wait; @expected = true }
35
- subject.set
36
- sleep(1)
37
- @expected.should be_true
38
- end
39
-
40
- it 'sets the state to set' do
41
- subject.set
42
- subject.should be_set
43
- end
44
- end
45
-
46
- context '#reset' do
47
-
48
- it 'sets the state to unset' do
49
- subject.set
50
- subject.should be_set
51
- subject.reset
52
- subject.should_not be_set
53
- end
54
- end
55
-
56
- context '#wait' do
57
-
58
- it 'returns immediately when the event has been set' do
59
- subject.reset
60
- @expected = false
61
- subject.set
62
- Thread.new{ subject.wait(1000); @expected = true}
63
- sleep(1)
64
- @expected.should be_true
65
- end
66
-
67
- it 'returns true once the event is set' do
68
- subject.set
69
- subject.wait.should be_true
70
- end
71
-
72
- it 'blocks indefinitely when the timer is nil' do
73
- subject.reset
74
- @expected = false
75
- Thread.new{ subject.wait; @expected = true}
76
- subject.set
77
- sleep(1)
78
- @expected.should be_true
79
- end
80
-
81
- it 'stops waiting when the timer expires' do
82
- subject.reset
83
- @expected = false
84
- Thread.new{ subject.wait(0.5); @expected = true}
85
- sleep(1)
86
- @expected.should be_true
87
- end
88
-
89
- it 'returns false when the timer expires' do
90
- subject.reset
91
- subject.wait(1).should be_false
92
- end
93
-
94
- it 'triggers multiple waiting threads' do
95
- subject.reset
96
- @expected = []
97
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
98
- subject.set
99
- sleep(1)
100
- @expected.length.should eq 5
101
- end
102
-
103
- it 'behaves appropriately if wait begins while #set is processing' do
104
- subject.reset
105
- @expected = []
106
- 5.times{ Thread.new{ subject.wait(5) } }
107
- subject.set
108
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
109
- sleep(1)
110
- @expected.length.should eq 5
111
- end
112
- end
113
- end
114
- end