functional-ruby 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +154 -562
  3. data/lib/functional/agent.rb +130 -0
  4. data/lib/functional/all.rb +9 -1
  5. data/lib/functional/behavior.rb +72 -39
  6. data/lib/functional/cached_thread_pool.rb +122 -0
  7. data/lib/functional/concurrency.rb +32 -24
  8. data/lib/functional/core.rb +2 -62
  9. data/lib/functional/event.rb +53 -0
  10. data/lib/functional/event_machine_defer_proxy.rb +23 -0
  11. data/lib/functional/fixed_thread_pool.rb +89 -0
  12. data/lib/functional/future.rb +42 -0
  13. data/lib/functional/global_thread_pool.rb +3 -0
  14. data/lib/functional/obligation.rb +121 -0
  15. data/lib/functional/promise.rb +194 -0
  16. data/lib/functional/thread_pool.rb +61 -0
  17. data/lib/functional/utilities.rb +114 -0
  18. data/lib/functional/version.rb +1 -1
  19. data/lib/functional.rb +1 -0
  20. data/lib/functional_ruby.rb +1 -0
  21. data/md/behavior.md +147 -0
  22. data/md/concurrency.md +465 -0
  23. data/md/future.md +32 -0
  24. data/md/obligation.md +32 -0
  25. data/md/pattern_matching.md +512 -0
  26. data/md/promise.md +220 -0
  27. data/md/utilities.md +53 -0
  28. data/spec/functional/agent_spec.rb +405 -0
  29. data/spec/functional/behavior_spec.rb +12 -33
  30. data/spec/functional/cached_thread_pool_spec.rb +112 -0
  31. data/spec/functional/concurrency_spec.rb +55 -0
  32. data/spec/functional/event_machine_defer_proxy_spec.rb +246 -0
  33. data/spec/functional/event_spec.rb +114 -0
  34. data/spec/functional/fixed_thread_pool_spec.rb +84 -0
  35. data/spec/functional/future_spec.rb +115 -0
  36. data/spec/functional/obligation_shared.rb +121 -0
  37. data/spec/functional/pattern_matching_spec.rb +10 -8
  38. data/spec/functional/promise_spec.rb +310 -0
  39. data/spec/functional/thread_pool_shared.rb +209 -0
  40. data/spec/functional/utilities_spec.rb +149 -0
  41. data/spec/spec_helper.rb +2 -0
  42. metadata +55 -5
@@ -0,0 +1,209 @@
1
+ require 'spec_helper'
2
+
3
+ module Functional
4
+
5
+ share_examples_for 'Thread Pool' do
6
+
7
+ context '#running?' do
8
+
9
+ it 'returns true when the thread pool is running' do
10
+ subject.should be_running
11
+ end
12
+
13
+ it 'returns false when the thread pool is shutting down' do
14
+ subject.post{ sleep(1) }
15
+ subject.shutdown
16
+ subject.should_not be_running
17
+ end
18
+
19
+ it 'returns false when the thread pool is shutdown' do
20
+ subject.shutdown
21
+ subject.should_not be_running
22
+ end
23
+
24
+ it 'returns false when the thread pool is killed' do
25
+ subject.shutdown
26
+ subject.should_not be_running
27
+ end
28
+ end
29
+
30
+ context '#shutdown?' do
31
+
32
+ it 'returns true if #shutdown has been called' do
33
+ subject.shutdown
34
+ subject.should be_shutdown
35
+ end
36
+
37
+ it 'returns false when running' do
38
+ subject.should_not be_shutdown
39
+ end
40
+ end
41
+
42
+ context '#killed?' do
43
+
44
+ it 'returns true if tasks were killed at shutdown' do
45
+ subject.post{ sleep(1) }
46
+ subject.kill
47
+ subject.should be_killed
48
+ end
49
+
50
+ it 'returns false when running' do
51
+ subject.should_not be_killed
52
+ end
53
+ end
54
+
55
+ context '#shutdown' do
56
+
57
+ it 'stops accepting new tasks' do
58
+ subject.post{ sleep(1) }
59
+ subject.shutdown
60
+ @expected = false
61
+ subject.post{ @expected = true }.should be_false
62
+ sleep(1)
63
+ @expected.should be_false
64
+ end
65
+
66
+ it 'allows in-progress tasks to complete' do
67
+ @expected = false
68
+ subject.post{ sleep(0.5); @expected = true }
69
+ subject.shutdown
70
+ sleep(1)
71
+ @expected.should be_true
72
+ end
73
+
74
+ it 'allows pending tasks to complete' do
75
+ @expected = false
76
+ subject.post{ sleep(0.2) }
77
+ subject.post{ sleep(0.2); @expected = true }
78
+ subject.shutdown
79
+ sleep(1)
80
+ @expected.should be_true
81
+ end
82
+
83
+ it 'allows threads to exit normally' do
84
+ pool = FixedThreadPool.new(5)
85
+ pool.shutdown
86
+ sleep(1)
87
+ pool.status.should be_empty
88
+ end
89
+ end
90
+
91
+ context '#kill' do
92
+
93
+ it 'stops accepting new tasks' do
94
+ subject.post{ sleep(1) }
95
+ subject.kill
96
+ @expected = false
97
+ subject.post{ @expected = true }.should be_false
98
+ sleep(1)
99
+ @expected.should be_false
100
+ end
101
+
102
+ it 'attempts to kill all in-progress tasks' do
103
+ @expected = false
104
+ subject.post{ sleep(1); @expected = true }
105
+ subject.kill
106
+ sleep(1)
107
+ @expected.should be_false
108
+ end
109
+
110
+ it 'rejects all pending tasks' do
111
+ @expected = false
112
+ subject.post{ sleep(0.5) }
113
+ subject.post{ sleep(0.5); @expected = true }
114
+ subject.kill
115
+ sleep(1)
116
+ @expected.should be_false
117
+ end
118
+ end
119
+
120
+ context '#wait_for_termination' do
121
+
122
+ it 'immediately returns true after shutdown has complete' do
123
+ subject.shutdown
124
+ subject.wait_for_termination.should be_true
125
+ end
126
+
127
+ it 'blocks indefinitely when timeout it nil' do
128
+ subject.post{ sleep(1) }
129
+ subject.shutdown
130
+ subject.wait_for_termination(nil).should be_true
131
+ end
132
+
133
+ it 'returns true when shutdown sucessfully completes before timeout' do
134
+ subject.post{ sleep(0.5) }
135
+ subject.shutdown
136
+ subject.wait_for_termination(1).should be_true
137
+ end
138
+
139
+ it 'returns false when shutdown fails to complete before timeout' do
140
+ subject.post{ sleep(1) }
141
+ subject.shutdown
142
+ subject.wait_for_termination(0.5).should be_true
143
+ end
144
+ end
145
+
146
+ context '#post' do
147
+
148
+ it 'raises an exception if no block is given' do
149
+ lambda {
150
+ subject.post
151
+ }.should raise_error(ArgumentError)
152
+ end
153
+
154
+ it 'returns true when the block is added to the queue' do
155
+ subject.post{ nil }.should be_true
156
+ end
157
+
158
+ it 'calls the block with the given arguments' do
159
+ @expected = nil
160
+ subject.post(1, 2, 3)do |a, b, c|
161
+ @expected = a + b + c
162
+ end
163
+ sleep(0.1)
164
+ @expected.should eq 6
165
+ end
166
+
167
+ it 'rejects the block while shutting down' do
168
+ pool = FixedThreadPool.new(5)
169
+ pool.post{ sleep(1) }
170
+ pool.shutdown
171
+ @expected = nil
172
+ pool.post(1, 2, 3)do |a, b, c|
173
+ @expected = a + b + c
174
+ end
175
+ @expected.should be_nil
176
+ end
177
+
178
+ it 'returns false while shutting down' do
179
+ subject.post{ sleep(1) }
180
+ subject.shutdown
181
+ subject.post{ nil }.should be_false
182
+ end
183
+
184
+ it 'rejects the block once shutdown' do
185
+ pool = FixedThreadPool.new(5)
186
+ pool.shutdown
187
+ @expected = nil
188
+ pool.post(1, 2, 3)do |a, b, c|
189
+ @expected = a + b + c
190
+ end
191
+ @expected.should be_nil
192
+ end
193
+
194
+ it 'returns false once shutdown' do
195
+ subject.post{ nil }
196
+ subject.shutdown
197
+ sleep(0.1)
198
+ subject.post{ nil }.should be_false
199
+ end
200
+
201
+ it 'aliases #<<' do
202
+ @expected = false
203
+ subject << proc { @expected = true }
204
+ sleep(0.1)
205
+ @expected.should be_true
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+ require 'fakefs/safe'
3
+
4
+ describe 'utilities' do
5
+
6
+ context '#repl?' do
7
+
8
+ before(:each) do
9
+ @dollar_zero = $0
10
+ end
11
+
12
+ after(:each) do
13
+ $0 = @dollar_zero
14
+ end
15
+
16
+ def set_dollar_zero(val)
17
+ $0 = val
18
+ end
19
+
20
+ it 'recognizes IRB' do
21
+ set_dollar_zero('irb')
22
+ repl?.should be_true
23
+ end
24
+
25
+ it 'recognizes Pry' do
26
+ set_dollar_zero('pry')
27
+ repl?.should be_true
28
+ end
29
+
30
+ it 'recognizes Rails Console' do
31
+ set_dollar_zero('script/rails')
32
+ repl?.should be_true
33
+ end
34
+
35
+ it 'recognizes Bundle Console' do
36
+ set_dollar_zero('bin/bundle')
37
+ repl?.should be_true
38
+ end
39
+
40
+ it 'returns false when not in a REPL' do
41
+ set_dollar_zero(__FILE__)
42
+ repl?.should be_false
43
+ end
44
+ end
45
+
46
+ context '#safe' do
47
+
48
+ it 'allows safe operations' do
49
+ lambda {
50
+ safe{ 1 + 1 }
51
+ }.should_not raise_error(SecurityError)
52
+ end
53
+
54
+ it 'returns the value of the block when safe' do
55
+ safe{ 1 + 1 }.should eq 2
56
+ end
57
+
58
+ it 'passes all arguments to the block' do
59
+ safe(1, 2, 3){|x, y, z| x + y + z }.should eq 6
60
+ end
61
+
62
+ it 'rejects unsafe operations on tainted objects' do
63
+ lambda {
64
+ safe{ Signal.trap('INT'.taint) }
65
+ }.should raise_error(SecurityError)
66
+ end
67
+
68
+ it 'rejects the use of #eval' do
69
+ lambda {
70
+ safe{ eval 'puts 1' }
71
+ }.should raise_error(SecurityError)
72
+ end
73
+ end
74
+
75
+ context '#slurp' do
76
+
77
+ before(:all) { FakeFS.activate! }
78
+ after(:all) { FakeFS.deactivate! }
79
+
80
+ let!(:path){ 'slurp.txt' }
81
+ let!(:text){ 'Hello, world!' }
82
+
83
+ it 'returns the contents of the file' do
84
+ File.open(path, 'w+') {|f| f.write(text) }
85
+ slurp(path).should eq text
86
+ end
87
+
88
+ it 'raises an exception when the file does not exist' do
89
+ lambda {
90
+ slurp('path/does/not/exist')
91
+ }.should raise_error(Errno::ENOENT)
92
+ end
93
+ end
94
+
95
+ context '#slurpee' do
96
+
97
+ before(:all) { FakeFS.activate! }
98
+ after(:all) { FakeFS.deactivate! }
99
+
100
+ let!(:path){ 'slurp.txt' }
101
+ let!(:text){ 'You are number 6.' }
102
+ let!(:erb) { 'You are number <%= 2 * 3 %>.' }
103
+
104
+ it 'returns the processed contents of the file' do
105
+ File.open(path, 'w+') {|f| f.write(erb) }
106
+ slurpee(path).should eq text
107
+ end
108
+
109
+ it 'raises an exception when the file does not exist' do
110
+ lambda {
111
+ slurpee('path/does/not/exist')
112
+ }.should raise_error(Errno::ENOENT)
113
+ end
114
+ end
115
+
116
+ context '#delta' do
117
+
118
+ it 'computes the delta of two positive values' do
119
+ delta(10.5, 5.0).should be_within(0.01).of(5.5)
120
+ end
121
+
122
+ it 'computes the delta of two negative values' do
123
+ delta(-10.5, -5.0).should be_within(0.01).of(5.5)
124
+ end
125
+
126
+ it 'computes the delta of a positive and negative value' do
127
+ delta(10.5, -5.0).should be_within(0.01).of(15.5)
128
+ end
129
+
130
+ it 'computes the delta of two positive values with a block' do
131
+ v1 = {:count => 10.5}
132
+ v2 = {:count => 5.0}
133
+ delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
134
+ end
135
+
136
+ it 'computes the delta of two negative values with a block' do
137
+ v1 = {:count => -10.5}
138
+ v2 = {:count => -5.0}
139
+ delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
140
+ end
141
+
142
+ it 'computes the delta of a positive and negative value with a block' do
143
+ v1 = {:count => 10.5}
144
+ v2 = {:count => -5.0}
145
+ delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(15.5)
146
+ end
147
+ end
148
+
149
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'eventmachine'
2
+
1
3
  require 'functional/all'
2
4
 
3
5
  # import all the support files
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functional-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-22 00:00:00.000000000 Z
11
+ date: 2013-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  description: |2
28
- A gem for adding Erlang and Clojure inspired functional programming tools to Ruby.
28
+ A gem for adding Erlang, Clojure, and Go inspired concurrency and functional programming tools to Ruby.
29
29
  email: jerry.dantonio@gmail.com
30
30
  executables: []
31
31
  extensions: []
@@ -35,22 +35,62 @@ extra_rdoc_files:
35
35
  files:
36
36
  - README.md
37
37
  - LICENSE
38
+ - lib/functional/agent.rb
38
39
  - lib/functional/all.rb
39
40
  - lib/functional/behavior.rb
40
41
  - lib/functional/behaviour.rb
42
+ - lib/functional/cached_thread_pool.rb
41
43
  - lib/functional/concurrency.rb
42
44
  - lib/functional/core.rb
45
+ - lib/functional/event.rb
46
+ - lib/functional/event_machine_defer_proxy.rb
47
+ - lib/functional/fixed_thread_pool.rb
48
+ - lib/functional/future.rb
49
+ - lib/functional/global_thread_pool.rb
50
+ - lib/functional/obligation.rb
43
51
  - lib/functional/pattern_matching.rb
52
+ - lib/functional/promise.rb
53
+ - lib/functional/thread_pool.rb
54
+ - lib/functional/utilities.rb
44
55
  - lib/functional/version.rb
56
+ - lib/functional.rb
57
+ - lib/functional_ruby.rb
58
+ - md/behavior.md
59
+ - md/concurrency.md
60
+ - md/future.md
61
+ - md/obligation.md
62
+ - md/pattern_matching.md
63
+ - md/promise.md
64
+ - md/utilities.md
65
+ - spec/functional/agent_spec.rb
45
66
  - spec/functional/behavior_spec.rb
67
+ - spec/functional/cached_thread_pool_spec.rb
68
+ - spec/functional/concurrency_spec.rb
69
+ - spec/functional/event_machine_defer_proxy_spec.rb
70
+ - spec/functional/event_spec.rb
71
+ - spec/functional/fixed_thread_pool_spec.rb
72
+ - spec/functional/future_spec.rb
46
73
  - spec/functional/integration_spec.rb
74
+ - spec/functional/obligation_shared.rb
47
75
  - spec/functional/pattern_matching_spec.rb
76
+ - spec/functional/promise_spec.rb
77
+ - spec/functional/thread_pool_shared.rb
78
+ - spec/functional/utilities_spec.rb
48
79
  - spec/spec_helper.rb
49
80
  homepage: https://github.com/jdantonio/functional-ruby/
50
81
  licenses:
51
82
  - MIT
52
83
  metadata: {}
53
- post_install_message: start() -> io:format("Hello, World!").
84
+ post_install_message: |2
85
+ hello() -> io:format("Hello, World!").
86
+
87
+ package main
88
+ import "fmt"
89
+ func main() {
90
+ fmt.Printf("hello, world")
91
+ }
92
+
93
+ (def hello (fn [] "Hello world"))
54
94
  rdoc_options: []
55
95
  require_paths:
56
96
  - lib
@@ -71,8 +111,18 @@ signing_key:
71
111
  specification_version: 4
72
112
  summary: Erlang and Clojure inspired functional programming tools for Ruby.
73
113
  test_files:
114
+ - spec/functional/agent_spec.rb
74
115
  - spec/functional/behavior_spec.rb
116
+ - spec/functional/cached_thread_pool_spec.rb
117
+ - spec/functional/concurrency_spec.rb
118
+ - spec/functional/event_machine_defer_proxy_spec.rb
119
+ - spec/functional/event_spec.rb
120
+ - spec/functional/fixed_thread_pool_spec.rb
121
+ - spec/functional/future_spec.rb
75
122
  - spec/functional/integration_spec.rb
123
+ - spec/functional/obligation_shared.rb
76
124
  - spec/functional/pattern_matching_spec.rb
125
+ - spec/functional/promise_spec.rb
126
+ - spec/functional/thread_pool_shared.rb
127
+ - spec/functional/utilities_spec.rb
77
128
  - spec/spec_helper.rb
78
- has_rdoc: