mylescarrick-aasm 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ *~
3
+ .DS_Store
4
+ .idea
5
+ coverage
6
+ pkg
7
+ rdoc
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Scott Barron
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,133 @@
1
+ = AASM - Ruby state machines
2
+
3
+ This package contains AASM, a library for adding finite state machines to Ruby classes.
4
+
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.
6
+
7
+ AASM has the following features:
8
+
9
+ * States
10
+ * Machines
11
+ * Events
12
+ * Transitions
13
+
14
+ == New Callbacks
15
+
16
+ The callback chain & order on a successful event looks like:
17
+
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*
31
+
32
+ (*) marks old callbacks
33
+
34
+
35
+ == Download
36
+
37
+ The latest AASM can currently be pulled from the git repository on github.
38
+
39
+ * http://github.com/rubyist/aasm/tree/master
40
+
41
+
42
+ == Installation
43
+
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)
51
+
52
+ % sudo gem sources -a http://gems.github.com # (you only need to do this once)
53
+ % sudo gem install rubyist-aasm
54
+
55
+ === Building your own gems
56
+
57
+ % rake gemspec
58
+ % rake build
59
+ % sudo gem install pkg/aasm-2.1.gem
60
+
61
+
62
+ == Simple Example
63
+
64
+ Here's a quick example highlighting some of the features.
65
+
66
+ class Conversation
67
+ include AASM
68
+
69
+ aasm_column :current_state # defaults to aasm_state
70
+
71
+ aasm_initial_state :unread
72
+
73
+ aasm_state :unread
74
+ aasm_state :read
75
+ aasm_state :closed
76
+
77
+
78
+ aasm_event :view do
79
+ transitions :to => :read, :from => [:unread]
80
+ end
81
+
82
+ aasm_event :close do
83
+ transitions :to => :closed, :from => [:read, :unread]
84
+ end
85
+ end
86
+
87
+ == A Slightly More Complex Example
88
+
89
+ This example uses a few of the more complex features available.
90
+
91
+ class Relationship
92
+ include AASM
93
+
94
+ aasm_column :status
95
+
96
+ aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }
97
+
98
+ aasm_state :dating, :enter => :make_happy, :exit => :make_depressed
99
+ aasm_state :intimate, :enter => :make_very_happy, :exit => :never_speak_again
100
+ aasm_state :married, :enter => :give_up_intimacy, :exit => :buy_exotic_car_and_wear_a_combover
101
+
102
+ aasm_event :get_intimate do
103
+ transitions :to => :intimate, :from => [:dating], :guard => :drunk?
104
+ end
105
+
106
+ aasm_event :get_married do
107
+ transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood?
108
+ end
109
+
110
+ def strictly_for_fun?; end
111
+ def drunk?; end
112
+ def willing_to_give_up_manhood?; end
113
+ def make_happy; end
114
+ def make_depressed; end
115
+ def make_very_happy; end
116
+ def never_speak_again; end
117
+ def give_up_intimacy; end
118
+ def buy_exotic_car_and_wear_a_combover; end
119
+ end
120
+
121
+ = Other Stuff
122
+
123
+ Author:: Scott Barron <scott at elitists dot net>
124
+ License:: Original code Copyright 2006, 2007, 2008 by Scott Barron.
125
+ Released under an MIT-style license. See the LICENSE file
126
+ included in the distribution.
127
+
128
+ == Warranty
129
+
130
+ This software is provided "as is" and without any express or
131
+ implied warranties, including, without limitation, the implied
132
+ warranties of merchantibility and fitness for a particular
133
+ purpose.
@@ -0,0 +1,108 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "mylescarrick-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"
21
+ end
22
+
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
30
+ end
31
+
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
+ 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'
104
+ end
105
+ rescue LoadError
106
+ puts "aasm makes use of the sdoc gem. Install it with: sudo gem install sdoc"
107
+ end
108
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.1.5
@@ -0,0 +1,9 @@
1
+ module AASM
2
+ end
3
+
4
+ require 'ostruct'
5
+
6
+ require File.join(File.dirname(__FILE__), 'aasm', 'supporting_classes')
7
+ require File.join(File.dirname(__FILE__), 'aasm', 'state_machine')
8
+ require File.join(File.dirname(__FILE__), 'aasm', 'persistence')
9
+ require File.join(File.dirname(__FILE__), 'aasm', 'aasm')
@@ -0,0 +1,195 @@
1
+ module AASM
2
+ class InvalidTransition < RuntimeError
3
+ end
4
+
5
+ class UndefinedState < RuntimeError
6
+ end
7
+
8
+ def self.included(base) #:nodoc:
9
+ base.extend AASM::ClassMethods
10
+ AASM::Persistence.set_persistence(base)
11
+ unless AASM::StateMachine[base]
12
+ AASM::StateMachine[base] = AASM::StateMachine.new('')
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def inherited(klass)
18
+ AASM::StateMachine[klass] = AASM::StateMachine[self].clone
19
+ super
20
+ end
21
+
22
+ def aasm_initial_state(set_state=nil)
23
+ if set_state
24
+ AASM::StateMachine[self].initial_state = set_state
25
+ else
26
+ AASM::StateMachine[self].initial_state
27
+ end
28
+ end
29
+
30
+ def aasm_initial_state=(state)
31
+ AASM::StateMachine[self].initial_state = state
32
+ end
33
+
34
+ def aasm_state(name, options={})
35
+ sm = AASM::StateMachine[self]
36
+ sm.create_state(name, options)
37
+ sm.initial_state = name unless sm.initial_state
38
+
39
+ define_method("#{name.to_s}?") do
40
+ aasm_current_state == name
41
+ end
42
+ end
43
+
44
+ def aasm_event(name, options = {}, &block)
45
+ sm = AASM::StateMachine[self]
46
+
47
+ unless sm.events.has_key?(name)
48
+ sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
49
+ end
50
+
51
+ define_method("#{name.to_s}!") do |*args|
52
+ aasm_fire_event(name, true, *args)
53
+ end
54
+
55
+ define_method("#{name.to_s}") do |*args|
56
+ aasm_fire_event(name, false, *args)
57
+ end
58
+ end
59
+
60
+ def aasm_states
61
+ AASM::StateMachine[self].states
62
+ end
63
+
64
+ def aasm_events
65
+ AASM::StateMachine[self].events
66
+ end
67
+
68
+ def aasm_states_for_select
69
+ AASM::StateMachine[self].states.map { |state| state.for_select }
70
+ end
71
+
72
+ end
73
+
74
+ # Instance methods
75
+ def aasm_current_state
76
+ return @aasm_current_state if @aasm_current_state
77
+
78
+ if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state')
79
+ @aasm_current_state = aasm_read_state
80
+ end
81
+ return @aasm_current_state if @aasm_current_state
82
+
83
+ aasm_enter_initial_state
84
+ end
85
+
86
+ def aasm_enter_initial_state
87
+ state_name = aasm_determine_state_name(self.class.aasm_initial_state)
88
+ state = aasm_state_object_for_state(state_name)
89
+
90
+ state.call_action(:before_enter, self)
91
+ state.call_action(:enter, self)
92
+ self.aasm_current_state = state_name
93
+ state.call_action(:after_enter, self)
94
+
95
+ state_name
96
+ end
97
+
98
+ def aasm_events_for_current_state
99
+ aasm_events_for_state(aasm_current_state)
100
+ end
101
+
102
+ def aasm_events_for_state(state)
103
+ events = self.class.aasm_events.values.select {|event| event.transitions_from_state?(state) }
104
+ events.map {|event| event.name}
105
+ end
106
+
107
+ private
108
+
109
+ def set_aasm_current_state_with_persistence(state)
110
+ save_success = true
111
+ if self.respond_to?(:aasm_write_state) || self.private_methods.include?('aasm_write_state')
112
+ save_success = aasm_write_state(state)
113
+ end
114
+ self.aasm_current_state = state if save_success
115
+
116
+ save_success
117
+ end
118
+
119
+ def aasm_current_state=(state)
120
+ if self.respond_to?(:aasm_write_state_without_persistence) || self.private_methods.include?('aasm_write_state_without_persistence')
121
+ aasm_write_state_without_persistence(state)
122
+ end
123
+ @aasm_current_state = state
124
+ end
125
+
126
+ def aasm_determine_state_name(state)
127
+ case state
128
+ when Symbol, String
129
+ state
130
+ when Proc
131
+ state.call(self)
132
+ else
133
+ raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc."
134
+ end
135
+ end
136
+
137
+ def aasm_state_object_for_state(name)
138
+ obj = self.class.aasm_states.find {|s| s == name}
139
+ raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil?
140
+ obj
141
+ end
142
+
143
+ def aasm_fire_event(name, persist, *args)
144
+ event = self.class.aasm_events[name]
145
+ begin
146
+ old_state = aasm_state_object_for_state(aasm_current_state)
147
+
148
+
149
+ old_state.call_action(:exit, self)
150
+
151
+ # new event before callback
152
+ event.call_action(:before, self)
153
+
154
+ new_state_name = event.fire(self, *args)
155
+
156
+ unless new_state_name.nil?
157
+ new_state = aasm_state_object_for_state(new_state_name)
158
+
159
+ # new before_ callbacks
160
+ old_state.call_action(:before_exit, self)
161
+ new_state.call_action(:before_enter, self)
162
+
163
+ new_state.call_action(:enter, self)
164
+
165
+ persist_successful = true
166
+ if persist
167
+ persist_successful = set_aasm_current_state_with_persistence(new_state_name)
168
+ event.execute_success_callback(self) if persist_successful
169
+ else
170
+ self.aasm_current_state = new_state_name
171
+ end
172
+
173
+ if persist_successful
174
+ old_state.call_action(:after_exit, self)
175
+ new_state.call_action(:after_enter, self)
176
+ event.call_action(:after, self)
177
+
178
+ self.aasm_event_fired(name, old_state.name, self.aasm_current_state) if self.respond_to?(:aasm_event_fired)
179
+ else
180
+ self.aasm_event_failed(name, old_state.name) if self.respond_to?(:aasm_event_failed)
181
+ end
182
+
183
+ persist_successful
184
+ else
185
+ if self.respond_to?(:aasm_event_failed)
186
+ self.aasm_event_failed(name, old_state.name)
187
+ end
188
+
189
+ false
190
+ end
191
+ rescue StandardError => e
192
+ event.execute_error_callback(self, e)
193
+ end
194
+ end
195
+ end