lib/aasm/base.rb in aasm-4.9.0 vs lib/aasm/base.rb in aasm-4.10.0
- old
+ new
@@ -1,10 +1,9 @@
module AASM
class Base
- attr_reader :klass,
- :state_machine
+ attr_reader :klass, :state_machine
def initialize(klass, name, state_machine, options={}, &block)
@klass = klass
@name = name
# @state_machine = klass.aasm(@name).state_machine
@@ -36,10 +35,13 @@
# allow a AASM::Base sub-class to be used for state machine
configure :with_klass, AASM::Base
configure :enum, nil
+ # Set to true to namespace reader methods and constants
+ configure :namespace, false
+
# make sure to raise an error if no_direct_assignment is enabled
# and attribute is directly assigned though
aasm_name = @name
klass.send :define_method, "#{@state_machine.config.column}=", ->(state_name) do
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
@@ -69,52 +71,58 @@
@state_machine.initial_state
end
end
# define a state
- def state(name, options={})
- @state_machine.add_state(name, klass, options)
+ # args
+ # [0] state
+ # [1] options (or nil)
+ # or
+ # [0] state
+ # [1..] state
+ def state(*args)
+ names, options = interpret_state_args(args)
+ names.each do |name|
+ @state_machine.add_state(name, klass, options)
- if klass.instance_methods.include?("#{name}?")
- warn "#{klass.name}: The aasm state name #{name} is already used!"
- end
+ aasm_name = @name.to_sym
+ state = name.to_sym
- aasm_name = @name
- klass.send :define_method, "#{name}?", ->() do
- aasm(:"#{aasm_name}").current_state == :"#{name}"
- end
+ method_name = namespace? ? "#{namespace}_#{name}" : name
+ safely_define_method klass, "#{method_name}?", -> do
+ aasm(aasm_name).current_state == state
+ end
- unless klass.const_defined?("STATE_#{name.upcase}")
- klass.const_set("STATE_#{name.upcase}", name)
+ const_name = namespace? ? "STATE_#{namespace.upcase}_#{name.upcase}" : "STATE_#{name.upcase}"
+ unless klass.const_defined?(const_name)
+ klass.const_set(const_name, name)
+ end
end
end
# define an event
def event(name, options={}, &block)
@state_machine.add_event(name, options, &block)
- if klass.instance_methods.include?("may_#{name}?".to_sym)
- warn "#{klass.name}: The aasm event name #{name} is already used!"
- end
+ aasm_name = @name.to_sym
+ event = name.to_sym
# an addition over standard aasm so that, before firing an event, you can ask
# may_event? and get back a boolean that tells you whether the guard method
# on the transition will let this happen.
- aasm_name = @name
-
- klass.send :define_method, "may_#{name}?", ->(*args) do
- aasm(:"#{aasm_name}").may_fire_event?(:"#{name}", *args)
+ safely_define_method klass, "may_#{name}?", ->(*args) do
+ aasm(aasm_name).may_fire_event?(event, *args)
end
- klass.send :define_method, "#{name}!", ->(*args, &block) do
- aasm(:"#{aasm_name}").current_event = :"#{name}!"
- aasm_fire_event(:"#{aasm_name}", :"#{name}", {:persist => true}, *args, &block)
+ safely_define_method klass, "#{name}!", ->(*args, &block) do
+ aasm(aasm_name).current_event = :"#{name}!"
+ aasm_fire_event(aasm_name, event, {:persist => true}, *args, &block)
end
- klass.send :define_method, "#{name}", ->(*args, &block) do
- aasm(:"#{aasm_name}").current_event = :"#{name}"
- aasm_fire_event(:"#{aasm_name}", :"#{name}", {:persist => false}, *args, &block)
+ safely_define_method klass, name, ->(*args, &block) do
+ aasm(aasm_name).current_event = event
+ aasm_fire_event(aasm_name, event, {:persist => false}, *args, &block)
end
end
def after_all_transitions(*callbacks, &block)
@state_machine.add_global_callbacks(:after_all_transitions, *callbacks, &block)
@@ -163,10 +171,11 @@
def from_states_for_state(state, options={})
if options[:transition]
@state_machine.events[options[:transition]].transitions_to_state(state).flatten.map(&:from).flatten
else
+
events.map {|e| e.transitions_to_state(state)}.flatten.map(&:from).flatten
end
end
private
@@ -178,9 +187,39 @@
def configure(key, default_value)
if @options.key?(key)
@state_machine.config.send("#{key}=", @options[key])
elsif @state_machine.config.send(key).nil?
@state_machine.config.send("#{key}=", default_value)
+ end
+ end
+
+ def safely_define_method(klass, method_name, method_definition)
+ if klass.instance_methods.include?(method_name.to_sym)
+ warn "#{klass.name}: overriding method '#{method_name}'!"
+ end
+
+ klass.send(:define_method, method_name, method_definition)
+ end
+
+ def namespace?
+ !!@state_machine.config.namespace
+ end
+
+ def namespace
+ if @state_machine.config.namespace == true
+ @name
+ else
+ @state_machine.config.namespace
+ end
+ end
+
+ def interpret_state_args(args)
+ if args.last.is_a?(Hash) && args.size == 2
+ [[args.first], args.last]
+ elsif args.size > 0
+ [args, {}]
+ else
+ raise "count not parse states: #{args}"
end
end
end
end