blather 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,11 @@
1
1
  # [develop](https://github.com/sprsquish/blather/compare/master...develop)
2
2
 
3
+ # [v0.8.0](https://github.com/sprsquish/blather/compare/v0.7.1...v0.8.0) - [2012-07-09](https://rubygems.org/gems/blather/versions/0.8.0)
4
+ * Feature(jmkeys): DSL methods for joining and sending messages to MUC rooms
5
+ * Feature(jackhong): Inband registration support
6
+ * Bugfix(benlangfeld): Ensure that presence nodes which are both status and subscription may be responded to
7
+ * Bugfix(benlangfeld): A whole bunch of JRuby fixes
8
+
3
9
  # [v0.7.1](https://github.com/sprsquish/blather/compare/v0.7.0...v0.7.1) - [2012-04-29](https://rubygems.org/gems/blather/versions/0.7.1)
4
10
  * Documentation updates
5
11
  * Bugfix(benlangfeld): Relax Nokogiri dependency to allow 1.5
data/README.md CHANGED
@@ -290,7 +290,7 @@ XEP-0100 | None |
290
290
  XEP-0106 | None |
291
291
  XEP-0107 | None |
292
292
  XEP-0108 | None |
293
- XEP-0114 | None |
293
+ XEP-0114 | Full |
294
294
  XEP-0115 | Partial |
295
295
  XEP-0118 | None |
296
296
  XEP-0122 | None |
@@ -34,9 +34,9 @@ Gem::Specification.new do |s|
34
34
  s.extra_rdoc_files = %w{LICENSE README.md}
35
35
 
36
36
  s.add_dependency "eventmachine", [">= 0.12.6"]
37
- s.add_dependency "nokogiri", ["~> 1.4"]
37
+ s.add_dependency "nokogiri", ["~> 1.5.5"]
38
38
  s.add_dependency "niceogiri", ["~> 1.0"]
39
- s.add_dependency "activesupport", [">= 3.0.7"]
39
+ s.add_dependency "activesupport", [">= 2.3.11"]
40
40
  s.add_dependency "girl_friday"
41
41
 
42
42
  s.add_development_dependency "bundler", ["~> 1.0"]
@@ -47,4 +47,5 @@ Gem::Specification.new do |s|
47
47
  s.add_development_dependency "yard", ["~> 0.6.1"]
48
48
  s.add_development_dependency "jruby-openssl", ["~> 0.7.4"] if jruby?
49
49
  s.add_development_dependency "bluecloth" unless jruby? || rbx?
50
+ s.add_development_dependency "countdownlatch"
50
51
  end
@@ -79,6 +79,7 @@
79
79
  blather/stream/features/sasl
80
80
  blather/stream/features/session
81
81
  blather/stream/features/tls
82
+ blather/stream/features/register
82
83
  ].each { |r| require r }
83
84
 
84
85
  module Blather
@@ -206,12 +206,32 @@ module Blather
206
206
  client.write stanza
207
207
  end
208
208
 
209
+ # Helper method to join a MUC room
210
+ #
211
+ # @overload join(room_jid, nickname)
212
+ # @param [Blather::JID, #to_s] room the JID of the room to join
213
+ # @param [#to_s] nickname the nickname to join the room as
214
+ # @overload join(room_jid, nickname)
215
+ # @param [#to_s] room the name of the room to join
216
+ # @param [Blather::JID, #to_s] service the service domain the room is hosted at
217
+ # @param [#to_s] nickname the nickname to join the room as
218
+ def join(room, service, nickname = nil)
219
+ join = Blather::Stanza::Presence::MUC.new
220
+ join.to = if nickname
221
+ "#{room}@#{service}/#{nickname}"
222
+ else
223
+ "#{room}/#{service}"
224
+ end
225
+ client.write join
226
+ end
227
+
209
228
  # Helper method to make sending basic messages easier
210
229
  #
211
230
  # @param [Blather::JID, #to_s] to the JID of the message recipient
212
231
  # @param [#to_s] msg the message to send
213
- def say(to, msg)
214
- client.write Blather::Stanza::Message.new(to, msg)
232
+ # @param [#to_sym] the stanza method to use
233
+ def say(to, msg, using = :chat)
234
+ client.write Blather::Stanza::Message.new(to, msg, using)
215
235
  end
216
236
 
217
237
  # The JID according to the server
@@ -121,9 +121,11 @@ module DSL
121
121
  #
122
122
  # @param [#to_s] node the node to create
123
123
  # @param [#to_s] host the PubSub host (defaults to the initialized host)
124
+ # @param [optional, Blather::Stanza::X] configuration the additional configuration to be set to created node
124
125
  # @yield [Blather::Stanza] stanza the reply stanza
125
- def create(node, host = nil)
126
+ def create(node, host = nil, configuration = nil)
126
127
  stanza = Stanza::PubSub::Create.new(:set, send_to(host), node)
128
+ stanza.configure_node << configuration if configuration
127
129
  request(stanza) { |n| yield n if block_given? }
128
130
  end
129
131
 
@@ -99,7 +99,7 @@ class Stanza
99
99
  decorators << Subscription
100
100
  end
101
101
 
102
- super
102
+ super node, *decorators
103
103
  end
104
104
 
105
105
  # Ensure element_name is "presence" for all subclasses
@@ -77,6 +77,7 @@ class Presence
77
77
  class Status < Presence
78
78
  # @private
79
79
  VALID_STATES = [:away, :chat, :dnd, :xa].freeze
80
+ VALID_TYPES = [:unavailable].freeze
80
81
 
81
82
  include Comparable
82
83
 
@@ -130,17 +131,6 @@ class Presence
130
131
  self.state == :xa
131
132
  end
132
133
 
133
- # Set the type attribute
134
- # Ensures type is nil or :unavailable
135
- #
136
- # @param [<:unavailable, nil>] type the type
137
- def type=(type)
138
- if type && type.to_sym != :unavailable
139
- raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
140
- end
141
- super
142
- end
143
-
144
134
  # Set the state
145
135
  # Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
146
136
  #
@@ -203,8 +193,10 @@ class Presence
203
193
  # @param [Blather::Stanza::Presence::Status] o
204
194
  # @return [true,false]
205
195
  def <=>(o)
206
- unless self.from && o.from && self.from.stripped == o.from.stripped
207
- raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
196
+ if self.from || o.from
197
+ unless self.from.stripped == o.from.stripped
198
+ raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
199
+ end
208
200
  end
209
201
 
210
202
  if (self.type.nil? && o.type.nil?) || (!self.type.nil? && !o.type.nil?)
@@ -31,7 +31,19 @@ class Stream
31
31
  @idx = @idx ? @idx+1 : 0
32
32
  if stanza = @features.children[@idx]
33
33
  if stanza.namespaces['xmlns'] && (klass = self.class.from_namespace(stanza.namespaces['xmlns']))
34
- @feature = klass.new @stream, proc { next! }, @fail
34
+ @feature = klass.new(
35
+ @stream,
36
+ proc {
37
+ if (klass == Blather::Stream::Register && stanza = feature?(:mechanisms))
38
+ @idx = @features.children.index(stanza)
39
+ @feature = Blather::Stream::SASL.new @stream, proc { next! }, @fail
40
+ @feature.receive_data stanza
41
+ else
42
+ next!
43
+ end
44
+ },
45
+ (klass == Blather::Stream::SASL && feature?(:register)) ? proc { next! } : @fail
46
+ )
35
47
  @feature.receive_data stanza
36
48
  else
37
49
  next!
@@ -48,6 +60,10 @@ class Stream
48
60
  def fail!(msg)
49
61
  @fail.call msg
50
62
  end
63
+
64
+ def feature?(feature)
65
+ @features && @features.children.find { |v| v.element_name == feature.to_s }
66
+ end
51
67
  end
52
68
 
53
69
  end #Stream
@@ -0,0 +1,38 @@
1
+ module Blather
2
+ class Stream
3
+ class Register < Features
4
+ REGISTER_NS = "http://jabber.org/features/iq-register".freeze
5
+
6
+ register REGISTER_NS
7
+
8
+ def initialize(stream, succeed, fail)
9
+ super
10
+ @jid = @stream.jid
11
+ @pass = @stream.password
12
+ end
13
+
14
+ def receive_data(stanza)
15
+ error_node = stanza.xpath("//error").first
16
+
17
+ if error_node
18
+ fail!(BlatherError.new(stanza))
19
+ elsif stanza['type'] == 'result' && (stanza.content.empty? || stanza.children.find { |v| v.element_name == "query" })
20
+ succeed!
21
+ else
22
+ @stream.send register_query
23
+ end
24
+ end
25
+
26
+ def register_query
27
+ node = Blather::Stanza::Iq::Query.new(:set)
28
+ query_node = node.xpath('//query').first
29
+ query_node['xmlns'] = 'jabber:iq:register'
30
+ Nokogiri::XML::Builder.with(query_node) do |xml|
31
+ xml.username @jid.node
32
+ xml.password @pass
33
+ end
34
+ node
35
+ end
36
+ end
37
+ end
38
+ end
@@ -48,7 +48,7 @@ class Stream
48
48
  @namespaces[[prefix, uri]] ||= node.add_namespace(prefix, uri) if prefix && !ns_keys.include?(prefix)
49
49
  node.namespace = @namespaces[[prefix, uri]]
50
50
 
51
- if !@receiver.stopped?
51
+ unless @receiver.stopped?
52
52
  @current << node if @current
53
53
  @current = node
54
54
  end
@@ -1,3 +1,3 @@
1
1
  module Blather
2
- VERSION = '0.7.1'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -682,6 +682,6 @@ describe 'Blather::Client::Caps' do
682
682
  http://jabber.org/protocol/disco#items
683
683
  http://jabber.org/protocol/muc
684
684
  }
685
- @caps.c.inspect.should == "<presence>\n <c xmlns=\"http://jabber.org/protocol/caps\" hash=\"sha-1\" node=\"http://code.google.com/p/exodus\" ver=\"QgayPKawpkPSDYmwT/WM94uAlu0=\"/>\n</presence>"
685
+ Nokogiri::XML(@caps.c.to_xml).to_s.should == Nokogiri::XML("<presence><c xmlns=\"http://jabber.org/protocol/caps\" hash=\"sha-1\" node=\"http://code.google.com/p/exodus\" ver=\"QgayPKawpkPSDYmwT/WM94uAlu0=\"/></presence>").to_s
686
686
  end
687
687
  end
@@ -268,6 +268,26 @@ describe Blather::DSL::PubSub do
268
268
  @pubsub.create '/path/to/node'
269
269
  end
270
270
 
271
+ it 'can create a node with configuration' do
272
+ pubsub_configure = Blather::Stanza::X.new({
273
+ :type => :submit,
274
+ :fields => [
275
+ { :var => "FORM_TYPE", :type => 'hidden', :value => "http://jabber.org/protocol/pubsub#node_config" },
276
+ { :var => "pubsub#persist_items", :value => "0" },
277
+ { :var => "pubsub#max_items", :value => "0" },
278
+ { :var => "pubsub#notify_retract", :value => "0" },
279
+ { :var => "pubsub#publish_model", :value => "open" }]
280
+ })
281
+ @client.expects(:write_with_handler).with do |n|
282
+ n.should be_instance_of Blather::Stanza::PubSub::Create
283
+ n.find("/iq[@type='set']/ns:pubsub/ns:create[@node='/path/to/node']", :ns => Blather::Stanza::PubSub.registered_ns).should_not be_empty
284
+ n.to.should == Blather::JID.new(@host)
285
+ n.type.should == :set
286
+ n.configure_node.should == pubsub_configure
287
+ end
288
+ @pubsub.create '/path/to/node', nil, pubsub_configure
289
+ end
290
+
271
291
  it 'can delete a node' do
272
292
  @client.expects(:write_with_handler).with do |n|
273
293
  n.should be_instance_of Blather::Stanza::PubSubOwner::Delete
@@ -118,11 +118,31 @@ describe Blather::DSL do
118
118
  @dsl.write_to_stream stanza
119
119
  end
120
120
 
121
+ describe "#join" do
122
+ context "providing room and service as separate args" do
123
+ it "should join to a muc room with a specified nick" do
124
+ presence = Blather::Stanza::Presence::MUC.new
125
+ presence.to = "rabbit_hole@wonderland.lit/alice"
126
+ @client.expects(:write).with presence
127
+ @dsl.join 'rabbit_hole', 'wonderland.lit', 'alice'
128
+ end
129
+ end
130
+
131
+ context "providing a room JID" do
132
+ it "should join to a muc room with a specified nick" do
133
+ presence = Blather::Stanza::Presence::MUC.new
134
+ presence.to = "rabbit_hole@wonderland.lit/alice"
135
+ @client.expects(:write).with presence
136
+ @dsl.join 'rabbit_hole@wonderland.lit', 'alice'
137
+ end
138
+ end
139
+ end
140
+
121
141
  it 'provides a "say" helper' do
122
- to, msg = 'me@me.com', 'hello!'
142
+ to, msg, type = 'me@me.com', 'hello!', :groupchat
123
143
  Blather::Stanza::Message.stubs(:next_id).returns 0
124
- @client.expects(:write).with Blather::Stanza::Message.new(to, msg)
125
- @dsl.say to, msg
144
+ @client.expects(:write).with Blather::Stanza::Message.new(to, msg, type)
145
+ @dsl.say to, msg, type
126
146
  end
127
147
 
128
148
  it 'provides a JID accessor' do
@@ -27,11 +27,9 @@ describe Blather::Stanza::Presence::Subscription do
27
27
  end
28
28
 
29
29
  it 'generates an approval using #approve!' do
30
- jid = Blather::JID.new 'a@b'
31
- sub = Blather::Stanza::Presence::Subscription.new
32
- sub.from = jid
30
+ sub = Blather::Stanza.import Nokogiri::XML('<presence from="a@b" type="subscribe"><status/></presence>').root
33
31
  sub.approve!
34
- sub.to.should == jid
32
+ sub.to.should == 'a@b'
35
33
  sub.type.should == :subscribed
36
34
  end
37
35
 
@@ -1033,4 +1033,58 @@ describe Blather::Stream::Client do
1033
1033
  comp.expects(:send_data).with { |s| s.should_not match(/\n/); true }
1034
1034
  comp.send msg
1035
1035
  end
1036
+
1037
+ it 'tries to register if initial authentication failed but in-band registration enabled' do
1038
+ state = nil
1039
+ mocked_server(4) do |val, server|
1040
+ case state
1041
+ when nil
1042
+ state = :sasl_failed
1043
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
1044
+ server.send_data "<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><register xmlns='http://jabber.org/features/iq-register'/></stream:features>"
1045
+ server.send_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized /></failure>"
1046
+ val.should match(/stream:stream/)
1047
+ when :sasl_failed
1048
+ state = :registered
1049
+ server.send_data "<iq type='result'/>"
1050
+ val.should match(/jabber:iq:register/)
1051
+ when :registered
1052
+ state = :authenticated
1053
+ server.send_data "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />"
1054
+ val.should match(/mechanism="PLAIN"/)
1055
+ when :authenticated
1056
+ EM.stop
1057
+ val.should match(/stream:stream/)
1058
+ else
1059
+ EM.stop
1060
+ false
1061
+ end
1062
+ end
1063
+ end
1064
+
1065
+ it 'fails when in-band registration failed' do
1066
+ state = nil
1067
+ @client = mock()
1068
+ @client.expects(:receive_data).with { |n| n.should be_instance_of Blather::BlatherError }
1069
+ mocked_server(3) do |val, server|
1070
+ case state
1071
+ when nil
1072
+ state = :sasl_failed
1073
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
1074
+ server.send_data "<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><register xmlns='http://jabber.org/features/iq-register'/></stream:features>"
1075
+ server.send_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized /></failure>"
1076
+ val.should match(/stream:stream/)
1077
+ when :sasl_failed
1078
+ state = :registration_failed
1079
+ server.send_data "<iq type='error'><query /><error code='409' type='cancel'><conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"
1080
+ val.should match(/jabber:iq:register/)
1081
+ when :registration_failed
1082
+ EM.stop
1083
+ val.should match(/\/stream:stream/)
1084
+ else
1085
+ EM.stop
1086
+ false
1087
+ end
1088
+ end
1089
+ end
1036
1090
  end
@@ -1,32 +1,37 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Blather::Stream::Parser do
4
- before do
5
- @client = Class.new do
4
+ let :client do
5
+ Class.new do
6
6
  attr_reader :data
7
+ attr_accessor :latch
7
8
  def stopped?; false; end
8
- def receive(data)
9
+ def receive(node)
9
10
  @data ||= []
10
- @data << data
11
+ @data << node
12
+ latch.countdown!
11
13
  end
12
14
  end.new
13
- @parser = Blather::Stream::Parser.new @client
14
15
  end
15
16
 
16
- after { @client = @parser = nil}
17
+ subject { Blather::Stream::Parser.new client }
18
+
19
+ def process(*data)
20
+ client.latch = CountDownLatch.new 1
21
+ data.each { |d| subject.receive_data d }
22
+ client.latch.wait(2).should be_true
23
+ end
17
24
 
18
25
  def check_parse(data)
19
- @parser.receive_data data
20
- @client.data.size.should == 1
21
- @client.data[0].to_s.gsub(/\n\s*/,'').should == data
26
+ process data
27
+ client.data.size.should == 1
28
+ client.data[0].to_s.gsub(/\n\s*/,'').should == data
22
29
  end
23
30
 
24
31
  it 'handles fragmented parsing' do
25
- @parser.receive_data '<foo>'
26
- @parser.receive_data '<bar/>'
27
- @parser.receive_data '</foo>'
28
- @client.data.size.should == 1
29
- @client.data[0].to_s.gsub(/\n\s*/,'').should == '<foo><bar/></foo>'
32
+ process '<foo>', '<bar/>', '</foo>'
33
+ client.data.size.should == 1
34
+ client.data[0].to_s.gsub(/\n\s*/,'').should == '<foo><bar/></foo>'
30
35
  end
31
36
 
32
37
  it 'handles a basic example' do
@@ -85,71 +90,63 @@ describe Blather::Stream::Parser do
85
90
  '<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Some special application diagnostic information...</text>',
86
91
  '<special-application-condition xmlns="special:application-ns"/>',
87
92
  "</error>",
88
- "</message>",
93
+ "</message>"
89
94
  ]
90
- data.each { |d| @parser.receive_data d }
91
- @client.data.size.should == 1
92
- @client.data[0].to_s.split("\n").map{|n|n.strip}.should == data
93
- @client.data[0].xpath('//*[namespace-uri()="urn:ietf:params:xml:ns:xmpp-stanzas"]').size.should == 2
95
+ process *data
96
+ client.data.size.should == 1
97
+ Nokogiri::XML(client.data[0].to_s.gsub(/\n\s*/, '')).to_s.should == Nokogiri::XML(data.join).to_s
98
+ client.data[0].xpath('//*[namespace-uri()="urn:ietf:params:xml:ns:xmpp-stanzas"]').size.should == 2
94
99
  end
95
100
 
96
101
  it 'handles not absolute namespaces' do
97
102
  lambda do
98
- @parser.receive_data '<iq type="result" id="blather0007" to="n@d/r"><vCard xmlns="vcard-temp"/></iq>'
103
+ process '<iq type="result" id="blather0007" to="n@d/r"><vCard xmlns="vcard-temp"/></iq>'
99
104
  end.should_not raise_error
100
105
  end
101
106
 
102
107
  it 'responds with stream:stream as a separate response' do
103
- data = [
104
- '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="example.com" version="1.0">',
108
+ process '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="example.com" version="1.0">',
105
109
  '<foo/>'
106
- ]
107
- data.each { |d| @parser.receive_data d }
108
- @client.data.size.should == 2
109
- @client.data[0].document.xpath('/stream:stream[@to="example.com" and @version="1.0"]', 'xmlns' => 'jabber:client', 'stream' => 'http://etherx.jabber.org/streams').size.should == 1
110
- @client.data[1].to_s.should == '<foo/>'
110
+ client.data.size.should == 2
111
+ client.data[0].document.xpath('/stream:stream[@to="example.com" and @version="1.0"]', 'xmlns' => 'jabber:client', 'stream' => 'http://etherx.jabber.org/streams').size.should == 1
112
+ client.data[1].to_s.should == '<foo/>'
111
113
  end
112
114
 
113
115
  it 'response with stream:end when receiving </stream:stream>' do
114
- @parser.receive_data '<stream:stream xmlns:stream="http://etherx.jabber.org/streams"/>'
115
- @client.data.size.should == 2
116
- @client.data[1].to_s.should == '<stream:end xmlns:stream="http://etherx.jabber.org/streams"/>'
116
+ process '<stream:stream xmlns:stream="http://etherx.jabber.org/streams"/>'
117
+ client.data.size.should == 2
118
+ client.data[1].to_s.should == '<stream:end xmlns:stream="http://etherx.jabber.org/streams"/>'
117
119
  end
118
120
 
119
121
  it 'raises ParseError when an error is sent' do
120
- lambda { @parser.receive_data "<stream:stream>" }.should raise_error(Blather::ParseError)
122
+ lambda { process "<stream:stream>" }.should raise_error(Blather::ParseError)
121
123
  end
122
124
 
123
125
  it 'handles stream stanzas without an issue' do
124
- data = [
125
- '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="example.com" version="1.0">',
126
+ process '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="example.com" version="1.0">',
126
127
  '<stream:features/>'
127
- ]
128
- data.each { |d| @parser.receive_data d }
129
- @client.data.size.should == 2
130
- @client.data[0].document.xpath('/stream:stream[@to="example.com" and @version="1.0"]', 'xmlns' => 'jabber:client', 'stream' => 'http://etherx.jabber.org/streams').size.should == 1
131
- @client.data[1].to_s.should == '<stream:features xmlns:stream="http://etherx.jabber.org/streams"/>'
128
+ client.data.size.should == 2
129
+ client.data[0].document.xpath('/stream:stream[@to="example.com" and @version="1.0"]', 'xmlns' => 'jabber:client', 'stream' => 'http://etherx.jabber.org/streams').size.should == 1
130
+ client.data[1].to_s.should == '<stream:features xmlns:stream="http://etherx.jabber.org/streams"/>'
132
131
  end
133
132
 
134
133
  it 'ignores the client namespace on stanzas' do
135
- [ "<message type='chat' to='n@d' from='n@d/r' id='id1' xmlns='jabber:client'>",
134
+ process "<message type='chat' to='n@d' from='n@d/r' id='id1' xmlns='jabber:client'>",
136
135
  "<body>exit</body>",
137
136
  "<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>exit</body></html>",
138
137
  "</message>"
139
- ].each { |d| @parser.receive_data d }
140
- @client.data.size.should == 1
141
- @client.data[0].document.xpath('/message/body[.="exit"]').should_not be_empty
142
- @client.data[0].document.xpath('/message/im:html/xhtml:body[.="exit"]', 'im' => 'http://jabber.org/protocol/xhtml-im', 'xhtml' => 'http://www.w3.org/1999/xhtml').should_not be_empty
138
+ client.data.size.should == 1
139
+ client.data[0].document.xpath('/message/body[.="exit"]').should_not be_empty
140
+ client.data[0].document.xpath('/message/im:html/xhtml:body[.="exit"]', 'im' => 'http://jabber.org/protocol/xhtml-im', 'xhtml' => 'http://www.w3.org/1999/xhtml').should_not be_empty
143
141
  end
144
142
 
145
143
  it 'ignores the component namespace on stanzas' do
146
- [ "<message type='chat' to='n@d' from='n@d/r' id='id1' xmlns='jabber:component:accept'>",
144
+ process "<message type='chat' to='n@d' from='n@d/r' id='id1' xmlns='jabber:component:accept'>",
147
145
  "<body>exit</body>",
148
146
  "<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>exit</body></html>",
149
147
  "</message>"
150
- ].each { |d| @parser.receive_data d }
151
- @client.data.size.should == 1
152
- @client.data[0].document.xpath('/message/body[.="exit"]').should_not be_empty
153
- @client.data[0].document.xpath('/message/im:html/xhtml:body[.="exit"]', 'im' => 'http://jabber.org/protocol/xhtml-im', 'xhtml' => 'http://www.w3.org/1999/xhtml').should_not be_empty
148
+ client.data.size.should == 1
149
+ client.data[0].document.xpath('/message/body[.="exit"]').should_not be_empty
150
+ client.data[0].document.xpath('/message/im:html/xhtml:body[.="exit"]', 'im' => 'http://jabber.org/protocol/xhtml-im', 'xhtml' => 'http://www.w3.org/1999/xhtml').should_not be_empty
154
151
  end
155
152
  end
@@ -1,5 +1,6 @@
1
1
  require 'blather'
2
2
  require 'mocha'
3
+ require 'countdownlatch'
3
4
 
4
5
  Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
5
6
 
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.7.1
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-29 00:00:00.000000000 Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '1.4'
37
+ version: 1.5.5
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: '1.4'
45
+ version: 1.5.5
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: niceogiri
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: 3.0.7
69
+ version: 2.3.11
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +74,7 @@ dependencies:
74
74
  requirements:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: 3.0.7
77
+ version: 2.3.11
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: girl_friday
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -203,6 +203,22 @@ dependencies:
203
203
  - - ! '>='
204
204
  - !ruby/object:Gem::Version
205
205
  version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: countdownlatch
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
206
222
  description: An XMPP DSL for Ruby written on top of EventMachine and Nokogiri
207
223
  email: sprsquish@gmail.com
208
224
  executables: []
@@ -295,6 +311,7 @@ files:
295
311
  - lib/blather/stream/client.rb
296
312
  - lib/blather/stream/component.rb
297
313
  - lib/blather/stream/features.rb
314
+ - lib/blather/stream/features/register.rb
298
315
  - lib/blather/stream/features/resource.rb
299
316
  - lib/blather/stream/features/sasl.rb
300
317
  - lib/blather/stream/features/session.rb
@@ -374,7 +391,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
374
391
  version: '0'
375
392
  segments:
376
393
  - 0
377
- hash: 4196042577194384774
394
+ hash: -4548531025459259087
378
395
  required_rubygems_version: !ruby/object:Gem::Requirement
379
396
  none: false
380
397
  requirements:
@@ -383,10 +400,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
383
400
  version: '0'
384
401
  segments:
385
402
  - 0
386
- hash: 4196042577194384774
403
+ hash: -4548531025459259087
387
404
  requirements: []
388
405
  rubyforge_project:
389
- rubygems_version: 1.8.21
406
+ rubygems_version: 1.8.24
390
407
  signing_key:
391
408
  specification_version: 3
392
409
  summary: Simpler XMPP built for speed