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,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