RubyValve
This gem provide a mechanism for doing easy flow type code pattern. Similar to what's done in the template design pattern.
Installation
Add this line to your application's Gemfile:
gem 'ruby_valve'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruby_valve
Usage
To use RubyValve you can subclass the base class:
require 'ruby_valve'
class Foo < RubyValve::Base
end
Or, you can include RubyValve::Core
require 'ruby_valve'
class Foo
include RubyValve::Core
end
#####step_n methods Next you define a number steps using the naming convention of #step_n for the method name.
class Foo < RubyValve::Base
def step_1
puts "A"
end
def step_2
puts "B"
end
end
After defining #step_n methods you can execute them all by running the #execute method.
Foo.new.execute
A
B
#####skip You can skip a step by using the #skip method
def step_1
puts "A"
skip :step_2, :step_3
end
def step_2
puts "B"
end
def step_3
puts "C"
end
def step_4
puts "D"
end
Foo.new.execute
A
D
#####abort You can have it abort at a certain step and it will not execute the remainder of the steps.
def step_1
puts "A"
end
def step_2
abort "Ug, again?"
end
def step_3
puts "C"
end
def step_4
puts "D"
end
Foo.new.execute
A
You can also have #abort raise an error as well.
def step_1
puts "A"
end
def step_2
abort "Ug, again?", raise: true
end
def step_3
puts "C"
end
def step_4
puts "D"
end
Foo.new.execute
A
RubyValve::AbortError:
Ug
#####step_n_result The result of each #step_n method can be accessed by calling #step_n_result. This allows the sharing of data between methods.
def step_1
"A"
end
def step_2
puts "step 1's result was: #{step_1_result}"
end
Foo.new.execute
step 1's result was: A
#####response The response for each step is recorded in a hash that can be accessed by this method
def step_1
"A"
end
def step_2
"B"
end
foo = Foo.new
foo.execute
foo.result
{:step_1_result=>"A", :step_2_result=>"B"}
###Callbacks RubyValve provides a number of callbacks.
#####before_all
Executes code once before all the steps.
def before_all
puts "..BA"
end
def step_1
"A"
end
def step_2
"B"
end
Foo.new.execute
..BA
A
B
#####before_each Executes code before each step method
def before_each
puts "..BE"
end
def step_1
"A"
end
def step_2
"B"
end
Foo.new.execute
..BE
A
..BE
B
#####after_each Executes code after each step method.
def after_each
puts "..AE"
end
def step_1
"A"
end
def step_2
"B"
end
Foo.new.execute
A
..AE
B
..AE
#####after_success Executes if no abort was triggered or exceptions raised.
def step_1
puts "E"
end
def after_success
puts "Yay!"
end
Foo.new.execute
E
Yay!
#####after_abort Executes if an abort, without a raise, was triggered.
def step_1
abort "call it off"
end
def step_2
puts "E"
end
def after_abort
puts "aborted!"
end
Foo.new.execute
aborted!
#####after_exception and #exception Creating an after_exception method will trigger an automatic rescue when an error is raised. The exception is stored in the exception method.
def step_1
abort "call it off", raise: true
end
def step_2
puts "E"
end
def after_exception
puts exception.message
end
Foo.new.execute
call it off
###execution logs There are a couple of methods that can be used to look at what was executed.
#####executed_steps
This will display each #step_n method that was actually executed.
def step_1
"A"
end
def step_2
"B"
end
def after_each
puts "..AE"
end
foo = Foo.new
foo.execute
foo.executed_steps
[:step_1, :step_2]
#####executed This will display each step and callback method that was executed.
def step_1
"A"
end
def step_2
"B"
end
def after_each
puts "..AE"
end
foo = Foo.new
foo.execute
foo.executed
[:step_1, :after_each, :step_2, :after_each]
##Suggestions
I would recommend encapsulating the logic of what is to be done into methods with names that clearly state the intention of the code. The calling these methods within the steps.
####Example
def step_1
post_paypal_transaction
end
def step_2
store_paypal_result(step_1_result)
end
def step_3
update_transaction_records
end
#=> ACTIONS
def post_paypal_transaction
#code
end
def store_paypal_result(paypal_results)
#code
end
def post_paypal_transaction
#code
end
###Tests Test are implemented in Rspec and use guard as well.
ruby_valve > bundle exec rspec spec