Let's define a simple Result class:
class Result
  def initialize(success: true, data: nil); @success = success; @data = data; end
  def success?; @success == true; end
  def error?; !success?; end
  def data; @data; end
  def self.success(data = nil); new(data: data); end
  def self.error(data = nil); new(success: false, data: data); end
end
and then a Flow class:
class Flow
  attr_accessor :tasks, :result
  def initialize(tasks: [])
    self.tasks = tasks
    self.result = nil
  end
  def step(task)
    self.tasks << task
  end
  def call
    tasks.each do |task|
      begin
        self.data = task.call
        self.result = Result.success(data) unless result.kind_of?(Result)
      rescue => exception
        self.result = Result.error(exception)
      end
      return result if result.error?
    end
    result
  end
end
We can now do some interesting things such as:
flow = Flow.new
flow.step -> { puts '#1' }
flow.step -> { puts '#2'; 3 * 3 }
flow.step -> { puts '#3 (error)'; raise 'foo' }
flow.step -> { puts '#4' }
result = flow.call
result.error? # => true
result.data # => #<RuntimeError: foo>
 

 
    
Top comments (0)