Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Callback symbols and transition callbacks by convention #241

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 13 additions & 7 deletions lib/workflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,13 @@ def check_transition(event)
end

def run_before_transition(from, to, event, *args, **kwargs)
run_action_callback(:before_transition, from, to, event, *args, **kwargs)
instance_exec(from.name, to.name, event, *args, **kwargs, &spec.before_transition_proc) if
spec.before_transition_proc
end

def run_on_error(error, from, to, event, *args, **kwargs)
run_action_callback(:on_error, error, from, to, event, *args, **kwargs)
if spec.on_error_proc
instance_exec(error, from.name, to.name, event, *args, **kwargs, &spec.on_error_proc)
halt(error.message)
Expand All @@ -184,10 +186,12 @@ def run_on_error(error, from, to, event, *args, **kwargs)
end

def run_on_transition(from, to, event, *args, **kwargs)
run_action_callback(:on_transition, from, to, event, *args, **kwargs)
instance_exec(from.name, to.name, event, *args, **kwargs, &spec.on_transition_proc) if spec.on_transition_proc
end

def run_after_transition(from, to, event, *args, **kwargs)
run_action_callback(:after_transition, from, to, event, *args, **kwargs)
instance_exec(from.name, to.name, event, *args, **kwargs, &spec.after_transition_proc) if
spec.after_transition_proc
end
Expand All @@ -210,23 +214,25 @@ def run_action_callback(action_name, *args, **kwargs)
action = action_name.to_sym
self.send(action, *args, **kwargs) if has_callback?(action)
end

def run_on_entry(state, prior_state, triggering_event, *args, **kwargs)
if state.on_entry
if state.on_entry&.is_a? Proc
instance_exec(prior_state.name, triggering_event, *args, **kwargs, &state.on_entry)
else
hook_name = "on_#{state}_entry"
self.send hook_name, prior_state, triggering_event, *args, **kwargs if has_callback?(hook_name)
[state.on_entry&.to_sym, "on_#{state}_entry"].compact.each do |hook_name|
self.send hook_name, prior_state, triggering_event, *args, **kwargs if has_callback?(hook_name)
end
end
end

def run_on_exit(state, new_state, triggering_event, *args, **kwargs)
if state
if state.on_exit
if state.on_exit&.is_a? Proc
instance_exec(new_state.name, triggering_event, *args, **kwargs, &state.on_exit)
else
hook_name = "on_#{state}_exit"
self.send hook_name, new_state, triggering_event, *args, **kwargs if has_callback?(hook_name)
[state.on_exit&.to_sym, "on_#{state}_exit"].compact.each do |hook_name|
self.send hook_name, new_state, triggering_event, *args, **kwargs if has_callback?(hook_name)
end
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/workflow/specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ def event(name, args = {}, &action)
)
end

def on_entry(&proc)
@scoped_state.on_entry = proc
def on_entry(sym=nil, &proc)
@scoped_state.on_entry = sym || proc
end

def on_exit(&proc)
@scoped_state.on_exit = proc
def on_exit(sym=nil, &proc)
@scoped_state.on_exit = sym || proc
end

def after_transition(&proc)
Expand Down
158 changes: 158 additions & 0 deletions test/symbol_callbacks_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
require File.join(File.dirname(__FILE__), 'test_helper')
require 'workflow'

class SymbolCallbacksTest < Minitest::Test

test "symbol callbacks" do

c = Class.new
c.class_eval do
include Workflow

attr_reader :events

def record(event)
@events ||= []
@events << event
end

def ran?(event)
@events.include? event
end

def clear_events
@events = []
end

def event_1(test)
# puts "running event_1 with arg '#{test}'"
record __method__
end

def before_transition(from, to, triggering_event, *args, **kwargs)
# puts "before_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
record __method__
end

def on_transition(from, to, triggering_event, *args, **kwargs)
# puts "on_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
record __method__
end

def after_transition(from, to, triggering_event, *args, **kwargs)
# puts "after_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
record __method__
end

def event_1_condition?
# puts "event_1_condition? -> true"
record __method__
true
end

def on_state_1_exit(new_state, event, *args)
# puts "on_state_1_exit(#{new_state}, #{event}, #{args})"
record __method__
end

def entering_state_2(prior_state, triggering_event, *args, **kwargs)
# puts "entering_state_2 #{prior_state}, #{triggering_event}, #{args}, #{kwargs}"
record __method__
end

def entering_state_3(prior_state, triggering_event, *args, **kwargs)
# puts "entering_state_3 #{prior_state}, #{triggering_event}, #{args}, #{kwargs}"
record __method__
end

def on_state_2_entry(new_state, event, *args)
# puts "on_state_2_entry(#{new_state}, #{event}, #{args})"
record __method__
end

end

ran_normal = []
hash = {
state_1: {
events: {
event_1: {
transition_to: :state_2,
if: :event_1_condition?,
meta: { e1: 1 }
},
},
meta: { a: 1 }
},
state_2: {
events: {
event_2: {
transition_to: :state_3,
}
},
on_entry: :entering_state_2,
meta: { a: 2 }
},
state_3: {
on_entry: "entering_state_3",
}
}

spec = Workflow::Specification.new do

hash.each_pair do |state_name, state_def|

state state_name, state_def

on_entry state_def[:on_entry] if state_def[:on_entry].present?
on_exit { ran_normal << :on_exit }

state_def[:events]&.each_pair do |event_name, event_def|
event event_name, event_def
end

end

before_transition do |from, to, triggering_event, *args, **kwargs|
ran_normal << :before_transition
end

on_transition do |from, to, triggering_event, *args, **kwargs|
ran_normal << :on_transition
end

after_transition do |from, to, triggering_event, *args, **kwargs|
ran_normal << :after_transition
end

end

c.send :assign_workflow, spec

o = c.new

assert o.state_1?, "Should be state_1"
refute o.state_2?, "Should not be state_2"

o.event_1! "hello"
[:event_1_condition?, :event_1, :entering_state_2, :before_transition, :on_transition, :after_transition].each do |event|
assert o.ran?(event), "Should have run event #{event}"
end

refute o.state_1?, "Should not be state_1"
assert o.state_2?, "Should be state_2"

o.clear_events
o.event_2!
refute o.ran?(:event_1), "Should not have run event_1"
[:entering_state_3, :before_transition, :on_transition, :after_transition].each do |event|
assert o.ran?(event), "Should have run event #{event}"
end

assert ran_normal.include?(:before_transition), "Should have run before_transition proc"
assert ran_normal.include?(:on_transition), "Should have run on_transition proc"
assert ran_normal.include?(:after_transition), "Should have run after_transition proc"
assert ran_normal.include?(:on_exit), "Should have run on_exit proc"

end
end