Class: Perfume::Promise
- Inherits:
-
Service
- Object
- SuperObject
- Service
- Perfume::Promise
- Defined in:
- lib/perfume/promise.rb
Overview
Public: Very often we’re in a situation that we have to catch and eventuall log some errors, or even more, solely catch errors for purpose of logging. Other times we must perform multiple actions in different places according to the results produces by our method or service. We’d normally have to pass these results around deppening our stack trace. Here comes this a bit twisted implementation of a promise. Maybe twisted is wrong description, it’s rather simplified. It’s not parallel, it’s simple to the bones. It just allows you to define three kinds of callbacks: before call, on success and on failure of course. Since it inherits from our own Service, it essentially is one with own logging and access to class level call method.
Here’s few interesting properties:
-
Define your logic in #call! method. Yes call with bang.
class FindWally < Perfume::Promise NotFoundWarning = Class.new(Warning) def call! Wally.latest_location.tap do |location| raise NotFoundWarning, "No idea where is Wally!" if location.nil? end end end -
Failures are dependent on the kind of error thrown. It means that the flow is directed by raised errors. Slow you might say, but benchmarking this shows that the overhead is negligible in real life apps. This also allows a nifty trick. Look at the example of ‘FindWally` above. Why there’s ‘NotFoundWarning` inhertiting from magical `Warning` class? The `Warning` is bundled into each new promise defined. This errors are not thrown like regular exceptions. Instead they’re handled and logged as warnings. This error will be passed to our ‘failure` callbacks as well. Check example:
FindWally.call do |_location| raise StandardError, "Something went wrong!" endThis one raises ‘StandardError`, while this one:
find_wally = FindWally.new find_wally.failure { |err| puts err. } find_wally.call { |_location| raise FindWally::Warning, "Uuups!" }Will log WARNING with “Uuups!” message.
-
Block passed to call is added to on success callbacks:
FindWally.call do |location| puts location end $ "Madrid"
Constant Summary collapse
- Warning =
Class.new(Exception)
Class Method Summary collapse
Instance Method Summary collapse
- #before(&block) ⇒ Object
-
#call(&block) ⇒ Object
Pubic: Safely executes your logic defined in call!, taking care that all callbacks are properly called.
-
#call! ⇒ Object
Public: Your logic goes here.
- #failure(&block) ⇒ Object
- #failure? ⇒ Boolean
-
#initialize ⇒ Promise
constructor
A new instance of Promise.
- #success(&block) ⇒ Object
- #success? ⇒ Boolean
Methods inherited from Service
Methods included from Gallus::Logging
Methods inherited from SuperObject
args, args_accessor, args_reader, args_writer, #defaults, #init, init_args
Constructor Details
#initialize ⇒ Promise
Returns a new instance of Promise.
64 65 66 67 68 69 70 |
# File 'lib/perfume/promise.rb', line 64 def initialize(*) super @__before = [] @__on_success = [] @__on_failure = [] end |
Class Method Details
.inherited(child) ⇒ Object
60 61 62 |
# File 'lib/perfume/promise.rb', line 60 def self.inherited(child) child.const_set(:Warning, Warning) end |
Instance Method Details
#before(&block) ⇒ Object
72 73 74 75 |
# File 'lib/perfume/promise.rb', line 72 def before(&block) @__before << block self end |
#call(&block) ⇒ Object
Pubic: Safely executes your logic defined in call!, taking care that all callbacks are properly called.
103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/perfume/promise.rb', line 103 def call(&block) @__ok = false @__before.each(&:call) success_callbacks = @__on_success + [block] call!.tap { |result| success_callbacks.compact.each { |callback| callback.call(result) } } @__ok = true self rescue Warning => err log.warn(err) @__on_failure.each { |callback| callback.call(err) } return nil end |
#call! ⇒ Object
Public: Your logic goes here. Flow is broken by raising an exception of local Error class or child classes. Any return value will be passed to on-success callbacks.
97 98 99 |
# File 'lib/perfume/promise.rb', line 97 def call! raise NotImplementedError end |
#failure(&block) ⇒ Object
82 83 84 85 |
# File 'lib/perfume/promise.rb', line 82 def failure(&block) @__on_failure << block self end |
#failure? ⇒ Boolean
91 92 93 |
# File 'lib/perfume/promise.rb', line 91 def failure? !success? end |
#success(&block) ⇒ Object
77 78 79 80 |
# File 'lib/perfume/promise.rb', line 77 def success(&block) @__on_success << block self end |
#success? ⇒ Boolean
87 88 89 |
# File 'lib/perfume/promise.rb', line 87 def success? @__ok end |