io_unblock 0.1.1 → 0.1.2
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.
- data/lib/io_unblock.rb +6 -6
- data/lib/io_unblock/buffer.rb +4 -4
- data/lib/io_unblock/errors.rb +4 -0
- data/lib/io_unblock/stream.rb +37 -16
- data/lib/io_unblock/tcp_socket.rb +16 -0
- data/lib/io_unblock/version.rb +1 -1
- data/spec/io_unblock/buffer_spec.rb +16 -16
- data/spec/io_unblock/stream_spec.rb +35 -0
- data/spec/io_unblock/tcp_socket_spec.rb +70 -0
- data/spec/spec_helper.rb +4 -68
- data/spec/support/dummy_io.rb +70 -0
- data/spec/support/stubz.rb +49 -0
- metadata +14 -6
data/lib/io_unblock.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
require 'thread'
|
|
2
|
-
require
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
end
|
|
7
|
-
|
|
2
|
+
require 'socket'
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require 'io_unblock/version'
|
|
5
|
+
require 'io_unblock/errors'
|
|
8
6
|
require 'io_unblock/delegation'
|
|
9
7
|
require 'io_unblock/buffer'
|
|
10
8
|
require 'io_unblock/stream'
|
|
9
|
+
require 'io_unblock/tcp_socket'
|
|
10
|
+
|
data/lib/io_unblock/buffer.rb
CHANGED
|
@@ -9,16 +9,16 @@ module IoUnblock
|
|
|
9
9
|
@mutex = Mutex.new
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def push bytes, cb
|
|
13
|
-
synched { @buffer.push [bytes, cb] }
|
|
12
|
+
def push bytes, cb, cb_args
|
|
13
|
+
synched { @buffer.push [bytes, cb, cb_args] }
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def pop
|
|
17
17
|
synched { @buffer.pop }
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def unshift bytes, cb
|
|
21
|
-
synched { @buffer.unshift [bytes, cb] }
|
|
20
|
+
def unshift bytes, cb, cb_args
|
|
21
|
+
synched { @buffer.unshift [bytes, cb, cb_args] }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def shift
|
data/lib/io_unblock/stream.rb
CHANGED
|
@@ -54,35 +54,55 @@ module IoUnblock
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def stop
|
|
57
|
-
@
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
57
|
+
if @processor == Thread.current
|
|
58
|
+
stop_inside
|
|
59
|
+
else
|
|
60
|
+
stop_outside
|
|
62
61
|
end
|
|
63
62
|
self
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
# The callback triggered here will be invoked only when all bytes
|
|
67
66
|
# have been written.
|
|
68
|
-
def write bytes, &cb
|
|
69
|
-
@w_buff.push bytes, cb
|
|
67
|
+
def write bytes, *cb_args, &cb
|
|
68
|
+
@w_buff.push bytes, cb, cb_args
|
|
70
69
|
self
|
|
71
70
|
end
|
|
71
|
+
|
|
72
|
+
def alive?
|
|
73
|
+
@processor && @processor.alive?
|
|
74
|
+
end
|
|
72
75
|
|
|
73
76
|
private
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
def stop_inside
|
|
78
|
+
@running = false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def stop_outside
|
|
82
|
+
@s_mutex.synchronize do
|
|
83
|
+
if @running
|
|
84
|
+
@running = false
|
|
85
|
+
@processor.join
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def guard_callback named, cb, *args
|
|
91
|
+
cb && cb.call(*args)
|
|
77
92
|
rescue Exception => ex
|
|
78
93
|
if named == :callback_failed
|
|
79
94
|
warn "Exception raised in callback_failed handler: #{ex}"
|
|
80
|
-
ex.backtrace.
|
|
95
|
+
warn "From: #{ex.backtrace.first}"
|
|
81
96
|
else
|
|
82
97
|
trigger_callbacks :callback_failed, ex, named
|
|
83
98
|
end
|
|
84
99
|
end
|
|
85
100
|
|
|
101
|
+
def trigger_callbacks named, *args, &other
|
|
102
|
+
guard_callback named, other, *args
|
|
103
|
+
guard_callback named, @callbacks[named], *args
|
|
104
|
+
end
|
|
105
|
+
|
|
86
106
|
def flush_and_close
|
|
87
107
|
_write while connected? && @w_buff.buffered?
|
|
88
108
|
io_close
|
|
@@ -109,25 +129,26 @@ private
|
|
|
109
129
|
def _write
|
|
110
130
|
written = 0
|
|
111
131
|
while written < MAX_BYTES_PER_WRITE
|
|
112
|
-
bytes, cb = @w_buff.shift
|
|
132
|
+
bytes, cb, cb_args = @w_buff.shift
|
|
113
133
|
break unless bytes
|
|
114
134
|
begin
|
|
115
135
|
w = io_write bytes
|
|
116
136
|
rescue Errno::EINTR, Errno::EAGAIN, Errno::EWOULDBLOCK
|
|
117
137
|
# writing will either block, or cannot otherwise be completed,
|
|
118
138
|
# put data back and try again some other day
|
|
119
|
-
@w_buff.unshift bytes, cb
|
|
139
|
+
@w_buff.unshift bytes, cb, cb_args
|
|
120
140
|
break
|
|
121
141
|
rescue Exception
|
|
122
142
|
force_close $!
|
|
123
143
|
break
|
|
124
144
|
end
|
|
125
145
|
written += w
|
|
146
|
+
trigger_callbacks :wrote, bytes, w
|
|
126
147
|
if w < bytes.size
|
|
127
|
-
@w_buff.unshift bytes[w..-1], cb
|
|
128
|
-
trigger_callbacks :wrote, bytes, w
|
|
148
|
+
@w_buff.unshift bytes[w..-1], cb, cb_args
|
|
129
149
|
else
|
|
130
|
-
|
|
150
|
+
# A separate callback invocation so we can pass custom args
|
|
151
|
+
guard_callback :wrote, cb, bytes, w, *cb_args
|
|
131
152
|
end
|
|
132
153
|
end
|
|
133
154
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module IoUnblock
|
|
2
|
+
class TcpSocket
|
|
3
|
+
extend Forwardable
|
|
4
|
+
|
|
5
|
+
def_delegators :@stream, :start, :stop, :callbacks, :write,
|
|
6
|
+
:running?, :connected?, :alive?, :select_delay, :select_delay=
|
|
7
|
+
attr_reader :host, :port
|
|
8
|
+
|
|
9
|
+
def initialize host, port, callbacks=nil
|
|
10
|
+
@host = host
|
|
11
|
+
@port = port
|
|
12
|
+
@socket = ::TCPSocket.new host, port
|
|
13
|
+
@stream = Stream.new @socket, callbacks
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/io_unblock/version.rb
CHANGED
|
@@ -6,41 +6,41 @@ describe IoUnblock::Buffer do
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
it "should be empty when nothing is buffered" do
|
|
9
|
-
@buffer.push :a, 1
|
|
9
|
+
@buffer.push :a, 1, 'hello'
|
|
10
10
|
@buffer.pop
|
|
11
11
|
@buffer.empty?.must_equal true
|
|
12
12
|
@buffer.buffered?.must_equal false
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
it "should not be empty when stuff is buffered" do
|
|
16
|
-
@buffer.push :a, 1
|
|
16
|
+
@buffer.push :a, 1, 'hello'
|
|
17
17
|
@buffer.empty?.must_equal false
|
|
18
18
|
@buffer.buffered?.must_equal true
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it "should push to the end of the buffer" do
|
|
22
|
-
@buffer.push :a, 1
|
|
23
|
-
@buffer.push :b, 2
|
|
24
|
-
@buffer.first.must_equal [:a, 1]
|
|
25
|
-
@buffer.last.must_equal [:b, 2]
|
|
22
|
+
@buffer.push :a, 1, 'hello'
|
|
23
|
+
@buffer.push :b, 2, 'world'
|
|
24
|
+
@buffer.first.must_equal [:a, 1, 'hello']
|
|
25
|
+
@buffer.last.must_equal [:b, 2, 'world']
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "should unshift to the beginning of the buffer" do
|
|
29
|
-
@buffer.unshift :a, 1
|
|
30
|
-
@buffer.unshift :b, 2
|
|
31
|
-
@buffer.
|
|
32
|
-
@buffer.
|
|
29
|
+
@buffer.unshift :a, 1, 'hello'
|
|
30
|
+
@buffer.unshift :b, 2, 'world'
|
|
31
|
+
@buffer.first.must_equal [:b, 2, 'world']
|
|
32
|
+
@buffer.last.must_equal [:a, 1, 'hello']
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "should shift from the beginning" do
|
|
36
|
-
@buffer.push :a, 1
|
|
37
|
-
@buffer.push :b, 2
|
|
38
|
-
@buffer.shift.must_equal [:a, 1]
|
|
36
|
+
@buffer.push :a, 1, 'hello'
|
|
37
|
+
@buffer.push :b, 2, 'world'
|
|
38
|
+
@buffer.shift.must_equal [:a, 1, 'hello']
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
it "should pop from the end" do
|
|
42
|
-
@buffer.push :a, 1
|
|
43
|
-
@buffer.push :b, 2
|
|
44
|
-
@buffer.pop.must_equal [:b, 2]
|
|
42
|
+
@buffer.push :a, 1, 'hello'
|
|
43
|
+
@buffer.push :b, 2, 'world'
|
|
44
|
+
@buffer.pop.must_equal [:b, 2, 'world']
|
|
45
45
|
end
|
|
46
46
|
end
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
require File.expand_path("../../spec_helper.rb", __FILE__)
|
|
2
2
|
|
|
3
3
|
describe IoUnblock::Stream do
|
|
4
|
+
include Stubz
|
|
4
5
|
def dummy_io; @dummy_io ||= DummyIO.new; end
|
|
5
6
|
def stream; @stream ||= IoUnblock::Stream.new dummy_io; end
|
|
7
|
+
|
|
8
|
+
# Watch for Thread exceptions
|
|
9
|
+
before do
|
|
10
|
+
@th_abort = Thread.abort_on_exception
|
|
11
|
+
Thread.abort_on_exception = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
after do
|
|
15
|
+
Thread.abort_on_exception = @th_abort
|
|
16
|
+
end
|
|
6
17
|
|
|
7
18
|
it "raises an exception if started twice" do
|
|
8
19
|
stream.start
|
|
@@ -179,6 +190,14 @@ describe IoUnblock::Stream do
|
|
|
179
190
|
called_with.must_equal [ ['lo', 2] ]
|
|
180
191
|
end
|
|
181
192
|
|
|
193
|
+
it "triggers the given callback after writing the full string with params" do
|
|
194
|
+
dummy_io.max_write = 3
|
|
195
|
+
stream.start
|
|
196
|
+
stream.write('hello', 'turbo', 'is', 'me', &callback)
|
|
197
|
+
stream.stop
|
|
198
|
+
called_with.must_equal [ ['lo', 2, 'turbo', 'is', 'me'] ]
|
|
199
|
+
end
|
|
200
|
+
|
|
182
201
|
it "is not connected when failed is triggered" do
|
|
183
202
|
is_connected = true
|
|
184
203
|
cb_stream = callback_stream(
|
|
@@ -202,13 +221,29 @@ describe IoUnblock::Stream do
|
|
|
202
221
|
end
|
|
203
222
|
|
|
204
223
|
it "warns when triggering callback_failed raises an exception" do
|
|
224
|
+
warn_lines = []
|
|
205
225
|
cb_err = RuntimeError.new 'failback!'
|
|
206
226
|
cb_stream = callback_stream(
|
|
207
227
|
:callback_failed => lambda { |*_| raise cb_err }
|
|
208
228
|
)
|
|
229
|
+
stub(cb_stream, :warn) { |w| warn_lines << w }
|
|
209
230
|
cb_stream.start
|
|
210
231
|
cb_stream.write('another test') { raise cb_err }
|
|
211
232
|
cb_stream.stop
|
|
233
|
+
warn_lines.first.must_equal 'Exception raised in callback_failed handler: failback!'
|
|
234
|
+
/\AFrom: /.must_match warn_lines.last
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "stops properly when called within the processor thread" do
|
|
238
|
+
stopped_called = false
|
|
239
|
+
cb_stream = callback_stream(
|
|
240
|
+
:looped => lambda { |s| sleep 0.25; s.stop },
|
|
241
|
+
:stopped => lambda { |s| stopped_called = true }
|
|
242
|
+
)
|
|
243
|
+
cb_stream.start
|
|
244
|
+
Thread.pass until cb_stream.running?
|
|
245
|
+
Thread.pass while cb_stream.alive?
|
|
246
|
+
stopped_called.must_equal true
|
|
212
247
|
end
|
|
213
248
|
end
|
|
214
249
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", __FILE__)
|
|
2
|
+
|
|
3
|
+
describe IoUnblock::TcpSocket do
|
|
4
|
+
include Stubz
|
|
5
|
+
|
|
6
|
+
def tcp_socket
|
|
7
|
+
@tcp_socket ||= IoUnblock::TcpSocket.new('host.name', 33, {:call => :back})
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
before do
|
|
11
|
+
@socket = MiniTest::Mock.new
|
|
12
|
+
@stream = MiniTest::Mock.new
|
|
13
|
+
stub(::TCPSocket, :new, @socket)
|
|
14
|
+
stub(::IoUnblock::Stream, :new, @stream)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "attribs" do
|
|
18
|
+
it "has a host" do
|
|
19
|
+
tcp_socket.host.must_equal 'host.name'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "has a port" do
|
|
23
|
+
tcp_socket.port.must_equal 33
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "delegation to the stream" do
|
|
28
|
+
it "delegates start" do
|
|
29
|
+
@stream.expect(:start, nil, [:some, :args])
|
|
30
|
+
tcp_socket.start :some, :args
|
|
31
|
+
@stream.verify
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "delegates stop" do
|
|
35
|
+
@stream.expect(:stop, nil, ['moar cowbell'])
|
|
36
|
+
tcp_socket.stop 'moar cowbell'
|
|
37
|
+
@stream.verify
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "delegates callbacks" do
|
|
41
|
+
@stream.expect(:callbacks, {:a => :hash})
|
|
42
|
+
tcp_socket.callbacks.must_equal({:a => :hash})
|
|
43
|
+
@stream.verify
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "delegates running?" do
|
|
47
|
+
@stream.expect(:running?, :generally_a_bool)
|
|
48
|
+
tcp_socket.running?.must_equal :generally_a_bool
|
|
49
|
+
@stream.verify
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "delegates connected?" do
|
|
53
|
+
@stream.expect(:connected?, :again_a_bool)
|
|
54
|
+
tcp_socket.connected?.must_equal :again_a_bool
|
|
55
|
+
@stream.verify
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "delegates select_delay" do
|
|
59
|
+
@stream.expect(:select_delay, 48)
|
|
60
|
+
tcp_socket.select_delay.must_equal 48
|
|
61
|
+
@stream.verify
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "delegates select_delay=" do
|
|
65
|
+
@stream.expect(:select_delay=, 19, [19])
|
|
66
|
+
tcp_socket.select_delay = 19
|
|
67
|
+
@stream.verify
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -11,74 +11,10 @@ begin
|
|
|
11
11
|
require 'minitest/emoji'
|
|
12
12
|
rescue LoadError
|
|
13
13
|
end
|
|
14
|
-
require 'io_unblock'
|
|
15
|
-
require 'stringio'
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
attr_reader :closed, :w_stream, :r_stream, :raised_write, :raised_read
|
|
21
|
-
alias :closed? :closed
|
|
22
|
-
alias :raised_write? :raised_write
|
|
23
|
-
alias :raised_read? :raised_read
|
|
24
|
-
attr_accessor :readable, :writeable
|
|
25
|
-
attr_accessor :write_delay, :read_delay
|
|
26
|
-
attr_accessor :max_write, :max_read
|
|
27
|
-
attr_accessor :raise_read, :raise_write
|
|
28
|
-
alias :readable? :readable
|
|
29
|
-
alias :writeable? :writeable
|
|
30
|
-
|
|
31
|
-
def initialize *args, &block
|
|
32
|
-
@r_stream = StringIO.new
|
|
33
|
-
@w_stream = StringIO.new
|
|
34
|
-
@readable = @writeable = true
|
|
35
|
-
@read_delay = @write_delay = 0
|
|
36
|
-
@max_write = 0
|
|
37
|
-
@max_read = 0
|
|
38
|
-
@closed = false
|
|
39
|
-
@raise_read = nil
|
|
40
|
-
@raise_write = nil
|
|
41
|
-
@raised_write = false
|
|
42
|
-
@raised_read = false
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def close
|
|
46
|
-
@closed = true
|
|
47
|
-
@w_stream.close
|
|
48
|
-
@r_stream.close
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def write_nonblock bytes
|
|
52
|
-
sleep(@write_delay) if @write_delay > 0
|
|
53
|
-
do_raise_write
|
|
54
|
-
if @max_write > 0 && bytes.size > @max_write
|
|
55
|
-
@w_stream.write bytes[0...@max_write]
|
|
56
|
-
else
|
|
57
|
-
@w_stream.write bytes
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def read_nonblock len
|
|
62
|
-
sleep(@read_delay) if @read_delay > 0
|
|
63
|
-
do_raise_read
|
|
64
|
-
if @max_read > 0 && len > @max_read
|
|
65
|
-
@r_stream.read @max_read
|
|
66
|
-
else
|
|
67
|
-
@r_stream.read len
|
|
68
|
-
end
|
|
69
|
-
end
|
|
15
|
+
Dir[File.expand_path('../support/*.rb', __FILE__)].each do |r|
|
|
16
|
+
require r
|
|
17
|
+
end
|
|
70
18
|
|
|
71
|
-
|
|
72
|
-
if @raise_write
|
|
73
|
-
@raised_write = true
|
|
74
|
-
raise @raise_write
|
|
75
|
-
end
|
|
76
|
-
end
|
|
19
|
+
require 'io_unblock'
|
|
77
20
|
|
|
78
|
-
def do_raise_read
|
|
79
|
-
if @raise_read
|
|
80
|
-
@raised_read = true
|
|
81
|
-
raise @raise_read
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'stringio'
|
|
2
|
+
|
|
3
|
+
# Used to test IO stuff, using stringio objects for the write and
|
|
4
|
+
# read stream.
|
|
5
|
+
class DummyIO
|
|
6
|
+
attr_reader :closed, :w_stream, :r_stream, :raised_write, :raised_read
|
|
7
|
+
alias :closed? :closed
|
|
8
|
+
alias :raised_write? :raised_write
|
|
9
|
+
alias :raised_read? :raised_read
|
|
10
|
+
attr_accessor :readable, :writeable
|
|
11
|
+
attr_accessor :write_delay, :read_delay
|
|
12
|
+
attr_accessor :max_write, :max_read
|
|
13
|
+
attr_accessor :raise_read, :raise_write
|
|
14
|
+
alias :readable? :readable
|
|
15
|
+
alias :writeable? :writeable
|
|
16
|
+
|
|
17
|
+
def initialize *args, &block
|
|
18
|
+
@r_stream = StringIO.new
|
|
19
|
+
@w_stream = StringIO.new
|
|
20
|
+
@readable = @writeable = true
|
|
21
|
+
@read_delay = @write_delay = 0
|
|
22
|
+
@max_write = 0
|
|
23
|
+
@max_read = 0
|
|
24
|
+
@closed = false
|
|
25
|
+
@raise_read = nil
|
|
26
|
+
@raise_write = nil
|
|
27
|
+
@raised_write = false
|
|
28
|
+
@raised_read = false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def close
|
|
32
|
+
@closed = true
|
|
33
|
+
@w_stream.close
|
|
34
|
+
@r_stream.close
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def write_nonblock bytes
|
|
38
|
+
sleep(@write_delay) if @write_delay > 0
|
|
39
|
+
do_raise_write
|
|
40
|
+
if @max_write > 0 && bytes.size > @max_write
|
|
41
|
+
@w_stream.write bytes[0...@max_write]
|
|
42
|
+
else
|
|
43
|
+
@w_stream.write bytes
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def read_nonblock len
|
|
48
|
+
sleep(@read_delay) if @read_delay > 0
|
|
49
|
+
do_raise_read
|
|
50
|
+
if @max_read > 0 && len > @max_read
|
|
51
|
+
@r_stream.read @max_read
|
|
52
|
+
else
|
|
53
|
+
@r_stream.read len
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def do_raise_write
|
|
58
|
+
if @raise_write
|
|
59
|
+
@raised_write = true
|
|
60
|
+
raise @raise_write
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def do_raise_read
|
|
65
|
+
if @raise_read
|
|
66
|
+
@raised_read = true
|
|
67
|
+
raise @raise_read
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Stubz
|
|
2
|
+
def self.included base
|
|
3
|
+
base.__send__(:before) { _ensure_stubs_ }
|
|
4
|
+
base.__send__(:after) { _reset_stubs_ }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def stub_instance(klass, meth, *val, &block)
|
|
8
|
+
_do_stub_ klass, meth, *val, &block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def stub(obj, meth, *val, &block)
|
|
12
|
+
_do_stub_ get_meta_class(obj), meth, *val, &block
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def get_meta_class klass
|
|
16
|
+
class << klass; self; end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def _do_stub_ klass, meth, *val, &block
|
|
20
|
+
if klass.method_defined? meth
|
|
21
|
+
aliased = "_stub_#{meth}_#{Time.now.to_i}_"
|
|
22
|
+
klass.send(:alias_method, aliased, meth)
|
|
23
|
+
else
|
|
24
|
+
aliased = nil
|
|
25
|
+
end
|
|
26
|
+
if block
|
|
27
|
+
klass.send(:define_method, meth, &block)
|
|
28
|
+
else
|
|
29
|
+
klass.send(:define_method, meth) do |*_|
|
|
30
|
+
val.first
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
@stubbies << [klass, meth, aliased]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _ensure_stubs_
|
|
37
|
+
@stubbies = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def _reset_stubs_
|
|
41
|
+
@stubbies.each do |(klass, meth, aliased)|
|
|
42
|
+
klass.send(:remove_method, meth)
|
|
43
|
+
if aliased
|
|
44
|
+
klass.send(:alias_method, meth, aliased)
|
|
45
|
+
klass.send(:remove_method, aliased)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: io_unblock
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-03-
|
|
12
|
+
date: 2012-03-15 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: minitest
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &2160167540 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ! '>='
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: '0'
|
|
22
22
|
type: :development
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *2160167540
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: rake
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &2160165920 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ! '>='
|
|
@@ -32,7 +32,7 @@ dependencies:
|
|
|
32
32
|
version: '0'
|
|
33
33
|
type: :development
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *2160165920
|
|
36
36
|
description: Non-blocking IO reads/writes wrapped in a thread
|
|
37
37
|
email:
|
|
38
38
|
- ian.eccles@gmail.com
|
|
@@ -50,12 +50,17 @@ files:
|
|
|
50
50
|
- lib/io_unblock.rb
|
|
51
51
|
- lib/io_unblock/buffer.rb
|
|
52
52
|
- lib/io_unblock/delegation.rb
|
|
53
|
+
- lib/io_unblock/errors.rb
|
|
53
54
|
- lib/io_unblock/stream.rb
|
|
55
|
+
- lib/io_unblock/tcp_socket.rb
|
|
54
56
|
- lib/io_unblock/version.rb
|
|
55
57
|
- spec/io_unblock/buffer_spec.rb
|
|
56
58
|
- spec/io_unblock/delegation_spec.rb
|
|
57
59
|
- spec/io_unblock/stream_spec.rb
|
|
60
|
+
- spec/io_unblock/tcp_socket_spec.rb
|
|
58
61
|
- spec/spec_helper.rb
|
|
62
|
+
- spec/support/dummy_io.rb
|
|
63
|
+
- spec/support/stubz.rb
|
|
59
64
|
homepage: https://github.com/iande/io_unblock
|
|
60
65
|
licenses: []
|
|
61
66
|
post_install_message:
|
|
@@ -84,5 +89,8 @@ test_files:
|
|
|
84
89
|
- spec/io_unblock/buffer_spec.rb
|
|
85
90
|
- spec/io_unblock/delegation_spec.rb
|
|
86
91
|
- spec/io_unblock/stream_spec.rb
|
|
92
|
+
- spec/io_unblock/tcp_socket_spec.rb
|
|
87
93
|
- spec/spec_helper.rb
|
|
94
|
+
- spec/support/dummy_io.rb
|
|
95
|
+
- spec/support/stubz.rb
|
|
88
96
|
has_rdoc:
|