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 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
- success = write(
50
- # Open room
51
- request.to_xml
52
- ).xpath(
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::Muc::Configuration.new response if response
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
- # Generate stanza
255
- request.to_xml
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
- # Generate stanza
295
- request.to_xml
296
- ).xpath(
297
- # Pull out required parts
298
- '//iq[@type="result"]/disco_items:query/disco_items:item',
299
- namespaces
300
- ).map{|item|
301
- # Convert to Jubjub object
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
- # Generate stanza
46
- request.to_xml
47
- ).xpath(
48
- # Pull out required parts
49
- '//iq[@type="result"]/disco_items:query/disco_items:item',
50
- namespaces
51
- ).map{|item|
52
- jid = item.attr('jid')
53
- node = item.attr('node')
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
- success = write(
97
- # Generate stanza
98
- request.to_xml
99
- ).xpath(
100
- # Pull out required parts
101
- '//iq[@type="result"]'
102
- ).any?
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
- response = write(
148
- # Request default node configuration
149
- request.to_xml
150
- ).xpath(
151
- # Get fields
152
- "//iq[@type='result']/pubsub_owner:pubsub/pubsub_owner:default/x_data:x[@type='form']",
153
- namespaces
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
- success = write(
187
- # Generate stanza
188
- request.to_xml
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
- success = write(
219
- # Generate stanza
220
- request.to_xml
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
- result = write(
262
- # Generate stanza
263
- request.to_xml
264
- ).xpath(
265
- # Pull out required parts
266
- '//iq[@type="result"]/pubsub:pubsub/pubsub:subscription',
267
- namespaces
268
- )
269
- if result.any?
270
- subscriber = Jubjub::Jid.new(result.first.attr('jid'))
271
- subid = result.first.attr('subid')
272
- subscription = result.first.attr('subscription')
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
- # Generate stanza
308
- request.to_xml
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
- result = write(
361
- # Generate stanza
362
- request.to_xml
363
- ).xpath(
364
- # Pull out required parts
365
- '//iq[@type="result"]/pubsub:pubsub/pubsub:publish/pubsub:item',
366
- namespaces
367
- )
368
- if result.any?
369
- item_id = result.first.attr('id')
370
- data = request.doc.xpath("//pubsub:item/*", namespaces).to_s
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
- # Generate stanza
405
- request.to_xml
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
- # Generate stanza
455
- request.to_xml
456
- ).xpath(
457
- # Pull out required parts
458
- '//iq[@type="result"]/pubsub:pubsub/pubsub:items/pubsub:item',
459
- namespaces
460
- ).map{|item|
461
- item_id = item.attr('id')
462
- data = item.xpath('./*').to_xml
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
- # Generate stanza
501
- request.to_xml
502
- ).xpath(
503
- # Pull out required parts
504
- '//iq[@type="result"]/pubsub_owner:pubsub/pubsub_owner:affiliations/pubsub_owner:affiliation',
505
- namespaces
506
- ).map{|affiliation|
507
- jid = Jubjub::Jid.new affiliation.attr('jid')
508
- affiliation = affiliation.attr('affiliation')
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
- # Generate stanza
546
- request.to_xml
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
@@ -0,0 +1,3 @@
1
+ require "jubjub/response/response"
2
+ require "jubjub/response/proxy"
3
+ require "jubjub/response/error"
data/lib/jubjub/user.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'jubjub/errors'
2
+ require 'jubjub/response'
2
3
  require 'jubjub/jid'
3
4
  require 'jubjub/connection/xmpp_gateway'
4
5
  require 'jubjub/pubsub'
@@ -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 be_a_kind_of Jubjub::Muc
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 be_a_kind_of Jubjub::Muc
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 be_a_kind_of Array
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 be_a_kind_of Jubjub::Pubsub
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 be_a_kind_of Jubjub::Pubsub::Configuration
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 be_a_kind_of Array
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 be_a_kind_of Jubjub::Pubsub::Subscription
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 be_a_kind_of Jubjub::Pubsub::Item
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 be_a_kind_of Jubjub::Pubsub::Item
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 be_a_kind_of Jubjub::Pubsub::Item
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 be_false
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
@@ -0,0 +1,7 @@
1
+ RSpec::Matchers.define :be_a_kind_of_response_proxied do |secondary_class|
2
+ match do |proxy|
3
+ proxy.proxy_class == Jubjub::Response::Proxy &&
4
+ proxy.proxy_primary.class == Jubjub::Response &&
5
+ proxy.proxy_secondary.class == secondary_class
6
+ end
7
+ 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: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 6
10
- version: 0.0.6
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-16 00:00:00 +01:00
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