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.rb +35 -12
  10. data/lib/blather/client.rb +1 -1
  11. data/lib/blather/client/client.rb +19 -13
  12. data/lib/blather/client/dsl.rb +16 -0
  13. data/lib/blather/client/dsl/pubsub.rb +133 -0
  14. data/lib/blather/core_ext/active_support.rb +1 -117
  15. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
  16. data/lib/blather/core_ext/nokogiri.rb +35 -0
  17. data/lib/blather/errors.rb +3 -20
  18. data/lib/blather/errors/sasl_error.rb +3 -1
  19. data/lib/blather/errors/stanza_error.rb +10 -17
  20. data/lib/blather/errors/stream_error.rb +11 -14
  21. data/lib/blather/jid.rb +1 -0
  22. data/lib/blather/roster.rb +9 -0
  23. data/lib/blather/roster_item.rb +6 -1
  24. data/lib/blather/stanza.rb +35 -18
  25. data/lib/blather/stanza/disco.rb +7 -1
  26. data/lib/blather/stanza/disco/disco_info.rb +45 -33
  27. data/lib/blather/stanza/disco/disco_items.rb +32 -21
  28. data/lib/blather/stanza/iq.rb +13 -8
  29. data/lib/blather/stanza/iq/query.rb +16 -8
  30. data/lib/blather/stanza/iq/roster.rb +33 -22
  31. data/lib/blather/stanza/message.rb +20 -31
  32. data/lib/blather/stanza/presence.rb +3 -5
  33. data/lib/blather/stanza/presence/status.rb +13 -21
  34. data/lib/blather/stanza/presence/subscription.rb +11 -16
  35. data/lib/blather/stanza/pubsub.rb +63 -0
  36. data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
  37. data/lib/blather/stanza/pubsub/create.rb +43 -0
  38. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  39. data/lib/blather/stanza/pubsub/event.rb +77 -0
  40. data/lib/blather/stanza/pubsub/items.rb +63 -0
  41. data/lib/blather/stanza/pubsub/publish.rb +58 -0
  42. data/lib/blather/stanza/pubsub/retract.rb +53 -0
  43. data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
  44. data/lib/blather/stanza/pubsub/subscription.rb +66 -0
  45. data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
  46. data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
  47. data/lib/blather/stanza/pubsub_owner.rb +41 -0
  48. data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
  49. data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
  50. data/lib/blather/stream.rb +76 -168
  51. data/lib/blather/stream/client.rb +1 -2
  52. data/lib/blather/stream/component.rb +9 -5
  53. data/lib/blather/stream/features.rb +53 -0
  54. data/lib/blather/stream/features/resource.rb +63 -0
  55. data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
  56. data/lib/blather/stream/features/session.rb +44 -0
  57. data/lib/blather/stream/features/tls.rb +28 -0
  58. data/lib/blather/stream/parser.rb +70 -46
  59. data/lib/blather/xmpp_node.rb +113 -52
  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 +54 -18
  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
@@ -4,13 +4,13 @@ module Blather
4
4
  # Base XML Node
5
5
  # All XML classes subclass XMPPNode
6
6
  # it allows the addition of helpers
7
- class XMPPNode < XML::Node
7
+ class XMPPNode < Nokogiri::XML::Node
8
8
  BASE_NAMES = %w[presence message iq].freeze
9
9
 
10
10
  @@registrations = {}
11
11
 
12
- class_inheritable_accessor :ns,
13
- :name
12
+ class_inheritable_accessor :registered_ns,
13
+ :registered_name
14
14
 
15
15
  ##
16
16
  # Lets a subclass register itself
@@ -19,9 +19,9 @@ module Blather
19
19
  # up the class name of the object to instantiate when a new
20
20
  # stanza is received
21
21
  def self.register(name, ns = nil)
22
- self.name = name.to_s
23
- self.ns = ns
24
- @@registrations[[self.name, self.ns]] = self
22
+ self.registered_name = name.to_s
23
+ self.registered_ns = ns
24
+ @@registrations[[self.registered_name, self.registered_ns]] = self
25
25
  end
26
26
 
27
27
  ##
@@ -36,7 +36,7 @@ module Blather
36
36
  # of that class and imports all the <tt>node</tt>'s attributes
37
37
  # and children into it.
38
38
  def self.import(node)
39
- klass = class_from_registration(node.element_name, node.namespace)
39
+ klass = class_from_registration(node.element_name, (node.namespace.href if node.namespace))
40
40
  if klass && klass != self
41
41
  klass.import(node)
42
42
  else
@@ -55,16 +55,18 @@ module Blather
55
55
  # end
56
56
  #
57
57
  # n = Node.new
58
- # n.attributes[:type] = 'foo'
58
+ # n[:type] = 'foo'
59
59
  # n.type == :foo
60
- # n.attributes[:name] = 'bar'
60
+ # n[:name] = 'bar'
61
61
  # n.name == 'bar'
62
62
  def self.attribute_reader(*syms)
63
63
  opts = syms.last.is_a?(Hash) ? syms.pop : {}
64
+ convert_str = "val.#{opts[:call]} if val" if opts[:call]
64
65
  syms.flatten.each do |sym|
65
66
  class_eval(<<-END, __FILE__, __LINE__)
66
67
  def #{sym}
67
- attributes[:#{sym}]#{".to_sym unless attributes[:#{sym}].blank?" unless opts[:to_sym] == false}
68
+ val = self[:#{sym}]
69
+ #{convert_str}
68
70
  end
69
71
  END
70
72
  end
@@ -79,13 +81,13 @@ module Blather
79
81
  #
80
82
  # n = Node.new
81
83
  # n.type = 'foo'
82
- # n.attributes[:type] == 'foo'
84
+ # n[:type] == 'foo'
83
85
  def self.attribute_writer(*syms)
84
86
  syms.flatten.each do |sym|
85
87
  next if sym.is_a?(Hash)
86
88
  class_eval(<<-END, __FILE__, __LINE__)
87
89
  def #{sym}=(value)
88
- attributes[:#{sym}] = value
90
+ self[:#{sym}] = value
89
91
  end
90
92
  END
91
93
  end
@@ -110,14 +112,74 @@ module Blather
110
112
  attribute_writer *syms
111
113
  end
112
114
 
115
+ ##
116
+ # Provides a content reader helper that returns the content of a node
117
+ # +method+ is the method to create
118
+ # +conversion+ is a method to call on the content before sending it back
119
+ # +node+ is the name of the content node (this defaults to the method name)
120
+ #
121
+ # class Node
122
+ # content_attr_reader :body
123
+ # content_attr_reader :type, :to_sym
124
+ # content_attr_reader :id, :to_i, :identity
125
+ # end
126
+ #
127
+ # n = Node.new 'foo'
128
+ # n.to_s == "<foo><body>foobarbaz</body><type>error</type><identity>1000</identity></foo>"
129
+ # n.body == 'foobarbaz'
130
+ # n.type == :error
131
+ # n.id == 1000
132
+ def self.content_attr_reader(method, conversion = nil, node = nil)
133
+ node ||= method
134
+ conversion = "val.#{conversion} if val.respond_to?(:#{conversion})" if conversion
135
+ class_eval(<<-END, __FILE__, __LINE__)
136
+ def #{method}
137
+ val = content_from :#{node}
138
+ #{conversion}
139
+ end
140
+ END
141
+ end
142
+
143
+ ##
144
+ # Provides a content writer helper that creates or updates the content of a node
145
+ # +method+ is the method to create
146
+ # +node+ is the name of the node to create (defaults to the method name)
147
+ #
148
+ # class Node
149
+ # content_attr_writer :body
150
+ # content_attr_writer :id, :identity
151
+ # end
152
+ #
153
+ # n = Node.new 'foo'
154
+ # n.body = 'thebodytext'
155
+ # n.id = 'id-text'
156
+ # n.to_s == '<foo><body>thebodytext</body><identity>id-text</identity></foo>'
157
+ def self.content_attr_writer(method, node = nil)
158
+ node ||= method
159
+ class_eval(<<-END, __FILE__, __LINE__)
160
+ def #{method}=(val)
161
+ set_content_for :#{node}, val
162
+ end
163
+ END
164
+ end
165
+
166
+ ##
167
+ # Provides a quick way of building +content_attr_reader+ and +content_attr_writer+
168
+ # for the same method and node
169
+ def self.content_attr_accessor(method, conversion = nil, node = nil)
170
+ content_attr_reader method, conversion, node
171
+ content_attr_writer method, node
172
+ end
173
+
113
174
  ##
114
175
  # Automatically sets the namespace registered by the subclass
115
- def initialize(name = nil, content = nil)
116
- name ||= self.class.name
117
- content = content.to_s if content
176
+ def self.new(name = nil, doc = nil)
177
+ name ||= self.registered_name
118
178
 
119
- super name.to_s, content
120
- self.namespace = self.class.ns unless BASE_NAMES.include?(name.to_s)
179
+ node = super name.to_s, (doc || Nokogiri::XML::Document.new)
180
+ node.document.root = node unless doc
181
+ node.namespace = self.registered_ns unless BASE_NAMES.include?(name.to_s)
182
+ node
121
183
  end
122
184
 
123
185
  ##
@@ -126,80 +188,79 @@ module Blather
126
188
  self.class.import self
127
189
  end
128
190
 
191
+ alias_method :nokogiri_namespace=, :namespace=
129
192
  def namespace=(namespaces)
130
193
  case namespaces
131
- when XML::Namespace
132
- self.namespaces.namespace = namespaces
194
+ when Nokogiri::XML::Namespace
195
+ self.nokogiri_namespace = namespaces
133
196
  when String
134
- self.namespaces.namespace = XML::Namespace.new(self, nil, namespaces)
197
+ self.add_namespace nil, namespaces
135
198
  when Hash
199
+ if ns = namespaces.delete(nil)
200
+ self.add_namespace nil, ns
201
+ end
136
202
  namespaces.each do |p, n|
137
- self.namespaces.namespace = XML::Namespace.new(self, p, n)
203
+ ns = self.add_namespace p, n
204
+ self.nokogiri_namespace = ns
138
205
  end
139
206
  end
140
207
  end
141
208
 
142
- def namespace(prefix = nil)
143
- (ns = namespaces.find_by_prefix(prefix)) ? ns.href : nil
209
+ def namespace_href
210
+ namespace.href if namespace
144
211
  end
145
212
 
146
213
  ##
147
214
  # Remove a child with the name and (optionally) namespace given
148
215
  def remove_child(name, ns = nil)
149
- name = name.to_s
150
- self.detect { |n| n.remove! if n.element_name == name && (!ns || n.namespace == ns) }
216
+ child = xpath(name, ns).first
217
+ child.remove if child
151
218
  end
152
219
 
153
220
  ##
154
221
  # Remove all children with a given name
155
222
  def remove_children(name)
156
- name = name.to_s
157
- self.find(name).each { |n| n.remove! }
223
+ xpath("./*[local-name()='#{name}']").remove
158
224
  end
159
225
 
160
226
  ##
161
227
  # Pull the content from a child
162
- def content_from(name)
163
- name = name.to_s
164
- (child = self.detect { |n| n.element_name == name }) ? child.content : nil
228
+ def content_from(name, ns = nil)
229
+ child = xpath(name, ns).first
230
+ child.content if child
165
231
  end
166
232
 
167
233
  ##
168
- # Create a copy
169
- def copy(deep = true)
170
- copy = self.class.new.inherit(self)
171
- copy.element_name = self.element_name
172
- copy
234
+ # Sets the content for the specified node.
235
+ # If the node exists it is updated. If not a new node is created
236
+ # If the node exists and the content is nil, the node will be removed entirely
237
+ def set_content_for(node, content = nil)
238
+ if content
239
+ child = xpath(node).first
240
+ self << (child = XMPPNode.new(node, self.document)) unless child
241
+ child.content = content
242
+ else
243
+ remove_child node
244
+ end
173
245
  end
174
246
 
247
+ alias_method :copy, :dup
248
+
175
249
  ##
176
250
  # Inherit all of <tt>stanza</tt>'s attributes and children
177
251
  def inherit(stanza)
252
+ set_namespace stanza.namespace if stanza.namespace
178
253
  inherit_attrs stanza.attributes
179
- stanza.children.each { |c| self << c.copy(true) }
254
+ stanza.children.each { |c| self << c.dup }
180
255
  self
181
256
  end
182
257
 
183
258
  ##
184
259
  # Inherit only <tt>stanza</tt>'s attributes
185
260
  def inherit_attrs(attrs)
186
- attrs.each { |a| attributes[a.name] = a.value }
261
+ attrs.each { |name, value| self[name] = value }
187
262
  self
188
263
  end
189
-
190
- ##
191
- # Turn itself into an XML string and remove all whitespace between nodes
192
- def to_xml
193
- # TODO: Fix this for HTML nodes (and any other that might require whitespace)
194
- to_s.gsub(">\n<", '><')
195
- end
196
-
197
- ##
198
- # Override #find to work when a node isn't attached to a document
199
- def find(what, nslist = nil)
200
- what = what.to_s
201
- (self.doc ? super(what, nslist) : select { |i| i.element_name == what })
202
- end
203
264
  end #XMPPNode
204
265
 
205
- end
266
+ end
@@ -1,7 +1,7 @@
1
1
  require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
2
2
  require 'blather/client/client'
3
3
 
4
- describe 'Blather::Client' do
4
+ describe Blather::Client do
5
5
  before do
6
6
  @client = Blather::Client.new
7
7
  end
@@ -13,13 +13,13 @@ describe 'Blather::Client' do
13
13
  jid = 'me@me.com/test'
14
14
  @client.must_respond_to :jid=
15
15
  @client.jid = jid
16
- @client.jid.must_be_kind_of JID
17
- @client.jid.must_equal JID.new(jid)
16
+ @client.jid.must_be_kind_of Blather::JID
17
+ @client.jid.must_equal Blather::JID.new(jid)
18
18
  end
19
19
 
20
20
  it 'provides a reader for the roster' do
21
21
  @client.must_respond_to :roster
22
- @client.roster.must_be_kind_of Roster
22
+ @client.roster.must_be_kind_of Blather::Roster
23
23
  end
24
24
 
25
25
  it 'provides a status reader' do
@@ -78,14 +78,8 @@ describe 'Blather::Client' do
78
78
  @client.unbind
79
79
  end
80
80
 
81
- it 'raises an error if the stream type somehow is not supported' do
82
- Blather::Stream::Component.stubs(:start).returns nil
83
- @client.setup('me.com', 'secret').run
84
- lambda { @client.post_init }.must_raise RuntimeError
85
- end
86
-
87
81
  it 'can register a temporary handler based on stanza ID' do
88
- stanza = Stanza::Iq.new
82
+ stanza = Blather::Stanza::Iq.new
89
83
  response = mock()
90
84
  response.expects(:call)
91
85
  @client.register_tmp_handler(stanza.id) { |_| response.call }
@@ -93,7 +87,7 @@ describe 'Blather::Client' do
93
87
  end
94
88
 
95
89
  it 'removes a tmp handler as soon as it is used' do
96
- stanza = Stanza::Iq.new
90
+ stanza = Blather::Stanza::Iq.new
97
91
  response = mock()
98
92
  response.expects(:call)
99
93
  @client.register_tmp_handler(stanza.id) { |_| response.call }
@@ -102,7 +96,7 @@ describe 'Blather::Client' do
102
96
  end
103
97
 
104
98
  it 'will create a handler then write the stanza' do
105
- stanza = Stanza::Iq.new
99
+ stanza = Blather::Stanza::Iq.new
106
100
  response = mock()
107
101
  response.expects(:call)
108
102
  @client.expects(:write).with do |s|
@@ -113,7 +107,7 @@ describe 'Blather::Client' do
113
107
  end
114
108
 
115
109
  it 'can register a handler' do
116
- stanza = Stanza::Iq.new
110
+ stanza = Blather::Stanza::Iq.new
117
111
  response = mock()
118
112
  response.expects(:call).times(2)
119
113
  @client.register_handler(:iq) { |_| response.call }
@@ -127,26 +121,8 @@ describe 'Blather::Client#write' do
127
121
  @client = Blather::Client.new
128
122
  end
129
123
 
130
- it 'sets the from attr on a stanza' do
131
- jid = 'me@me.com'
132
- stanza = mock(:from => nil)
133
- stanza.expects(:from=).with jid
134
- @client.jid = jid
135
- @client.write stanza
136
- end
137
-
138
- it 'does not set the from attr if it already exists' do
139
- jid = 'me@me.com'
140
- stanza = Stanza::Iq.new
141
- stanza.from = jid
142
- stanza.expects(:from).returns jid
143
- stanza.expects(:from=).never
144
- @client.jid = jid
145
- @client.write stanza
146
- end
147
-
148
124
  it 'writes to the stream' do
149
- stanza = Stanza::Iq.new
125
+ stanza = Blather::Stanza::Iq.new
150
126
  stream = mock()
151
127
  stream.expects(:send).with stanza
152
128
  Blather::Stream::Client.expects(:start).returns stream
@@ -173,11 +149,11 @@ describe 'Blather::Client#status=' do
173
149
  end
174
150
 
175
151
  it 'writes the new status to the stream' do
176
- Stanza::Presence::Status.stubs(:next_id).returns 0
152
+ Blather::Stanza::Presence::Status.stubs(:next_id).returns 0
177
153
  status = [:away, 'message']
178
154
  @client.expects(:write).with do |s|
179
- s.must_be_kind_of Stanza::Presence::Status
180
- s.to_s.must_equal Stanza::Presence::Status.new(*status).to_s
155
+ s.must_be_kind_of Blather::Stanza::Presence::Status
156
+ s.to_s.must_equal Blather::Stanza::Presence::Status.new(*status).to_s
181
157
  end
182
158
  @client.status = status
183
159
  end
@@ -189,34 +165,34 @@ describe 'Blather::Client default handlers' do
189
165
  end
190
166
 
191
167
  it 're-raises errors' do
192
- err = BlatherError.new
193
- lambda { @client.receive_data err }.must_raise BlatherError
168
+ err = Blather::BlatherError.new
169
+ lambda { @client.receive_data err }.must_raise Blather::BlatherError
194
170
  end
195
171
 
196
172
  it 'responds to iq:get with a "service-unavailable" error' do
197
- get = Stanza::Iq.new :get
198
- err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
173
+ get = Blather::Stanza::Iq.new :get
174
+ err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
199
175
  @client.expects(:write).with err
200
176
  @client.receive_data get
201
177
  end
202
178
 
203
179
  it 'responds to iq:get with a "service-unavailable" error' do
204
- get = Stanza::Iq.new :get
205
- err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
206
- @client.expects(:write).with err
180
+ get = Blather::Stanza::Iq.new :get
181
+ err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
182
+ @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
207
183
  @client.receive_data get
208
184
  end
209
185
 
210
186
  it 'responds to iq:set with a "service-unavailable" error' do
211
- get = Stanza::Iq.new :set
212
- err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
213
- @client.expects(:write).with err
187
+ get = Blather::Stanza::Iq.new :set
188
+ err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
189
+ @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
214
190
  @client.receive_data get
215
191
  end
216
192
 
217
193
  it 'handles status changes by updating the roster if the status is from a JID in the roster' do
218
194
  jid = 'friend@jabber.local'
219
- status = Stanza::Presence::Status.new :away
195
+ status = Blather::Stanza::Presence::Status.new :away
220
196
  status.stubs(:from).returns jid
221
197
  roster_item = mock()
222
198
  roster_item.expects(:status=).with status
@@ -225,7 +201,7 @@ describe 'Blather::Client default handlers' do
225
201
  end
226
202
 
227
203
  it 'handles an incoming roster node by processing it through the roster' do
228
- roster = Stanza::Iq::Roster.new
204
+ roster = Blather::Stanza::Iq::Roster.new
229
205
  client_roster = mock()
230
206
  client_roster.expects(:process).with roster
231
207
  @client.stubs(:roster).returns client_roster
@@ -259,12 +235,12 @@ describe 'Blather::Client with a Client stream' do
259
235
  end
260
236
 
261
237
  it 'sends a request for the roster when post_init is called' do
262
- @stream.expects(:send).with { |stanza| stanza.must_be_kind_of Stanza::Iq::Roster }
238
+ @stream.expects(:send).with { |stanza| stanza.must_be_kind_of Blather::Stanza::Iq::Roster }
263
239
  @client.post_init
264
240
  end
265
241
 
266
242
  it 'calls the ready handler after post_init and roster is received' do
267
- result_roster = Stanza::Iq::Roster.new :result
243
+ result_roster = Blather::Stanza::Iq::Roster.new :result
268
244
  @stream.stubs(:send).with { |s| result_roster.id = s.id; @client.receive_data result_roster; true }
269
245
 
270
246
  ready = mock()
@@ -277,7 +253,7 @@ end
277
253
  describe 'Blather::Client guards' do
278
254
  before do
279
255
  @client = Blather::Client.new
280
- @stanza = Stanza::Iq.new
256
+ @stanza = Blather::Stanza::Iq.new
281
257
  @response = mock()
282
258
  end
283
259
 
@@ -329,15 +305,15 @@ describe 'Blather::Client guards' do
329
305
  @response.expects(:call).times(2)
330
306
  @client.register_handler(:iq, :type => [:result, :error]) { |_| @response.call }
331
307
 
332
- stanza = Stanza::Iq.new
308
+ stanza = Blather::Stanza::Iq.new
333
309
  stanza.expects(:type).at_least_once.returns :result
334
310
  @client.receive_data stanza
335
311
 
336
- stanza = Stanza::Iq.new
312
+ stanza = Blather::Stanza::Iq.new
337
313
  stanza.expects(:type).at_least_once.returns :error
338
314
  @client.receive_data stanza
339
315
 
340
- stanza = Stanza::Iq.new
316
+ stanza = Blather::Stanza::Iq.new
341
317
  stanza.expects(:type).at_least_once.returns :get
342
318
  @client.receive_data stanza
343
319
  end
@@ -346,12 +322,12 @@ describe 'Blather::Client guards' do
346
322
  @response.expects :call
347
323
  @client.register_handler(:iq, :type => :get, :body => 'test') { |_| @response.call }
348
324
 
349
- stanza = Stanza::Iq.new
325
+ stanza = Blather::Stanza::Iq.new
350
326
  stanza.expects(:type).at_least_once.returns :get
351
327
  stanza.expects(:body).returns 'test'
352
328
  @client.receive_data stanza
353
329
 
354
- stanza = Stanza::Iq.new
330
+ stanza = Blather::Stanza::Iq.new
355
331
  stanza.expects(:type).at_least_once.returns :set
356
332
  stanza.expects(:body).never
357
333
  @client.receive_data stanza
@@ -361,12 +337,12 @@ describe 'Blather::Client guards' do
361
337
  @response.expects(:call).times 2
362
338
  @client.register_handler(:iq, [{:type => :get}, {:body => 'test'}]) { |_| @response.call }
363
339
 
364
- stanza = Stanza::Iq.new
340
+ stanza = Blather::Stanza::Iq.new
365
341
  stanza.expects(:type).at_least_once.returns :set
366
342
  stanza.expects(:body).returns 'test'
367
343
  @client.receive_data stanza
368
344
 
369
- stanza = Stanza::Iq.new
345
+ stanza = Blather::Stanza::Iq.new
370
346
  stanza.stubs(:type).at_least_once.returns :get
371
347
  stanza.expects(:body).never
372
348
  @client.receive_data stanza
@@ -383,6 +359,16 @@ describe 'Blather::Client guards' do
383
359
  @client.receive_data @stanza
384
360
  end
385
361
 
362
+ it 'can be an xpath and will send the result to the handler' do
363
+ @response.expects(:call).with do |stanza, xpath|
364
+ xpath.must_be_instance_of Nokogiri::XML::NodeSet
365
+ xpath.wont_be_empty
366
+ stanza.must_equal @stanza
367
+ end
368
+ @client.register_handler(:iq, "/iq[@id='#{@stanza.id}']") { |stanza, xpath| @response.call stanza, xpath }
369
+ @client.receive_data @stanza
370
+ end
371
+
386
372
  it 'raises an error when a bad guard is tried' do
387
373
  lambda { @client.register_handler(:iq, 0) {} }.must_raise RuntimeError
388
374
  end