ione 1.2.2 → 1.2.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 941fc3fd59d15b806854ddd8ff0f30f645ff51bf
4
- data.tar.gz: 1b89b672b8b69eda9561138190aed7d35d677538
2
+ SHA256:
3
+ metadata.gz: 9c062de288365ad9e47516ad7b9d3ab028ab9449964c88675c0b913657a8ef07
4
+ data.tar.gz: f349d422d1df3001a9c5fb5df55c329ed60cebc9dad20ddf1a97f52883c53093
5
5
  SHA512:
6
- metadata.gz: f26209edcf366c70ac80a913901f4c6db5a7a15e2e4a9c53e0d73f99b9d1e25e98bd4f0533dc4e88d3ec846abd538b6f80cb9d877ae547091a363121d1a05992
7
- data.tar.gz: 6c5565772dd3994caac71ffd2a63cf25f2c595161eeb501928050123c59b5579cf1d5a45ac4a0e585ca15fd9c82b9c7f1253135c2e6f74cf0e9569a89e66d1dc
6
+ metadata.gz: 4523ab1052502a8da1879f73481f8326b260b478d71c7e9d882b264e2c274092ae0801a43c5884492ea06fd69dd3ac02ab184ef309dbcf1cf5b8d441f37e8bd6
7
+ data.tar.gz: 1e5d1c7f51593988a2270ec4c6b74cd61d72a1dd2c6a69d5c6f4b2053052aa4ee3bd52375c4e419d423110bd70994350662a61850907570db47ea45c24a7575b
@@ -179,10 +179,12 @@ module Ione
179
179
  swap_buffers
180
180
  end
181
181
  read_buffer_length = @read_buffer.bytesize
182
- if start_index < read_buffer_length - @offset && (index = @read_buffer.index(substring, @offset + start_index))
182
+ if start_index + substring.bytesize <= read_buffer_length - @offset && (index = @read_buffer.index(substring, @offset + start_index))
183
183
  index - @offset
184
- elsif (index = @write_buffer.index(substring, start_index - read_buffer_length + @offset))
185
- index + read_buffer_length - @offset
184
+ elsif start_index + substring.bytesize <= read_buffer_length - @offset + @write_buffer.bytesize
185
+ merge_read_buffer
186
+ start_index = read_buffer_length - substring.bytesize if read_buffer_length - substring.bytesize > start_index
187
+ @read_buffer.index(substring, start_index)
186
188
  else
187
189
  nil
188
190
  end
@@ -298,5 +300,11 @@ module Ione
298
300
  @read_buffer = @write_buffer
299
301
  @write_buffer = ''
300
302
  end
303
+
304
+ def merge_read_buffer
305
+ @read_buffer = @read_buffer[@offset, @read_buffer.length - @offset] << @write_buffer
306
+ @write_buffer = ''
307
+ @offset = 0
308
+ end
301
309
  end
302
310
  end
data/lib/ione/future.rb CHANGED
@@ -209,6 +209,8 @@ module Ione
209
209
  end
210
210
  if futures.count == 0
211
211
  resolved([])
212
+ elsif (failed = futures.find { |f| f.respond_to?(:failed?) && f.failed? })
213
+ failed
212
214
  else
213
215
  CombinedFuture.new(futures)
214
216
  end
@@ -231,6 +233,7 @@ module Ione
231
233
  if futures.size == 1 && (fs = futures.first).is_a?(Enumerable)
232
234
  *futures = *fs
233
235
  end
236
+ futures.reject! { |f| f.respond_to?(:resolved?) && f.resolved? }
234
237
  if futures.count == 0
235
238
  ResolvedFuture::NIL
236
239
  elsif futures.count == 1
@@ -262,7 +265,9 @@ module Ione
262
265
  futures = fs
263
266
  end
264
267
  if futures.count == 0
265
- resolved
268
+ ResolvedFuture::NIL
269
+ elsif (done = futures.find { |f| f.respond_to?(:resolved?) && f.resolved? })
270
+ done
266
271
  else
267
272
  FirstFuture.new(futures)
268
273
  end
@@ -594,6 +599,8 @@ module Ione
594
599
  @lock = Mutex.new
595
600
  @state = PENDING_STATE
596
601
  @listeners = []
602
+ @value = nil
603
+ @error = nil
597
604
  end
598
605
 
599
606
  # Registers a listener that will be called when this future completes,
@@ -854,9 +861,9 @@ module Ione
854
861
  looping = more = true
855
862
  while more
856
863
  more = false
857
- @futures.pop.on_complete do |v, e|
858
- if e || @futures.empty? || !looping || !Thread.current.equal?(outer)
859
- await_next(v, e)
864
+ @futures.pop.on_complete do |value, error|
865
+ if error || @futures.empty? || !looping || !Thread.current.equal?(outer)
866
+ await_next(value, error)
860
867
  else
861
868
  more = true
862
869
  end
@@ -874,64 +881,56 @@ module Ione
874
881
  def initialize(futures, initial_value, reducer)
875
882
  super()
876
883
  @futures = Array(futures)
877
- @remaining = @futures.size
878
- @initial_value = initial_value
879
- @accumulator = initial_value.nil? ? NO_INITIAL_VALUE : initial_value
884
+ @initial_value = initial_value.nil? ? NO_INITIAL_VALUE : initial_value
880
885
  @reducer = reducer
881
886
  end
882
-
883
- private
884
-
885
- def reduce_one(value)
886
- unless failed?
887
- @lock.lock
888
- begin
889
- if @accumulator.equal?(NO_INITIAL_VALUE)
890
- @accumulator = value
891
- else
892
- @accumulator = @reducer.call(@accumulator, value)
893
- end
894
- @remaining -= 1
895
- rescue => e
896
- @lock.unlock
897
- fail(e)
898
- else
899
- @lock.unlock
900
- end
901
- unless failed?
902
- if @remaining == 0
903
- resolve(@accumulator)
904
- :done
905
- else
906
- :continue
907
- end
908
- end
909
- end
910
- end
911
887
  end
912
888
 
913
889
  # @private
914
890
  class OrderedReducingFuture < ReducingFuture
915
891
  def initialize(futures, initial_value, reducer)
916
892
  super
917
- if @remaining > 0
918
- reduce_next(0)
893
+ if @futures.empty?
894
+ resolve(@initial_value.equal?(NO_INITIAL_VALUE) ? nil : @initial_value)
895
+ elsif @initial_value.equal?(NO_INITIAL_VALUE)
896
+ @futures.shift.on_complete(&method(:reduce_next))
919
897
  else
920
- resolve(@initial_value)
898
+ reduce_next(@initial_value, nil)
921
899
  end
922
900
  end
923
901
 
924
902
  private
925
903
 
926
- def reduce_next(i)
927
- @futures[i].on_complete do |v, e|
928
- unless failed?
929
- if e
930
- fail(e)
931
- elsif reduce_one(v) == :continue
932
- reduce_next(i + 1)
904
+ def reduce_next(accumulator, e)
905
+ if e
906
+ @futures = nil
907
+ fail(e)
908
+ elsif @futures.empty?
909
+ @futures = nil
910
+ resolve(accumulator)
911
+ else
912
+ outer = Thread.current
913
+ looping = more = true
914
+ while more
915
+ more = false
916
+ @futures.shift.on_complete do |v, ee|
917
+ if ee
918
+ reduce_next(nil, ee)
919
+ else
920
+ begin
921
+ accumulator = @reducer.call(accumulator, v)
922
+ if @futures.empty? || !looping || !Thread.current.equal?(outer)
923
+ reduce_next(accumulator, nil)
924
+ else
925
+ more = true
926
+ end
927
+ rescue => eee
928
+ reduce_next(nil, eee)
929
+ end
930
+ end
933
931
  end
934
932
  end
933
+ looping = false
935
934
  end
936
935
  end
937
936
  end
@@ -940,20 +939,37 @@ module Ione
940
939
  class UnorderedReducingFuture < ReducingFuture
941
940
  def initialize(futures, initial_value, reducer)
942
941
  super
943
- if @remaining > 0
944
- futures.each do |f|
942
+ if @futures.empty?
943
+ resolve(@initial_value.equal?(NO_INITIAL_VALUE) ? nil : @initial_value)
944
+ else
945
+ accumulator = @initial_value
946
+ remaining = @futures.size
947
+ @futures.each do |f|
945
948
  f.on_complete do |v, e|
946
949
  unless failed?
947
950
  if e
948
951
  fail(e)
949
952
  else
950
- reduce_one(v)
953
+ done = false
954
+ @lock.lock
955
+ begin
956
+ accumulator = accumulator.equal?(NO_INITIAL_VALUE) ? v : @reducer.call(accumulator, v)
957
+ remaining -= 1
958
+ done = (remaining == 0)
959
+ rescue => ee
960
+ @lock.unlock
961
+ fail(ee)
962
+ else
963
+ @lock.unlock
964
+ end
965
+ if done
966
+ @futures = nil
967
+ resolve(accumulator)
968
+ end
951
969
  end
952
970
  end
953
971
  end
954
972
  end
955
- else
956
- resolve(@initial_value)
957
973
  end
958
974
  end
959
975
  end
@@ -22,6 +22,7 @@ module Ione
22
22
  @backlog = backlog
23
23
  @unblocker = unblocker
24
24
  @reactor = reactor
25
+ @io = nil
25
26
  @socket_impl = socket_impl || ServerSocket
26
27
  @accept_listeners = []
27
28
  @lock = Mutex.new
@@ -15,10 +15,12 @@ module Ione
15
15
  def initialize(host, port, unblocker)
16
16
  @host = host
17
17
  @port = port
18
+ @io = nil
18
19
  @unblocker = unblocker
19
20
  @state = CONNECTING_STATE
20
21
  @writable = false
21
22
  @lock = Mutex.new
23
+ @data_listener = nil
22
24
  @write_buffer = ByteBuffer.new
23
25
  @closed_promise = Promise.new
24
26
  end
@@ -14,6 +14,7 @@ module Ione
14
14
  @connection_timeout = connection_timeout
15
15
  @clock = clock
16
16
  @socket_impl = socket_impl
17
+ @addrinfos = nil
17
18
  @connected_promise = Promise.new
18
19
  on_closed(&method(:cleanup_on_close))
19
20
  end
@@ -95,8 +95,9 @@ module Ione
95
95
  @clock = options[:clock] || Time
96
96
  @state = PENDING_STATE
97
97
  @error_listeners = []
98
+ @unblocker = nil
98
99
  @io_loop = IoLoopBody.new(@options)
99
- @scheduler = Scheduler.new
100
+ @scheduler = Scheduler.new(@options)
100
101
  @lock = Mutex.new
101
102
  end
102
103
 
@@ -124,7 +125,7 @@ module Ione
124
125
  # after {#stop} has been called, but false when the future returned by
125
126
  # {#stop} completes.
126
127
  def running?
127
- @state == RUNNING_STATE
128
+ (state = @state) == RUNNING_STATE || state == STOPPING_STATE
128
129
  end
129
130
 
130
131
  # Starts the reactor. This will spawn a background thread that will manage
@@ -570,8 +571,8 @@ module Ione
570
571
  ensure
571
572
  @lock.unlock
572
573
  end
573
- timers.each do |timer|
574
- timer.fail(CancelledError.new)
574
+ timers.each do |t|
575
+ t.fail(CancelledError.new)
575
576
  end
576
577
  nil
577
578
  end
@@ -592,8 +593,8 @@ module Ione
592
593
  ensure
593
594
  @lock.unlock
594
595
  end
595
- expired_timers.each do |timer|
596
- timer.fulfill
596
+ expired_timers.each do |t|
597
+ t.fulfill
597
598
  end
598
599
  end
599
600
  end
@@ -604,4 +605,4 @@ module Ione
604
605
  end
605
606
  end
606
607
  end
607
- end
608
+ end
@@ -12,6 +12,7 @@ module Ione
12
12
  @socket_impl = socket_impl
13
13
  @ssl_context = ssl_context
14
14
  @raw_io = io
15
+ @io = nil
15
16
  @connected_promise = Promise.new
16
17
  on_closed(&method(:cleanup_on_close))
17
18
  end
data/lib/ione/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Ione
4
- VERSION = '1.2.2'.freeze
4
+ VERSION = '1.2.5'.freeze
5
5
  end
@@ -37,7 +37,7 @@ describe 'An IO reactor' do
37
37
  fake_server.await_connects(1)
38
38
  fake_server.broadcast('hello world')
39
39
  await { protocol_handler.data.bytesize > 0 }
40
- protocol_handler.data.should == 'hello world'
40
+ protocol_handler.data.should eq('hello world')
41
41
  end
42
42
 
43
43
  it 'receives data on multiple connections' do
@@ -45,7 +45,7 @@ describe 'An IO reactor' do
45
45
  fake_server.await_connects(10)
46
46
  fake_server.broadcast('hello world')
47
47
  await { protocol_handlers.all? { |c| c.data.bytesize > 0 } }
48
- protocol_handlers.sample.data.should == 'hello world'
48
+ protocol_handlers.sample.data.should eq('hello world')
49
49
  end
50
50
  end
51
51
 
@@ -81,7 +81,7 @@ describe 'An IO reactor' do
81
81
  socket = TCPSocket.new(ENV['SERVER_HOST'], port)
82
82
  socket.puts('HELLO')
83
83
  result = socket.read(5)
84
- result.should == 'HELLO'
84
+ result.should eq('HELLO')
85
85
  socket.close
86
86
  end
87
87
  end
@@ -49,6 +49,7 @@ describe 'SSL' do
49
49
  ssl_context = OpenSSL::SSL::SSLContext.new
50
50
  ssl_context.key = OpenSSL::PKey::RSA.new(ssl_key)
51
51
  ssl_context.cert = OpenSSL::X509::Certificate.new(ssl_cert)
52
+ ssl_context.tmp_dh_callback = proc { SslSpec::DH_PARAMS }
52
53
 
53
54
  f = io_reactor.start
54
55
  f = f.flat_map do
@@ -80,8 +81,8 @@ describe 'SSL' do
80
81
  end
81
82
  client.write('hello world')
82
83
  response_received.future.value
83
- server_received_data.to_s.should == 'hello world'
84
- client_received_data.to_s.should == 'dlrow olleh'
84
+ server_received_data.to_s.should eq('hello world')
85
+ client_received_data.to_s.should eq('dlrow olleh')
85
86
  end
86
87
 
87
88
  it 'fails to send a message when not using encryption' do
@@ -95,3 +96,7 @@ describe 'SSL' do
95
96
  client.should be_closed
96
97
  end
97
98
  end
99
+
100
+ module SslSpec
101
+ DH_PARAMS = OpenSSL::PKey::DH.new(File.read(File.expand_path('../../resources/dh.pem', __FILE__)))
102
+ end
@@ -15,28 +15,28 @@ module Ione
15
15
  end
16
16
 
17
17
  it 'can be initialized with bytes' do
18
- described_class.new('hello').length.should == 5
18
+ described_class.new('hello').length.should eq(5)
19
19
  end
20
20
  end
21
21
 
22
22
  describe '#length/#size/#bytesize' do
23
23
  it 'returns the number of bytes in the buffer' do
24
24
  buffer << 'foo'
25
- buffer.length.should == 3
25
+ buffer.length.should eq(3)
26
26
  end
27
27
 
28
28
  it 'is zero initially' do
29
- buffer.length.should == 0
29
+ buffer.length.should eq(0)
30
30
  end
31
31
 
32
32
  it 'is aliased as #size' do
33
33
  buffer << 'foo'
34
- buffer.size.should == 3
34
+ buffer.size.should eq(3)
35
35
  end
36
36
 
37
37
  it 'is aliased as #bytesize' do
38
38
  buffer << 'foo'
39
- buffer.bytesize.should == 3
39
+ buffer.bytesize.should eq(3)
40
40
  end
41
41
  end
42
42
 
@@ -67,19 +67,19 @@ module Ione
67
67
  end
68
68
 
69
69
  it 'stores its bytes as binary' do
70
- buffer.append('hällö').length.should == 7
71
- buffer.to_s.encoding.should == ::Encoding::BINARY
70
+ buffer.append('hällö').length.should eq(7)
71
+ buffer.to_s.encoding.should eq(::Encoding::BINARY)
72
72
  end
73
73
 
74
74
  it 'handles appending with multibyte strings' do
75
75
  buffer.append('hello')
76
76
  buffer.append('würld')
77
- buffer.to_s.should == 'hellowürld'.force_encoding(::Encoding::BINARY)
77
+ buffer.to_s.should eq('hellowürld'.force_encoding(::Encoding::BINARY))
78
78
  end
79
79
 
80
80
  it 'handles appending with another byte buffer' do
81
81
  buffer.append('hello ').append(ByteBuffer.new('world'))
82
- buffer.to_s.should == 'hello world'
82
+ buffer.to_s.should eq('hello world')
83
83
  end
84
84
  end
85
85
 
@@ -105,7 +105,7 @@ module Ione
105
105
  b2 = described_class.new
106
106
  b1.append('foo')
107
107
  b2.append('foo')
108
- b1.should == b2
108
+ b1.should eq(b2)
109
109
  end
110
110
 
111
111
  it 'is equal to another buffer when both are empty' do
@@ -121,7 +121,7 @@ module Ione
121
121
  b2 = described_class.new
122
122
  b1.append('foo')
123
123
  b2.append('foo')
124
- b1.hash.should == b2.hash
124
+ b1.hash.should eq(b2.hash)
125
125
  end
126
126
 
127
127
  it 'is not equal to the hash code of another buffer with other contents' do
@@ -135,26 +135,26 @@ module Ione
135
135
  it 'is equal to the hash code of another buffer when both are empty' do
136
136
  b1 = described_class.new
137
137
  b2 = described_class.new
138
- b1.hash.should == b2.hash
138
+ b1.hash.should eq(b2.hash)
139
139
  end
140
140
  end
141
141
 
142
142
  describe '#to_s' do
143
143
  it 'returns the bytes' do
144
- buffer.append('hello world').to_s.should == 'hello world'
144
+ buffer.append('hello world').to_s.should eq('hello world')
145
145
  end
146
146
  end
147
147
 
148
148
  describe '#to_str' do
149
149
  it 'returns the bytes' do
150
- buffer.append('hello world').to_str.should == 'hello world'
150
+ buffer.append('hello world').to_str.should eq('hello world')
151
151
  end
152
152
  end
153
153
 
154
154
  describe '#inspect' do
155
155
  it 'returns the bytes wrapped in ByteBuffer(...)' do
156
156
  buffer.append("\xca\xfe")
157
- buffer.inspect.should == '#<Ione::ByteBuffer: "\xCA\xFE">'
157
+ buffer.inspect.should eq('#<Ione::ByteBuffer: "\xCA\xFE">')
158
158
  end
159
159
  end
160
160
 
@@ -162,12 +162,12 @@ module Ione
162
162
  it 'discards the specified number of bytes from the front of the buffer' do
163
163
  buffer.append('hello world')
164
164
  buffer.discard(4)
165
- buffer.should == ByteBuffer.new('o world')
165
+ buffer.should eq(ByteBuffer.new('o world'))
166
166
  end
167
167
 
168
168
  it 'returns the byte buffer' do
169
169
  buffer.append('hello world')
170
- buffer.discard(4).should == ByteBuffer.new('o world')
170
+ buffer.discard(4).should eq(ByteBuffer.new('o world'))
171
171
  end
172
172
 
173
173
  it 'raises an error if the number of bytes in the buffer is fewer than the number to discard' do
@@ -185,14 +185,14 @@ module Ione
185
185
  describe '#read' do
186
186
  it 'returns the specified number of bytes, as a string' do
187
187
  buffer.append('hello')
188
- buffer.read(4).should == 'hell'
188
+ buffer.read(4).should eq('hell')
189
189
  end
190
190
 
191
191
  it 'removes the bytes from the buffer' do
192
192
  buffer.append('hello')
193
193
  buffer.read(3)
194
- buffer.should == ByteBuffer.new('lo')
195
- buffer.read(2).should == 'lo'
194
+ buffer.should eq(ByteBuffer.new('lo'))
195
+ buffer.read(2).should eq('lo')
196
196
  end
197
197
 
198
198
  it 'raises an error if there are not enough bytes' do
@@ -208,22 +208,22 @@ module Ione
208
208
 
209
209
  it 'returns a string with binary encoding' do
210
210
  buffer.append('hello')
211
- buffer.read(4).encoding.should == ::Encoding::BINARY
211
+ buffer.read(4).encoding.should eq(::Encoding::BINARY)
212
212
  buffer.append('∆')
213
- buffer.read(2).encoding.should == ::Encoding::BINARY
213
+ buffer.read(2).encoding.should eq(::Encoding::BINARY)
214
214
  end
215
215
  end
216
216
 
217
217
  describe '#read_int' do
218
218
  it 'returns the first four bytes interpreted as an int' do
219
219
  buffer.append("\xca\xfe\xba\xbe\x01")
220
- buffer.read_int.should == 0xcafebabe
220
+ buffer.read_int.should eq(0xcafebabe)
221
221
  end
222
222
 
223
223
  it 'removes the bytes from the buffer' do
224
224
  buffer.append("\xca\xfe\xba\xbe\x01")
225
225
  buffer.read_int
226
- buffer.should == ByteBuffer.new("\x01")
226
+ buffer.should eq(ByteBuffer.new("\x01"))
227
227
  end
228
228
 
229
229
  it 'raises an error if there are not enough bytes' do
@@ -235,13 +235,13 @@ module Ione
235
235
  describe '#read_short' do
236
236
  it 'returns the first two bytes interpreted as a short' do
237
237
  buffer.append("\xca\xfe\x01")
238
- buffer.read_short.should == 0xcafe
238
+ buffer.read_short.should eq(0xcafe)
239
239
  end
240
240
 
241
241
  it 'removes the bytes from the buffer' do
242
242
  buffer.append("\xca\xfe\x01")
243
243
  buffer.read_short
244
- buffer.should == ByteBuffer.new("\x01")
244
+ buffer.should eq(ByteBuffer.new("\x01"))
245
245
  end
246
246
 
247
247
  it 'raises an error if there are not enough bytes' do
@@ -253,14 +253,14 @@ module Ione
253
253
  describe '#read_byte' do
254
254
  it 'returns the first bytes interpreted as an int' do
255
255
  buffer.append("\x10\x01")
256
- buffer.read_byte.should == 0x10
257
- buffer.read_byte.should == 0x01
256
+ buffer.read_byte.should eq(0x10)
257
+ buffer.read_byte.should eq(0x01)
258
258
  end
259
259
 
260
260
  it 'removes the byte from the buffer' do
261
261
  buffer.append("\x10\x01")
262
262
  buffer.read_byte
263
- buffer.should == ByteBuffer.new("\x01")
263
+ buffer.should eq(ByteBuffer.new("\x01"))
264
264
  end
265
265
 
266
266
  it 'raises an error if there are no bytes' do
@@ -269,8 +269,8 @@ module Ione
269
269
 
270
270
  it 'can interpret the byte as signed' do
271
271
  buffer.append("\x81\x02")
272
- buffer.read_byte(true).should == -127
273
- buffer.read_byte(true).should == 2
272
+ buffer.read_byte(true).should eq(-127)
273
+ buffer.read_byte(true).should eq(2)
274
274
  end
275
275
  end
276
276
 
@@ -278,14 +278,14 @@ module Ione
278
278
  it 'changes the bytes at the specified location' do
279
279
  buffer.append('foo bar')
280
280
  buffer.update(4, 'baz')
281
- buffer.to_s.should == 'foo baz'
281
+ buffer.to_s.should eq('foo baz')
282
282
  end
283
283
 
284
284
  it 'handles updates after a read' do
285
285
  buffer.append('foo bar')
286
286
  buffer.read(1)
287
287
  buffer.update(3, 'baz')
288
- buffer.to_s.should == 'oo baz'
288
+ buffer.to_s.should eq('oo baz')
289
289
  end
290
290
 
291
291
  it 'handles updates after multiple reads and appends' do
@@ -295,7 +295,7 @@ module Ione
295
295
  buffer.update(4, 'baz')
296
296
  buffer.append('yyyy')
297
297
  buffer.read(1)
298
- buffer.to_s.should == 'o bbazyyyy'
298
+ buffer.to_s.should eq('o bbazyyyy')
299
299
  end
300
300
 
301
301
  it 'returns itself' do
@@ -335,12 +335,12 @@ module Ione
335
335
  describe '#index' do
336
336
  it 'returns the first index of the specified substring' do
337
337
  buffer.append('fizz buzz')
338
- buffer.index('zz').should == 2
338
+ buffer.index('zz').should eq(2)
339
339
  end
340
340
 
341
341
  it 'returns the first index of the specified substring, after the specified index' do
342
342
  buffer.append('fizz buzz')
343
- buffer.index('zz', 3).should == 7
343
+ buffer.index('zz', 3).should eq(7)
344
344
  end
345
345
 
346
346
  it 'returns nil when the substring is not found' do
@@ -352,7 +352,21 @@ module Ione
352
352
  buffer.append('foo bar')
353
353
  buffer.read(1)
354
354
  buffer.append(' baz baz')
355
- buffer.index('baz', 8).should == 11
355
+ buffer.index('baz', 8).should eq(11)
356
+ end
357
+
358
+ it 'returns the first index when the matching substring spans the read and write buffer' do
359
+ buffer.append('foo bar')
360
+ buffer.read(1)
361
+ buffer.append('bar barbar')
362
+ buffer.index('barbar', 0).should eq(3)
363
+ end
364
+
365
+ it 'returns nil when the substring does not fit in the search space' do
366
+ buffer.append('foo')
367
+ buffer.read(1)
368
+ buffer.append('bar')
369
+ buffer.index('bar', 3).should be_nil
356
370
  end
357
371
  end
358
372