blather 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -20,6 +20,8 @@ RubyForge:: http://rubyforge.org/projects/squishtech
20
20
 
21
21
  RDocs:: http://squishtech.rubyforge.org/blather
22
22
 
23
+ Google Group:: http://groups.google.com/group/xmpp-blather
24
+
23
25
  = Usage
24
26
 
25
27
  == Installation
@@ -78,7 +78,7 @@ module Blather #:nodoc:
78
78
  def run
79
79
  raise 'not setup!' unless setup?
80
80
  klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
81
- @stream = klass.start self, *@setup
81
+ klass.start self, *@setup
82
82
  end
83
83
 
84
84
  ##
@@ -111,7 +111,7 @@ module Blather #:nodoc:
111
111
  ##
112
112
  # Write data to the stream
113
113
  def write(stanza)
114
- @stream.send(stanza) if @stream
114
+ self.stream.send(stanza)
115
115
  end
116
116
 
117
117
  ##
@@ -131,10 +131,12 @@ module Blather #:nodoc:
131
131
  ##
132
132
  # Close the connection
133
133
  def close
134
- @stream.close_connection_after_writing
134
+ self.stream.close_connection_after_writing
135
135
  end
136
136
 
137
- def post_init # :nodoc:
137
+ def post_init(stream, jid = nil) # :nodoc:
138
+ @stream = stream
139
+ @jid = JID.new(jid) if jid
138
140
  self.jid.node ? client_post_init : ready!
139
141
  end
140
142
 
@@ -150,10 +152,6 @@ module Blather #:nodoc:
150
152
  end
151
153
  end
152
154
 
153
- def jid=(new_jid) # :nodoc :
154
- @jid = JID.new new_jid
155
- end
156
-
157
155
  def setup? # :nodoc:
158
156
  @setup.is_a? Array
159
157
  end
@@ -167,6 +165,11 @@ module Blather #:nodoc:
167
165
  end
168
166
 
169
167
  protected
168
+ def stream
169
+ raise 'Stream not ready!' unless @stream
170
+ @stream
171
+ end
172
+
170
173
  def check_handler(type, guards)
171
174
  Blather.logger.warn "Handler for type \"#{type}\" will never be called as it's not a registered type" unless current_handlers.include?(type)
172
175
  check_guards guards
@@ -233,10 +236,11 @@ module Blather #:nodoc:
233
236
  end
234
237
 
235
238
  def call_handler(handler, guards, stanza) # :nodoc:
236
- if guards.first.respond_to?(:to_str) && !(result = stanza.find(*guards)).empty?
237
- handler.call(stanza, result)
238
- elsif !guarded?(guards, stanza)
239
- handler.call(stanza)
239
+ if guards.first.respond_to?(:to_str)
240
+ result = stanza.find(*guards)
241
+ handler.call(stanza, result) unless result.empty?
242
+ else
243
+ handler.call(stanza) unless guarded?(guards, stanza)
240
244
  end
241
245
  end
242
246
 
@@ -256,8 +260,9 @@ module Blather #:nodoc:
256
260
  # return FALSE unless any inequality is found
257
261
  guard.find do |method, test|
258
262
  value = stanza.__send__(method)
263
+ # last_match is the only method found unique to Regexp classes
259
264
  if test.class.respond_to?(:last_match)
260
- !(test =~ value)
265
+ !(test =~ value.to_s)
261
266
  elsif test.is_a?(Array)
262
267
  !test.include? value
263
268
  else
@@ -115,7 +115,7 @@ module Blather
115
115
  stanza.to = who
116
116
  stanza.node = where
117
117
 
118
- client.temporary_handler stanza.id, &callback
118
+ client.register_tmp_handler stanza.id, &callback
119
119
  write stanza
120
120
  end
121
121
 
@@ -98,7 +98,9 @@ class Presence
98
98
  ##
99
99
  # :available if state is nil
100
100
  def state # :nodoc:
101
- (type || content_from(:show) || :available).to_sym
101
+ state = type || content_from(:show)
102
+ state = :available if state.blank?
103
+ state.to_sym
102
104
  end
103
105
 
104
106
  ##
@@ -25,7 +25,7 @@ class PubSub
25
25
  end
26
26
 
27
27
  def retractions
28
- items_node.find('ns:retract', :ns => self.class.registered_ns).map { |i| i[:id] }
28
+ items_node.find('//ns:retract', :ns => self.class.registered_ns).map { |i| i[:id] }
29
29
  end
30
30
 
31
31
  def retractions?
@@ -33,7 +33,7 @@ class PubSub
33
33
  end
34
34
 
35
35
  def items
36
- items_node.find('ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
36
+ items_node.find('//ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
37
37
  end
38
38
 
39
39
  def items?
@@ -45,8 +45,8 @@ class PubSub
45
45
  end
46
46
 
47
47
  def event_node
48
- node = find_first('ns:event', :ns => self.class.registered_ns)
49
- node = find_first('event', self.class.registered_ns) unless node
48
+ node = find_first('//ns:event', :ns => self.class.registered_ns)
49
+ node = find_first('//event', self.class.registered_ns) unless node
50
50
  unless node
51
51
  (self << (node = XMPPNode.new('event', self.document)))
52
52
  node.namespace = self.class.registered_ns
@@ -55,7 +55,7 @@ class PubSub
55
55
  end
56
56
 
57
57
  def items_node
58
- node = find_first('event/ns:items', :ns => self.class.registered_ns)
58
+ node = find_first('ns:event/ns:items', :ns => self.class.registered_ns)
59
59
  unless node
60
60
  (self.event_node << (node = XMPPNode.new('items', self.document)))
61
61
  node.namespace = event_node.namespace
@@ -64,7 +64,7 @@ class PubSub
64
64
  end
65
65
 
66
66
  def purge_node
67
- event_node.find_first('ns:purge', :ns => self.class.registered_ns)
67
+ event_node.find_first('//ns:purge', :ns => self.class.registered_ns)
68
68
  end
69
69
 
70
70
  def subscription_ids
@@ -4,7 +4,8 @@ module Blather
4
4
  class NoConnection < RuntimeError; end
5
5
 
6
6
  STREAM_NS = 'http://etherx.jabber.org/streams'
7
- attr_accessor :jid, :password
7
+ attr_accessor :password
8
+ attr_reader :jid
8
9
 
9
10
  ##
10
11
  # Start the stream between client and server
@@ -25,9 +26,7 @@ module Blather
25
26
  connect jid.domain, port, self, client, jid, pass
26
27
  else
27
28
  srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
28
- conn = nil
29
- srv.each { |r| break unless (conn = connect(r.target.to_s, r.port, self, client, jid, pass)) === false }
30
- conn
29
+ srv.each { |r| break unless connect(r.target.to_s, r.port, self, client, jid, pass) === false }
31
30
  end
32
31
  end
33
32
  end
@@ -139,7 +138,6 @@ module Blather
139
138
  def jid=(new_jid) # :nodoc:
140
139
  Blather.logger.debug "NEW JID: #{new_jid}"
141
140
  @jid = JID.new new_jid
142
- @client.jid = @jid
143
141
  end
144
142
 
145
143
  protected
@@ -160,7 +158,7 @@ module Blather
160
158
  def ready!
161
159
  @state = :started
162
160
  @receiver = @client
163
- @client.post_init
161
+ @client.post_init self, @jid
164
162
  end
165
163
  end
166
164
  end
@@ -51,7 +51,7 @@ class Stream # :nodoc:
51
51
  Blather.logger.debug "RESOURCE NODE #{@node}"
52
52
  # ensure this is a response to our original request
53
53
  if @id == @node['id']
54
- @stream.jid = JID.new @node.find_first('//bind/bind_ns:jid', :bind_ns => BIND_NS).content
54
+ @stream.jid = JID.new @node.find_first('bind_ns:bind/bind_ns:jid', :bind_ns => BIND_NS).content
55
55
  succeed!
56
56
  else
57
57
  fail!("BIND result ID mismatch. Expected: #{@id}. Received: #{@node['id']}")
@@ -6,7 +6,7 @@ class Stream # :nodoc:
6
6
  class Parser # :nodoc:
7
7
  NS_TO_IGNORE = %w[jabber:client jabber:component:accept]
8
8
 
9
- @@debug = !false
9
+ @@debug = false
10
10
  def self.debug; @@debug; end
11
11
  def self.debug=(debug); @@debug = debug; end
12
12
 
@@ -27,9 +27,11 @@ class Stream # :nodoc:
27
27
 
28
28
  def start_document; end
29
29
  def end_document; end
30
+ def start_element(*args); end
31
+ def end_element(*args); end
30
32
  def warning(*args); end
31
33
 
32
- def start_element_ns(elem, attrs, prefix, uri, namespaces)
34
+ def start_element_namespace(elem, attrs, prefix, uri, namespaces)
33
35
  Blather.logger.debug "START ELEM: (#{{:elem => elem, :attrs => attrs, :prefix => prefix, :uri => uri, :ns => namespaces}.inspect})" if @@debug
34
36
 
35
37
  args = [elem]
@@ -37,13 +39,17 @@ class Stream # :nodoc:
37
39
  node = XMPPNode.new *args
38
40
  node.document.root = node unless @current
39
41
 
40
- attrs.each { |k,v| node[k] = v if k }
42
+ attrs.each do |attr|
43
+ node[attr.localname] = attr.value
44
+ end
41
45
 
42
46
  if !@receiver.stopped?
43
47
  @current << node if @current
44
48
  @current = node
45
49
  end
46
50
 
51
+
52
+ ns_keys = namespaces.map { |pre, href| pre }
47
53
  namespaces.delete_if { |pre, href| NS_TO_IGNORE.include? href }
48
54
  @namespace_definitions.push []
49
55
  namespaces.each do |pre, href|
@@ -51,7 +57,7 @@ class Stream # :nodoc:
51
57
  ns = node.add_namespace(pre, href)
52
58
  @namespaces[[pre, href]] ||= ns
53
59
  end
54
- @namespaces[[prefix, uri]] ||= node.add_namespace(prefix, uri) if prefix && !namespaces[prefix]
60
+ @namespaces[[prefix, uri]] ||= node.add_namespace(prefix, uri) if prefix && !ns_keys.include?(prefix)
55
61
  node.namespace = @namespaces[[prefix, uri]]
56
62
 
57
63
  deliver(node) if elem == 'stream'
@@ -66,7 +72,7 @@ class Stream # :nodoc:
66
72
  =end
67
73
  end
68
74
 
69
- def end_element_ns(elem, prefix, uri)
75
+ def end_element_namespace(elem, prefix, uri)
70
76
  Blather.logger.debug "END ELEM: #{{:elem => elem, :prefix => prefix, :uri => uri}.inspect}" if @@debug
71
77
 
72
78
  if elem == 'stream'
@@ -251,7 +251,11 @@ module Blather
251
251
  def inherit(stanza)
252
252
  set_namespace stanza.namespace if stanza.namespace
253
253
  inherit_attrs stanza.attributes
254
- stanza.children.each { |c| self << c.dup }
254
+ stanza.children.each do |c|
255
+ self << (n = c.dup)
256
+ ns = n.namespace_definitions.find { |ns| ns.prefix == c.namespace.prefix }
257
+ n.namespace = ns if ns
258
+ end
255
259
  self
256
260
  end
257
261
 
@@ -4,17 +4,15 @@ require 'blather/client/client'
4
4
  describe Blather::Client do
5
5
  before do
6
6
  @client = Blather::Client.new
7
+ @stream = mock()
8
+ @stream.stubs(:send)
9
+ @jid = Blather::JID.new('n@d/r')
10
+ @client.post_init @stream, @jid
7
11
  end
8
12
 
9
- it 'provides a JID accessor' do
13
+ it 'provides a Blather::JID reader' do
10
14
  @client.must_respond_to :jid
11
- @client.jid.must_be_nil
12
-
13
- jid = 'me@me.com/test'
14
- @client.must_respond_to :jid=
15
- @client.jid = jid
16
- @client.jid.must_be_kind_of Blather::JID
17
- @client.jid.must_equal Blather::JID.new(jid)
15
+ @client.jid.must_equal @jid
18
16
  end
19
17
 
20
18
  it 'provides a reader for the roster' do
@@ -61,8 +59,8 @@ describe Blather::Client do
61
59
  it 'writes to the connection the closes when #close is called' do
62
60
  stream = mock()
63
61
  stream.expects(:close_connection_after_writing)
64
- Blather::Stream::Component.stubs(:start).returns stream
65
- @client.setup('me.com', 'secret').run
62
+ @client.setup('me.com', 'secret')
63
+ @client.post_init stream, Blather::JID.new('me.com')
66
64
  @client.close
67
65
  end
68
66
 
@@ -162,8 +160,8 @@ describe 'Blather::Client#write' do
162
160
  stanza = Blather::Stanza::Iq.new
163
161
  stream = mock()
164
162
  stream.expects(:send).with stanza
165
- Blather::Stream::Client.expects(:start).returns stream
166
- @client.setup('me@me.com', 'me').run
163
+ @client.setup('me@me.com', 'me')
164
+ @client.post_init stream, Blather::JID.new('me.com')
167
165
  @client.write stanza
168
166
  end
169
167
  end
@@ -171,15 +169,20 @@ end
171
169
  describe 'Blather::Client#status=' do
172
170
  before do
173
171
  @client = Blather::Client.new
172
+ @stream = mock()
173
+ @stream.stubs(:send)
174
+ @client.post_init @stream, Blather::JID.new('n@d/r')
174
175
  end
175
176
 
176
- it 'updates the state when not sending to a JID' do
177
+ it 'updates the state when not sending to a Blather::JID' do
178
+ @stream.stubs(:write)
177
179
  @client.status.wont_equal :away
178
180
  @client.status = :away, 'message'
179
181
  @client.status.must_equal :away
180
182
  end
181
183
 
182
- it 'does not update the state when sending to a JID' do
184
+ it 'does not update the state when sending to a Blather::JID' do
185
+ @stream.stubs(:write)
183
186
  @client.status.wont_equal :away
184
187
  @client.status = :away, 'message', 'me@me.com'
185
188
  @client.status.wont_equal :away
@@ -188,7 +191,7 @@ describe 'Blather::Client#status=' do
188
191
  it 'writes the new status to the stream' do
189
192
  Blather::Stanza::Presence::Status.stubs(:next_id).returns 0
190
193
  status = [:away, 'message']
191
- @client.expects(:write).with do |s|
194
+ @stream.expects(:send).with do |s|
192
195
  s.must_be_kind_of Blather::Stanza::Presence::Status
193
196
  s.to_s.must_equal Blather::Stanza::Presence::Status.new(*status).to_s
194
197
  end
@@ -199,6 +202,9 @@ end
199
202
  describe 'Blather::Client default handlers' do
200
203
  before do
201
204
  @client = Blather::Client.new
205
+ @stream = mock()
206
+ @stream.stubs(:send)
207
+ @client.post_init @stream, Blather::JID.new('n@d/r')
202
208
  end
203
209
 
204
210
  it 're-raises errors' do
@@ -227,7 +233,7 @@ describe 'Blather::Client default handlers' do
227
233
  @client.receive_data get
228
234
  end
229
235
 
230
- it 'handles status changes by updating the roster if the status is from a JID in the roster' do
236
+ it 'handles status changes by updating the roster if the status is from a Blather::JID in the roster' do
231
237
  jid = 'friend@jabber.local'
232
238
  status = Blather::Stanza::Presence::Status.new :away
233
239
  status.stubs(:from).returns jid
@@ -275,16 +281,17 @@ end
275
281
  describe 'Blather::Client with a Component stream' do
276
282
  before do
277
283
  class MockComponent < Blather::Stream::Component; def initialize(); end; end
284
+ @stream = MockComponent.new('')
285
+ @stream.stubs(:send_data)
278
286
  @client = Blather::Client.new
279
- Blather::Stream::Component.stubs(:start).returns MockComponent.new('')
280
- @client.setup('me.com', 'secret').run
287
+ @client.setup('me.com', 'secret')
281
288
  end
282
289
 
283
290
  it 'calls the ready handler when sent post_init' do
284
291
  ready = mock()
285
292
  ready.expects(:call)
286
293
  @client.register_handler(:ready) { ready.call }
287
- @client.post_init
294
+ @client.post_init @stream
288
295
  end
289
296
  end
290
297
 
@@ -299,7 +306,7 @@ describe 'Blather::Client with a Client stream' do
299
306
 
300
307
  it 'sends a request for the roster when post_init is called' do
301
308
  @stream.expects(:send).with { |stanza| stanza.must_be_kind_of Blather::Stanza::Iq::Roster }
302
- @client.post_init
309
+ @client.post_init @stream, Blather::JID.new('n@d/r')
303
310
  end
304
311
 
305
312
  it 'calls the ready handler after post_init and roster is received' do
@@ -309,13 +316,16 @@ describe 'Blather::Client with a Client stream' do
309
316
  ready = mock()
310
317
  ready.expects(:call)
311
318
  @client.register_handler(:ready) { ready.call }
312
- @client.post_init
319
+ @client.post_init @stream, Blather::JID.new('n@d/r')
313
320
  end
314
321
  end
315
322
 
316
323
  describe 'Blather::Client filters' do
317
324
  before do
318
325
  @client = Blather::Client.new
326
+ @stream = mock()
327
+ @stream.stubs(:send)
328
+ @client.post_init @stream, Blather::JID.new('n@d/r')
319
329
  end
320
330
 
321
331
  it 'raises an error when an invalid filter type is registered' do
@@ -383,7 +393,10 @@ end
383
393
 
384
394
  describe 'Blather::Client guards' do
385
395
  before do
396
+ stream = mock()
397
+ stream.stubs(:send)
386
398
  @client = Blather::Client.new
399
+ @client.post_init stream, Blather::JID.new('n@d/r')
387
400
  @stanza = Blather::Stanza::Iq.new
388
401
  @response = mock()
389
402
  end
@@ -430,6 +443,9 @@ describe 'Blather::Client guards' do
430
443
 
431
444
  @stanza.expects(:body).returns 'keyword not found'
432
445
  @client.receive_data @stanza
446
+
447
+ @stanza.expects(:body).returns nil
448
+ @client.receive_data @stanza
433
449
  end
434
450
 
435
451
  it 'can be a hash with an array' do
@@ -500,6 +516,17 @@ describe 'Blather::Client guards' do
500
516
  @client.receive_data @stanza
501
517
  end
502
518
 
519
+ it 'can be an xpath with namespaces and will send the result to the handler' do
520
+ @stanza = Blather::Stanza.import(parse_stanza('<message><foo xmlns="http://bar.com"></message>').root)
521
+ @response.expects(:call).with do |stanza, xpath|
522
+ xpath.must_be_instance_of Nokogiri::XML::NodeSet
523
+ xpath.wont_be_empty
524
+ stanza.must_equal @stanza
525
+ end
526
+ @client.register_handler(:message, "/message/bar:foo", :bar => 'http://bar.com') { |stanza, xpath| @response.call stanza, xpath }
527
+ @client.receive_data @stanza
528
+ end
529
+
503
530
  it 'raises an error when a bad guard is tried' do
504
531
  lambda { @client.register_handler(:iq, 0) {} }.must_raise RuntimeError
505
532
  end
@@ -274,8 +274,7 @@ describe 'Blather::DSL::PubSub callbacks' do
274
274
  before do
275
275
  @host = 'host.name'
276
276
  @pubsub = Blather::DSL::PubSub.new @host
277
- @client = Blather::Client.new
278
- @client.jid = Blather::JID.new('n@d/r')
277
+ @client = Blather::Client.setup Blather::JID.new('n@d/r'), 'pass'
279
278
  Blather::DSL.stubs(:client).returns @client
280
279
  end
281
280
 
@@ -102,7 +102,7 @@ describe Blather::DSL do
102
102
  it 'provides a disco helper for items' do
103
103
  what, who, where = :items, 'me@me.com', 'my/node'
104
104
  Blather::Stanza::Disco::DiscoItems.stubs(:next_id).returns 0
105
- @client.expects(:temporary_handler).with '0'
105
+ @client.expects(:register_tmp_handler).with '0'
106
106
  expected_stanza = Blather::Stanza::Disco::DiscoItems.new
107
107
  expected_stanza.to = who
108
108
  expected_stanza.node = where
@@ -113,7 +113,7 @@ describe Blather::DSL do
113
113
  it 'provides a disco helper for info' do
114
114
  what, who, where = :info, 'me@me.com', 'my/node'
115
115
  Blather::Stanza::Disco::DiscoInfo.stubs(:next_id).returns 0
116
- @client.expects(:temporary_handler).with '0'
116
+ @client.expects(:register_tmp_handler).with '0'
117
117
  expected_stanza = Blather::Stanza::Disco::DiscoInfo.new
118
118
  expected_stanza.to = who
119
119
  expected_stanza.node = where
@@ -49,6 +49,13 @@ describe Blather::Stanza::Presence::Status do
49
49
  Blather::Stanza::Presence::Status.new.state.must_equal :available
50
50
  end
51
51
 
52
+ it 'returns :available if <show/> is blank' do
53
+ status = Blather::XMPPNode.import(parse_stanza(<<-NODE).root)
54
+ <presence><show/><presence/>
55
+ NODE
56
+ status.state.must_equal :available
57
+ end
58
+
52
59
  it 'returns :unavailable if type is :unavailable' do
53
60
  status = Blather::Stanza::Presence::Status.new
54
61
  status.type = :unavailable
@@ -721,7 +721,7 @@ describe Blather::Stream::Client do
721
721
 
722
722
  when :complete
723
723
  EM.stop
724
- @client.jid.must_equal Blather::JID.new('n@d/server_resource')
724
+ @stream.jid.must_equal Blather::JID.new('n@d/server_resource')
725
725
 
726
726
  else
727
727
  EM.stop
@@ -754,7 +754,7 @@ describe Blather::Stream::Client do
754
754
 
755
755
  when :complete
756
756
  EM.stop
757
- @client.jid.must_equal Blather::JID.new('n@d/r')
757
+ @stream.jid.must_equal Blather::JID.new('n@d/r')
758
758
 
759
759
  else
760
760
  EM.stop
@@ -213,7 +213,7 @@ describe Blather::XMPPNode do
213
213
  n2.element_name.must_equal n.element_name
214
214
  end
215
215
 
216
- it 'provides an inhert mechanism' do
216
+ it 'provides an inherit mechanism' do
217
217
  n = Blather::XMPPNode.new 'foo'
218
218
  n2 = Blather::XMPPNode.new 'foo'
219
219
  n2.content = 'bar'
@@ -222,6 +222,13 @@ describe Blather::XMPPNode do
222
222
  n.inherit(n2)
223
223
  n['foo'].must_equal 'bar'
224
224
  n.content.must_equal 'bar'
225
+ n2.to_s.must_equal n.to_s
226
+ end
227
+
228
+ it 'holds on to namespaces when inheriting content' do
229
+ n = parse_stanza('<message><bar:foo xmlns:bar="http://bar.com"></message>').root
230
+ n2 = Blather::XMPPNode.new('message').inherit n
231
+ n2.to_s.must_equal n.to_s
225
232
  end
226
233
 
227
234
  it 'provides a mechanism to inherit attrs' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blather
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Smick
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-13 00:00:00 -07:00
12
+ date: 2009-07-18 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.3.0
33
+ version: 1.3.2
34
34
  version:
35
35
  description: An XMPP DSL for Ruby written on top of EventMachine and Nokogiri
36
36
  email: sprsquish@gmail.com