functional-ruby 0.5.0 → 0.6.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 (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: