sprsquish-blather 0.3.4 → 0.4.0

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.
Files changed (110) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +41 -12
  3. data/examples/echo.rb +1 -1
  4. data/examples/execute.rb +0 -5
  5. data/examples/pubsub/cli.rb +64 -0
  6. data/examples/pubsub/ping_pong.rb +18 -0
  7. data/examples/rosterprint.rb +14 -0
  8. data/examples/xmpp4r/echo.rb +35 -0
  9. data/lib/blather/client/client.rb +19 -13
  10. data/lib/blather/client/dsl/pubsub.rb +133 -0
  11. data/lib/blather/client/dsl.rb +16 -0
  12. data/lib/blather/client.rb +1 -1
  13. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
  14. data/lib/blather/core_ext/active_support.rb +1 -117
  15. data/lib/blather/core_ext/nokogiri.rb +35 -0
  16. data/lib/blather/errors/sasl_error.rb +3 -1
  17. data/lib/blather/errors/stanza_error.rb +10 -17
  18. data/lib/blather/errors/stream_error.rb +11 -14
  19. data/lib/blather/errors.rb +3 -20
  20. data/lib/blather/jid.rb +1 -0
  21. data/lib/blather/roster.rb +9 -0
  22. data/lib/blather/roster_item.rb +6 -1
  23. data/lib/blather/stanza/disco/disco_info.rb +45 -33
  24. data/lib/blather/stanza/disco/disco_items.rb +32 -21
  25. data/lib/blather/stanza/disco.rb +7 -1
  26. data/lib/blather/stanza/iq/query.rb +16 -8
  27. data/lib/blather/stanza/iq/roster.rb +33 -22
  28. data/lib/blather/stanza/iq.rb +13 -8
  29. data/lib/blather/stanza/message.rb +20 -31
  30. data/lib/blather/stanza/presence/status.rb +13 -21
  31. data/lib/blather/stanza/presence/subscription.rb +11 -16
  32. data/lib/blather/stanza/presence.rb +3 -5
  33. data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
  34. data/lib/blather/stanza/pubsub/create.rb +43 -0
  35. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  36. data/lib/blather/stanza/pubsub/event.rb +77 -0
  37. data/lib/blather/stanza/pubsub/items.rb +63 -0
  38. data/lib/blather/stanza/pubsub/publish.rb +58 -0
  39. data/lib/blather/stanza/pubsub/retract.rb +53 -0
  40. data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
  41. data/lib/blather/stanza/pubsub/subscription.rb +66 -0
  42. data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
  43. data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
  44. data/lib/blather/stanza/pubsub.rb +63 -0
  45. data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
  46. data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
  47. data/lib/blather/stanza/pubsub_owner.rb +41 -0
  48. data/lib/blather/stanza.rb +35 -18
  49. data/lib/blather/stream/client.rb +1 -2
  50. data/lib/blather/stream/component.rb +9 -5
  51. data/lib/blather/stream/features/resource.rb +63 -0
  52. data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
  53. data/lib/blather/stream/features/session.rb +44 -0
  54. data/lib/blather/stream/features/tls.rb +28 -0
  55. data/lib/blather/stream/features.rb +53 -0
  56. data/lib/blather/stream/parser.rb +70 -46
  57. data/lib/blather/stream.rb +76 -168
  58. data/lib/blather/xmpp_node.rb +113 -52
  59. data/lib/blather.rb +35 -12
  60. data/spec/blather/client/client_spec.rb +44 -58
  61. data/spec/blather/client/dsl/pubsub_spec.rb +465 -0
  62. data/spec/blather/client/dsl_spec.rb +19 -6
  63. data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
  64. data/spec/blather/errors/sasl_error_spec.rb +8 -8
  65. data/spec/blather/errors/stanza_error_spec.rb +25 -33
  66. data/spec/blather/errors/stream_error_spec.rb +21 -16
  67. data/spec/blather/errors_spec.rb +4 -11
  68. data/spec/blather/jid_spec.rb +31 -30
  69. data/spec/blather/roster_item_spec.rb +34 -23
  70. data/spec/blather/roster_spec.rb +27 -12
  71. data/spec/blather/stanza/discos/disco_info_spec.rb +61 -42
  72. data/spec/blather/stanza/discos/disco_items_spec.rb +47 -35
  73. data/spec/blather/stanza/iq/query_spec.rb +34 -11
  74. data/spec/blather/stanza/iq/roster_spec.rb +47 -30
  75. data/spec/blather/stanza/iq_spec.rb +19 -14
  76. data/spec/blather/stanza/message_spec.rb +30 -17
  77. data/spec/blather/stanza/presence/status_spec.rb +43 -20
  78. data/spec/blather/stanza/presence/subscription_spec.rb +41 -21
  79. data/spec/blather/stanza/presence_spec.rb +34 -21
  80. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  81. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  82. data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
  83. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  84. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  85. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  86. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  87. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  88. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  89. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
  90. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  91. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  92. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  93. data/spec/blather/stanza/pubsub_spec.rb +62 -0
  94. data/spec/blather/stanza_spec.rb +53 -38
  95. data/spec/blather/stream/client_spec.rb +231 -88
  96. data/spec/blather/stream/component_spec.rb +14 -5
  97. data/spec/blather/stream/parser_spec.rb +145 -0
  98. data/spec/blather/xmpp_node_spec.rb +192 -96
  99. data/spec/fixtures/pubsub.rb +311 -0
  100. data/spec/spec_helper.rb +5 -4
  101. metadata +53 -17
  102. data/Rakefile +0 -139
  103. data/ext/extconf.rb +0 -65
  104. data/ext/push_parser.c +0 -209
  105. data/lib/blather/core_ext/libxml.rb +0 -28
  106. data/lib/blather/stream/resource.rb +0 -48
  107. data/lib/blather/stream/session.rb +0 -36
  108. data/lib/blather/stream/stream_handler.rb +0 -39
  109. data/lib/blather/stream/tls.rb +0 -33
  110. data/spec/blather/core_ext/libxml_spec.rb +0 -58
@@ -7,9 +7,10 @@ class Iq
7
7
 
8
8
  ##
9
9
  # Any new items are added to the query
10
- def initialize(type = nil, item = nil)
11
- super type
12
- query << item if item
10
+ def self.new(type = nil, item = nil)
11
+ node = super type
12
+ node.query << item if item
13
+ node
13
14
  end
14
15
 
15
16
  ##
@@ -17,19 +18,17 @@ class Iq
17
18
  # Creates RosterItem objects out of each roster item as well.
18
19
  def inherit(node)
19
20
  # remove the current set of nodes
20
- items.each { |i| i.remove! }
21
+ remove_children :item
21
22
  super
22
23
  # transmogrify nodes into RosterItems
23
- items.each { |i| query << RosterItem.new(i); i.remove! }
24
+ items.each { |i| query << RosterItem.new(i); i.remove }
24
25
  self
25
26
  end
26
27
 
27
28
  ##
28
29
  # Roster items
29
30
  def items
30
- items = query.find('//item', self.class.ns)
31
- items = query.find('//query_ns:item', :query_ns => self.class.ns) if items.empty?
32
- items.map { |i| RosterItem.new(i) }
31
+ query.find('//ns:item', :ns => self.class.registered_ns).map { |i| RosterItem.new(i) }
33
32
  end
34
33
 
35
34
  class RosterItem < XMPPNode
@@ -38,42 +37,54 @@ class Iq
38
37
  # [name] name alias of the given JID
39
38
  # [subscription] subscription type
40
39
  # [ask] ask subscription sub-state
41
- def initialize(jid = nil, name = nil, subscription = nil, ask = nil)
42
- super :item
40
+ def self.new(jid = nil, name = nil, subscription = nil, ask = nil)
41
+ new_node = super :item
43
42
 
44
- if jid.is_a?(XML::Node)
45
- self.inherit jid
43
+ case jid
44
+ when Nokogiri::XML::Node
45
+ new_node.inherit jid
46
+ when Hash
47
+ new_node.jid = jid[:jid]
48
+ new_node.name = jid[:name]
49
+ new_node.subscription = jid[:subscription]
50
+ new_node.ask = jid[:ask]
46
51
  else
47
- self.jid = jid
48
- self.name = name
49
- self.subscription = subscription
50
- self.ask = ask
52
+ new_node.jid = jid
53
+ new_node.name = name
54
+ new_node.subscription = subscription
55
+ new_node.ask = ask
51
56
  end
57
+ new_node
52
58
  end
53
59
 
54
60
  ##
55
61
  # Roster item's JID
56
62
  def jid
57
- (j = attributes[:jid]) ? JID.new(j) : nil
63
+ (j = self[:jid]) ? JID.new(j) : nil
58
64
  end
59
65
  attribute_writer :jid
60
66
 
61
- attribute_accessor :name, :to_sym => false
67
+ attribute_accessor :name
62
68
 
63
- attribute_accessor :subscription, :ask
69
+ attribute_accessor :subscription, :ask, :call => :to_sym
64
70
 
65
71
  ##
66
72
  # The groups roster item belongs to
67
73
  def groups
68
- find(:group).map { |g| g.content }
74
+ find('child::*[local-name()="group"]').map { |g| g.content }
69
75
  end
70
76
 
71
77
  ##
72
78
  # Set the roster item's groups
73
79
  # must be an array
74
80
  def groups=(new_groups)
75
- find(:group).each { |g| g.remove! }
76
- new_groups.uniq.each { |g| self << XMPPNode.new(:group, g) } if new_groups
81
+ remove_children :group
82
+ if new_groups
83
+ new_groups.uniq.each do |g|
84
+ self << (group = XMPPNode.new(:group, self.document))
85
+ group.content = g
86
+ end
87
+ end
77
88
  end
78
89
 
79
90
  ##
@@ -9,17 +9,22 @@ class Stanza
9
9
  register :iq
10
10
 
11
11
  def self.import(node)
12
- raise(ArgumentError, "Import missmatch #{[node.element_name, self.name].inspect}") if node.element_name != self.name.to_s
13
12
  klass = nil
14
- node.children.each { |e| break if klass = class_from_registration(e.element_name, e.namespace) }
15
- (klass || self).new(node.attributes[:type]).inherit(node)
13
+ node.children.each { |e| break if klass = class_from_registration(e.element_name, (e.namespace.href if e.namespace)) }
14
+
15
+ if klass && klass != self
16
+ klass.import(node)
17
+ else
18
+ new(node[:type]).inherit(node)
19
+ end
16
20
  end
17
21
 
18
- def initialize(type = nil, to = nil, id = nil)
19
- super :iq
20
- self.type = type || :get
21
- self.to = to
22
- self.id = id if id
22
+ def self.new(type = nil, to = nil, id = nil)
23
+ node = super :iq
24
+ node.type = type || :get
25
+ node.to = to
26
+ node.id = id || self.next_id
27
+ node
23
28
  end
24
29
 
25
30
  VALID_TYPES.each do |valid_type|
@@ -8,11 +8,23 @@ class Stanza
8
8
 
9
9
  register :message
10
10
 
11
- def initialize(to = nil, body = nil, type = :chat)
12
- super()
13
- self.to = to
14
- self.type = type
15
- self.body = body
11
+ def self.import(node)
12
+ klass = nil
13
+ node.children.each { |e| break if klass = class_from_registration(e.element_name, (e.namespace.href if e.namespace)) }
14
+
15
+ if klass && klass != self
16
+ klass.import(node)
17
+ else
18
+ new(node[:type]).inherit(node)
19
+ end
20
+ end
21
+
22
+ def self.new(to = nil, body = nil, type = :chat)
23
+ node = super(:message)
24
+ node.to = to
25
+ node.type = type
26
+ node.body = body
27
+ node
16
28
  end
17
29
 
18
30
  VALID_TYPES.each do |valid_type|
@@ -26,32 +38,9 @@ class Stanza
26
38
  super
27
39
  end
28
40
 
29
- def body=(body)
30
- remove_child :body
31
- self << XMPPNode.new('body', body) if body
32
- end
33
-
34
- def body
35
- content_from :body
36
- end
37
-
38
- def subject=(subject)
39
- remove_child :subject
40
- self << XMPPNode.new('subject', subject) if subject
41
- end
42
-
43
- def subject
44
- content_from :subject
45
- end
46
-
47
- def thread=(thread)
48
- remove_child :thread
49
- self << XMPPNode.new('thread', thread) if thread
50
- end
51
-
52
- def thread
53
- content_from :thread
54
- end
41
+ content_attr_accessor :body
42
+ content_attr_accessor :subject
43
+ content_attr_accessor :thread
55
44
  end
56
45
 
57
46
  end #Stanza
@@ -9,12 +9,15 @@ class Presence
9
9
 
10
10
  register :status, :status
11
11
 
12
- def initialize(state = nil, message = nil)
13
- super()
14
- self.state = state
15
- self.message = message
12
+ def self.new(state = nil, message = nil)
13
+ node = super()
14
+ node.state = state
15
+ node.message = message
16
+ node
16
17
  end
17
18
 
19
+ attribute_helpers_for(:state, VALID_STATES)
20
+
18
21
  ##
19
22
  # Ensures type is nil or :unavailable
20
23
  def type=(type)
@@ -29,8 +32,7 @@ class Presence
29
32
  state = nil if state == :available
30
33
  raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}" if state && !VALID_STATES.include?(state)
31
34
 
32
- remove_child :show
33
- self << XMPPNode.new('show', state) if state
35
+ set_content_for :show, state
34
36
  end
35
37
 
36
38
  ##
@@ -43,23 +45,13 @@ class Presence
43
45
  # Ensure priority is between -128 and 127
44
46
  def priority=(new_priority)
45
47
  raise ArgumentError, 'Priority must be between -128 and +127' if new_priority && !(-128..127).include?(new_priority.to_i)
46
-
47
- remove_child :priority
48
- self << XMPPNode.new('priority', new_priority) if new_priority
49
- end
50
-
51
- def priority
52
- content_from(:priority).to_i
48
+ set_content_for :priority, new_priority
49
+
53
50
  end
54
51
 
55
- def message=(msg)
56
- remove_child :status
57
- self << XMPPNode.new('status', msg) if msg
58
- end
52
+ content_attr_reader :priority, :to_i
59
53
 
60
- def message
61
- content_from :status
62
- end
54
+ content_attr_accessor :message, nil, :status
63
55
 
64
56
  ##
65
57
  # Compare status based on priority
@@ -75,4 +67,4 @@ class Presence
75
67
 
76
68
  end #Presence
77
69
  end #Stanza
78
- end #Blather
70
+ end #Blather
@@ -5,10 +5,11 @@ class Presence
5
5
  class Subscription < Presence
6
6
  register :subscription, :subscription
7
7
 
8
- def initialize(to = nil, type = nil)
9
- super()
10
- self.to = to
11
- self.type = type
8
+ def self.new(to = nil, type = nil)
9
+ node = super()
10
+ node.to = to
11
+ node.type = type
12
+ node
12
13
  end
13
14
 
14
15
  def inherit(node)
@@ -24,49 +25,43 @@ class Presence
24
25
  # Create an approve stanza
25
26
  def approve!
26
27
  self.type = :subscribed
27
- morph_to_reply
28
+ reply_if_needed!
28
29
  end
29
30
 
30
31
  ##
31
32
  # Create a refuse stanza
32
33
  def refuse!
33
34
  self.type = :unsubscribed
34
- morph_to_reply
35
+ reply_if_needed!
35
36
  end
36
37
 
37
38
  ##
38
39
  # Create an unsubscribe stanza
39
40
  def unsubscribe!
40
41
  self.type = :unsubscribe
41
- morph_to_reply
42
+ reply_if_needed!
42
43
  end
43
44
 
44
45
  ##
45
46
  # Create a cancel stanza
46
47
  def cancel!
47
48
  self.type = :unsubscribed
48
- morph_to_reply
49
+ reply_if_needed!
49
50
  end
50
51
 
51
52
  ##
52
53
  # Create a request stanza
53
54
  def request!
54
55
  self.type = :subscribe
55
- morph_to_reply
56
+ reply_if_needed!
56
57
  end
57
58
 
58
59
  def request?
59
60
  self.type == :subscribe
60
61
  end
61
62
 
62
- private
63
- def morph_to_reply
64
- self.to = self.from if self.from
65
- self.from = nil
66
- self
67
- end
68
63
  end #Subscription
69
64
 
70
65
  end #Presence
71
66
  end #Stanza
72
- end
67
+ end
@@ -24,13 +24,11 @@ class Stanza
24
24
 
25
25
  ##
26
26
  # Ensure element_name is "presence" for all subclasses
27
- def initialize
27
+ def self.new
28
28
  super :presence
29
29
  end
30
30
 
31
- VALID_TYPES.each do |valid_type|
32
- define_method("#{valid_type}?") { self.type == valid_type }
33
- end
31
+ attribute_helpers_for(:type, VALID_TYPES)
34
32
 
35
33
  ##
36
34
  # Ensures type is one of :unavailable, :subscribe, :subscribed, :unsubscribe, :unsubscribed, :probe or :error
@@ -42,4 +40,4 @@ class Stanza
42
40
  end
43
41
 
44
42
  end #Stanza
45
- end
43
+ end
@@ -0,0 +1,50 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ class Affiliations < PubSub
6
+ register :pubsub_affiliations, :affiliations, self.registered_ns
7
+
8
+ include Enumerable
9
+ alias_method :find, :xpath
10
+
11
+ def self.new(type = nil, host = nil)
12
+ new_node = super
13
+ new_node.affiliations
14
+ new_node
15
+ end
16
+
17
+ ##
18
+ # Kill the affiliations node before running inherit
19
+ def inherit(node)
20
+ affiliations.remove
21
+ super
22
+ end
23
+
24
+ def affiliations
25
+ aff = pubsub.find_first('pubsub_ns:affiliations', :pubsub_ns => self.class.registered_ns)
26
+ self.pubsub << (aff = XMPPNode.new('affiliations', self.document)) unless aff
27
+ aff
28
+ end
29
+
30
+ def each(&block)
31
+ list.each &block
32
+ end
33
+
34
+ def size
35
+ list.size
36
+ end
37
+
38
+ def list
39
+ items = affiliations.find('//ns:affiliation', :ns => self.class.registered_ns)
40
+ items.inject({}) do |hash, item|
41
+ hash[item[:affiliation].to_sym] ||= []
42
+ hash[item[:affiliation].to_sym] << item[:node]
43
+ hash
44
+ end
45
+ end
46
+ end #Affiliations
47
+
48
+ end #PubSub
49
+ end #Stanza
50
+ end #Blather
@@ -0,0 +1,43 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ class Create < PubSub
6
+ register :pubsub_create, :create, self.registered_ns
7
+
8
+ def self.new(type = :set, host = nil, node = nil)
9
+ new_node = super(type, host)
10
+ new_node.create_node
11
+ new_node.configure_node
12
+ new_node.node = node
13
+ new_node
14
+ end
15
+
16
+ def node
17
+ create_node[:node]
18
+ end
19
+
20
+ def node=(node)
21
+ create_node[:node] = node
22
+ end
23
+
24
+ def create_node
25
+ unless create_node = pubsub.find_first('ns:create', :ns => self.class.registered_ns)
26
+ self.pubsub << (create_node = XMPPNode.new('create', self.document))
27
+ create_node.namespace = self.pubsub.namespace
28
+ end
29
+ create_node
30
+ end
31
+
32
+ def configure_node
33
+ unless configure_node = pubsub.find_first('ns:configure', :ns => self.class.registered_ns)
34
+ self.pubsub << (configure_node = XMPPNode.new('configure', self.document))
35
+ configure_node.namespace = self.pubsub.namespace
36
+ end
37
+ configure_node
38
+ end
39
+ end #Retract
40
+
41
+ end #PubSub
42
+ end #Stanza
43
+ end #Blather
@@ -0,0 +1,9 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ class PubSubErrors < PubSub
5
+ attribute_accessor :node, :to_sym => false
6
+ end
7
+
8
+ end #Stanza
9
+ end #Blather
@@ -0,0 +1,77 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ class Event < Message
6
+ register :pubsub_event, :event, 'http://jabber.org/protocol/pubsub#event'
7
+
8
+ ##
9
+ # Ensure the event_node is created
10
+ def self.new(type = nil)
11
+ node = super
12
+ node.event_node
13
+ node
14
+ end
15
+
16
+ ##
17
+ # Kill the event_node node before running inherit
18
+ def inherit(node)
19
+ event_node.remove
20
+ super
21
+ end
22
+
23
+ def node
24
+ !purge? ? items_node[:node] : purge_node[:node]
25
+ end
26
+
27
+ def retractions
28
+ items_node.find('ns:retract', :ns => self.class.registered_ns).map { |i| i[:id] }
29
+ end
30
+
31
+ def retractions?
32
+ !retractions.empty?
33
+ end
34
+
35
+ def items
36
+ items_node.find('ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
37
+ end
38
+
39
+ def items?
40
+ !items.empty?
41
+ end
42
+
43
+ def purge?
44
+ purge_node
45
+ end
46
+
47
+ def event_node
48
+ node = find_first('ns:event', :ns => self.class.registered_ns)
49
+ node = find_first('event', self.class.registered_ns) unless node
50
+ unless node
51
+ (self << (node = XMPPNode.new('event', self.document)))
52
+ node.namespace = self.class.registered_ns
53
+ end
54
+ node
55
+ end
56
+
57
+ def items_node
58
+ node = find_first('event/ns:items', :ns => self.class.registered_ns)
59
+ unless node
60
+ (self.event_node << (node = XMPPNode.new('items', self.document)))
61
+ node.namespace = event_node.namespace
62
+ end
63
+ node
64
+ end
65
+
66
+ def purge_node
67
+ event_node.find_first('ns:purge', :ns => self.class.registered_ns)
68
+ end
69
+
70
+ def subscription_ids
71
+ find('//ns:header[@name="SubID"]', :ns => 'http://jabber.org/protocol/shim').map { |n| n.content }
72
+ end
73
+ end
74
+
75
+ end #PubSub
76
+ end #Stanza
77
+ end #Blather
@@ -0,0 +1,63 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ class Items < PubSub
6
+ register :pubsub_items, :items, self.registered_ns
7
+
8
+ include Enumerable
9
+ alias_method :find, :xpath
10
+
11
+ def self.request(host, path, list = [], max = nil)
12
+ node = self.new :get, host
13
+
14
+ node.node = path
15
+ node.max_items = max
16
+
17
+ (list || []).each { |id| node.items_node << PubSubItem.new(id, nil, node.document) }
18
+
19
+ node
20
+ end
21
+
22
+ def self.new(type = nil, host = nil)
23
+ new_node = super
24
+ new_node.items
25
+ new_node
26
+ end
27
+
28
+ def node
29
+ items_node[:node]
30
+ end
31
+
32
+ def node=(node)
33
+ items_node[:node] = node
34
+ end
35
+
36
+ def max_items
37
+ items_node[:max_items].to_i if items_node[:max_items]
38
+ end
39
+
40
+ def max_items=(max_items)
41
+ items_node[:max_items] = max_items
42
+ end
43
+
44
+ def each(&block)
45
+ items.each &block
46
+ end
47
+
48
+ def items
49
+ items_node.find('ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
50
+ end
51
+
52
+ def items_node
53
+ unless node = self.pubsub.find_first('ns:items', :ns => self.class.registered_ns)
54
+ (self.pubsub << (node = XMPPNode.new('items', self.document)))
55
+ node.namespace = self.pubsub.namespace
56
+ end
57
+ node
58
+ end
59
+ end
60
+
61
+ end #PubSub
62
+ end #Stanza
63
+ end #Blather
@@ -0,0 +1,58 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ class Publish < PubSub
6
+ register :pubsub_publish, :publish, self.registered_ns
7
+
8
+ include Enumerable
9
+ alias_method :find, :xpath
10
+
11
+ def self.new(host = nil, node = nil, type = :set, payload = nil)
12
+ new_node = super(type, host)
13
+ new_node.node = node
14
+ new_node.payload = payload if payload
15
+ new_node
16
+ end
17
+
18
+ def payload=(payload)
19
+ payload = case payload
20
+ when Hash then payload.to_a
21
+ when Array then payload.map { |v| [nil, v] }
22
+ else [[nil, payload.to_s]]
23
+ end
24
+ payload.each { |id,value| self.publish << PubSubItem.new(id, value, self.document) }
25
+ end
26
+
27
+ def node
28
+ publish[:node]
29
+ end
30
+
31
+ def node=(node)
32
+ publish[:node] = node
33
+ end
34
+
35
+ def publish
36
+ unless publish = pubsub.find_first('ns:publish', :ns => self.class.registered_ns)
37
+ self.pubsub << (publish = XMPPNode.new('publish', self.document))
38
+ publish.namespace = self.pubsub.namespace
39
+ end
40
+ publish
41
+ end
42
+
43
+ def items
44
+ publish.find('ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
45
+ end
46
+
47
+ def each(&block)
48
+ items.each &block
49
+ end
50
+
51
+ def size
52
+ items.size
53
+ end
54
+ end #Publish
55
+
56
+ end #PubSub
57
+ end #Stanza
58
+ end #Blather