r38y-aasm 2.1.5

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.
@@ -0,0 +1,247 @@
1
+ module AASM
2
+ module Persistence
3
+ module MongoidPersistence
4
+ # This method:
5
+ #
6
+ # * extends the model with ClassMethods
7
+ # * includes InstanceMethods
8
+ #
9
+ # Unless the corresponding methods are already defined, it includes
10
+ # * ReadState
11
+ # * WriteState
12
+ # * WriteStateWithoutPersistence
13
+ #
14
+ # Adds
15
+ #
16
+ # before_validation :aasm_ensure_initial_state
17
+ #
18
+ # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
19
+ #
20
+ # class Foo
21
+ # include Mongoid::Document
22
+ # def aasm_write_state(state)
23
+ # "bar"
24
+ # end
25
+ # include AASM
26
+ # end
27
+ #
28
+ # class Foo
29
+ # include Mongoid::Document
30
+ # include AASM
31
+ # def aasm_write_state(state)
32
+ # "bar"
33
+ # end
34
+ # end
35
+ #
36
+ def self.included(base)
37
+ base.extend AASM::Persistence::MongoidPersistence::ClassMethods
38
+ base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
39
+ base.send(:include, AASM::Persistence::MongoidPersistence::ReadState) unless base.method_defined?(:aasm_read_state)
40
+ base.send(:include, AASM::Persistence::MongoidPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
41
+ base.send(:include, AASM::Persistence::MongoidPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
42
+
43
+ # if base.respond_to?(:named_scope)
44
+ # base.extend(AASM::Persistence::MongoidPersistence::NamedScopeMethods)
45
+ #
46
+ # base.class_eval do
47
+ # class << self
48
+ # unless method_defined?(:aasm_state_without_named_scope)
49
+ # alias_method :aasm_state_without_named_scope, :aasm_state
50
+ # alias_method :aasm_state, :aasm_state_with_named_scope
51
+ # end
52
+ # end
53
+ # end
54
+ # end
55
+
56
+ # Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet.
57
+ # base.before_validation_on_create :aasm_ensure_initial_state
58
+ base.before_validation :aasm_ensure_initial_state
59
+ end
60
+
61
+ module ClassMethods
62
+ # Maps to the aasm_column in the database. Deafults to "aasm_state". You can write:
63
+ #
64
+ # class Foo
65
+ # include Mongoid::Document
66
+ # include AASM
67
+ # field :aasm_state
68
+ # end
69
+ #
70
+ # OR:
71
+ #
72
+ # class Foo
73
+ # include Mongoid::Document
74
+ # include AASM
75
+ # field :status
76
+ # aasm_column :status
77
+ # end
78
+ #
79
+ # This method is both a getter and a setter
80
+ def aasm_column(column_name=nil)
81
+ if column_name
82
+ AASM::StateMachine[self].config.column = column_name.to_sym
83
+ # @aasm_column = column_name.to_sym
84
+ else
85
+ AASM::StateMachine[self].config.column ||= :aasm_state
86
+ # @aasm_column ||= :aasm_state
87
+ end
88
+ # @aasm_column
89
+ AASM::StateMachine[self].config.column
90
+ end
91
+
92
+ # def find_in_state(number, state, *args)
93
+ # with_state_scope state do
94
+ # find(number, *args)
95
+ # end
96
+ # end
97
+ #
98
+ # def count_in_state(state, *args)
99
+ # with_state_scope state do
100
+ # count(*args)
101
+ # end
102
+ # end
103
+ #
104
+ # def calculate_in_state(state, *args)
105
+ # with_state_scope state do
106
+ # calculate(*args)
107
+ # end
108
+ # end
109
+
110
+ protected
111
+ def with_state_scope(state)
112
+ with_scope :find => {:conditions => ["#{table_name}.#{aasm_column} = ?", state.to_s]} do
113
+ yield if block_given?
114
+ end
115
+ end
116
+ end
117
+
118
+ module InstanceMethods
119
+
120
+ # Returns the current aasm_state of the object. Respects reload and
121
+ # any changes made to the aasm_state field directly
122
+ #
123
+ # Internally just calls <tt>aasm_read_state</tt>
124
+ #
125
+ # foo = Foo.find(1)
126
+ # foo.aasm_current_state # => :pending
127
+ # foo.aasm_state = "opened"
128
+ # foo.aasm_current_state # => :opened
129
+ # foo.close # => calls aasm_write_state_without_persistence
130
+ # foo.aasm_current_state # => :closed
131
+ # foo.reload
132
+ # foo.aasm_current_state # => :pending
133
+ #
134
+ def aasm_current_state
135
+ @current_state = aasm_read_state
136
+ end
137
+
138
+ private
139
+
140
+ # Ensures that if the aasm_state column is nil and the record is new
141
+ # that the initial state gets populated before validation on create
142
+ #
143
+ # foo = Foo.new
144
+ # foo.aasm_state # => nil
145
+ # foo.valid?
146
+ # foo.aasm_state # => "open" (where :open is the initial state)
147
+ #
148
+ #
149
+ # foo = Foo.find(:first)
150
+ # foo.aasm_state # => 1
151
+ # foo.aasm_state = nil
152
+ # foo.valid?
153
+ # foo.aasm_state # => nil
154
+ #
155
+ def aasm_ensure_initial_state
156
+ send("#{self.class.aasm_column}=", self.aasm_enter_initial_state.to_s) if send(self.class.aasm_column).blank?
157
+ end
158
+
159
+ end
160
+
161
+ module WriteStateWithoutPersistence
162
+ # Writes <tt>state</tt> to the state column, but does not persist it to the database
163
+ #
164
+ # foo = Foo.find(1)
165
+ # foo.aasm_current_state # => :opened
166
+ # foo.close
167
+ # foo.aasm_current_state # => :closed
168
+ # Foo.find(1).aasm_current_state # => :opened
169
+ # foo.save
170
+ # foo.aasm_current_state # => :closed
171
+ # Foo.find(1).aasm_current_state # => :closed
172
+ #
173
+ # NOTE: intended to be called from an event
174
+ def aasm_write_state_without_persistence(state)
175
+ write_attribute(self.class.aasm_column, state.to_s)
176
+ end
177
+ end
178
+
179
+ module WriteState
180
+ # Writes <tt>state</tt> to the state column and persists it to the database
181
+ # using update_attribute (which bypasses validation)
182
+ #
183
+ # foo = Foo.find(1)
184
+ # foo.aasm_current_state # => :opened
185
+ # foo.close!
186
+ # foo.aasm_current_state # => :closed
187
+ # Foo.find(1).aasm_current_state # => :closed
188
+ #
189
+ # NOTE: intended to be called from an event
190
+ def aasm_write_state(state)
191
+ old_value = read_attribute(self.class.aasm_column)
192
+ write_attribute(self.class.aasm_column, state.to_s)
193
+
194
+ unless self.save(false)
195
+ write_attribute(self.class.aasm_column, old_value)
196
+ return false
197
+ end
198
+
199
+ true
200
+ end
201
+ end
202
+
203
+ module ReadState
204
+
205
+ # Returns the value of the aasm_column - called from <tt>aasm_current_state</tt>
206
+ #
207
+ # If it's a new record, and the aasm state column is blank it returns the initial state:
208
+ #
209
+ # class Foo
210
+ # include Mongoid::Document
211
+ # include AASM
212
+ # aasm_column :status
213
+ # aasm_state :opened
214
+ # aasm_state :closed
215
+ # end
216
+ #
217
+ # foo = Foo.new
218
+ # foo.current_state # => :opened
219
+ # foo.close
220
+ # foo.current_state # => :closed
221
+ #
222
+ # foo = Foo.find(1)
223
+ # foo.current_state # => :opened
224
+ # foo.aasm_state = nil
225
+ # foo.current_state # => nil
226
+ #
227
+ # NOTE: intended to be called from an event
228
+ #
229
+ # This allows for nil aasm states - be sure to add validation to your model
230
+ def aasm_read_state
231
+ if new_record?
232
+ send(self.class.aasm_column).blank? ? aasm_determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym
233
+ else
234
+ send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
235
+ end
236
+ end
237
+ end
238
+
239
+ module NamedScopeMethods
240
+ def aasm_state_with_named_scope name, options = {}
241
+ aasm_state_without_named_scope name, options
242
+ self.named_scope name, :conditions => { "#{table_name}.#{self.aasm_column}" => name.to_s} unless self.respond_to?(name)
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,53 @@
1
+ class AASM::SupportingClasses::State
2
+ attr_reader :name, :options
3
+
4
+ def initialize(name, options={})
5
+ @name = name
6
+ update(options)
7
+ end
8
+
9
+ def ==(state)
10
+ if state.is_a? Symbol
11
+ name == state
12
+ else
13
+ name == state.name
14
+ end
15
+ end
16
+
17
+ def call_action(action, record)
18
+ action = @options[action]
19
+ catch :halt_aasm_chain do
20
+ action.is_a?(Array) ?
21
+ action.each {|a| _call_action(a, record)} :
22
+ _call_action(action, record)
23
+ end
24
+ end
25
+
26
+ def display_name
27
+ @display_name ||= name.to_s.gsub(/_/, ' ').capitalize
28
+ end
29
+
30
+ def for_select
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
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
+
53
+ end
@@ -0,0 +1,32 @@
1
+ class AASM::StateMachine
2
+ def self.[](*args)
3
+ (@machines ||= {})[args]
4
+ end
5
+
6
+ def self.[]=(*args)
7
+ val = args.pop
8
+ (@machines ||= {})[args] = val
9
+ end
10
+
11
+ attr_accessor :states, :events, :initial_state, :config
12
+ attr_reader :name
13
+
14
+ def initialize(name)
15
+ @name = name
16
+ @initial_state = nil
17
+ @states = []
18
+ @events = {}
19
+ @config = OpenStruct.new
20
+ end
21
+
22
+ def clone
23
+ klone = super
24
+ klone.states = states.clone
25
+ klone.events = events.clone
26
+ klone
27
+ end
28
+
29
+ def create_state(name, options)
30
+ @states << AASM::SupportingClasses::State.new(name, options) unless @states.include?(name)
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ class AASM::SupportingClasses::StateTransition
2
+ attr_reader :from, :to, :opts
3
+ alias_method :options, :opts
4
+
5
+ def initialize(opts)
6
+ @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
7
+ @opts = opts
8
+ end
9
+
10
+ def perform(obj)
11
+ case @guard
12
+ when Symbol, String
13
+ obj.send(@guard)
14
+ when Proc
15
+ @guard.call(obj)
16
+ else
17
+ true
18
+ end
19
+ end
20
+
21
+ def execute(obj, *args)
22
+ @on_transition.is_a?(Array) ?
23
+ @on_transition.each {|ot| _execute(obj, ot, *args)} :
24
+ _execute(obj, @on_transition, *args)
25
+ end
26
+
27
+ def ==(obj)
28
+ @from == obj.from && @to == obj.to
29
+ end
30
+
31
+ def from?(value)
32
+ @from == value
33
+ end
34
+
35
+ private
36
+
37
+ def _execute(obj, on_transition, *args)
38
+ case on_transition
39
+ when Symbol, String
40
+ obj.send(on_transition, *args)
41
+ when Proc
42
+ on_transition.call(obj, *args)
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,6 @@
1
+ module AASM::SupportingClasses
2
+ end
3
+
4
+ require File.join(File.dirname(__FILE__), 'state_transition')
5
+ require File.join(File.dirname(__FILE__), 'event')
6
+ require File.join(File.dirname(__FILE__), 'state')
@@ -0,0 +1,97 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{r38y-aasm}
8
+ s.version = "2.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Scott Barron", "Scott Petersen", "Travis Tilley"]
12
+ s.date = %q{2010-02-04}
13
+ 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/persistence/mongo_mapper_persistence.rb",
33
+ "lib/aasm/persistence/mongoid_persistence.rb",
34
+ "lib/aasm/state.rb",
35
+ "lib/aasm/state_machine.rb",
36
+ "lib/aasm/state_transition.rb",
37
+ "lib/aasm/supporting_classes.rb",
38
+ "r38y-aasm.gemspec",
39
+ "spec/functional/conversation.rb",
40
+ "spec/functional/conversation_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "spec/unit/aasm_spec.rb",
43
+ "spec/unit/active_record_persistence_spec.rb",
44
+ "spec/unit/before_after_callbacks_spec.rb",
45
+ "spec/unit/event_spec.rb",
46
+ "spec/unit/state_spec.rb",
47
+ "spec/unit/state_transition_spec.rb",
48
+ "test/functional/auth_machine_test.rb",
49
+ "test/test_helper.rb",
50
+ "test/unit/aasm_test.rb",
51
+ "test/unit/event_test.rb",
52
+ "test/unit/state_test.rb",
53
+ "test/unit/state_transition_test.rb"
54
+ ]
55
+ s.homepage = %q{http://rubyist.github.com/aasm/}
56
+ s.rdoc_options = ["--charset=UTF-8"]
57
+ s.require_paths = ["lib"]
58
+ s.rubygems_version = %q{1.3.5}
59
+ s.summary = %q{State machine mixin for Ruby objects}
60
+ s.test_files = [
61
+ "spec/functional/conversation.rb",
62
+ "spec/functional/conversation_spec.rb",
63
+ "spec/spec_helper.rb",
64
+ "spec/unit/aasm_spec.rb",
65
+ "spec/unit/active_record_persistence_spec.rb",
66
+ "spec/unit/before_after_callbacks_spec.rb",
67
+ "spec/unit/event_spec.rb",
68
+ "spec/unit/state_spec.rb",
69
+ "spec/unit/state_transition_spec.rb",
70
+ "test/functional/auth_machine_test.rb",
71
+ "test/test_helper.rb",
72
+ "test/unit/aasm_test.rb",
73
+ "test/unit/event_test.rb",
74
+ "test/unit/state_test.rb",
75
+ "test/unit/state_transition_test.rb"
76
+ ]
77
+
78
+ if s.respond_to? :specification_version then
79
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
80
+ s.specification_version = 3
81
+
82
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
83
+ s.add_development_dependency(%q<rspec>, [">= 0"])
84
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
85
+ s.add_development_dependency(%q<sdoc>, [">= 0"])
86
+ else
87
+ s.add_dependency(%q<rspec>, [">= 0"])
88
+ s.add_dependency(%q<shoulda>, [">= 0"])
89
+ s.add_dependency(%q<sdoc>, [">= 0"])
90
+ end
91
+ else
92
+ s.add_dependency(%q<rspec>, [">= 0"])
93
+ s.add_dependency(%q<shoulda>, [">= 0"])
94
+ s.add_dependency(%q<sdoc>, [">= 0"])
95
+ end
96
+ end
97
+