jubjub 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|