lib/stateful_enum/machine.rb in stateful_enum-0.2.1 vs lib/stateful_enum/machine.rb in stateful_enum-0.3.0
- old
+ new
@@ -1,61 +1,80 @@
module StatefulEnum
class Machine
- def initialize(model, column, states, &block)
+ def initialize(model, column, states, prefix, suffix, &block)
@model, @column, @states, @event_names = model, column, states, []
+ @prefix = if prefix == true
+ "#{column}_"
+ elsif prefix
+ "#{prefix}_"
+ end
+ @suffix = if suffix == true
+ "_#{column}"
+ elsif suffix
+ "_#{suffix}"
+ end
# undef non-verb methods e.g. Model#active!
states.each do |state|
- @model.send :undef_method, "#{state}!"
+ @model.send :undef_method, "#{@prefix}#{state}#{@suffix}!"
end
instance_eval(&block) if block
end
def event(name, &block)
- raise "event: :#{name} has already been defined." if @event_names.include? name
- Event.new @model, @column, @states, name, &block
+ raise ArgumentError, "event: :#{name} has already been defined." if @event_names.include? name
+ Event.new @model, @column, @states, @prefix, @suffix, name, &block
@event_names << name
end
class Event
- def initialize(model, column, states, name, &block)
- @model, @column, @states, @name, @transitions = model, column, states, name, {}
+ def initialize(model, column, states, prefix, suffix, name, &block)
+ @states, @name, @transitions, @before, @after = states, name, {}, nil, nil
instance_eval(&block) if block
- define_transition_methods
- end
+ transitions, before, after = @transitions, @before, @after
+ new_method_name = "#{prefix}#{name}#{suffix}"
- def define_transition_methods
- column, name, transitions, before, after = @column, @name, @transitions, @before, @after
+ # defining event methods
+ model.class_eval do
+ # def assign()
+ detect_enum_conflict! column, new_method_name
+ define_method new_method_name do
+ to, condition = transitions[self.send(column).to_sym]
+ #TODO better error
+ if to && (!condition || instance_exec(&condition))
+ #TODO transaction?
+ instance_eval(&before) if before
+ original_method = self.class.send(:_enum_methods_module).instance_method "#{prefix}#{to}#{suffix}!"
+ ret = original_method.bind(self).call
+ instance_eval(&after) if after
+ ret
+ else
+ false
+ end
+ end
- @model.send(:define_method, name) do
- to, condition = transitions[self.send(column).to_sym]
- #TODO better error
- if to && (!condition || instance_exec(&condition))
- #TODO transaction?
- instance_eval(&before) if before
- ret = self.class.instance_variable_get(:@_enum_methods_module).instance_method("#{to}!").bind(self).call
- instance_eval(&after) if after
- ret
- else
- false
+ # def assign!()
+ detect_enum_conflict! column, "#{new_method_name}!"
+ define_method "#{new_method_name}!" do
+ send(new_method_name) || raise('Invalid transition')
end
- end
- @model.send(:define_method, "#{name}!") do
- send(name) || raise('Invalid transition')
- end
+ # def can_assign?()
+ detect_enum_conflict! column, "can_#{new_method_name}?"
+ define_method "can_#{new_method_name}?" do
+ transitions.has_key? self.send(column).to_sym
+ end
- @model.send(:define_method, "can_#{name}?") do
- transitions.has_key? self.send(column).to_sym
+ # def assign_transition()
+ detect_enum_conflict! column, "#{new_method_name}_transition"
+ define_method "#{new_method_name}_transition" do
+ transitions[self.send(column).to_sym].try! :first
+ end
end
-
- @model.send(:define_method, "#{name}_transition") do
- transitions[self.send(column).to_sym].try! :first
- end
end
def transition(transitions, options = {})
if options.blank?
options[:if] = transitions.delete :if
@@ -66,9 +85,10 @@
end
transitions.each_pair do |from, to|
raise "Undefined state #{to}" unless @states.include? to
Array(from).each do |f|
raise "Undefined state #{f}" unless @states.include? f
+ raise "Duplicate entry: Transition from #{f} to #{@transitions[f].first} has already been defined." if @transitions[f]
@transitions[f] = [to, options[:if]]
end
end
end