deferrable_gratification 0.2.0 → 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.
@@ -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.
|