aasm 2.1.1 → 2.1.3
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/.document +5 -0
- data/.gitignore +8 -0
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/README.rdoc +10 -4
- data/Rakefile +86 -73
- data/VERSION +1 -0
- data/lib/aasm/aasm.rb +25 -15
- data/lib/aasm/event.rb +45 -23
- data/lib/aasm/persistence/active_record_persistence.rb +1 -1
- data/lib/aasm/state.rb +30 -10
- data/lib/aasm/state_machine.rb +2 -1
- data/lib/aasm/state_transition.rb +26 -12
- data/spec/functional/conversation.rb +49 -0
- data/spec/functional/conversation_spec.rb +8 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/aasm_spec.rb +432 -0
- data/spec/unit/active_record_persistence_spec.rb +254 -0
- data/spec/unit/before_after_callbacks_spec.rb +79 -0
- data/spec/unit/event_spec.rb +126 -0
- data/spec/unit/state_spec.rb +74 -0
- data/spec/unit/state_transition_spec.rb +84 -0
- data/test/functional/auth_machine_test.rb +120 -0
- data/test/test_helper.rb +33 -0
- data/test/unit/aasm_test.rb +0 -0
- data/test/unit/event_test.rb +54 -0
- data/test/unit/state_test.rb +69 -0
- data/test/unit/state_transition_test.rb +75 -0
- metadata +77 -24
- data/CHANGELOG +0 -33
- data/TODO +0 -9
- data/doc/jamis.rb +0 -591
data/.document
ADDED
data/.gitignore
ADDED
data/{MIT-LICENSE → LICENSE}
RENAMED
File without changes
|
data/README.rdoc
CHANGED
@@ -25,7 +25,7 @@ The callback chain & order on a successful event looks like:
|
|
25
25
|
__update state__
|
26
26
|
event:success*
|
27
27
|
oldstate:after_exit
|
28
|
-
|
28
|
+
newstate:after_enter
|
29
29
|
event:after
|
30
30
|
obj:aasm_event_fired*
|
31
31
|
|
@@ -36,15 +36,21 @@ The callback chain & order on a successful event looks like:
|
|
36
36
|
|
37
37
|
The latest AASM can currently be pulled from the git repository on github.
|
38
38
|
|
39
|
-
* http://github.com/
|
39
|
+
* http://github.com/rubyist/aasm/tree/master
|
40
40
|
|
41
41
|
|
42
42
|
== Installation
|
43
43
|
|
44
|
-
=== From
|
44
|
+
=== From gemcutter
|
45
|
+
|
46
|
+
% sudo gem install gemcutter
|
47
|
+
% sudo gem tumble
|
48
|
+
% sudo gem install aasm
|
49
|
+
|
50
|
+
=== From GitHub hosted gems (only older releases are available)
|
45
51
|
|
46
52
|
% sudo gem sources -a http://gems.github.com # (you only need to do this once)
|
47
|
-
% sudo gem install
|
53
|
+
% sudo gem install rubyist-aasm
|
48
54
|
|
49
55
|
=== Building your own gems
|
50
56
|
|
data/Rakefile
CHANGED
@@ -1,95 +1,108 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# This file may be distributed under an MIT style license.
|
5
|
-
# See MIT-LICENSE for details.
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
6
3
|
|
7
4
|
begin
|
8
|
-
require '
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "aasm"
|
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"
|
15
21
|
end
|
16
22
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/*_test.rb'
|
29
|
+
test.verbose = true
|
21
30
|
end
|
22
|
-
$package_version = CURRENT_VERSION
|
23
31
|
|
24
|
-
|
25
|
-
'
|
26
|
-
|
27
|
-
|
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
|
28
44
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
rdoc.rdoc_dir = 'rdoc'
|
34
|
-
rdoc.title = 'AASM'
|
35
|
-
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc' << '--title' << 'AASM'
|
36
|
-
rdoc.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'TODO', 'CHANGELOG')
|
37
|
-
rdoc.rdoc_files.include('lib/*.rb', 'lib/**/*.rb', 'doc/**/*.rdoc')
|
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']
|
38
49
|
end
|
39
50
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
spec =
|
44
|
-
|
45
|
-
s.version = $package_version
|
46
|
-
s.summary = 'State machine mixin for Ruby objects'
|
47
|
-
s.description = <<EOF
|
48
|
-
AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.
|
49
|
-
EOF
|
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
|
50
56
|
|
51
|
-
|
52
|
-
|
53
|
-
s.has_rdoc = true
|
54
|
-
s.extra_rdoc_files = rd.rdoc_files.reject {|fn| fn =~ /\.rb$/}.to_a
|
55
|
-
s.rdoc_options = rd.options
|
57
|
+
task :test => :check_dependencies
|
58
|
+
task :spec => :check_dependencies
|
56
59
|
|
57
|
-
|
58
|
-
|
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'
|
60
66
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
pkg.need_tar = true
|
67
|
+
rescue LoadError
|
68
|
+
task :reek do
|
69
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
t.spec_files = FileList['spec/**/*.rb']
|
74
|
-
t.rcov = true
|
75
|
-
t.rcov_opts = ['--exclude', 'spec', '--exclude', 'Library', '--exclude', 'rcov.rb']
|
73
|
+
begin
|
74
|
+
require 'roodi'
|
75
|
+
require 'roodi_task'
|
76
|
+
RoodiTask.new do |t|
|
77
|
+
t.verbose = false
|
76
78
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
t.spec_files = FileList['spec/**/*.rb']
|
81
|
-
t.rcov = false
|
82
|
-
t.spec_opts = ['-cfs']
|
79
|
+
rescue LoadError
|
80
|
+
task :roodi do
|
81
|
+
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
83
82
|
end
|
84
83
|
end
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
task :default => :test
|
86
|
+
|
87
|
+
begin
|
88
|
+
require 'rake/rdoctask'
|
89
|
+
require 'sdoc'
|
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')
|
101
|
+
|
102
|
+
rdoc.options << '--fmt' << 'shtml'
|
103
|
+
rdoc.template = 'direct'
|
92
104
|
end
|
105
|
+
rescue LoadError
|
106
|
+
puts "aasm makes use of the sdoc gem. Install it with: sudo gem install sdoc"
|
93
107
|
end
|
94
108
|
|
95
|
-
task :default => [:spec]
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.3
|
data/lib/aasm/aasm.rb
CHANGED
@@ -4,10 +4,6 @@ require File.join(File.dirname(__FILE__), 'state_machine')
|
|
4
4
|
require File.join(File.dirname(__FILE__), 'persistence')
|
5
5
|
|
6
6
|
module AASM
|
7
|
-
def self.Version
|
8
|
-
'2.1.1'
|
9
|
-
end
|
10
|
-
|
11
7
|
class InvalidTransition < RuntimeError
|
12
8
|
end
|
13
9
|
|
@@ -88,7 +84,20 @@ module AASM
|
|
88
84
|
@aasm_current_state = aasm_read_state
|
89
85
|
end
|
90
86
|
return @aasm_current_state if @aasm_current_state
|
91
|
-
|
87
|
+
|
88
|
+
aasm_enter_initial_state
|
89
|
+
end
|
90
|
+
|
91
|
+
def aasm_enter_initial_state
|
92
|
+
state_name = aasm_determine_state_name(self.class.aasm_initial_state)
|
93
|
+
state = aasm_state_object_for_state(state_name)
|
94
|
+
|
95
|
+
state.call_action(:before_enter, self)
|
96
|
+
state.call_action(:enter, self)
|
97
|
+
self.aasm_current_state = state_name
|
98
|
+
state.call_action(:after_enter, self)
|
99
|
+
|
100
|
+
state_name
|
92
101
|
end
|
93
102
|
|
94
103
|
def aasm_events_for_current_state
|
@@ -101,6 +110,7 @@ module AASM
|
|
101
110
|
end
|
102
111
|
|
103
112
|
private
|
113
|
+
|
104
114
|
def set_aasm_current_state_with_persistence(state)
|
105
115
|
save_success = true
|
106
116
|
if self.respond_to?(:aasm_write_state) || self.private_methods.include?('aasm_write_state')
|
@@ -120,12 +130,12 @@ module AASM
|
|
120
130
|
|
121
131
|
def aasm_determine_state_name(state)
|
122
132
|
case state
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
133
|
+
when Symbol, String
|
134
|
+
state
|
135
|
+
when Proc
|
136
|
+
state.call(self)
|
137
|
+
else
|
138
|
+
raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc."
|
129
139
|
end
|
130
140
|
end
|
131
141
|
|
@@ -148,13 +158,13 @@ module AASM
|
|
148
158
|
|
149
159
|
unless new_state_name.nil?
|
150
160
|
new_state = aasm_state_object_for_state(new_state_name)
|
151
|
-
|
161
|
+
|
152
162
|
# new before_ callbacks
|
153
163
|
old_state.call_action(:before_exit, self)
|
154
164
|
new_state.call_action(:before_enter, self)
|
155
|
-
|
165
|
+
|
156
166
|
new_state.call_action(:enter, self)
|
157
|
-
|
167
|
+
|
158
168
|
persist_successful = true
|
159
169
|
if persist
|
160
170
|
persist_successful = set_aasm_current_state_with_persistence(new_state_name)
|
@@ -163,7 +173,7 @@ module AASM
|
|
163
173
|
self.aasm_current_state = new_state_name
|
164
174
|
end
|
165
175
|
|
166
|
-
if persist_successful
|
176
|
+
if persist_successful
|
167
177
|
old_state.call_action(:after_exit, self)
|
168
178
|
new_state.call_action(:after_enter, self)
|
169
179
|
event.call_action(:after, self)
|
data/lib/aasm/event.rb
CHANGED
@@ -4,13 +4,11 @@ module AASM
|
|
4
4
|
module SupportingClasses
|
5
5
|
class Event
|
6
6
|
attr_reader :name, :success, :options
|
7
|
-
|
7
|
+
|
8
8
|
def initialize(name, options = {}, &block)
|
9
9
|
@name = name
|
10
|
-
@success = options[:success]
|
11
10
|
@transitions = []
|
12
|
-
|
13
|
-
instance_eval(&block) if block
|
11
|
+
update(options, &block)
|
14
12
|
end
|
15
13
|
|
16
14
|
def fire(obj, to_state=nil, *args)
|
@@ -37,35 +35,59 @@ module AASM
|
|
37
35
|
@transitions.select { |t| t.from == state }
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
41
|
-
|
42
|
-
case(callback)
|
43
|
-
when String, Symbol
|
44
|
-
obj.send(callback)
|
45
|
-
when Proc
|
46
|
-
callback.call(obj)
|
47
|
-
when Array
|
48
|
-
callback.each{|meth|self.execute_success_callback(obj, meth)}
|
49
|
-
end
|
38
|
+
def all_transitions
|
39
|
+
@transitions
|
50
40
|
end
|
51
41
|
|
52
42
|
def call_action(action, record)
|
53
43
|
action = @options[action]
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
44
|
+
action.is_a?(Array) ?
|
45
|
+
action.each {|a| _call_action(a, record)} :
|
46
|
+
_call_action(action, record)
|
47
|
+
end
|
48
|
+
|
49
|
+
def ==(event)
|
50
|
+
if event.is_a? Symbol
|
51
|
+
name == event
|
52
|
+
else
|
53
|
+
name == event.name
|
61
54
|
end
|
62
55
|
end
|
63
56
|
|
64
|
-
def
|
65
|
-
|
57
|
+
def update(options = {}, &block)
|
58
|
+
if options.key?(:success) then
|
59
|
+
@success = options[:success]
|
60
|
+
end
|
61
|
+
if block then
|
62
|
+
instance_eval(&block)
|
63
|
+
end
|
64
|
+
@options = options
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def execute_success_callback(obj, success = nil)
|
69
|
+
callback = success || @success
|
70
|
+
case(callback)
|
71
|
+
when String, Symbol
|
72
|
+
obj.send(callback)
|
73
|
+
when Proc
|
74
|
+
callback.call(obj)
|
75
|
+
when Array
|
76
|
+
callback.each{|meth|self.execute_success_callback(obj, meth)}
|
77
|
+
end
|
66
78
|
end
|
67
79
|
|
68
80
|
private
|
81
|
+
|
82
|
+
def _call_action(action, record)
|
83
|
+
case action
|
84
|
+
when Symbol, String
|
85
|
+
record.send(action)
|
86
|
+
when Proc
|
87
|
+
action.call(record)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
69
91
|
def transitions(trans_opts)
|
70
92
|
Array(trans_opts[:from]).each do |s|
|
71
93
|
@transitions << SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
@@ -155,7 +155,7 @@ module AASM
|
|
155
155
|
# foo.aasm_state # => nil
|
156
156
|
#
|
157
157
|
def aasm_ensure_initial_state
|
158
|
-
send("#{self.class.aasm_column}=", self.
|
158
|
+
send("#{self.class.aasm_column}=", self.aasm_enter_initial_state.to_s) if send(self.class.aasm_column).blank?
|
159
159
|
end
|
160
160
|
|
161
161
|
end
|
data/lib/aasm/state.rb
CHANGED
@@ -4,7 +4,8 @@ module AASM
|
|
4
4
|
attr_reader :name, :options
|
5
5
|
|
6
6
|
def initialize(name, options={})
|
7
|
-
@name
|
7
|
+
@name = name
|
8
|
+
update(options)
|
8
9
|
end
|
9
10
|
|
10
11
|
def ==(state)
|
@@ -17,19 +18,38 @@ module AASM
|
|
17
18
|
|
18
19
|
def call_action(action, record)
|
19
20
|
action = @options[action]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
21
|
+
action.is_a?(Array) ?
|
22
|
+
action.each {|a| _call_action(a, record)} :
|
23
|
+
_call_action(action, record)
|
24
|
+
end
|
25
|
+
|
26
|
+
def display_name
|
27
|
+
@display_name ||= name.to_s.gsub(/_/, ' ').capitalize
|
28
28
|
end
|
29
29
|
|
30
30
|
def for_select
|
31
|
-
[
|
31
|
+
[display_name, name.to_s]
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(options = {})
|
35
|
+
if options.key?(:display) then
|
36
|
+
@display_name = options.delete(:display)
|
37
|
+
end
|
38
|
+
@options = options
|
39
|
+
self
|
32
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def _call_action(action, record)
|
45
|
+
case action
|
46
|
+
when Symbol, String
|
47
|
+
record.send(action)
|
48
|
+
when Proc
|
49
|
+
action.call(record)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
33
53
|
end
|
34
54
|
end
|
35
55
|
end
|