tp-blather 0.8.2

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 (150) hide show
  1. data/.autotest +13 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +8 -0
  6. data/CHANGELOG.md +249 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +22 -0
  10. data/README.md +413 -0
  11. data/Rakefile +20 -0
  12. data/TODO.md +2 -0
  13. data/blather.gemspec +51 -0
  14. data/examples/certs/README +20 -0
  15. data/examples/certs/ca-bundle.crt +3987 -0
  16. data/examples/echo.rb +19 -0
  17. data/examples/execute.rb +17 -0
  18. data/examples/ping_pong.rb +38 -0
  19. data/examples/print_hierarchy.rb +77 -0
  20. data/examples/rosterprint.rb +15 -0
  21. data/examples/stream_only.rb +28 -0
  22. data/examples/trusted_echo.rb +21 -0
  23. data/examples/xmpp4r/echo.rb +36 -0
  24. data/lib/blather.rb +112 -0
  25. data/lib/blather/cert_store.rb +53 -0
  26. data/lib/blather/client.rb +95 -0
  27. data/lib/blather/client/client.rb +345 -0
  28. data/lib/blather/client/dsl.rb +320 -0
  29. data/lib/blather/client/dsl/pubsub.rb +174 -0
  30. data/lib/blather/core_ext/eventmachine.rb +125 -0
  31. data/lib/blather/core_ext/ipaddr.rb +20 -0
  32. data/lib/blather/errors.rb +69 -0
  33. data/lib/blather/errors/sasl_error.rb +44 -0
  34. data/lib/blather/errors/stanza_error.rb +110 -0
  35. data/lib/blather/errors/stream_error.rb +84 -0
  36. data/lib/blather/file_transfer.rb +107 -0
  37. data/lib/blather/file_transfer/ibb.rb +68 -0
  38. data/lib/blather/file_transfer/s5b.rb +114 -0
  39. data/lib/blather/jid.rb +141 -0
  40. data/lib/blather/roster.rb +118 -0
  41. data/lib/blather/roster_item.rb +146 -0
  42. data/lib/blather/stanza.rb +167 -0
  43. data/lib/blather/stanza/disco.rb +32 -0
  44. data/lib/blather/stanza/disco/capabilities.rb +161 -0
  45. data/lib/blather/stanza/disco/disco_info.rb +205 -0
  46. data/lib/blather/stanza/disco/disco_items.rb +134 -0
  47. data/lib/blather/stanza/iq.rb +144 -0
  48. data/lib/blather/stanza/iq/command.rb +339 -0
  49. data/lib/blather/stanza/iq/ibb.rb +86 -0
  50. data/lib/blather/stanza/iq/ping.rb +50 -0
  51. data/lib/blather/stanza/iq/query.rb +53 -0
  52. data/lib/blather/stanza/iq/roster.rb +185 -0
  53. data/lib/blather/stanza/iq/s5b.rb +208 -0
  54. data/lib/blather/stanza/iq/si.rb +415 -0
  55. data/lib/blather/stanza/iq/vcard.rb +149 -0
  56. data/lib/blather/stanza/message.rb +428 -0
  57. data/lib/blather/stanza/message/muc_user.rb +119 -0
  58. data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
  59. data/lib/blather/stanza/presence.rb +172 -0
  60. data/lib/blather/stanza/presence/c.rb +100 -0
  61. data/lib/blather/stanza/presence/muc.rb +35 -0
  62. data/lib/blather/stanza/presence/muc_user.rb +147 -0
  63. data/lib/blather/stanza/presence/status.rb +218 -0
  64. data/lib/blather/stanza/presence/subscription.rb +100 -0
  65. data/lib/blather/stanza/pubsub.rb +119 -0
  66. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  67. data/lib/blather/stanza/pubsub/create.rb +65 -0
  68. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  69. data/lib/blather/stanza/pubsub/event.rb +139 -0
  70. data/lib/blather/stanza/pubsub/items.rb +103 -0
  71. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  72. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  73. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  74. data/lib/blather/stanza/pubsub/subscription.rb +135 -0
  75. data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
  76. data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
  77. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  78. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  79. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  80. data/lib/blather/stanza/x.rb +416 -0
  81. data/lib/blather/stream.rb +266 -0
  82. data/lib/blather/stream/client.rb +32 -0
  83. data/lib/blather/stream/component.rb +39 -0
  84. data/lib/blather/stream/features.rb +70 -0
  85. data/lib/blather/stream/features/register.rb +38 -0
  86. data/lib/blather/stream/features/resource.rb +63 -0
  87. data/lib/blather/stream/features/sasl.rb +190 -0
  88. data/lib/blather/stream/features/session.rb +45 -0
  89. data/lib/blather/stream/features/tls.rb +29 -0
  90. data/lib/blather/stream/parser.rb +102 -0
  91. data/lib/blather/version.rb +3 -0
  92. data/lib/blather/xmpp_node.rb +94 -0
  93. data/spec/blather/client/client_spec.rb +687 -0
  94. data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
  95. data/spec/blather/client/dsl_spec.rb +266 -0
  96. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  97. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  98. data/spec/blather/errors/stream_error_spec.rb +108 -0
  99. data/spec/blather/errors_spec.rb +33 -0
  100. data/spec/blather/file_transfer_spec.rb +135 -0
  101. data/spec/blather/jid_spec.rb +87 -0
  102. data/spec/blather/roster_item_spec.rb +134 -0
  103. data/spec/blather/roster_spec.rb +107 -0
  104. data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
  105. data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
  106. data/spec/blather/stanza/iq/command_spec.rb +206 -0
  107. data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
  108. data/spec/blather/stanza/iq/ping_spec.rb +45 -0
  109. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  110. data/spec/blather/stanza/iq/roster_spec.rb +139 -0
  111. data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
  112. data/spec/blather/stanza/iq/si_spec.rb +98 -0
  113. data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
  114. data/spec/blather/stanza/iq_spec.rb +61 -0
  115. data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
  116. data/spec/blather/stanza/message_spec.rb +282 -0
  117. data/spec/blather/stanza/presence/c_spec.rb +56 -0
  118. data/spec/blather/stanza/presence/muc_spec.rb +37 -0
  119. data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
  120. data/spec/blather/stanza/presence/status_spec.rb +144 -0
  121. data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
  122. data/spec/blather/stanza/presence_spec.rb +125 -0
  123. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  124. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  125. data/spec/blather/stanza/pubsub/event_spec.rb +98 -0
  126. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  127. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  128. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  129. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  130. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  131. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  132. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +74 -0
  133. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  134. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  135. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  136. data/spec/blather/stanza/pubsub_spec.rb +68 -0
  137. data/spec/blather/stanza/x_spec.rb +231 -0
  138. data/spec/blather/stanza_spec.rb +134 -0
  139. data/spec/blather/stream/client_spec.rb +1090 -0
  140. data/spec/blather/stream/component_spec.rb +108 -0
  141. data/spec/blather/stream/parser_spec.rb +152 -0
  142. data/spec/blather/stream/ssl_spec.rb +32 -0
  143. data/spec/blather/xmpp_node_spec.rb +47 -0
  144. data/spec/blather_spec.rb +34 -0
  145. data/spec/fixtures/pubsub.rb +311 -0
  146. data/spec/spec_helper.rb +17 -0
  147. data/yard/templates/default/class/html/handlers.erb +18 -0
  148. data/yard/templates/default/class/setup.rb +10 -0
  149. data/yard/templates/default/class/text/handlers.erb +1 -0
  150. metadata +459 -0
@@ -0,0 +1,218 @@
1
+ module Blather
2
+ class Stanza
3
+ class Presence
4
+
5
+ # # Status Stanza
6
+ #
7
+ # [RFC 3921 Section 2.2.2 - Presence Child Elements](http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2)
8
+ #
9
+ # Presence stanzas are used to express an entity's current network
10
+ # availability (offline or online, along with various sub-states of the
11
+ # latter and optional user-defined descriptive text), and to notify other
12
+ # entities of that availability.
13
+ #
14
+ # ## "State" Attribute
15
+ #
16
+ # The `state` attribute determains the availability of the entity and can be
17
+ # one of the following:
18
+ #
19
+ # * `:available` -- The entity or resource is available
20
+ #
21
+ # * `:away` -- The entity or resource is temporarily away.
22
+ #
23
+ # * `:chat` -- The entity or resource is actively interested in chatting.
24
+ #
25
+ # * `:dnd` -- The entity or resource is busy (dnd = "Do Not Disturb").
26
+ #
27
+ # * `:xa` -- The entity or resource is away for an extended period (xa =
28
+ # "eXtended Away").
29
+ #
30
+ # Blather provides a helper for each possible state:
31
+ #
32
+ # Status#available?
33
+ # Status#away?
34
+ # Status#chat?
35
+ # Status#dnd?
36
+ # Status#xa?
37
+ #
38
+ # Blather treats the `type` attribute like a normal ruby object attribute
39
+ # providing a getter and setter. The default `type` is `available`.
40
+ #
41
+ # status = Status.new
42
+ # status.state # => :available
43
+ # status.available? # => true
44
+ # status.state = :away
45
+ # status.away? # => true
46
+ # status.available? # => false
47
+ # status
48
+ # status.state = :invalid # => RuntimeError
49
+ #
50
+ # ## "Type" Attribute
51
+ #
52
+ # The `type` attribute is inherited from Presence, but limits the value to
53
+ # either `nil` or `:unavailable` as these are the only types that relate to
54
+ # Status.
55
+ #
56
+ # ## "Priority" Attribute
57
+ #
58
+ # The `priority` attribute sets the priority of the status for the entity
59
+ # and must be an integer between -128 and 127.
60
+ #
61
+ # ## "Message" Attribute
62
+ #
63
+ # The optional `message` element contains XML character data specifying a
64
+ # natural-language description of availability status. It is normally used
65
+ # in conjunction with the show element to provide a detailed description of
66
+ # an availability state (e.g., "In a meeting").
67
+ #
68
+ # Blather treats the `message` attribute like a normal ruby object attribute
69
+ # providing a getter and setter. The default `message` is nil.
70
+ #
71
+ # status = Status.new
72
+ # status.message # => nil
73
+ # status.message = "gone!"
74
+ # status.message # => "gone!"
75
+ #
76
+ # @handler :status
77
+ class Status < Presence
78
+ # @private
79
+ VALID_STATES = [:away, :chat, :dnd, :xa].freeze
80
+ VALID_TYPES = [:unavailable].freeze
81
+
82
+ include Comparable
83
+
84
+ register :status, :status
85
+
86
+ # Create a new Status stanza
87
+ #
88
+ # @param [<:away, :chat, :dnd, :xa>] state the state of the status
89
+ # @param [#to_s] message a message to send with the status
90
+ def self.new(state = nil, message = nil)
91
+ node = super()
92
+ node.state = state
93
+ node.message = message
94
+ node
95
+ end
96
+
97
+ module InstanceMethods
98
+
99
+ # Check if the state is available
100
+ #
101
+ # @return [true, false]
102
+ def available?
103
+ self.state == :available
104
+ end
105
+
106
+ # Check if the state is away
107
+ #
108
+ # @return [true, false]
109
+ def away?
110
+ self.state == :away
111
+ end
112
+
113
+ # Check if the state is chat
114
+ #
115
+ # @return [true, false]
116
+ def chat?
117
+ self.state == :chat
118
+ end
119
+
120
+ # Check if the state is dnd
121
+ #
122
+ # @return [true, false]
123
+ def dnd?
124
+ self.state == :dnd
125
+ end
126
+
127
+ # Check if the state is xa
128
+ #
129
+ # @return [true, false]
130
+ def xa?
131
+ self.state == :xa
132
+ end
133
+
134
+ # Set the state
135
+ # Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
136
+ #
137
+ # @param [<:available, :away, :chat, :dnd, :xa, nil>] state
138
+ def state=(state) # :nodoc:
139
+ state = state.to_sym if state
140
+ state = nil if state == :available
141
+ if state && !VALID_STATES.include?(state)
142
+ raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
143
+ end
144
+
145
+ set_content_for :show, state
146
+ end
147
+
148
+ # Get the state of the status
149
+ #
150
+ # @return [<:available, :away, :chat, :dnd, :xa>]
151
+ def state
152
+ state = type || content_from(:show)
153
+ state = :available if state.blank?
154
+ state.to_sym
155
+ end
156
+
157
+ # Set the priority of the status
158
+ # Ensures priority is between -128 and 127
159
+ #
160
+ # @param [Fixnum<-128...127>] new_priority
161
+ def priority=(new_priority) # :nodoc:
162
+ if new_priority && !(-128..127).include?(new_priority.to_i)
163
+ raise ArgumentError, 'Priority must be between -128 and +127'
164
+ end
165
+ set_content_for :priority, new_priority
166
+ end
167
+
168
+ # Get the priority of the status
169
+ #
170
+ # @return [Fixnum<-128...127>]
171
+ def priority
172
+ read_content(:priority).to_i
173
+ end
174
+
175
+ # Get the status message
176
+ #
177
+ # @return [String, nil]
178
+ def message
179
+ read_content :status
180
+ end
181
+
182
+ # Set the status message
183
+ #
184
+ # @param [String, nil] message
185
+ def message=(message)
186
+ set_content_for :status, message
187
+ end
188
+
189
+ # Compare status based on priority and state:
190
+ # unavailable status is always less valuable than others
191
+ # Raises an error if the JIDs aren't the same
192
+ #
193
+ # @param [Blather::Stanza::Presence::Status] o
194
+ # @return [true,false]
195
+ def <=>(o)
196
+ if self.from || o.from
197
+ unless self.from.stripped == o.from.stripped
198
+ raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
199
+ end
200
+ end
201
+
202
+ if (self.type.nil? && o.type.nil?) || (!self.type.nil? && !o.type.nil?)
203
+ self.priority <=> o.priority
204
+ elsif self.type.nil? && !o.type.nil?
205
+ 1
206
+ elsif !self.type.nil? && o.type.nil?
207
+ -1
208
+ end
209
+ end
210
+ end
211
+
212
+ include InstanceMethods
213
+
214
+ end #Status
215
+
216
+ end #Presence
217
+ end #Stanza
218
+ end #Blather
@@ -0,0 +1,100 @@
1
+ module Blather
2
+ class Stanza
3
+ class Presence
4
+
5
+ # # Subscription Stanza
6
+ #
7
+ # [RFC 3921 Section 8 - Integration of Roster Items and Presence Subscriptions](http://xmpp.org/rfcs/rfc3921.html#rfc.section.8)
8
+ #
9
+ # Blather handles subscription request/response through this class. It
10
+ # provides a set of helper methods to quickly transform the stanza into a
11
+ # response.
12
+ #
13
+ # @handler :subscription
14
+ class Subscription < Presence
15
+ register :subscription, :subscription
16
+
17
+ # Create a new Subscription stanza
18
+ #
19
+ # @param [Blather::JID, #to_s] to the JID to subscribe to
20
+ # @param [Symbol, nil] type the subscription type
21
+ def self.new(to = nil, type = nil)
22
+ node = super()
23
+ node.to = to
24
+ node.type = type
25
+ node
26
+ end
27
+
28
+ module InstanceMethods
29
+
30
+ # Set the to value on the stanza
31
+ #
32
+ # @param [Blather::JID, #to_s] to a JID to subscribe to
33
+ def to=(to)
34
+ super JID.new(to).stripped
35
+ end
36
+
37
+ # Transform the stanza into an approve stanza
38
+ # makes approving requests simple
39
+ #
40
+ # @example approve an incoming request
41
+ # subscription(:request?) { |s| write_to_stream s.approve! }
42
+ # @return [self]
43
+ def approve!
44
+ self.type = :subscribed
45
+ reply_if_needed!
46
+ end
47
+
48
+ # Transform the stanza into a refuse stanza
49
+ # makes refusing requests simple
50
+ #
51
+ # @example refuse an incoming request
52
+ # subscription(:request?) { |s| write_to_stream s.refuse! }
53
+ # @return [self]
54
+ def refuse!
55
+ self.type = :unsubscribed
56
+ reply_if_needed!
57
+ end
58
+
59
+ # Transform the stanza into an unsubscribe stanza
60
+ # makes unsubscribing simple
61
+ #
62
+ # @return [self]
63
+ def unsubscribe!
64
+ self.type = :unsubscribe
65
+ reply_if_needed!
66
+ end
67
+
68
+ # Transform the stanza into a cancel stanza
69
+ # makes canceling simple
70
+ #
71
+ # @return [self]
72
+ def cancel!
73
+ self.type = :unsubscribed
74
+ reply_if_needed!
75
+ end
76
+
77
+ # Transform the stanza into a request stanza
78
+ # makes requests simple
79
+ #
80
+ # @return [self]
81
+ def request!
82
+ self.type = :subscribe
83
+ reply_if_needed!
84
+ end
85
+
86
+ # Check if the stanza is a request
87
+ #
88
+ # @return [true, false]
89
+ def request?
90
+ self.type == :subscribe
91
+ end
92
+ end
93
+
94
+ include InstanceMethods
95
+
96
+ end #Subscription
97
+
98
+ end #Presence
99
+ end #Stanza
100
+ end
@@ -0,0 +1,119 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # Pubsub Stanza
5
+ #
6
+ # [XEP-0060 - Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html)
7
+ #
8
+ # The base class for all PubSub nodes. This provides helper methods common to
9
+ # all PubSub nodes.
10
+ #
11
+ # @handler :pubsub_node
12
+ class PubSub < Iq
13
+ register :pubsub_node, :pubsub, 'http://jabber.org/protocol/pubsub'
14
+
15
+ # @private
16
+ def self.import(node)
17
+ klass = nil
18
+ if pubsub = node.document.find_first('//ns:pubsub', :ns => self.registered_ns)
19
+ pubsub.children.detect do |e|
20
+ ns = e.namespace ? e.namespace.href : nil
21
+ klass = class_from_registration(e.element_name, ns)
22
+ end
23
+ end
24
+ (klass || self).new(node[:type]).inherit(node)
25
+ end
26
+
27
+ # Overwrites the parent constructor to ensure a pubsub node is present.
28
+ # Also allows the addition of a host attribute
29
+ #
30
+ # @param [<Blather::Stanza::Iq::VALID_TYPES>] type the IQ type
31
+ # @param [String, nil] host the host the node should be sent to
32
+ def self.new(type = nil, host = nil)
33
+ new_node = super type
34
+ new_node.to = host
35
+ new_node.pubsub
36
+ new_node
37
+ end
38
+
39
+ # Overrides the parent to ensure the current pubsub node is destroyed before
40
+ # inheritting the new content
41
+ #
42
+ # @private
43
+ def inherit(node)
44
+ remove_children :pubsub
45
+ super
46
+ end
47
+
48
+ # Get or create the pubsub node on the stanza
49
+ #
50
+ # @return [Blather::XMPPNode]
51
+ def pubsub
52
+ p = find_first('ns:pubsub', :ns => self.class.registered_ns) ||
53
+ find_first('pubsub', :ns => self.class.registered_ns)
54
+
55
+ unless p
56
+ self << (p = XMPPNode.new('pubsub', self.document))
57
+ p.namespace = self.class.registered_ns
58
+ end
59
+ p
60
+ end
61
+ end # PubSub
62
+
63
+ # # PubSubItem Fragment
64
+ #
65
+ # This fragment is found in many places throughout the pubsub spec
66
+ # This is a convenience class to attach methods to the node
67
+ class PubSubItem < XMPPNode
68
+ # Create a new PubSubItem
69
+ #
70
+ # @param [String, nil] id the id of the stanza
71
+ # @param [#to_s, nil] payload the payload to attach to this item.
72
+ # @param [XML::Document, nil] document the document the node should be
73
+ # attached to. This should be the document of the parent PubSub node.
74
+ def self.new(id = nil, payload = nil, document = nil)
75
+ new_node = super 'item', document
76
+ new_node.id = id
77
+ new_node.payload = payload if payload
78
+ new_node
79
+ end
80
+
81
+ # Get the item's ID
82
+ #
83
+ # @return [String, nil]
84
+ def id
85
+ read_attr :id
86
+ end
87
+
88
+ # Set the item's ID
89
+ #
90
+ # @param [#to_s] id the new ID
91
+ def id=(id)
92
+ write_attr :id, id
93
+ end
94
+
95
+ alias_method :payload_node, :child
96
+
97
+ # Get the item's payload
98
+ #
99
+ # @return [String, nil]
100
+ def payload
101
+ children.empty? ? nil : children.to_s
102
+ end
103
+
104
+ # Set the item's payload
105
+ #
106
+ # @param [String, XMPPNode, nil] payload the payload
107
+ def payload=(payload)
108
+ children.map &:remove
109
+ return unless payload
110
+ if payload.is_a?(String)
111
+ self.content = payload
112
+ else
113
+ self << payload
114
+ end
115
+ end
116
+ end # PubSubItem
117
+
118
+ end # Stanza
119
+ end # Blather
@@ -0,0 +1,79 @@
1
+ module Blather
2
+ class Stanza
3
+ class PubSub
4
+
5
+ # # PubSub Affiliations Stanza
6
+ #
7
+ # [XEP-0060 Section 8.9 - Manage Affiliations](http://xmpp.org/extensions/xep-0060.html#owner-affiliations)
8
+ #
9
+ # @handler :pubsub_affiliations
10
+ class Affiliations < PubSub
11
+ register :pubsub_affiliations, :affiliations, self.registered_ns
12
+
13
+ include Enumerable
14
+ alias_method :find, :xpath
15
+
16
+ # Overrides the parent to ensure an affiliation node is created
17
+ # @private
18
+ def self.new(type = nil, host = nil)
19
+ new_node = super
20
+ new_node.affiliations
21
+ new_node
22
+ end
23
+
24
+ # Kill the affiliations node before running inherit
25
+ # @private
26
+ def inherit(node)
27
+ affiliations.remove
28
+ super
29
+ end
30
+
31
+ # Get or create the affiliations node
32
+ #
33
+ # @return [Blather::XMPPNode]
34
+ def affiliations
35
+ aff = pubsub.find_first('ns:affiliations', :ns => self.class.registered_ns)
36
+ unless aff
37
+ self.pubsub << (aff = XMPPNode.new('affiliations', self.document))
38
+ end
39
+ aff
40
+ end
41
+
42
+ # Convenience method for iterating over the list
43
+ #
44
+ # @see #list for the format of the yielded input
45
+ def each(&block)
46
+ list.each &block
47
+ end
48
+
49
+ # Get the number of affiliations
50
+ #
51
+ # @return [Fixnum]
52
+ def size
53
+ list.size
54
+ end
55
+
56
+ # Get the hash of affilations as affiliation-type => [nodes]
57
+ #
58
+ # @example
59
+ #
60
+ # { :owner => ['node1', 'node2'],
61
+ # :publisher => ['node3'],
62
+ # :outcast => ['node4'],
63
+ # :member => ['node5'],
64
+ # :none => ['node6'] }
65
+ #
66
+ # @return [Hash<String => Array<String>>]
67
+ def list
68
+ items = affiliations.find('//ns:affiliation', :ns => self.class.registered_ns)
69
+ items.inject({}) do |hash, item|
70
+ hash[item[:affiliation].to_sym] ||= []
71
+ hash[item[:affiliation].to_sym] << item[:node]
72
+ hash
73
+ end
74
+ end
75
+ end # Affiliations
76
+
77
+ end # PubSub
78
+ end # Stanza
79
+ end # Blather