jubjub 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +32 -1
- data/lib/jubjub/connection/xmpp_gateway/muc.rb +2 -10
- data/lib/jubjub/connection/xmpp_gateway/pubsub.rb +153 -1
- data/lib/jubjub/data_form.rb +91 -0
- data/lib/jubjub/muc.rb +15 -70
- data/lib/jubjub/pubsub.rb +95 -0
- data/lib/jubjub/user.rb +3 -0
- data/spec/connection/xmpp_gateway_pubsub_spec.rb +102 -0
- data/spec/fixtures/vcr_cassettes/pubsub_publish_with_dataform_payload.yml +28 -0
- data/spec/fixtures/vcr_cassettes/pubsub_publish_with_id.yml +28 -0
- data/spec/fixtures/vcr_cassettes/pubsub_publish_with_string_payload.yml +28 -0
- data/spec/fixtures/vcr_cassettes/pubsub_retract.yml +122 -0
- data/spec/fixtures/vcr_cassettes/pubsub_retrieve_items.yml +166 -0
- data/spec/fixtures/vcr_cassettes/pubsub_setup_node.yml +47 -0
- data/spec/models/data_form_spec.rb +7 -0
- data/spec/models/muc_collection_spec.rb +32 -3
- data/spec/models/muc_configuration_spec.rb +1 -453
- data/spec/models/pubsub_collection_spec.rb +26 -0
- data/spec/models/pubsub_item_collection_spec.rb +76 -0
- data/spec/models/pubsub_item_spec.rb +87 -0
- data/spec/models/pubsub_spec.rb +53 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/shared_examples.rb +477 -0
- metadata +46 -25
data/README.mdown
CHANGED
@@ -50,6 +50,10 @@ Examples
|
|
50
50
|
#<Jubjub::Muc:0x10166dcb0 @jid="think_linux@conference.jabber.ru" @name="think_linux (n/a)">
|
51
51
|
...
|
52
52
|
|
53
|
+
# Find a room
|
54
|
+
u.mucs('conference.jabber.ru')['tota-room']
|
55
|
+
=> #<Jubjub::Muc:0x10166e930 @jid="tota-room@conference.jabber.ru" @name="tota-room (5)">
|
56
|
+
|
53
57
|
# Create a room
|
54
58
|
room = u.mucs.create('jubjub')
|
55
59
|
=> #<Jubjub::Muc:0x101532f58 @jid="jubjub@conference.jabber.org" @name=nil>
|
@@ -79,6 +83,10 @@ Examples
|
|
79
83
|
#<Jubjub::Pubsub:0x101f23a30 @service="pubsub.jabber.org" @node="news">
|
80
84
|
]
|
81
85
|
|
86
|
+
# Find a pubsub node
|
87
|
+
u.pubsub['facts']
|
88
|
+
=> #<Jubjub::Pubsub:0x101f23c88 @service="pubsub.jabber.org" @node="facts">
|
89
|
+
|
82
90
|
# List from a different service?
|
83
91
|
u.pubsub('pubsub.jabber.ru')
|
84
92
|
=> [
|
@@ -97,6 +105,29 @@ Examples
|
|
97
105
|
u.pubsub.subscribe('new_thing')
|
98
106
|
=> #<Jubjub::PubsubSubscription:0x101effd60 @service="pubsub.jabber.org" @node="new_thing" @subscriber="theozaurus@jabber.org" @subid="5129CD7935528" @subscription="subscribed">
|
99
107
|
|
108
|
+
# Publish to a node
|
109
|
+
item = u.pubsub['node_1'].publish(Jubjub::DataForm.new({:foo => {:type => 'boolean', :value => 'bar'}}))
|
110
|
+
=> #<Jubjub::PubsubItem:0x101f2e9f8 @jid="pubsub.jabber.org" @node="node_1" @item_id="519DCAA72FFD6" @data="<x xmlns=\"jabber:x:data\" type=\"submit\">\n <field var=\"foo\">\n <value>false</value>\n </field>\n</x>">
|
111
|
+
|
112
|
+
# Retract an item from a node
|
113
|
+
item.retract
|
114
|
+
=> true
|
115
|
+
|
116
|
+
# Or
|
117
|
+
u.pubsub['node_1'].retract('abc')
|
118
|
+
=> true
|
119
|
+
|
120
|
+
# List items on a node
|
121
|
+
u.pubsub['node_1'].items
|
122
|
+
=> [
|
123
|
+
#<Jubjub::PubsubItem:0x101f7bd48 @jid="pubsub.jabber.org" @node="node_1" @item_id="519DCAA72FFD6" @data="...">,
|
124
|
+
...
|
125
|
+
]
|
126
|
+
|
127
|
+
# Retrieve an item from a node
|
128
|
+
u.pubsub['node_1'].items['519DCAA72FFD6']
|
129
|
+
=> #<Jubjub::PubsubItem:0x101f7bd48 @jid="pubsub.jabber.org" @node="node_1" @item_id="519DCAA72FFD6" @data="...">
|
130
|
+
|
100
131
|
# Unsubscribe
|
101
132
|
subscription.unsubscribe
|
102
133
|
=> true
|
@@ -118,7 +149,7 @@ TODO
|
|
118
149
|
|
119
150
|
- Error handling
|
120
151
|
- MUC user role and affiliation control
|
152
|
+
- Pubsub configuration
|
121
153
|
- Service discovery
|
122
|
-
- Pubsub / PEP
|
123
154
|
- Operations that are not IQ based, such as rosters and two way messaging
|
124
155
|
- Other backends (for servers that are evented)
|
@@ -33,21 +33,13 @@ module Jubjub
|
|
33
33
|
# to='crone1@shakespeare.lit/desktop'
|
34
34
|
# type='result'/>
|
35
35
|
#
|
36
|
-
def create(full_jid, configuration =
|
36
|
+
def create(full_jid, configuration = Jubjub::MucConfiguration.new)
|
37
37
|
room_jid = Jubjub::Jid.new full_jid.node, full_jid.domain
|
38
38
|
|
39
39
|
request = Nokogiri::XML::Builder.new do |xml|
|
40
40
|
xml.iq_(:type => 'set', :to => room_jid) {
|
41
41
|
xml.query_('xmlns' => 'http://jabber.org/protocol/muc#owner'){
|
42
|
-
xml.
|
43
|
-
configuration.settings.each{|name,values|
|
44
|
-
xml.field_('var' => name){
|
45
|
-
values.each {|v|
|
46
|
-
xml.value_ v
|
47
|
-
}
|
48
|
-
}
|
49
|
-
} if configuration
|
50
|
-
}
|
42
|
+
configuration.to_builder(xml.parent)
|
51
43
|
}
|
52
44
|
}
|
53
45
|
end
|
@@ -217,7 +217,159 @@ module Jubjub
|
|
217
217
|
'//iq[@type="result"]'
|
218
218
|
).any?
|
219
219
|
end
|
220
|
-
|
220
|
+
|
221
|
+
# http://xmpp.org/extensions/xep-0060.html#publisher-publish
|
222
|
+
# <iq type='set'
|
223
|
+
# from='hamlet@denmark.lit/blogbot'
|
224
|
+
# to='pubsub.shakespeare.lit'
|
225
|
+
# id='publish1'>
|
226
|
+
# <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
227
|
+
# <publish node='princely_musings'>
|
228
|
+
# <item id='ae890ac52d0df67ed7cfdf51b644e901'>
|
229
|
+
# ...
|
230
|
+
# </item>
|
231
|
+
# </publish>
|
232
|
+
# </pubsub>
|
233
|
+
# </iq>
|
234
|
+
#
|
235
|
+
# Expected
|
236
|
+
# <iq type='result'
|
237
|
+
# from='pubsub.shakespeare.lit'
|
238
|
+
# to='hamlet@denmark.lit/blogbot'
|
239
|
+
# id='publish1'>
|
240
|
+
# <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
241
|
+
# <publish node='princely_musings'>
|
242
|
+
# <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
|
243
|
+
# </publish>
|
244
|
+
# </pubsub>
|
245
|
+
# </iq>
|
246
|
+
def publish(jid, node, data, item_id = nil)
|
247
|
+
item_options = {}
|
248
|
+
item_options[:id] = item_id if item_id
|
249
|
+
|
250
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
251
|
+
xml.iq_(:to => jid, :type => 'set') {
|
252
|
+
xml.pubsub_('xmlns' => namespaces['pubsub']) {
|
253
|
+
xml.publish_(:node => node){
|
254
|
+
xml.item_(item_options){
|
255
|
+
if data.respond_to?( :to_builder )
|
256
|
+
data.to_builder(xml.parent)
|
257
|
+
else
|
258
|
+
xml << data
|
259
|
+
end
|
260
|
+
}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
result = write(
|
267
|
+
# Generate stanza
|
268
|
+
request.to_xml
|
269
|
+
).xpath(
|
270
|
+
# Pull out required parts
|
271
|
+
'//iq[@type="result"]/pubsub:pubsub/pubsub:publish/pubsub:item',
|
272
|
+
namespaces
|
273
|
+
)
|
274
|
+
if result.any?
|
275
|
+
item_id = result.first.attr('id')
|
276
|
+
data = request.doc.xpath("//pubsub:item/*", namespaces).to_s
|
277
|
+
Jubjub::PubsubItem.new jid, node, item_id, data, @connection
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# http://xmpp.org/extensions/xep-0060.html#publisher-delete
|
282
|
+
# <iq type='set'
|
283
|
+
# from='hamlet@denmark.lit/elsinore'
|
284
|
+
# to='pubsub.shakespeare.lit'
|
285
|
+
# id='retract1'>
|
286
|
+
# <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
287
|
+
# <retract node='princely_musings'>
|
288
|
+
# <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
|
289
|
+
# </retract>
|
290
|
+
# </pubsub>
|
291
|
+
# </iq>
|
292
|
+
#
|
293
|
+
# Expected
|
294
|
+
# <iq type='result'
|
295
|
+
# from='pubsub.shakespeare.lit'
|
296
|
+
# to='hamlet@denmark.lit/elsinore'
|
297
|
+
# id='retract1'/>
|
298
|
+
def retract(jid, node, item_id)
|
299
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
300
|
+
xml.iq_(:to => jid, :type => 'set') {
|
301
|
+
xml.pubsub_('xmlns' => namespaces['pubsub']) {
|
302
|
+
xml.retract_(:node => node){
|
303
|
+
xml.item_ :id => item_id
|
304
|
+
}
|
305
|
+
}
|
306
|
+
}
|
307
|
+
end
|
308
|
+
|
309
|
+
write(
|
310
|
+
# Generate stanza
|
311
|
+
request.to_xml
|
312
|
+
).xpath('//iq[@type="result"]').any?
|
313
|
+
end
|
314
|
+
|
315
|
+
# http://xmpp.org/extensions/xep-0060.html#subscriber-retrieve
|
316
|
+
# <iq type='get'
|
317
|
+
# from='francisco@denmark.lit/barracks'
|
318
|
+
# to='pubsub.shakespeare.lit'
|
319
|
+
# id='items1'>
|
320
|
+
# <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
321
|
+
# <items node='princely_musings'/>
|
322
|
+
# </pubsub>
|
323
|
+
# </iq>
|
324
|
+
#
|
325
|
+
# Expected
|
326
|
+
# <iq type='result'
|
327
|
+
# from='pubsub.shakespeare.lit'
|
328
|
+
# to='francisco@denmark.lit/barracks'
|
329
|
+
# id='items1'>
|
330
|
+
# <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
331
|
+
# <items node='princely_musings'>
|
332
|
+
# <item id='368866411b877c30064a5f62b917cffe'>
|
333
|
+
# <entry xmlns='http://www.w3.org/2005/Atom'>
|
334
|
+
# <title>The Uses of This World</title>
|
335
|
+
# <summary>
|
336
|
+
# O, that this too too solid flesh would melt
|
337
|
+
# Thaw and resolve itself into a dew!
|
338
|
+
# </summary>
|
339
|
+
# <link rel='alternate' type='text/html'
|
340
|
+
# href='http://denmark.lit/2003/12/13/atom03'/>
|
341
|
+
# <id>tag:denmark.lit,2003:entry-32396</id>
|
342
|
+
# <published>2003-12-12T17:47:23Z</published>
|
343
|
+
# <updated>2003-12-12T17:47:23Z</updated>
|
344
|
+
# </entry>
|
345
|
+
# </item>
|
346
|
+
# ...
|
347
|
+
# </items>
|
348
|
+
# </pubsub>
|
349
|
+
# </iq>
|
350
|
+
def retrieve_items(jid, node)
|
351
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
352
|
+
xml.iq_(:to => jid, :type => 'get') {
|
353
|
+
xml.pubsub_(:xmlns => namespaces['pubsub']){
|
354
|
+
xml.items_(:node => node)
|
355
|
+
}
|
356
|
+
}
|
357
|
+
end
|
358
|
+
|
359
|
+
write(
|
360
|
+
# Generate stanza
|
361
|
+
request.to_xml
|
362
|
+
).xpath(
|
363
|
+
# Pull out required parts
|
364
|
+
'//iq[@type="result"]/pubsub:pubsub/pubsub:items/pubsub:item',
|
365
|
+
namespaces
|
366
|
+
).map{|item|
|
367
|
+
item_id = item.attr('id')
|
368
|
+
data = item.xpath('./*').to_xml
|
369
|
+
Jubjub::PubsubItem.new jid, node, item_id, data, @connection
|
370
|
+
}
|
371
|
+
end
|
372
|
+
|
221
373
|
private
|
222
374
|
|
223
375
|
def subscriber
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Jubjub
|
4
|
+
class DataForm
|
5
|
+
|
6
|
+
attr_reader :fields
|
7
|
+
|
8
|
+
def initialize(config={})
|
9
|
+
check_config config
|
10
|
+
|
11
|
+
@fields = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](arg)
|
15
|
+
if fields.has_key? arg
|
16
|
+
case fields[arg][:type]
|
17
|
+
when 'boolean'
|
18
|
+
fields[arg][:value] == '1' || fields[arg][:value] == 'true' || fields[arg][:value] == true ? true : false
|
19
|
+
when 'jid-multi'
|
20
|
+
fields[arg][:value].map{|j| Jubjub::Jid.new j }
|
21
|
+
when 'jid-single'
|
22
|
+
Jubjub::Jid.new fields[arg][:value]
|
23
|
+
else
|
24
|
+
fields[arg][:value]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def []=(arg,value)
|
30
|
+
if fields.has_key? arg
|
31
|
+
check_options arg, value if fields[arg].has_key?(:options)
|
32
|
+
value = Array[value].flatten if fields[arg][:type].match /-multi$/
|
33
|
+
fields[arg][:value] = value
|
34
|
+
else
|
35
|
+
raise Jubjub::ArgumentError.new("#{arg} is not a valid field")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def settings
|
40
|
+
Hash[fields.keys.map{|field|
|
41
|
+
[field, Array[self[field]].flatten]
|
42
|
+
}]
|
43
|
+
end
|
44
|
+
|
45
|
+
def ==(thing)
|
46
|
+
thing.is_a?( self.class ) && thing.fields == self.fields
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_builder(root_doc=Nokogiri::XML.parse(""))
|
50
|
+
Nokogiri::XML::Builder.with(root_doc) do |xml|
|
51
|
+
xml.x_('xmlns' => 'jabber:x:data', :type => 'submit') {
|
52
|
+
settings.each{|name,values|
|
53
|
+
xml.field_('var' => name){
|
54
|
+
values.each {|v|
|
55
|
+
xml.value_ v
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def check_options(name, value)
|
66
|
+
valid_options = fields[name][:options].map{|o| o[:value].to_s }
|
67
|
+
invalid_options = Array[value].flatten - valid_options
|
68
|
+
raise Jubjub::ArgumentError.new(
|
69
|
+
"#{invalid_options.join(', ')} is not an accepted value please choose from #{valid_options.join(', ')}"
|
70
|
+
) if invalid_options.any?
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_config(config)
|
74
|
+
required = [:type]
|
75
|
+
understood = required + [:label, :options, :value]
|
76
|
+
|
77
|
+
raise Jubjub::ArgumentError.new("please initialize with a hash of the format { 'foo' => {:type => 'boolean', :value => false, :label => 'Fooey'} }") unless config.is_a? Hash
|
78
|
+
|
79
|
+
config.each do |name,argument|
|
80
|
+
required.each{|r| raise Jubjub::ArgumentError.new(":#{r} is missing for #{name}") unless argument.keys.include? r }
|
81
|
+
|
82
|
+
mystery_arguments = (argument.keys - understood)
|
83
|
+
raise Jubjub::ArgumentError.new(
|
84
|
+
":#{mystery_arguments.join(', :')} is not a recognised option for #{name}"
|
85
|
+
) if mystery_arguments.any?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/lib/jubjub/muc.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'jubjub/data_form'
|
2
|
+
|
1
3
|
module Jubjub
|
2
4
|
class Muc
|
3
5
|
|
@@ -55,6 +57,18 @@ module Jubjub
|
|
55
57
|
|
56
58
|
end
|
57
59
|
|
60
|
+
def [](jid_node_num)
|
61
|
+
case jid_node_num
|
62
|
+
when Fixnum
|
63
|
+
list[jid_node_num]
|
64
|
+
when Jubjub::Jid
|
65
|
+
list.find{|m| m.jid == jid_node_num }
|
66
|
+
else
|
67
|
+
j = Jubjub::Jid.new jid_node_num, jid.domain
|
68
|
+
list.find{|m| m.jid == j }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
58
72
|
# Hint that methods are actually applied to list using method_missing
|
59
73
|
def inspect
|
60
74
|
list.inspect
|
@@ -72,76 +86,7 @@ module Jubjub
|
|
72
86
|
|
73
87
|
end
|
74
88
|
|
75
|
-
class MucConfiguration
|
76
|
-
|
77
|
-
attr_reader :fields
|
78
|
-
|
79
|
-
def initialize(config)
|
80
|
-
check_config config
|
81
|
-
|
82
|
-
@fields = config
|
83
|
-
end
|
84
|
-
|
85
|
-
def [](arg)
|
86
|
-
if fields.has_key? arg
|
87
|
-
case fields[arg][:type]
|
88
|
-
when 'boolean'
|
89
|
-
fields[arg][:value] == '1' || fields[arg][:value] == 'true' || fields[arg][:value] == true ? true : false
|
90
|
-
when 'jid-multi'
|
91
|
-
fields[arg][:value].map{|j| Jubjub::Jid.new j }
|
92
|
-
when 'jid-single'
|
93
|
-
Jubjub::Jid.new fields[arg][:value]
|
94
|
-
else
|
95
|
-
fields[arg][:value]
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def []=(arg,value)
|
101
|
-
if fields.has_key? arg
|
102
|
-
check_options arg, value if fields[arg].has_key?(:options)
|
103
|
-
value = Array[value].flatten if fields[arg][:type].match /-multi$/
|
104
|
-
fields[arg][:value] = value
|
105
|
-
else
|
106
|
-
raise Jubjub::ArgumentError.new("#{arg} is not a valid field")
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def settings
|
111
|
-
Hash[fields.keys.map{|field|
|
112
|
-
[field, Array[self[field]].flatten]
|
113
|
-
}]
|
114
|
-
end
|
115
|
-
|
116
|
-
def ==(thing)
|
117
|
-
thing.is_a?( self.class ) && thing.fields == self.fields
|
118
|
-
end
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def check_options(name, value)
|
123
|
-
valid_options = fields[name][:options].map{|o| o[:value].to_s }
|
124
|
-
invalid_options = Array[value].flatten - valid_options
|
125
|
-
raise Jubjub::ArgumentError.new(
|
126
|
-
"#{invalid_options.join(', ')} is not an accepted value please choose from #{valid_options.join(', ')}"
|
127
|
-
) if invalid_options.any?
|
128
|
-
end
|
129
|
-
|
130
|
-
def check_config(config)
|
131
|
-
required = [:type]
|
132
|
-
understood = required + [:label, :options, :value]
|
133
|
-
|
134
|
-
raise Jubjub::ArgumentError.new("please initialize with a hash of the format { 'foo' => {:type => 'boolean', :value => false, :label => 'Fooey'} }") unless config.is_a? Hash
|
135
|
-
|
136
|
-
config.each do |name,argument|
|
137
|
-
required.each{|r| raise Jubjub::ArgumentError.new(":#{r} is missing for #{name}") unless argument.keys.include? r }
|
138
|
-
|
139
|
-
mystery_arguments = (argument.keys - understood)
|
140
|
-
raise Jubjub::ArgumentError.new(
|
141
|
-
":#{mystery_arguments.join(', :')} is not a recognised option for #{name}"
|
142
|
-
) if mystery_arguments.any?
|
143
|
-
end
|
144
|
-
end
|
89
|
+
class MucConfiguration < DataForm
|
145
90
|
|
146
91
|
end
|
147
92
|
|
data/lib/jubjub/pubsub.rb
CHANGED
@@ -25,12 +25,98 @@ module Jubjub
|
|
25
25
|
@connection.pubsub.unsubscribe jid, node, subid
|
26
26
|
end
|
27
27
|
|
28
|
+
def publish(data, item_id = nil)
|
29
|
+
@connection.pubsub.publish jid, node, data, item_id
|
30
|
+
end
|
31
|
+
|
32
|
+
def retract(item_id)
|
33
|
+
@connection.pubsub.retract jid, node, item_id
|
34
|
+
end
|
35
|
+
|
28
36
|
# Hide the connection details and show jid as string for compactness
|
29
37
|
def inspect
|
30
38
|
obj_id = "%x" % (object_id << 1)
|
31
39
|
"#<#{self.class}:0x#{obj_id} @jid=\"#{jid}\" @node=#{node.inspect}>"
|
32
40
|
end
|
33
41
|
|
42
|
+
def items
|
43
|
+
PubsubItemCollection.new jid, node, @connection
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def method_missing(name, *args, &block)
|
49
|
+
items.send(name, *args, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class PubsubItemCollection
|
55
|
+
|
56
|
+
attr_reader :jid, :node
|
57
|
+
|
58
|
+
def initialize(jid,node,connection)
|
59
|
+
@jid = Jubjub::Jid.new jid
|
60
|
+
@node = node
|
61
|
+
@connection = connection
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](item_num)
|
65
|
+
case item_num
|
66
|
+
when Fixnum
|
67
|
+
items[item_num]
|
68
|
+
else
|
69
|
+
items.find{|i| i.item_id == item_num }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Hint that methods are actually applied to list using method_missing
|
74
|
+
def inspect
|
75
|
+
items.inspect
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def method_missing(name, *args, &block)
|
81
|
+
items.send(name, *args, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def items
|
85
|
+
@items ||= @connection.pubsub.retrieve_items( @jid, @node )
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
class PubsubItem
|
91
|
+
|
92
|
+
attr_reader :jid, :node, :item_id, :data
|
93
|
+
|
94
|
+
def initialize(jid, node, item_id, data, connection)
|
95
|
+
@jid = Jubjub::Jid.new jid
|
96
|
+
@node = node
|
97
|
+
@item_id = item_id
|
98
|
+
@data = data
|
99
|
+
@connection = connection
|
100
|
+
end
|
101
|
+
|
102
|
+
# Hide the connection details and show jid as string for compactness
|
103
|
+
def inspect
|
104
|
+
obj_id = "%x" % (object_id << 1)
|
105
|
+
"#<#{self.class}:0x#{obj_id} @jid=\"#{jid}\" @node=#{node.inspect} @item_id=#{item_id.inspect} @data=#{data.inspect}>"
|
106
|
+
end
|
107
|
+
|
108
|
+
def retract
|
109
|
+
@connection.pubsub.retract jid, node, item_id
|
110
|
+
end
|
111
|
+
|
112
|
+
def ==(other)
|
113
|
+
other.is_a?( self.class ) &&
|
114
|
+
other.jid == self.jid &&
|
115
|
+
other.node == self.node &&
|
116
|
+
other.item_id == self.item_id &&
|
117
|
+
other.data == self.data
|
118
|
+
end
|
119
|
+
|
34
120
|
end
|
35
121
|
|
36
122
|
class PubsubSubscription
|
@@ -87,6 +173,15 @@ module Jubjub
|
|
87
173
|
@connection.pubsub.unsubscribe jid, node, subid
|
88
174
|
end
|
89
175
|
|
176
|
+
def [](node_num)
|
177
|
+
case node_num
|
178
|
+
when Fixnum
|
179
|
+
list[node_num]
|
180
|
+
else
|
181
|
+
list.find{|p| p.node == node_num }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
90
185
|
# Hint that methods are actually applied to list using method_missing
|
91
186
|
def inspect
|
92
187
|
list.inspect
|