blather 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,13 @@
1
- # develop
1
+ # [develop](https://github.com/sprsquish/blather/compare/master...develop)
2
2
 
3
- # v0.7.0
3
+ # [v0.7.1](https://github.com/sprsquish/blather/compare/v0.7.0...v0.7.1) - [2012-04-29](https://rubygems.org/gems/blather/versions/0.7.1)
4
+ * Documentation updates
5
+ * Bugfix(benlangfeld): Relax Nokogiri dependency to allow 1.5
6
+ * Bugfix(benlangfeld): Fix some nokogiri 1.5 related bugs on JRuby (some remain)
7
+ * Bugfix(benlangfeld): Set namespaces correctly on some tricky nodes
8
+ * Bugfix(benlangfeld): Ensure all presence sub-types trigger the correct handlers
9
+
10
+ # [v0.7.0](https://github.com/sprsquish/blather/compare/v0.6.2...v0.7.0) - [2012-03-15](https://rubygems.org/gems/blather/versions/0.7.0)
4
11
  * Change(benlangfeld): Drop Ruby 1.8.7 compatability
5
12
  * Change(bklang): Remove the wire log, which duplicated the parsed logging
6
13
  * Feature(benlangfeld): Stanza handlers are now executed outside of the EM reactor, so it is not blocked on stanza processing
@@ -10,34 +17,34 @@
10
17
  * Bugfix(benlangfeld): Presence stanzas are now composed on import, including all children
11
18
  * Bugfix(mtrudel): JIDs in roster item stanzas are now stripped of resources
12
19
 
13
- # v0.6.2
14
- * Feature(benlangfeld): Add password support to MUCUser
15
- * Feature(benlangfeld): Add support for invitation elements to MUCUser messages
20
+ # [v0.6.2](https://github.com/sprsquish/blather/compare/v0.6.1...v0.6.2) - [2012-02-28](https://rubygems.org/gems/blather/versions/0.6.2)
21
+ * Feature(benlangfeld): Add password support to `MUCUser`
22
+ * Feature(benlangfeld): Add support for invitation elements to `MUCUser` messages
16
23
  * Feature(benlangfeld): Add support for MUC invite declines
17
24
  * Bugfix(benlangfeld): Don't implicitly create an invite node when checking invite status
18
25
  * Bugfix(benlangfeld): Ensure that form nodes are not duplicated on muc/muc_user presence stanzas
19
26
 
20
- # v0.6.1
27
+ # [v0.6.1](https://github.com/sprsquish/blather/compare/v0.6.0...v0.6.1) - [2012-02-25](https://rubygems.org/gems/blather/versions/0.6.1)
21
28
  * Bugfix(benlangfeld): Ensure MUC presence nodes (joining) have a form element on creation
22
29
 
23
- # v0.6.0
30
+ # [v0.6.0](https://github.com/sprsquish/blather/compare/v0.5.12...v0.6.0) - [2012-02-24](https://rubygems.org/gems/blather/versions/0.6.0)
24
31
  * Feature(benlangfeld): Very basic MUC and delayed message support
25
32
  * Bugfix(theozaurus): Disable connection timeout timer if client deliberately disconnects
26
- * Bugfix(mtrudel): Fix Roster#each to return roster_items as per documentation
33
+ * Bugfix(mtrudel): Fix `Roster#each` to return roster_items as per documentation
27
34
 
28
- # v0.5.12
35
+ # [v0.5.12](https://github.com/sprsquish/blather/compare/v0.5.11...v0.5.12) - [2012-01-06](https://rubygems.org/gems/blather/versions/0.5.12)
29
36
  * Bugfix(benlangfeld): Allow specifying the connection timeout in DSL setup
30
37
 
31
- # v0.5.11
38
+ # [v0.5.11](https://github.com/sprsquish/blather/compare/v0.5.10...v0.5.11) - [2012-01-06](https://rubygems.org/gems/blather/versions/0.5.11)
32
39
  * Feature(benlangfeld): Allow specifying a connection timeout
33
- * Raise Blather::Stream::ConnectionTimeout if timeout is exceeded
40
+ * Raise `Blather::Stream::ConnectionTimeout` if timeout is exceeded
34
41
  * Default to 180 seconds
35
42
 
36
- # v0.5.10
43
+ # [v0.5.10](https://github.com/sprsquish/blather/compare/v0.5.9...v0.5.10) - [2011-12-02](https://rubygems.org/gems/blather/versions/0.5.10)
37
44
  * Feature(juandebravo): Allow configuring the wire log level
38
45
  * Bugfix(benlangfeld): Checking connection status before the stream is established
39
46
 
40
- # v0.5.9
47
+ # [v0.5.9](https://github.com/sprsquish/blather/compare/v0.5.8...v0.5.9) - [2011-11-24](https://rubygems.org/gems/blather/versions/0.5.9)
41
48
  * Bugfix(benlangfeld): Failed connections now raise a Blather::Stream::ConnectionFailed exception
42
49
  * Bugfix(crohr): Blather now supports EventMachine 1.0
43
50
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Blather [ ![Build status](http://travis-ci.org/sprsquish/blather.png) ](http://travis-ci.org/sprsquish/blather)
2
2
 
3
- XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
3
+ XMPP DSL (and more) for Ruby written on [EventMachine](http://rubyeventmachine.com/) and [Nokogiri](http://nokogiri.org/).
4
4
 
5
5
  ## Features
6
6
 
@@ -10,9 +10,9 @@ XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
10
10
 
11
11
  ## Project Pages
12
12
 
13
- * [Docs](http://blather.squishtech.com)
14
13
  * [GitHub](https://github.com/sprsquish/blather)
15
14
  * [Gemcutter](http://gemcutter.org/gems/blather)
15
+ * [API Documentation](http://rdoc.info/gems/blather/file/README.md)
16
16
  * [Google Group](http://groups.google.com/group/xmpp-blather)
17
17
 
18
18
  # Usage
@@ -23,99 +23,138 @@ XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
23
23
 
24
24
  ## Example
25
25
 
26
- See the examples directory for more advanced examples.
26
+ Blather comes with a DSL that makes writing XMPP bots quick and easy. See the examples directory for more advanced examples.
27
27
 
28
- This will auto-accept any subscription requests and echo back any chat messages.
28
+ ```ruby
29
+ require 'rubygems'
30
+ require 'blather/client'
29
31
 
30
- require 'rubygems'
31
- require 'blather/client'
32
+ setup 'echo@jabber.local', 'echo'
32
33
 
33
- setup 'echo@jabber.local', 'echo'
34
+ # Auto approve subscription requests
35
+ subscription :request? do |s|
36
+ write_to_stream s.approve!
37
+ end
34
38
 
35
- # Auto approve subscription requests
36
- subscription :request? do |s|
37
- write_to_stream s.approve!
38
- end
39
-
40
- # Echo back what was said
41
- message :chat?, :body do |m|
42
- write_to_stream m.reply
43
- end
39
+ # Echo back what was said
40
+ message :chat?, :body do |m|
41
+ write_to_stream m.reply
42
+ end
43
+ ```
44
44
 
45
45
  ## Handlers
46
46
 
47
- Setup handlers by calling their names as methods.
47
+ Handlers let Blather know how you'd like each type of stanza to be well.. handled. Each type of stanza has an associated handler which is part of a handler hierarchy. In the example above we're handling message and subscription stanzas.
48
+
49
+ XMPP is built on top of three main stanza types (presence, message, and iq). All other stanzas are built on these three base types. This creates a natural hierarchy of handlers. For example a subscription stanza is a type of presence stanza and can be processed by a subscription handler or a presence handler. Likewise, a PubSub::Items stanza has its own identifier :pubsub_items but it's also a :pubsub_node, :iq and :staza. Any or each of these could be used to handle the PubSub::Items stanza. If you've done any DOM programming you'll be familiar with this.
50
+
51
+ Incoming stanzas will be handled by the first handler found. Unlike the DOM this will stop the handling bubble unless the handler returns false.
52
+
53
+ The entire handler hierarchy can be seen below.
54
+
55
+ ### Example
56
+
57
+ Here we have a presence handler and a subscription handler. When this script receives a subscription stanza the subscription handler will be notified first. If that handler doesn't know what to do it can return false and let the stanza bubble up to the presence handler.
58
+
59
+ ```ruby
60
+ # Handle all presence stanzas
61
+ presence do |stanza|
62
+ # do stuff
63
+ end
64
+
65
+ # Handle all subscription stanzas
66
+ subscription do |stanza|
67
+ # do stuff
68
+ end
69
+ ```
48
70
 
49
- # Will only be called for messages where #chat? responds positively
50
- # and #body == 'exit'
51
- message :chat?, :body => 'exit'
71
+ Additionally, handlers may be 'guarded'. That is, they may have conditions set declaratively, against which the stanza must match in order to trigger the handler.
72
+
73
+ ```ruby
74
+ # Will only be called for messages where #chat? responds positively
75
+ # and #body == 'exit'
76
+ message :chat?, :body => 'exit'
77
+ ```
52
78
 
53
79
  ### Non-Stanza Handlers
54
80
 
55
81
  So far there are two non-stanza related handlers.
56
82
 
57
- # Called after the connection has been connected. It's good for initializing
58
- # your system.
59
- # DSL:
60
- when_ready {}
61
- # Client:
62
- client.register_handler(:ready) {}
63
-
64
- # Called after the connection has been terminated. Good for teardown or
65
- # automatic reconnection.
66
- # DSL:
67
- disconnected {}
68
- # Client
69
- client.register_handler(:disconnected) {}
70
- # The following will reconnect every time the connection is lost:
71
- disconnected { client.connect }
83
+ ```ruby
84
+ # Called after the connection has been connected. It's good for initializing
85
+ # your system.
86
+ # DSL:
87
+ when_ready {}
88
+ # Client:
89
+ client.register_handler(:ready) {}
90
+
91
+ # Called after the connection has been terminated. Good for teardown or
92
+ # automatic reconnection.
93
+ # DSL:
94
+ disconnected {}
95
+ # Client
96
+ client.register_handler(:disconnected) {}
97
+ # The following will reconnect every time the connection is lost:
98
+ disconnected { client.connect }
99
+ ```
72
100
 
73
101
  ### Handler Guards
74
102
 
75
- Guards act like AND statements. Each condition must be met if the handler is to
103
+ Guards are a concept borrowed from Erlang. They help to better compartmentalize handlers.
104
+
105
+ There are a number of guard types and one bit of special syntax. Guards act like AND statements. Each condition must be met if the handler is to
76
106
  be used.
77
107
 
78
- # Equivalent to saying (stanza.chat? && stanza.body)
79
- message :chat?, :body
108
+ ```ruby
109
+ # Equivalent to saying (stanza.chat? && stanza.body)
110
+ message :chat?, :body
111
+ ```
80
112
 
81
113
  The different types of guards are:
82
114
 
83
- # Symbol
84
- # Checks for a non-false reply to calling the symbol on the stanza
85
- # Equivalent to stanza.chat?
86
- message :chat?
87
-
88
- # Hash with any value (:body => 'exit')
89
- # Calls the key on the stanza and checks for equality
90
- # Equivalent to stanza.body == 'exit'
91
- message :body => 'exit'
92
-
93
- # Hash with regular expression (:body => /exit/)
94
- # Calls the key on the stanza and checks for a match
95
- # Equivalent to stanza.body.match /exit/
96
- message :body => /exit/
97
-
98
- # Hash with array (:name => [:gone, :forbidden])
99
- # Calls the key on the stanza and check for inclusion in the array
100
- # Equivalent to [:gone, :forbidden].include?(stanza.name)
101
- stanza_error :name => [:gone, :fobidden]
102
-
103
- # Proc
104
- # Calls the proc passing in the stanza
105
- # Checks that the ID is modulo 3
106
- message proc { |m| m.id % 3 == 0 }
107
-
108
- # Array
109
- # Use arrays with the previous types effectively turns the guard into
110
- # an OR statement.
111
- # Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
112
- message [{:body => 'foo'}, {:body => 'baz'}]
113
-
114
- # XPath
115
- # Runs the xpath query on the stanza and checks for results
116
- # This guard type cannot be combined with other guards
117
- # Equivalent to !stanza.find('/iq/ns:pubsub', :ns => 'pubsub:namespace').empty?
118
- iq '/iq/ns:pubsub', :ns => 'pubsub:namespace'
115
+ ```ruby
116
+ # Symbol
117
+ # Checks for a non-false reply to calling the symbol on the stanza
118
+ # Equivalent to stanza.chat?
119
+ message :chat?
120
+
121
+ # Hash with any value (:body => 'exit')
122
+ # Calls the key on the stanza and checks for equality
123
+ # Equivalent to stanza.body == 'exit'
124
+ message :body => 'exit'
125
+
126
+ # Hash with regular expression (:body => /exit/)
127
+ # Calls the key on the stanza and checks for a match
128
+ # Equivalent to stanza.body.match /exit/
129
+ message :body => /exit/
130
+
131
+ # Hash with array (:name => [:gone, :forbidden])
132
+ # Calls the key on the stanza and check for inclusion in the array
133
+ # Equivalent to [:gone, :forbidden].include?(stanza.name)
134
+ stanza_error :name => [:gone, :fobidden]
135
+
136
+ # Proc
137
+ # Calls the proc passing in the stanza
138
+ # Checks that the ID is modulo 3
139
+ message proc { |m| m.id % 3 == 0 }
140
+
141
+ # Array
142
+ # Use arrays with the previous types effectively turns the guard into
143
+ # an OR statement.
144
+ # Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
145
+ message [{:body => 'foo'}, {:body => 'baz'}]
146
+
147
+ # XPath
148
+ # Runs the xpath query on the stanza and checks for results
149
+ # This guard type cannot be combined with other guards
150
+ # Equivalent to !stanza.find('/iq/ns:pubsub', :ns => 'pubsub:namespace').empty?
151
+ # It also passes two arguments into the handler block: the stanza and the result
152
+ # of the xpath query.
153
+ iq '/iq/ns:pubsub', :ns => 'pubsub:namespace' do |stanza, xpath_result|
154
+ # stanza will be the original stanza
155
+ # xpath_result will be the pubsub node in the stanza
156
+ end
157
+ ```
119
158
 
120
159
  ### Filters
121
160
 
@@ -123,37 +162,241 @@ Blather provides before and after filters that work much the way regular
123
162
  handlers work. Filters come in a before and after flavor. They're called in
124
163
  order of definition and can be guarded like handlers.
125
164
 
126
- before { |s| "I'm run before any handler" }
127
- before { |s| "I'm run next" }
128
-
129
- before(:message) { |s| "I'm only run in front of message stanzas" }
130
- before(nil, :id => 1) { |s| "I'll only be run when the stanza's ID == 1" }
131
-
132
- # ... handlers
133
-
134
- after { |s| "I'm run after everything" }
135
-
136
- ## On the Command Line:
165
+ ```ruby
166
+ before { |s| "I'm run before any handler" }
167
+ before { |s| "I'm run next" }
168
+
169
+ before(:message) { |s| "I'm only run in front of message stanzas" }
170
+ before(nil, :id => 1) { |s| "I'll only be run when the stanza's ID == 1" }
171
+
172
+ # ... handlers
173
+
174
+ after { |s| "I'm run after everything" }
175
+ ```
176
+
177
+ ### Handlers Hierarchy
178
+
179
+ ```
180
+ stanza
181
+ |- iq
182
+ | |- pubsub_node
183
+ | | |- pubsub_affiliations
184
+ | | |- pubsub_create
185
+ | | |- pubsub_items
186
+ | | |- pubsub_publish
187
+ | | |- pubsub_retract
188
+ | | |- pubsub_subscribe
189
+ | | |- pubsub_subscription
190
+ | | |- pubsub_subscriptions
191
+ | | `- pubsub_unsubscribe
192
+ | |- pubsub_owner
193
+ | | |- pubsub_delete
194
+ | | `- pubsub_purge
195
+ | `- query
196
+ | |- disco_info
197
+ | |- disco_items
198
+ | `- roster
199
+ |- message
200
+ | `- pubsub_event
201
+ `- presence
202
+ |- status
203
+ `- subscription
204
+
205
+ error
206
+ |- argument_error
207
+ |- parse_error
208
+ |- sasl_error
209
+ |- sasl_unknown_mechanism
210
+ |- stanza_error
211
+ |- stream_error
212
+ |- tls_failure
213
+ `- unknown_response_error
214
+ ```
215
+
216
+ ## On the Command Line
137
217
 
138
218
  Default usage is:
139
219
 
140
- [blather_script] [options] node@domain.com/resource password [host] [port]
220
+ ```
221
+ [blather_script] [options] node@domain.com/resource password [host] [port]
222
+ ```
141
223
 
142
224
  Command line options:
143
225
 
144
- -D, --debug Run in debug mode (you will see all XMPP communication)
145
- -d, --daemonize Daemonize the process
146
- --pid=[PID] Write the PID to this file
147
- --log=[LOG] Write to the [LOG] file instead of stdout/stderr
148
- -h, --help Show this message
149
- -v, --version Show version
226
+ ```
227
+ -D, --debug Run in debug mode (you will see all XMPP communication)
228
+ -d, --daemonize Daemonize the process
229
+ --pid=[PID] Write the PID to this file
230
+ --log=[LOG] Write to the [LOG] file instead of stdout/stderr
231
+ -h, --help Show this message
232
+ -v, --version Show version
233
+ ```
150
234
 
151
- ## Health warning:
235
+ ## Health warning
152
236
 
153
237
  Some parts of Blather will allow you to do stupid things that don't conform to XMPP
154
238
  spec. You should exercise caution and read the relevant specifications (indicated in
155
239
  the preamble to most relevant classes).
156
240
 
241
+ ## Spec compliance
242
+
243
+ Blather provides support in one way or another for many XMPP specifications. Below is a list of specifications and the status of support for them in Blather. This list *may not be correct*. If the list indicates a lack of support for a specification you wish to use, you are encouraged to check that this is correct. Likewise, if you find an overstatement of Blather's spec compliance, please point this out. Also note that even without built-in support for a specification, you can still manually construct and parse stanzas alongside use of Blather's built-in helpers.
244
+
245
+ Specification | Support | Notes
246
+ ------------- | ------- | -----
247
+ RFC 6120 | Full |
248
+ RFC 6121 | Full |
249
+ RFC 6122 | Full |
250
+ XEP-0001 | N/A |
251
+ XEP-0002 | N/A |
252
+ XEP-0004 | Partial |
253
+ XEP-0009 | None |
254
+ XEP-0012 | None |
255
+ XEP-0013 | None |
256
+ XEP-0016 | None |
257
+ XEP-0019 | N/A |
258
+ XEP-0020 | Partial |
259
+ XEP-0027 | None |
260
+ XEP-0030 | Partial |
261
+ XEP-0033 | None |
262
+ XEP-0045 | Partial |
263
+ XEP-0047 | None |
264
+ XEP-0048 | None |
265
+ XEP-0049 | None |
266
+ XEP-0050 | Partial |
267
+ XEP-0053 | None |
268
+ XEP-0054 | None |
269
+ XEP-0055 | None |
270
+ XEP-0059 | None |
271
+ XEP-0060 | Partial |
272
+ XEP-0065 | None |
273
+ XEP-0066 | None |
274
+ XEP-0068 | None |
275
+ XEP-0070 | None |
276
+ XEP-0071 | Partial |
277
+ XEP-0072 | None |
278
+ XEP-0076 | None |
279
+ XEP-0077 | None |
280
+ XEP-0079 | None |
281
+ XEP-0080 | None |
282
+ XEP-0082 | None |
283
+ XEP-0083 | None |
284
+ XEP-0084 | None |
285
+ XEP-0085 | Partial |
286
+ XEP-0092 | None |
287
+ XEP-0095 | Partial |
288
+ XEP-0096 | Partial |
289
+ XEP-0100 | None |
290
+ XEP-0106 | None |
291
+ XEP-0107 | None |
292
+ XEP-0108 | None |
293
+ XEP-0114 | None |
294
+ XEP-0115 | Partial |
295
+ XEP-0118 | None |
296
+ XEP-0122 | None |
297
+ XEP-0124 | None |
298
+ XEP-0126 | None |
299
+ XEP-0127 | None |
300
+ XEP-0128 | None |
301
+ XEP-0130 | None |
302
+ XEP-0131 | None |
303
+ XEP-0132 | None |
304
+ XEP-0133 | None |
305
+ XEP-0134 | None |
306
+ XEP-0136 | None |
307
+ XEP-0137 | None |
308
+ XEP-0138 | None |
309
+ XEP-0141 | None |
310
+ XEP-0143 | None |
311
+ XEP-0144 | N/A |
312
+ XEP-0145 | None |
313
+ XEP-0146 | None |
314
+ XEP-0147 | None |
315
+ XEP-0148 | None |
316
+ XEP-0149 | None |
317
+ XEP-0153 | None |
318
+ XEP-0155 | None |
319
+ XEP-0156 | None |
320
+ XEP-0157 | None |
321
+ XEP-0158 | None |
322
+ XEP-0160 | None |
323
+ XEP-0163 | Partial |
324
+ XEP-0166 | None |
325
+ XEP-0167 | None |
326
+ XEP-0169 | None |
327
+ XEP-0170 | None |
328
+ XEP-0171 | None |
329
+ XEP-0172 | None |
330
+ XEP-0174 | None |
331
+ XEP-0175 | None |
332
+ XEP-0176 | None |
333
+ XEP-0177 | None |
334
+ XEP-0178 | None |
335
+ XEP-0182 | N/A |
336
+ XEP-0183 | None |
337
+ XEP-0184 | None |
338
+ XEP-0185 | None |
339
+ XEP-0191 | None |
340
+ XEP-0198 | None |
341
+ XEP-0199 | Partial |
342
+ XEP-0201 | None |
343
+ XEP-0202 | None |
344
+ XEP-0203 | Partial |
345
+ XEP-0205 | None |
346
+ XEP-0206 | None |
347
+ XEP-0207 | None |
348
+ XEP-0220 | None |
349
+ XEP-0221 | None |
350
+ XEP-0222 | None |
351
+ XEP-0223 | None |
352
+ XEP-0224 | None |
353
+ XEP-0227 | None |
354
+ XEP-0229 | None |
355
+ XEP-0231 | None |
356
+ XEP-0233 | None |
357
+ XEP-0234 | None |
358
+ XEP-0239 | None |
359
+ XEP-0242 | None |
360
+ XEP-0243 | None |
361
+ XEP-0245 | None |
362
+ XEP-0249 | None |
363
+ XEP-0256 | None |
364
+ XEP-0258 | None |
365
+ XEP-0260 | None |
366
+ XEP-0261 | None |
367
+ XEP-0262 | None |
368
+ XEP-0263 | None |
369
+ XEP-0266 | None |
370
+ XEP-0267 | None |
371
+ XEP-0270 | None |
372
+ XEP-0273 | None |
373
+ XEP-0277 | None |
374
+ XEP-0278 | None |
375
+ XEP-0280 | None |
376
+ XEP-0288 | None |
377
+ XEP-0292 | None |
378
+ XEP-0293 | None |
379
+ XEP-0294 | None |
380
+ XEP-0295 | None |
381
+ XEP-0296 | None |
382
+ XEP-0297 | None |
383
+ XEP-0298 | None |
384
+ XEP-0299 | None |
385
+ XEP-0300 | None |
386
+ XEP-0301 | None |
387
+ XEP-0302 | None |
388
+ XEP-0303 | None |
389
+ XEP-0304 | None |
390
+ XEP-0305 | None |
391
+ XEP-0306 | None |
392
+ XEP-0307 | None |
393
+ XEP-0308 | None |
394
+ XEP-0309 | None |
395
+ XEP-0310 | None |
396
+ XEP-0311 | None |
397
+ XEP-0312 | None |
398
+
399
+
157
400
  # Contributions
158
401
 
159
402
  All contributions are welcome, even encouraged. However, contributions must be
@@ -167,4 +410,4 @@ than a change set made directly on master.
167
410
 
168
411
  # Copyright
169
412
 
170
- Copyright (c) 2011 Jeff Smick. See LICENSE for details.
413
+ Copyright (c) 2012 Jeff Smick. See LICENSE for details.
@@ -34,8 +34,8 @@ Gem::Specification.new do |s|
34
34
  s.extra_rdoc_files = %w{LICENSE README.md}
35
35
 
36
36
  s.add_dependency "eventmachine", [">= 0.12.6"]
37
- s.add_dependency "nokogiri", ["~> 1.4.0"]
38
- s.add_dependency "niceogiri", ["~> 1.0.0"]
37
+ s.add_dependency "nokogiri", ["~> 1.4"]
38
+ s.add_dependency "niceogiri", ["~> 1.0"]
39
39
  s.add_dependency "activesupport", [">= 3.0.7"]
40
40
  s.add_dependency "girl_friday"
41
41
 
@@ -50,7 +50,8 @@ class StreamError < BlatherError
50
50
  #
51
51
  # @return [Blather::XMPPNode]
52
52
  def to_node
53
- node = XMPPNode.new('stream:error')
53
+ node = XMPPNode.new('error')
54
+ node.namespace = {'stream' => Blather::Stream::STREAM_NS}
54
55
 
55
56
  node << (err = XMPPNode.new(@name, node.document))
56
57
  err.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
@@ -113,11 +113,11 @@ module Blather
113
113
  #
114
114
  # @return [Blather::Stanza::Iq::Roster]
115
115
  def to_stanza(type = nil)
116
- r = Stanza::Iq::Roster.new type
117
- n = Stanza::Iq::Roster::RosterItem.new jid, name, subscription, ask
118
- r.query << n
119
- n.groups = groups
120
- r
116
+ Stanza::Iq::Roster.new type, to_node
117
+ end
118
+
119
+ def to_node
120
+ Stanza::Iq::Roster::RosterItem.new jid, name, subscription, ask, groups
121
121
  end
122
122
 
123
123
  # Compare two RosterItems by their JID
@@ -13,6 +13,7 @@ module Blather
13
13
  @@handler_list = []
14
14
 
15
15
  class_attribute :handler_hierarchy
16
+ attr_writer :handler_hierarchy
16
17
 
17
18
  # Registers a callback onto the callback stack
18
19
  #
@@ -30,6 +31,15 @@ module Blather
30
31
  super name, ns
31
32
  end
32
33
 
34
+ def initialize(*args)
35
+ super
36
+ @handler_hierarchy = []
37
+ end
38
+
39
+ def handler_hierarchy
40
+ @handler_hierarchy + self.class.handler_hierarchy
41
+ end
42
+
33
43
  # The handler stack for the current stanza class
34
44
  #
35
45
  # @return [Array<Symbol>]
@@ -48,6 +48,8 @@ class Iq
48
48
  # This is a convenience class to attach methods to the node
49
49
  class RosterItem < XMPPNode
50
50
 
51
+ register :item, Roster.registered_ns
52
+
51
53
  # Create a new RosterItem
52
54
  # @overload new(XML::Node)
53
55
  # Create a RosterItem by inheriting a node
@@ -61,6 +63,7 @@ class Iq
61
63
  # the RosterItem must be one of
62
64
  # Blather::RosterItem::VALID_SUBSCRIPTION_TYPES
63
65
  # @option opts [:subscribe, nil] :ask the ask value of the RosterItem
66
+ # @option opts [Array<#to_s>] :groups the group names the RosterItem is a member of
64
67
  # @overload new(jid = nil, name = nil, subscription = nil, ask = nil)
65
68
  # @param [Blather::JID, String, nil] jid the JID of the item
66
69
  # @param [String, nil] name the alias to give the JID
@@ -68,7 +71,8 @@ class Iq
68
71
  # RosterItem must be one of
69
72
  # Blather::RosterItem::VALID_SUBSCRIPTION_TYPES
70
73
  # @param [:subscribe, nil] ask the ask value of the RosterItem
71
- def self.new(jid = nil, name = nil, subscription = nil, ask = nil)
74
+ # @param [Array<#to_s>] groups the group names the RosterItem is a member of
75
+ def self.new(jid = nil, name = nil, subscription = nil, ask = nil, groups = nil)
72
76
  new_node = super :item
73
77
 
74
78
  case jid
@@ -79,11 +83,13 @@ class Iq
79
83
  new_node.name = jid[:name]
80
84
  new_node.subscription = jid[:subscription]
81
85
  new_node.ask = jid[:ask]
86
+ new_node.groups = jid[:groups]
82
87
  else
83
88
  new_node.jid = jid
84
89
  new_node.name = name
85
90
  new_node.subscription = subscription
86
91
  new_node.ask = ask
92
+ new_node.groups = groups
87
93
  end
88
94
  new_node
89
95
  end
@@ -39,7 +39,7 @@ class PubSub
39
39
 
40
40
  # Get or create the actual create node on the stanza
41
41
  #
42
- # @return [Balther::XMPPNode]
42
+ # @return [Blather::XMPPNode]
43
43
  def create_node
44
44
  unless create_node = pubsub.find_first('ns:create', :ns => self.class.registered_ns)
45
45
  self.pubsub << (create_node = XMPPNode.new('create', self.document))
@@ -300,10 +300,10 @@ class Stanza
300
300
  #
301
301
  # @param [true, false]
302
302
  def required?
303
- if self.namespace
304
- !self.find_first('ns:required', :ns => self.namespace.href).nil?
303
+ !!if self.namespace
304
+ self.find_first 'ns:required', :ns => self.namespace.href
305
305
  else
306
- !self.find_first('required').nil?
306
+ self.find_first 'required'
307
307
  end
308
308
  end
309
309
 
@@ -311,8 +311,10 @@ class Stanza
311
311
  #
312
312
  # @param [true, false] required the field's required flag
313
313
  def required=(required)
314
- self.remove_children(:required) unless required
315
- self << XMPPNode.new(:required) if required
314
+ return self.remove_children(:required) unless required
315
+
316
+ self << (r = XMPPNode.new(:required))
317
+ r.namespace = self.namespace
316
318
  end
317
319
 
318
320
  # Extract list of option objects
@@ -331,7 +333,7 @@ class Stanza
331
333
  def options=(options)
332
334
  remove_children :option
333
335
  if options
334
- [options].flatten.each { |o| self << Option.new(o) }
336
+ Array(options).each { |o| self << Option.new(o) }
335
337
  end
336
338
  end
337
339
 
@@ -69,7 +69,7 @@ module Blather
69
69
  # to use the domain on the JID
70
70
  # @param [Fixnum, nil] port the port to connect on. Default is the XMPP
71
71
  # default of 5222
72
- # @param [String, nil] certs the trusted cert store in pem format to verify
72
+ # @param [String, nil] certs the trusted cert store in pem format to verify
73
73
  # communication with the server is trusted.
74
74
  # @param [Fixnum, nil] connect_timeout the number of seconds for which to wait for a successful connection
75
75
  def self.start(client, jid, pass, host = nil, port = nil, certs_directory = nil, connect_timeout = nil)
@@ -126,7 +126,7 @@ module Blather
126
126
  # @param [#to_xml, #to_s] stanza the stanza to send over the wire
127
127
  def send(stanza)
128
128
  data = stanza.respond_to?(:to_xml) ? stanza.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML) : stanza.to_s
129
- Blather.log "SENDING: (#{caller[1]}) #{data}"
129
+ Blather.log "SENDING: (#{caller[1]}) #{stanza}"
130
130
  send_data data
131
131
  end
132
132
 
@@ -168,15 +168,15 @@ module Blather
168
168
  send "<stream:error><xml-not-well-formed xmlns='#{StreamError::STREAM_ERR_NS}'/></stream:error>"
169
169
  stop
170
170
  end
171
-
172
- # Called by EM to verify the peer certificate. If a certificate store directory
171
+
172
+ # Called by EM to verify the peer certificate. If a certificate store directory
173
173
  # has not been configured don't worry about peer verification. At least it is encrypted
174
174
  # We Log the certificate so that you can add it to the trusted store easily if desired
175
175
  # @private
176
176
  def ssl_verify_peer(pem)
177
177
  # EM is supposed to close the connection when this returns false,
178
178
  # but it only does that for inbound connections, not when we
179
- # make a connection to another server.
179
+ # make a connection to another server.
180
180
  Blather.log "Checking SSL cert: #{pem}"
181
181
  return true if !@@store
182
182
  @@store.trusted?(pem).tap do |trusted|
@@ -1,3 +1,3 @@
1
1
  module Blather
2
- VERSION = '0.7.0'
2
+ VERSION = '0.7.1'
3
3
  end
@@ -77,6 +77,8 @@ module Blather
77
77
  decorator.decorator_modules.each do |mod|
78
78
  extend mod
79
79
  end
80
+
81
+ @handler_hierarchy.unshift decorator.handler_hierarchy.first
80
82
  end
81
83
  self
82
84
  end
@@ -45,24 +45,28 @@ describe Blather::Stanza::Presence do
45
45
  s = Blather::Stanza::Presence.parse string
46
46
  s.should be_kind_of Blather::Stanza::Presence::C::InstanceMethods
47
47
  s.node.should == 'http://www.chatopus.com'
48
+ s.handler_hierarchy.should include(:c)
48
49
  end
49
50
 
50
51
  it 'creates a Status object when importing a node with type == nil' do
51
52
  s = Blather::Stanza::Presence.parse('<presence/>')
52
53
  s.should be_kind_of Blather::Stanza::Presence::Status::InstanceMethods
53
54
  s.state.should == :available
55
+ s.handler_hierarchy.should include(Blather::Stanza::Presence::Status.registered_name.to_sym)
54
56
  end
55
57
 
56
58
  it 'creates a Status object when importing a node with type == "unavailable"' do
57
59
  s = Blather::Stanza::Presence.parse('<presence type="unavailable"/>')
58
60
  s.should be_kind_of Blather::Stanza::Presence::Status::InstanceMethods
59
61
  s.state.should == :unavailable
62
+ s.handler_hierarchy.should include(Blather::Stanza::Presence::Status.registered_name.to_sym)
60
63
  end
61
64
 
62
65
  it 'creates a Subscription object when importing a node with type == "subscribe"' do
63
66
  s = Blather::Stanza::Presence.parse('<presence type="subscribe"/>')
64
67
  s.should be_kind_of Blather::Stanza::Presence::Subscription::InstanceMethods
65
68
  s.type.should == :subscribe
69
+ s.handler_hierarchy.should include(Blather::Stanza::Presence::Subscription.registered_name.to_sym)
66
70
  end
67
71
 
68
72
  it 'creates a MUC object when importing a node with a form in the MUC namespace' do
@@ -90,6 +94,7 @@ describe Blather::Stanza::Presence do
90
94
  s = Blather::Stanza::Presence.parse string
91
95
  s.should be_kind_of Blather::Stanza::Presence
92
96
  s.type.should == :foo
97
+ s.handler_hierarchy.should include(Blather::Stanza::Presence.registered_name.to_sym)
93
98
  end
94
99
 
95
100
  it 'behaves like a C, a Status, and a MUCUser when all types of children are present' do
@@ -114,5 +119,7 @@ describe Blather::Stanza::Presence do
114
119
  s.state.should == :chat
115
120
  s.node.should == 'http://www.chatopus.com'
116
121
  s.role.should == :participant
122
+ s.handler_hierarchy.should include(Blather::Stanza::Presence::C.registered_name.to_sym)
123
+ s.handler_hierarchy.should include(Blather::Stanza::Presence::Status.registered_name.to_sym)
117
124
  end
118
125
  end
@@ -137,6 +137,10 @@ describe Blather::Stanza::X do
137
137
  end
138
138
 
139
139
  describe Blather::Stanza::X::Field do
140
+ subject { Blather::Stanza::X::Field.new nil }
141
+
142
+ its(:namespace) { subject.href.should be == 'jabber:x:data' }
143
+
140
144
  it 'will auto-inherit nodes' do
141
145
  n = parse_stanza "<field type='text-single' var='music' label='Music from the time of Shakespeare' />"
142
146
  i = Blather::Stanza::X::Field.new n.root
@@ -193,13 +197,10 @@ describe Blather::Stanza::X::Field do
193
197
  n.value.should == 'book2'
194
198
  end
195
199
 
196
- # Option child elements
197
- it 'allows adding of options' do
200
+ it 'allows setting options' do
198
201
  di = Blather::Stanza::X::Field.new nil
199
202
  di.options.size.should == 0
200
- di.options += [{:label => 'Person', :value => 'person'}]
201
- di.options.size.should == 1
202
- di.options += [Blather::Stanza::X::Field::Option.new(*%w[person1 Person1])]
203
+ di.options = [{:label => 'Person', :value => 'person'}, Blather::Stanza::X::Field::Option.new(*%w[person1 Person1])]
203
204
  di.options.size.should == 2
204
205
  end
205
206
 
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.7.0
4
+ version: 0.7.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-15 00:00:00.000000000 Z
12
+ date: 2012-04-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
16
- requirement: &2160912760 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,32 +21,47 @@ dependencies:
21
21
  version: 0.12.6
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2160912760
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.12.6
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: nokogiri
27
- requirement: &2160912200 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
31
36
  - !ruby/object:Gem::Version
32
- version: 1.4.0
37
+ version: '1.4'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *2160912200
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.4'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: niceogiri
38
- requirement: &2160911680 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
42
52
  - !ruby/object:Gem::Version
43
- version: 1.0.0
53
+ version: '1.0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *2160911680
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: activesupport
49
- requirement: &2160911180 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: 3.0.7
55
70
  type: :runtime
56
71
  prerelease: false
57
- version_requirements: *2160911180
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 3.0.7
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: girl_friday
60
- requirement: &2160910780 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,10 +85,15 @@ dependencies:
65
85
  version: '0'
66
86
  type: :runtime
67
87
  prerelease: false
68
- version_requirements: *2160910780
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
69
94
  - !ruby/object:Gem::Dependency
70
95
  name: bundler
71
- requirement: &2160910100 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
72
97
  none: false
73
98
  requirements:
74
99
  - - ~>
@@ -76,10 +101,15 @@ dependencies:
76
101
  version: '1.0'
77
102
  type: :development
78
103
  prerelease: false
79
- version_requirements: *2160910100
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
80
110
  - !ruby/object:Gem::Dependency
81
111
  name: rake
82
- requirement: &2160830340 !ruby/object:Gem::Requirement
112
+ requirement: !ruby/object:Gem::Requirement
83
113
  none: false
84
114
  requirements:
85
115
  - - ! '>='
@@ -87,10 +117,15 @@ dependencies:
87
117
  version: '0'
88
118
  type: :development
89
119
  prerelease: false
90
- version_requirements: *2160830340
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
91
126
  - !ruby/object:Gem::Dependency
92
127
  name: rspec
93
- requirement: &2160829420 !ruby/object:Gem::Requirement
128
+ requirement: !ruby/object:Gem::Requirement
94
129
  none: false
95
130
  requirements:
96
131
  - - ~>
@@ -98,10 +133,15 @@ dependencies:
98
133
  version: '2.7'
99
134
  type: :development
100
135
  prerelease: false
101
- version_requirements: *2160829420
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: '2.7'
102
142
  - !ruby/object:Gem::Dependency
103
143
  name: mocha
104
- requirement: &2160828500 !ruby/object:Gem::Requirement
144
+ requirement: !ruby/object:Gem::Requirement
105
145
  none: false
106
146
  requirements:
107
147
  - - ~>
@@ -109,10 +149,15 @@ dependencies:
109
149
  version: 0.9.12
110
150
  type: :development
111
151
  prerelease: false
112
- version_requirements: *2160828500
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 0.9.12
113
158
  - !ruby/object:Gem::Dependency
114
159
  name: guard-rspec
115
- requirement: &2160828100 !ruby/object:Gem::Requirement
160
+ requirement: !ruby/object:Gem::Requirement
116
161
  none: false
117
162
  requirements:
118
163
  - - ! '>='
@@ -120,10 +165,15 @@ dependencies:
120
165
  version: '0'
121
166
  type: :development
122
167
  prerelease: false
123
- version_requirements: *2160828100
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
124
174
  - !ruby/object:Gem::Dependency
125
175
  name: yard
126
- requirement: &2160827480 !ruby/object:Gem::Requirement
176
+ requirement: !ruby/object:Gem::Requirement
127
177
  none: false
128
178
  requirements:
129
179
  - - ~>
@@ -131,10 +181,15 @@ dependencies:
131
181
  version: 0.6.1
132
182
  type: :development
133
183
  prerelease: false
134
- version_requirements: *2160827480
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ~>
188
+ - !ruby/object:Gem::Version
189
+ version: 0.6.1
135
190
  - !ruby/object:Gem::Dependency
136
191
  name: bluecloth
137
- requirement: &2160826940 !ruby/object:Gem::Requirement
192
+ requirement: !ruby/object:Gem::Requirement
138
193
  none: false
139
194
  requirements:
140
195
  - - ! '>='
@@ -142,7 +197,12 @@ dependencies:
142
197
  version: '0'
143
198
  type: :development
144
199
  prerelease: false
145
- version_requirements: *2160826940
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
146
206
  description: An XMPP DSL for Ruby written on top of EventMachine and Nokogiri
147
207
  email: sprsquish@gmail.com
148
208
  executables: []
@@ -314,7 +374,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
314
374
  version: '0'
315
375
  segments:
316
376
  - 0
317
- hash: -4263563827557354673
377
+ hash: 4196042577194384774
318
378
  required_rubygems_version: !ruby/object:Gem::Requirement
319
379
  none: false
320
380
  requirements:
@@ -323,10 +383,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
323
383
  version: '0'
324
384
  segments:
325
385
  - 0
326
- hash: -4263563827557354673
386
+ hash: 4196042577194384774
327
387
  requirements: []
328
388
  rubyforge_project:
329
- rubygems_version: 1.8.10
389
+ rubygems_version: 1.8.21
330
390
  signing_key:
331
391
  specification_version: 3
332
392
  summary: Simpler XMPP built for speed