jubjub 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +47 -1
- data/lib/jubjub/connection/xmpp_gateway/muc.rb +24 -36
- data/lib/jubjub/connection/xmpp_gateway/pubsub.rb +86 -116
- data/lib/jubjub/response/error.rb +33 -0
- data/lib/jubjub/response/proxy.rb +44 -0
- data/lib/jubjub/response/response.rb +33 -0
- data/lib/jubjub/response.rb +3 -0
- data/lib/jubjub/user.rb +1 -0
- data/spec/connection/xmpp_gateway_muc_spec.rb +3 -3
- data/spec/connection/xmpp_gateway_pubsub_spec.rb +8 -8
- data/spec/models/response_error_spec.rb +68 -0
- data/spec/models/response_proxy_spec.rb +143 -0
- data/spec/models/response_spec.rb +113 -0
- data/spec/support/matchers.rb +7 -0
- metadata +16 -4
data/README.mdown
CHANGED
@@ -181,11 +181,57 @@ Examples
|
|
181
181
|
u.pubsub.destroy('old_node', 'pubsub.jabber.ru', 'new_new')
|
182
182
|
=> true
|
183
183
|
|
184
|
+
Dealing with errors
|
185
|
+
===================
|
186
|
+
|
187
|
+
Every returned object from every action is really a Jubjub::Response::Proxy, which delegates to the Jubjub::Response and if the method doesn't exist there to the actual result. As Jubjub::Response only has a few methods it will usually just behaves like the actual result (say a Jubjub::Pubsub::Item). However, you can check what has really happened like so:
|
188
|
+
|
189
|
+
# Attempt to destroy a node that does not exist
|
190
|
+
u.pubsub.destroy('made up')
|
191
|
+
=> false
|
192
|
+
|
193
|
+
# False tells us destroy didn't succeed in this case, but it's not terribly helpful
|
194
|
+
# So we can use methods provided by the Jubjub::Response as well
|
195
|
+
|
196
|
+
response = u.pubsub.destroy('made up')
|
197
|
+
response.success?
|
198
|
+
=> false
|
199
|
+
|
200
|
+
response.stanza.to_s
|
201
|
+
=> "<?xml version=\"1.0\"?>\n<iq type=\"error\" id=\"blather0011\" from=\"pubsub.theo-template.local\" to=\"theozaurus@theo-template.local/42607076141308656900975361\" lang=\"en\">\n <pubsub xmlns=\"http://jabber.org/protocol/pubsub#owner\">\n <delete node=\"made up\"/>\n </pubsub>\n<error code=\"404\" type=\"cancel\"><item-not-found xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/></error></iq>\n"
|
202
|
+
|
203
|
+
# We can get the real result with no proxy sat in front
|
204
|
+
response.result
|
205
|
+
=> false
|
206
|
+
response.result.success?
|
207
|
+
NoMethodError: undefined method `success?' for false:FalseClass
|
208
|
+
from (irb):14
|
209
|
+
|
210
|
+
# We can also get an enhanced error object, Jubjub::Response::Error
|
211
|
+
response.error
|
212
|
+
=> #<Jubjub::Response::Error:0x101ef51f8 @stanza=#<Nokogiri::XML::Element:0x80f7a7bc name="error" attributes=[#<Nokogiri::XML::Attr:0x80f7a654 name="code" value="404">, #<Nokogiri::XML::Attr:0x80f7a640 name="type" value="cancel">] children=[#<Nokogiri::XML::Element:0x80f7a03c name="item-not-found" namespace=#<Nokogiri::XML::Namespace:0x80f79fb0 href="urn:ietf:params:xml:ns:xmpp-stanzas">>]>>
|
213
|
+
|
214
|
+
response.error.stanza.to_s
|
215
|
+
=> "<error code=\"404\" type=\"cancel\">\n <item-not-found xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>\n</error>"
|
216
|
+
|
217
|
+
response.error.condition
|
218
|
+
=> 'item-not-found'
|
219
|
+
|
220
|
+
response.error.type
|
221
|
+
=> 'cancel'
|
222
|
+
|
223
|
+
# If there is any error text this can also be extracted
|
224
|
+
response.error.text
|
225
|
+
=> 'Item not found'
|
226
|
+
|
227
|
+
|
228
|
+
The error `type` and error `condition` are the important factors. The `type` is defined in the [RFC 6121](http://xmpp.org/rfcs/rfc6120.html#stanzas-error-syntax), and helps decide whether the action should be attempted again. The `condition` provides a bit more detail, and will always be part of the [urn:ietf:params:xml:ns:xmpp-stanzas namespace](http://xmpp.org/schemas/stanzaerror.xsd).
|
229
|
+
|
184
230
|
TODO
|
185
231
|
====
|
186
232
|
|
187
|
-
- Error handling
|
188
233
|
- MUC user role and affiliation control
|
234
|
+
- Better exception handling
|
189
235
|
- Service discovery
|
190
236
|
- Operations that are not IQ based, such as rosters and two way messaging
|
191
237
|
- Other backends (for servers that are evented)
|
@@ -46,14 +46,10 @@ module Jubjub
|
|
46
46
|
|
47
47
|
presence full_jid
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# Check for valid response
|
54
|
-
'//iq[@type="result"]'
|
55
|
-
).any?
|
56
|
-
Jubjub::Muc.new room_jid, nil, @connection if success
|
49
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
50
|
+
success = stanza.xpath( '/iq[@type="result"]' ).any?
|
51
|
+
Jubjub::Muc.new room_jid, nil, @connection if success
|
52
|
+
}.proxy_result
|
57
53
|
end
|
58
54
|
|
59
55
|
# http://xmpp.org/extensions/xep-0045.html#createroom-reserved
|
@@ -212,16 +208,14 @@ module Jubjub
|
|
212
208
|
end
|
213
209
|
|
214
210
|
presence full_jid
|
215
|
-
response = write(
|
216
|
-
# Request room configuration
|
217
|
-
request.to_xml
|
218
|
-
).xpath(
|
219
|
-
# Get fields
|
220
|
-
"//iq[@type='result']/muc_owner:query/x_data:x[@type='form']",
|
221
|
-
namespaces
|
222
|
-
)
|
223
211
|
|
224
|
-
Jubjub::
|
212
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
213
|
+
config = stanza.xpath(
|
214
|
+
"/iq[@type='result']/muc_owner:query/x_data:x[@type='form']",
|
215
|
+
namespaces
|
216
|
+
)
|
217
|
+
Jubjub::Muc::Configuration.new config if config
|
218
|
+
}.proxy_result
|
225
219
|
end
|
226
220
|
|
227
221
|
# http://xmpp.org/extensions/xep-0045.html#destroyroom
|
@@ -250,13 +244,9 @@ module Jubjub
|
|
250
244
|
}
|
251
245
|
end
|
252
246
|
|
253
|
-
write
|
254
|
-
|
255
|
-
|
256
|
-
).xpath(
|
257
|
-
# Check for valid response
|
258
|
-
'//iq[@type="result"]'
|
259
|
-
).any?
|
247
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
248
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
249
|
+
}.proxy_result
|
260
250
|
end
|
261
251
|
|
262
252
|
# http://xmpp.org/extensions/xep-0045.html#disco-rooms
|
@@ -289,18 +279,16 @@ module Jubjub
|
|
289
279
|
xml.query_('xmlns' => 'http://jabber.org/protocol/disco#items')
|
290
280
|
}
|
291
281
|
end
|
292
|
-
|
293
|
-
write
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
Jubjub::Muc.new item.attr('jid'), item.attr('name'), @connection
|
303
|
-
}
|
282
|
+
|
283
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
284
|
+
stanza.xpath(
|
285
|
+
'/iq[@type="result"]/disco_items:query/disco_items:item',
|
286
|
+
namespaces
|
287
|
+
).map{|item|
|
288
|
+
# Convert to Jubjub object
|
289
|
+
Jubjub::Muc.new item.attr('jid'), item.attr('name'), @connection
|
290
|
+
}
|
291
|
+
}.proxy_result
|
304
292
|
end
|
305
293
|
|
306
294
|
# http://xmpp.org/extensions/xep-0045.html#exit
|
@@ -40,19 +40,17 @@ module Jubjub
|
|
40
40
|
xml.query_('xmlns' => namespaces['disco_items'])
|
41
41
|
}
|
42
42
|
end
|
43
|
-
|
44
|
-
write
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
Jubjub::Pubsub.new jid, node, @connection
|
55
|
-
}
|
43
|
+
|
44
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
45
|
+
stanza.xpath(
|
46
|
+
'/iq[@type="result"]/disco_items:query/disco_items:item',
|
47
|
+
namespaces
|
48
|
+
).map{|item|
|
49
|
+
jid = item.attr('jid')
|
50
|
+
node = item.attr('node')
|
51
|
+
Jubjub::Pubsub.new jid, node, @connection
|
52
|
+
}
|
53
|
+
}.proxy_result
|
56
54
|
end
|
57
55
|
|
58
56
|
# http://xmpp.org/extensions/xep-0060.html#owner-create-and-configure
|
@@ -93,14 +91,13 @@ module Jubjub
|
|
93
91
|
}
|
94
92
|
end
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
Jubjub::Pubsub.new jid, node, @connection if success
|
94
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
95
|
+
success = stanza.xpath(
|
96
|
+
# Pull out required parts
|
97
|
+
'/iq[@type="result"]'
|
98
|
+
).any?
|
99
|
+
Jubjub::Pubsub.new jid, node, @connection if success
|
100
|
+
}.proxy_result
|
104
101
|
end
|
105
102
|
|
106
103
|
# http://xmpp.org/extensions/xep-0060.html#owner-configure
|
@@ -144,16 +141,14 @@ module Jubjub
|
|
144
141
|
}
|
145
142
|
end
|
146
143
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
Jubjub::Pubsub::Configuration.new response if response
|
144
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
145
|
+
config = stanza.xpath(
|
146
|
+
# Pull out required parts
|
147
|
+
"/iq[@type='result']/pubsub_owner:pubsub/pubsub_owner:default/x_data:x[@type='form']",
|
148
|
+
namespaces
|
149
|
+
)
|
150
|
+
Jubjub::Pubsub::Configuration.new config if config
|
151
|
+
}.proxy_result
|
157
152
|
end
|
158
153
|
|
159
154
|
# http://xmpp.org/extensions/xep-0060.html#owner-delete
|
@@ -183,13 +178,9 @@ module Jubjub
|
|
183
178
|
}
|
184
179
|
end
|
185
180
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
).xpath(
|
190
|
-
# Pull out required parts
|
191
|
-
'//iq[@type="result"]'
|
192
|
-
).any?
|
181
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
182
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
183
|
+
}.proxy_result
|
193
184
|
end
|
194
185
|
|
195
186
|
# http://xmpp.org/extensions/xep-0060.html#owner-purge
|
@@ -215,13 +206,9 @@ module Jubjub
|
|
215
206
|
}
|
216
207
|
end
|
217
208
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
).xpath(
|
222
|
-
# Pull out required parts
|
223
|
-
'//iq[@type="result"]'
|
224
|
-
).any?
|
209
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
210
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
211
|
+
}.proxy_result
|
225
212
|
end
|
226
213
|
|
227
214
|
# http://xmpp.org/extensions/xep-0060.html#subscriber-subscribe
|
@@ -257,21 +244,19 @@ module Jubjub
|
|
257
244
|
}
|
258
245
|
}
|
259
246
|
end
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
Jubjub::Pubsub::Subscription.new jid, node, subscriber, subid, subscription, @connection
|
274
|
-
end
|
247
|
+
|
248
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
249
|
+
result = stanza.xpath(
|
250
|
+
'/iq[@type="result"]/pubsub:pubsub/pubsub:subscription',
|
251
|
+
namespaces
|
252
|
+
)
|
253
|
+
if result.any?
|
254
|
+
subscriber = Jubjub::Jid.new(result.first.attr('jid'))
|
255
|
+
subid = result.first.attr('subid')
|
256
|
+
subscription = result.first.attr('subscription')
|
257
|
+
Jubjub::Pubsub::Subscription.new jid, node, subscriber, subid, subscription, @connection
|
258
|
+
end
|
259
|
+
}.proxy_result
|
275
260
|
end
|
276
261
|
|
277
262
|
# http://xmpp.org/extensions/xep-0060.html#subscriber-unsubscribe
|
@@ -303,13 +288,9 @@ module Jubjub
|
|
303
288
|
}
|
304
289
|
end
|
305
290
|
|
306
|
-
write
|
307
|
-
|
308
|
-
|
309
|
-
).xpath(
|
310
|
-
# Pull out required parts
|
311
|
-
'//iq[@type="result"]'
|
312
|
-
).any?
|
291
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
292
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
293
|
+
}.proxy_result
|
313
294
|
end
|
314
295
|
|
315
296
|
# http://xmpp.org/extensions/xep-0060.html#publisher-publish
|
@@ -357,19 +338,17 @@ module Jubjub
|
|
357
338
|
}
|
358
339
|
end
|
359
340
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
Jubjub::Pubsub::Item.new jid, node, item_id, data, @connection
|
372
|
-
end
|
341
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
342
|
+
result = stanza.xpath(
|
343
|
+
'/iq[@type="result"]/pubsub:pubsub/pubsub:publish/pubsub:item',
|
344
|
+
namespaces
|
345
|
+
)
|
346
|
+
if result.any?
|
347
|
+
item_id = result.first.attr('id')
|
348
|
+
data = request.doc.xpath("//pubsub:item/*", namespaces).to_s
|
349
|
+
Jubjub::Pubsub::Item.new jid, node, item_id, data, @connection
|
350
|
+
end
|
351
|
+
}.proxy_result
|
373
352
|
end
|
374
353
|
|
375
354
|
# http://xmpp.org/extensions/xep-0060.html#publisher-delete
|
@@ -400,10 +379,9 @@ module Jubjub
|
|
400
379
|
}
|
401
380
|
end
|
402
381
|
|
403
|
-
write
|
404
|
-
|
405
|
-
|
406
|
-
).xpath('//iq[@type="result"]').any?
|
382
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
383
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
384
|
+
}.proxy_result
|
407
385
|
end
|
408
386
|
|
409
387
|
# http://xmpp.org/extensions/xep-0060.html#subscriber-retrieve
|
@@ -449,19 +427,17 @@ module Jubjub
|
|
449
427
|
}
|
450
428
|
}
|
451
429
|
end
|
452
|
-
|
453
|
-
write
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
Jubjub::Pubsub::Item.new jid, node, item_id, data, @connection
|
464
|
-
}
|
430
|
+
|
431
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
432
|
+
stanza.xpath(
|
433
|
+
'/iq[@type="result"]/pubsub:pubsub/pubsub:items/pubsub:item',
|
434
|
+
namespaces
|
435
|
+
).map{|item|
|
436
|
+
item_id = item.attr('id')
|
437
|
+
data = item.xpath('./*').to_xml
|
438
|
+
Jubjub::Pubsub::Item.new jid, node, item_id, data, @connection
|
439
|
+
}
|
440
|
+
}.proxy_result
|
465
441
|
end
|
466
442
|
|
467
443
|
|
@@ -496,18 +472,16 @@ module Jubjub
|
|
496
472
|
}
|
497
473
|
end
|
498
474
|
|
499
|
-
write
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
Jubjub::Pubsub::Affiliation.new pubsub_jid, pubsub_node, jid, affiliation, @connection
|
510
|
-
}
|
475
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
476
|
+
stanza.xpath(
|
477
|
+
'/iq[@type="result"]/pubsub_owner:pubsub/pubsub_owner:affiliations/pubsub_owner:affiliation',
|
478
|
+
namespaces
|
479
|
+
).map{|item|
|
480
|
+
jid = Jubjub::Jid.new item.attr('jid')
|
481
|
+
affiliation = item.attr('affiliation')
|
482
|
+
Jubjub::Pubsub::Affiliation.new pubsub_jid, pubsub_node, jid, affiliation, @connection
|
483
|
+
}
|
484
|
+
}.proxy_result
|
511
485
|
end
|
512
486
|
|
513
487
|
# http://xmpp.org/extensions/xep-0060.html#owner-affiliations-modify
|
@@ -541,13 +515,9 @@ module Jubjub
|
|
541
515
|
}
|
542
516
|
end
|
543
517
|
|
544
|
-
write
|
545
|
-
|
546
|
-
|
547
|
-
).xpath(
|
548
|
-
# Pull out required parts
|
549
|
-
'//iq[@type="result"]'
|
550
|
-
).any?
|
518
|
+
Jubjub::Response.new( write request.to_xml ){|stanza|
|
519
|
+
stanza.xpath( '/iq[@type="result"]' ).any?
|
520
|
+
}.proxy_result
|
551
521
|
end
|
552
522
|
|
553
523
|
private
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Jubjub
|
2
|
+
class Response
|
3
|
+
class Error
|
4
|
+
|
5
|
+
attr_reader :stanza
|
6
|
+
|
7
|
+
def initialize(xml)
|
8
|
+
@stanza = xml
|
9
|
+
end
|
10
|
+
|
11
|
+
def condition
|
12
|
+
@condition ||= begin
|
13
|
+
condition = @stanza.xpath('//error/ietf:*','ietf' => 'urn:ietf:params:xml:ns:xmpp-stanzas').first
|
14
|
+
condition.name if condition
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
@error_type ||= stanza.xpath('//error').first.attr('type')
|
20
|
+
end
|
21
|
+
|
22
|
+
def text(language=nil)
|
23
|
+
if language
|
24
|
+
xpath = "//error/text[@xml:lang='#{language}']"
|
25
|
+
else
|
26
|
+
xpath = "//error/text"
|
27
|
+
end
|
28
|
+
stanza.xpath(xpath).text
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Jubjub
|
2
|
+
class Response
|
3
|
+
class Proxy
|
4
|
+
|
5
|
+
# Turn proxy class into a 'BasicObject'
|
6
|
+
instance_methods.each do |m|
|
7
|
+
undef_method(m) if m.to_s !~ /(?:^__|^nil?$|^send$|^object_id$|^should$)/
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :proxy_primary, :proxy_secondary
|
11
|
+
|
12
|
+
def initialize(primary, secondary, primary_method)
|
13
|
+
@proxy_primary = primary
|
14
|
+
@proxy_secondary = secondary
|
15
|
+
@primary_method = primary_method
|
16
|
+
end
|
17
|
+
|
18
|
+
# We really want to show the secondary object
|
19
|
+
# as the primary is just a thin layer on top
|
20
|
+
def inspect
|
21
|
+
proxy_secondary.inspect
|
22
|
+
end
|
23
|
+
|
24
|
+
# Used to give away this is really a proxy
|
25
|
+
def proxy_class
|
26
|
+
Jubjub::Response::Proxy
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def method_missing(name, *args, &block)
|
32
|
+
# If the method exists on the primary use that
|
33
|
+
# unless it's the method name called to create the proxy from the primary, or is a standard object method
|
34
|
+
if name.to_s != @primary_method && (proxy_primary.public_methods - Object.public_methods).include?( name.to_s )
|
35
|
+
proxy_primary.send(name, *args, &block)
|
36
|
+
else
|
37
|
+
# Else use a method on the secondary
|
38
|
+
proxy_secondary.send(name, *args, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Jubjub
|
2
|
+
|
3
|
+
class Response
|
4
|
+
|
5
|
+
attr_reader :stanza, :result
|
6
|
+
|
7
|
+
def initialize(xml,&block)
|
8
|
+
@stanza = xml
|
9
|
+
|
10
|
+
@result = nil
|
11
|
+
@result = yield stanza if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
def proxy_result
|
15
|
+
# Allows some syntax sugar. We can chain from the result,
|
16
|
+
# but still get access to the response via the proxy
|
17
|
+
@proxy_result ||= Proxy.new self, result, 'proxy_result'
|
18
|
+
end
|
19
|
+
|
20
|
+
def success?
|
21
|
+
@success ||= stanza.xpath('/iq[@type="result"]|/iq[@type="set"]|/iq[@type="get"]').any?
|
22
|
+
end
|
23
|
+
|
24
|
+
def error
|
25
|
+
@errors ||= begin
|
26
|
+
s = stanza.at_xpath('/iq[@type="error"]/error')
|
27
|
+
Error.new s if s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/jubjub/user.rb
CHANGED
@@ -14,7 +14,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
14
14
|
|
15
15
|
it "return a Jubjub::Muc" do
|
16
16
|
@room = @connection.muc.create( Jubjub::Jid.new 'room@conference.theo-template.local/nick' )
|
17
|
-
@room.should
|
17
|
+
@room.should be_a_kind_of_response_proxied Jubjub::Muc
|
18
18
|
@room.jid.should == Jubjub::Jid.new( 'room@conference.theo-template.local' )
|
19
19
|
end
|
20
20
|
|
@@ -32,7 +32,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
32
32
|
@config = Jubjub::Muc::Configuration.new("allow_query_users" => { :type => "boolean", :value => "1", :label => "Allow users to query other users" })
|
33
33
|
|
34
34
|
@room = @connection.muc.create( Jubjub::Jid.new( 'room@conference.theo-template.local/nick' ), @config )
|
35
|
-
@room.should
|
35
|
+
@room.should be_a_kind_of_response_proxied Jubjub::Muc
|
36
36
|
@room.jid.should == Jubjub::Jid.new( 'room@conference.theo-template.local' )
|
37
37
|
end
|
38
38
|
|
@@ -104,7 +104,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
104
104
|
|
105
105
|
it "return an array of Jubjub::Muc" do
|
106
106
|
list = @connection.muc.list( Jubjub::Jid.new 'conference.theo-template.local' )
|
107
|
-
list.should
|
107
|
+
list.should be_a_kind_of_response_proxied Array
|
108
108
|
|
109
109
|
list.size.should eql(2)
|
110
110
|
list[0].should be_a_kind_of Jubjub::Muc
|
@@ -15,7 +15,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
15
15
|
it "return a Jubjub::Pubsub" do
|
16
16
|
@pubsub = @connection.pubsub.create 'pubsub.theo-template.local', 'node_1'
|
17
17
|
|
18
|
-
@pubsub.should
|
18
|
+
@pubsub.should be_a_kind_of_response_proxied Jubjub::Pubsub
|
19
19
|
@pubsub.jid.should == Jubjub::Jid.new('pubsub.theo-template.local')
|
20
20
|
@pubsub.node.should == 'node_1'
|
21
21
|
end
|
@@ -82,7 +82,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
82
82
|
|
83
83
|
config = @connection.pubsub.default_configuration 'pubsub.theo-template.local'
|
84
84
|
|
85
|
-
config.should
|
85
|
+
config.should be_a_kind_of_response_proxied Jubjub::Pubsub::Configuration
|
86
86
|
config.should == Jubjub::Pubsub::Configuration.new( expected_config )
|
87
87
|
end
|
88
88
|
end
|
@@ -130,7 +130,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
130
130
|
|
131
131
|
it "return an array of Jubjub::Muc" do
|
132
132
|
list = @connection.pubsub.list 'pubsub.theo-template.local'
|
133
|
-
list.should
|
133
|
+
list.should be_a_kind_of_response_proxied Array
|
134
134
|
|
135
135
|
list.size.should eql(2)
|
136
136
|
list[0].should be_a_kind_of Jubjub::Pubsub
|
@@ -173,7 +173,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
173
173
|
it "return a Jubjub::Pubsub::Subscription" do
|
174
174
|
@subscription = @connection.pubsub.subscribe( 'pubsub.theo-template.local', 'node_1' )
|
175
175
|
|
176
|
-
@subscription.should
|
176
|
+
@subscription.should be_a_kind_of_response_proxied Jubjub::Pubsub::Subscription
|
177
177
|
@subscription.jid.should == Jubjub::Jid.new('pubsub.theo-template.local')
|
178
178
|
@subscription.node.should == 'node_1'
|
179
179
|
@subscription.subscriber.should == @jid
|
@@ -239,7 +239,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
239
239
|
|
240
240
|
it "should return a Jubjub::Pubsub::Item" do
|
241
241
|
i = @connection.pubsub.publish 'pubsub.theo-template.local', 'node_1', Jubjub::DataForm.new, '123'
|
242
|
-
i.should
|
242
|
+
i.should be_a_kind_of_response_proxied Jubjub::Pubsub::Item
|
243
243
|
i.item_id.should == '123'
|
244
244
|
i.data.should == "<x xmlns=\"jabber:x:data\" type=\"submit\"/>"
|
245
245
|
end
|
@@ -252,7 +252,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
252
252
|
it "should return a Jubjub::Pubsub::Item" do
|
253
253
|
item = "<x xmlns=\"jabber:x:data\" type=\"submit\"><field var=\"foo\"><value>true</value></field></x>"
|
254
254
|
i = @connection.pubsub.publish 'pubsub.theo-template.local', 'node_1', item
|
255
|
-
i.should
|
255
|
+
i.should be_a_kind_of_response_proxied Jubjub::Pubsub::Item
|
256
256
|
i.item_id.should be_a_kind_of String
|
257
257
|
i.data.should == "<x xmlns=\"jabber:x:data\" type=\"submit\">\n <field var=\"foo\">\n <value>true</value>\n </field>\n</x>"
|
258
258
|
end
|
@@ -264,7 +264,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
264
264
|
|
265
265
|
it "should return a Jubjub::Pubsub::Item" do
|
266
266
|
i = @connection.pubsub.publish 'pubsub.theo-template.local', 'node_1', Jubjub::DataForm.new({ :foo => {:type => "boolean", :value => true }})
|
267
|
-
i.should
|
267
|
+
i.should be_a_kind_of_response_proxied Jubjub::Pubsub::Item
|
268
268
|
i.item_id.should be_a_kind_of String
|
269
269
|
i.data.should == "<x xmlns=\"jabber:x:data\" type=\"submit\">\n <field var=\"foo\">\n <value>true</value>\n </field>\n</x>"
|
270
270
|
end
|
@@ -292,7 +292,7 @@ describe Jubjub::Connection::XmppGateway do
|
|
292
292
|
end
|
293
293
|
|
294
294
|
it "should return false when not successful" do
|
295
|
-
@connection.pubsub.retract( 'pubsub.theo-template.local', 'node_pubsub_retract', "wibble" ).should
|
295
|
+
@connection.pubsub.retract( 'pubsub.theo-template.local', 'node_pubsub_retract', "wibble" ).should equal(false)
|
296
296
|
end
|
297
297
|
|
298
298
|
after do
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jubjub::Response::Error do
|
4
|
+
|
5
|
+
describe 'creating' do
|
6
|
+
|
7
|
+
it 'should take a stanza' do
|
8
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'><feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>"
|
9
|
+
|
10
|
+
response = Jubjub::Response::Error.new xml
|
11
|
+
|
12
|
+
response.stanza.should == xml
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'instance method' do
|
18
|
+
|
19
|
+
describe 'condition' do
|
20
|
+
it 'should return a "urn:ietf:params:xml:ns:xmpp-stanzas" error condition' do
|
21
|
+
xml = Nokogiri::XML::Document.parse "<error><bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'></error>"
|
22
|
+
Jubjub::Response::Error.new( xml ).condition.should == "bad-request"
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return nil if unknown' do
|
26
|
+
xml = Nokogiri::XML::Document.parse "<error><text>Something went wrong</text><error/>"
|
27
|
+
Jubjub::Response::Error.new( xml ).condition.should equal(nil)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'type' do
|
32
|
+
it 'should return nil if no error type available' do
|
33
|
+
xml = Nokogiri::XML::Document.parse "<error/>"
|
34
|
+
Jubjub::Response::Error.new( xml ).type.should equal(nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return value errors present' do
|
38
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'/>"
|
39
|
+
Jubjub::Response::Error.new( xml ).type.should == 'cancel'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'text' do
|
44
|
+
it 'should return empty string if no text is available' do
|
45
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'/>"
|
46
|
+
Jubjub::Response::Error.new( xml ).text.should == ""
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return the text if available' do
|
50
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'><text>Hello!</text></error>"
|
51
|
+
Jubjub::Response::Error.new( xml ).text.should == "Hello!"
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should return all text if available if multiple locales available' do
|
55
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'><text xml:lang='en'>Hello!</text><text xml:lang='fr'>Bonjour!</text></error>"
|
56
|
+
Jubjub::Response::Error.new( xml ).text.should == "Hello!Bonjour!"
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return the text in the correct locale if language specified' do
|
60
|
+
xml = Nokogiri::XML::Document.parse "<error type='cancel'><text xml:lang='en'>Hello!</text><text xml:lang='fr'>Bonjour!</text></error>"
|
61
|
+
Jubjub::Response::Error.new( xml ).text('fr').should == "Bonjour!"
|
62
|
+
Jubjub::Response::Error.new( xml ).text('en').should == "Hello!"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
describe Jubjub::Response::Proxy do
|
2
|
+
|
3
|
+
describe "creating" do
|
4
|
+
|
5
|
+
it "should require proxy_primary, proxy_secondary and public_method" do
|
6
|
+
primary = "String"
|
7
|
+
secondary = ["Array"]
|
8
|
+
|
9
|
+
p = Jubjub::Response::Proxy.new primary, secondary, "to_s"
|
10
|
+
|
11
|
+
p.proxy_primary.should equal(primary)
|
12
|
+
p.proxy_secondary.should equal(secondary)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "proxied methods" do
|
18
|
+
|
19
|
+
before do
|
20
|
+
@primary_class = Class.new do
|
21
|
+
def abc() end
|
22
|
+
def efg() end
|
23
|
+
def xyz() end
|
24
|
+
end
|
25
|
+
|
26
|
+
@secondary_class = Class.new do
|
27
|
+
def abc() end # Same as primary
|
28
|
+
def efg() end # Same as primary
|
29
|
+
def cba() end # Does not exist on primary
|
30
|
+
end
|
31
|
+
|
32
|
+
@primary = @primary_class.new
|
33
|
+
@secondary = @secondary_class.new
|
34
|
+
end
|
35
|
+
|
36
|
+
subject { Jubjub::Response::Proxy.new @primary, @secondary, 'efg' }
|
37
|
+
|
38
|
+
describe "that exist on proxy_primary" do
|
39
|
+
|
40
|
+
it "should not defer the primary_method" do
|
41
|
+
@primary.should_receive(:efg).never
|
42
|
+
|
43
|
+
subject.efg
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not defer methods that belong to Object.public_methods" do
|
47
|
+
@primary.should_receive(:class).never
|
48
|
+
|
49
|
+
subject.class
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should defer to the proxy_primary" do
|
53
|
+
@primary.should_receive(:abc)
|
54
|
+
|
55
|
+
subject.abc
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "that don't defer to proxy_primary" do
|
61
|
+
|
62
|
+
it "should defer to proxy_secondary" do
|
63
|
+
@secondary.should_receive(:cba)
|
64
|
+
|
65
|
+
subject.cba
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should defer Object.public_methods to proxy_secondary" do
|
69
|
+
@secondary.should_receive(:class)
|
70
|
+
|
71
|
+
subject.class
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should defer to proxy_secondary if primary_method" do
|
75
|
+
@secondary.should_receive(:efg)
|
76
|
+
|
77
|
+
subject.efg
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should blow up if it doesn't exist on proxy_secondary either" do
|
81
|
+
expect {
|
82
|
+
subject.explode
|
83
|
+
}.to raise_error(NoMethodError,"undefined method `explode' for #{@secondary.inspect}")
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "instance method" do
|
91
|
+
|
92
|
+
describe "inspect" do
|
93
|
+
|
94
|
+
it "should really inspect proxy_secondary" do
|
95
|
+
# The proxy_primary is just a thin layer over the top of the proxy_secondary
|
96
|
+
# So make sure inspect shows us the proxy_secondary
|
97
|
+
primary = "String"
|
98
|
+
secondary = ["Array"]
|
99
|
+
|
100
|
+
p = Jubjub::Response::Proxy.new primary, secondary, "to_s"
|
101
|
+
|
102
|
+
p.inspect.should == secondary.inspect
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "proxy_primary" do
|
108
|
+
|
109
|
+
it "should return the proxy_primary object" do
|
110
|
+
primary = "p"
|
111
|
+
|
112
|
+
proxy = Jubjub::Response::Proxy.new primary, "s", "to_s"
|
113
|
+
|
114
|
+
proxy.proxy_primary.should equal(primary)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "proxy_secondary" do
|
120
|
+
|
121
|
+
it "should return the proxy_secondary object" do
|
122
|
+
secondary = "p"
|
123
|
+
|
124
|
+
proxy = Jubjub::Response::Proxy.new "p", secondary, "to_s"
|
125
|
+
|
126
|
+
proxy.proxy_secondary.should equal(secondary)
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "proxy_class" do
|
132
|
+
|
133
|
+
it "should return Jubjub::Response::Proxy" do
|
134
|
+
p = Jubjub::Response::Proxy.new "p", "s", "to_s"
|
135
|
+
|
136
|
+
p.proxy_class.should equal(Jubjub::Response::Proxy)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jubjub::Response do
|
4
|
+
|
5
|
+
describe 'creating' do
|
6
|
+
|
7
|
+
it 'should take a stanza' do
|
8
|
+
stanza = xml_fixture 'dataform_1'
|
9
|
+
|
10
|
+
response = Jubjub::Response.new stanza
|
11
|
+
|
12
|
+
response.stanza.should == stanza
|
13
|
+
response.result.should == nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should take a block to define result' do
|
17
|
+
stanza = xml_fixture 'dataform_1'
|
18
|
+
|
19
|
+
namespaces = {
|
20
|
+
'commands' => 'http://jabber.org/protocol/commands',
|
21
|
+
'x_data' => 'jabber:x:data'
|
22
|
+
}
|
23
|
+
|
24
|
+
response = Jubjub::Response.new( stanza ) do |s|
|
25
|
+
s.xpath(
|
26
|
+
"//iq[@type='result']/commands:command/x_data:x[@type='form']/x_data:instructions",
|
27
|
+
namespaces
|
28
|
+
).text
|
29
|
+
end
|
30
|
+
|
31
|
+
response.result.should == 'Fill out this form to configure your new bot!'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'instance method' do
|
37
|
+
|
38
|
+
describe 'result' do
|
39
|
+
|
40
|
+
before { @stanza = xml_fixture 'dataform_1' }
|
41
|
+
|
42
|
+
it 'should return result of block used in initialization if specified' do
|
43
|
+
Jubjub::Response.new( @stanza ){ "Result" }.result.should == "Result"
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should return nil if no block provided' do
|
47
|
+
Jubjub::Response.new( @stanza ).result.should == nil
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'proxy_result' do
|
53
|
+
|
54
|
+
before { @stanza = xml_fixture 'dataform_1' }
|
55
|
+
|
56
|
+
it 'should return proxy of result' do
|
57
|
+
result = "Result"
|
58
|
+
Jubjub::Response.new( @stanza ){ result }.proxy_result.should be_a_kind_of_response_proxied result.class
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'success?' do
|
64
|
+
it 'should return true when stanza is iq[@type="get"]' do
|
65
|
+
xml = Nokogiri::XML::Document.parse "<iq type='get'/>"
|
66
|
+
Jubjub::Response.new( xml ).success?.should equal(true)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return true when stanza is iq[@type="result"]' do
|
70
|
+
xml = Nokogiri::XML::Document.parse "<iq type='result'/>"
|
71
|
+
Jubjub::Response.new( xml ).success?.should equal(true)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should return true when stanza is iq[@type="set"]' do
|
75
|
+
xml = Nokogiri::XML::Document.parse "<iq type='set'/>"
|
76
|
+
Jubjub::Response.new( xml ).success?.should equal(true)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should return false when stanza is iq[@type="error"]' do
|
80
|
+
xml = Nokogiri::XML::Document.parse "<iq type='error'/>"
|
81
|
+
Jubjub::Response.new( xml ).success?.should equal(false)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should not look at child iq elements' do
|
85
|
+
xml = Nokogiri::XML::Document.parse "<totally><wrong><iq type='result'/></wrong></totally>"
|
86
|
+
Jubjub::Response.new( xml ).success?.should equal(false)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should return false when stanza is nonsensical' do
|
90
|
+
xml = Nokogiri::XML::Document.parse "<presence/>"
|
91
|
+
Jubjub::Response.new( xml ).success?.should equal(false)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'error' do
|
96
|
+
|
97
|
+
it 'should return Jubjub::Response:Error object if error present' do
|
98
|
+
xml = Nokogiri::XML::Document.parse "<iq type='error'><error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'></error></iq>"
|
99
|
+
r = Jubjub::Response.new( xml )
|
100
|
+
r.error.should be_a Jubjub::Response::Error
|
101
|
+
r.error.condition.should == "policy-violation"
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should return nil if error is not present' do
|
105
|
+
xml = Nokogiri::XML::Document.parse "<iq type='set'/>"
|
106
|
+
Jubjub::Response.new( xml ).error.should be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jubjub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Theo Cushion
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-21 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -119,6 +119,10 @@ files:
|
|
119
119
|
- lib/jubjub/pubsub/pubsub.rb
|
120
120
|
- lib/jubjub/pubsub/subscription.rb
|
121
121
|
- lib/jubjub/pubsub.rb
|
122
|
+
- lib/jubjub/response/error.rb
|
123
|
+
- lib/jubjub/response/proxy.rb
|
124
|
+
- lib/jubjub/response/response.rb
|
125
|
+
- lib/jubjub/response.rb
|
122
126
|
- lib/jubjub/user.rb
|
123
127
|
- lib/jubjub.rb
|
124
128
|
- LICENSE
|
@@ -162,8 +166,12 @@ files:
|
|
162
166
|
- spec/models/pubsub_item_spec.rb
|
163
167
|
- spec/models/pubsub_spec.rb
|
164
168
|
- spec/models/pubsub_subscription_spec.rb
|
169
|
+
- spec/models/response_error_spec.rb
|
170
|
+
- spec/models/response_proxy_spec.rb
|
171
|
+
- spec/models/response_spec.rb
|
165
172
|
- spec/spec_helper.rb
|
166
173
|
- spec/support/helpers.rb
|
174
|
+
- spec/support/matchers.rb
|
167
175
|
- spec/support/shared_examples.rb
|
168
176
|
- .rspec
|
169
177
|
- .infinity_test
|
@@ -243,8 +251,12 @@ test_files:
|
|
243
251
|
- spec/models/pubsub_item_spec.rb
|
244
252
|
- spec/models/pubsub_spec.rb
|
245
253
|
- spec/models/pubsub_subscription_spec.rb
|
254
|
+
- spec/models/response_error_spec.rb
|
255
|
+
- spec/models/response_proxy_spec.rb
|
256
|
+
- spec/models/response_spec.rb
|
246
257
|
- spec/spec_helper.rb
|
247
258
|
- spec/support/helpers.rb
|
259
|
+
- spec/support/matchers.rb
|
248
260
|
- spec/support/shared_examples.rb
|
249
261
|
- .rspec
|
250
262
|
- .infinity_test
|