blather 0.4.7 → 0.4.8

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