state_shifter 0.7.2 → 0.8.0

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/Gemfile CHANGED
@@ -7,6 +7,7 @@ source "http://rubygems.org"
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
  group :development do
9
9
  gem 'activerecord', '~> 3.2.x'
10
+ gem 'sqlite3'
10
11
  gem "rspec", "~> 2.8.0"
11
12
  gem "yard", "~> 0.7"
12
13
  gem 'redcarpet'
data/Gemfile.lock CHANGED
@@ -40,6 +40,7 @@ GEM
40
40
  multi_json (~> 1.0)
41
41
  simplecov-html (~> 0.5.3)
42
42
  simplecov-html (0.5.3)
43
+ sqlite3 (1.3.6)
43
44
  tzinfo (0.3.33)
44
45
  yard (0.8.2.1)
45
46
 
@@ -54,4 +55,5 @@ DEPENDENCIES
54
55
  redcarpet
55
56
  rspec (~> 2.8.0)
56
57
  simplecov
58
+ sqlite3
57
59
  yard (~> 0.7)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.2
1
+ 0.8.0
@@ -1,4 +1,4 @@
1
- class Advanced
1
+ class MalformedPersistence
2
2
  include StateShifter::Definition
3
3
 
4
4
  ###
@@ -0,0 +1,98 @@
1
+ class MissingPersistence < ActiveRecord::Base
2
+ include StateShifter::Definition
3
+
4
+ ###
5
+
6
+ persist_attribute :lollies
7
+
8
+ state_machine do
9
+
10
+ state :initialized do
11
+
12
+ event :start_date_changed, :call => :handle_start_date_changed
13
+ event :forced_start => :running
14
+ event :start_date_reached => :running, :if => :start_date_reached?
15
+ event :abort_initialized_contest => :finalized
16
+ end
17
+
18
+ state :running do
19
+
20
+ on_entry do |previous_state, trigger_event|
21
+ running_entry previous_state, trigger_event
22
+ end
23
+
24
+ event :abort_running_contest => :notify_stakeholders
25
+ event :changed_properties
26
+ event :keep_users_engaged
27
+ event :deadline_reached => :notify_organizers, :if => :entries_deadline_reached?
28
+ event :spots_filled => :notify_organizers, :if => :spots_filled?
29
+ event :deadline_reached_without_approvals => :notify_pending_users, :if => :entries_deadline_reached_without_approvals?
30
+ event :deadline_reached_without_entries => :finalized, :if => :entries_deadline_reached_without_entries?
31
+ end
32
+
33
+ state :notify_organizers do
34
+ on_entry :send_notification_to_organizers
35
+ event :organizers_notified => :awaiting_organizer_reply
36
+ end
37
+
38
+ state :awaiting_organizer_reply do
39
+ event :organizer_confirmation_missing => :notify_stakeholders, :if => :organizer_confirmation_deadline_reached?
40
+ event :keep_organizers_engaged
41
+ event :organizer_confirmation_received => :notify_approved_users
42
+ event :organizer_has_more_tickets => :running
43
+ end
44
+
45
+ state :notify_stakeholders do
46
+ on_entry :send_notification_to_stakeholders
47
+ event :stakeholders_notified => :cancelled
48
+ end
49
+
50
+ state :cancelled
51
+
52
+ state :notify_pending_users do
53
+ on_entry :send_notification_to_pending_users
54
+ event :pending_users_notified => :finalized
55
+ end
56
+
57
+ state :notify_approved_users do
58
+ on_entry :send_notification_to_approved_users
59
+ event :approved_users_notified => :send_list_to_organizers
60
+ end
61
+
62
+ state :send_list_to_organizers do
63
+ on_entry :send_guestlist_to_organizers
64
+ event :list_sent_to_organizers => :awaiting_attendance
65
+ end
66
+
67
+ state :awaiting_attendance do
68
+ event :remind_to_fill_in_report => :create_report_filling_requests
69
+ end
70
+
71
+ state :create_report_filling_requests do
72
+ on_entry :send_report_filling_requests
73
+ event :finalize => :finalized
74
+ end
75
+
76
+ state :finalized
77
+
78
+ on_transition do |from,to,trigger_event, duration|
79
+ benchmark from, to, trigger_event, duration
80
+ end
81
+ end
82
+
83
+
84
+ ###
85
+
86
+ def entries_deadline_reached?
87
+ true
88
+ end
89
+
90
+ def running_entry previous_state, trigger_event
91
+ #
92
+ end
93
+
94
+ def benchmark from, to, trigger_event, duration
95
+ #
96
+ end
97
+
98
+ end
@@ -0,0 +1,33 @@
1
+ class Review < ActiveRecord::Base
2
+ include StateShifter::Definition
3
+
4
+ state_machine do
5
+
6
+ # first state to be defined is the initial one
7
+ state :new do
8
+ event :submit => :awaiting_review
9
+ end
10
+
11
+ state :awaiting_review do
12
+ event :review => :being_reviewed
13
+ end
14
+
15
+ state :being_reviewed do
16
+ event :accept => :accepted, :if => :cool_article?
17
+ event :reject => :rejected, :if => :bad_article?
18
+ end
19
+
20
+ state :accepted
21
+ state :rejected
22
+
23
+ end
24
+
25
+ def cool_article?
26
+ true
27
+ end
28
+
29
+ def bad_article?
30
+ false
31
+ end
32
+
33
+ end
@@ -0,0 +1,35 @@
1
+ class ReviewCustomPersistence < ActiveRecord::Base
2
+ include StateShifter::Definition
3
+
4
+ persist_attribute :stamp
5
+
6
+ state_machine do
7
+
8
+ # first state to be defined is the initial one
9
+ state :new do
10
+ event :submit => :awaiting_review
11
+ end
12
+
13
+ state :awaiting_review do
14
+ event :review => :being_reviewed
15
+ end
16
+
17
+ state :being_reviewed do
18
+ event :accept => :accepted, :if => :cool_article?
19
+ event :reject => :rejected, :if => :bad_article?
20
+ end
21
+
22
+ state :accepted
23
+ state :rejected
24
+
25
+ end
26
+
27
+ def cool_article?
28
+ true
29
+ end
30
+
31
+ def bad_article?
32
+ false
33
+ end
34
+
35
+ end
@@ -0,0 +1,24 @@
1
+ module StateShifter
2
+ module Definition
3
+ module ActiveRecordIntegrationMethods
4
+
5
+ class ::StateShifter::Definition::StatePersistenceAttributeNotPresent < RuntimeError; end
6
+
7
+ def get_current_state
8
+ raise StatePersistenceAttributeNotPresent unless self.attribute_names.include? self.class.persist_attr_name.to_s
9
+ read_attribute self.class.persist_attr_name
10
+ end
11
+
12
+ def set_current_state value
13
+ raise StatePersistenceAttributeNotPresent unless self.attribute_names.include? self.class.persist_attr_name.to_s
14
+ update_attribute self.class.persist_attr_name, value
15
+ end
16
+
17
+ def write_initial_state
18
+ raise StatePersistenceAttributeNotPresent unless self.attribute_names.include? self.class.persist_attr_name.to_s
19
+ write_attribute self.class.persist_attr_name, self.class.state_machine_definition.initial_state.name.to_sym
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -3,7 +3,7 @@ module StateShifter
3
3
  module InstanceMethods
4
4
 
5
5
  def current_state
6
- @current_state ||= get_current_state
6
+ get_current_state
7
7
  end
8
8
 
9
9
  def get_current_state
@@ -19,11 +19,11 @@ module StateShifter
19
19
  end
20
20
 
21
21
  def next_states
22
- _next_states current_state
22
+ _next_states get_current_state
23
23
  end
24
24
 
25
25
  def transitionable_states
26
- _next_states current_state, {:check_guards => true}
26
+ _next_states get_current_state, {:check_guards => true}
27
27
  end
28
28
 
29
29
  def state_names
@@ -52,7 +52,7 @@ module StateShifter
52
52
  end
53
53
 
54
54
  def current_state_def
55
- state_machine_definition.get(:state, current_state)
55
+ state_machine_definition.get(:state, get_current_state)
56
56
  end
57
57
 
58
58
  def call_state_entry_callback trigger, old_state
@@ -73,7 +73,7 @@ module StateShifter
73
73
  _start = Time.now
74
74
 
75
75
  # BOOP!
76
- old_state = current_state
76
+ old_state = get_current_state
77
77
  set_current_state args[:to].to_sym
78
78
  #
79
79
 
@@ -81,7 +81,7 @@ module StateShifter
81
81
 
82
82
  call_state_entry_callback(args[:trigger], old_state) if current_state_def.has_entry_callback?
83
83
 
84
- self.instance_exec(old_state, current_state, args[:trigger].to_sym, (Time.now - _start), &state_machine_definition.on_transition_proc) if state_machine_definition.has_on_transition_proc?
84
+ self.instance_exec(old_state, get_current_state, args[:trigger].to_sym, (Time.now - _start), &state_machine_definition.on_transition_proc) if state_machine_definition.has_on_transition_proc?
85
85
 
86
86
  true
87
87
  end
@@ -4,6 +4,13 @@ module StateShifter
4
4
  def self.included klass
5
5
  klass.send :include, InstanceMethods
6
6
  klass.extend ClassMethods
7
+
8
+ if Object.const_defined?(:ActiveRecord)
9
+ if klass < ActiveRecord::Base
10
+ klass.send :include, ActiveRecordIntegrationMethods
11
+ klass.before_validation :write_initial_state
12
+ end
13
+ end
7
14
  end
8
15
 
9
16
  end
data/lib/state_shifter.rb CHANGED
@@ -4,6 +4,7 @@ require 'state_shifter/definition'
4
4
  require 'state_shifter/definition/contents'
5
5
  require 'state_shifter/definition/class_methods'
6
6
  require 'state_shifter/definition/instance_methods'
7
+ require 'state_shifter/definition/active_record_integration_methods'
7
8
 
8
9
  class ::StateShifter::TransitionHalted < Exception ; end
9
10
  class ::StateShifter::GuardMethodUndefined < Exception ; end
@@ -1,11 +1,14 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require_relative '../examples/simple'
3
3
  require_relative '../examples/advanced'
4
+ require_relative '../examples/review'
5
+ require_relative '../examples/review_custom_persistence'
4
6
 
5
7
  shared_examples_for 'a simple state machine' do
6
8
 
7
9
  before(:each) do
8
10
  @state_machine = described_class.new
11
+ @state_machine.save if @state_machine.class < ActiveRecord::Base
9
12
  end
10
13
 
11
14
  it 'should have all states and events defined' do
@@ -19,6 +22,7 @@ shared_examples_for 'a simple state machine' do
19
22
 
20
23
  @state_machine.submit
21
24
  @state_machine.initial_state.should == :new
25
+
22
26
  @state_machine.current_state.should == :awaiting_review
23
27
  end
24
28
 
@@ -162,3 +166,60 @@ describe 'Advanced state machine functionality' do
162
166
 
163
167
  end
164
168
 
169
+ describe Review do
170
+
171
+ before(:all) do
172
+ ActiveRecord::Migration.verbose = false
173
+
174
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
175
+
176
+ ActiveRecord::Schema.define do
177
+ create_table :reviews do |t|
178
+ t.string :current_state
179
+ end
180
+ end
181
+ end
182
+
183
+ it_should_behave_like 'a simple state machine'
184
+
185
+ end
186
+
187
+ describe ReviewCustomPersistence do
188
+
189
+ before(:all) do
190
+ ActiveRecord::Migration.verbose = false
191
+
192
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
193
+
194
+ ActiveRecord::Schema.define do
195
+ create_table :review_custom_persistences do |t|
196
+ t.string :stamp
197
+ end
198
+ end
199
+ end
200
+
201
+ it_should_behave_like 'a simple state machine'
202
+
203
+ end
204
+
205
+ describe 'Malformed persistence definition' do
206
+
207
+ before(:all) do
208
+ ActiveRecord::Migration.verbose = false
209
+
210
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
211
+
212
+ ActiveRecord::Schema.define do
213
+ create_table :missing_persistences do |t|
214
+ t.string :xyz
215
+ end
216
+ end
217
+ end
218
+
219
+ it 'should complain when the persist attribute is not present' do
220
+ require_relative '../examples/missing_persistence'
221
+ review_custom_persistence = MissingPersistence.new
222
+ lambda { review_custom_persistence.save }.should raise_error(StateShifter::Definition::StatePersistenceAttributeNotPresent)
223
+ end
224
+
225
+ end
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "state_shifter"
8
- s.version = "0.7.2"
8
+ s.version = "0.8.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bruno Antunes"]
@@ -29,9 +29,13 @@ Gem::Specification.new do |s|
29
29
  "examples/malformed_events.rb",
30
30
  "examples/malformed_persistence.rb",
31
31
  "examples/malformed_states.rb",
32
+ "examples/missing_persistence.rb",
33
+ "examples/review.rb",
34
+ "examples/review_custom_persistence.rb",
32
35
  "examples/simple.rb",
33
36
  "lib/state_shifter.rb",
34
37
  "lib/state_shifter/definition.rb",
38
+ "lib/state_shifter/definition/active_record_integration_methods.rb",
35
39
  "lib/state_shifter/definition/class_methods.rb",
36
40
  "lib/state_shifter/definition/contents.rb",
37
41
  "lib/state_shifter/definition/instance_methods.rb",
@@ -52,6 +56,7 @@ Gem::Specification.new do |s|
52
56
 
53
57
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
58
  s.add_development_dependency(%q<activerecord>, ["~> 3.2.x"])
59
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
55
60
  s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
56
61
  s.add_development_dependency(%q<yard>, ["~> 0.7"])
57
62
  s.add_development_dependency(%q<redcarpet>, [">= 0"])
@@ -61,6 +66,7 @@ Gem::Specification.new do |s|
61
66
  s.add_development_dependency(%q<simplecov>, [">= 0"])
62
67
  else
63
68
  s.add_dependency(%q<activerecord>, ["~> 3.2.x"])
69
+ s.add_dependency(%q<sqlite3>, [">= 0"])
64
70
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
65
71
  s.add_dependency(%q<yard>, ["~> 0.7"])
66
72
  s.add_dependency(%q<redcarpet>, [">= 0"])
@@ -71,6 +77,7 @@ Gem::Specification.new do |s|
71
77
  end
72
78
  else
73
79
  s.add_dependency(%q<activerecord>, ["~> 3.2.x"])
80
+ s.add_dependency(%q<sqlite3>, [">= 0"])
74
81
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
75
82
  s.add_dependency(%q<yard>, ["~> 0.7"])
76
83
  s.add_dependency(%q<redcarpet>, [">= 0"])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: state_shifter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.2.x
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rspec
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -159,9 +175,13 @@ files:
159
175
  - examples/malformed_events.rb
160
176
  - examples/malformed_persistence.rb
161
177
  - examples/malformed_states.rb
178
+ - examples/missing_persistence.rb
179
+ - examples/review.rb
180
+ - examples/review_custom_persistence.rb
162
181
  - examples/simple.rb
163
182
  - lib/state_shifter.rb
164
183
  - lib/state_shifter/definition.rb
184
+ - lib/state_shifter/definition/active_record_integration_methods.rb
165
185
  - lib/state_shifter/definition/class_methods.rb
166
186
  - lib/state_shifter/definition/contents.rb
167
187
  - lib/state_shifter/definition/instance_methods.rb
@@ -185,7 +205,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
205
  version: '0'
186
206
  segments:
187
207
  - 0
188
- hash: -2788732275758639550
208
+ hash: 3920605756095371187
189
209
  required_rubygems_version: !ruby/object:Gem::Requirement
190
210
  none: false
191
211
  requirements: