functional-ruby 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -126
- data/lib/functional.rb +4 -1
- data/lib/functional/utilities.rb +46 -0
- data/lib/functional/version.rb +1 -1
- data/lib/functional_ruby.rb +1 -1
- data/md/utilities.md +2 -0
- data/spec/functional/behavior_spec.rb +2 -2
- data/spec/functional/pattern_matching_spec.rb +2 -2
- data/spec/functional/utilities_spec.rb +131 -43
- data/spec/spec_helper.rb +1 -3
- metadata +3 -40
- data/lib/functional/agent.rb +0 -130
- data/lib/functional/all.rb +0 -13
- data/lib/functional/cached_thread_pool.rb +0 -122
- data/lib/functional/concurrency.rb +0 -35
- data/lib/functional/core.rb +0 -2
- data/lib/functional/event.rb +0 -53
- data/lib/functional/event_machine_defer_proxy.rb +0 -23
- data/lib/functional/fixed_thread_pool.rb +0 -89
- data/lib/functional/future.rb +0 -42
- data/lib/functional/global_thread_pool.rb +0 -3
- data/lib/functional/obligation.rb +0 -121
- data/lib/functional/promise.rb +0 -194
- data/lib/functional/thread_pool.rb +0 -61
- data/md/concurrency.md +0 -465
- data/md/future.md +0 -32
- data/md/obligation.md +0 -32
- data/md/promise.md +0 -220
- data/spec/functional/agent_spec.rb +0 -405
- data/spec/functional/cached_thread_pool_spec.rb +0 -112
- data/spec/functional/concurrency_spec.rb +0 -55
- data/spec/functional/event_machine_defer_proxy_spec.rb +0 -246
- data/spec/functional/event_spec.rb +0 -114
- data/spec/functional/fixed_thread_pool_spec.rb +0 -84
- data/spec/functional/future_spec.rb +0 -115
- data/spec/functional/obligation_shared.rb +0 -121
- data/spec/functional/promise_spec.rb +0 -310
- data/spec/functional/thread_pool_shared.rb +0 -209
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ebc0dab7cc6ee079416729c8cc131bf239ca2bb
|
4
|
+
data.tar.gz: 24b3193d7e6fef20addd8688ab372c104163edae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65b487a457f8b8a4dcb3adfe98e8429ae0184656d3ddf6292c515c598f4cb6e610f8aca4185950626bf4e67cda95a77eb081031caf5f7ea95ccf3592df6c9d0a
|
7
|
+
data.tar.gz: bbe8b613ee9ac7a4aa4ed6626a36a2bfc148e4ddc42ef5fd2f5be5703f74567beb15dd772d0b4e63156f6ca46accae1425dfdeac0a36d75a34a09aa4bceafc45
|
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# Functional Ruby [![Build Status](https://secure.travis-ci.org/jdantonio/functional-ruby.png)](https://travis-ci.org/jdantonio/functional-ruby?branch=master) [![Dependency Status](https://gemnasium.com/jdantonio/functional-ruby.png)](https://gemnasium.com/jdantonio/functional-ruby)
|
2
2
|
|
3
|
-
A gem for adding Erlang, Clojure, and Go inspired
|
3
|
+
A gem for adding Erlang, Clojure, and Go inspired functional programming tools to Ruby.
|
4
|
+
|
5
|
+
*NOTE: As of version 0.7.0 the concurrency tools from this gem have been moved to the
|
6
|
+
[concurrent-ruby](https://github.com/jdantonio/concurrent-ruby) gem.*
|
4
7
|
|
5
8
|
The project is hosted on the following sites:
|
6
9
|
|
7
10
|
* [RubyGems project page](https://rubygems.org/gems/functional-ruby)
|
8
11
|
* [Source code on GitHub](https://github.com/jdantonio/functional-ruby)
|
9
|
-
* [YARD documentation on RubyDoc.info](http://rubydoc.info/github/jdantonio/functional-ruby/
|
12
|
+
* [YARD documentation on RubyDoc.info](http://rubydoc.info/github/jdantonio/functional-ruby/frames)
|
10
13
|
* [Continuous integration on Travis-CI](https://travis-ci.org/jdantonio/functional-ruby)
|
11
14
|
* [Dependency tracking on Gemnasium](https://gemnasium.com/jdantonio/functional-ruby)
|
12
15
|
* [Follow me on Twitter](https://twitter.com/jerrydantonio)
|
@@ -27,19 +30,11 @@ area. Ruby 2.0 is now a [relevant](https://blog.heroku.com/archives/2013/6/17/ru
|
|
27
30
|
platform for concurrent applications.
|
28
31
|
|
29
32
|
This gem is my small and humble attempt to help Ruby reach its full potential as
|
30
|
-
a highly performant, functional
|
33
|
+
a highly performant, functional programming language.
|
31
34
|
|
32
35
|
### Goals
|
33
36
|
|
34
|
-
My
|
35
|
-
I have the same scars as everyone else doing that kind of work with those languages.
|
36
|
-
I'm fascinated by modern concurrency patterns like [Actors](http://en.wikipedia.org/wiki/Actor_model),
|
37
|
-
[Agents](http://doc.akka.io/docs/akka/snapshot/java/agents.html), and
|
38
|
-
[Promises](http://promises-aplus.github.io/promises-spec/). I'm equally fascinated by languages
|
39
|
-
with strong concurrency support like [Erlang](http://www.erlang.org/doc/getting_started/conc_prog.html),
|
40
|
-
[Go](http://golang.org/doc/articles/concurrency_patterns.html), and
|
41
|
-
[Clojure](http://clojure.org/concurrent_programming) (I program with Erlang at work).
|
42
|
-
My goal is to implement those patterns in Ruby. Specifically:
|
37
|
+
My goal is to implement various functional programming patterns in Ruby. Specifically:
|
43
38
|
|
44
39
|
* Stay true to the spirit of the languages providing inspiration
|
45
40
|
* But implement in a way that makes sense for Ruby
|
@@ -51,12 +46,10 @@ My goal is to implement those patterns in Ruby. Specifically:
|
|
51
46
|
|
52
47
|
## Features (and Documentation)
|
53
48
|
|
54
|
-
Several features from Erlang,
|
49
|
+
Several features from Erlang, Go, and Clojure have been implemented thus far:
|
55
50
|
|
56
51
|
* Function overloading with Erlang-style [Pattern Matching](https://github.com/jdantonio/functional-ruby/blob/master/md/pattern_matching.md)
|
57
52
|
* Interface specifications with Erlang-style [Behavior](https://github.com/jdantonio/functional-ruby/blob/master/md/behavior.md)
|
58
|
-
* Chained asynchronous operations inspried by JavaScript [Promises](https://github.com/jdantonio/functional-ruby/blob/master/md/promise.md)
|
59
|
-
* Additional Clojure, Go, and Erlang inspired [Concurrency](https://github.com/jdantonio/functional-ruby/blob/master/md/concurrency.md)
|
60
53
|
* Several useful functional [Utilities](https://github.com/jdantonio/functional-ruby/blob/master/md/utilities.md)
|
61
54
|
|
62
55
|
### Is it any good?
|
@@ -85,30 +78,18 @@ gem 'functional-ruby'
|
|
85
78
|
|
86
79
|
and run `bundle install` from your shell.
|
87
80
|
|
88
|
-
Once you've installed the gem you must `require` it in your project
|
89
|
-
that not all users may want, several `require` options are available:
|
81
|
+
Once you've installed the gem you must `require` it in your project:
|
90
82
|
|
91
83
|
```ruby
|
92
|
-
require 'functional
|
93
|
-
require 'functional/behaviour' # alternate spelling
|
94
|
-
require 'functional/concurrency'
|
95
|
-
require 'functional/pattern_matching'
|
96
|
-
require 'functional/promise'
|
97
|
-
require 'functional/utilities'
|
84
|
+
require 'functional'
|
98
85
|
```
|
99
86
|
|
100
|
-
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
require 'functional/all'
|
104
|
-
```
|
105
|
-
|
106
|
-
## Examples
|
87
|
+
### Examples
|
107
88
|
|
108
89
|
For complete examples, see the specific documentation linked above. Below are a
|
109
90
|
few examples to whet your appetite.
|
110
91
|
|
111
|
-
|
92
|
+
#### Pattern Matching (Erlang)
|
112
93
|
|
113
94
|
Documentation: [Pattern Matching](https://github.com/jdantonio/functional-ruby/blob/master/md/pattern_matching.md)
|
114
95
|
|
@@ -132,7 +113,7 @@ foo.greet(:male) #=> "Hello, sir!"
|
|
132
113
|
foo.greet(:female) #=> "Hello, ma'am!"
|
133
114
|
```
|
134
115
|
|
135
|
-
|
116
|
+
#### Behavior (Erlang)
|
136
117
|
|
137
118
|
Documentation: [Behavior](https://github.com/jdantonio/functional-ruby/blob/master/md/behavior.md)
|
138
119
|
|
@@ -160,100 +141,7 @@ foo.behaves_as?(:bogus) #=> false
|
|
160
141
|
'foo'.behaves_as? :gen_foo #=> false
|
161
142
|
```
|
162
143
|
|
163
|
-
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
require 'functional/concurrency'
|
167
|
-
|
168
|
-
@expected = nil
|
169
|
-
go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
|
170
|
-
sleep(0.1)
|
171
|
-
@expected #=> [3, 2, 1]
|
172
|
-
```
|
173
|
-
|
174
|
-
### Agent (Clojure)
|
175
|
-
|
176
|
-
```ruby
|
177
|
-
require 'functional/agent'
|
178
|
-
# or
|
179
|
-
require 'functional/concurrency'
|
180
|
-
|
181
|
-
score = agent(10)
|
182
|
-
score.value #=> 10
|
183
|
-
|
184
|
-
score << proc{|current| current + 100 }
|
185
|
-
sleep(0.1)
|
186
|
-
score.value #=> 110
|
187
|
-
|
188
|
-
score << proc{|current| current * 2 }
|
189
|
-
sleep(0.1)
|
190
|
-
deref score #=> 220
|
191
|
-
|
192
|
-
score << proc{|current| current - 50 }
|
193
|
-
sleep(0.1)
|
194
|
-
score.value #=> 170
|
195
|
-
```
|
196
|
-
|
197
|
-
### Future (Clojure)
|
198
|
-
|
199
|
-
```ruby
|
200
|
-
require 'functional/future'
|
201
|
-
# or
|
202
|
-
require 'functional/concurrency'
|
203
|
-
|
204
|
-
count = future{ sleep(1); 10 }
|
205
|
-
count.state #=> :pending
|
206
|
-
# do stuff...
|
207
|
-
count.value #=> 10 (after blocking)
|
208
|
-
deref count #=> 10
|
209
|
-
```
|
210
|
-
|
211
|
-
### Promise (JavaScript)
|
212
|
-
|
213
|
-
* [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
|
214
|
-
* [Promises/A+](http://promises-aplus.github.io/promises-spec/)
|
215
|
-
|
216
|
-
```ruby
|
217
|
-
require 'functional/promise'
|
218
|
-
# or
|
219
|
-
require 'functional/concurrency'
|
220
|
-
|
221
|
-
p = promise("Jerry", "D'Antonio"){|a, b| "#{a} #{b}" }.
|
222
|
-
then{|result| "Hello #{result}." }.
|
223
|
-
rescue(StandardError){|ex| puts "Boom!" }.
|
224
|
-
then{|result| "#{result} Would you like to play a game?"}
|
225
|
-
sleep(1)
|
226
|
-
p.value #=> "Hello Jerry D'Antonio. Would you like to play a game?"
|
227
|
-
```
|
228
|
-
|
229
|
-
### Thread Pools
|
230
|
-
|
231
|
-
```ruby
|
232
|
-
require 'functional/fixed_thread_pool'
|
233
|
-
require 'functional/cached_thread_pool'
|
234
|
-
# or
|
235
|
-
require 'functional/concurrency'
|
236
|
-
|
237
|
-
pool = Functional::FixedThreadPool.new(10)
|
238
|
-
@expected = 0
|
239
|
-
pool.post{ sleep(0.5); @expected += 100 }
|
240
|
-
pool.post{ sleep(0.5); @expected += 100 }
|
241
|
-
pool.post{ sleep(0.5); @expected += 100 }
|
242
|
-
@expected #=> nil
|
243
|
-
sleep(1)
|
244
|
-
@expected #=> 300
|
245
|
-
|
246
|
-
pool = Functional::CachedThreadPool.new
|
247
|
-
@expected = 0
|
248
|
-
pool << proc{ sleep(0.5); @expected += 10 }
|
249
|
-
pool << proc{ sleep(0.5); @expected += 10 }
|
250
|
-
pool << proc{ sleep(0.5); @expected += 10 }
|
251
|
-
@expected #=> 0
|
252
|
-
sleep(1)
|
253
|
-
@expected #=> 30
|
254
|
-
```
|
255
|
-
|
256
|
-
### Utilities
|
144
|
+
#### Utilities
|
257
145
|
|
258
146
|
Documentation: [Utilities](https://github.com/jdantonio/functional-ruby/blob/master/md/utilities.md)
|
259
147
|
|
data/lib/functional.rb
CHANGED
data/lib/functional/utilities.rb
CHANGED
@@ -30,6 +30,52 @@ module Kernel
|
|
30
30
|
end
|
31
31
|
module_function :delta
|
32
32
|
|
33
|
+
# Perform an operation numerous times, passing the value of the
|
34
|
+
# previous iteration, and collecting the results into an array.
|
35
|
+
#
|
36
|
+
# @yield iterates over each element in the data set
|
37
|
+
# @yieldparam previous the initial value (or nil) for the first
|
38
|
+
# iteration then the value of the previous iteration for all
|
39
|
+
# subsequent iterations
|
40
|
+
#
|
41
|
+
# @param [Integer] count the number of times to perform the operation
|
42
|
+
# @param [Object] initial the initial value to pass to the first iteration
|
43
|
+
#
|
44
|
+
# @return [Array] the results of the iterations collected into an array
|
45
|
+
def repeatedly(count, initial = nil)
|
46
|
+
return [] if (count = count.to_i) == 0
|
47
|
+
return count.times.collect{ nil } unless block_given?
|
48
|
+
return count.times.collect do
|
49
|
+
initial = yield(initial)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
module_function :repeatedly
|
53
|
+
|
54
|
+
# Try an operation. If it fails (raises an exception), wait a second
|
55
|
+
# and try again. Try no more than the given number of times.
|
56
|
+
#
|
57
|
+
# @yield Tries the given block operation
|
58
|
+
#
|
59
|
+
# @param [Integer] tries The maximum number of times to attempt the operation.
|
60
|
+
# @param [Array] args Optional block arguments
|
61
|
+
#
|
62
|
+
# @return [Boolean] true if the operation succeeds on any attempt,
|
63
|
+
# false if none of the attempts are successful
|
64
|
+
def retro(tries, *args)
|
65
|
+
tries = tries.to_i
|
66
|
+
return false if tries == 0 || ! block_given?
|
67
|
+
yield(*args)
|
68
|
+
return true
|
69
|
+
rescue Exception
|
70
|
+
sleep(1)
|
71
|
+
if (tries = tries - 1) > 0
|
72
|
+
retry
|
73
|
+
else
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
module_function :retro
|
78
|
+
|
33
79
|
# Sandbox the given operation at a high $SAFE level.
|
34
80
|
#
|
35
81
|
# @param args [Array] zero or more arguments to pass to the block
|
data/lib/functional/version.rb
CHANGED
data/lib/functional_ruby.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'functional
|
1
|
+
require 'functional'
|
data/md/utilities.md
CHANGED
@@ -107,7 +107,7 @@ describe '-behavior' do
|
|
107
107
|
|
108
108
|
lambda {
|
109
109
|
clazz.new
|
110
|
-
}.should_not raise_error
|
110
|
+
}.should_not raise_error
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'creates the object when function definitions match' do
|
@@ -120,7 +120,7 @@ describe '-behavior' do
|
|
120
120
|
|
121
121
|
lambda {
|
122
122
|
clazz.new
|
123
|
-
}.should_not raise_error
|
123
|
+
}.should_not raise_error
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -44,7 +44,7 @@ describe PatternMatching do
|
|
44
44
|
|
45
45
|
it 'can pattern match the constructor' do
|
46
46
|
|
47
|
-
unless RUBY_VERSION
|
47
|
+
unless RUBY_VERSION == '1.9.2'
|
48
48
|
subject.defn(:initialize, PatternMatching::UNBOUND, PatternMatching::UNBOUND, PatternMatching::UNBOUND) { 'three args' }
|
49
49
|
subject.defn(:initialize, PatternMatching::UNBOUND, PatternMatching::UNBOUND) { 'two args' }
|
50
50
|
subject.defn(:initialize, PatternMatching::UNBOUND) { 'one arg' }
|
@@ -152,7 +152,7 @@ describe PatternMatching do
|
|
152
152
|
|
153
153
|
lambda {
|
154
154
|
obj.foo
|
155
|
-
}.should_not raise_error
|
155
|
+
}.should_not raise_error
|
156
156
|
end
|
157
157
|
|
158
158
|
it 'does not accept any parameters' do
|
@@ -3,43 +3,125 @@ require 'fakefs/safe'
|
|
3
3
|
|
4
4
|
describe 'utilities' do
|
5
5
|
|
6
|
-
context '#
|
6
|
+
context '#delta' do
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
it 'computes the delta of two positive values' do
|
9
|
+
delta(10.5, 5.0).should be_within(0.01).of(5.5)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
it 'computes the delta of two negative values' do
|
13
|
+
delta(-10.5, -5.0).should be_within(0.01).of(5.5)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
it 'computes the delta of a positive and negative value' do
|
17
|
+
delta(10.5, -5.0).should be_within(0.01).of(15.5)
|
18
18
|
end
|
19
19
|
|
20
|
-
it '
|
21
|
-
|
22
|
-
|
20
|
+
it 'computes the delta of two positive values with a block' do
|
21
|
+
v1 = {:count => 10.5}
|
22
|
+
v2 = {:count => 5.0}
|
23
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
23
24
|
end
|
24
25
|
|
25
|
-
it '
|
26
|
-
|
27
|
-
|
26
|
+
it 'computes the delta of two negative values with a block' do
|
27
|
+
v1 = {:count => -10.5}
|
28
|
+
v2 = {:count => -5.0}
|
29
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
28
30
|
end
|
29
31
|
|
30
|
-
it '
|
31
|
-
|
32
|
-
|
32
|
+
it 'computes the delta of a positive and negative value with a block' do
|
33
|
+
v1 = {:count => 10.5}
|
34
|
+
v2 = {:count => -5.0}
|
35
|
+
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(15.5)
|
33
36
|
end
|
37
|
+
end
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
context '#repeatedly' do
|
40
|
+
|
41
|
+
it 'returns an empty array when requested times is zero' do
|
42
|
+
expected = repeatedly(0){ 1 }
|
43
|
+
expected.should be_empty
|
38
44
|
end
|
39
45
|
|
40
|
-
it 'returns
|
41
|
-
|
42
|
-
|
46
|
+
it 'returns an array with all nil values when no block is given' do
|
47
|
+
expected = repeatedly(10)
|
48
|
+
expected.length.should eq 10
|
49
|
+
expected.each do |elem|
|
50
|
+
elem.should be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'iterates the requested number of times and puts the results into an array' do
|
55
|
+
expected = repeatedly(10){ 5 }
|
56
|
+
expected.length.should eq 10
|
57
|
+
expected.each do |elem|
|
58
|
+
elem.should eq 5
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'passes the initial value to the first iteration' do
|
63
|
+
@expected = nil
|
64
|
+
repeatedly(1,100){|previous| @expected = previous }
|
65
|
+
@expected.should eq 100
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'passes the result of each iteration to the next iteration' do
|
69
|
+
expected = repeatedly(10, 1){|previous| previous * 2 }
|
70
|
+
expected.should eq [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context '#retro' do
|
75
|
+
|
76
|
+
it 'does not run the block if requested times is zero' do
|
77
|
+
@expected = true
|
78
|
+
retro(0){ @expected = false }
|
79
|
+
@expected.should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'passes all arguments to the block' do
|
83
|
+
@expected = nil
|
84
|
+
retro(1, ?a, ?b, ?c){|*args| @expected = args }
|
85
|
+
@expected.should eq [?a, ?b, ?c]
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'calls the block once if the first pass is successful' do
|
89
|
+
@expected = 0
|
90
|
+
retro(5){ @expected += 1 }
|
91
|
+
@expected.should eq 1
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'calls the block more than once if the first pass fails' do
|
95
|
+
@expected = 0
|
96
|
+
retro(5) do
|
97
|
+
@expected += 1
|
98
|
+
raise StandardError if @expected < 3
|
99
|
+
end
|
100
|
+
@expected.should eq 3
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'calls the block no more than the requested number of times' do
|
104
|
+
@expected = 0
|
105
|
+
retro(5) do
|
106
|
+
@expected += 1
|
107
|
+
raise StandardError
|
108
|
+
end
|
109
|
+
@expected.should eq 5
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns true if any attempt succeeds' do
|
113
|
+
expected = retro(1){ nil }
|
114
|
+
expected.should be_true
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'returns false if all attempts fail' do
|
118
|
+
expected = retro(1){ raise StandardError }
|
119
|
+
expected.should be_false
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns false if no block is given' do
|
123
|
+
expected = retro(10)
|
124
|
+
expected.should eq false
|
43
125
|
end
|
44
126
|
end
|
45
127
|
|
@@ -48,7 +130,7 @@ describe 'utilities' do
|
|
48
130
|
it 'allows safe operations' do
|
49
131
|
lambda {
|
50
132
|
safe{ 1 + 1 }
|
51
|
-
}.should_not raise_error
|
133
|
+
}.should_not raise_error
|
52
134
|
end
|
53
135
|
|
54
136
|
it 'returns the value of the block when safe' do
|
@@ -113,37 +195,43 @@ describe 'utilities' do
|
|
113
195
|
end
|
114
196
|
end
|
115
197
|
|
116
|
-
context '#
|
198
|
+
context '#repl?' do
|
117
199
|
|
118
|
-
|
119
|
-
|
200
|
+
before(:each) do
|
201
|
+
@dollar_zero = $0
|
120
202
|
end
|
121
203
|
|
122
|
-
|
123
|
-
|
204
|
+
after(:each) do
|
205
|
+
$0 = @dollar_zero
|
124
206
|
end
|
125
207
|
|
126
|
-
|
127
|
-
|
208
|
+
def set_dollar_zero(val)
|
209
|
+
$0 = val
|
128
210
|
end
|
129
211
|
|
130
|
-
it '
|
131
|
-
|
132
|
-
|
133
|
-
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
212
|
+
it 'recognizes IRB' do
|
213
|
+
set_dollar_zero('irb')
|
214
|
+
repl?.should be_true
|
134
215
|
end
|
135
216
|
|
136
|
-
it '
|
137
|
-
|
138
|
-
|
139
|
-
delta(v1, v2){|x| x[:count]}.should be_within(0.01).of(5.5)
|
217
|
+
it 'recognizes Pry' do
|
218
|
+
set_dollar_zero('pry')
|
219
|
+
repl?.should be_true
|
140
220
|
end
|
141
221
|
|
142
|
-
it '
|
143
|
-
|
144
|
-
|
145
|
-
|
222
|
+
it 'recognizes Rails Console' do
|
223
|
+
set_dollar_zero('script/rails')
|
224
|
+
repl?.should be_true
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'recognizes Bundle Console' do
|
228
|
+
set_dollar_zero('bin/bundle')
|
229
|
+
repl?.should be_true
|
146
230
|
end
|
147
|
-
end
|
148
231
|
|
232
|
+
it 'returns false when not in a REPL' do
|
233
|
+
set_dollar_zero(__FILE__)
|
234
|
+
repl?.should be_false
|
235
|
+
end
|
236
|
+
end
|
149
237
|
end
|