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,161 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # Capabilities Stanza
5
+ #
6
+ # [XEP-0115 Entity Capabilities](http://xmpp.org/extensions/xep-0115.html)
7
+ #
8
+ # XMPP protocol extension for broadcasting and dynamically discovering client, device, or generic entity capabilities.
9
+ #
10
+ class Capabilities < Blather::Stanza::DiscoInfo
11
+ def self.new
12
+ super :result
13
+ end
14
+
15
+ # A string that is used to verify the identity and supported features of the entity.
16
+ #
17
+ # @return [String]
18
+ def ver
19
+ generate_ver identities, features
20
+ end
21
+
22
+ # A URI that uniquely identifies a software application, typically a URL at the
23
+ # website of the project or company that produces the software.
24
+ #
25
+ # @param [String] node the node URI
26
+ def node=(node)
27
+ @bare_node = node
28
+ super "#{node}##{ver}"
29
+ end
30
+
31
+ # Add an array of identities
32
+ # @param identities the array of identities, passed directly to Identity.new
33
+ def identities=(identities)
34
+ super identities
35
+ regenerate_full_node
36
+ end
37
+
38
+ # Add an array of features
39
+ # @param features the array of features, passed directly to Feature.new
40
+ def features=(features)
41
+ super features
42
+ regenerate_full_node
43
+ end
44
+
45
+ # The generated Presence::C node
46
+ #
47
+ # @return [Blather::Stanza::Presence::C]
48
+ def c
49
+ Blather::Stanza::Presence::C.new @bare_node, ver
50
+ end
51
+
52
+ private
53
+
54
+ def regenerate_full_node
55
+ self.node = @bare_node
56
+ end
57
+
58
+ def generate_ver_str(identities, features, forms = [])
59
+ # 1. Initialize an empty string S.
60
+ s = ''
61
+
62
+ # 2. Sort the service discovery identities by category and
63
+ # then by type (if it exists) and then by xml:lang (if it
64
+ # exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
65
+ # [NAME]. Note that each slash is included even if the TYPE,
66
+ # LANG, or NAME is not included.
67
+ identities.sort! do |identity1, identity2|
68
+ cmp_result = nil
69
+ [:category, :type, :xml_lang, :name].each do |field|
70
+ value1 = identity1.send(field)
71
+ value2 = identity2.send(field)
72
+
73
+ if value1 != value2
74
+ cmp_result = value1 <=> value2
75
+ break
76
+ end
77
+ end
78
+ cmp_result
79
+ end
80
+
81
+ # 3. For each identity, append the 'category/type/lang/name' to
82
+ # S, followed by the '<' character.
83
+ s += identities.collect do |identity|
84
+ [:category, :type, :xml_lang, :name].collect do |field|
85
+ identity.send(field).to_s
86
+ end.join('/') + '<'
87
+ end.join
88
+
89
+ # 4. Sort the supported service discovery features.
90
+ features.sort! { |feature1, feature2| feature1.var <=> feature2.var }
91
+
92
+ # 5. For each feature, append the feature to S, followed by the
93
+ # '<' character.
94
+ s += features.collect { |feature| feature.var.to_s + '<' }.join
95
+
96
+ # 6. If the service discovery information response includes
97
+ # XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e., by
98
+ # the XML character data of the <value/> element).
99
+ forms.sort! do |form1, form2|
100
+ fform_type1 = form1.field 'FORM_TYPE'
101
+ fform_type2 = form2.field 'FORM_TYPE'
102
+ form_type1 = fform_type1 ? fform_type1.values.to_s : nil
103
+ form_type2 = fform_type2 ? fform_type2.values.to_s : nil
104
+ form_type1 <=> form_type2
105
+ end
106
+
107
+ # 7. For each extended service discovery information form:
108
+ forms.each do |form|
109
+ # 7.1. Append the XML character data of the FORM_TYPE field's
110
+ # <value/> element, followed by the '<' character.
111
+ fform_type = form.field 'FORM_TYPE'
112
+ form_type = fform_type ? fform_type.values.to_s : nil
113
+ s += "#{form_type}<"
114
+
115
+ # 7.2. Sort the fields by the value of the "var" attribute
116
+ fields = form.fields.sort { |field1, field2| field1.var <=> field2.var }
117
+
118
+ # 7.3. For each field:
119
+ fields.each do |field|
120
+ # 7.3.1. Append the value of the "var" attribute, followed by
121
+ # the '<' character.
122
+ s += "#{field.var}<"
123
+
124
+ # 7.3.2. Sort values by the XML character data of the <value/> element
125
+ # values = field.values.sort { |value1, value2| value1 <=> value2 }
126
+
127
+ # 7.3.3. For each <value/> element, append the XML character
128
+ # data, followed by the '<' character.
129
+ # s += values.collect { |value| "#{value}<" }.join
130
+ s += "#{field.value}<"
131
+ end
132
+ end
133
+ s
134
+ end
135
+
136
+ def generate_ver(identities, features, forms = [], hash = 'sha-1')
137
+ s = generate_ver_str identities, features, forms
138
+
139
+ # 9. Compute the verification string by hashing S using the
140
+ # algorithm specified in the 'hash' attribute (e.g., SHA-1 as
141
+ # defined in RFC 3174). The hashed data MUST be generated
142
+ # with binary output and encoded using Base64 as specified in
143
+ # Section 4 of RFC 4648 (note: the Base64 output MUST NOT
144
+ # include whitespace and MUST set padding bits to zero).
145
+
146
+ # See http://www.iana.org/assignments/hash-function-text-names
147
+ hash_klass = case hash
148
+ when 'md2' then nil
149
+ when 'md5' then Digest::MD5
150
+ when 'sha-1' then Digest::SHA1
151
+ when 'sha-224' then nil
152
+ when 'sha-256' then Digest::SHA256
153
+ when 'sha-384' then Digest::SHA384
154
+ when 'sha-512' then Digest::SHA512
155
+ end
156
+ hash_klass ? [hash_klass::digest(s)].pack('m').strip : nil
157
+ end
158
+ end # Caps
159
+
160
+ end # Stanza
161
+ end # Blather
@@ -0,0 +1,205 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # DiscoInfo Stanza
5
+ #
6
+ # [XEP-0030 Disco Info](http://xmpp.org/extensions/xep-0030.html#info)
7
+ #
8
+ # Disco Info node that provides or retreives information about a jabber entity
9
+ #
10
+ # @handler :disco_info
11
+ class DiscoInfo < Disco
12
+ register :disco_info, nil, 'http://jabber.org/protocol/disco#info'
13
+
14
+ # Create a new DiscoInfo stanza
15
+ # @param [:get, :set, :result, :error, nil] type the Iq stanza type
16
+ # @param [String, nil] node the name of the node the info belongs to
17
+ # @param [Array<Array, DiscoInfo::Identity>, nil] identities a list of
18
+ # identities. these are passed directly to DiscoInfo::Identity.new
19
+ # @param [Array<Array, DiscoInfo::Identity>, nil] features a list of
20
+ # features. these are passed directly to DiscoInfo::Feature.new
21
+ # @return [DiscoInfo] a new DiscoInfo stanza
22
+ def self.new(type = nil, node = nil, identities = [], features = [])
23
+ new_node = super type
24
+ new_node.node = node
25
+ new_node.identities = [identities]
26
+ new_node.features = [features]
27
+ new_node
28
+ end
29
+
30
+ # List of identity objects
31
+ def identities
32
+ query.find('//ns:identity', :ns => self.class.registered_ns).map do |i|
33
+ Identity.new i
34
+ end
35
+ end
36
+
37
+ # Add an array of identities
38
+ # @param identities the array of identities, passed directly to Identity.new
39
+ def identities=(identities)
40
+ query.find('//ns:identity', :ns => self.class.registered_ns).each &:remove
41
+ if identities
42
+ [identities].flatten.each { |i| self.query << Identity.new(i) }
43
+ end
44
+ end
45
+
46
+ # List of feature objects
47
+ def features
48
+ query.find('//ns:feature', :ns => self.class.registered_ns).map do |f|
49
+ Feature.new f
50
+ end
51
+ end
52
+
53
+ # Add an array of features
54
+ # @param features the array of features, passed directly to Feature.new
55
+ def features=(features)
56
+ query.find('//ns:feature', :ns => self.class.registered_ns).each &:remove
57
+ if features
58
+ [features].flatten.each { |f| self.query << Feature.new(f) }
59
+ end
60
+ end
61
+
62
+ # Compare two DiscoInfo objects by name, type and category
63
+ # @param [DiscoInfo] o the Identity object to compare against
64
+ # @return [true, false]
65
+ def eql?(o, *fields)
66
+ super o, *(fields + [:identities, :features])
67
+ end
68
+
69
+ # DiscoInfo::Identity
70
+ class Identity < XMPPNode
71
+ # Create a new DiscoInfo::Identity
72
+ # @overload new(node)
73
+ # Imports the XML::Node to create a Identity object
74
+ # @param [XML::Node] node the node object to import
75
+ # @overload new(opts = {})
76
+ # Creates a new Identity using a hash of options
77
+ # @param [Hash] opts a hash of options
78
+ # @option opts [String] :name the name of the identity
79
+ # @option opts [String] :type the type of the identity
80
+ # @option opts [String] :category the category of the identity
81
+ # @overload new(name, type = nil, category = nil)
82
+ # Create a new Identity by name
83
+ # @param [String] name the name of the Identity
84
+ # @param [String, nil] type the type of the Identity
85
+ # @param [String, nil] category the category of the Identity
86
+ def self.new(name, type = nil, category = nil, xml_lang = nil)
87
+ new_node = super :identity
88
+
89
+ case name
90
+ when Nokogiri::XML::Node
91
+ new_node.inherit name
92
+ when Hash
93
+ new_node.name = name[:name]
94
+ new_node.type = name[:type]
95
+ new_node.category = name[:category]
96
+ new_node.xml_lang = name[:xml_lang]
97
+ else
98
+ new_node.name = name
99
+ new_node.type = type
100
+ new_node.category = category
101
+ new_node.xml_lang = xml_lang
102
+ end
103
+ new_node
104
+ end
105
+
106
+ # The Identity's category
107
+ # @return [Symbol, nil]
108
+ def category
109
+ read_attr :category, :to_sym
110
+ end
111
+
112
+ # Set the Identity's category
113
+ # @param [String, Symbol] category the new category
114
+ def category=(category)
115
+ write_attr :category, category
116
+ end
117
+
118
+ # The Identity's type
119
+ # @return [Symbol, nil]
120
+ def type
121
+ read_attr :type, :to_sym
122
+ end
123
+
124
+ # Set the Identity's type
125
+ # @param [String, Symbol] type the new category
126
+ def type=(type)
127
+ write_attr :type, type
128
+ end
129
+
130
+ # The Identity's name
131
+ # @return [String]
132
+ def name
133
+ read_attr :name
134
+ end
135
+
136
+ # Set the Identity's name
137
+ # @param [String] name the new name for the identity
138
+ def name=(name)
139
+ write_attr :name, name
140
+ end
141
+
142
+ # The Identity's xml_lang
143
+ # @return [String]
144
+ def xml_lang
145
+ read_attr "lang"
146
+ end
147
+
148
+ # Set the Identity's name
149
+ # @param [String] name the new name for the identity
150
+ def xml_lang=(xml_lang)
151
+ write_attr "xml:lang", xml_lang
152
+ end
153
+
154
+ # Compare two Identity objects by name, type and category
155
+ # @param [DiscoInfo::Identity] o the Identity object to compare against
156
+ # @return [true, false]
157
+ def eql?(o, *fields)
158
+ super o, *(fields + [:name, :type, :category, :xml_lang])
159
+ end
160
+ end # Identity
161
+
162
+ # DiscoInfo::Feature
163
+ class Feature < XMPPNode
164
+ # Create a new DiscoInfo::Feature object
165
+ # @overload new(node)
166
+ # Create a new Feature by importing an XML::Node
167
+ # @param [XML::Node] node an XML::Node to import
168
+ # @overload new(var)
169
+ # Create a new feature by var
170
+ # @param [String] var a the Feautre's var
171
+ # @return [DiscoInfo::Feature]
172
+ def self.new(var)
173
+ new_node = super :feature
174
+ case var
175
+ when Nokogiri::XML::Node
176
+ new_node.inherit var
177
+ else
178
+ new_node.var = var
179
+ end
180
+ new_node
181
+ end
182
+
183
+ # The Feature's var
184
+ # @return [String]
185
+ def var
186
+ read_attr :var
187
+ end
188
+
189
+ # Set the Feature's var
190
+ # @param [String] var the new var
191
+ def var=(var)
192
+ write_attr :var, var
193
+ end
194
+
195
+ # Compare two DiscoInfo::Feature objects by name, type and category
196
+ # @param [DiscoInfo::Feature] o the Identity object to compare against
197
+ # @return [true, false]
198
+ def eql?(o, *fields)
199
+ super o, *(fields + [:var])
200
+ end
201
+ end
202
+ end # Feature
203
+
204
+ end # Stanza
205
+ end # Blather
@@ -0,0 +1,134 @@
1
+ module Blather
2
+ class Stanza
3
+
4
+ # # DiscoItems Stanza
5
+ #
6
+ # [XEP-0030 Disco Info](http://xmpp.org/extensions/xep-0030.html#items)
7
+ #
8
+ # Disco Items node that provides or retreives items associated with a
9
+ # jabbery entity
10
+ #
11
+ # @handler :disco_items
12
+ class DiscoItems < Disco
13
+ register :disco_items, nil, 'http://jabber.org/protocol/disco#items'
14
+
15
+ # Create a new DiscoItems node
16
+ #
17
+ # @param [#to_s] type the IQ type
18
+ # @param [#to_s] node the node the items are associated with
19
+ # @param [Array<Blather::XMPPNode>] items an array of Disco::Items
20
+ # @return [Blather::Stanza::DiscoItems]
21
+ def self.new(type = nil, node = nil, items = [])
22
+ new_node = super type
23
+ new_node.node = node
24
+ new_node.items = [items]
25
+ new_node
26
+ end
27
+
28
+ # Set of items associated with the node
29
+ #
30
+ # @return [Array<Blather::Stanza::DiscoItems::Item>]
31
+ def items
32
+ query.find('//ns:item', :ns => self.class.registered_ns).map do |i|
33
+ Item.new i
34
+ end
35
+ end
36
+
37
+ # Add an array of items
38
+ # @param items the array of items, passed directly to Item.new
39
+ def items=(items)
40
+ query.find('//ns:item', :ns => self.class.registered_ns).each &:remove
41
+ if items
42
+ [items].flatten.each { |i| self.query << Item.new(i) }
43
+ end
44
+ end
45
+
46
+ # An individual Disco Item
47
+ class Item < XMPPNode
48
+ # Create a new Blather::Stanza::DiscoItems::Item
49
+ #
50
+ # @overload new(node)
51
+ # Create a new Item by inheriting an existing node
52
+ # @param [XML::Node] node an XML::Node to inherit from
53
+ # @overload new(opts)
54
+ # Create a new Item through a hash of options
55
+ # @param [Hash] opts a hash options
56
+ # @option opts [Blather::JID, String] :jid the JID to attach to the item
57
+ # @option opts [#to_s] :node the node the item is attached to
58
+ # @option opts [#to_S] :name the name of the Item
59
+ # @overload new(jid, node = nil, name = nil)
60
+ # Create a new Item
61
+ # @param [Blather::JID, String] jid the JID to attach to the item
62
+ # @param [#to_s] node the node the item is attached to
63
+ # @param [#to_s] name the name of the Item
64
+ def self.new(jid, node = nil, name = nil)
65
+ new_node = super :item
66
+
67
+ case jid
68
+ when Nokogiri::XML::Node
69
+ new_node.inherit jid
70
+ when Hash
71
+ new_node.jid = jid[:jid]
72
+ new_node.node = jid[:node]
73
+ new_node.name = jid[:name]
74
+ else
75
+ new_node.jid = jid
76
+ new_node.node = node
77
+ new_node.name = name
78
+ end
79
+ new_node
80
+ end
81
+
82
+ # Get the JID attached to the node
83
+ #
84
+ # @return [Blather::JID, nil]
85
+ def jid
86
+ (j = self[:jid]) ? JID.new(j) : nil
87
+ end
88
+
89
+ # Set the JID of the node
90
+ #
91
+ # @param [Blather::JID, String, nil] jid the new JID
92
+ def jid=(jid)
93
+ write_attr :jid, jid
94
+ end
95
+
96
+ # Get the name of the node
97
+ #
98
+ # @return [String, nil]
99
+ def node
100
+ read_attr :node
101
+ end
102
+
103
+ # Set the name of the node
104
+ #
105
+ # @param [String, nil] node the new node name
106
+ def node=(node)
107
+ write_attr :node, node
108
+ end
109
+
110
+ # Get the Item name
111
+ #
112
+ # @return [String, nil]
113
+ def name
114
+ read_attr :name
115
+ end
116
+
117
+ # Set the Item name
118
+ #
119
+ # @param [#to_s] name the Item name
120
+ def name=(name)
121
+ write_attr :name, name
122
+ end
123
+
124
+ # Compare two DiscoItems::Item objects by name, type and category
125
+ # @param [DiscoItems::Item] o the Identity object to compare against
126
+ # @return [true, false]
127
+ def eql?(o, *fields)
128
+ super o, *(fields + [:jid, :node, :name])
129
+ end
130
+ end
131
+ end
132
+
133
+ end #Stanza
134
+ end #Blather