hatetepe 0.5.2 → 0.6.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/.yardopts +1 -0
- data/Gemfile +9 -4
- data/Gemfile.devtools +55 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -192
- data/Rakefile +3 -2
- data/bin/hatetepe +35 -2
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +103 -0
- data/config/rubocop.yml +58 -0
- data/config/yardstick.yml +2 -0
- data/hatetepe.gemspec +23 -27
- data/lib/hatetepe/client/keep_alive.rb +59 -0
- data/lib/hatetepe/client/timeouts.rb +19 -0
- data/lib/hatetepe/client.rb +54 -302
- data/lib/hatetepe/connection/eventmachine.rb +61 -0
- data/lib/hatetepe/connection/status.rb +28 -0
- data/lib/hatetepe/errors.rb +7 -0
- data/lib/hatetepe/promise.rb +86 -0
- data/lib/hatetepe/request.rb +15 -39
- data/lib/hatetepe/response.rb +82 -22
- data/lib/hatetepe/serializer/encoding.rb +58 -0
- data/lib/hatetepe/serializer.rb +61 -0
- data/lib/hatetepe/server/keep_alive.rb +53 -13
- data/lib/hatetepe/server/timeouts.rb +17 -0
- data/lib/hatetepe/server.rb +37 -85
- data/lib/hatetepe/support/handlers.rb +19 -0
- data/lib/hatetepe/support/keep_alive.rb +14 -0
- data/lib/hatetepe/support/message.rb +40 -0
- data/lib/hatetepe/version.rb +3 -1
- data/lib/hatetepe.rb +29 -7
- data/spec/integration/error_handling_spec.rb +7 -0
- data/spec/integration/keep_alive_spec.rb +106 -0
- data/spec/integration/smoke_spec.rb +21 -0
- data/spec/integration/streaming_spec.rb +61 -0
- data/spec/integration/timeouts_spec.rb +82 -0
- data/spec/shared/integration/server_client_pair.rb +26 -0
- data/spec/spec_helper.rb +41 -10
- data/spec/support/handler.rb +55 -0
- data/spec/support/helper.rb +74 -0
- data/spec/unit/client_spec.rb +115 -156
- data/spec/unit/connection/eventmachine_spec.rb +146 -0
- data/spec/unit/request_spec.rb +35 -0
- data/spec/unit/response_spec.rb +42 -0
- data/spec/unit/server_spec.rb +65 -100
- data/spec/unit/support/keep_alive_spec.rb +52 -0
- data/spec/unit/support/message_spec.rb +41 -0
- metadata +68 -103
- data/Gemfile.lock +0 -46
- data/LICENSE +0 -19
- data/Procfile +0 -1
- data/config.ru +0 -7
- data/examples/parallel_requests.rb +0 -32
- data/lib/hatetepe/body.rb +0 -182
- data/lib/hatetepe/builder.rb +0 -171
- data/lib/hatetepe/cli.rb +0 -61
- data/lib/hatetepe/connection.rb +0 -73
- data/lib/hatetepe/events.rb +0 -35
- data/lib/hatetepe/message.rb +0 -13
- data/lib/hatetepe/parser.rb +0 -83
- data/lib/hatetepe/server/pipeline.rb +0 -20
- data/lib/hatetepe/server/rack_app.rb +0 -39
- data/lib/rack/handler/hatetepe.rb +0 -33
- data/spec/integration/cli/start_spec.rb +0 -113
- data/spec/integration/client/keep_alive_spec.rb +0 -23
- data/spec/integration/client/timeout_spec.rb +0 -97
- data/spec/integration/server/keep_alive_spec.rb +0 -27
- data/spec/integration/server/timeout_spec.rb +0 -51
- data/spec/unit/body_spec.rb +0 -205
- data/spec/unit/builder_spec.rb +0 -372
- data/spec/unit/connection_spec.rb +0 -62
- data/spec/unit/events_spec.rb +0 -96
- data/spec/unit/parser_spec.rb +0 -209
- data/spec/unit/rack_handler_spec.rb +0 -60
data/spec/unit/builder_spec.rb
DELETED
@@ -1,372 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "hatetepe/builder"
|
3
|
-
|
4
|
-
describe Hatetepe::Builder do
|
5
|
-
let(:builder) { Hatetepe::Builder.allocate }
|
6
|
-
|
7
|
-
describe ".build {|builder| ... }"
|
8
|
-
|
9
|
-
describe "#initialize" do
|
10
|
-
it "resets the builder" do
|
11
|
-
builder.should_receive :reset
|
12
|
-
builder.send :initialize
|
13
|
-
end
|
14
|
-
|
15
|
-
it "initializes the on_complete, on_write, on_error hooks" do
|
16
|
-
builder.send :initialize
|
17
|
-
[:complete, :write, :error].each do |hook|
|
18
|
-
builder.send(:"on_#{hook}").tap do |h|
|
19
|
-
h.should be_an(Array)
|
20
|
-
h.should be_empty
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe "#initialize {|builder| ... }" do
|
27
|
-
it "yields the builder" do
|
28
|
-
arg = nil
|
29
|
-
builder.send(:initialize) {|b| arg = b }
|
30
|
-
arg.should equal(builder)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
[:complete, :write, :error].each do |hook|
|
35
|
-
describe "#on_#{hook} {|*| ... }" do
|
36
|
-
let(:block) { proc {} }
|
37
|
-
before { builder.send :initialize }
|
38
|
-
|
39
|
-
it "adds a hook block" do
|
40
|
-
builder.send :"on_#{hook}", &block
|
41
|
-
builder.send(:"on_#{hook}").should include(block)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "#writing_trailing_headers?" do
|
47
|
-
it "returns true if the builder state is :ready" do
|
48
|
-
builder.stub :state => :ready
|
49
|
-
builder.ready?.should be_true
|
50
|
-
end
|
51
|
-
|
52
|
-
it "returns false otherwise" do
|
53
|
-
builder.stub :state => :something
|
54
|
-
builder.ready?.should be_false
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe "#reset" do
|
59
|
-
before { builder.send :reset }
|
60
|
-
|
61
|
-
# XXX maybe don't test chunked flag
|
62
|
-
it "resets the chunked flag and the builder state" do
|
63
|
-
builder.chunked?.should be_nil
|
64
|
-
builder.ready?.should be_true
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# XXX maybe test states and flags where they are being mutated
|
69
|
-
describe "#ready?"
|
70
|
-
describe "#writing_headers?"
|
71
|
-
describe "#writing_body?"
|
72
|
-
describe "#writing_trailing_headers?"
|
73
|
-
describe "#chunked?"
|
74
|
-
|
75
|
-
describe "#request(array)" do
|
76
|
-
let(:req) { [:get, "/foo", {"Key" => "value"}, double("body")] }
|
77
|
-
|
78
|
-
before { builder.send :initialize }
|
79
|
-
|
80
|
-
it "is a shortcut for #request_line, #headers, #body, #complete" do
|
81
|
-
builder.should_receive(:request_line).with req[0], req[1], "1.1"
|
82
|
-
builder.should_receive(:headers).with req[2]
|
83
|
-
builder.should_receive(:body).with req[3]
|
84
|
-
builder.should_receive :complete
|
85
|
-
builder.request req
|
86
|
-
end
|
87
|
-
|
88
|
-
it "doesn't require a body (fourth element)" do
|
89
|
-
builder.should_receive(:request_line).with req[0], req[1], "1.1"
|
90
|
-
builder.should_receive(:headers).with req[2]
|
91
|
-
builder.should_not_receive :body
|
92
|
-
builder.request req[0..2]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
describe "#request_line(verb, uri, version)" do
|
97
|
-
before { builder.send :initialize }
|
98
|
-
|
99
|
-
it "writes a request line" do
|
100
|
-
builder.should_receive(:write).with "GET /foo HTTP/1.0\r\n"
|
101
|
-
builder.request_line :get, "/foo", "1.0"
|
102
|
-
end
|
103
|
-
|
104
|
-
it "changes the state to :writing_headers" do
|
105
|
-
builder.request_line :get, "/foo"
|
106
|
-
builder.state.should equal(:writing_headers)
|
107
|
-
end
|
108
|
-
|
109
|
-
it "defaults the version to 1.1" do
|
110
|
-
builder.should_receive(:write).with "GET /foo HTTP/1.1\r\n"
|
111
|
-
builder.request_line :get, "/foo"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe "#response_line(code, version)" do
|
116
|
-
before { builder.send :initialize }
|
117
|
-
|
118
|
-
it "writes a response line" do
|
119
|
-
builder.should_receive(:write).with "HTTP/1.0 403 Forbidden\r\n"
|
120
|
-
builder.response_line 403, "1.0"
|
121
|
-
end
|
122
|
-
|
123
|
-
it "changes the state to :writing_headers" do
|
124
|
-
builder.response_line 403
|
125
|
-
builder.state.should equal(:writing_headers)
|
126
|
-
end
|
127
|
-
|
128
|
-
it "default the version to 1.1" do
|
129
|
-
builder.should_receive(:write).with "HTTP/1.1 403 Forbidden\r\n"
|
130
|
-
builder.response_line 403
|
131
|
-
end
|
132
|
-
|
133
|
-
it "fails if there's no status message for code" do
|
134
|
-
builder.should_receive :error
|
135
|
-
builder.response_line 666
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
describe "#response(array)" do
|
140
|
-
let(:res) { [201, {"Key" => "value"}, double("body")] }
|
141
|
-
|
142
|
-
before { builder.send :initialize }
|
143
|
-
|
144
|
-
it "is a shortcut for #response_line, #headers, #body, #complete" do
|
145
|
-
builder.should_receive(:response_line).with res[0], "1.1"
|
146
|
-
builder.should_receive(:headers).with res[1]
|
147
|
-
builder.should_receive(:body).with res[2]
|
148
|
-
builder.should_receive :complete
|
149
|
-
builder.response res
|
150
|
-
end
|
151
|
-
|
152
|
-
it "doesn't require a body (third element)" do
|
153
|
-
builder.should_receive(:response_line).with res[0], "1.1"
|
154
|
-
builder.should_receive(:headers).with res[1]
|
155
|
-
builder.should_not_receive :body
|
156
|
-
builder.response res[0..1]
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
describe "#headers(hash)" do
|
161
|
-
it "writes each of the header pairs" do
|
162
|
-
builder.should_receive(:header).with "Key", "value"
|
163
|
-
builder.should_receive(:header).with "Key2", "value2"
|
164
|
-
builder.headers "Key" => "value", "Key2" => "value2"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe "#header(name, value)" do
|
169
|
-
it "writes the header pair" do
|
170
|
-
builder.should_receive(:raw_header).with "Key: value"
|
171
|
-
builder.header "Key", "value"
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
describe "#raw_header(header)" do
|
176
|
-
before do
|
177
|
-
builder.send :initialize
|
178
|
-
builder.response_line 200
|
179
|
-
end
|
180
|
-
|
181
|
-
it "writes the header line" do
|
182
|
-
builder.should_receive(:write).with "Key: value\r\n"
|
183
|
-
builder.raw_header "Key: value"
|
184
|
-
end
|
185
|
-
|
186
|
-
it "fails if no request or response line has been written" do
|
187
|
-
builder.reset
|
188
|
-
builder.should_receive :error
|
189
|
-
builder.raw_header "Key: value"
|
190
|
-
end
|
191
|
-
|
192
|
-
it "fails if body already started" do
|
193
|
-
builder.header "Content-Length", 5
|
194
|
-
builder.body_chunk "asd"
|
195
|
-
|
196
|
-
builder.should_receive :error
|
197
|
-
builder.raw_header "Key: value"
|
198
|
-
end
|
199
|
-
|
200
|
-
it "writes trailing header if body already started and transfer is chunked" do
|
201
|
-
builder.header "Transfer-Encoding", "chunked"
|
202
|
-
builder.body_chunk "asd"
|
203
|
-
|
204
|
-
builder.should_not_receive :error
|
205
|
-
builder.should_receive(:write).with "0\r\n"
|
206
|
-
builder.should_receive(:write).with "Key: value\r\n"
|
207
|
-
builder.raw_header "Key: value"
|
208
|
-
|
209
|
-
builder.state.should equal(:writing_trailing_headers)
|
210
|
-
end
|
211
|
-
|
212
|
-
it "sets the chunked flag" do
|
213
|
-
builder.header "Transfer-Encoding", "chunked"
|
214
|
-
builder.chunked?.should be_true
|
215
|
-
|
216
|
-
builder.reset
|
217
|
-
builder.response_line 200
|
218
|
-
|
219
|
-
builder.header "Content-Length", "0"
|
220
|
-
builder.chunked?.should be_false
|
221
|
-
end
|
222
|
-
|
223
|
-
it "doesn't set the chunked flag a second time" do
|
224
|
-
builder.header "Transfer-Encoding", "chunked"
|
225
|
-
builder.chunked?.should be_true
|
226
|
-
|
227
|
-
builder.header "Content-Length", "0"
|
228
|
-
builder.chunked?.should be_true
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
describe "#body(#each)" do
|
233
|
-
let(:body) { [double("chunk#1"), double("chunk#2")] }
|
234
|
-
|
235
|
-
it "calls #body_chunk for each element" do
|
236
|
-
builder.should_receive(:body_chunk).with body[0]
|
237
|
-
builder.should_receive(:body_chunk).with body[1]
|
238
|
-
builder.body body
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
describe "#body_chunk(chunk)" do
|
243
|
-
before do
|
244
|
-
builder.send :initialize
|
245
|
-
builder.response_line 200
|
246
|
-
end
|
247
|
-
|
248
|
-
it "fails if no request or response line has been written" do
|
249
|
-
builder.reset
|
250
|
-
builder.should_receive :error
|
251
|
-
builder.body_chunk "asd"
|
252
|
-
end
|
253
|
-
|
254
|
-
it "fails if already writing trailing headers" do
|
255
|
-
builder.body_chunk "asd"
|
256
|
-
builder.header "Key", "value"
|
257
|
-
builder.should_receive :error
|
258
|
-
builder.body_chunk "asd"
|
259
|
-
end
|
260
|
-
|
261
|
-
it "assumes Transfer-Encoding: chunked if chunked flag isn't set" do
|
262
|
-
builder.should_receive(:header).with "Transfer-Encoding", "chunked"
|
263
|
-
builder.body_chunk "asd"
|
264
|
-
end
|
265
|
-
|
266
|
-
it "changes the state to :writing_body" do
|
267
|
-
builder.body_chunk "asd"
|
268
|
-
builder.state.should equal(:writing_body)
|
269
|
-
end
|
270
|
-
|
271
|
-
it "writes chunked body data" do
|
272
|
-
builder.body_chunk ""
|
273
|
-
builder.should_receive(:write).with "c\r\nasdfoobarbaz\r\n"
|
274
|
-
builder.body_chunk "asdfoobarbaz"
|
275
|
-
end
|
276
|
-
|
277
|
-
it "writes empty chunked data" do
|
278
|
-
builder.body_chunk ""
|
279
|
-
builder.should_receive(:write).with "0\r\n\r\n"
|
280
|
-
builder.body_chunk ""
|
281
|
-
end
|
282
|
-
|
283
|
-
it "writes plain body data" do
|
284
|
-
builder.header "Content-Length", "12"
|
285
|
-
builder.body_chunk ""
|
286
|
-
builder.should_receive(:write).with "asdfoobarbaz"
|
287
|
-
builder.body_chunk "asdfoobarbaz"
|
288
|
-
end
|
289
|
-
|
290
|
-
it "doesn't write empty plain data" do
|
291
|
-
builder.header "Content-Length", "123"
|
292
|
-
builder.body_chunk ""
|
293
|
-
builder.should_not_receive :write
|
294
|
-
builder.body_chunk ""
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
describe "#complete" do
|
299
|
-
before do
|
300
|
-
builder.send :initialize
|
301
|
-
builder.response_line 200
|
302
|
-
builder.stub :body_chunk
|
303
|
-
end
|
304
|
-
|
305
|
-
it "does nothing if state is :ready" do
|
306
|
-
builder.reset
|
307
|
-
builder.should_not_receive :write
|
308
|
-
builder.complete
|
309
|
-
end
|
310
|
-
|
311
|
-
it "sets Content-Length to 0 if no body has been sent and transfer is chunked" do
|
312
|
-
builder.should_receive(:header).with "Content-Length", "0"
|
313
|
-
builder.complete
|
314
|
-
end
|
315
|
-
|
316
|
-
it "writes an empty body chunk" do
|
317
|
-
builder.should_receive(:body_chunk).with ""
|
318
|
-
builder.complete
|
319
|
-
end
|
320
|
-
|
321
|
-
let(:hook) { double "hook", :call => nil }
|
322
|
-
|
323
|
-
it "calls the on_complete hooks" do
|
324
|
-
builder.on_complete << hook
|
325
|
-
hook.should_receive :call
|
326
|
-
builder.complete
|
327
|
-
end
|
328
|
-
|
329
|
-
it "calls #reset" do
|
330
|
-
builder.should_receive :reset
|
331
|
-
builder.complete
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
describe "#write(data)" do
|
336
|
-
let(:hook) { double "hook" }
|
337
|
-
let(:data) { double "data" }
|
338
|
-
|
339
|
-
before { builder.send :initialize }
|
340
|
-
|
341
|
-
it "calls the on_write hooks" do
|
342
|
-
builder.on_write << hook
|
343
|
-
hook.should_receive(:call).with data
|
344
|
-
builder.write data
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
describe "#error(message)" do
|
349
|
-
let(:hook1) { double "hook#1" }
|
350
|
-
let(:hook2) { double "hook#2" }
|
351
|
-
let(:message) { "error! error!" }
|
352
|
-
let(:exception) { double "exception" }
|
353
|
-
|
354
|
-
before do
|
355
|
-
builder.send :initialize
|
356
|
-
builder.on_error << hook1 << hook2
|
357
|
-
end
|
358
|
-
|
359
|
-
it "calls the error hooks" do
|
360
|
-
Hatetepe::BuilderError.stub :new => exception
|
361
|
-
|
362
|
-
hook1.should_receive(:call).with exception
|
363
|
-
hook2.should_receive(:call).with exception
|
364
|
-
builder.error message
|
365
|
-
end
|
366
|
-
|
367
|
-
it "raises the exception if no hooks were added" do
|
368
|
-
builder.on_error.clear
|
369
|
-
proc { builder.error message }.should raise_error(Hatetepe::BuilderError, message)
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "hatetepe/connection"
|
3
|
-
|
4
|
-
describe Hatetepe::Connection do
|
5
|
-
let :conn do
|
6
|
-
Object.new.extend Hatetepe::Connection
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:address) { "127.0.0.1" }
|
10
|
-
let(:port) { 34450 }
|
11
|
-
let(:peername) { Socket.pack_sockaddr_in(port, address) }
|
12
|
-
|
13
|
-
before { conn.stub :get_peername => peername }
|
14
|
-
|
15
|
-
describe "#remote_address" do
|
16
|
-
it "returns the remote peer's address" do
|
17
|
-
conn.remote_address.should == address
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#remote_port" do
|
22
|
-
it "returns the remote peer's port" do
|
23
|
-
conn.remote_port.should == port
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe "#close_connection" do
|
28
|
-
before { EM::Connection.any_instance.stub :close_connection }
|
29
|
-
|
30
|
-
it "sets the closed-by-self flag" do
|
31
|
-
pending "How to test a call to super?"
|
32
|
-
|
33
|
-
conn.close_connection
|
34
|
-
conn.should be_closed
|
35
|
-
conn.should be_closed_by_self
|
36
|
-
end
|
37
|
-
|
38
|
-
let(:arg) { stub "arg" }
|
39
|
-
|
40
|
-
it "calls EM::Connection.close_connection" do
|
41
|
-
pending "How to test a call to super?"
|
42
|
-
|
43
|
-
EM::Connection.any_instance.should_receive(:close_connection).with arg
|
44
|
-
conn.close_connection arg
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "#unbind" do
|
49
|
-
it "sets the closed-by-remote flag" do
|
50
|
-
conn.unbind(nil)
|
51
|
-
conn.should be_closed
|
52
|
-
conn.should be_closed_by_remote
|
53
|
-
end
|
54
|
-
|
55
|
-
it "doesn't overwrite an existing closed-by flag" do
|
56
|
-
conn.stub :closed? => true
|
57
|
-
conn.unbind(nil)
|
58
|
-
conn.should be_closed
|
59
|
-
conn.should_not be_closed_by_remote
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/spec/unit/events_spec.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "hatetepe/events"
|
3
|
-
|
4
|
-
describe Hatetepe::Events do
|
5
|
-
let(:klass) {
|
6
|
-
Class.new {
|
7
|
-
include Hatetepe::Events
|
8
|
-
event :foo
|
9
|
-
}
|
10
|
-
}
|
11
|
-
let(:obj) { klass.new }
|
12
|
-
|
13
|
-
context "#event(name, *args)" do
|
14
|
-
let(:args) { ["arg#1", "arg#2", "arg#3"] }
|
15
|
-
let(:called) { [] }
|
16
|
-
|
17
|
-
before {
|
18
|
-
obj.on_foo {|*args| called << [:bar, args] }
|
19
|
-
obj.on_foo {|*args| called << [:baz, args] }
|
20
|
-
}
|
21
|
-
|
22
|
-
it "calls the listeners" do
|
23
|
-
obj.event :foo, *args
|
24
|
-
called.should == [[:bar, args], [:baz, args]]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "#event!(name, *args)" do
|
29
|
-
let(:args) { [:foo, "arg#1", "arg#2"] }
|
30
|
-
|
31
|
-
it "forwards to #event" do
|
32
|
-
obj.should_receive(:event).with(*args)
|
33
|
-
obj.event! *args
|
34
|
-
end
|
35
|
-
|
36
|
-
it "changes the state to specified name" do
|
37
|
-
obj.on_foo {
|
38
|
-
obj.foo?.should be_true
|
39
|
-
}
|
40
|
-
obj.event! :foo
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context ".event(name, *more_names)" do
|
45
|
-
before { klass.event :bar, :baz }
|
46
|
-
|
47
|
-
it "adds #on_name method" do
|
48
|
-
obj.should respond_to(:on_bar)
|
49
|
-
end
|
50
|
-
|
51
|
-
it "adds #name? method" do
|
52
|
-
obj.should respond_to(:bar?)
|
53
|
-
end
|
54
|
-
|
55
|
-
it "calls itself for each additional name" do
|
56
|
-
obj.should respond_to(:on_baz)
|
57
|
-
obj.should respond_to(:baz?)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context "#on_name {|*args| ... }" do
|
62
|
-
let(:block) { proc {} }
|
63
|
-
|
64
|
-
it "adds the block to the listener stack" do
|
65
|
-
obj.on_foo &block
|
66
|
-
obj.on_foo.should include(block)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "#on_name" do
|
71
|
-
let(:blocks) { [proc {}, proc {}] }
|
72
|
-
|
73
|
-
it "returns the listener stack" do
|
74
|
-
obj.on_foo &blocks[0]
|
75
|
-
obj.on_foo &blocks[1]
|
76
|
-
|
77
|
-
obj.on_foo.should == blocks
|
78
|
-
end
|
79
|
-
|
80
|
-
it "returns an empty stack if no listeners have been added yet" do
|
81
|
-
obj.on_foo.should be_empty
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context "#name?" do
|
86
|
-
it "returns true if the state equals :name" do
|
87
|
-
obj.stub :state => :foo
|
88
|
-
obj.foo?.should be_true
|
89
|
-
end
|
90
|
-
|
91
|
-
it "returns false if the state doesn't equal :name" do
|
92
|
-
obj.stub :state => :bar
|
93
|
-
obj.foo?.should be_false
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|