blather 0.4.7 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/README.md +162 -0
  2. data/examples/{print_heirarchy.rb → print_hierarchy.rb} +5 -5
  3. data/examples/stream_only.rb +27 -0
  4. data/lib/blather.rb +4 -0
  5. data/lib/blather/client/client.rb +91 -73
  6. data/lib/blather/client/dsl.rb +156 -32
  7. data/lib/blather/client/dsl/pubsub.rb +86 -54
  8. data/lib/blather/core_ext/active_support.rb +9 -9
  9. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +2 -2
  10. data/lib/blather/core_ext/nokogiri.rb +12 -7
  11. data/lib/blather/errors.rb +25 -14
  12. data/lib/blather/errors/sasl_error.rb +21 -3
  13. data/lib/blather/errors/stanza_error.rb +37 -21
  14. data/lib/blather/errors/stream_error.rb +27 -17
  15. data/lib/blather/jid.rb +79 -24
  16. data/lib/blather/roster.rb +39 -21
  17. data/lib/blather/roster_item.rb +43 -21
  18. data/lib/blather/stanza.rb +88 -40
  19. data/lib/blather/stanza/disco.rb +12 -2
  20. data/lib/blather/stanza/disco/disco_info.rb +112 -20
  21. data/lib/blather/stanza/disco/disco_items.rb +81 -12
  22. data/lib/blather/stanza/iq.rb +94 -38
  23. data/lib/blather/stanza/iq/query.rb +16 -22
  24. data/lib/blather/stanza/iq/roster.rb +98 -20
  25. data/lib/blather/stanza/message.rb +266 -111
  26. data/lib/blather/stanza/presence.rb +118 -42
  27. data/lib/blather/stanza/presence/status.rb +140 -60
  28. data/lib/blather/stanza/presence/subscription.rb +44 -10
  29. data/lib/blather/stanza/pubsub.rb +70 -15
  30. data/lib/blather/stanza/pubsub/affiliations.rb +36 -7
  31. data/lib/blather/stanza/pubsub/create.rb +26 -4
  32. data/lib/blather/stanza/pubsub/errors.rb +13 -4
  33. data/lib/blather/stanza/pubsub/event.rb +56 -10
  34. data/lib/blather/stanza/pubsub/items.rb +46 -6
  35. data/lib/blather/stanza/pubsub/publish.rb +52 -7
  36. data/lib/blather/stanza/pubsub/retract.rb +45 -6
  37. data/lib/blather/stanza/pubsub/subscribe.rb +30 -4
  38. data/lib/blather/stanza/pubsub/subscription.rb +74 -6
  39. data/lib/blather/stanza/pubsub/subscriptions.rb +35 -9
  40. data/lib/blather/stanza/pubsub/unsubscribe.rb +30 -4
  41. data/lib/blather/stanza/pubsub_owner.rb +17 -7
  42. data/lib/blather/stanza/pubsub_owner/delete.rb +23 -5
  43. data/lib/blather/stanza/pubsub_owner/purge.rb +23 -5
  44. data/lib/blather/stream.rb +96 -29
  45. data/lib/blather/stream/parser.rb +6 -9
  46. data/lib/blather/xmpp_node.rb +101 -153
  47. data/spec/blather/client/client_spec.rb +1 -1
  48. data/spec/blather/errors_spec.rb +5 -5
  49. data/spec/blather/stanza/message_spec.rb +56 -0
  50. data/spec/blather/stanza/presence/status_spec.rb +1 -1
  51. data/spec/blather/stanza_spec.rb +3 -3
  52. data/spec/blather/xmpp_node_spec.rb +19 -74
  53. metadata +6 -10
  54. data/README.rdoc +0 -185
  55. data/examples/drb_client.rb +0 -5
  56. data/examples/ping.rb +0 -11
  57. data/examples/pong.rb +0 -6
  58. data/examples/pubsub/cli.rb +0 -64
  59. data/examples/pubsub/ping_pong.rb +0 -18
@@ -1,58 +1,85 @@
1
1
  module Blather
2
2
  class Stanza
3
3
 
4
- # = Presence Stanza
4
+ # # Presence Stanza
5
5
  #
6
- # Within Blather most of the interaction with Presence stanzas will be through one of its child classes: Status or Subscription.
6
+ # [RFC 3921 Section 2.2 - Presence Syntax](http://xmpp.org/rfcs/rfc3921.html#stanzas-presence)
7
7
  #
8
- # Presence stanzas are used to express an entity's current network availability (offline or online, along with
9
- # various sub-states of the latter and optional user-defined descriptive text), and to notify other entities of
10
- # that availability. Presence stanzas are also used to negotiate and manage subscriptions to the presence of other entities.
8
+ # Within Blather most of the interaction with Presence stanzas will be
9
+ # through one of its child classes: Status or Subscription.
11
10
  #
12
- # == Type Attribute
11
+ # Presence stanzas are used to express an entity's current network
12
+ # availability (offline or online, along with various sub-states of the
13
+ # latter and optional user-defined descriptive text), and to notify other
14
+ # entities of that availability. Presence stanzas are also used to negotiate
15
+ # and manage subscriptions to the presence of other entities.
13
16
  #
14
- # The +type+ attribute of a presence stanza is optional. A presence stanza that does not possess a +type+ attribute
15
- # is used to signal to the server that the sender is online and available for communication. If included, the +type+
16
- # attribute specifies a lack of availability, a request to manage a subscription to another entity's presence, a
17
- # request for another entity's current presence, or an error related to a previously-sent presence stanza. If included,
18
- # the +type+ attribute must have one of the following values:
17
+ # ## "Type" Attribute
19
18
  #
20
- # * +:unavailable+ -- Signals that the entity is no longer available for communication
21
- # * +:subscribe+ -- The sender wishes to subscribe to the recipient's presence.
22
- # * +:subscribed+ -- The sender has allowed the recipient to receive their presence.
23
- # * +:unsubscribe+ -- The sender is unsubscribing from another entity's presence.
24
- # * +:unsubscribed+ -- The subscription request has been denied or a previously-granted subscription has been cancelled.
25
- # * +:probe+ -- A request for an entity's current presence; should be generated only by a server on behalf of a user.
26
- # * +:error+ -- An error has occurred regarding processing or delivery of a previously-sent presence stanza.
19
+ # The `type` attribute of a presence stanza is optional. A presence stanza
20
+ # that does not possess a `type` attribute is used to signal to the server
21
+ # that the sender is online and available for communication. If included,
22
+ # the `type` attribute specifies a lack of availability, a request to manage
23
+ # a subscription to another entity's presence, a request for another
24
+ # entity's current presence, or an error related to a previously-sent
25
+ # presence stanza. If included, the `type` attribute must have one of the
26
+ # following values:
27
+ #
28
+ # * `:unavailable` -- Signals that the entity is no longer available for
29
+ # communication
30
+ #
31
+ # * `:subscribe` -- The sender wishes to subscribe to the recipient's
32
+ # presence.
33
+ #
34
+ # * `:subscribed` -- The sender has allowed the recipient to receive their
35
+ # presence.
36
+ #
37
+ # * `:unsubscribe` -- The sender is unsubscribing from another entity's
38
+ # presence.
39
+ #
40
+ # * `:unsubscribed` -- The subscription request has been denied or a
41
+ # previously-granted subscription has been cancelled.
42
+ #
43
+ # * `:probe` -- A request for an entity's current presence; should be
44
+ # generated only by a server on behalf of a user.
45
+ #
46
+ # * `:error` -- An error has occurred regarding processing or delivery of a
47
+ # previously-sent presence stanza.
27
48
  #
28
49
  # Blather provides a helper for each possible type:
29
50
  #
30
- # Presence#unavailabe?
31
- # Presence#unavailable?
32
- # Presence#subscribe?
33
- # Presence#subscribed?
34
- # Presence#unsubscribe?
35
- # Presence#unsubscribed?
36
- # Presence#probe?
37
- # Presence#error?
51
+ # Presence#unavailabe?
52
+ # Presence#unavailable?
53
+ # Presence#subscribe?
54
+ # Presence#subscribed?
55
+ # Presence#unsubscribe?
56
+ # Presence#unsubscribed?
57
+ # Presence#probe?
58
+ # Presence#error?
38
59
  #
39
- # Blather treats the +type+ attribute like a normal ruby object attribute providing a getter and setter.
40
- # The default +type+ is nil.
60
+ # Blather treats the `type` attribute like a normal ruby object attribute
61
+ # providing a getter and setter. The default `type` is nil.
41
62
  #
42
- # presence = Presence.new
43
- # presence.type # => nil
44
- # presence.type = :unavailable
45
- # presence.unavailable? # => true
46
- # presence.error? # => false
63
+ # presence = Presence.new
64
+ # presence.type # => nil
65
+ # presence.type = :unavailable
66
+ # presence.unavailable? # => true
67
+ # presence.error? # => false
47
68
  #
48
- # presence.type = :invalid # => RuntimeError
69
+ # presence.type = :invalid # => RuntimeError
49
70
  #
71
+ # @handler :presence
50
72
  class Presence < Stanza
51
- VALID_TYPES = [:unavailable, :subscribe, :subscribed, :unsubscribe, :unsubscribed, :probe, :error] # :nodoc:
73
+ VALID_TYPES = [ :unavailable,
74
+ :subscribe,
75
+ :subscribed,
76
+ :unsubscribe,
77
+ :unsubscribed,
78
+ :probe,
79
+ :error].freeze
52
80
 
53
81
  register :presence
54
82
 
55
- ##
56
83
  # Creates a class based on the presence type
57
84
  # either a Status or Subscription object is created based
58
85
  # on the type attribute.
@@ -66,18 +93,67 @@ class Stanza
66
93
  klass.new.inherit(node)
67
94
  end
68
95
 
69
- ##
70
96
  # Ensure element_name is "presence" for all subclasses
71
97
  def self.new
72
98
  super :presence
73
99
  end
74
100
 
75
- attribute_helpers_for(:type, VALID_TYPES)
101
+ # Check if the IQ is of type :unavailable
102
+ #
103
+ # @return [true, false]
104
+ def unavailable?
105
+ self.type == :unavailable
106
+ end
76
107
 
77
- ##
78
- # Ensures type is one of :unavailable, :subscribe, :subscribed, :unsubscribe, :unsubscribed, :probe or :error
79
- def type=(type) # :nodoc:
80
- raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}" if type && !VALID_TYPES.include?(type.to_sym)
108
+ # Check if the IQ is of type :subscribe
109
+ #
110
+ # @return [true, false]
111
+ def subscribe?
112
+ self.type == :subscribe
113
+ end
114
+
115
+ # Check if the IQ is of type :subscribed
116
+ #
117
+ # @return [true, false]
118
+ def subscribed?
119
+ self.type == :subscribed
120
+ end
121
+
122
+ # Check if the IQ is of type :unsubscribe
123
+ #
124
+ # @return [true, false]
125
+ def unsubscribe?
126
+ self.type == :unsubscribe
127
+ end
128
+
129
+ # Check if the IQ is of type :unsubscribed
130
+ #
131
+ # @return [true, false]
132
+ def unsubscribed?
133
+ self.type == :unsubscribed
134
+ end
135
+
136
+ # Check if the IQ is of type :probe
137
+ #
138
+ # @return [true, false]
139
+ def probe?
140
+ self.type == :probe
141
+ end
142
+
143
+ # Check if the IQ is of type :error
144
+ #
145
+ # @return [true, false]
146
+ def error?
147
+ self.type == :error
148
+ end
149
+
150
+ # Ensures type is one of Blather::Stanza::Presence::VALID_TYPES
151
+ #
152
+ # @param [#to_sym] type the Presence type. Must be one of VALID_TYPES
153
+ def type=(type)
154
+ if type && !VALID_TYPES.include?(type.to_sym)
155
+ raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}"
156
+ end
81
157
  super
82
158
  end
83
159
 
@@ -2,73 +2,89 @@ module Blather
2
2
  class Stanza
3
3
  class Presence
4
4
 
5
- # = Status Stanza
5
+ # # Status Stanza
6
6
  #
7
- # Presence stanzas are used to express an entity's current network availability (offline or online, along with
8
- # various sub-states of the latter and optional user-defined descriptive text), and to notify other entities of
9
- # that availability.
7
+ # [RFC 3921 Section 2.2.2 - Presence Child Elements](http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2)
10
8
  #
11
- # == State Attribute
9
+ # Presence stanzas are used to express an entity's current network
10
+ # availability (offline or online, along with various sub-states of the
11
+ # latter and optional user-defined descriptive text), and to notify other
12
+ # entities of that availability.
12
13
  #
13
- # The +state+ attribute determains the availability of the entity and can be one of the following:
14
+ # ## "State" Attribute
14
15
  #
15
- # * +:available+ -- The entity or resource is available
16
- # * +:away+ -- The entity or resource is temporarily away.
17
- # * +:chat+ -- The entity or resource is actively interested in chatting.
18
- # * +:dnd+ -- The entity or resource is busy (dnd = "Do Not Disturb").
19
- # * +:xa+ -- The entity or resource is away for an extended period (xa = "eXtended Away").
16
+ # The `state` attribute determains the availability of the entity and can be
17
+ # one of the following:
18
+ #
19
+ # * `:available` -- The entity or resource is available
20
+ #
21
+ # * `:away` -- The entity or resource is temporarily away.
22
+ #
23
+ # * `:chat` -- The entity or resource is actively interested in chatting.
24
+ #
25
+ # * `:dnd` -- The entity or resource is busy (dnd = "Do Not Disturb").
26
+ #
27
+ # * `:xa` -- The entity or resource is away for an extended period (xa =
28
+ # "eXtended Away").
20
29
  #
21
30
  # Blather provides a helper for each possible state:
22
31
  #
23
- # Status#available?
24
- # Status#away?
25
- # Status#chat?
26
- # Status#dnd?
27
- # Status#xa?
32
+ # Status#available?
33
+ # Status#away?
34
+ # Status#chat?
35
+ # Status#dnd?
36
+ # Status#xa?
37
+ #
38
+ # Blather treats the `type` attribute like a normal ruby object attribute
39
+ # providing a getter and setter. The default `type` is `available`.
28
40
  #
29
- # Blather treats the +type+ attribute like a normal ruby object attribute providing a getter and setter.
30
- # The default +type+ is +available+.
41
+ # status = Status.new
42
+ # status.state # => :available
43
+ # status.available? # => true
44
+ # status.state = :away
45
+ # status.away? # => true
46
+ # status.available? # => false
47
+ # status
48
+ # status.state = :invalid # => RuntimeError
31
49
  #
32
- # status = Status.new
33
- # status.state # => :available
34
- # status.available? # => true
35
- # status.state = :away
36
- # status.away? # => true
37
- # status.available? # => false
38
- # status
39
- # status.state = :invalid # => RuntimeError
50
+ # ## "Type" Attribute
40
51
  #
41
- # == Type Attribute
52
+ # The `type` attribute is inherited from Presence, but limits the value to
53
+ # either `nil` or `:unavailable` as these are the only types that relate to
54
+ # Status.
42
55
  #
43
- # The +type+ attribute is inherited from Presence, but limits the value to either +nil+ or +:unavailable+
44
- # as these are the only types that relate to Status.
56
+ # ## "Priority" Attribute
45
57
  #
46
- # == Priority Attribute
58
+ # The `priority` attribute sets the priority of the status for the entity
59
+ # and must be an integer between -128 and 127.
47
60
  #
48
- # The +priority+ attribute sets the priority of the status for the entity and must be an integer between
49
- # -128 and 127.
61
+ # ## "Message" Attribute
50
62
  #
51
- # == Message Attribute
63
+ # The optional `message` element contains XML character data specifying a
64
+ # natural-language description of availability status. It is normally used
65
+ # in conjunction with the show element to provide a detailed description of
66
+ # an availability state (e.g., "In a meeting").
52
67
  #
53
- # The optional +message+ element contains XML character data specifying a natural-language description of
54
- # availability status. It is normally used in conjunction with the show element to provide a detailed
55
- # description of an availability state (e.g., "In a meeting").
56
- #
57
- # Blather treats the +message+ attribute like a normal ruby object attribute providing a getter and setter.
58
- # The default +message+ is nil.
68
+ # Blather treats the `message` attribute like a normal ruby object attribute
69
+ # providing a getter and setter. The default `message` is nil.
59
70
  #
60
- # status = Status.new
61
- # status.message # => nil
62
- # status.message = "gone!"
63
- # status.message # => "gone!"
71
+ # status = Status.new
72
+ # status.message # => nil
73
+ # status.message = "gone!"
74
+ # status.message # => "gone!"
64
75
  #
76
+ # @handler :status
65
77
  class Status < Presence
66
- VALID_STATES = [:away, :chat, :dnd, :xa] # :nodoc:
78
+ VALID_STATES = [:away, :chat, :dnd, :xa].freeze
67
79
 
68
80
  include Comparable
69
81
 
70
82
  register :status, :status
71
83
 
84
+ # Create a new Status stanza
85
+ #
86
+ # @param [<:away, :chat, :dnd, :xa>] state the state of the status
87
+ # @param [#to_s] message a message to send with the status
72
88
  def self.new(state = nil, message = nil)
73
89
  node = super()
74
90
  node.state = state
@@ -76,48 +92,112 @@ class Presence
76
92
  node
77
93
  end
78
94
 
79
- attribute_helpers_for(:state, [:available] + VALID_STATES)
95
+ # Check if the state is available
96
+ #
97
+ # @return [true, false]
98
+ def available?
99
+ self.state == :available
100
+ end
101
+
102
+ # Check if the state is away
103
+ #
104
+ # @return [true, false]
105
+ def away?
106
+ self.state == :away
107
+ end
108
+
109
+ # Check if the state is chat
110
+ #
111
+ # @return [true, false]
112
+ def chat?
113
+ self.state == :chat
114
+ end
115
+
116
+ # Check if the state is dnd
117
+ #
118
+ # @return [true, false]
119
+ def dnd?
120
+ self.state == :dnd
121
+ end
122
+
123
+ # Check if the state is xa
124
+ #
125
+ # @return [true, false]
126
+ def xa?
127
+ self.state == :xa
128
+ end
80
129
 
81
- ##
130
+ # Set the type attribute
82
131
  # Ensures type is nil or :unavailable
83
- def type=(type) # :nodoc:
84
- raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable" if type && type.to_sym != :unavailable
132
+ #
133
+ # @param [<:unavailable, nil>] type the type
134
+ def type=(type)
135
+ if type && type.to_sym != :unavailable
136
+ raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
137
+ end
85
138
  super
86
139
  end
87
140
 
88
- ##
141
+ # Set the state
89
142
  # Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
143
+ #
144
+ # @param [<:available, :away, :chat, :dnd, :xa, nil>] state
90
145
  def state=(state) # :nodoc:
91
146
  state = state.to_sym if state
92
147
  state = nil if state == :available
93
- raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}" if state && !VALID_STATES.include?(state)
148
+ if state && !VALID_STATES.include?(state)
149
+ raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
150
+ end
94
151
 
95
152
  set_content_for :show, state
96
153
  end
97
154
 
98
- ##
99
- # :available if state is nil
100
- def state # :nodoc:
155
+ # Get the state of the status
156
+ #
157
+ # @return [<:available, :away, :chat, :dnd, :xa>]
158
+ def state
101
159
  state = type || content_from(:show)
102
160
  state = :available if state.blank?
103
161
  state.to_sym
104
162
  end
105
163
 
106
- ##
107
- # Ensure priority is between -128 and 127
164
+ # Set the priority of the status
165
+ # Ensures priority is between -128 and 127
166
+ #
167
+ # @param [Fixnum<-128...127>] new_priority
108
168
  def priority=(new_priority) # :nodoc:
109
- raise ArgumentError, 'Priority must be between -128 and +127' if new_priority && !(-128..127).include?(new_priority.to_i)
169
+ if new_priority && !(-128..127).include?(new_priority.to_i)
170
+ raise ArgumentError, 'Priority must be between -128 and +127'
171
+ end
110
172
  set_content_for :priority, new_priority
111
-
112
173
  end
113
174
 
114
- content_attr_reader :priority, :to_i
175
+ # Get the priority of the status
176
+ #
177
+ # @return [Fixnum<-128...127>]
178
+ def priority
179
+ read_content(:priority).to_i
180
+ end
115
181
 
116
- content_attr_accessor :message, nil, :status
182
+ # Get the status message
183
+ #
184
+ # @return [String, nil]
185
+ def message
186
+ read_content :status
187
+ end
188
+
189
+ # Set the status message
190
+ #
191
+ # @param [String, nil] message
192
+ def message=(message)
193
+ set_content_for :status, message
194
+ end
117
195
 
118
- ##
119
196
  # Compare status based on priority
120
197
  # raises an error if the JIDs aren't the same
198
+ #
199
+ # @param [Blather::Stanza::Presence::Status] o
200
+ # @return [true,false]
121
201
  def <=>(o)
122
202
  unless self.from && o.from && self.from.stripped == o.from.stripped
123
203
  raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"