alexrevin-aasm_numerical 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.document +5 -0
  2. data/.gitignore +11 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +20 -0
  5. data/README.md +149 -0
  6. data/Rakefile +27 -0
  7. data/lib/alexrevin-aasm_numerical.rb +10 -0
  8. data/lib/alexrevin-aasm_numerical/aasm.rb +222 -0
  9. data/lib/alexrevin-aasm_numerical/event.rb +127 -0
  10. data/lib/alexrevin-aasm_numerical/localizer.rb +36 -0
  11. data/lib/alexrevin-aasm_numerical/persistence.rb +14 -0
  12. data/lib/alexrevin-aasm_numerical/persistence/active_record_persistence.rb +257 -0
  13. data/lib/alexrevin-aasm_numerical/state.rb +53 -0
  14. data/lib/alexrevin-aasm_numerical/state_machine.rb +31 -0
  15. data/lib/alexrevin-aasm_numerical/state_transition.rb +46 -0
  16. data/lib/alexrevin-aasm_numerical/supporting_classes.rb +6 -0
  17. data/lib/alexrevin-aasm_numerical/version.rb +3 -0
  18. data/spec/database.yml +3 -0
  19. data/spec/en.yml +10 -0
  20. data/spec/functional/conversation.rb +49 -0
  21. data/spec/functional/conversation_spec.rb +8 -0
  22. data/spec/schema.rb +7 -0
  23. data/spec/spec_helper.rb +16 -0
  24. data/spec/unit/aasm_spec.rb +462 -0
  25. data/spec/unit/active_record_persistence_spec.rb +246 -0
  26. data/spec/unit/before_after_callbacks_spec.rb +79 -0
  27. data/spec/unit/event_spec.rb +140 -0
  28. data/spec/unit/localizer_spec.rb +51 -0
  29. data/spec/unit/state_spec.rb +85 -0
  30. data/spec/unit/state_transition_spec.rb +163 -0
  31. data/test/functional/auth_machine_test.rb +148 -0
  32. data/test/models/process.rb +18 -0
  33. data/test/test_helper.rb +43 -0
  34. data/test/unit/aasm_test.rb +0 -0
  35. data/test/unit/event_test.rb +54 -0
  36. data/test/unit/state_machine_test.rb +37 -0
  37. data/test/unit/state_test.rb +69 -0
  38. data/test/unit/state_transition_test.rb +75 -0
  39. metadata +254 -0
@@ -0,0 +1,246 @@
1
+ begin
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'logger'
5
+
6
+ load_schema
7
+
8
+ ActiveRecord::Base.logger = Logger.new(STDERR)
9
+
10
+ class Gate < ActiveRecord::Base
11
+ include AASM
12
+
13
+ # Fake this column for testing purposes
14
+ attr_accessor :aasm_state
15
+
16
+ aasm_state :opened
17
+ aasm_state :closed
18
+
19
+ aasm_event :view do
20
+ transitions :to => :read, :from => [:needs_attention]
21
+ end
22
+ end
23
+
24
+ class Reader < ActiveRecord::Base
25
+ def aasm_read_state
26
+ "fi"
27
+ end
28
+ include AASM
29
+ end
30
+
31
+ class Writer < ActiveRecord::Base
32
+ def aasm_write_state(state)
33
+ "fo"
34
+ end
35
+ include AASM
36
+ end
37
+
38
+ class Transient < ActiveRecord::Base
39
+ def aasm_write_state_without_persistence(state)
40
+ "fum"
41
+ end
42
+ include AASM
43
+ end
44
+
45
+ class Simple < ActiveRecord::Base
46
+ include AASM
47
+ aasm_column :status
48
+ end
49
+
50
+ class Derivate < Simple
51
+ end
52
+
53
+ class Thief < ActiveRecord::Base
54
+ set_table_name "thieves"
55
+ include AASM
56
+ aasm_initial_state Proc.new { |thief| thief.skilled ? :rich : :jailed }
57
+ aasm_state :rich
58
+ aasm_state :jailed
59
+ attr_accessor :skilled, :aasm_state
60
+ end
61
+
62
+ shared_examples_for "aasm model" do
63
+ it "should include AASM::Persistence::ActiveRecordPersistence" do
64
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
65
+ end
66
+ it "should include AASM::Persistence::ActiveRecordPersistence::InstanceMethods" do
67
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
68
+ end
69
+ end
70
+
71
+ describe Gate, "class methods" do
72
+ before(:each) do
73
+ @klass = Gate
74
+ end
75
+ it_should_behave_like "aasm model"
76
+ it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
77
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
78
+ end
79
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
80
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
81
+ end
82
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
83
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
84
+ end
85
+ end
86
+
87
+ describe Reader, "class methods" do
88
+ before(:each) do
89
+ @klass = Reader
90
+ end
91
+ it_should_behave_like "aasm model"
92
+ it "should not include AASM::Persistence::ActiveRecordPersistence::ReadState" do
93
+ @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
94
+ end
95
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
96
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
97
+ end
98
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
99
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
100
+ end
101
+ end
102
+
103
+ describe Writer, "class methods" do
104
+ before(:each) do
105
+ @klass = Writer
106
+ end
107
+ it_should_behave_like "aasm model"
108
+ it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
109
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
110
+ end
111
+ it "should not include AASM::Persistence::ActiveRecordPersistence::WriteState" do
112
+ @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
113
+ end
114
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
115
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
116
+ end
117
+ end
118
+
119
+ describe Transient, "class methods" do
120
+ before(:each) do
121
+ @klass = Transient
122
+ end
123
+ it_should_behave_like "aasm model"
124
+ it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
125
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
126
+ end
127
+ it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
128
+ @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
129
+ end
130
+ it "should not include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
131
+ @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
132
+ end
133
+ end
134
+
135
+ describe Gate, "instance methods" do
136
+
137
+ it "should respond to aasm read state when not previously defined" do
138
+ Gate.new.should respond_to(:aasm_read_state)
139
+ end
140
+
141
+ it "should respond to aasm write state when not previously defined" do
142
+ Gate.new.should respond_to(:aasm_write_state)
143
+ end
144
+
145
+ it "should respond to aasm write state without persistence when not previously defined" do
146
+ Gate.new.should respond_to(:aasm_write_state_without_persistence)
147
+ end
148
+
149
+ it "should return the initial state when new and the aasm field is nil" do
150
+ Gate.new.aasm_current_state.should == :opened
151
+ end
152
+
153
+ it "should return the aasm column when new and the aasm field is not nil" do
154
+ foo = Gate.new
155
+ foo.aasm_state = "closed"
156
+ foo.aasm_current_state.should == :closed
157
+ end
158
+
159
+ it "should return the aasm column when not new and the aasm_column is not nil" do
160
+ foo = Gate.new
161
+ foo.stub!(:new_record?).and_return(false)
162
+ foo.aasm_state = "state"
163
+ foo.aasm_current_state.should == :state
164
+ end
165
+
166
+ it "should allow a nil state" do
167
+ foo = Gate.new
168
+ foo.stub!(:new_record?).and_return(false)
169
+ foo.aasm_state = nil
170
+ foo.aasm_current_state.should be_nil
171
+ end
172
+
173
+ it "should have aasm_ensure_initial_state" do
174
+ foo = Gate.new
175
+ foo.send :aasm_ensure_initial_state
176
+ end
177
+
178
+ it "should call aasm_ensure_initial_state on validation before create" do
179
+ foo = Gate.new
180
+ foo.should_receive(:aasm_ensure_initial_state).and_return(true)
181
+ foo.valid?
182
+ end
183
+
184
+ it "should call aasm_ensure_initial_state on validation before create" do
185
+ foo = Gate.new
186
+ foo.stub!(:new_record?).and_return(false)
187
+ foo.should_not_receive(:aasm_ensure_initial_state)
188
+ foo.valid?
189
+ end
190
+
191
+ end
192
+
193
+ describe 'Derivates' do
194
+ it "should have the same states as it's parent" do
195
+ Derivate.aasm_states.should == Simple.aasm_states
196
+ end
197
+
198
+ it "should have the same events as it's parent" do
199
+ Derivate.aasm_events.should == Simple.aasm_events
200
+ end
201
+
202
+ it "should have the same column as it's parent" do
203
+ Derivate.aasm_column.should == :status
204
+ end
205
+ end
206
+
207
+ describe AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods do
208
+
209
+ context "Does not already respond_to? the scope name" do
210
+ it "should add a scope" do
211
+ Simple.should_not respond_to(:unknown_scope)
212
+ Simple.aasm_state :unknown_scope
213
+ Simple.should respond_to(:unknown_scope)
214
+ Simple.unknown_scope.class.should == ActiveRecord::Relation
215
+ end
216
+ end
217
+
218
+ context "Already respond_to? the scope name" do
219
+ it "should not add a scope" do
220
+ Simple.aasm_state :new
221
+ Simple.should respond_to(:new)
222
+ Simple.new.class.should == Simple
223
+ end
224
+ end
225
+ end
226
+
227
+ describe 'Thieves' do
228
+
229
+ it 'should be rich if they\'re skilled' do
230
+ Thief.new(:skilled => true).aasm_current_state.should == :rich
231
+ end
232
+
233
+ it 'should be jailed if they\'re unskilled' do
234
+ Thief.new(:skilled => false).aasm_current_state.should == :jailed
235
+ end
236
+ end
237
+
238
+ # TODO: figure out how to test ActiveRecord reload! without a database
239
+
240
+ rescue LoadError => e
241
+ if e.message == "no such file to load -- active_record"
242
+ puts "You must install active record to run this spec. Install with sudo gem install activerecord"
243
+ else
244
+ raise
245
+ end
246
+ end
@@ -0,0 +1,79 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ class Foo2
4
+ include AASM
5
+ aasm_initial_state :open
6
+ aasm_state :open,
7
+ :before_enter => :before_enter_open,
8
+ :before_exit => :before_exit_open,
9
+ :after_enter => :after_enter_open,
10
+ :after_exit => :after_exit_open
11
+ aasm_state :closed,
12
+ :before_enter => :before_enter_closed,
13
+ :before_exit => :before_exit_closed,
14
+ :after_enter => :after_enter_closed,
15
+ :after_exit => :after_exit_closed
16
+
17
+ aasm_event :close, :before => :before, :after => :after do
18
+ transitions :to => :closed, :from => [:open]
19
+ end
20
+
21
+ aasm_event :open, :before => :before, :after => :after do
22
+ transitions :to => :open, :from => :closed
23
+ end
24
+
25
+ def before_enter_open
26
+ end
27
+ def before_exit_open
28
+ end
29
+ def after_enter_open
30
+ end
31
+ def after_exit_open
32
+ end
33
+
34
+ def before_enter_closed
35
+ end
36
+ def before_exit_closed
37
+ end
38
+ def after_enter_closed
39
+ end
40
+ def after_exit_closed
41
+ end
42
+
43
+ def before
44
+ end
45
+ def after
46
+ end
47
+ end
48
+
49
+ describe Foo2, '- new callbacks' do
50
+ before(:each) do
51
+ @foo = Foo2.new
52
+ end
53
+
54
+ it "should get close callbacks" do
55
+ @foo.should_receive(:before).once.ordered
56
+ @foo.should_receive(:before_exit_open).once.ordered # these should be before the state changes
57
+ @foo.should_receive(:before_enter_closed).once.ordered
58
+ @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
59
+ @foo.should_receive(:after_exit_open).once.ordered # these should be after the state changes
60
+ @foo.should_receive(:after_enter_closed).once.ordered
61
+ @foo.should_receive(:after).once.ordered
62
+
63
+ @foo.close!
64
+ end
65
+
66
+ it "should get open callbacks" do
67
+ @foo.close!
68
+
69
+ @foo.should_receive(:before).once.ordered
70
+ @foo.should_receive(:before_exit_closed).once.ordered # these should be before the state changes
71
+ @foo.should_receive(:before_enter_open).once.ordered
72
+ @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
73
+ @foo.should_receive(:after_exit_closed).once.ordered # these should be after the state changes
74
+ @foo.should_receive(:after_enter_open).once.ordered
75
+ @foo.should_receive(:after).once.ordered
76
+
77
+ @foo.open!
78
+ end
79
+ end
@@ -0,0 +1,140 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe AASM::SupportingClasses::Event do
4
+ before(:each) do
5
+ @name = :close_order
6
+ @success = :success_callback
7
+ end
8
+
9
+ def new_event
10
+ @event = AASM::SupportingClasses::Event.new(@name, {:success => @success}) do
11
+ transitions :to => :closed, :from => [:open, :received]
12
+ end
13
+ end
14
+
15
+ it 'should set the name' do
16
+ new_event
17
+ @event.name.should == @name
18
+ end
19
+
20
+ it 'should set the success option' do
21
+ new_event
22
+ @event.success.should == @success
23
+ end
24
+
25
+ it 'should create StateTransitions' do
26
+ AASM::SupportingClasses::StateTransition.should_receive(:new).with({:to => :closed, :from => :open})
27
+ AASM::SupportingClasses::StateTransition.should_receive(:new).with({:to => :closed, :from => :received})
28
+ new_event
29
+ end
30
+ end
31
+
32
+ describe AASM::SupportingClasses::Event, 'when firing an event' do
33
+ it 'should raise an AASM::InvalidTransition error if the transitions are empty' do
34
+ obj = mock('object')
35
+ obj.stub!(:aasm_current_state)
36
+
37
+ event = AASM::SupportingClasses::Event.new(:event)
38
+ lambda { event.fire(obj) }.should raise_error(AASM::InvalidTransition)
39
+ end
40
+
41
+ it 'should return the state of the first matching transition it finds' do
42
+ event = AASM::SupportingClasses::Event.new(:event) do
43
+ transitions :to => :closed, :from => [:open, :received]
44
+ end
45
+
46
+ obj = mock('object')
47
+ obj.stub!(:aasm_current_state).and_return(:open)
48
+
49
+ event.fire(obj).should == :closed
50
+ end
51
+
52
+
53
+ it 'should call the guard with the params passed in' do
54
+ event = AASM::SupportingClasses::Event.new(:event) do
55
+ transitions :to => :closed, :from => [:open, :received], :guard => :guard_fn
56
+ end
57
+
58
+ obj = mock('object')
59
+ obj.stub!(:aasm_current_state).and_return(:open)
60
+ obj.should_receive(:guard_fn).with('arg1', 'arg2').and_return(true)
61
+
62
+ event.fire(obj, nil, 'arg1', 'arg2').should == :closed
63
+ end
64
+
65
+ end
66
+
67
+ describe AASM::SupportingClasses::Event, 'when executing the success callback' do
68
+ class ThisNameBetterNotBeInUse
69
+ include AASM
70
+
71
+ aasm_state :initial
72
+ aasm_state :symbol
73
+ aasm_state :string
74
+ aasm_state :array
75
+ aasm_state :proc
76
+ end
77
+
78
+ it "should send the success callback if it's a symbol" do
79
+ ThisNameBetterNotBeInUse.instance_eval {
80
+ aasm_event :with_symbol, :success => :symbol_success_callback do
81
+ transitions :to => :symbol, :from => [:initial]
82
+ end
83
+ }
84
+
85
+ model = ThisNameBetterNotBeInUse.new
86
+ model.should_receive(:symbol_success_callback)
87
+ model.with_symbol!
88
+ end
89
+
90
+ it "should send the success callback if it's a string" do
91
+ ThisNameBetterNotBeInUse.instance_eval {
92
+ aasm_event :with_string, :success => 'string_success_callback' do
93
+ transitions :to => :string, :from => [:initial]
94
+ end
95
+ }
96
+
97
+ model = ThisNameBetterNotBeInUse.new
98
+ model.should_receive(:string_success_callback)
99
+ model.with_string!
100
+ end
101
+
102
+ it "should call each success callback if passed an array of strings and/or symbols" do
103
+ ThisNameBetterNotBeInUse.instance_eval {
104
+ aasm_event :with_array, :success => [:success_callback1, 'success_callback2'] do
105
+ transitions :to => :array, :from => [:initial]
106
+ end
107
+ }
108
+
109
+ model = ThisNameBetterNotBeInUse.new
110
+ model.should_receive(:success_callback1)
111
+ model.should_receive(:success_callback2)
112
+ model.with_array!
113
+ end
114
+
115
+ it "should call each success callback if passed an array of strings and/or symbols and/or procs" do
116
+ ThisNameBetterNotBeInUse.instance_eval {
117
+ aasm_event :with_array_including_procs, :success => [:success_callback1, 'success_callback2', lambda { |obj| obj.proc_success_callback }] do
118
+ transitions :to => :array, :from => [:initial]
119
+ end
120
+ }
121
+
122
+ model = ThisNameBetterNotBeInUse.new
123
+ model.should_receive(:success_callback1)
124
+ model.should_receive(:success_callback2)
125
+ model.should_receive(:proc_success_callback)
126
+ model.with_array_including_procs!
127
+ end
128
+
129
+ it "should call the success callback if it's a proc" do
130
+ ThisNameBetterNotBeInUse.instance_eval {
131
+ aasm_event :with_proc, :success => lambda { |obj| obj.proc_success_callback } do
132
+ transitions :to => :proc, :from => [:initial]
133
+ end
134
+ }
135
+
136
+ model = ThisNameBetterNotBeInUse.new
137
+ model.should_receive(:proc_success_callback)
138
+ model.with_proc!
139
+ end
140
+ end