blather 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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