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