blather 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|