deferrable_gratification 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
@@ -19,6 +19,19 @@ module DeferrableGratification
|
|
19
19
|
# Allow DG.const, DG.failure etc
|
20
20
|
extend Primitives
|
21
21
|
|
22
|
+
# Exception passed to errbacks by {Combinators#guard} if the arguments to
|
23
|
+
# +Deferrable#succeed+ fail the supplied predicate.
|
24
|
+
class GuardFailed < RuntimeError
|
25
|
+
attr_reader :reason
|
26
|
+
attr_reader :args
|
27
|
+
|
28
|
+
def initialize(reason, args)
|
29
|
+
@reason = reason || 'guard failed'
|
30
|
+
@args = args
|
31
|
+
super("#{@args.inspect}: #{@reason}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
# Bestow DG goodness upon an existing module or class.
|
23
36
|
#
|
24
37
|
# N.B. calling this on a module won't enhance any classes that have already
|
@@ -165,6 +165,58 @@ module DeferrableGratification
|
|
165
165
|
end
|
166
166
|
|
167
167
|
|
168
|
+
# If this Deferrable succeeds, ensure that the arguments passed to
|
169
|
+
# +Deferrable#succeed+ meet certain criteria (specified by passing a
|
170
|
+
# predicate as a block). If they do, subsequently defined callbacks will
|
171
|
+
# fire as normal, receiving the same arguments; if they do not, this
|
172
|
+
# Deferrable will fail instead, calling its errbacks with a {GuardFailed}
|
173
|
+
# exception.
|
174
|
+
#
|
175
|
+
# This follows the usual Deferrable semantics of calling +Deferrable#fail+
|
176
|
+
# inside a callback: any callbacks defined *before* the call to {#guard}
|
177
|
+
# will still execute as normal, but those defined *after* the call to
|
178
|
+
# {#guard} will only execute if the predicate returns truthy.
|
179
|
+
#
|
180
|
+
# Multiple successive calls to {#guard} will work as expected: the
|
181
|
+
# predicates will be evaluated in order, stopping as soon as any of them
|
182
|
+
# returns falsy, and subsequent callbacks will fire only if all the
|
183
|
+
# predicates pass.
|
184
|
+
#
|
185
|
+
# If instead of returning a boolean, the predicate raises an exception,
|
186
|
+
# the Deferrable will fail, but errbacks will receive the exception raised
|
187
|
+
# instead of {GuardFailed}. You could use this to indicate the reason for
|
188
|
+
# failure in a complex guard expression; however the same intent might be
|
189
|
+
# more clearly expressed by multiple guard expressions with appropriate
|
190
|
+
# reason messages.
|
191
|
+
#
|
192
|
+
# @param [String] reason optional description of the reason for the guard:
|
193
|
+
# specifying this will both serve as code
|
194
|
+
# documentation, and be included in the
|
195
|
+
# {GuardFailed} exception for error handling
|
196
|
+
# purposes.
|
197
|
+
#
|
198
|
+
# @yieldparam *args the arguments passed to callbacks if this Deferrable
|
199
|
+
# succeeds.
|
200
|
+
# @yieldreturn [Boolean] +true+ if subsequent callbacks should fire (with
|
201
|
+
# the same arguments); +false+ if instead errbacks
|
202
|
+
# should fire.
|
203
|
+
#
|
204
|
+
# @raise [ArgumentError] if called without a predicate
|
205
|
+
def guard(reason = nil, &block)
|
206
|
+
raise ArgumentError, 'must be called with a block' unless block_given?
|
207
|
+
callback do |*callback_args|
|
208
|
+
begin
|
209
|
+
unless block.call(*callback_args)
|
210
|
+
raise ::DeferrableGratification::GuardFailed.new(reason, callback_args)
|
211
|
+
end
|
212
|
+
rescue => exception
|
213
|
+
fail(exception)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
self
|
217
|
+
end
|
218
|
+
|
219
|
+
|
168
220
|
# Boilerplate hook to extend {ClassMethods}.
|
169
221
|
def self.included(base)
|
170
222
|
base.send :extend, ClassMethods
|
@@ -30,5 +30,16 @@ module DeferrableGratification
|
|
30
30
|
super(&block)
|
31
31
|
self
|
32
32
|
end
|
33
|
+
|
34
|
+
# Ensure that if this Deferrable doesn't either succeed or fail within the
|
35
|
+
# timeout, it will call its errback with no parameters.
|
36
|
+
#
|
37
|
+
# @return [Deferrable, Fluent] +self+
|
38
|
+
#
|
39
|
+
# @see EventMachine::Deferrable#timeout
|
40
|
+
def timeout(seconds)
|
41
|
+
super(seconds)
|
42
|
+
self
|
43
|
+
end
|
33
44
|
end
|
34
45
|
end
|
@@ -12,20 +12,39 @@ module DeferrableGratification
|
|
12
12
|
# {DeferrableGratification} extends this module, and thus the methods here
|
13
13
|
# are accessible via the {DG} alias.
|
14
14
|
module Primitives
|
15
|
-
# Return a Deferrable which immediately succeeds
|
15
|
+
# Return a Deferrable which immediately succeeds, passing 0 or more values
|
16
|
+
# to callbacks.
|
17
|
+
def success(*values)
|
18
|
+
blank.tap {|d| d.succeed(*values) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return a Deferrable which immediately succeeds, passing a constant value
|
22
|
+
# to callbacks.
|
16
23
|
def const(value)
|
17
|
-
|
24
|
+
success(value)
|
18
25
|
end
|
19
26
|
|
20
27
|
# Return a Deferrable which immediately fails with an exception.
|
21
|
-
|
28
|
+
#
|
29
|
+
# @overload failure(message)
|
30
|
+
# Passes +RuntimeError.new(message)+ to errbacks.
|
31
|
+
# @overload failure(exception_class)
|
32
|
+
# Passes +exception_class.new+ to errbacks.
|
33
|
+
# @overload failure(exception_class, message)
|
34
|
+
# Passes +exception_class.new(message)+ to errbacks.
|
35
|
+
# @overload failure(exception)
|
36
|
+
# Passes +exception+ to errbacks.
|
37
|
+
def failure(exception_class_or_message, message_or_nil = nil)
|
22
38
|
blank.tap do |d|
|
23
39
|
d.fail(
|
24
|
-
case
|
40
|
+
case exception_class_or_message
|
41
|
+
when Exception
|
42
|
+
raise ArgumentError, "can't specify both exception and message" if message_or_nil
|
43
|
+
exception_class_or_message
|
25
44
|
when Class
|
26
|
-
|
45
|
+
exception_class_or_message.new(message_or_nil)
|
27
46
|
else
|
28
|
-
RuntimeError.new(
|
47
|
+
RuntimeError.new(exception_class_or_message.to_s)
|
29
48
|
end)
|
30
49
|
end
|
31
50
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deferrable_gratification
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sam Stokes
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-03-25 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -152,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
152
|
requirements: []
|
153
153
|
|
154
154
|
rubyforge_project:
|
155
|
-
rubygems_version: 1.
|
155
|
+
rubygems_version: 1.4.2
|
156
156
|
signing_key:
|
157
157
|
specification_version: 3
|
158
158
|
summary: Makes evented programming easier with composition and abstraction.
|