diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-01-31 14:32:26 +0000 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-01-31 14:32:26 +0000 |
commit | ed60021f39f7913537dcad181e4061e423dc6c3d (patch) | |
tree | 86532c43aabe9125422f84b48a899f2672900bf5 /activemodel | |
parent | c6af337d2d6c86792cdc8132224ebe9294d35774 (diff) | |
parent | b3a028259f373fd58fea2171a1e9e8b2fe3e253a (diff) | |
download | rails-ed60021f39f7913537dcad181e4061e423dc6c3d.tar.gz rails-ed60021f39f7913537dcad181e4061e423dc6c3d.tar.bz2 rails-ed60021f39f7913537dcad181e4061e423dc6c3d.zip |
Merge remote branch 'mainstream/master'
Conflicts:
activemodel/lib/active_model/state_machine.rb
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/lib/active_model.rb | 1 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 21 | ||||
-rw-r--r-- | activemodel/lib/active_model/state_machine.rb | 219 | ||||
-rw-r--r-- | activemodel/lib/active_model/state_machine/event.rb | 62 | ||||
-rw-r--r-- | activemodel/lib/active_model/state_machine/machine.rb | 75 | ||||
-rw-r--r-- | activemodel/lib/active_model/state_machine/state.rb | 47 | ||||
-rw-r--r-- | activemodel/lib/active_model/state_machine/state_transition.rb | 40 | ||||
-rw-r--r-- | activemodel/test/cases/state_machine/event_test.rb | 49 | ||||
-rw-r--r-- | activemodel/test/cases/state_machine/machine_test.rb | 43 | ||||
-rw-r--r-- | activemodel/test/cases/state_machine/state_test.rb | 72 | ||||
-rw-r--r-- | activemodel/test/cases/state_machine/state_transition_test.rb | 84 | ||||
-rw-r--r-- | activemodel/test/cases/state_machine_test.rb | 312 | ||||
-rw-r--r-- | activemodel/test/cases/validations/i18n_validation_test.rb | 28 |
13 files changed, 28 insertions, 1025 deletions
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index 6eab00c177..1609075f7e 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -43,7 +43,6 @@ module ActiveModel autoload :Observer, 'active_model/observing' autoload :Observing autoload :Serialization - autoload :StateMachine autoload :TestCase autoload :Translation autoload :VERSION diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 76e6ad93a7..f1d74db5f3 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -242,28 +242,35 @@ module ActiveModel # <li><tt>activemodel.errors.models.admin.blank</tt></li> # <li><tt>activemodel.errors.models.user.attributes.title.blank</tt></li> # <li><tt>activemodel.errors.models.user.blank</tt></li> - # <li><tt>activemodel.errors.messages.blank</tt></li> # <li>any default you provided through the +options+ hash (in the activemodel.errors scope)</li> + # <li><tt>activemodel.errors.messages.blank</tt></li> + # <li><tt>errors.attributes.title.blank</tt></li> + # <li><tt>errors.messages.blank</tt></li> # </ol> def generate_message(attribute, message = :invalid, options = {}) message, options[:default] = options[:default], message if options[:default].is_a?(Symbol) defaults = @base.class.lookup_ancestors.map do |klass| - [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}", - :"models.#{klass.name.underscore}.#{message}" ] + [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{message}", + :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{message}" ] end defaults << options.delete(:default) - defaults = defaults.compact.flatten << :"messages.#{message}" + defaults << :"#{@base.class.i18n_scope}.errors.messages.#{message}" + defaults << :"errors.attributes.#{attribute}.#{message}" + defaults << :"errors.messages.#{message}" + + defaults.compact! + defaults.flatten! key = defaults.shift value = @base.send(:read_attribute_for_validation, attribute) - options = { :default => defaults, + options = { + :default => defaults, :model => @base.class.model_name.human, :attribute => @base.class.human_attribute_name(attribute), - :value => value, - :scope => [:errors] + :value => value }.merge(options) I18n.translate(key, options) diff --git a/activemodel/lib/active_model/state_machine.rb b/activemodel/lib/active_model/state_machine.rb deleted file mode 100644 index 64b91c1659..0000000000 --- a/activemodel/lib/active_model/state_machine.rb +++ /dev/null @@ -1,219 +0,0 @@ -module ActiveModel - - # ActiveModel::StateMachine provides methods that turn your object into a - # finite state machine, able to move from one state to another. - # - # A minimal implementation could be: - # - # class EmailMessage - # include ActiveModel::StateMachine - # - # state_machine do - # state :unread - # state :read - # end - # - # event :open_email do - # transitions :to => :read, :from => :unread - # end - # end - # - # === Examples - # - # class TrafficLight - # include ActiveModel::StateMachine - # - # attr_reader :runners_caught - # - # def initialize - # @runners_caught = 0 - # end - # - # state_machine do - # state :red - # state :green - # state :yellow - # state :blink - # - # event :change_color do - # transitions :to => :red, :from => [:yellow], - # :on_transition => :catch_runners - # transitions :to => :green, :from => [:red] - # transitions :to => :yellow, :from => [:green] - # end - # - # event :defect do - # transitions :to => :blink, :from => [:yellow, :red, :green] - # end - # - # event :repair do - # transitions :to => :red, :from => [:blink] - # end - # end - # - # def catch_runners - # @runners_caught += 1 - # end - # end - # - # light = TrafficLight.new - # light.current_state # => :red - # light.change_color! # => true - # light.current_state # => :green - # light.green? # => true - # light.change_color! # => true - # light.current_state # => :yellow - # light.red? # => false - # light.change_color! # => true - # light.runners_caught # => 1 - # - # * The initial state for TrafficLight is red which is the first state defined. - # - # TrafficLight.state_machine.initial_state # => :red - # - # * Call an event to transition a state machine, e.g. <tt>change_color!</tt>. - # You can call the event with or without the exclamation mark, however, the common Ruby - # idiom is to name methods that directly change the state of the receivier with - # an exclamation mark, so <tt>change_color!</tt> is preferred over <tt>change_color</tt>. - # - # light.current_state #=> :green - # light.change_color! #=> true - # light.current_state #=> :yellow - # - # * On a succesful transition to red (from yellow), the local +catch_runners+ - # method is executed - # - # light.current_state #=> :red - # light.change_color! #=> true - # light.runners_caught #=> 1 - # - # * The object acts differently depending on its current state, for instance, - # the change_color! method has a different action depending on the current - # color of the light - # - # light.change_color! #=> true - # light.current_state #=> :red - # light.change_color! #=> true - # light.current_state #=> :green - # - # * Get the possible events for a state - # - # TrafficLight.state_machine.events_for(:red) # => [:change_color, :defect] - # TrafficLight.state_machine.events_for(:blink) # => [:repair] - # - # The StateMachine also supports the following features : - # - # * Success callbacks on event transition - # - # event :sample, :success => :we_win do - # ... - # end - # - # * Enter and exit callbacks par state - # - # state :open, :enter => [:alert_twitter, :send_emails], :exit => :alert_twitter - # - # * Guards on transition - # - # event :close do - # # You may only close the store if the safe is locked!! - # transitions :to => :closed, :from => :open, :guard => :safe_locked? - # end - # - # * Setting the initial state - # - # state_machine :initial => :yellow do - # ... - # end - # - # * Named the state machine, to have more than one - # - # class Stated - # include ActiveModel::StateMachine - # - # strate_machine :name => :ontest do - # end - # - # state_machine do - # end - # end - # - # # Get the state of the <tt>:ontest</tt> state machine - # stat.current_state(:ontest) - # # Get the initial state - # Stated.state_machine(:ontest).initial_state - # - # * Changing the state - # - # stat.current_state(:default, :astate) # => :astate - # # But you must give the name of the state machine, here <tt>:default</tt> - # - module StateMachine - autoload :Event, 'active_model/state_machine/event' - autoload :Machine, 'active_model/state_machine/machine' - autoload :State, 'active_model/state_machine/state' - autoload :StateTransition, 'active_model/state_machine/state_transition' - - extend ActiveSupport::Concern - - class InvalidTransition < Exception - end - - module ClassMethods - def inherited(klass) - super - klass.state_machines = state_machines - end - - def state_machines - @state_machines ||= {} - end - - def state_machines=(value) - @state_machines = value ? value.dup : nil - end - - def state_machine(name = nil, options = {}, &block) - if name.is_a?(Hash) - options = name - name = nil - end - name ||= :default - state_machines[name] ||= Machine.new(self, name) - block ? state_machines[name].update(options, &block) : state_machines[name] - end - - def define_state_query_method(state_name) - name = "#{state_name}?" - undef_method(name) if method_defined?(name) - class_eval "def #{name}; current_state.to_s == %(#{state_name}) end" - end - end - - def current_state(name = nil, new_state = nil, persist = false) - sm = self.class.state_machine(name) - ivar = sm.current_state_variable - if name && new_state - if persist && respond_to?(:write_state) - write_state(sm, new_state) - end - - if respond_to?(:write_state_without_persistence) - write_state_without_persistence(sm, new_state) - end - - instance_variable_set(ivar, new_state) - else - instance_variable_set(ivar, nil) unless instance_variable_defined?(ivar) - value = instance_variable_get(ivar) - return value if value - - if respond_to?(:read_state) - value = instance_variable_set(ivar, read_state(sm)) - end - - value || sm.initial_state - end - end - end -end diff --git a/activemodel/lib/active_model/state_machine/event.rb b/activemodel/lib/active_model/state_machine/event.rb deleted file mode 100644 index 30e9601dc2..0000000000 --- a/activemodel/lib/active_model/state_machine/event.rb +++ /dev/null @@ -1,62 +0,0 @@ -module ActiveModel - module StateMachine - class Event - attr_reader :name, :success - - def initialize(machine, name, options = {}, &block) - @machine, @name, @transitions = machine, name, [] - if machine - machine.klass.send(:define_method, "#{name}!") do |*args| - machine.fire_event(name, self, true, *args) - end - - machine.klass.send(:define_method, name.to_s) do |*args| - machine.fire_event(name, self, false, *args) - end - end - update(options, &block) - end - - def fire(obj, to_state = nil, *args) - transitions = @transitions.select { |t| t.from == obj.current_state(@machine ? @machine.name : nil) } - raise InvalidTransition if transitions.size == 0 - - next_state = nil - transitions.each do |transition| - next if to_state && !Array(transition.to).include?(to_state) - if transition.perform(obj) - next_state = to_state || Array(transition.to).first - transition.execute(obj, *args) - break - end - end - next_state - end - - def transitions_from_state?(state) - @transitions.any? { |t| t.from? state } - end - - def ==(event) - if event.is_a? Symbol - name == event - else - name == event.name - end - end - - def update(options = {}, &block) - if options.key?(:success) then @success = options[:success] end - if block then instance_eval(&block) end - self - end - - private - def transitions(trans_opts) - Array(trans_opts[:from]).each do |s| - @transitions << StateTransition.new(trans_opts.merge({:from => s.to_sym})) - end - end - end - end -end diff --git a/activemodel/lib/active_model/state_machine/machine.rb b/activemodel/lib/active_model/state_machine/machine.rb deleted file mode 100644 index 777531213e..0000000000 --- a/activemodel/lib/active_model/state_machine/machine.rb +++ /dev/null @@ -1,75 +0,0 @@ -module ActiveModel - module StateMachine - class Machine - attr_writer :initial_state - attr_accessor :states, :events, :state_index - attr_reader :klass, :name - - def initialize(klass, name, options = {}, &block) - @klass, @name, @states, @state_index, @events = klass, name, [], {}, {} - update(options, &block) - end - - def initial_state - @initial_state ||= (states.first ? states.first.name : nil) - end - - def update(options = {}, &block) - if options.key?(:initial) then @initial_state = options[:initial] end - if block then instance_eval(&block) end - self - end - - def fire_event(event, record, persist, *args) - state_index[record.current_state(@name)].call_action(:exit, record) - if new_state = @events[event].fire(record, *args) - state_index[new_state].call_action(:enter, record) - - if record.respond_to?(event_fired_callback) - record.send(event_fired_callback, record.current_state, new_state) - end - - record.current_state(@name, new_state, persist) - record.send(@events[event].success) if @events[event].success - true - else - if record.respond_to?(event_failed_callback) - record.send(event_failed_callback, event) - end - - false - end - end - - def states_for_select - states.map { |st| [st.display_name, st.name.to_s] } - end - - def events_for(state) - events = @events.values.select { |event| event.transitions_from_state?(state) } - events.map! { |event| event.name } - end - - def current_state_variable - "@#{@name}_current_state" - end - - private - def state(name, options = {}) - @states << (state_index[name] ||= State.new(name, :machine => self)).update(options) - end - - def event(name, options = {}, &block) - (@events[name] ||= Event.new(self, name)).update(options, &block) - end - - def event_fired_callback - @event_fired_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_fired' - end - - def event_failed_callback - @event_failed_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_failed' - end - end - end -end diff --git a/activemodel/lib/active_model/state_machine/state.rb b/activemodel/lib/active_model/state_machine/state.rb deleted file mode 100644 index 76916b1d86..0000000000 --- a/activemodel/lib/active_model/state_machine/state.rb +++ /dev/null @@ -1,47 +0,0 @@ -module ActiveModel - module StateMachine - class State - attr_reader :name, :options - - def initialize(name, options = {}) - @name = name - if machine = options.delete(:machine) - machine.klass.define_state_query_method(name) - end - update(options) - end - - def ==(state) - if state.is_a? Symbol - name == state - else - name == state.name - end - end - - def call_action(action, record) - action = @options[action] - case action - when Symbol, String - record.send(action) - when Proc - action.call(record) - end - end - - def display_name - @display_name ||= name.to_s.gsub(/_/, ' ').capitalize - end - - def for_select - [display_name, name.to_s] - end - - def update(options = {}) - if options.key?(:display) then @display_name = options.delete(:display) end - @options = options - self - end - end - end -end diff --git a/activemodel/lib/active_model/state_machine/state_transition.rb b/activemodel/lib/active_model/state_machine/state_transition.rb deleted file mode 100644 index b0c5504de7..0000000000 --- a/activemodel/lib/active_model/state_machine/state_transition.rb +++ /dev/null @@ -1,40 +0,0 @@ -module ActiveModel - module StateMachine - class StateTransition - attr_reader :from, :to, :options - - def initialize(opts) - @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition] - @options = opts - end - - def perform(obj) - case @guard - when Symbol, String - obj.send(@guard) - when Proc - @guard.call(obj) - else - true - end - end - - def execute(obj, *args) - case @on_transition - when Symbol, String - obj.send(@on_transition, *args) - when Proc - @on_transition.call(obj, *args) - end - end - - def ==(obj) - @from == obj.from && @to == obj.to - end - - def from?(value) - @from == value - end - end - end -end diff --git a/activemodel/test/cases/state_machine/event_test.rb b/activemodel/test/cases/state_machine/event_test.rb deleted file mode 100644 index 2a0ef53a3f..0000000000 --- a/activemodel/test/cases/state_machine/event_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'cases/helper' - -class EventTest < ActiveModel::TestCase - def setup - @state_name = :close_order - @success = :success_callback - end - - def new_event - @event = ActiveModel::StateMachine::Event.new(nil, @state_name, {:success => @success}) do - transitions :to => :closed, :from => [:open, :received] - end - end - - test 'should set the name' do - assert_equal @state_name, new_event.name - end - - test 'should set the success option' do - assert_equal @success, new_event.success - end - - test 'should create StateTransitions' do - ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :open) - ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :received) - new_event - end -end - -class EventBeingFiredTest < ActiveModel::TestCase - test 'should raise an AASM::InvalidTransition error if the transitions are empty' do - event = ActiveModel::StateMachine::Event.new(nil, :event) - - assert_raise ActiveModel::StateMachine::InvalidTransition do - event.fire(nil) - end - end - - test 'should return the state of the first matching transition it finds' do - event = ActiveModel::StateMachine::Event.new(nil, :event) do - transitions :to => :closed, :from => [:open, :received] - end - - obj = stub - obj.stubs(:current_state).returns(:open) - - assert_equal :closed, event.fire(obj) - end -end diff --git a/activemodel/test/cases/state_machine/machine_test.rb b/activemodel/test/cases/state_machine/machine_test.rb deleted file mode 100644 index 2aa954d80c..0000000000 --- a/activemodel/test/cases/state_machine/machine_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'cases/helper' - -class MachineTestSubject - include ActiveModel::StateMachine - - state_machine do - state :open - state :closed - end - - state_machine :initial => :foo do - event :shutdown do - transitions :from => :open, :to => :closed - end - - event :timeout do - transitions :from => :open, :to => :closed - end - end - - state_machine :extra, :initial => :bar do - end -end - -class StateMachineMachineTest < ActiveModel::TestCase - test "allows reuse of existing machines" do - assert_equal 2, MachineTestSubject.state_machines.size - end - - test "sets #initial_state from :initial option" do - assert_equal :bar, MachineTestSubject.state_machine(:extra).initial_state - end - - test "accesses non-default state machine" do - assert_kind_of ActiveModel::StateMachine::Machine, MachineTestSubject.state_machine(:extra) - end - - test "finds events for given state" do - events = MachineTestSubject.state_machine.events_for(:open) - assert events.include?(:shutdown) - assert events.include?(:timeout) - end -end diff --git a/activemodel/test/cases/state_machine/state_test.rb b/activemodel/test/cases/state_machine/state_test.rb deleted file mode 100644 index 527bfd4c04..0000000000 --- a/activemodel/test/cases/state_machine/state_test.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'cases/helper' - -class StateTestSubject - include ActiveModel::StateMachine - - state_machine do - end -end - -class StateTest < ActiveModel::TestCase - def setup - @state_name = :astate - @machine = StateTestSubject.state_machine - @options = { :crazy_custom_key => 'key', :machine => @machine } - end - - def new_state(options={}) - ActiveModel::StateMachine::State.new(@state_name, @options.merge(options)) - end - - test 'sets the name' do - assert_equal :astate, new_state.name - end - - test 'sets the display_name from name' do - assert_equal "Astate", new_state.display_name - end - - test 'sets the display_name from options' do - assert_equal "A State", new_state(:display => "A State").display_name - end - - test 'sets the options and expose them as options' do - @options.delete(:machine) - assert_equal @options, new_state.options - end - - test 'equals a symbol of the same name' do - assert_equal new_state, :astate - end - - test 'equals a State of the same name' do - assert_equal new_state, new_state - end - - test 'should send a message to the record for an action if the action is present as a symbol' do - state = new_state(:entering => :foo) - - record = stub - record.expects(:foo) - - state.call_action(:entering, record) - end - - test 'should send a message to the record for an action if the action is present as a string' do - state = new_state(:entering => 'foo') - - record = stub - record.expects(:foo) - - state.call_action(:entering, record) - end - - test 'should call a proc, passing in the record for an action if the action is present' do - state = new_state(:entering => Proc.new {|r| r.foobar}) - - record = stub - record.expects(:foobar) - - state.call_action(:entering, record) - end -end diff --git a/activemodel/test/cases/state_machine/state_transition_test.rb b/activemodel/test/cases/state_machine/state_transition_test.rb deleted file mode 100644 index 17f9d88be7..0000000000 --- a/activemodel/test/cases/state_machine/state_transition_test.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'cases/helper' - -class StateTransitionTest < ActiveModel::TestCase - test 'should set from, to, and opts attr readers' do - opts = {:from => 'foo', :to => 'bar', :guard => 'g'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - assert_equal opts[:from], st.from - assert_equal opts[:to], st.to - assert_equal opts, st.options - end - - test 'should pass equality check if from and to are the same' do - opts = {:from => 'foo', :to => 'bar', :guard => 'g'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.stubs(:from).returns(opts[:from]) - obj.stubs(:to).returns(opts[:to]) - - assert_equal st, obj - end - - test 'should fail equality check if from are not the same' do - opts = {:from => 'foo', :to => 'bar', :guard => 'g'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.stubs(:from).returns('blah') - obj.stubs(:to).returns(opts[:to]) - - assert_not_equal st, obj - end - - test 'should fail equality check if to are not the same' do - opts = {:from => 'foo', :to => 'bar', :guard => 'g'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.stubs(:from).returns(opts[:from]) - obj.stubs(:to).returns('blah') - - assert_not_equal st, obj - end -end - -class StateTransitionGuardCheckTest < ActiveModel::TestCase - test 'should return true of there is no guard' do - opts = {:from => 'foo', :to => 'bar'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - assert st.perform(nil) - end - - test 'should call the method on the object if guard is a symbol' do - opts = {:from => 'foo', :to => 'bar', :guard => :test_guard} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.expects(:test_guard) - - st.perform(obj) - end - - test 'should call the method on the object if guard is a string' do - opts = {:from => 'foo', :to => 'bar', :guard => 'test_guard'} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.expects(:test_guard) - - st.perform(obj) - end - - test 'should call the proc passing the object if the guard is a proc' do - opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test_guard}} - st = ActiveModel::StateMachine::StateTransition.new(opts) - - obj = stub - obj.expects(:test_guard) - - st.perform(obj) - end -end diff --git a/activemodel/test/cases/state_machine_test.rb b/activemodel/test/cases/state_machine_test.rb deleted file mode 100644 index f66299741e..0000000000 --- a/activemodel/test/cases/state_machine_test.rb +++ /dev/null @@ -1,312 +0,0 @@ -require 'cases/helper' - -class StateMachineSubject - include ActiveModel::StateMachine - - state_machine do - state :open, :exit => :exit - state :closed, :enter => :enter - - event :close, :success => :success_callback do - transitions :to => :closed, :from => [:open] - end - - event :null do - transitions :to => :closed, :from => [:open], :guard => :always_false - end - end - - state_machine :bar do - state :read - state :ended - - event :foo do - transitions :to => :ended, :from => [:read] - end - end - - def always_false - false - end - - def success_callback - end - - def enter - end - def exit - end -end - -class StateMachineSubjectSubclass < StateMachineSubject -end - -class StateMachineClassLevelTest < ActiveModel::TestCase - test 'defines a class level #state_machine method on its including class' do - assert StateMachineSubject.respond_to?(:state_machine) - end - - test 'defines a class level #state_machines method on its including class' do - assert StateMachineSubject.respond_to?(:state_machines) - end - - test 'class level #state_machine returns machine instance' do - assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine - end - - test 'class level #state_machine returns machine instance with given name' do - assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine(:default) - end - - test 'class level #state_machines returns hash of machine instances' do - assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machines[:default] - end - - test "should return a select friendly array of states in the form of [['Friendly name', 'state_name']]" do - assert_equal [['Open', 'open'], ['Closed', 'closed']], StateMachineSubject.state_machine.states_for_select - end -end - -class StateMachineInstanceLevelTest < ActiveModel::TestCase - def setup - @foo = StateMachineSubject.new - end - - test 'defines an accessor for the current state' do - assert @foo.respond_to?(:current_state) - end - - test 'defines a state querying instance method on including class' do - assert @foo.respond_to?(:open?) - end - - test 'defines an event! instance method' do - assert @foo.respond_to?(:close!) - end - - test 'defines an event instance method' do - assert @foo.respond_to?(:close) - end -end - -class StateMachineInitialStatesTest < ActiveModel::TestCase - def setup - @foo = StateMachineSubject.new - end - - test 'sets the initial state' do - assert_equal :open, @foo.current_state - end - - test '#open? should be initially true' do - assert @foo.open? - end - - test '#closed? should be initially false' do - assert !@foo.closed? - end - - test 'uses the first state defined if no initial state is given' do - assert_equal :read, @foo.current_state(:bar) - end -end - -class StateMachineEventFiringWithPersistenceTest < ActiveModel::TestCase - def setup - @subj = StateMachineSubject.new - end - - test 'updates the current state' do - @subj.close! - - assert_equal :closed, @subj.current_state - end - - test 'fires the Event' do - @subj.class.state_machine.events[:close].expects(:fire).with(@subj) - @subj.close! - end - - test 'calls the success callback if one was provided' do - @subj.expects(:success_callback) - @subj.close! - end - - test 'attempts to persist if write_state is defined' do - def @subj.write_state - end - - @subj.expects(:write_state) - @subj.close! - end -end - -class StateMachineEventFiringWithoutPersistence < ActiveModel::TestCase - test 'updates the current state' do - subj = StateMachineSubject.new - assert_equal :open, subj.current_state - subj.close - assert_equal :closed, subj.current_state - end - - test 'fires the Event' do - subj = StateMachineSubject.new - - StateMachineSubject.state_machine.events[:close].expects(:fire).with(subj) - subj.close - end - - test 'attempts to persist if write_state is defined' do - subj = StateMachineSubject.new - - def subj.write_state - end - - subj.expects(:write_state_without_persistence) - - subj.close - end -end - -class StateMachinePersistenceTest < ActiveModel::TestCase - test 'reads the state if it has not been set and read_state is defined' do - subj = StateMachineSubject.new - def subj.read_state - end - - subj.expects(:read_state).with(StateMachineSubject.state_machine) - - subj.current_state - end -end - -class StateMachineEventCallbacksTest < ActiveModel::TestCase - test 'should call aasm_event_fired if defined and successful for bang fire' do - subj = StateMachineSubject.new - def subj.aasm_event_fired(from, to) - end - - subj.expects(:event_fired) - - subj.close! - end - - test 'should call aasm_event_fired if defined and successful for non-bang fire' do - subj = StateMachineSubject.new - def subj.aasm_event_fired(from, to) - end - - subj.expects(:event_fired) - - subj.close - end - - test 'should call aasm_event_failed if defined and transition failed for bang fire' do - subj = StateMachineSubject.new - def subj.event_failed(event) - end - - subj.expects(:event_failed) - - subj.null! - end - - test 'should call aasm_event_failed if defined and transition failed for non-bang fire' do - subj = StateMachineSubject.new - def subj.aasm_event_failed(event) - end - - subj.expects(:event_failed) - - subj.null - end -end - -class StateMachineStateActionsTest < ActiveModel::TestCase - test "calls enter when entering state" do - subj = StateMachineSubject.new - subj.expects(:enter) - subj.close - end - - test "calls exit when exiting state" do - subj = StateMachineSubject.new - subj.expects(:exit) - subj.close - end -end - -class StateMachineInheritanceTest < ActiveModel::TestCase - test "has the same states as its parent" do - assert_equal StateMachineSubject.state_machine.states, StateMachineSubjectSubclass.state_machine.states - end - - test "has the same events as its parent" do - assert_equal StateMachineSubject.state_machine.events, StateMachineSubjectSubclass.state_machine.events - end -end - -class StateMachineSubject - state_machine :chetan_patil, :initial => :sleeping do - state :sleeping - state :showering - state :working - state :dating - - event :wakeup do - transitions :from => :sleeping, :to => [:showering, :working] - end - - event :dress do - transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes - transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) } - end - end - - def wear_clothes(shirt_color, trouser_type) - end -end - -class StateMachineWithComplexTransitionsTest < ActiveModel::TestCase - def setup - @subj = StateMachineSubject.new - end - - test 'transitions to specified next state (sleeping to showering)' do - @subj.wakeup! :showering - - assert_equal :showering, @subj.current_state(:chetan_patil) - end - - test 'transitions to specified next state (sleeping to working)' do - @subj.wakeup! :working - - assert_equal :working, @subj.current_state(:chetan_patil) - end - - test 'transitions to default (first or showering) state' do - @subj.wakeup! - - assert_equal :showering, @subj.current_state(:chetan_patil) - end - - test 'transitions to default state when on_transition invoked' do - @subj.dress!(nil, 'purple', 'dressy') - - assert_equal :working, @subj.current_state(:chetan_patil) - end - - test 'calls on_transition method with args' do - @subj.wakeup! :showering - - @subj.expects(:wear_clothes).with('blue', 'jeans') - @subj.dress! :working, 'blue', 'jeans' - end - - test 'calls on_transition proc' do - @subj.wakeup! :showering - - @subj.expects(:wear_clothes).with('purple', 'slacks') - @subj.dress!(:dating, 'purple', 'slacks') - end -end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 7d33fcea98..38844bb1fa 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -254,7 +254,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_confirmation_of w/o mocha def test_validates_confirmation_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:confirmation => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:confirmation => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:confirmation => 'global message'}} Person.validates_confirmation_of :title @@ -275,7 +275,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_acceptance_of w/o mocha def test_validates_acceptance_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:accepted => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:accepted => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:accepted => 'global message'}} Person.validates_acceptance_of :title, :allow_nil => false @@ -294,7 +294,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_presence_of w/o mocha def test_validates_presence_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:blank => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:blank => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:blank => 'global message'}} Person.validates_presence_of :title @@ -313,7 +313,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_length_of :within w/o mocha def test_validates_length_of_within_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:too_short => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:too_short => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:too_short => 'global message'}} Person.validates_length_of :title, :within => 3..5 @@ -332,7 +332,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_length_of :is w/o mocha def test_validates_length_of_is_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:wrong_length => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:wrong_length => 'global message'}} Person.validates_length_of :title, :is => 5 @@ -351,7 +351,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_format_of w/o mocha def test_validates_format_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:invalid => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:invalid => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:invalid => 'global message'}} Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ @@ -370,7 +370,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_inclusion_of w/o mocha def test_validates_inclusion_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:inclusion => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:inclusion => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:inclusion => 'global message'}} Person.validates_inclusion_of :title, :in => %w(a b c) @@ -389,7 +389,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_exclusion_of w/o mocha def test_validates_exclusion_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:exclusion => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:exclusion => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:exclusion => 'global message'}} Person.validates_exclusion_of :title, :in => %w(a b c) @@ -410,7 +410,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_numericality_of without :only_integer w/o mocha def test_validates_numericality_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}} Person.validates_numericality_of :title @@ -431,7 +431,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_numericality_of with :only_integer w/o mocha def test_validates_numericality_of_only_integer_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}} Person.validates_numericality_of :title, :only_integer => true @@ -452,7 +452,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_numericality_of :odd w/o mocha def test_validates_numericality_of_odd_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:odd => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:odd => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:odd => 'global message'}} Person.validates_numericality_of :title, :only_integer => true, :odd => true @@ -473,7 +473,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_numericality_of :less_than w/o mocha def test_validates_numericality_of_less_than_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:less_than => 'custom message'}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:less_than => 'custom message'}}}}}} I18n.backend.store_translations 'en', :errors => {:messages => {:less_than => 'global message'}} Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 @@ -502,7 +502,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_attribute - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:attributes => {:title => {:custom_error => "I am a custom error"}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:custom_error => "I am a custom error"}}}}}} Person.validates_presence_of :title, :message => :custom_error @person.title = nil @person.valid? @@ -510,7 +510,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_model - I18n.backend.store_translations 'en', :errors => {:models => {:person => {:custom_error => "I am a custom error"}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:custom_error => "I am a custom error"}}}} Person.validates_presence_of :title, :message => :custom_error @person.title = nil @person.valid? |