aasm 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/{README.rdoc → README.md} +53 -41
- data/Rakefile +13 -94
- data/aasm.gemspec +21 -87
- data/lib/aasm/aasm.rb +28 -2
- data/lib/aasm/event.rb +19 -1
- data/lib/aasm/localizer.rb +36 -0
- data/lib/aasm/state_machine.rb +6 -7
- data/lib/aasm/state_transition.rb +7 -7
- data/lib/aasm/version.rb +3 -0
- data/lib/aasm.rb +1 -0
- data/spec/database.yml +3 -0
- data/spec/en.yml +10 -0
- data/spec/schema.rb +7 -0
- data/spec/spec_helper.rb +10 -5
- data/spec/unit/active_record_persistence_spec.rb +42 -51
- data/spec/unit/event_spec.rb +14 -0
- data/spec/unit/localizer_spec.rb +51 -0
- data/spec/unit/state_transition_spec.rb +79 -0
- data/test/functional/auth_machine_test.rb +28 -0
- data/test/models/process.rb +18 -0
- data/test/test_helper.rb +12 -2
- data/test/unit/state_machine_test.rb +37 -0
- metadata +121 -16
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/Gemfile
ADDED
data/{README.rdoc → README.md}
RENAMED
|
@@ -1,72 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
If you are looking for an alternative to AASM, I would highly suggest transitions: http://github.com/qoobaa/transitions
|
|
4
|
-
|
|
5
|
-
= AASM - Ruby state machines
|
|
1
|
+
# AASM - Ruby state machines #
|
|
6
2
|
|
|
7
3
|
This package contains AASM, a library for adding finite state machines to Ruby classes.
|
|
8
4
|
|
|
9
5
|
AASM started as the acts_as_state_machine plugin but has evolved into a more generic library that no longer targets only ActiveRecord models.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
## Features ##
|
|
12
8
|
|
|
13
9
|
* States
|
|
14
10
|
* Machines
|
|
15
11
|
* Events
|
|
16
12
|
* Transitions
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
## New Callbacks ##
|
|
19
15
|
|
|
20
16
|
The callback chain & order on a successful event looks like:
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
18
|
+
oldstate:exit*
|
|
19
|
+
event:before
|
|
20
|
+
__find transition, if possible__
|
|
21
|
+
transition:on_transition*
|
|
22
|
+
oldstate:before_exit
|
|
23
|
+
newstate:before_enter
|
|
24
|
+
newstate:enter*
|
|
25
|
+
__update state__
|
|
26
|
+
event:success*
|
|
27
|
+
oldstate:after_exit
|
|
28
|
+
newstate:after_enter
|
|
29
|
+
event:after
|
|
30
|
+
obj:aasm_event_fired*
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
(*) marks old callbacks
|
|
37
33
|
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
## Download ##
|
|
40
36
|
|
|
41
37
|
The latest AASM can currently be pulled from the git repository on github.
|
|
42
38
|
|
|
43
39
|
* http://github.com/rubyist/aasm/tree/master
|
|
44
40
|
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
=== From gemcutter
|
|
49
|
-
|
|
50
|
-
% sudo gem install gemcutter
|
|
51
|
-
% sudo gem tumble
|
|
52
|
-
% sudo gem install aasm
|
|
42
|
+
## Installation ##
|
|
53
43
|
|
|
54
|
-
|
|
44
|
+
### From RubyGems.org ###
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
46
|
+
```sh
|
|
47
|
+
% gem install aasm
|
|
48
|
+
```
|
|
58
49
|
|
|
59
|
-
|
|
50
|
+
### Building your own gems ###
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
```sh
|
|
53
|
+
% rake build
|
|
54
|
+
% sudo gem install pkg/aasm-x.y.z.gem
|
|
55
|
+
```
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
== Simple Example
|
|
57
|
+
## Simple Example ##
|
|
67
58
|
|
|
68
59
|
Here's a quick example highlighting some of the features.
|
|
69
60
|
|
|
61
|
+
```ruby
|
|
70
62
|
class Conversation
|
|
71
63
|
include AASM
|
|
72
64
|
|
|
@@ -87,11 +79,13 @@ Here's a quick example highlighting some of the features.
|
|
|
87
79
|
transitions :to => :closed, :from => [:read, :unread]
|
|
88
80
|
end
|
|
89
81
|
end
|
|
82
|
+
```
|
|
90
83
|
|
|
91
|
-
|
|
84
|
+
## A Slightly More Complex Example ##
|
|
92
85
|
|
|
93
86
|
This example uses a few of the more complex features available.
|
|
94
87
|
|
|
88
|
+
```ruby
|
|
95
89
|
class Relationship
|
|
96
90
|
include AASM
|
|
97
91
|
|
|
@@ -121,15 +115,33 @@ This example uses a few of the more complex features available.
|
|
|
121
115
|
def give_up_intimacy; end
|
|
122
116
|
def buy_exotic_car_and_wear_a_combover; end
|
|
123
117
|
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Callbacks around events
|
|
121
|
+
```ruby
|
|
122
|
+
class Relationship
|
|
123
|
+
include AASM
|
|
124
|
+
|
|
125
|
+
aasm_state :dating
|
|
126
|
+
aasm_state :married
|
|
127
|
+
|
|
128
|
+
aasm_event :get_married,
|
|
129
|
+
:before => :make_vows,
|
|
130
|
+
:after => :eat_wedding_cake do
|
|
131
|
+
transitions :to => :married, :from => [:dating]
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
# Other Stuff #
|
|
126
138
|
|
|
127
139
|
Author:: Scott Barron <scott at elitists dot net>
|
|
128
140
|
License:: Original code Copyright 2006, 2007, 2008 by Scott Barron.
|
|
129
141
|
Released under an MIT-style license. See the LICENSE file
|
|
130
142
|
included in the distribution.
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
## Warranty ##
|
|
133
145
|
|
|
134
146
|
This software is provided "as is" and without any express or
|
|
135
147
|
implied warranties, including, without limitation, the implied
|
data/Rakefile
CHANGED
|
@@ -1,108 +1,27 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require 'rake'
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
gem.summary = %Q{State machine mixin for Ruby objects}
|
|
9
|
-
gem.description = %Q{AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.}
|
|
10
|
-
gem.homepage = "http://rubyist.github.com/aasm/"
|
|
11
|
-
gem.authors = ["Scott Barron", "Scott Petersen", "Travis Tilley"]
|
|
12
|
-
gem.email = "scott@elitists.net, ttilley@gmail.com"
|
|
13
|
-
gem.add_development_dependency "rspec"
|
|
14
|
-
gem.add_development_dependency "shoulda"
|
|
15
|
-
gem.add_development_dependency 'sdoc'
|
|
16
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
17
|
-
end
|
|
18
|
-
Jeweler::GemcutterTasks.new
|
|
19
|
-
rescue LoadError
|
|
20
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
3
|
+
require 'rspec/core'
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
6
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
|
21
7
|
end
|
|
22
8
|
|
|
23
|
-
require 'spec/rake/spectask'
|
|
24
9
|
require 'rake/testtask'
|
|
25
|
-
|
|
26
10
|
Rake::TestTask.new(:test) do |test|
|
|
27
11
|
test.libs << 'lib' << 'test'
|
|
28
12
|
test.pattern = 'test/**/*_test.rb'
|
|
29
13
|
test.verbose = true
|
|
30
14
|
end
|
|
31
15
|
|
|
32
|
-
begin
|
|
33
|
-
require 'rcov/rcovtask'
|
|
34
|
-
Rcov::RcovTask.new(:rcov_shoulda) do |test|
|
|
35
|
-
test.libs << 'test'
|
|
36
|
-
test.pattern = 'test/**/*_test.rb'
|
|
37
|
-
test.verbose = true
|
|
38
|
-
end
|
|
39
|
-
rescue LoadError
|
|
40
|
-
task :rcov do
|
|
41
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
46
|
-
spec.libs << 'lib' << 'spec'
|
|
47
|
-
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
48
|
-
spec.spec_opts = ['-cfs']
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
Spec::Rake::SpecTask.new(:rcov_rspec) do |spec|
|
|
52
|
-
spec.libs << 'lib' << 'spec'
|
|
53
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
|
54
|
-
spec.rcov = true
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
task :test => :check_dependencies
|
|
58
|
-
task :spec => :check_dependencies
|
|
59
|
-
|
|
60
|
-
begin
|
|
61
|
-
require 'reek/rake_task'
|
|
62
|
-
Reek::RakeTask.new do |t|
|
|
63
|
-
t.fail_on_error = true
|
|
64
|
-
t.verbose = false
|
|
65
|
-
t.source_files = 'lib/**/*.rb'
|
|
66
|
-
end
|
|
67
|
-
rescue LoadError
|
|
68
|
-
task :reek do
|
|
69
|
-
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
begin
|
|
74
|
-
require 'roodi'
|
|
75
|
-
require 'roodi_task'
|
|
76
|
-
RoodiTask.new do |t|
|
|
77
|
-
t.verbose = false
|
|
78
|
-
end
|
|
79
|
-
rescue LoadError
|
|
80
|
-
task :roodi do
|
|
81
|
-
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
16
|
task :default => :test
|
|
86
17
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Rake::RDocTask.new do |rdoc|
|
|
91
|
-
if File.exist?('VERSION')
|
|
92
|
-
version = File.read('VERSION')
|
|
93
|
-
else
|
|
94
|
-
version = ""
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
98
|
-
rdoc.title = "aasm #{version}"
|
|
99
|
-
rdoc.rdoc_files.include('README*')
|
|
100
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
18
|
+
require 'rdoc/task'
|
|
19
|
+
require 'aasm/version'
|
|
20
|
+
require 'sdoc'
|
|
101
21
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
22
|
+
Rake::RDocTask.new do |rdoc|
|
|
23
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
24
|
+
rdoc.title = "aasm #{AASM::VERSION}"
|
|
25
|
+
rdoc.rdoc_files.include('README*')
|
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
107
27
|
end
|
|
108
|
-
|
data/aasm.gemspec
CHANGED
|
@@ -1,94 +1,28 @@
|
|
|
1
|
-
# Generated by jeweler
|
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
|
4
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "aasm/version"
|
|
5
4
|
|
|
6
5
|
Gem::Specification.new do |s|
|
|
7
|
-
s.name
|
|
8
|
-
s.version
|
|
9
|
-
|
|
10
|
-
s.
|
|
11
|
-
s.
|
|
12
|
-
s.
|
|
6
|
+
s.name = "aasm"
|
|
7
|
+
s.version = AASM::VERSION
|
|
8
|
+
s.authors = ["Scott Barron", "Scott Petersen", "Travis Tilley", "Thorsten Böttger"]
|
|
9
|
+
s.email = %q{scott@elitists.net, ttilley@gmail.com}
|
|
10
|
+
s.homepage = %q{http://rubyist.github.com/aasm/}
|
|
11
|
+
s.summary = %q{State machine mixin for Ruby objects}
|
|
13
12
|
s.description = %q{AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.}
|
|
14
|
-
s.email = %q{scott@elitists.net, ttilley@gmail.com}
|
|
15
|
-
s.extra_rdoc_files = [
|
|
16
|
-
"LICENSE",
|
|
17
|
-
"README.rdoc"
|
|
18
|
-
]
|
|
19
|
-
s.files = [
|
|
20
|
-
".document",
|
|
21
|
-
".gitignore",
|
|
22
|
-
"LICENSE",
|
|
23
|
-
"README.rdoc",
|
|
24
|
-
"Rakefile",
|
|
25
|
-
"VERSION",
|
|
26
|
-
"aasm.gemspec",
|
|
27
|
-
"lib/aasm.rb",
|
|
28
|
-
"lib/aasm/aasm.rb",
|
|
29
|
-
"lib/aasm/event.rb",
|
|
30
|
-
"lib/aasm/persistence.rb",
|
|
31
|
-
"lib/aasm/persistence/active_record_persistence.rb",
|
|
32
|
-
"lib/aasm/state.rb",
|
|
33
|
-
"lib/aasm/state_machine.rb",
|
|
34
|
-
"lib/aasm/state_transition.rb",
|
|
35
|
-
"lib/aasm/supporting_classes.rb",
|
|
36
|
-
"spec/functional/conversation.rb",
|
|
37
|
-
"spec/functional/conversation_spec.rb",
|
|
38
|
-
"spec/spec_helper.rb",
|
|
39
|
-
"spec/unit/aasm_spec.rb",
|
|
40
|
-
"spec/unit/active_record_persistence_spec.rb",
|
|
41
|
-
"spec/unit/before_after_callbacks_spec.rb",
|
|
42
|
-
"spec/unit/event_spec.rb",
|
|
43
|
-
"spec/unit/state_spec.rb",
|
|
44
|
-
"spec/unit/state_transition_spec.rb",
|
|
45
|
-
"test/functional/auth_machine_test.rb",
|
|
46
|
-
"test/test_helper.rb",
|
|
47
|
-
"test/unit/aasm_test.rb",
|
|
48
|
-
"test/unit/event_test.rb",
|
|
49
|
-
"test/unit/state_test.rb",
|
|
50
|
-
"test/unit/state_transition_test.rb"
|
|
51
|
-
]
|
|
52
|
-
s.homepage = %q{http://rubyist.github.com/aasm/}
|
|
53
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
|
54
|
-
s.require_paths = ["lib"]
|
|
55
|
-
s.rubygems_version = %q{1.3.7}
|
|
56
|
-
s.summary = %q{State machine mixin for Ruby objects}
|
|
57
|
-
s.test_files = [
|
|
58
|
-
"spec/functional/conversation.rb",
|
|
59
|
-
"spec/functional/conversation_spec.rb",
|
|
60
|
-
"spec/spec_helper.rb",
|
|
61
|
-
"spec/unit/aasm_spec.rb",
|
|
62
|
-
"spec/unit/active_record_persistence_spec.rb",
|
|
63
|
-
"spec/unit/before_after_callbacks_spec.rb",
|
|
64
|
-
"spec/unit/event_spec.rb",
|
|
65
|
-
"spec/unit/state_spec.rb",
|
|
66
|
-
"spec/unit/state_transition_spec.rb",
|
|
67
|
-
"test/functional/auth_machine_test.rb",
|
|
68
|
-
"test/test_helper.rb",
|
|
69
|
-
"test/unit/aasm_test.rb",
|
|
70
|
-
"test/unit/event_test.rb",
|
|
71
|
-
"test/unit/state_test.rb",
|
|
72
|
-
"test/unit/state_transition_test.rb"
|
|
73
|
-
]
|
|
74
13
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
14
|
+
s.add_dependency 'activerecord'
|
|
15
|
+
s.add_development_dependency 'rake'
|
|
16
|
+
s.add_development_dependency 'sdoc'
|
|
17
|
+
s.add_development_dependency 'rspec', '~> 2.0'
|
|
18
|
+
s.add_development_dependency 'rr'
|
|
19
|
+
s.add_development_dependency 'shoulda'
|
|
20
|
+
s.add_development_dependency 'sqlite3'
|
|
21
|
+
s.add_development_dependency 'minitest'
|
|
22
|
+
s.add_development_dependency 'ruby-debug-completion'
|
|
78
23
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
else
|
|
84
|
-
s.add_dependency(%q<rspec>, [">= 0"])
|
|
85
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
86
|
-
s.add_dependency(%q<sdoc>, [">= 0"])
|
|
87
|
-
end
|
|
88
|
-
else
|
|
89
|
-
s.add_dependency(%q<rspec>, [">= 0"])
|
|
90
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
91
|
-
s.add_dependency(%q<sdoc>, [">= 0"])
|
|
92
|
-
end
|
|
24
|
+
s.files = `git ls-files`.split("\n")
|
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
27
|
+
s.require_paths = ["lib"]
|
|
93
28
|
end
|
|
94
|
-
|
data/lib/aasm/aasm.rb
CHANGED
|
@@ -7,6 +7,7 @@ module AASM
|
|
|
7
7
|
|
|
8
8
|
def self.included(base) #:nodoc:
|
|
9
9
|
base.extend AASM::ClassMethods
|
|
10
|
+
|
|
10
11
|
AASM::Persistence.set_persistence(base)
|
|
11
12
|
unless AASM::StateMachine[base]
|
|
12
13
|
AASM::StateMachine[base] = AASM::StateMachine.new('')
|
|
@@ -41,7 +42,7 @@ module AASM
|
|
|
41
42
|
aasm_current_state == name
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
def aasm_event(name, options = {}, &block)
|
|
46
47
|
sm = AASM::StateMachine[self]
|
|
47
48
|
|
|
@@ -49,6 +50,13 @@ module AASM
|
|
|
49
50
|
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
# an addition over standard aasm so that, before firing an event, you can ask
|
|
54
|
+
# may_event? and get back a boolean that tells you whether the guard method
|
|
55
|
+
# on the transition will let this happen.
|
|
56
|
+
define_method("may_#{name.to_s}?") do |*args|
|
|
57
|
+
aasm_test_event(name, *args)
|
|
58
|
+
end
|
|
59
|
+
|
|
52
60
|
define_method("#{name.to_s}!") do |*args|
|
|
53
61
|
aasm_fire_event(name, true, *args)
|
|
54
62
|
end
|
|
@@ -70,8 +78,11 @@ module AASM
|
|
|
70
78
|
AASM::StateMachine[self].states.map { |state| state.for_select }
|
|
71
79
|
end
|
|
72
80
|
|
|
81
|
+
def human_event_name(event)
|
|
82
|
+
AASM::Localizer.new.human_event_name(self, event)
|
|
83
|
+
end
|
|
73
84
|
end
|
|
74
|
-
|
|
85
|
+
|
|
75
86
|
# Instance methods
|
|
76
87
|
def aasm_current_state
|
|
77
88
|
return @aasm_current_state if @aasm_current_state
|
|
@@ -100,11 +111,21 @@ module AASM
|
|
|
100
111
|
aasm_events_for_state(aasm_current_state)
|
|
101
112
|
end
|
|
102
113
|
|
|
114
|
+
# filters the results of events_for_current_state so that only those that
|
|
115
|
+
# are really currently possible (given transition guards) are shown.
|
|
116
|
+
def aasm_permissible_events_for_current_state
|
|
117
|
+
aasm_events_for_current_state.select{ |e| self.send(("may_" + e.to_s + "?").to_sym) }
|
|
118
|
+
end
|
|
119
|
+
|
|
103
120
|
def aasm_events_for_state(state)
|
|
104
121
|
events = self.class.aasm_events.values.select {|event| event.transitions_from_state?(state) }
|
|
105
122
|
events.map {|event| event.name}
|
|
106
123
|
end
|
|
107
124
|
|
|
125
|
+
def human_state
|
|
126
|
+
AASM::Localizer.new.human_state(self)
|
|
127
|
+
end
|
|
128
|
+
|
|
108
129
|
private
|
|
109
130
|
|
|
110
131
|
def set_aasm_current_state_with_persistence(state)
|
|
@@ -141,6 +162,11 @@ module AASM
|
|
|
141
162
|
obj
|
|
142
163
|
end
|
|
143
164
|
|
|
165
|
+
def aasm_test_event(name, *args)
|
|
166
|
+
event = self.class.aasm_events[name]
|
|
167
|
+
event.may_fire?(self, *args)
|
|
168
|
+
end
|
|
169
|
+
|
|
144
170
|
def aasm_fire_event(name, persist, *args)
|
|
145
171
|
event = self.class.aasm_events[name]
|
|
146
172
|
begin
|
data/lib/aasm/event.rb
CHANGED
|
@@ -7,6 +7,24 @@ class AASM::SupportingClasses::Event
|
|
|
7
7
|
update(options, &block)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
# a neutered version of fire - it doesn't actually fir the event, it just
|
|
11
|
+
# executes the transition guards to determine if a transition is even
|
|
12
|
+
# an option given current conditions.
|
|
13
|
+
def may_fire?(obj, to_state=nil)
|
|
14
|
+
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
|
15
|
+
return false if transitions.size == 0
|
|
16
|
+
|
|
17
|
+
result = false
|
|
18
|
+
transitions.each do |transition|
|
|
19
|
+
next if to_state and !Array(transition.to).include?(to_state)
|
|
20
|
+
if transition.perform(obj)
|
|
21
|
+
result = true
|
|
22
|
+
break
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
result
|
|
26
|
+
end
|
|
27
|
+
|
|
10
28
|
def fire(obj, to_state=nil, *args)
|
|
11
29
|
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
|
12
30
|
raise AASM::InvalidTransition, "Event '#{name}' cannot transition from '#{obj.aasm_current_state}'" if transitions.size == 0
|
|
@@ -14,7 +32,7 @@ class AASM::SupportingClasses::Event
|
|
|
14
32
|
next_state = nil
|
|
15
33
|
transitions.each do |transition|
|
|
16
34
|
next if to_state and !Array(transition.to).include?(to_state)
|
|
17
|
-
if transition.perform(obj)
|
|
35
|
+
if transition.perform(obj, *args)
|
|
18
36
|
next_state = to_state || Array(transition.to).first
|
|
19
37
|
transition.execute(obj, *args)
|
|
20
38
|
break
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class AASM::Localizer
|
|
2
|
+
def human_event_name(klass, event)
|
|
3
|
+
defaults = ancestors_list(klass).map do |ancestor|
|
|
4
|
+
:"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
|
|
5
|
+
end << event.to_s.humanize
|
|
6
|
+
|
|
7
|
+
I18n.translate(defaults.shift, :default => defaults, :raise => true)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def human_state(obj)
|
|
11
|
+
klass = obj.class
|
|
12
|
+
defaults = ancestors_list(klass).map do |ancestor|
|
|
13
|
+
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}.#{obj.aasm_current_state}"
|
|
14
|
+
end << obj.aasm_current_state.to_s.humanize
|
|
15
|
+
|
|
16
|
+
I18n.translate(defaults.shift, :default => defaults, :raise => true)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# added for rails 2.x compatibility
|
|
22
|
+
def i18n_scope(klass)
|
|
23
|
+
klass.respond_to?(:i18n_scope) ? klass.i18n_scope : :activerecord
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# added for rails < 3.0.3 compatibility
|
|
27
|
+
def i18n_klass(klass)
|
|
28
|
+
klass.model_name.respond_to?(:i18n_key) ? klass.model_name.i18n_key : klass.name.underscore
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ancestors_list(klass)
|
|
32
|
+
klass.ancestors.select do |ancestor|
|
|
33
|
+
ancestor.respond_to?(:model_name) unless ancestor == ActiveRecord::Base
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/aasm/state_machine.rb
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
class AASM::StateMachine
|
|
2
|
-
def self.[](
|
|
3
|
-
(@machines ||= {})[
|
|
2
|
+
def self.[](clazz)
|
|
3
|
+
(@machines ||= {})[clazz.to_s]
|
|
4
4
|
end
|
|
5
|
-
|
|
6
|
-
def self.[]=(
|
|
7
|
-
|
|
8
|
-
(@machines ||= {})[args] = val
|
|
5
|
+
|
|
6
|
+
def self.[]=(clazz, machine)
|
|
7
|
+
(@machines ||= {})[clazz.to_s] = machine
|
|
9
8
|
end
|
|
10
|
-
|
|
9
|
+
|
|
11
10
|
attr_accessor :states, :events, :initial_state, :config
|
|
12
11
|
attr_reader :name
|
|
13
12
|
|
|
@@ -7,12 +7,12 @@ class AASM::SupportingClasses::StateTransition
|
|
|
7
7
|
@opts = opts
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def perform(obj)
|
|
10
|
+
def perform(obj, *args)
|
|
11
11
|
case @guard
|
|
12
12
|
when Symbol, String
|
|
13
|
-
obj.send(@guard)
|
|
13
|
+
obj.send(@guard, *args)
|
|
14
14
|
when Proc
|
|
15
|
-
@guard.call(obj)
|
|
15
|
+
@guard.call(obj, *args)
|
|
16
16
|
else
|
|
17
17
|
true
|
|
18
18
|
end
|
|
@@ -36,10 +36,10 @@ class AASM::SupportingClasses::StateTransition
|
|
|
36
36
|
|
|
37
37
|
def _execute(obj, on_transition, *args)
|
|
38
38
|
case on_transition
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
when Proc
|
|
40
|
+
on_transition.arity == 0 ? on_transition.call : on_transition.call(obj, *args)
|
|
41
|
+
when Symbol, String
|
|
42
|
+
obj.send(:method, on_transition.to_sym).arity == 0 ? obj.send(on_transition) : obj.send(on_transition, *args)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
data/lib/aasm/version.rb
ADDED
data/lib/aasm.rb
CHANGED
|
@@ -7,3 +7,4 @@ require File.join(File.dirname(__FILE__), 'aasm', 'supporting_classes')
|
|
|
7
7
|
require File.join(File.dirname(__FILE__), 'aasm', 'state_machine')
|
|
8
8
|
require File.join(File.dirname(__FILE__), 'aasm', 'persistence')
|
|
9
9
|
require File.join(File.dirname(__FILE__), 'aasm', 'aasm')
|
|
10
|
+
require File.join(File.dirname(__FILE__), 'aasm', 'localizer')
|
data/spec/database.yml
ADDED
data/spec/en.yml
ADDED
data/spec/schema.rb
ADDED
data/spec/spec_helper.rb
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
|
2
2
|
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
|
3
|
-
|
|
4
3
|
require 'aasm'
|
|
5
4
|
|
|
6
|
-
require '
|
|
7
|
-
require '
|
|
5
|
+
require 'rspec'
|
|
6
|
+
require 'rspec/autorun'
|
|
7
|
+
|
|
8
|
+
# require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
|
|
9
|
+
# require 'ruby-debug/completion'
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
def load_schema
|
|
12
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
|
13
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
|
14
|
+
ActiveRecord::Base.establish_connection(config['sqlite3'])
|
|
15
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
|
11
16
|
end
|