blather 0.2.3 → 0.3.0
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.
- data/README.rdoc +7 -4
- data/Rakefile +3 -1
- data/examples/print_heirarchy.rb +76 -0
- data/lib/blather.rb +3 -3
- data/lib/blather/client.rb +4 -247
- data/lib/blather/client/client.rb +168 -0
- data/lib/blather/client/dsl.rb +99 -0
- data/lib/blather/errors.rb +5 -0
- data/lib/blather/errors/sasl_error.rb +6 -70
- data/lib/blather/errors/stanza_error.rb +12 -176
- data/lib/blather/errors/stream_error.rb +8 -186
- data/lib/blather/stanza.rb +2 -3
- data/lib/blather/stanza/{iq/disco.rb → disco.rb} +1 -3
- data/lib/blather/stanza/{iq/discos → disco}/disco_info.rb +3 -5
- data/lib/blather/stanza/{iq/discos → disco}/disco_items.rb +0 -2
- data/lib/blather/stanza/iq/query.rb +1 -1
- data/lib/blather/stanza/iq/roster.rb +2 -2
- data/lib/blather/stanza/pubsub/subscriber.rb +64 -0
- data/lib/blather/stream.rb +13 -7
- data/lib/blather/stream/component.rb +1 -1
- data/lib/blather/stream/parser.rb +11 -4
- data/lib/blather/stream/resource.rb +1 -1
- data/lib/blather/stream/sasl.rb +15 -9
- data/lib/blather/xmpp_node.rb +10 -4
- data/spec/blather/client/client_spec.rb +4 -0
- data/spec/blather/client/dsl_spec.rb +4 -0
- data/spec/blather/client_spec.rb +0 -0
- data/spec/blather/errors/sasl_error_spec.rb +2 -25
- data/spec/blather/errors/stanza_error_spec.rb +7 -18
- data/spec/blather/errors/stream_error_spec.rb +4 -15
- data/spec/blather/stanza/{iq/discos → discos}/disco_info_spec.rb +12 -12
- data/spec/blather/stanza/{iq/discos → discos}/disco_items_spec.rb +1 -1
- data/spec/blather/stanza/iq/query_spec.rb +7 -0
- data/spec/blather/stanza/iq/roster_spec.rb +21 -21
- data/spec/blather/stanza/pubsub/subscriber_spec.rb +70 -0
- data/spec/blather/stanza_spec.rb +1 -7
- data/spec/blather/stream/client_spec.rb +36 -7
- data/spec/spec_helper.rb +1 -1
- metadata +16 -18
- data/ext/Makefile +0 -149
- data/ext/mkmf.log +0 -30
- data/ext/push_parser.bundle +0 -0
- data/ext/push_parser.o +0 -0
- data/lib/autotest/discover.rb +0 -1
- data/lib/autotest/spec.rb +0 -60
- data/spec/blather/stanza/pubsub/event_spec.rb +0 -13
- data/spec/build_safe.rb +0 -20
data/README.rdoc
CHANGED
@@ -77,6 +77,11 @@ There are 5 different types of guards:
|
|
77
77
|
# Equivalent to stanza.body.match /exit/
|
78
78
|
message :body => /exit/
|
79
79
|
|
80
|
+
# Hash with array (:name => [:gone, :forbidden])
|
81
|
+
# Calls the key on the stanza and check for inclusion in the array
|
82
|
+
# Equivalent to [:gone, :forbidden].include?(stanza.name)
|
83
|
+
stanza_error :name => [:gone, :fobidden]
|
84
|
+
|
80
85
|
# Proc
|
81
86
|
# Calls the proc passing in the stanza
|
82
87
|
# Checks that the ID is modulo 3
|
@@ -90,14 +95,12 @@ There are 5 different types of guards:
|
|
90
95
|
|
91
96
|
= TODO
|
92
97
|
|
93
|
-
* Cleanup API
|
94
|
-
* Add lambda callback ability to Iq stanzas
|
95
98
|
* Better Documentation
|
96
|
-
*
|
99
|
+
* Add XPath guard that passes the result to the handler
|
100
|
+
* Add Disco the the DSL
|
97
101
|
* PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
|
98
102
|
* More examples (Re-write XMPP4R examples into Blather)
|
99
103
|
|
100
104
|
= License
|
101
105
|
|
102
106
|
Please see LICENSE
|
103
|
-
The LibXML-Ruby license can be found in its directory
|
data/Rakefile
CHANGED
@@ -18,7 +18,9 @@ begin
|
|
18
18
|
gem.add_dependency 'eventmachine', '>= 0.12.6'
|
19
19
|
gem.add_dependency 'libxml-ruby', '>= 1.1.3'
|
20
20
|
|
21
|
-
gem.files = FileList['examples/**/*', 'lib/**/*', 'ext
|
21
|
+
gem.files = FileList['examples/**/*', 'lib/**/*', 'ext/*.{rb,c}'].to_a
|
22
|
+
|
23
|
+
gem.test_files = FileList['spec/**/*.rb']
|
22
24
|
|
23
25
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
24
26
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'blather'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
begin
|
5
|
+
ObjectSpace.each_object(Class.new) {}
|
6
|
+
|
7
|
+
# Exclude this class unless it's a subclass of our supers and is defined.
|
8
|
+
# We check defined? in case we find a removed class that has yet to be
|
9
|
+
# garbage collected. This also fails for anonymous classes -- please
|
10
|
+
# submit a patch if you have a workaround.
|
11
|
+
def subclasses_of(*superclasses) #:nodoc:
|
12
|
+
subclasses = []
|
13
|
+
|
14
|
+
superclasses.each do |sup|
|
15
|
+
ObjectSpace.each_object(class << sup; self; end) do |k|
|
16
|
+
if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
17
|
+
subclasses << k
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subclasses
|
23
|
+
end
|
24
|
+
rescue RuntimeError
|
25
|
+
# JRuby and any implementations which cannot handle the objectspace traversal
|
26
|
+
# above fall back to this implementation
|
27
|
+
def subclasses_of(*superclasses) #:nodoc:
|
28
|
+
subclasses = []
|
29
|
+
|
30
|
+
superclasses.each do |sup|
|
31
|
+
ObjectSpace.each_object(Class) do |k|
|
32
|
+
if superclasses.any? { |superclass| k < superclass } &&
|
33
|
+
(k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
34
|
+
subclasses << k
|
35
|
+
end
|
36
|
+
end
|
37
|
+
subclasses.uniq!
|
38
|
+
end
|
39
|
+
subclasses
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Hash
|
45
|
+
def deep_merge(second)
|
46
|
+
# From: http://www.ruby-forum.com/topic/142809
|
47
|
+
# Author: Stefan Rusterholz
|
48
|
+
merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
49
|
+
self.merge(second, &merger)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
handlers = {}
|
54
|
+
(Object.subclasses_of(Blather::Stanza) + Object.subclasses_of(Blather::BlatherError)).each do |klass|
|
55
|
+
handlers = handlers.deep_merge klass.handler_heirarchy.inject('klass' => klass.to_s.gsub('Blather::', '')) { |h,k| {k.to_s => h} }
|
56
|
+
end
|
57
|
+
|
58
|
+
level = 0
|
59
|
+
runner = proc do |k,v|
|
60
|
+
next if k == 'klass'
|
61
|
+
|
62
|
+
str = ''
|
63
|
+
if level > 0
|
64
|
+
(level - 1).times { str << '| ' }
|
65
|
+
str << '|-- '
|
66
|
+
end
|
67
|
+
|
68
|
+
puts str+k
|
69
|
+
if Hash === v
|
70
|
+
level += 1
|
71
|
+
v.sort.each &runner
|
72
|
+
level -= 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
handlers.sort.each &runner
|
data/lib/blather.rb
CHANGED
@@ -26,9 +26,9 @@ $:.unshift File.join(File.dirname(__FILE__), '..')
|
|
26
26
|
blather/stanza/iq
|
27
27
|
blather/stanza/iq/query
|
28
28
|
blather/stanza/iq/roster
|
29
|
-
blather/stanza/
|
30
|
-
blather/stanza/
|
31
|
-
blather/stanza/
|
29
|
+
blather/stanza/disco
|
30
|
+
blather/stanza/disco/disco_info
|
31
|
+
blather/stanza/disco/disco_items
|
32
32
|
blather/stanza/message
|
33
33
|
blather/stanza/presence
|
34
34
|
blather/stanza/presence/status
|
data/lib/blather/client.rb
CHANGED
@@ -1,256 +1,13 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[
|
2
|
-
|
3
|
-
module Blather #:nodoc:
|
4
|
-
|
5
|
-
class Client #:nodoc:
|
6
|
-
attr_accessor :jid,
|
7
|
-
:roster
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@state = :initializing
|
11
|
-
|
12
|
-
@status = Stanza::Presence::Status.new
|
13
|
-
@handlers = {}
|
14
|
-
@tmp_handlers = {}
|
15
|
-
@roster = Roster.new self
|
16
|
-
|
17
|
-
setup_initial_handlers
|
18
|
-
end
|
19
|
-
|
20
|
-
def setup(jid, password, host = nil, port = 5222)
|
21
|
-
@setup = [JID.new(jid), password, host, port]
|
22
|
-
self
|
23
|
-
end
|
24
|
-
|
25
|
-
def setup?
|
26
|
-
@setup.is_a?(Array) && !@setup.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
def run
|
30
|
-
raise 'Not setup!' unless @setup.is_a?(Array)
|
31
|
-
trap(:INT) { EM.stop }
|
32
|
-
EM.run {
|
33
|
-
klass = @setup[2].node ? Blather::Stream::Client : Blather::Stream::Component
|
34
|
-
klass.start Blather.client, *@setup
|
35
|
-
}
|
36
|
-
|
37
|
-
def temporary_handler(id, &handler)
|
38
|
-
@tmp_handlers[id] = handler
|
39
|
-
end
|
40
|
-
|
41
|
-
def register_handler(type, *guards, &handler)
|
42
|
-
@handlers[type] ||= []
|
43
|
-
@handlers[type] << [guards, handler]
|
44
|
-
end
|
45
|
-
|
46
|
-
def status
|
47
|
-
@status.state
|
48
|
-
end
|
49
|
-
|
50
|
-
def status=(state)
|
51
|
-
state, msg, to = state
|
52
|
-
|
53
|
-
status = Stanza::Presence::Status.new state, msg
|
54
|
-
status.to = to
|
55
|
-
@statustatus unless to
|
56
|
-
|
57
|
-
write status
|
58
|
-
end
|
59
|
-
|
60
|
-
def write(stanza)
|
61
|
-
stanza.from ||= jid if stanza.respond_to?(:from)
|
62
|
-
@stream.send(stanza) if @stream
|
63
|
-
end
|
64
|
-
|
65
|
-
def stream_started(stream)
|
66
|
-
@stream = stream
|
67
|
-
|
68
|
-
#retreive roster
|
69
|
-
if @stream.is_a?(Stream::Component)
|
70
|
-
@state = :ready
|
71
|
-
call_handler_for :ready, nil
|
72
|
-
else
|
73
|
-
write Stanza::Iq::Roster.new
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def stop
|
78
|
-
@stream.close_connection_after_writing
|
79
|
-
end
|
80
|
-
|
81
|
-
def stopped
|
82
|
-
EM.stop
|
83
|
-
end
|
84
|
-
|
85
|
-
def call(stanza)
|
86
|
-
if handler = @tmp_handlers.delete(stanza.id)
|
87
|
-
handler.call stanza
|
88
|
-
else
|
89
|
-
stanza.handler_heirarchy.each do |type|
|
90
|
-
break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def call_handler_for(type, stanza)
|
96
|
-
if @handlers[type]
|
97
|
-
@handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
|
98
|
-
true
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
protected
|
103
|
-
def setup_initial_handlers
|
104
|
-
register_handler :error do |err|
|
105
|
-
raise err
|
106
|
-
end
|
107
|
-
|
108
|
-
register_handler :iq do |iq|
|
109
|
-
write(StanzaError::ServiceUnavailable.new(iq, :cancel).to_node) if [:set, :get].include?(iq.type)
|
110
|
-
end
|
111
|
-
|
112
|
-
register_handler :status do |status|
|
113
|
-
roster[status.from].status = status if roster[status.from]
|
114
|
-
end
|
115
|
-
|
116
|
-
register_handler :roster do |node|
|
117
|
-
roster.process node
|
118
|
-
if @state == :initializing
|
119
|
-
@state = :ready
|
120
|
-
write @status
|
121
|
-
call_handler_for :ready, nil
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
##
|
127
|
-
# If any of the guards returns FALSE this returns true
|
128
|
-
def guarded?(guards, stanza)
|
129
|
-
guards.find do |guard|
|
130
|
-
case guard
|
131
|
-
when Symbol
|
132
|
-
!stanza.__send__(guard)
|
133
|
-
when Array
|
134
|
-
# return FALSE if any item is TRUE
|
135
|
-
!guard.detect { |condition| !guarded?([condition], stanza) }
|
136
|
-
when Hash
|
137
|
-
# return FALSE unless any inequality is found
|
138
|
-
guard.find do |method, value|
|
139
|
-
if value.is_a?(Regexp)
|
140
|
-
!stanza.__send__(method).to_s.match(value)
|
141
|
-
else
|
142
|
-
stanza.__send__(method) != value
|
143
|
-
end
|
144
|
-
end
|
145
|
-
when Proc
|
146
|
-
!guard.call(stanza)
|
147
|
-
else
|
148
|
-
raise "Bad guard: #{guard.inspect}"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
end #Client
|
154
|
-
|
155
|
-
def client
|
156
|
-
@client ||= Client.new
|
157
|
-
end
|
158
|
-
module_function :client
|
159
|
-
end #Blather
|
160
|
-
|
161
|
-
##
|
162
|
-
# Prepare server settings
|
163
|
-
# setup_client [node@domain/resource], [password], [host], [port]
|
164
|
-
# host and port are optional defaulting to the domain in the JID and 5222 respectively
|
165
|
-
def setup_client(jid, password, host = nil, port = 5222)
|
166
|
-
at_exit { Blather.client.setup_client(jid, password, host, port).run }
|
167
|
-
end
|
168
|
-
|
169
|
-
def setup_component(jid, secret, host, port)
|
170
|
-
at_exit { Blather.client.setup_component(jid, secret, host, port).run }
|
171
|
-
end
|
172
|
-
|
173
|
-
##
|
174
|
-
# Shutdown the connection.
|
175
|
-
# Flushes the write buffer then stops EventMachine
|
176
|
-
def shutdown
|
177
|
-
Blather.client.stop
|
178
|
-
end
|
179
|
-
|
180
|
-
##
|
181
|
-
# Set handler for a stanza type
|
182
|
-
def handle(stanza_type, *guards, &block)
|
183
|
-
Blather.client.register_handler stanza_type, *guards, &block
|
184
|
-
end
|
185
|
-
|
186
|
-
##
|
187
|
-
# Wrapper for "handle :ready" (just a bit of syntactic sugar)
|
188
|
-
def when_ready(&block)
|
189
|
-
handle :ready, &block
|
190
|
-
end
|
191
|
-
|
192
|
-
##
|
193
|
-
# Set current status
|
194
|
-
def status(state = nil, msg = nil)
|
195
|
-
Blather.client.status = state, msg
|
196
|
-
end
|
197
|
-
|
198
|
-
##
|
199
|
-
# Direct access to the roster
|
200
|
-
def roster
|
201
|
-
Blather.client.roster
|
202
|
-
end
|
203
|
-
|
204
|
-
##
|
205
|
-
# Write data to the stream
|
206
|
-
# Anything that resonds to #to_s can be paseed to the stream
|
207
|
-
def write(stanza)
|
208
|
-
Blather.client.write(stanza)
|
209
|
-
end
|
210
|
-
|
211
|
-
##
|
212
|
-
# Helper method to make sending basic messages easier
|
213
|
-
# say [jid], [msg]
|
214
|
-
def say(to, msg)
|
215
|
-
Blather.client.write Blather::Stanza::Message.new(to, msg)
|
216
|
-
end
|
217
|
-
|
218
|
-
##
|
219
|
-
# Wrapper to grab the current JID
|
220
|
-
def jid
|
221
|
-
Blather.client.jid
|
222
|
-
end
|
223
|
-
|
224
|
-
##
|
225
|
-
#
|
226
|
-
def discover(what, who, where, &callback)
|
227
|
-
stanza = Blather::Stanza.class_from_registration(:query, "http://jabber.org/protocol/disco##{what}").new
|
228
|
-
stanza.to = who
|
229
|
-
stanza.node = where
|
230
|
-
|
231
|
-
Blather.client.temporary_handler stanza.id, &callback
|
232
|
-
write stanza
|
233
|
-
end
|
234
|
-
|
235
|
-
##
|
236
|
-
# Checks to see if the method is part of the handlers list.
|
237
|
-
# If so it creates a handler, otherwise it'll pass it back
|
238
|
-
# to Ruby's method_missing handler
|
239
|
-
def method_missing(method, *args, &block)
|
240
|
-
if Blather::Stanza.handler_list.include?(method)
|
241
|
-
handle method, *args, &block
|
242
|
-
else
|
243
|
-
super
|
244
|
-
end
|
245
|
-
end
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[client dsl])
|
246
2
|
|
3
|
+
include Blather::DSL
|
247
4
|
|
248
5
|
at_exit do
|
249
|
-
unless
|
6
|
+
unless client.setup?
|
250
7
|
if ARGV.length < 2
|
251
8
|
puts "Run with #{$0} user@server/resource password [host] [port]"
|
252
9
|
else
|
253
|
-
|
10
|
+
client.setup(*ARGV).run
|
254
11
|
end
|
255
12
|
end
|
256
13
|
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. blather])
|
2
|
+
|
3
|
+
module Blather #:nodoc:
|
4
|
+
|
5
|
+
class Client #:nodoc:
|
6
|
+
attr_accessor :jid,
|
7
|
+
:roster
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@state = :initializing
|
11
|
+
|
12
|
+
@status = Stanza::Presence::Status.new
|
13
|
+
@handlers = {}
|
14
|
+
@tmp_handlers = {}
|
15
|
+
@roster = Roster.new self
|
16
|
+
|
17
|
+
setup_initial_handlers
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup?
|
21
|
+
@setup.is_a? Array
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup(jid, password, host = nil, port = nil)
|
25
|
+
@setup = [JID.new(jid), password]
|
26
|
+
@setup << host if host
|
27
|
+
@setup << port if port
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
raise 'not setup!' unless setup?
|
33
|
+
trap(:INT) { EM.stop }
|
34
|
+
EM.run {
|
35
|
+
klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
|
36
|
+
klass.start self, *@setup
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def register_tmp_handler(id, &handler)
|
41
|
+
@tmp_handlers[id] = handler
|
42
|
+
end
|
43
|
+
|
44
|
+
def register_handler(type, *guards, &handler)
|
45
|
+
@handlers[type] ||= []
|
46
|
+
@handlers[type] << [guards, handler]
|
47
|
+
end
|
48
|
+
|
49
|
+
def status
|
50
|
+
@status.state
|
51
|
+
end
|
52
|
+
|
53
|
+
def status=(state)
|
54
|
+
state, msg, to = state
|
55
|
+
|
56
|
+
status = Stanza::Presence::Status.new state, msg
|
57
|
+
status.to = to
|
58
|
+
@status = status unless to
|
59
|
+
|
60
|
+
write status
|
61
|
+
end
|
62
|
+
|
63
|
+
def write(stanza)
|
64
|
+
stanza.from ||= jid if stanza.respond_to?(:from)
|
65
|
+
@stream.send(stanza) if @stream
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_with_handler(stanza, &hanlder)
|
69
|
+
register_tmp_handler stanza.id, &handler
|
70
|
+
write stanza
|
71
|
+
end
|
72
|
+
|
73
|
+
def stream_started(stream)
|
74
|
+
@stream = stream
|
75
|
+
|
76
|
+
#retreive roster
|
77
|
+
if @stream.is_a?(Stream::Component)
|
78
|
+
@state = :ready
|
79
|
+
call_handler_for :ready, nil
|
80
|
+
else
|
81
|
+
r = Stanza::Iq::Roster.new
|
82
|
+
register_tmp_handler r.id do |node|
|
83
|
+
roster.process node
|
84
|
+
@state = :ready
|
85
|
+
write @status
|
86
|
+
call_handler_for :ready, nil
|
87
|
+
end
|
88
|
+
write r
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def stop
|
93
|
+
@stream.close_connection_after_writing
|
94
|
+
end
|
95
|
+
|
96
|
+
def stopped
|
97
|
+
EM.stop
|
98
|
+
end
|
99
|
+
|
100
|
+
def call(stanza)
|
101
|
+
if handler = @tmp_handlers.delete(stanza.id)
|
102
|
+
handler.call stanza
|
103
|
+
else
|
104
|
+
stanza.handler_heirarchy.each do |type|
|
105
|
+
break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def call_handler_for(type, stanza)
|
111
|
+
if @handlers[type]
|
112
|
+
@handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
|
113
|
+
true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
protected
|
118
|
+
def setup_initial_handlers
|
119
|
+
register_handler :error do |err|
|
120
|
+
raise err
|
121
|
+
end
|
122
|
+
|
123
|
+
register_handler :iq do |iq|
|
124
|
+
write(StanzaError.new(iq, 'service-unavailable', :cancel).to_node) if [:set, :get].include?(iq.type)
|
125
|
+
end
|
126
|
+
|
127
|
+
register_handler :status do |status|
|
128
|
+
roster[status.from].status = status if roster[status.from]
|
129
|
+
end
|
130
|
+
|
131
|
+
register_handler :roster do |node|
|
132
|
+
roster.process node
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# If any of the guards returns FALSE this returns true
|
138
|
+
def guarded?(guards, stanza)
|
139
|
+
guards.find do |guard|
|
140
|
+
case guard
|
141
|
+
when Symbol
|
142
|
+
!stanza.__send__(guard)
|
143
|
+
when Array
|
144
|
+
# return FALSE if any item is TRUE
|
145
|
+
!guard.detect { |condition| !guarded?([condition], stanza) }
|
146
|
+
when Hash
|
147
|
+
# return FALSE unless any inequality is found
|
148
|
+
guard.find do |method, test|
|
149
|
+
value = stanza.__send__(method)
|
150
|
+
case test
|
151
|
+
when Regexp
|
152
|
+
!value.to_s.match(test)
|
153
|
+
when Array
|
154
|
+
!test.include? value
|
155
|
+
else
|
156
|
+
test != value
|
157
|
+
end
|
158
|
+
end
|
159
|
+
when Proc
|
160
|
+
!guard.call(stanza)
|
161
|
+
else
|
162
|
+
raise "Bad guard: #{guard.inspect}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end #Client
|
168
|
+
end #Blather
|