diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb
index 843e43de..7bb6d0ed 100644
--- a/app/controllers/todos_controller.rb
+++ b/app/controllers/todos_controller.rb
@@ -89,9 +89,6 @@ class TodosController < ApplicationController
specified_state = @todo.state
@saved = @todo.save
- # Fix for #977 because AASM overrides @state on creation
- @todo.update_attribute('state', specified_state) unless specified_state == "immediate" || specified_state.nil? || !@saved
- @saved = @todo.save
@todo.update_state_from_project if @saved
unless (@saved == false) || tag_list.blank?
diff --git a/app/models/project.rb b/app/models/project.rb
index 1eb3e04c..13819cf2 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -40,23 +40,27 @@ class Project < ActiveRecord::Base
validates_does_not_contain :name, :string => ','
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\''
- acts_as_state_machine :initial => :active, :column => 'state'
+
+ include AASM
+ aasm_column :state
+ aasm_initial_state :active
+
extend NamePartFinder
#include Tracks::TodoList
- state :active
- state :hidden, :enter => :hide_todos, :exit => :unhide_todos
- state :completed, :enter => Proc.new { |p| p.completed_at = Time.zone.now }, :exit => Proc.new { |p| p.completed_at = nil }
+ aasm_state :active
+ aasm_state :hidden, :enter => :hide_todos, :exit => :unhide_todos
+ aasm_state :completed, :enter => :set_completed_at_date, :exit => :clear_completed_at_date
- event :activate do
- transitions :to => :active, :from => [:hidden, :completed]
+ aasm_event :activate do
+ transitions :to => :active, :from => [:active, :hidden, :completed]
end
- event :hide do
+ aasm_event :hide do
transitions :to => :hidden, :from => [:active, :completed]
end
- event :complete do
+ aasm_event :complete do
transitions :to => :completed, :from => [:active, :hidden]
end
@@ -92,6 +96,14 @@ class Project < ActiveRecord::Base
end
end
+ def set_completed_at_date
+ self.completed_at = Time.zone.now
+ end
+
+ def clear_completed_at_date
+ self.completed_at = nil
+ end
+
def note_count
cached_note_count || notes.count
end
@@ -106,7 +118,7 @@ class Project < ActiveRecord::Base
# as a result of acts_as_state_machine calling state=() to update the attribute
def transition_to(candidate_state)
case candidate_state.to_sym
- when current_state
+ when aasm_current_state
return
when :hidden
hide!
diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb
index 48c9ede3..e46ad36e 100644
--- a/app/models/recurring_todo.rb
+++ b/app/models/recurring_todo.rb
@@ -10,20 +10,19 @@ class RecurringTodo < ActiveRecord::Base
named_scope :completed, :conditions => { :state => 'completed'}
attr_protected :user
-
- acts_as_state_machine :initial => :active, :column => 'state'
- state :active, :enter => Proc.new { |t|
- t[:show_from], t.completed_at = nil, nil
- t.occurences_count = 0
- }
- state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
+ include AASM
+ aasm_column :state
+ aasm_initial_state :active
+
+ aasm_state :active, :enter => Proc.new { |t| t.occurences_count = 0 }
+ aasm_state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
- event :complete do
+ aasm_event :complete do
transitions :to => :completed, :from => [:active]
end
- event :activate do
+ aasm_event :activate do
transitions :to => :active, :from => [:completed]
end
@@ -41,8 +40,7 @@ class RecurringTodo < ActiveRecord::Base
validate :set_recurrence_on_validations
def period_specific_validations
- periods = %W[daily weekly monthly yearly]
- if periods.include?(recurring_period)
+ if %W[daily weekly monthly yearly].include?(recurring_period)
self.send("validate_#{recurring_period}")
else
errors.add(:recurring_period, "is an unknown recurrence pattern: '#{self.recurring_period}'")
@@ -94,7 +92,6 @@ class RecurringTodo < ActiveRecord::Base
end
end
-
def starts_and_ends_on_validations
errors.add_to_base("The start date needs to be filled in") if start_from.nil? || start_from.blank?
case self.ends_on
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 6ddbd5b0..58dcc30a 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -45,40 +45,42 @@ class Todo < ActiveRecord::Base
RE_PARTS = /'(#{RE_TODO})'\s<'(#{RE_CONTEXT})';\s'(#{RE_PROJECT})'>/ # results in array
RE_SPEC = /'#{RE_TODO}'\s<'#{RE_CONTEXT}';\s'#{RE_PROJECT}'>/ # results in string
- acts_as_state_machine :initial => :active, :column => 'state'
+ include AASM
+ aasm_column :state
+ aasm_initial_state Proc.new { |todo| (todo.show_from && (todo.show_from > todo.user.date)) ? :deferred : :active}
# when entering active state, also remove completed_at date. Looks like :exit
# of state completed is not run, see #679
- state :active, :enter => Proc.new { |t| t[:show_from], t.completed_at = nil, nil }
- state :project_hidden
- state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
- state :deferred
- state :pending
+ aasm_state :active
+ aasm_state :project_hidden, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
+ aasm_state :completed, :exit => Proc.new { |t| t.completed_at = nil }
+ aasm_state :deferred, :exit => Proc.new { |t| t[:show_from] = nil }
+ aasm_state :pending
- event :defer do
+ aasm_event :defer do
transitions :to => :deferred, :from => [:active]
end
- event :complete do
+ aasm_event :complete do
transitions :to => :completed, :from => [:active, :project_hidden, :deferred]
end
- event :activate do
+ aasm_event :activate do
transitions :to => :active, :from => [:project_hidden, :completed, :deferred]
transitions :to => :active, :from => [:pending], :guard => :no_uncompleted_predecessors_or_deferral?
transitions :to => :deferred, :from => [:pending], :guard => :no_uncompleted_predecessors?
end
- event :hide do
+ aasm_event :hide do
transitions :to => :project_hidden, :from => [:active, :deferred]
end
- event :unhide do
+ aasm_event :unhide do
transitions :to => :deferred, :from => [:project_hidden], :guard => Proc.new{|t| !t.show_from.blank? }
transitions :to => :active, :from => [:project_hidden]
end
- event :block do
+ aasm_event :block do
transitions :to => :pending, :from => [:active, :deferred]
end
@@ -97,7 +99,7 @@ class Todo < ActiveRecord::Base
@predecessor_array = nil # Used for deferred save of predecessors
@removed_predecessors = nil
end
-
+
def no_uncompleted_predecessors_or_deferral?
return (show_from.blank? or Time.zone.now > show_from and uncompleted_predecessors.empty?)
end
@@ -153,10 +155,8 @@ class Todo < ActiveRecord::Base
end
def remove_predecessor(predecessor)
- puts "@@@ before delete"
# remove predecessor and activate myself
self.predecessors.delete(predecessor)
- puts "@@@ before activate"
self.activate!
end
@@ -214,9 +214,14 @@ class Todo < ActiveRecord::Base
def show_from=(date)
# parse Date objects into the proper timezone
date = user.at_midnight(date) if (date.is_a? Date)
+
+ # show_from needs to be set before state_change because of "bug" in aasm.
+ # If show_From is not set, the todo will not validate and thus aasm will not save
+ # (see http://stackoverflow.com/questions/682920/persisting-the-state-column-on-transition-using-rubyist-aasm-acts-as-state-machi)
+ self[:show_from] = date
+
activate! if deferred? && date.blank?
defer! if active? && !date.blank? && date > user.date
- self[:show_from] = date
end
alias_method :original_project, :project
@@ -224,27 +229,7 @@ class Todo < ActiveRecord::Base
def project
original_project.nil? ? Project.null_object : original_project
end
-
- alias_method :original_set_initial_state, :set_initial_state
- def set_initial_state
- if show_from && (show_from > user.date)
- write_attribute self.class.state_column, 'deferred'
- else
- original_set_initial_state
- end
- end
-
- alias_method :original_run_initial_state_actions, :run_initial_state_actions
-
- def run_initial_state_actions
- # only run the initial state actions if the standard initial state hasn't
- # been changed
- if self.class.initial_state.to_sym == current_state
- original_run_initial_state_actions
- end
- end
-
def self.feed_options(user)
{
:title => 'Tracks Actions',
diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml
index 7f84add5..b07bf0c3 100644
--- a/app/views/projects/_project_listing.rhtml
+++ b/app/views/projects/_project_listing.rhtml
@@ -17,7 +17,7 @@ suppress_edit_button ||= false
- <%= project.current_state.to_s.upcase %>
+ <%= project.aasm_current_state.to_s.upcase %>
<%= link_to_delete_project(project, image_tag( "blank.png", :title => t('projects.delete_project_title'), :class=>"delete_item")) %>
<%= suppress_edit_button ? "" : link_to_edit_project(project, image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item")) %>
diff --git a/app/views/projects/project_mobile.rhtml b/app/views/projects/project_mobile.rhtml
index 3b35c8e2..d79cad08 100644
--- a/app/views/projects/project_mobile.rhtml
+++ b/app/views/projects/project_mobile.rhtml
@@ -24,4 +24,4 @@
<% else -%><%= render :partial => "notes/mobile_notes_summary", :collection => @project.notes %>
<% end -%>
<%= t('projects.settings') %>
-<%= t('projects.state', :state => project.current_state.to_s) %>. <%= @project_default_context %>
\ No newline at end of file
+<%= t('projects.state', :state => project.aasm_current_state.to_s) %>. <%= @project_default_context %>
\ No newline at end of file
diff --git a/app/views/projects/update_status.js.rjs b/app/views/projects/update_status.js.rjs
index f2570dd4..c15a4acb 100644
--- a/app/views/projects/update_status.js.rjs
+++ b/app/views/projects/update_status.js.rjs
@@ -1,11 +1,11 @@
# TODO: is this dead code?
page.select('#project_status .active span').each do |element|
- element.className = @project.current_state == :active ? 'active_state' : 'inactive_state'
+ element.className = @project.aasm_current_state == :active ? 'active_state' : 'inactive_state'
end
page.select('#project_status .hidden span').each do |element|
- element.className = @project.current_state == :hidden ? 'active_state' : 'inactive_state'
+ element.className = @project.aasm_current_state == :hidden ? 'active_state' : 'inactive_state'
end
page.select('#project_status .completed span').each do |element|
- element.className = @project.current_state == :completed ? 'active_state' : 'inactive_state'
+ element.className = @project.aasm_current_state == :completed ? 'active_state' : 'inactive_state'
end
-page.notify :notice, "Set project status to #{@project.current_state}", 5.0
+page.notify :notice, "Set project status to #{@project.aasm_current_state}", 5.0
diff --git a/config/environment.rb b/config/environment.rb
index a16ce4c8..bb4e50fc 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -29,6 +29,7 @@ Rails::Initializer.run do |config|
config.gem 'rack', :version => '1.1.0'
config.gem 'will_paginate', :version => '~> 2.3.15'
config.gem 'has_many_polymorphs'
+ config.gem 'aasm', :version => '2.2.0'
config.action_controller.use_accept_header = true
diff --git a/db/migrate/20110526192008_adapt_to_new_aasm.rb b/db/migrate/20110526192008_adapt_to_new_aasm.rb
new file mode 100644
index 00000000..206a6ec6
--- /dev/null
+++ b/db/migrate/20110526192008_adapt_to_new_aasm.rb
@@ -0,0 +1,13 @@
+class AdaptToNewAasm < ActiveRecord::Migration
+ def self.up
+ change_column_default :todos, :state, nil
+ change_column_default :projects, :state, nil
+ change_column_default :recurring_todos, :state, nil
+ end
+
+ def self.down
+ change_column :todos, :state, :string, :limit => 20, :default => "immediate", :null => false
+ change_column :projects, :state, :string, :limit => 20, :default => "active", :null => false
+ change_column :recurring_todos, :state, :string, :limit => 20, :default => "active", :null => false
+ end
+end
diff --git a/test/fixtures/recurring_todos.yml b/test/fixtures/recurring_todos.yml
index a9bfb18c..84872204 100644
--- a/test/fixtures/recurring_todos.yml
+++ b/test/fixtures/recurring_todos.yml
@@ -41,7 +41,7 @@ call_bill_gates_every_day:
show_from_delta: ~
recurring_period: daily
recurrence_selector: ~
- show_always: 0
+ show_always: 1
every_other1: 1
every_other2: ~
every_other3: ~
diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb
index 297ae2e2..ba419ecf 100644
--- a/test/functional/projects_controller_test.rb
+++ b/test/functional/projects_controller_test.rb
@@ -58,7 +58,7 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
login_as(:admin_user)
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"}
todos.each do |t|
- assert_equal :project_hidden, t.reload().current_state
+ assert_equal :project_hidden, t.reload().aasm_current_state
end
assert p.reload().hidden?
end
@@ -70,7 +70,7 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"}
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"active"}
todos.each do |t|
- assert_equal :active, t.reload().current_state
+ assert_equal :active, t.reload().aasm_current_state
end
assert p.reload().active?
end
diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb
index 52543c8b..d080bfc5 100644
--- a/test/functional/todos_controller_test.rb
+++ b/test/functional/todos_controller_test.rb
@@ -62,7 +62,6 @@ class TodosControllerTest < ActionController::TestCase
assert_equal 2, t.tags.count
end
-
def test_not_done_counts_after_hiding_project
p = Project.find(1)
p.hide!
diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb
index 180f0876..76f61cec 100644
--- a/test/unit/project_test.rb
+++ b/test/unit/project_test.rb
@@ -53,26 +53,26 @@ class ProjectTest < ActiveSupport::TestCase
end
def test_project_initial_state_is_active
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
assert @timemachine.active?
end
def test_hide_project
@timemachine.hide!
- assert_equal :hidden, @timemachine.current_state
+ assert_equal :hidden, @timemachine.aasm_current_state
assert @timemachine.hidden?
end
def test_activate_project
@timemachine.activate!
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
assert @timemachine.active?
end
def test_complete_project
assert_nil @timemachine.completed_at
@timemachine.complete!
- assert_equal :completed, @timemachine.current_state
+ assert_equal :completed, @timemachine.aasm_current_state
assert @timemachine.completed?
assert_not_nil @timemachine.completed_at, "completed_at not expected to be nil"
assert_in_delta Time.now, @timemachine.completed_at, 1
@@ -141,25 +141,26 @@ class ProjectTest < ActiveSupport::TestCase
end
def test_transition_to_another_state
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
@timemachine.transition_to(:hidden)
- assert_equal :hidden, @timemachine.current_state
+ assert_equal :hidden, @timemachine.aasm_current_state
@timemachine.transition_to(:completed)
- assert_equal :completed, @timemachine.current_state
+ assert_equal :completed, @timemachine.aasm_current_state
@timemachine.transition_to(:active)
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
end
def test_transition_to_same_state
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
@timemachine.transition_to(:active)
- assert_equal :active, @timemachine.current_state
+ assert_equal :active, @timemachine.aasm_current_state
end
def test_deferred_todo_count
assert_equal 1, @timemachine.deferred_todos.count
assert_equal 0, @moremoney.deferred_todos.count
@moremoney.todos[0].show_from = next_week
+ assert_equal :deferred, @moremoney.todos[0].aasm_current_state
assert_equal 1, @moremoney.deferred_todos.count
end
diff --git a/test/unit/recurring_todo_test.rb b/test/unit/recurring_todo_test.rb
index 980525be..b82bc59e 100644
--- a/test/unit/recurring_todo_test.rb
+++ b/test/unit/recurring_todo_test.rb
@@ -275,25 +275,31 @@ class RecurringTodoTest < ActiveSupport::TestCase
end
def test_toggle_completion
- t = @yearly
- assert_equal :active, t.current_state
- t.toggle_completion!
- assert_equal :completed, t.current_state
- t.toggle_completion!
- assert_equal :active, t.current_state
+ assert @yearly.active?
+ assert @yearly.toggle_completion!
+ assert @yearly.completed?
+
+ # entering completed state should set completed_at
+ assert !@yearly.completed_at.nil?
+
+ assert @yearly.toggle_completion!
+ assert @yearly.active?
+
+ # re-entering active state should clear completed_at
+ assert @yearly.completed_at.nil?
end
def test_starred
@yearly.tag_with("1, 2, starred")
@yearly.tags.reload
- assert_equal true, @yearly.starred?
- assert_equal false, @weekly_every_day.starred?
+ assert @yearly.starred?
+ assert !@weekly_every_day.starred?
@yearly.toggle_star!
- assert_equal false, @yearly.starred?
+ assert !@yearly.starred?
@yearly.toggle_star!
- assert_equal true, @yearly.starred?
+ assert @yearly.starred?
end
def test_occurence_count
@@ -307,8 +313,9 @@ class RecurringTodoTest < ActiveSupport::TestCase
# after completion, when you reactivate the recurring todo, the occurences
# count should be reset
assert_equal 2, @every_day.occurences_count
- @every_day.toggle_completion!
- @every_day.toggle_completion!
+ assert @every_day.toggle_completion!
+ assert @every_day.toggle_completion!
+
assert_equal true, @every_day.has_next_todo(@in_three_days)
assert_equal 0, @every_day.occurences_count
end
diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb
index 45b77af7..00460139 100644
--- a/test/unit/todo_test.rb
+++ b/test/unit/todo_test.rb
@@ -77,10 +77,10 @@ class TodoTest < ActiveSupport::TestCase
def test_defer_an_existing_todo
@not_completed2
- assert_equal :active, @not_completed2.current_state
+ assert_equal :active, @not_completed2.aasm_current_state
@not_completed2.show_from = next_week
assert @not_completed2.save, "should have saved successfully" + @not_completed2.errors.to_xml
- assert_equal :deferred, @not_completed2.current_state
+ assert_equal :deferred, @not_completed2.aasm_current_state
end
def test_create_a_new_deferred_todo
@@ -88,16 +88,16 @@ class TodoTest < ActiveSupport::TestCase
todo = user.todos.build
todo.show_from = next_week
todo.context_id = 1
- todo.description = 'foo'
+ todo.description = 'foo'
assert todo.save, "should have saved successfully" + todo.errors.to_xml
- assert_equal :deferred, todo.current_state
+ assert_equal :deferred, todo.aasm_current_state
end
def test_create_a_new_deferred_todo_by_passing_attributes
user = users(:other_user)
- todo = user.todos.build(:show_from => next_week, :context_id => 1, :description => 'foo')
+ todo = user.todos.build(:show_from => next_week, :context_id => 1, :description => 'foo')
assert todo.save, "should have saved successfully" + todo.errors.to_xml
- assert_equal :deferred, todo.current_state
+ assert_equal :deferred, todo.aasm_current_state
end
def test_feed_options
@@ -108,11 +108,11 @@ class TodoTest < ActiveSupport::TestCase
def test_toggle_completion
t = @not_completed1
- assert_equal :active, t.current_state
+ assert_equal :active, t.aasm_current_state
t.toggle_completion!
- assert_equal :completed, t.current_state
+ assert_equal :completed, t.aasm_current_state
t.toggle_completion!
- assert_equal :active, t.current_state
+ assert_equal :active, t.aasm_current_state
end
def test_activate_also_saves
@@ -154,7 +154,7 @@ class TodoTest < ActiveSupport::TestCase
t.context_id = 1
t.save!
t.reload
- assert_equal :active, t.current_state
+ assert_equal :active, t.aasm_current_state
end
def test_initial_state_is_deferred_when_show_from_in_future
@@ -165,7 +165,7 @@ class TodoTest < ActiveSupport::TestCase
t.show_from = 1.week.from_now.to_date
t.save!
t.reload
- assert_equal :deferred, t.current_state
+ assert_equal :deferred, t.aasm_current_state
end
def test_todo_is_not_starred
diff --git a/vendor/plugins/acts_as_state_machine/CHANGELOG b/vendor/plugins/acts_as_state_machine/CHANGELOG
deleted file mode 100644
index b97ad744..00000000
--- a/vendor/plugins/acts_as_state_machine/CHANGELOG
+++ /dev/null
@@ -1,13 +0,0 @@
-* trunk *
- break with true value [Kaspar Schiess]
-
-* 2.1 *
- After actions [Saimon Moore]
-
-* 2.0 * (2006-01-20 15:26:28 -0500)
- Enter / Exit actions
- Transition guards
- Guards and actions can be a symbol pointing to a method or a Proc
-
-* 1.0 * (2006-01-15 12:16:55 -0500)
- Initial Release
diff --git a/vendor/plugins/acts_as_state_machine/MIT-LICENSE b/vendor/plugins/acts_as_state_machine/MIT-LICENSE
deleted file mode 100644
index 3189ba6b..00000000
--- a/vendor/plugins/acts_as_state_machine/MIT-LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2006 Scott Barron
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/acts_as_state_machine/README b/vendor/plugins/acts_as_state_machine/README
deleted file mode 100644
index 2bbcced6..00000000
--- a/vendor/plugins/acts_as_state_machine/README
+++ /dev/null
@@ -1,33 +0,0 @@
-= Acts As State Machine
-
-This act gives an Active Record model the ability to act as a finite state
-machine (FSM).
-
-Acquire via subversion at:
-
-http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk
-
-If prompted, use the user/pass anonymous/anonymous.
-
-== Example
-
- class Order < ActiveRecord::Base
- acts_as_state_machine :initial => :opened
-
- state :opened
- state :closed, :enter => Proc.new {|o| Mailer.send_notice(o)}
- state :returned
-
- event :close do
- transitions :to => :closed, :from => :opened
- end
-
- event :return do
- transitions :to => :returned, :from => :closed
- end
- end
-
- o = Order.create
- o.close! # notice is sent by mailer
- o.return!
-
diff --git a/vendor/plugins/acts_as_state_machine/Rakefile b/vendor/plugins/acts_as_state_machine/Rakefile
deleted file mode 100644
index 101fdde9..00000000
--- a/vendor/plugins/acts_as_state_machine/Rakefile
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'rake'
-require 'rake/testtask'
-require 'rake/rdoctask'
-
-desc 'Default: run unit tests.'
-task :default => [:clean_db, :test]
-
-desc 'Remove the stale db file'
-task :clean_db do
- `rm -f #{File.dirname(__FILE__)}/test/state_machine.sqlite.db`
-end
-
-desc 'Test the acts as state machine plugin.'
-Rake::TestTask.new(:test) do |t|
- t.libs << 'lib'
- t.pattern = 'test/**/*_test.rb'
- t.verbose = true
-end
-
-desc 'Generate documentation for the acts as state machine plugin.'
-Rake::RDocTask.new(:rdoc) do |rdoc|
- rdoc.rdoc_dir = 'rdoc'
- rdoc.title = 'Acts As State Machine'
- rdoc.options << '--line-numbers --inline-source'
- rdoc.rdoc_files.include('README')
- rdoc.rdoc_files.include('TODO')
- rdoc.rdoc_files.include('lib/**/*.rb')
-end
diff --git a/vendor/plugins/acts_as_state_machine/TODO b/vendor/plugins/acts_as_state_machine/TODO
deleted file mode 100644
index 8d5d7063..00000000
--- a/vendor/plugins/acts_as_state_machine/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-* Currently invalid events are ignored, create an option so that they can be
- ignored or raise an exception.
-
-* Query for a list of possible next states.
-
-* Make listing states optional since they can be inferred from the events.
- Only required to list a state if you want to define a transition block for it.
-
-* Real transition actions
-
-* Default states
diff --git a/vendor/plugins/acts_as_state_machine/init.rb b/vendor/plugins/acts_as_state_machine/init.rb
deleted file mode 100644
index dd1b4cd2..00000000
--- a/vendor/plugins/acts_as_state_machine/init.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require 'acts_as_state_machine'
-
-ActiveRecord::Base.class_eval do
- include ScottBarron::Acts::StateMachine
-end
diff --git a/vendor/plugins/acts_as_state_machine/lib/acts_as_state_machine.rb b/vendor/plugins/acts_as_state_machine/lib/acts_as_state_machine.rb
deleted file mode 100644
index cbbf5f1f..00000000
--- a/vendor/plugins/acts_as_state_machine/lib/acts_as_state_machine.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-module ScottBarron #:nodoc:
- module Acts #:nodoc:
- module StateMachine #:nodoc:
- class InvalidState < Exception #:nodoc:
- end
- class NoInitialState < Exception #:nodoc:
- end
-
- def self.included(base) #:nodoc:
- base.extend ActMacro
- end
-
- module SupportingClasses
- class State
- attr_reader :name
-
- def initialize(name, opts)
- @name, @opts = name, opts
- end
-
- def entering(record)
- enteract = @opts[:enter]
- record.send(:run_transition_action, enteract) if enteract
- end
-
- def entered(record)
- afteractions = @opts[:after]
- return unless afteractions
- Array(afteractions).each do |afteract|
- record.send(:run_transition_action, afteract)
- end
- end
-
- def exited(record)
- exitact = @opts[:exit]
- record.send(:run_transition_action, exitact) if exitact
- end
- end
-
- class StateTransition
- attr_reader :from, :to, :opts
-
- def initialize(opts)
- @from, @to, @guard = opts[:from], opts[:to], opts[:guard]
- @opts = opts
- end
-
- def guard(obj)
- @guard ? obj.send(:run_transition_action, @guard) : true
- end
-
- def perform(record)
- return false unless guard(record)
- loopback = record.current_state == to
- states = record.class.read_inheritable_attribute(:states)
- next_state = states[to]
- old_state = states[record.current_state]
-
- next_state.entering(record) unless loopback
- if record.new_record?
- record.send(record.class.state_column.to_s + '=', to.to_s)
- else
- record.update_attribute(record.class.state_column, to.to_s)
- end
-
- next_state.entered(record) unless loopback
- old_state.exited(record) unless loopback
- true
- end
-
- def ==(obj)
- @from == obj.from && @to == obj.to
- end
- end
-
- class Event
- attr_reader :name
- attr_reader :transitions
- attr_reader :opts
-
- def initialize(name, opts, transition_table, &block)
- @name = name.to_sym
- @transitions = transition_table[@name] = []
- instance_eval(&block) if block
- @opts = opts
- @opts.freeze
- @transitions.freeze
- freeze
- end
-
- def next_states(record)
- @transitions.select { |t| t.from == record.current_state }
- end
-
- def fire(record)
- next_states(record).each do |transition|
- break true if transition.perform(record)
- end
- end
-
- def transitions(trans_opts)
- Array(trans_opts[:from]).each do |s|
- @transitions << SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
- end
- end
- end
- end
-
- module ActMacro
- # Configuration options are
- #
- # * +column+ - specifies the column name to use for keeping the state (default: state)
- # * +initial+ - specifies an initial state for newly created objects (required)
- def acts_as_state_machine(opts)
- self.extend(ClassMethods)
- raise NoInitialState unless opts[:initial]
-
- write_inheritable_attribute :states, {}
- write_inheritable_attribute :initial_state, opts[:initial]
- write_inheritable_attribute :transition_table, {}
- write_inheritable_attribute :event_table, {}
- write_inheritable_attribute :state_column, opts[:column] || 'state'
-
- class_inheritable_reader :initial_state
- class_inheritable_reader :state_column
- class_inheritable_reader :transition_table
- class_inheritable_reader :event_table
-
- self.send(:include, ScottBarron::Acts::StateMachine::InstanceMethods)
-
- before_create :set_initial_state
- after_create :run_initial_state_actions
- end
- end
-
- module InstanceMethods
- def set_initial_state #:nodoc:
- write_attribute self.class.state_column, self.class.initial_state.to_s
- end
-
- def run_initial_state_actions
- initial = self.class.read_inheritable_attribute(:states)[self.class.initial_state.to_sym]
- initial.entering(self)
- initial.entered(self)
- end
-
- # Returns the current state the object is in, as a Ruby symbol.
- def current_state
- x = self.send(self.class.state_column)
- return x.to_sym if not x.nil?
-
- # if current state is not yet set, set it
- self.set_initial_state
- return self.current_state
- end
-
- # Returns what the next state for a given event would be, as a Ruby symbol.
- def next_state_for_event(event)
- ns = next_states_for_event(event)
- ns.empty? ? nil : ns.first.to
- end
-
- def next_states_for_event(event)
- self.class.read_inheritable_attribute(:transition_table)[event.to_sym].select do |s|
- s.from == current_state
- end
- end
-
- def run_transition_action(action)
- Symbol === action ? self.method(action).call : action.call(self)
- end
- private :run_transition_action
- end
-
- module ClassMethods
- # Returns an array of all known states.
- def states
- read_inheritable_attribute(:states).keys
- end
-
- # Define an event. This takes a block which describes all valid transitions
- # for this event.
- #
- # Example:
- #
- # class Order < ActiveRecord::Base
- # acts_as_state_machine :initial => :open
- #
- # state :open
- # state :closed
- #
- # event :close_order do
- # transitions :to => :closed, :from => :open
- # end
- # end
- #
- # +transitions+ takes a hash where :to is the state to transition
- # to and :from is a state (or Array of states) from which this
- # event can be fired.
- #
- # This creates an instance method used for firing the event. The method
- # created is the name of the event followed by an exclamation point (!).
- # Example: order.close_order!.
- def event(event, opts={}, &block)
- tt = read_inheritable_attribute(:transition_table)
-
- et = read_inheritable_attribute(:event_table)
- e = et[event.to_sym] = SupportingClasses::Event.new(event, opts, tt, &block)
- define_method("#{event.to_s}!") { e.fire(self) }
- end
-
- # Define a state of the system. +state+ can take an optional Proc object
- # which will be executed every time the system transitions into that
- # state. The proc will be passed the current object.
- #
- # Example:
- #
- # class Order < ActiveRecord::Base
- # acts_as_state_machine :initial => :open
- #
- # state :open
- # state :closed, Proc.new { |o| Mailer.send_notice(o) }
- # end
- def state(name, opts={})
- state = SupportingClasses::State.new(name.to_sym, opts)
- read_inheritable_attribute(:states)[name.to_sym] = state
-
- define_method("#{state.name}?") { current_state == state.name }
- end
-
- # Wraps ActiveRecord::Base.find to conveniently find all records in
- # a given state. Options:
- #
- # * +number+ - This is just :first or :all from ActiveRecord +find+
- # * +state+ - The state to find
- # * +args+ - The rest of the args are passed down to ActiveRecord +find+
- def find_in_state(number, state, *args)
- with_state_scope state do
- find(number, *args)
- end
- end
-
- # Wraps ActiveRecord::Base.count to conveniently count all records in
- # a given state. Options:
- #
- # * +state+ - The state to find
- # * +args+ - The rest of the args are passed down to ActiveRecord +find+
- def count_in_state(state, *args)
- with_state_scope state do
- count(*args)
- end
- end
-
- # Wraps ActiveRecord::Base.calculate to conveniently calculate all records in
- # a given state. Options:
- #
- # * +state+ - The state to find
- # * +args+ - The rest of the args are passed down to ActiveRecord +calculate+
- def calculate_in_state(state, *args)
- with_state_scope state do
- calculate(*args)
- end
- end
-
- protected
- def with_state_scope(state)
- raise InvalidState unless states.include?(state)
-
- with_scope :find => {:conditions => ["#{table_name}.#{state_column} = ?", state.to_s]} do
- yield if block_given?
- end
- end
- end
- end
- end
-end
\ No newline at end of file
diff --git a/vendor/plugins/acts_as_state_machine/test/acts_as_state_machine_test.rb b/vendor/plugins/acts_as_state_machine/test/acts_as_state_machine_test.rb
deleted file mode 100644
index e1135152..00000000
--- a/vendor/plugins/acts_as_state_machine/test/acts_as_state_machine_test.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-require File.dirname(__FILE__) + '/test_helper'
-
-include ScottBarron::Acts::StateMachine
-
-class ActsAsStateMachineTest < Test::Unit::TestCase
- fixtures :conversations
-
- def test_no_initial_value_raises_exception
- assert_raise(NoInitialState) {
- Person.acts_as_state_machine({})
- }
- end
-
- def test_initial_state_value
- assert_equal :needs_attention, Conversation.initial_state
- end
-
- def test_column_was_set
- assert_equal 'state_machine', Conversation.state_column
- end
-
- def test_initial_state
- c = Conversation.create
- assert_equal :needs_attention, c.current_state
- assert c.needs_attention?
- end
-
- def test_states_were_set
- [:needs_attention, :read, :closed, :awaiting_response, :junk].each do |s|
- assert Conversation.states.include?(s)
- end
- end
-
- def test_event_methods_created
- c = Conversation.create
- %w(new_message! view! reply! close! junk! unjunk!).each do |event|
- assert c.respond_to?(event)
- end
- end
-
- def test_query_methods_created
- c = Conversation.create
- %w(needs_attention? read? closed? awaiting_response? junk?).each do |event|
- assert c.respond_to?(event)
- end
- end
-
- def test_transition_table
- tt = Conversation.transition_table
-
- assert tt[:new_message].include?(SupportingClasses::StateTransition.new(:from => :read, :to => :needs_attention))
- assert tt[:new_message].include?(SupportingClasses::StateTransition.new(:from => :closed, :to => :needs_attention))
- assert tt[:new_message].include?(SupportingClasses::StateTransition.new(:from => :awaiting_response, :to => :needs_attention))
- end
-
- def test_next_state_for_event
- c = Conversation.create
- assert_equal :read, c.next_state_for_event(:view)
- end
-
- def test_change_state
- c = Conversation.create
- c.view!
- assert c.read?
- end
-
- def test_can_go_from_read_to_closed_because_guard_passes
- c = Conversation.create
- c.can_close = true
- c.view!
- c.reply!
- c.close!
- assert_equal :closed, c.current_state
- end
-
- def test_cannot_go_from_read_to_closed_because_of_guard
- c = Conversation.create
- c.can_close = false
- c.view!
- c.reply!
- c.close!
- assert_equal :read, c.current_state
- end
-
- def test_ignore_invalid_events
- c = Conversation.create
- c.view!
- c.junk!
-
- # This is the invalid event
- c.new_message!
- assert_equal :junk, c.current_state
- end
-
- def test_entry_action_executed
- c = Conversation.create
- c.read_enter = false
- c.view!
- assert c.read_enter
- end
-
- def test_after_actions_executed
- c = Conversation.create
-
- c.read_after_first = false
- c.read_after_second = false
- c.closed_after = false
-
- c.view!
- assert c.read_after_first
- assert c.read_after_second
-
- c.can_close = true
- c.close!
-
- assert c.closed_after
- assert_equal :closed, c.current_state
- end
-
- def test_after_actions_not_run_on_loopback_transition
- c = Conversation.create
-
- c.view!
- c.read_after_first = false
- c.read_after_second = false
- c.view!
-
- assert !c.read_after_first
- assert !c.read_after_second
-
- c.can_close = true
-
- c.close!
- c.closed_after = false
- c.close!
-
- assert !c.closed_after
- end
-
- def test_exit_action_executed
- c = Conversation.create
- c.read_exit = false
- c.view!
- c.junk!
- assert c.read_exit
- end
-
- def test_entry_and_exit_not_run_on_loopback_transition
- c = Conversation.create
- c.view!
- c.read_enter = false
- c.read_exit = false
- c.view!
- assert !c.read_enter
- assert !c.read_exit
- end
-
- def test_entry_and_after_actions_called_for_initial_state
- c = Conversation.create
- assert c.needs_attention_enter
- assert c.needs_attention_after
- end
-
- def test_run_transition_action_is_private
- c = Conversation.create
- assert_raise(NoMethodError) { c.run_transition_action :foo }
- end
-
- def test_find_all_in_state
- cs = Conversation.find_in_state(:all, :read)
-
- assert_equal 2, cs.size
- end
-
- def test_find_first_in_state
- c = Conversation.find_in_state(:first, :read)
-
- assert_equal conversations(:first).id, c.id
- end
-
- def test_find_all_in_state_with_conditions
- cs = Conversation.find_in_state(:all, :read, :conditions => ['subject = ?', conversations(:second).subject])
-
- assert_equal 1, cs.size
- assert_equal conversations(:second).id, cs.first.id
- end
-
- def test_find_first_in_state_with_conditions
- c = Conversation.find_in_state(:first, :read, :conditions => ['subject = ?', conversations(:second).subject])
- assert_equal conversations(:second).id, c.id
- end
-
- def test_count_in_state
- cnt0 = Conversation.count(['state_machine = ?', 'read'])
- cnt = Conversation.count_in_state(:read)
-
- assert_equal cnt0, cnt
- end
-
- def test_count_in_state_with_conditions
- cnt0 = Conversation.count(['state_machine = ? AND subject = ?', 'read', 'Foo'])
- cnt = Conversation.count_in_state(:read, ['subject = ?', 'Foo'])
-
- assert_equal cnt0, cnt
- end
-
- def test_find_in_invalid_state_raises_exception
- assert_raise(InvalidState) {
- Conversation.find_in_state(:all, :dead)
- }
- end
-
- def test_count_in_invalid_state_raises_exception
- assert_raise(InvalidState) {
- Conversation.count_in_state(:dead)
- }
- end
-
- def test_can_access_events_via_event_table
- event = Conversation.event_table[:junk]
- assert_equal :junk, event.name
- assert_equal "finished", event.opts[:note]
- end
-end
diff --git a/vendor/plugins/acts_as_state_machine/test/database.yml b/vendor/plugins/acts_as_state_machine/test/database.yml
deleted file mode 100644
index f012c25c..00000000
--- a/vendor/plugins/acts_as_state_machine/test/database.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-sqlite:
- :adapter: sqlite
- :dbfile: state_machine.sqlite.db
-sqlite3:
- :adapter: sqlite3
- :dbfile: state_machine.sqlite3.db
-postgresql:
- :adapter: postgresql
- :username: postgres
- :password: postgres
- :database: state_machine_test
- :min_messages: ERROR
-mysql:
- :adapter: mysql
- :host: localhost
- :username: rails
- :password:
- :database: state_machine_test
\ No newline at end of file
diff --git a/vendor/plugins/acts_as_state_machine/test/fixtures/conversation.rb b/vendor/plugins/acts_as_state_machine/test/fixtures/conversation.rb
deleted file mode 100644
index 8b414325..00000000
--- a/vendor/plugins/acts_as_state_machine/test/fixtures/conversation.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-class Conversation < ActiveRecord::Base
- attr_writer :can_close
- attr_accessor :read_enter, :read_exit, :read_after_first, :read_after_second,
- :closed_after, :needs_attention_enter, :needs_attention_after
-
- acts_as_state_machine :initial => :needs_attention, :column => 'state_machine'
-
- state :needs_attention, :enter => Proc.new { |o| o.needs_attention_enter = true },
- :after => Proc.new { |o| o.needs_attention_after = true }
-
- state :read, :enter => :read_enter_action,
- :exit => Proc.new { |o| o.read_exit = true },
- :after => [:read_after_first_action, :read_after_second_action]
-
- state :closed, :after => :closed_after_action
- state :awaiting_response
- state :junk
-
- event :new_message do
- transitions :to => :needs_attention, :from => [:read, :closed, :awaiting_response]
- end
-
- event :view do
- transitions :to => :read, :from => [:needs_attention, :read]
- end
-
- event :reply do
- transitions :to => :awaiting_response, :from => [:read, :closed]
- end
-
- event :close do
- transitions :to => :closed, :from => [:read, :awaiting_response], :guard => Proc.new {|o| o.can_close?}
- transitions :to => :read, :from => [:read, :awaiting_response], :guard => :always_true
- end
-
- event :junk, :note => "finished" do
- transitions :to => :junk, :from => [:read, :closed, :awaiting_response]
- end
-
- event :unjunk do
- transitions :to => :closed, :from => :junk
- end
-
- def can_close?
- @can_close
- end
-
- def read_enter_action
- self.read_enter = true
- end
-
- def always_true
- true
- end
-
- def read_after_first_action
- self.read_after_first = true
- end
-
- def read_after_second_action
- self.read_after_second = true
- end
-
- def closed_after_action
- self.closed_after = true
- end
-end
diff --git a/vendor/plugins/acts_as_state_machine/test/fixtures/conversations.yml b/vendor/plugins/acts_as_state_machine/test/fixtures/conversations.yml
deleted file mode 100644
index 572e0ee1..00000000
--- a/vendor/plugins/acts_as_state_machine/test/fixtures/conversations.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-first:
- id: 1
- state_machine: read
- subject: This is a test
- closed: false
-
-second:
- id: 2
- state_machine: read
- subject: Foo
- closed: false
diff --git a/vendor/plugins/acts_as_state_machine/test/fixtures/person.rb b/vendor/plugins/acts_as_state_machine/test/fixtures/person.rb
deleted file mode 100644
index e64a8262..00000000
--- a/vendor/plugins/acts_as_state_machine/test/fixtures/person.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class Person < ActiveRecord::Base
-end
\ No newline at end of file
diff --git a/vendor/plugins/acts_as_state_machine/test/schema.rb b/vendor/plugins/acts_as_state_machine/test/schema.rb
deleted file mode 100644
index 50128995..00000000
--- a/vendor/plugins/acts_as_state_machine/test/schema.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-ActiveRecord::Schema.define(:version => 1) do
- create_table :conversations, :force => true do |t|
- t.column :state_machine, :string
- t.column :subject, :string
- t.column :closed, :boolean
- end
-
- create_table :people, :force => true do |t|
- t.column :name, :string
- end
-end
diff --git a/vendor/plugins/acts_as_state_machine/test/test_helper.rb b/vendor/plugins/acts_as_state_machine/test/test_helper.rb
deleted file mode 100644
index 95331d03..00000000
--- a/vendor/plugins/acts_as_state_machine/test/test_helper.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-$:.unshift(File.dirname(__FILE__) + '/../lib')
-RAILS_ROOT = File.dirname(__FILE__)
-
-require 'rubygems'
-require 'test/unit'
-require 'active_record'
-require 'active_record/fixtures'
-require 'active_support/binding_of_caller'
-require 'active_support/breakpoint'
-require "#{File.dirname(__FILE__)}/../init"
-
-
-config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
-ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
-ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
-
-load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
-
-Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
-$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
-
-class Test::Unit::TestCase #:nodoc:
- def create_fixtures(*table_names)
- if block_given?
- Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
- else
- Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
- end
- end
-
- # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
- self.use_transactional_fixtures = true
-
- # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
- self.use_instantiated_fixtures = false
-
- # Add more helper methods to be used by all tests here...
-end
\ No newline at end of file