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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c798e8848a4a1a3e47077fa48ac65c0595df304
4
- data.tar.gz: 0785957a5566c7fe58c753d8a2c09b040e11a17c
3
+ metadata.gz: 7ebc0dab7cc6ee079416729c8cc131bf239ca2bb
4
+ data.tar.gz: 24b3193d7e6fef20addd8688ab372c104163edae
5
5
  SHA512:
6
- metadata.gz: 7e2bd7f3b530d2c95134733f2a275ed2eb5ea16a68aac88ae9bbc9f50a9391a277afbf1608b9b15e7a25df193179523f5b6da920751e5e64f5255841823ebc6e
7
- data.tar.gz: 46a8e971f0c9e39f4287c3b743495678975a7fac5f22dbb607b9ec10321e5e2c27ee120bcf67a6d8adde48d4a7b95b910f65a7be0fe38931481153bf0b7afecf
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 concurrency and functional programming tools to Ruby.
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/master/frames)
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, concurrent programming language.
33
+ a highly performant, functional programming language.
31
34
 
32
35
  ### Goals
33
36
 
34
- My history with high-performance, highly-concurrent programming goes back to my days with C/C++.
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, Co, Clojure, and JavaScript have been implemented this far:
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. Becuase this gem includes multiple features
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/behavior'
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
- If you want everything you can do that, too:
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
- ### Pattern Matching (Erlang)
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
- ### Behavior (Erlang)
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
- ### Goroutine (Go)
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
 
@@ -1 +1,4 @@
1
- require 'functional/all'
1
+ require 'functional/behavior'
2
+ require 'functional/pattern_matching'
3
+ require 'functional/utilities'
4
+ require 'functional/version'
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Functional
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -1 +1 @@
1
- require 'functional/all'
1
+ require 'functional'
@@ -21,6 +21,8 @@ pp_s [1,2,3,4] #=> "[1, 2, 3, 4]\n" props to Rha7
21
21
 
22
22
  delta(-1, 1) #=> 2
23
23
  delta({count: -1}, {count: 1}){|item| item[:count]} #=> 2
24
+
25
+ repeatedly(10, 1){|previous| previous * 2 } #=> [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
24
26
  ```
25
27
 
26
28
  ## Copyright
@@ -107,7 +107,7 @@ describe '-behavior' do
107
107
 
108
108
  lambda {
109
109
  clazz.new
110
- }.should_not raise_error(BehaviorError)
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(BehaviorError)
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 = '1.9.2'
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(NoMethodError)
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 '#repl?' do
6
+ context '#delta' do
7
7
 
8
- before(:each) do
9
- @dollar_zero = $0
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
- after(:each) do
13
- $0 = @dollar_zero
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
- def set_dollar_zero(val)
17
- $0 = val
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 'recognizes IRB' do
21
- set_dollar_zero('irb')
22
- repl?.should be_true
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 'recognizes Pry' do
26
- set_dollar_zero('pry')
27
- repl?.should be_true
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 'recognizes Rails Console' do
31
- set_dollar_zero('script/rails')
32
- repl?.should be_true
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
- it 'recognizes Bundle Console' do
36
- set_dollar_zero('bin/bundle')
37
- repl?.should be_true
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 false when not in a REPL' do
41
- set_dollar_zero(__FILE__)
42
- repl?.should be_false
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(SecurityError)
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 '#delta' do
198
+ context '#repl?' do
117
199
 
118
- it 'computes the delta of two positive values' do
119
- delta(10.5, 5.0).should be_within(0.01).of(5.5)
200
+ before(:each) do
201
+ @dollar_zero = $0
120
202
  end
121
203
 
122
- it 'computes the delta of two negative values' do
123
- delta(-10.5, -5.0).should be_within(0.01).of(5.5)
204
+ after(:each) do
205
+ $0 = @dollar_zero
124
206
  end
125
207
 
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)
208
+ def set_dollar_zero(val)
209
+ $0 = val
128
210
  end
129
211
 
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)
212
+ it 'recognizes IRB' do
213
+ set_dollar_zero('irb')
214
+ repl?.should be_true
134
215
  end
135
216
 
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)
217
+ it 'recognizes Pry' do
218
+ set_dollar_zero('pry')
219
+ repl?.should be_true
140
220
  end
141
221
 
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)
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