aasm 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.0.1
4
+
5
+ * added support for Mongoid (Thanks, Michał Taberski)
6
+
3
7
  ## 3.0.0
4
8
 
5
9
  * switched documentation to the new DSL
data/README.md CHANGED
@@ -128,6 +128,7 @@ This example uses a few of the more complex features available.
128
128
  :after => :eat_wedding_cake do
129
129
  transitions :to => :married, :from => [:dating]
130
130
  end
131
+ end
131
132
  end
132
133
  ```
133
134
 
@@ -1,5 +1,6 @@
1
1
  require 'ostruct'
2
2
 
3
+ # TODO shorten this [thorsten, 2011-12-20]
3
4
  require File.join(File.dirname(__FILE__), 'aasm', 'version')
4
5
  require File.join(File.dirname(__FILE__), 'aasm', 'errors')
5
6
  require File.join(File.dirname(__FILE__), 'aasm', 'base')
@@ -9,6 +9,9 @@ module AASM
9
9
  if hierarchy.include?("ActiveRecord::Base")
10
10
  require File.join(File.dirname(__FILE__), 'persistence', 'active_record_persistence')
11
11
  base.send(:include, AASM::Persistence::ActiveRecordPersistence)
12
+ elsif hierarchy.include?("Mongoid::Document")
13
+ require File.join(File.dirname(__FILE__), 'persistence', 'mongoid_persistence')
14
+ base.send(:include, AASM::Persistence::MongoidPersistence)
12
15
  end
13
16
  end
14
17
  end
@@ -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(:validate => 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
@@ -9,6 +9,7 @@ module AASM
9
9
  @opts = opts
10
10
  end
11
11
 
12
+ # TODO: should be named allowed? or similar
12
13
  def perform(obj, *args)
13
14
  case @guard
14
15
  when Symbol, String
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "3.0.0"
2
+ VERSION = "3.0.1"
3
3
  end
@@ -143,58 +143,56 @@ end
143
143
 
144
144
  describe Gate, "instance methods" do
145
145
 
146
+ before do
147
+ @gate = Gate.new
148
+ end
149
+
146
150
  it "should respond to aasm read state when not previously defined" do
147
- Gate.new.should respond_to(:aasm_read_state)
151
+ @gate.should respond_to(:aasm_read_state)
148
152
  end
149
153
 
150
154
  it "should respond to aasm write state when not previously defined" do
151
- Gate.new.should respond_to(:aasm_write_state)
155
+ @gate.should respond_to(:aasm_write_state)
152
156
  end
153
157
 
154
158
  it "should respond to aasm write state without persistence when not previously defined" do
155
- Gate.new.should respond_to(:aasm_write_state_without_persistence)
159
+ @gate.should respond_to(:aasm_write_state_without_persistence)
156
160
  end
157
161
 
158
162
  it "should return the initial state when new and the aasm field is nil" do
159
- Gate.new.aasm_current_state.should == :opened
163
+ @gate.aasm_current_state.should == :opened
160
164
  end
161
165
 
162
166
  it "should return the aasm column when new and the aasm field is not nil" do
163
- foo = Gate.new
164
- foo.aasm_state = "closed"
165
- foo.aasm_current_state.should == :closed
167
+ @gate.aasm_state = "closed"
168
+ @gate.aasm_current_state.should == :closed
166
169
  end
167
170
 
168
171
  it "should return the aasm column when not new and the aasm_column is not nil" do
169
- foo = Gate.new
170
- foo.stub!(:new_record?).and_return(false)
171
- foo.aasm_state = "state"
172
- foo.aasm_current_state.should == :state
172
+ @gate.stub!(:new_record?).and_return(false)
173
+ @gate.aasm_state = "state"
174
+ @gate.aasm_current_state.should == :state
173
175
  end
174
176
 
175
177
  it "should allow a nil state" do
176
- foo = Gate.new
177
- foo.stub!(:new_record?).and_return(false)
178
- foo.aasm_state = nil
179
- foo.aasm_current_state.should be_nil
178
+ @gate.stub!(:new_record?).and_return(false)
179
+ @gate.aasm_state = nil
180
+ @gate.aasm_current_state.should be_nil
180
181
  end
181
182
 
182
183
  it "should have aasm_ensure_initial_state" do
183
- foo = Gate.new
184
- foo.send :aasm_ensure_initial_state
184
+ @gate.send :aasm_ensure_initial_state
185
185
  end
186
186
 
187
187
  it "should call aasm_ensure_initial_state on validation before create" do
188
- foo = Gate.new
189
- foo.should_receive(:aasm_ensure_initial_state).and_return(true)
190
- foo.valid?
188
+ @gate.should_receive(:aasm_ensure_initial_state).and_return(true)
189
+ @gate.valid?
191
190
  end
192
191
 
193
192
  it "should call aasm_ensure_initial_state on validation before create" do
194
- foo = Gate.new
195
- foo.stub!(:new_record?).and_return(false)
196
- foo.should_not_receive(:aasm_ensure_initial_state)
197
- foo.valid?
193
+ @gate.stub!(:new_record?).and_return(false)
194
+ @gate.should_not_receive(:aasm_ensure_initial_state)
195
+ @gate.valid?
198
196
  end
199
197
 
200
198
  end
@@ -248,5 +246,3 @@ describe 'Thieves' do
248
246
  Thief.new(:skilled => false).aasm_current_state.should == :jailed
249
247
  end
250
248
  end
251
-
252
- # TODO: figure out how to test ActiveRecord reload! without a database
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aasm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 0
10
- version: 3.0.0
9
+ - 1
10
+ version: 3.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Scott Barron
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-11-26 00:00:00 +01:00
21
+ date: 2011-12-21 00:00:00 +01:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -172,6 +172,7 @@ files:
172
172
  - lib/aasm/errors.rb
173
173
  - lib/aasm/persistence.rb
174
174
  - lib/aasm/persistence/active_record_persistence.rb
175
+ - lib/aasm/persistence/mongoid_persistence.rb
175
176
  - lib/aasm/state_machine.rb
176
177
  - lib/aasm/supporting_classes/event.rb
177
178
  - lib/aasm/supporting_classes/localizer.rb