blather 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ v0.2.1 Upgrade to libxml 0.9.7
2
+
1
3
  v0.2 Overhaul the DSL to look more like Sinatra
2
4
 
3
5
  v0.1 Initial release (birth!)
data/Manifest CHANGED
@@ -3,6 +3,8 @@ examples/drb_client.rb
3
3
  examples/echo.rb
4
4
  lib/autotest/discover.rb
5
5
  lib/autotest/spec.rb
6
+ lib/blather/core_ext/active_support.rb
7
+ lib/blather/core_ext/libxml.rb
6
8
  lib/blather/errors.rb
7
9
  lib/blather/jid.rb
8
10
  lib/blather/roster.rb
@@ -22,7 +24,6 @@ lib/blather/stream/sasl.rb
22
24
  lib/blather/stream/session.rb
23
25
  lib/blather/stream/tls.rb
24
26
  lib/blather/stream.rb
25
- lib/blather/sugar.rb
26
27
  lib/blather/xmpp_node.rb
27
28
  lib/blather.rb
28
29
  LICENSE
data/README.rdoc CHANGED
@@ -46,7 +46,13 @@ This will auto-accept any subscription requests and echo back any chat messages.
46
46
  write(m.reply) if m.chat? && m.body
47
47
  end
48
48
 
49
-
49
+ = TODO
50
+
51
+ * Cleanup API
52
+ * Better Documentation
53
+ * Service Discovery (XEP-0030: http://xmpp.org/extensions/xep-0030.html)
54
+ * PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
55
+ * ?? (suggestions)
50
56
 
51
57
  = License
52
58
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ Echoe.new('blather') do |p|
9
9
  p.project = 'squishtech'
10
10
  p.summary = 'An evented XMPP library written on EventMachine and libxml-ruby'
11
11
 
12
- p.runtime_dependencies = ['eventmachine', 'libxml-ruby >=0.9.2']
12
+ p.runtime_dependencies = ['eventmachine', 'libxml-ruby >=0.9.7']
13
13
  p.rdoc_options += %w[-S -T hanna --main README.rdoc --exclude autotest]
14
14
 
15
15
  p.test_pattern = 'spec/**/*_spec.rb'
data/blather.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{blather}
5
- s.version = "0.2"
5
+ s.version = "0.2.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jeff Smick"]
9
- s.date = %q{2008-12-19}
9
+ s.date = %q{2008-12-21}
10
10
  s.description = %q{An evented XMPP library written on EventMachine and libxml-ruby}
11
11
  s.email = %q{sprsquish@gmail.com}
12
- s.extra_rdoc_files = ["CHANGELOG", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/errors.rb", "lib/blather/jid.rb", "lib/blather/roster.rb", "lib/blather/roster_item.rb", "lib/blather/stanza/error.rb", "lib/blather/stanza/iq/query.rb", "lib/blather/stanza/iq/roster.rb", "lib/blather/stanza/iq.rb", "lib/blather/stanza/message.rb", "lib/blather/stanza/presence/status.rb", "lib/blather/stanza/presence/subscription.rb", "lib/blather/stanza/presence.rb", "lib/blather/stanza.rb", "lib/blather/stream/parser.rb", "lib/blather/stream/resource.rb", "lib/blather/stream/sasl.rb", "lib/blather/stream/session.rb", "lib/blather/stream/tls.rb", "lib/blather/stream.rb", "lib/blather/sugar.rb", "lib/blather/xmpp_node.rb", "lib/blather.rb", "LICENSE", "README.rdoc"]
13
- s.files = ["CHANGELOG", "examples/drb_client.rb", "examples/echo.rb", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/errors.rb", "lib/blather/jid.rb", "lib/blather/roster.rb", "lib/blather/roster_item.rb", "lib/blather/stanza/error.rb", "lib/blather/stanza/iq/query.rb", "lib/blather/stanza/iq/roster.rb", "lib/blather/stanza/iq.rb", "lib/blather/stanza/message.rb", "lib/blather/stanza/presence/status.rb", "lib/blather/stanza/presence/subscription.rb", "lib/blather/stanza/presence.rb", "lib/blather/stanza.rb", "lib/blather/stream/parser.rb", "lib/blather/stream/resource.rb", "lib/blather/stream/sasl.rb", "lib/blather/stream/session.rb", "lib/blather/stream/tls.rb", "lib/blather/stream.rb", "lib/blather/sugar.rb", "lib/blather/xmpp_node.rb", "lib/blather.rb", "LICENSE", "Manifest", "Rakefile", "README.rdoc", "spec/blather/jid_spec.rb", "spec/blather/roster_item_spec.rb", "spec/blather/roster_spec.rb", "spec/blather/stanza/iq/query_spec.rb", "spec/blather/stanza/iq/roster_spec.rb", "spec/blather/stanza/iq_spec.rb", "spec/blather/stanza/message_spec.rb", "spec/blather/stanza/presence/status_spec.rb", "spec/blather/stanza/presence/subscription_spec.rb", "spec/blather/stanza/presence_spec.rb", "spec/blather/stanza_spec.rb", "spec/blather/stream_spec.rb", "spec/blather/xmpp_node_spec.rb", "spec/build_safe.rb", "spec/spec_helper.rb", "blather.gemspec"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/core_ext/active_support.rb", "lib/blather/core_ext/libxml.rb", "lib/blather/errors.rb", "lib/blather/jid.rb", "lib/blather/roster.rb", "lib/blather/roster_item.rb", "lib/blather/stanza/error.rb", "lib/blather/stanza/iq/query.rb", "lib/blather/stanza/iq/roster.rb", "lib/blather/stanza/iq.rb", "lib/blather/stanza/message.rb", "lib/blather/stanza/presence/status.rb", "lib/blather/stanza/presence/subscription.rb", "lib/blather/stanza/presence.rb", "lib/blather/stanza.rb", "lib/blather/stream/parser.rb", "lib/blather/stream/resource.rb", "lib/blather/stream/sasl.rb", "lib/blather/stream/session.rb", "lib/blather/stream/tls.rb", "lib/blather/stream.rb", "lib/blather/xmpp_node.rb", "lib/blather.rb", "LICENSE", "README.rdoc"]
13
+ s.files = ["CHANGELOG", "examples/drb_client.rb", "examples/echo.rb", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/core_ext/active_support.rb", "lib/blather/core_ext/libxml.rb", "lib/blather/errors.rb", "lib/blather/jid.rb", "lib/blather/roster.rb", "lib/blather/roster_item.rb", "lib/blather/stanza/error.rb", "lib/blather/stanza/iq/query.rb", "lib/blather/stanza/iq/roster.rb", "lib/blather/stanza/iq.rb", "lib/blather/stanza/message.rb", "lib/blather/stanza/presence/status.rb", "lib/blather/stanza/presence/subscription.rb", "lib/blather/stanza/presence.rb", "lib/blather/stanza.rb", "lib/blather/stream/parser.rb", "lib/blather/stream/resource.rb", "lib/blather/stream/sasl.rb", "lib/blather/stream/session.rb", "lib/blather/stream/tls.rb", "lib/blather/stream.rb", "lib/blather/xmpp_node.rb", "lib/blather.rb", "LICENSE", "Manifest", "Rakefile", "README.rdoc", "spec/blather/jid_spec.rb", "spec/blather/roster_item_spec.rb", "spec/blather/roster_spec.rb", "spec/blather/stanza/iq/query_spec.rb", "spec/blather/stanza/iq/roster_spec.rb", "spec/blather/stanza/iq_spec.rb", "spec/blather/stanza/message_spec.rb", "spec/blather/stanza/presence/status_spec.rb", "spec/blather/stanza/presence/subscription_spec.rb", "spec/blather/stanza/presence_spec.rb", "spec/blather/stanza_spec.rb", "spec/blather/stream_spec.rb", "spec/blather/xmpp_node_spec.rb", "spec/build_safe.rb", "spec/spec_helper.rb", "blather.gemspec"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://github.com/sprsquish/blather/tree/master}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blather", "--main", "README.rdoc", "-S", "-T", "hanna", "--main", "README.rdoc", "--exclude", "autotest"]
@@ -26,16 +26,16 @@ Gem::Specification.new do |s|
26
26
 
27
27
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
28
  s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
29
- s.add_runtime_dependency(%q<libxml-ruby>, [">= 0.9.2"])
29
+ s.add_runtime_dependency(%q<libxml-ruby>, [">= 0.9.7"])
30
30
  s.add_development_dependency(%q<echoe>, [">= 0"])
31
31
  else
32
32
  s.add_dependency(%q<eventmachine>, [">= 0"])
33
- s.add_dependency(%q<libxml-ruby>, [">= 0.9.2"])
33
+ s.add_dependency(%q<libxml-ruby>, [">= 0.9.7"])
34
34
  s.add_dependency(%q<echoe>, [">= 0"])
35
35
  end
36
36
  else
37
37
  s.add_dependency(%q<eventmachine>, [">= 0"])
38
- s.add_dependency(%q<libxml-ruby>, [">= 0.9.2"])
38
+ s.add_dependency(%q<libxml-ruby>, [">= 0.9.7"])
39
39
  s.add_dependency(%q<echoe>, [">= 0"])
40
40
  end
41
41
  end
data/lib/blather.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
+ # Require the necessary files
3
4
  %w[
4
5
  rubygems
5
6
  xml/libxml
@@ -7,11 +8,13 @@ $:.unshift File.dirname(__FILE__)
7
8
  digest/md5
8
9
  logger
9
10
 
11
+ blather/core_ext/active_support
12
+ blather/core_ext/libxml
13
+
10
14
  blather/errors
11
15
  blather/jid
12
16
  blather/roster
13
17
  blather/roster_item
14
- blather/sugar
15
18
  blather/xmpp_node
16
19
 
17
20
  blather/stanza
@@ -36,6 +39,8 @@ XML.indent_tree_output = false
36
39
 
37
40
  module Blather
38
41
  LOG = Logger.new(STDOUT)
42
+ Stream::Parser.debug = true
43
+ # LOG.level = Logger::INFO
39
44
 
40
45
  class Client
41
46
  attr_accessor :jid,
@@ -1,22 +1,9 @@
1
- module LibXML # :nodoc:
2
- module XML # :nodoc:
1
+ # Thanks to Rails ActiveSupport for everything in this file
3
2
 
4
- class Node
5
- alias_method :element_name, :name
6
- end
7
-
8
- class Attributes
9
- # Helper method for removing attributes
10
- def remove(name)
11
- name = name.to_s
12
- self.each { |a| a.remove! or break if a.name == name }
13
- end
14
- end #Attributes
15
-
16
- end #XML
17
- end #LibXML
18
-
19
- ## Thanks to ActiveSupport for everything below this line
3
+ # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
4
+ # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
5
+ # to, for example, an array without those additions being shared with either their parent, siblings, or
6
+ # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
20
7
  class Class # :nodoc:
21
8
  def class_inheritable_reader(*syms)
22
9
  syms.each do |sym|
@@ -131,18 +118,35 @@ end #Class
131
118
 
132
119
  class Object # :nodoc:
133
120
  def duplicable?; true; end
121
+ def blank?; respond_to?(:empty?) ? empty? : !self; end
122
+ def present?; !blank?; end
123
+ end
124
+
125
+ class Array #:nodoc:
126
+ alias_method :blank?, :empty?
127
+ end
128
+
129
+ class Hash #:nodoc:
130
+ alias_method :blank?, :empty?
131
+ end
132
+
133
+ class String #:nodoc:
134
+ def blank?; self !~ /\S/; end
134
135
  end
135
136
 
136
137
  class NilClass #:nodoc:
137
138
  def duplicable?; false; end
139
+ def blank?; true; end
138
140
  end
139
141
 
140
142
  class FalseClass #:nodoc:
141
143
  def duplicable?; false; end
144
+ def blank?; true; end
142
145
  end
143
146
 
144
147
  class TrueClass #:nodoc:
145
148
  def duplicable?; false; end
149
+ def blank?; false; end
146
150
  end
147
151
 
148
152
  class Symbol #:nodoc:
@@ -151,4 +155,5 @@ end
151
155
 
152
156
  class Numeric #:nodoc:
153
157
  def duplicable?; false; end
158
+ def blank?; false; end
154
159
  end
@@ -0,0 +1,22 @@
1
+ module LibXML # :nodoc:
2
+ module XML # :nodoc:
3
+
4
+ class Node
5
+ alias_method :element_name, :name
6
+ end
7
+
8
+ class Attributes
9
+ # Helper method for removing attributes
10
+ def remove(name)
11
+ attribute = get_attribute(name.to_s)
12
+ attribute.remove! if attribute
13
+ end
14
+
15
+ alias_method :old_hash_set, :[]=
16
+ def []=(name, val)
17
+ val.nil? ? remove(name.to_s) : old_hash_set(name.to_s, val.to_s)
18
+ end
19
+ end #Attributes
20
+
21
+ end #XML
22
+ end #LibXML
@@ -2,6 +2,9 @@ module Blather
2
2
  # Main error class
3
3
  class BlatherError < StandardError; end
4
4
 
5
+ #Parse Errors
6
+ class ParseError < BlatherError; end
7
+
5
8
  # Stream errors
6
9
  class StreamError < BlatherError
7
10
  attr_accessor :type, :text
@@ -2,6 +2,8 @@ module Blather
2
2
  ##
3
3
  # Base XMPP Stanza
4
4
  class Stanza < XMPPNode
5
+ @@last_id = 0
6
+
5
7
  class_inheritable_array :handler_heirarchy
6
8
 
7
9
  ##
@@ -22,7 +24,6 @@ module Blather
22
24
  ##
23
25
  # Helper method that creates a unique ID for stanzas
24
26
  def self.next_id
25
- @@last_id ||= 0
26
27
  @@last_id += 1
27
28
  'blather%04x' % @@last_id
28
29
  end
@@ -35,15 +36,17 @@ module Blather
35
36
  end
36
37
 
37
38
  ##
38
- # Creates a new Stanza with the name given
39
- # then attaches an ID and document (to enable searching)
40
- def self.new(elem_name = nil)
41
- elem = super
42
- elem.id = next_id
43
- XML::Document.new.root = elem
44
- elem
39
+ # Automatically set the stanza's ID
40
+ # and attach it to a document so XPath searching works
41
+ def initialize(name = nil)
42
+ super
43
+ XML::Document.new.root = self
44
+ self.name = name.to_s if name
45
+ self.id = self.class.next_id
45
46
  end
46
47
 
48
+ ##
49
+ # Helper method to ask the object if it's an error
47
50
  def error?
48
51
  self.type == :error
49
52
  end
@@ -63,45 +66,41 @@ module Blather
63
66
  end
64
67
 
65
68
  def id=(id)
66
- attributes.remove :id
67
- self['id'] = id if id
69
+ attributes['id'] = id
68
70
  end
69
71
 
70
72
  def id
71
- self['id']
73
+ attributes['id']
72
74
  end
73
75
 
74
76
  def to=(to)
75
- attributes.remove :to
76
- self['to'] = to.to_s if to
77
+ attributes['to'] = to
77
78
  end
78
79
 
79
80
  ##
80
81
  # returns:: JID created from the "to" value of the stanza
81
82
  def to
82
- JID.new(self['to']) if self['to']
83
+ JID.new(attributes['to']) if attributes['to']
83
84
  end
84
85
 
85
86
  def from=(from)
86
- attributes.remove :from
87
- self['from'] = from.to_s if from
87
+ attributes['from'] = from
88
88
  end
89
89
 
90
90
  ##
91
91
  # returns:: JID created from the "from" value of the stanza
92
92
  def from
93
- JID.new(self['from']) if self['from']
93
+ JID.new(attributes['from']) if attributes['from']
94
94
  end
95
95
 
96
96
  def type=(type)
97
- attributes.remove :type
98
- self['type'] = type.to_s
97
+ attributes['type'] = type
99
98
  end
100
99
 
101
100
  ##
102
101
  # returns:: a symbol of the type
103
102
  def type
104
- self['type'].to_sym unless self['type'].nil? || self['type'].empty?
103
+ attributes['type'].to_sym unless attributes['type'].blank?
105
104
  end
106
105
 
107
106
  end
@@ -13,13 +13,12 @@ class Stanza
13
13
  (klass || self).new(node['type']).inherit(node)
14
14
  end
15
15
 
16
- def self.new(type = nil, to = nil, id = nil)
17
- elem = super :iq
18
- elem.xmlns = nil
19
- elem.type = type || :get
20
- elem.to = to
21
- elem.id = id if id
22
- elem
16
+ def initialize(type = nil, to = nil, id = nil)
17
+ super :iq
18
+ self.xmlns = nil
19
+ self.type = type || :get
20
+ self.to = to
21
+ self.id = id if id
23
22
  end
24
23
  end
25
24
 
@@ -7,10 +7,9 @@ class Iq
7
7
 
8
8
  ##
9
9
  # Ensure the namespace is set to the query node
10
- def self.new(type = nil)
11
- elem = super
12
- elem.query.xmlns = self.xmlns
13
- elem
10
+ def initialize(type = nil)
11
+ super
12
+ query.xmlns = self.class.xmlns
14
13
  end
15
14
 
16
15
  ##
@@ -5,10 +5,9 @@ class Iq
5
5
  class Roster < Query
6
6
  register :roster, nil, 'jabber:iq:roster'
7
7
 
8
- def self.new(type = nil, item = nil)
9
- elem = super(type)
10
- elem.query << item if item
11
- elem
8
+ def initialize(type = nil, item = nil)
9
+ super(type)
10
+ query << item if item
12
11
  end
13
12
 
14
13
  def inherit(node)
@@ -25,53 +24,48 @@ class Iq
25
24
  end
26
25
 
27
26
  class RosterItem < XMPPNode
28
- def self.new(jid = nil, name = nil, subscription = nil, ask = nil)
29
- elem = super('item')
27
+ def initialize(jid = nil, name = nil, subscription = nil, ask = nil)
28
+ super('item')
30
29
  if jid.is_a?(XML::Node)
31
- elem.inherit jid
30
+ self.inherit jid
32
31
  else
33
- elem.jid = jid
34
- elem.name = name
35
- elem.subscription = subscription
36
- elem.ask = ask
32
+ self.jid = jid
33
+ self.name = name
34
+ self.subscription = subscription
35
+ self.ask = ask
37
36
  end
38
- elem
39
37
  end
40
38
 
41
39
  def jid
42
- (j = self['jid']) ? JID.new(j) : nil
40
+ (j = attributes['jid']) ? JID.new(j) : nil
43
41
  end
44
42
 
45
43
  def jid=(jid)
46
- attributes.remove :jid
47
- self['jid'] = jid.to_s if jid
44
+ attributes['jid'] = jid
48
45
  end
49
46
 
50
47
  def name
51
- self['name']
48
+ attributes['name']
52
49
  end
53
50
 
54
51
  def name=(name)
55
- attributes.remove :name
56
- self['name'] = name if name
52
+ attributes['name'] = name
57
53
  end
58
54
 
59
55
  def subscription
60
- self['subscription'].to_sym if self['subscription']
56
+ attributes['subscription'].to_sym if attributes['subscription']
61
57
  end
62
58
 
63
59
  def subscription=(subscription)
64
- attributes.remove :subscription
65
- self['subscription'] = subscription.to_s if subscription
60
+ attributes['subscription'] = subscription
66
61
  end
67
62
 
68
63
  def ask
69
- self['ask'].to_sym if self['ask']
64
+ attributes['ask'].to_sym if attributes['ask']
70
65
  end
71
66
 
72
67
  def ask=(ask)
73
- attributes.remove :ask
74
- self['ask'] = ask if ask
68
+ attributes['ask'] = ask
75
69
  end
76
70
 
77
71
  def groups
@@ -82,7 +76,7 @@ class Iq
82
76
  find('group').each { |g| g.remove! }
83
77
  @groups = nil
84
78
 
85
- grps.uniq.each { |g| add_node XML::Node.new('group', g.to_s) } if grps
79
+ grps.uniq.each { |g| add_node XMPPNode.new('group', g.to_s) } if grps
86
80
  end
87
81
 
88
82
  def to_stanza
@@ -8,12 +8,11 @@ class Stanza
8
8
 
9
9
  register :message
10
10
 
11
- def self.new(to = nil, body = nil, type = :chat)
12
- elem = super()
13
- elem.to = to
14
- elem.type = type
15
- elem.body = body
16
- elem
11
+ def initialize(to = nil, body = nil, type = :chat)
12
+ super()
13
+ self.to = to
14
+ self.type = type
15
+ self.body = body
17
16
  end
18
17
 
19
18
  VALID_TYPES.each do |valid_type|
@@ -8,12 +8,6 @@ class Stanza
8
8
 
9
9
  register :presence
10
10
 
11
- ##
12
- # Ensure element_name is "presence" for all subclasses
13
- def self.new
14
- super :presence
15
- end
16
-
17
11
  ##
18
12
  # Creates a class based on the presence type
19
13
  # either a Status or Subscription object is created based
@@ -28,6 +22,12 @@ class Stanza
28
22
  klass.new.inherit(node)
29
23
  end
30
24
 
25
+ ##
26
+ # Ensure element_name is "presence" for all subclasses
27
+ def initialize
28
+ super :presence
29
+ end
30
+
31
31
  VALID_TYPES.each do |valid_type|
32
32
  define_method("#{valid_type}?") { self.type == valid_type }
33
33
  end
@@ -9,11 +9,10 @@ class Presence
9
9
 
10
10
  register :status, :status
11
11
 
12
- def self.new(state = nil, message = nil)
13
- elem = super()
14
- elem.state = state
15
- elem.message = message
16
- elem
12
+ def initialize(state = nil, message = nil)
13
+ super()
14
+ self.state = state
15
+ self.message = message
17
16
  end
18
17
 
19
18
  ##
@@ -5,11 +5,10 @@ class Presence
5
5
  class Subscription < Presence
6
6
  register :subscription, :subscription
7
7
 
8
- def self.new(to = nil, type = nil)
9
- elem = super()
10
- elem.to = to
11
- elem.type = type
12
- elem
8
+ def initialize(to = nil, type = nil)
9
+ super()
10
+ self.to = to
11
+ self.type = type
13
12
  end
14
13
 
15
14
  def inherit(node)
@@ -3,6 +3,7 @@ module Stream # :nodoc:
3
3
 
4
4
  class Parser # :nodoc:
5
5
  STREAM_REGEX = %r{(/)?stream:stream}.freeze
6
+ ERROR_REGEX = /^<(stream:[a-z]+)/.freeze
6
7
 
7
8
  @@debug = false
8
9
  def self.debug; @@debug; end
@@ -15,6 +16,7 @@ module Stream # :nodoc:
15
16
  @current = nil
16
17
 
17
18
  @parser = XML::SaxParser.new
19
+ @parser.io = StringIO.new
18
20
  @parser.callbacks = self
19
21
  end
20
22
 
@@ -24,16 +26,19 @@ module Stream # :nodoc:
24
26
  @receiver.receive XMPPNode.new('stream:end')
25
27
  else
26
28
  string << "</stream:stream>" if string =~ STREAM_REGEX && !$1
29
+ string.gsub!(ERROR_REGEX, "<\\1 xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'")
27
30
 
28
31
  @parser.string = string
29
32
  @parser.parse
30
33
  end
31
34
  end
32
35
 
33
- def on_start_element(elem, attrs)
34
- LOG.debug "START ELEM: (#{[elem, attrs].inspect})" if @@debug
36
+ NON_ATTRS = [nil, 'stream'].freeze
37
+ def on_start_element_ns(elem, attrs, prefix, uri, namespaces)
38
+ LOG.debug "START ELEM: (#{{:elem => elem, :attrs => attrs, :prefix => prefix, :ns => namespaces}.inspect})" if @@debug
39
+ elem = "#{"#{prefix}:" if prefix}#{elem}"
35
40
  e = XMPPNode.new elem
36
- attrs.each { |n,v| e[n] = v }
41
+ attrs.each { |n,v| n = "xmlns#{":#{n}" if n}" if NON_ATTRS.include?(n); e.attributes[n] = v }
37
42
 
38
43
  if elem == 'stream:stream'
39
44
  @receiver.receive e
@@ -50,10 +55,12 @@ module Stream # :nodoc:
50
55
  @current << XML::Node.new_text(chars) if @current
51
56
  end
52
57
 
53
- def on_end_element(elem)
58
+ def on_end_element_ns(elem, prefix, uri)
59
+ LOG.debug "END ELEM: #{{:elem => elem, :prefix => prefix, :uri => uri, :current => @current}.inspect}" if @@debug
60
+
61
+ elem = "#{"#{prefix}:" if prefix}#{elem}"
54
62
  return if elem =~ STREAM_REGEX
55
63
 
56
- LOG.debug "END ELEM: (#{@current}) #{elem}" if @@debug
57
64
  if @current.parent?
58
65
  @current = @current.parent
59
66
 
@@ -62,6 +69,10 @@ module Stream # :nodoc:
62
69
  @receiver.receive c
63
70
 
64
71
  end
72
+
73
+ def on_error(msg)
74
+ raise Blather::ParseError, msg.to_s
75
+ end
65
76
  end
66
77
  end #Parser
67
78
 
@@ -18,7 +18,11 @@ module Stream # :nodoc:
18
18
  end
19
19
 
20
20
  def init_callbacks
21
- @callbacks['mechanisms'] = proc { @mechanisms = @node.children; set_mechanism; authenticate }
21
+ @callbacks['mechanisms'] = proc {
22
+ @mechanisms = @node.children
23
+ set_mechanism
24
+ authenticate
25
+ }
22
26
  end
23
27
 
24
28
  def set_mechanism
@@ -10,20 +10,6 @@ module Blather
10
10
  class_inheritable_accessor :xmlns,
11
11
  :name
12
12
 
13
- ##
14
- # Automatically sets the namespace registered by the subclass
15
- def self.new(name = nil, content = nil)
16
- name ||= self.name
17
-
18
- args = []
19
- args << name.to_s if name
20
- args << content if content
21
-
22
- elem = super *args
23
- elem.xmlns = xmlns
24
- elem
25
- end
26
-
27
13
  ##
28
14
  # Lets a subclass register itself
29
15
  #
@@ -56,6 +42,16 @@ module Blather
56
42
  end
57
43
  end
58
44
 
45
+ ##
46
+ # Automatically sets the namespace registered by the subclass
47
+ def initialize(name = nil, content = nil)
48
+ name ||= self.class.name
49
+ content = content.to_s if content
50
+
51
+ super name.to_s, content
52
+ self.xmlns = self.class.xmlns
53
+ end
54
+
59
55
  ##
60
56
  # Quickway of turning itself into a proper object
61
57
  def to_stanza
@@ -63,12 +59,11 @@ module Blather
63
59
  end
64
60
 
65
61
  def xmlns=(ns)
66
- attributes.remove :xmlns
67
- self['xmlns'] = ns if ns
62
+ attributes['xmlns'] = ns
68
63
  end
69
64
 
70
65
  def xmlns
71
- self['xmlns']
66
+ attributes['xmlns']
72
67
  end
73
68
 
74
69
  ##
@@ -52,7 +52,7 @@ describe 'Blather::Stream' do
52
52
 
53
53
  stream.expects(:send_data).with do |val|
54
54
  val.must_match(/stream:stream/)
55
- stream.receive_data "<stream:stream><message to='a@b/c' from='d@e/f' type='chat' xml:lang='en'><body>Message!</body></message>"
55
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><message to='a@b/c' from='d@e/f' type='chat' xml:lang='en'><body>Message!</body></message>"
56
56
  end
57
57
  stream.connection_completed
58
58
  end
@@ -60,7 +60,7 @@ describe 'Blather::Stream' do
60
60
  it 'puts itself in the stopped state when unbound' do
61
61
  stream = mock_stream do |val|
62
62
  val.must_match(/stream:stream/)
63
- stream.receive_data "<stream:stream>"
63
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
64
64
 
65
65
  stream.stopped?.wont_equal true
66
66
  stream.unbind
@@ -94,7 +94,7 @@ describe 'Blather::Stream' do
94
94
  end
95
95
  end
96
96
  stream.connection_completed
97
- stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
97
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
98
98
  end
99
99
 
100
100
  it 'raises an error when it receives stream:error' do
@@ -123,7 +123,7 @@ describe 'Blather::Stream' do
123
123
  end
124
124
  end
125
125
  stream.connection_completed
126
- stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
126
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
127
127
  end.must_raise(StreamError)
128
128
  end
129
129
 
@@ -145,7 +145,7 @@ describe 'Blather::Stream' do
145
145
  end
146
146
  end
147
147
  stream.connection_completed
148
- stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
148
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
149
149
  end
150
150
 
151
151
  it 'connects via SASL MD5 when asked' do
@@ -161,7 +161,7 @@ describe 'Blather::Stream' do
161
161
  when nil
162
162
  val.must_match(/stream:stream/)
163
163
  state = :started
164
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>"
164
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>"
165
165
  true
166
166
 
167
167
  when :started
@@ -206,7 +206,7 @@ describe 'Blather::Stream' do
206
206
  when nil
207
207
  val.must_match(/stream:stream/)
208
208
  state = :started
209
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms></stream:features>"
209
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms></stream:features>"
210
210
  true
211
211
 
212
212
  when :started
@@ -239,7 +239,7 @@ describe 'Blather::Stream' do
239
239
  when nil
240
240
  val.must_match(/stream:stream/)
241
241
  state = :started
242
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
242
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
243
243
  true
244
244
 
245
245
  when :started
@@ -272,7 +272,7 @@ describe 'Blather::Stream' do
272
272
  when nil
273
273
  val.must_match(/stream:stream/)
274
274
  state = :started
275
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
275
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
276
276
  true
277
277
 
278
278
  when :started
@@ -317,7 +317,7 @@ describe 'Blather::Stream' do
317
317
  when nil
318
318
  val.must_match(/stream:stream/)
319
319
  state = :started
320
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
320
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
321
321
  true
322
322
 
323
323
  when :started
@@ -356,7 +356,7 @@ describe 'Blather::Stream' do
356
356
  state = :started
357
357
  val.must_match(/stream:stream/)
358
358
  lambda do
359
- stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>UNKNOWN</mechanism></mechanisms></stream:features>"
359
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>UNKNOWN</mechanism></mechanisms></stream:features>"
360
360
  end.must_raise(Stream::SASL::UnknownMechanism)
361
361
 
362
362
  else
@@ -380,11 +380,11 @@ describe 'Blather::Stream' do
380
380
  when nil
381
381
  val.must_match(/stream:stream/)
382
382
  state = :started
383
- stream.receive_data "<stream:stream><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></stream:features>"
383
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></stream:features>"
384
384
  true
385
385
 
386
386
  when :started
387
- val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"\s*/>})
387
+ val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>})
388
388
  val =~ %r{<iq[^>]+id="([^"]+)"}
389
389
  state = :complete
390
390
  stream.receive_data "<iq type='result' id='#{$1}'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>#{jid}/server_resource</jid></bind></iq>"
@@ -412,7 +412,7 @@ describe 'Blather::Stream' do
412
412
  when nil
413
413
  val.must_match(/stream:stream/)
414
414
  state = :started
415
- stream.receive_data "<stream:stream><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></stream:features>"
415
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></stream:features>"
416
416
  true
417
417
 
418
418
  when :started
@@ -443,7 +443,7 @@ describe 'Blather::Stream' do
443
443
  when nil
444
444
  val.must_match(/stream:stream/)
445
445
  state = :started
446
- stream.receive_data "<stream:stream><stream:features><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></stream:features>"
446
+ stream.receive_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></stream:features>"
447
447
  true
448
448
 
449
449
  when :started
data/spec/spec_helper.rb CHANGED
@@ -33,9 +33,7 @@ end
33
33
 
34
34
  class Object
35
35
  def must_change *args, &block
36
- return MiniTest::Spec.current.assert_change(*args, &self) if Proc === self
37
- return MiniTest::Spec.current.assert_change(args.first, self) if args.size == 1
38
- return MiniTest::Spec.current.assert_change(self, *args)
36
+ return MiniTest::Spec.current.assert_change(*args, &self)
39
37
  end
40
38
  end
41
39
 
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.2"
4
+ version: 0.2.1
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: 2008-12-19 00:00:00 -08:00
12
+ date: 2008-12-21 00:00:00 -08: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: 0.9.2
33
+ version: 0.9.7
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: echoe
@@ -52,6 +52,8 @@ extra_rdoc_files:
52
52
  - CHANGELOG
53
53
  - lib/autotest/discover.rb
54
54
  - lib/autotest/spec.rb
55
+ - lib/blather/core_ext/active_support.rb
56
+ - lib/blather/core_ext/libxml.rb
55
57
  - lib/blather/errors.rb
56
58
  - lib/blather/jid.rb
57
59
  - lib/blather/roster.rb
@@ -71,7 +73,6 @@ extra_rdoc_files:
71
73
  - lib/blather/stream/session.rb
72
74
  - lib/blather/stream/tls.rb
73
75
  - lib/blather/stream.rb
74
- - lib/blather/sugar.rb
75
76
  - lib/blather/xmpp_node.rb
76
77
  - lib/blather.rb
77
78
  - LICENSE
@@ -82,6 +83,8 @@ files:
82
83
  - examples/echo.rb
83
84
  - lib/autotest/discover.rb
84
85
  - lib/autotest/spec.rb
86
+ - lib/blather/core_ext/active_support.rb
87
+ - lib/blather/core_ext/libxml.rb
85
88
  - lib/blather/errors.rb
86
89
  - lib/blather/jid.rb
87
90
  - lib/blather/roster.rb
@@ -101,7 +104,6 @@ files:
101
104
  - lib/blather/stream/session.rb
102
105
  - lib/blather/stream/tls.rb
103
106
  - lib/blather/stream.rb
104
- - lib/blather/sugar.rb
105
107
  - lib/blather/xmpp_node.rb
106
108
  - lib/blather.rb
107
109
  - LICENSE