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,121 +1,248 @@
1
1
  require File.join(File.dirname(__FILE__), 'client')
2
2
 
3
3
  module Blather
4
+
5
+ # # Blather DSL
6
+ #
7
+ # The DSL is a set of methods that enables you to write cleaner code. Being a
8
+ # module means it can be included in or extend any class you may want to
9
+ # create.
10
+ #
11
+ # Every stanza handler is registered as a method on the DSL.
12
+ #
13
+ # @example Include the DSL in the top level namespace.
14
+ #
15
+ # require 'blather/client'
16
+ # when_ready { puts "Connected ! send messages to #{jid.stripped}." }
17
+ #
18
+ # subscription :request? do |s|
19
+ # write_to_stream s.approve!
20
+ # end
21
+ #
22
+ # message :chat?, :body => 'exit' do |m|
23
+ # say m.from, 'Exiting ...'
24
+ # shutdown
25
+ # end
26
+ #
27
+ # message :chat?, :body do |m|
28
+ # say m.from, "You sent: #{m.body}"
29
+ # end
30
+ #
31
+ # @example Set the DSL to its own namespace.
32
+ #
33
+ # require 'blather/client/dsl'
34
+ # module Echo
35
+ # extend Blather::DSL
36
+ # def self.run
37
+ # client.run
38
+ # end
39
+ #
40
+ # when_ready { puts "Connected ! send messages to #{jid.stripped}." }
41
+ #
42
+ # subscription :request? do |s|
43
+ # write_to_stream s.approve!
44
+ # end
45
+ #
46
+ # message :chat?, :body => 'exit' do |m|
47
+ # say m.from, 'Exiting ...'
48
+ # shutdown
49
+ # end
50
+ #
51
+ # message :chat?, :body do |m|
52
+ # say m.from, "You sent: #{m.body}"
53
+ # end
54
+ # end
55
+ #
56
+ # EM.run { Echo.run }
57
+ #
58
+ # @example Create a class out of it
59
+ #
60
+ # require 'blather/client/dsl'
61
+ # class Echo
62
+ # include Blather::DSL
63
+ # end
64
+ #
65
+ # echo = Echo.new
66
+ # echo.when_ready { puts "Connected ! send messages to #{jid.stripped}." }
67
+ #
68
+ # echo.subscription :request? do |s|
69
+ # write_to_stream s.approve!
70
+ # end
71
+ #
72
+ # echo.message :chat?, :body => 'exit' do |m|
73
+ # say m.from, 'Exiting ...'
74
+ # shutdown
75
+ # end
76
+ #
77
+ # echo.message :chat?, :body do |m|
78
+ # say m.from, "You sent: #{m.body}"
79
+ # end
80
+ #
81
+ # EM.run { echo.client.run }
4
82
  module DSL
5
83
 
6
84
  autoload :PubSub, File.expand_path(File.join(File.dirname(__FILE__), *%w[dsl pubsub]))
7
85
 
86
+ # The actual client connection
87
+ #
88
+ # @return [Blather::Client]
8
89
  def client
9
90
  @client ||= Client.new
10
91
  end
11
92
  module_function :client
12
93
 
94
+ # A pubsub helper
95
+ #
96
+ # @return [Blather::PubSub]
13
97
  def pubsub
14
98
  @pubsub ||= PubSub.new client, jid.domain
15
99
  end
16
100
 
17
- ##
18
101
  # Push data to the stream
19
102
  # This works such that it can be chained:
20
- # self << stanza1 << stanza2 << "raw data"
103
+ # self << stanza1 << stanza2 << "raw data"
104
+ #
105
+ # @param [#to_xml, #to_s] stanza data to send down the wire
106
+ # @return [self]
21
107
  def <<(stanza)
22
108
  client.write stanza
23
109
  self
24
110
  end
25
111
 
26
- ##
27
112
  # Prepare server settings
28
- # setup [node@domain/resource], [password], [host], [port]
29
- # host and port are optional defaulting to the domain in the JID and 5222 respectively
113
+ #
114
+ # @param [#to_s] jid the JID to authenticate with
115
+ # @param [#to_s] password the password to authenticate with
116
+ # @param [String] host (optional) the host to connect to (can be an IP). If
117
+ # this is `nil` the domain on the JID will be used
118
+ # @param [Fixnum, String] (optional) port the port to connect on
30
119
  def setup(jid, password, host = nil, port = nil)
31
120
  client.setup(jid, password, host, port)
32
121
  end
33
122
 
34
- ##
35
123
  # Shutdown the connection.
36
124
  # Flushes the write buffer then stops EventMachine
37
125
  def shutdown
38
126
  client.close
39
127
  end
40
128
 
41
- ##
42
129
  # Setup a before filter
130
+ #
131
+ # @param [Symbol] handler (optional) the stanza handler the filter should
132
+ # run before
133
+ # @param [guards] guards (optional) a set of guards to check the stanza
134
+ # against
135
+ # @yield [Blather::Stanza] stanza
43
136
  def before(handler = nil, *guards, &block)
44
137
  client.register_filter :before, handler, *guards, &block
45
138
  end
46
139
 
47
- ##
48
140
  # Setup an after filter
141
+ #
142
+ # @param [Symbol] handler (optional) the stanza handler the filter should
143
+ # run after
144
+ # @param [guards] guards (optional) a set of guards to check the stanza
145
+ # against
146
+ # @yield [Blather::Stanza] stanza
49
147
  def after(handler = nil, *guards, &block)
50
148
  client.register_filter :after, handler, *guards, &block
51
149
  end
52
150
 
53
- ##
54
151
  # Set handler for a stanza type
55
- def handle(stanza_type, *guards, &block)
56
- client.register_handler stanza_type, *guards, &block
152
+ #
153
+ # @param [Symbol] handler the stanza type it should handle
154
+ # @param [guards] guards (optional) a set of guards to check the stanza
155
+ # against
156
+ # @yield [Blather::Stanza] stanza
157
+ def handle(handler, *guards, &block)
158
+ client.register_handler handler, *guards, &block
57
159
  end
58
160
 
59
- ##
60
161
  # Wrapper for "handle :ready" (just a bit of syntactic sugar)
162
+ #
163
+ # This is run after the connection has been completely setup
61
164
  def when_ready(&block)
62
165
  handle :ready, &block
63
166
  end
64
167
 
65
- ##
66
168
  # Wrapper for "handle :disconnected"
169
+ #
170
+ # This is run after the connection has been shut down.
171
+ #
172
+ # @example Reconnect after a disconnection
173
+ # disconnected { client.run }
67
174
  def disconnected(&block)
68
175
  handle :disconnected, &block
69
176
  end
70
177
 
71
- ##
72
178
  # Set current status
179
+ #
180
+ # @param [Blather::Stanza::Presence::State::VALID_STATES] state the current
181
+ # state
182
+ # @param [#to_s] msg the status message to use
73
183
  def set_status(state = nil, msg = nil)
74
184
  client.status = state, msg
75
185
  end
76
186
 
77
- ##
78
187
  # Direct access to the roster
188
+ #
189
+ # @return [Blather::Roster]
79
190
  def my_roster
80
191
  client.roster
81
192
  end
82
193
 
83
- ##
84
194
  # Write data to the stream
85
- # Anything that resonds to #to_s can be paseed to the stream
195
+ #
196
+ # @param [#to_xml, #to_s] stanza the data to send down the wire.
86
197
  def write_to_stream(stanza)
87
198
  client.write stanza
88
199
  end
89
200
 
90
- ##
91
201
  # Helper method to make sending basic messages easier
92
- # say [jid], [msg]
202
+ #
203
+ # @param [Blather::JID, #to_s] to the JID of the message recipient
204
+ # @param [#to_s] msg the message to send
93
205
  def say(to, msg)
94
206
  client.write Blather::Stanza::Message.new(to, msg)
95
207
  end
96
208
 
97
- ##
98
- # Wrapper to grab the current JID
209
+ # The JID according to the server
210
+ #
211
+ # @return [Blather::JID]
99
212
  def jid
100
213
  client.jid
101
214
  end
102
215
 
103
- ##
104
216
  # Halt the handler chain
217
+ #
218
+ # Use this to stop the propogation of the stanza though the handler chain.
219
+ #
220
+ # @example
221
+ # Ignore all IQ stanzas
222
+ #
223
+ # before(:iq) { halt }
105
224
  def halt
106
225
  throw :halt
107
226
  end
108
227
 
109
- ##
110
228
  # Pass responsibility to the next handler
229
+ #
230
+ # Use this to jump out of the current handler and let the next registered
231
+ # handler take care of the stanza
232
+ #
233
+ # @example
234
+ # This is contrive and should be handled with guards, but pass a message
235
+ # to the next handler based on the content
236
+ #
237
+ # message { |s| puts "message caught" }
238
+ # message { |s| pass if s.body =~ /pass along/ }
111
239
  def pass
112
240
  throw :pass
113
241
  end
114
242
 
115
- ##
116
243
  # Request items or info from an entity
117
- # discover (items|info), [jid], [node] do |response|
118
- # end
244
+ # discover (items|info), [jid], [node] do |response|
245
+ # end
119
246
  def discover(what, who, where, &callback)
120
247
  stanza = Blather::Stanza.class_from_registration(:query, "http://jabber.org/protocol/disco##{what}").new
121
248
  stanza.to = who
@@ -125,10 +252,7 @@ module Blather
125
252
  client.write stanza
126
253
  end
127
254
 
128
- ##
129
- # Checks to see if the method is part of the handlers list.
130
- # If so it creates a handler, otherwise it'll pass it back
131
- # to Ruby's method_missing handler
255
+ # Generate a method for every stanza handler that exists.
132
256
  Blather::Stanza.handler_list.each do |handler_name|
133
257
  module_eval <<-METHOD, __FILE__, __LINE__
134
258
  def #{handler_name}(*args, &callback)
@@ -136,5 +260,5 @@ module Blather
136
260
  end
137
261
  METHOD
138
262
  end
139
- end #DSL
140
- end #Blather
263
+ end # DSL
264
+ end # Blather
@@ -4,31 +4,36 @@ module DSL
4
4
  class PubSub
5
5
  attr_accessor :host
6
6
 
7
+ # Create a new pubsub DSL
8
+ #
9
+ # @param [Blather::Client] client the client who's connection will be used
10
+ # @param [#to_s] host the PubSub host
7
11
  def initialize(client, host)
8
12
  @client = client
9
13
  @host = host
10
14
  end
11
15
 
12
- ##
13
16
  # Retrieve Affiliations
14
- # Yields a hash of affiliations in the form:
15
- # {:aff_type => ['node1', 'node2']}
17
+ #
18
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
19
+ # @yield [Hash] affiliations See {Blather::Stanza::PubSub::Affiliations#list}
16
20
  def affiliations(host = nil, &callback)
17
21
  request Stanza::PubSub::Affiliations.new(:get, send_to(host)), :list, callback
18
22
  end
19
23
 
20
- ##
21
24
  # Retrieve Subscriptions
22
- # Yields a hash of subscriptions in the form:
23
- # {:sub_type => [{:node => 'node1', :jid => 'j@d'}]}
25
+ #
26
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
27
+ # @yield [Hash] affiliations See {Blather::Stanza::PubSub::Subscriptions#list}
24
28
  def subscriptions(host = nil, &callback)
25
29
  request Stanza::PubSub::Subscriptions.new(:get, send_to(host)), :list, callback
26
30
  end
27
31
 
28
- ##
29
32
  # Discover Nodes
30
- # Yields a list of DiscoItem::Item objects
31
- # * +path+ is the node's path. Default is '/'
33
+ #
34
+ # @param [#to_s] path the node path
35
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
36
+ # @yield [Array<Blather::Stanza::DiscoItems::Item>] items
32
37
  def nodes(path = nil, host = nil, &callback)
33
38
  path ||= '/'
34
39
  stanza = Stanza::DiscoItems.new(:get, path)
@@ -36,91 +41,118 @@ module DSL
36
41
  request stanza, :items, callback
37
42
  end
38
43
 
39
- ##
40
44
  # Discover node information
41
- # Yields a DiscoInfo node
42
- # * +path+ is the node's path
45
+ #
46
+ # @param [#to_s] path the node path
47
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
48
+ # @yield [Blather::Stanza::DiscoInfo>] info
43
49
  def node(path, host = nil, &callback)
44
50
  stanza = Stanza::DiscoInfo.new(:get, path)
45
51
  stanza.to = send_to(host)
46
52
  request stanza, nil, callback
47
53
  end
48
54
 
49
- ##
50
55
  # Retrieve items for a node
51
- # * +path+ is the node's path
52
- # * +list+ can be an array of items to retrieve
53
- # * +max+ can be the maximum number of items to return
56
+ #
57
+ # @param [#to_s] path the node path
58
+ # @param [Array<#to_s>] list a list of IDs to retrieve
59
+ # @param [Fixnum, #to_s] max the maximum number of items to return
60
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
61
+ # @yield [Array<Blather::Stanza::PubSub::PubSubItem>] items see {Blather::Stanza::PubSub::Items#items}
54
62
  def items(path, list = [], max = nil, host = nil, &callback)
55
- request Stanza::PubSub::Items.request(send_to(host), path, list, max), :items, callback
63
+ request(
64
+ Stanza::PubSub::Items.request(send_to(host), path, list, max),
65
+ :items,
66
+ callback
67
+ )
56
68
  end
57
69
 
58
- ##
59
70
  # Subscribe to a node
60
- # Yields the resulting Subscription object
61
- # * +node+ is the node to subscribe to
62
- # * +jid+ is the jid that should be used. Defaults to the stripped current JID
71
+ #
72
+ # @param [#to_s] node the node to subscribe to
73
+ # @param [Blather::JID, #to_s] jid is the jid that should be used.
74
+ # Defaults to the stripped current JID
75
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
76
+ # @yield [Blather::Stanza] stanza the reply stanza
63
77
  def subscribe(node, jid = nil, host = nil)
64
78
  jid ||= client.jid.stripped
65
- request(Stanza::PubSub::Subscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
79
+ stanza = Stanza::PubSub::Subscribe.new(:set, send_to(host), node, jid)
80
+ request(stanza) { |n| yield n if block_given? }
66
81
  end
67
82
 
68
- ##
69
83
  # Unsubscribe from a node
70
- # Yields the resulting Unsubscribe object
71
- # * +node+ is the node to subscribe to
72
- # * +jid+ is the jid that should be used. Defaults to the stripped current JID
84
+ #
85
+ # @param [#to_s] node the node to unsubscribe from
86
+ # @param [Blather::JID, #to_s] jid is the jid that should be used.
87
+ # Defaults to the stripped current JID
88
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
89
+ # @yield [Blather::Stanza] stanza the reply stanza
73
90
  def unsubscribe(node, jid = nil, host = nil)
74
91
  jid ||= client.jid.stripped
75
- request(Stanza::PubSub::Unsubscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
92
+ stanza = Stanza::PubSub::Unsubscribe.new(:set, send_to(host), node, jid)
93
+ request(stanza) { |n| yield n if block_given? }
76
94
  end
77
95
 
78
- ##
79
96
  # Publish an item to a node
80
- # Yields the resulting Publish node
81
- # * +node+ is the node to publish to
82
- # * +payload+ is the payload to send (see Blather::Stanza::PubSub::Publish for details)
97
+ #
98
+ # @param [#to_s] node the node to publish to
99
+ # @param [#to_s] payload the payload to send see {Blather::Stanza::PubSub::Publish}
100
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
101
+ # @yield [Blather::Stanza] stanza the reply stanza
83
102
  def publish(node, payload, host = nil)
84
- request(Stanza::PubSub::Publish.new(send_to(host), node, :set, payload)) { |n| yield n if block_given? }
103
+ stanza = Stanza::PubSub::Publish.new(send_to(host), node, :set, payload)
104
+ request(stanza) { |n| yield n if block_given? }
85
105
  end
86
106
 
87
- ##
88
107
  # Delete items from a node
89
- # Yields the resulting node
90
- # * +node+ is the node to retract items from
91
- # * +ids+ is a list of ids to retract. This can also be a single id
108
+ #
109
+ # @param [#to_s] node the node to delete from
110
+ # @param [Array<#to_s>] ids a list of ids to delete
111
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
112
+ # @yield [Blather::Stanza] stanza the reply stanza
92
113
  def retract(node, ids = [], host = nil)
93
- request(Stanza::PubSub::Retract.new(send_to(host), node, :set, ids)) { |n| yield n if block_given? }
114
+ stanza = Stanza::PubSub::Retract.new(send_to(host), node, :set, ids)
115
+ request(stanza) { |n| yield n if block_given? }
94
116
  end
95
117
 
96
- ##
97
118
  # Create a node
98
- # Yields the resulting node
99
- # This does not (yet) handle configuration
100
- # * +node+ is the node to create
119
+ #
120
+ # @param [#to_s] node the node to create
121
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
122
+ # @yield [Blather::Stanza] stanza the reply stanza
101
123
  def create(node, host = nil)
102
- request(Stanza::PubSub::Create.new(:set, send_to(host), node)) { |n| yield n if block_given? }
124
+ stanza = Stanza::PubSub::Create.new(:set, send_to(host), node)
125
+ request(stanza) { |n| yield n if block_given? }
103
126
  end
104
127
 
105
- ##
106
128
  # Purge all node items
107
- # Yields the resulting node
108
- # * +node+ is the node to purge
129
+ #
130
+ # @param [#to_s] node the node to purge
131
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
132
+ # @yield [Blather::Stanza] stanza the reply stanza
109
133
  def purge(node, host = nil)
110
- request(Stanza::PubSubOwner::Purge.new(:set, send_to(host), node)) { |n| yield n if block_given? }
134
+ stanza = Stanza::PubSubOwner::Purge.new(:set, send_to(host), node)
135
+ request(stanza) { |n| yield n if block_given? }
111
136
  end
112
137
 
113
- ##
114
138
  # Delete a node
115
- # Yields the resulting node
116
- # * +node+ is the node to delete
139
+ #
140
+ # @param [#to_s] node the node to delete
141
+ # @param [#to_s] host the PubSub host (defaults to the initialized host)
142
+ # @yield [Blather::Stanza] stanza the reply stanza
117
143
  def delete(node, host = nil)
118
- request(Stanza::PubSubOwner::Delete.new(:set, send_to(host), node)) { |n| yield n if block_given? }
144
+ stanza = Stanza::PubSubOwner::Delete.new(:set, send_to(host), node)
145
+ request(stanza) { |n| yield n if block_given? }
119
146
  end
120
147
 
121
148
  private
122
149
  def request(node, method = nil, callback = nil, &block)
123
- block = lambda { |node| callback.call(method ? node.__send__(method) : node) } unless block_given?
150
+ unless block_given?
151
+ block = lambda do |node|
152
+ callback.call(method ? node.__send__(method) : node)
153
+ end
154
+ end
155
+
124
156
  client.write_with_handler(node, &block)
125
157
  end
126
158
 
@@ -132,7 +164,7 @@ module DSL
132
164
  def client
133
165
  @client
134
166
  end
135
- end
167
+ end # PubSub
136
168
 
137
- end
138
- end
169
+ end # DSL
170
+ end # Blather