transitions 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -1
- data/.travis.yml +5 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +7 -6
- data/LICENSE.txt +21 -0
- data/README.md +9 -4
- data/Rakefile +9 -4
- data/bin/console +7 -0
- data/lib/active_model/transitions.rb +19 -12
- data/lib/transitions.rb +15 -15
- data/lib/transitions/event.rb +19 -15
- data/lib/transitions/machine.rb +23 -22
- data/lib/transitions/presenter.rb +2 -6
- data/lib/transitions/state.rb +10 -7
- data/lib/transitions/state_transition.rb +37 -6
- data/lib/transitions/version.rb +1 -1
- data/transitions.gemspec +23 -24
- metadata +39 -45
- data/.ruby-gemset +0 -1
- data/MIT-LICENSE.txt +0 -21
- data/test/active_record/test_active_record.rb +0 -326
- data/test/active_record/test_active_record_scopes.rb +0 -64
- data/test/active_record/test_active_record_timestamps.rb +0 -132
- data/test/active_record/test_custom_select.rb +0 -33
- data/test/event/test_event.rb +0 -72
- data/test/event/test_event_arguments.rb +0 -29
- data/test/event/test_event_being_fired.rb +0 -26
- data/test/event/test_event_checks.rb +0 -33
- data/test/helper.rb +0 -18
- data/test/machine/machine_template.rb +0 -27
- data/test/machine/test_available_states_listing.rb +0 -24
- data/test/machine/test_fire_event_machine.rb +0 -29
- data/test/machine/test_machine.rb +0 -66
- data/test/state/test_state.rb +0 -71
- data/test/state/test_state_predicate_method.rb +0 -32
- data/test/state_transition/test_state_transition.rb +0 -45
- data/test/state_transition/test_state_transition_event_failed_callback.rb +0 -36
- data/test/state_transition/test_state_transition_event_fired_callback.rb +0 -44
- data/test/state_transition/test_state_transition_guard_check.rb +0 -66
- data/test/state_transition/test_state_transition_on_transition_callback.rb +0 -48
- data/test/state_transition/test_state_transition_success_callback.rb +0 -49
@@ -1,15 +1,11 @@
|
|
1
1
|
module Transitions
|
2
2
|
module Presenter
|
3
3
|
def available_states
|
4
|
-
|
4
|
+
get_state_machine.states.map(&:name).sort_by(&:to_s)
|
5
5
|
end
|
6
6
|
|
7
7
|
def available_events
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def available_transitions
|
12
|
-
@state_machine.events_for(current_state)
|
8
|
+
get_state_machine.events.keys.sort
|
13
9
|
end
|
14
10
|
end
|
15
11
|
end
|
data/lib/transitions/state.rb
CHANGED
@@ -10,11 +10,11 @@ module Transitions
|
|
10
10
|
update(options)
|
11
11
|
end
|
12
12
|
|
13
|
-
def ==(
|
14
|
-
if
|
15
|
-
name ==
|
13
|
+
def ==(other)
|
14
|
+
if other.is_a? Symbol
|
15
|
+
name == other
|
16
16
|
else
|
17
|
-
name ==
|
17
|
+
name == other.name
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -29,7 +29,7 @@ module Transitions
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def display_name
|
32
|
-
@display_name ||= name.to_s.
|
32
|
+
@display_name ||= name.to_s.tr('_', ' ').capitalize
|
33
33
|
end
|
34
34
|
|
35
35
|
def for_select
|
@@ -45,9 +45,12 @@ module Transitions
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def define_state_query_method(machine)
|
48
|
-
method_name
|
48
|
+
method_name = "#{@name}?"
|
49
|
+
state_name = @name # Instance vars are out of scope when calling define_method below, so we use local variables.
|
49
50
|
if machine.klass.method_defined?(method_name.to_sym)
|
50
|
-
fail InvalidMethodOverride,
|
51
|
+
fail InvalidMethodOverride,
|
52
|
+
"Transitions: Can not define method `#{method_name}` because it is already"\
|
53
|
+
'defined - either rename the existing method or the state.'
|
51
54
|
end
|
52
55
|
machine.klass.send :define_method, method_name do
|
53
56
|
current_state.to_s == state_name.to_s
|
@@ -1,16 +1,45 @@
|
|
1
1
|
module Transitions
|
2
2
|
class StateTransition
|
3
|
-
attr_reader :from, :to, :
|
3
|
+
attr_reader :from, :to, :guard, :on_transition
|
4
|
+
# TODO: `from` and `to` should be private as well
|
5
|
+
private :guard, :on_transition
|
4
6
|
|
5
7
|
def initialize(opts)
|
6
|
-
@from
|
8
|
+
@from = opts[:from]
|
9
|
+
@to = opts[:to]
|
10
|
+
@guard = opts[:guard]
|
11
|
+
@on_transition = opts[:on_transition]
|
7
12
|
@options = opts
|
8
13
|
end
|
9
14
|
|
15
|
+
#
|
16
|
+
# @param obj [Any] - the subject
|
17
|
+
# @param args [Array<Symbol>] - any arguments passed into the transition method
|
18
|
+
# E.g. something like
|
19
|
+
# car.drive!(:fast, :now)
|
20
|
+
# with `car` being the subject and `drive` the transition method would result
|
21
|
+
# in `args` looking like this:
|
22
|
+
# [:fast, :now]
|
23
|
+
#
|
24
|
+
# @return [Bool]
|
25
|
+
#
|
10
26
|
def executable?(obj, *args)
|
11
27
|
[@guard].flatten.all? { |g| perform_guard(obj, g, *args) }
|
12
28
|
end
|
13
29
|
|
30
|
+
#
|
31
|
+
# @param obj [Any] - the subject
|
32
|
+
# @param args [Array<Symbol>] - any arguments passed into the transition method
|
33
|
+
# E.g. something like
|
34
|
+
# car.drive!(:fast, :now)
|
35
|
+
# with `car` being the subject and `drive` the transition method would result
|
36
|
+
# in `args` looking like this:
|
37
|
+
# [:fast, :now]
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
# rubocop:disable Metrics/MethodLength
|
42
|
+
#
|
14
43
|
def execute(obj, *args)
|
15
44
|
case @on_transition
|
16
45
|
when Symbol, String
|
@@ -24,13 +53,15 @@ module Transitions
|
|
24
53
|
obj.send(callback, *args)
|
25
54
|
end
|
26
55
|
else
|
27
|
-
# TODO We probably should check for this in the constructor and not that late.
|
28
|
-
fail ArgumentError,
|
56
|
+
# TODO: We probably should check for this in the constructor and not that late.
|
57
|
+
fail ArgumentError,
|
58
|
+
"You can only pass a Symbol, a String, a Proc or an Array to 'on_transition'"\
|
59
|
+
" - got #{@on_transition.class}." unless @on_transition.nil?
|
29
60
|
end
|
30
61
|
end
|
31
62
|
|
32
|
-
def ==(
|
33
|
-
@from ==
|
63
|
+
def ==(other)
|
64
|
+
@from == other.from && @to == other.to
|
34
65
|
end
|
35
66
|
|
36
67
|
def from?(value)
|
data/lib/transitions/version.rb
CHANGED
data/transitions.gemspec
CHANGED
@@ -1,29 +1,28 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'transitions/version'
|
3
5
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
s.email = 'timo.roessner@googlemail.com'
|
10
|
-
s.homepage = 'http://github.com/troessner/transitions'
|
11
|
-
s.summary = 'State machine extracted from ActiveModel'
|
12
|
-
s.description = 'Lightweight state machine extracted from ActiveModel'
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'transitions'
|
8
|
+
spec.version = Transitions::VERSION
|
9
|
+
spec.authors = ['Timo Rößner']
|
10
|
+
spec.email = ['timo.roessner@googlemail.com']
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
spec.summary = 'State machine extracted from ActiveModel'
|
13
|
+
spec.description = 'Lightweight state machine extracted from ActiveModel'
|
14
|
+
spec.homepage = 'http://github.com/troessner/transitions'
|
15
|
+
spec.license = 'MIT'
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
s.add_development_dependency 'mocha', '~> 0.11.0' # With mocha 0.12 we get: undefined method `run' for #<StateMachineMachineTest:0x94918b8> (NoMethodError)
|
20
|
-
s.add_development_dependency 'rake'
|
21
|
-
s.add_development_dependency 'random_data'
|
22
|
-
s.add_development_dependency 'appraisal'
|
23
|
-
s.add_development_dependency 'activerecord', ['>= 3.0', '<= 4.0']
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.require_paths = ['lib']
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'test-unit', '~> 2.5'
|
23
|
+
spec.add_development_dependency 'mocha', '~> 0.11.0' # With mocha 0.12 we get: undefined method `run' for #<StateMachineMachineTest:0x94918b8> (NoMethodError)
|
24
|
+
spec.add_development_dependency 'random_data'
|
25
|
+
spec.add_development_dependency 'appraisal'
|
26
|
+
spec.add_development_dependency 'activerecord', ['>= 3.0', '<= 4.0']
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 0.36'
|
29
28
|
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transitions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
- Timo Roessner
|
7
|
+
- Timo Rößner
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-02-05 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
@@ -17,56 +16,56 @@ dependencies:
|
|
17
16
|
requirements:
|
18
17
|
- - "~>"
|
19
18
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1'
|
19
|
+
version: '1.0'
|
21
20
|
type: :development
|
22
21
|
prerelease: false
|
23
22
|
version_requirements: !ruby/object:Gem::Requirement
|
24
23
|
requirements:
|
25
24
|
- - "~>"
|
26
25
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1'
|
26
|
+
version: '1.0'
|
28
27
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
28
|
+
name: rake
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
|
-
- - "
|
31
|
+
- - ">="
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
33
|
+
version: '0'
|
35
34
|
type: :development
|
36
35
|
prerelease: false
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
|
-
- - "
|
38
|
+
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
40
|
+
version: '0'
|
42
41
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
42
|
+
name: test-unit
|
44
43
|
requirement: !ruby/object:Gem::Requirement
|
45
44
|
requirements:
|
46
45
|
- - "~>"
|
47
46
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
47
|
+
version: '2.5'
|
49
48
|
type: :development
|
50
49
|
prerelease: false
|
51
50
|
version_requirements: !ruby/object:Gem::Requirement
|
52
51
|
requirements:
|
53
52
|
- - "~>"
|
54
53
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
54
|
+
version: '2.5'
|
56
55
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
56
|
+
name: mocha
|
58
57
|
requirement: !ruby/object:Gem::Requirement
|
59
58
|
requirements:
|
60
|
-
- - "
|
59
|
+
- - "~>"
|
61
60
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
61
|
+
version: 0.11.0
|
63
62
|
type: :development
|
64
63
|
prerelease: false
|
65
64
|
version_requirements: !ruby/object:Gem::Requirement
|
66
65
|
requirements:
|
67
|
-
- - "
|
66
|
+
- - "~>"
|
68
67
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
68
|
+
version: 0.11.0
|
70
69
|
- !ruby/object:Gem::Dependency
|
71
70
|
name: random_data
|
72
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,23 +114,38 @@ dependencies:
|
|
115
114
|
- - "<="
|
116
115
|
- !ruby/object:Gem::Version
|
117
116
|
version: '4.0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rubocop
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0.36'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.36'
|
118
131
|
description: Lightweight state machine extracted from ActiveModel
|
119
|
-
email:
|
132
|
+
email:
|
133
|
+
- timo.roessner@googlemail.com
|
120
134
|
executables: []
|
121
135
|
extensions: []
|
122
136
|
extra_rdoc_files: []
|
123
137
|
files:
|
124
138
|
- ".gitignore"
|
125
139
|
- ".rubocop.yml"
|
126
|
-
- ".ruby-gemset"
|
127
140
|
- ".ruby-version"
|
128
141
|
- ".travis.yml"
|
129
142
|
- Appraisals
|
130
143
|
- CHANGELOG.md
|
131
144
|
- Gemfile
|
132
|
-
-
|
145
|
+
- LICENSE.txt
|
133
146
|
- README.md
|
134
147
|
- Rakefile
|
148
|
+
- bin/console
|
135
149
|
- gemfiles/rails_3_0.gemfile
|
136
150
|
- gemfiles/rails_3_1.gemfile
|
137
151
|
- gemfiles/rails_3_2.gemfile
|
@@ -145,27 +159,6 @@ files:
|
|
145
159
|
- lib/transitions/state.rb
|
146
160
|
- lib/transitions/state_transition.rb
|
147
161
|
- lib/transitions/version.rb
|
148
|
-
- test/active_record/test_active_record.rb
|
149
|
-
- test/active_record/test_active_record_scopes.rb
|
150
|
-
- test/active_record/test_active_record_timestamps.rb
|
151
|
-
- test/active_record/test_custom_select.rb
|
152
|
-
- test/event/test_event.rb
|
153
|
-
- test/event/test_event_arguments.rb
|
154
|
-
- test/event/test_event_being_fired.rb
|
155
|
-
- test/event/test_event_checks.rb
|
156
|
-
- test/helper.rb
|
157
|
-
- test/machine/machine_template.rb
|
158
|
-
- test/machine/test_available_states_listing.rb
|
159
|
-
- test/machine/test_fire_event_machine.rb
|
160
|
-
- test/machine/test_machine.rb
|
161
|
-
- test/state/test_state.rb
|
162
|
-
- test/state/test_state_predicate_method.rb
|
163
|
-
- test/state_transition/test_state_transition.rb
|
164
|
-
- test/state_transition/test_state_transition_event_failed_callback.rb
|
165
|
-
- test/state_transition/test_state_transition_event_fired_callback.rb
|
166
|
-
- test/state_transition/test_state_transition_guard_check.rb
|
167
|
-
- test/state_transition/test_state_transition_on_transition_callback.rb
|
168
|
-
- test/state_transition/test_state_transition_success_callback.rb
|
169
162
|
- transitions.gemspec
|
170
163
|
homepage: http://github.com/troessner/transitions
|
171
164
|
licenses:
|
@@ -184,11 +177,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
177
|
requirements:
|
185
178
|
- - ">="
|
186
179
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
180
|
+
version: '0'
|
188
181
|
requirements: []
|
189
|
-
rubyforge_project:
|
182
|
+
rubyforge_project:
|
190
183
|
rubygems_version: 2.4.5.1
|
191
184
|
signing_key:
|
192
185
|
specification_version: 4
|
193
186
|
summary: State machine extracted from ActiveModel
|
194
187
|
test_files: []
|
188
|
+
has_rdoc:
|
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
transitions
|
data/MIT-LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
Copyright 2013 jQuery Foundation and other contributors
|
2
|
-
http://jquery.com/
|
3
|
-
|
4
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
a copy of this software and associated documentation files (the
|
6
|
-
"Software"), to deal in the Software without restriction, including
|
7
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be
|
13
|
-
included in all copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,326 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class CreateTrafficLights < ActiveRecord::Migration
|
4
|
-
def self.up
|
5
|
-
create_table(:traffic_lights, force: true) do |t|
|
6
|
-
t.string :state
|
7
|
-
t.string :name
|
8
|
-
t.string :power
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class CreateDifferentTrafficLights < ActiveRecord::Migration
|
14
|
-
def self.up
|
15
|
-
create_table(:different_traffic_lights) do |t|
|
16
|
-
t.string :different_state
|
17
|
-
t.string :name
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class TrafficLight < ActiveRecord::Base
|
23
|
-
include ActiveModel::Transitions
|
24
|
-
|
25
|
-
state_machine auto_scopes: true do
|
26
|
-
state :off, enter: :turn_power_on
|
27
|
-
|
28
|
-
state :red
|
29
|
-
state :green
|
30
|
-
state :yellow
|
31
|
-
|
32
|
-
event :red_on do
|
33
|
-
transitions to: :red, from: [:yellow]
|
34
|
-
end
|
35
|
-
|
36
|
-
event :green_on do
|
37
|
-
transitions to: :green, from: [:red]
|
38
|
-
end
|
39
|
-
|
40
|
-
event :yellow_on do
|
41
|
-
transitions to: :yellow, from: [:green]
|
42
|
-
end
|
43
|
-
|
44
|
-
event :reset do
|
45
|
-
transitions to: :red, from: [:off]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def turn_power_on
|
50
|
-
fail 'the power should not have been on already' if power == 'on'
|
51
|
-
self.power = 'on'
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class ValidatingTrafficLight < TrafficLight
|
56
|
-
validate { |t| errors.add(:base, 'This TrafficLight will never validate after creation') unless t.new_record? }
|
57
|
-
end
|
58
|
-
|
59
|
-
class ConditionalValidatingTrafficLight < TrafficLight
|
60
|
-
validates(:name, presence: true, if: :red?)
|
61
|
-
end
|
62
|
-
|
63
|
-
class TestActiveRecord < Test::Unit::TestCase
|
64
|
-
def setup
|
65
|
-
set_up_db CreateTrafficLights
|
66
|
-
@light = TrafficLight.create!
|
67
|
-
end
|
68
|
-
|
69
|
-
test 'new record has the initial state set' do
|
70
|
-
@light = TrafficLight.new
|
71
|
-
assert_equal 'off', @light.state
|
72
|
-
end
|
73
|
-
|
74
|
-
test 'new active records defaults current state to the initial state' do
|
75
|
-
assert_equal :off, @light.current_state
|
76
|
-
end
|
77
|
-
|
78
|
-
test 'states initial state' do
|
79
|
-
assert @light.off?
|
80
|
-
assert_equal :off, @light.current_state
|
81
|
-
end
|
82
|
-
|
83
|
-
test 'calls enter when setting the initial state' do
|
84
|
-
@new_light = TrafficLight.new
|
85
|
-
assert_equal 'on', @new_light.power
|
86
|
-
end
|
87
|
-
|
88
|
-
test 'does not call enter when loading a persisted record' do
|
89
|
-
assert_equal 'on', @light.power
|
90
|
-
assert_nothing_raised { TrafficLight.find(@light.id) }
|
91
|
-
end
|
92
|
-
|
93
|
-
test 'transition to a valid state' do
|
94
|
-
@light.reset
|
95
|
-
assert @light.red?
|
96
|
-
assert_equal :red, @light.current_state
|
97
|
-
|
98
|
-
@light.green_on
|
99
|
-
assert @light.green?
|
100
|
-
assert_equal :green, @light.current_state
|
101
|
-
end
|
102
|
-
|
103
|
-
test 'transition does not persist state' do
|
104
|
-
@light.reset
|
105
|
-
assert_equal :red, @light.current_state
|
106
|
-
@light.reload
|
107
|
-
assert_equal 'off', @light.state
|
108
|
-
end
|
109
|
-
|
110
|
-
test 'transition does persists state' do
|
111
|
-
@light.reset!
|
112
|
-
assert_equal :red, @light.current_state
|
113
|
-
@light.reload
|
114
|
-
assert_equal 'red', @light.state
|
115
|
-
end
|
116
|
-
|
117
|
-
test 'transition to an invalid state' do
|
118
|
-
assert_raise(Transitions::InvalidTransition) { @light.yellow_on }
|
119
|
-
assert_equal :off, @light.current_state
|
120
|
-
end
|
121
|
-
|
122
|
-
test 'transition with wrong state will not validate' do
|
123
|
-
for s in @light.class.get_state_machine.states
|
124
|
-
@light.state = s.name
|
125
|
-
assert @light.valid?
|
126
|
-
end
|
127
|
-
@light.state = 'invalid_one'
|
128
|
-
assert_false @light.valid?
|
129
|
-
end
|
130
|
-
|
131
|
-
test 'transition raises exception when model validation fails' do
|
132
|
-
validating_light = ValidatingTrafficLight.create!(name: 'Foobar')
|
133
|
-
assert_raise(ActiveRecord::RecordInvalid) do
|
134
|
-
validating_light.reset!
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
test 'state query method used in a validation condition' do
|
139
|
-
validating_light = ConditionalValidatingTrafficLight.create!
|
140
|
-
assert_raise(ActiveRecord::RecordInvalid) do
|
141
|
-
validating_light.reset!
|
142
|
-
end
|
143
|
-
assert(validating_light.off?)
|
144
|
-
end
|
145
|
-
|
146
|
-
test 'reloading model resets current state' do
|
147
|
-
@light.reset
|
148
|
-
assert @light.red?
|
149
|
-
@light.update_attribute(:state, 'green')
|
150
|
-
assert @light.reload.green?, 'reloaded state should come from database, not instance variable'
|
151
|
-
end
|
152
|
-
|
153
|
-
test 'calling non-bang event updates state attribute' do
|
154
|
-
@light.reset!
|
155
|
-
assert @light.red?
|
156
|
-
@light.green_on
|
157
|
-
assert_equal 'green', @light.state
|
158
|
-
assert_equal 'red', @light.reload.state
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
if ActiveRecord::VERSION::MAJOR == 3
|
163
|
-
|
164
|
-
class TestMassAssignmentActiveRecord < Test::Unit::TestCase
|
165
|
-
# attr_protected unfortunately invokes a db call, so this test requires that
|
166
|
-
# we define the class after the table already exists.
|
167
|
-
def setup
|
168
|
-
set_up_db CreateTrafficLights
|
169
|
-
|
170
|
-
@light_with_protected_state = Class.new(TrafficLight) do
|
171
|
-
attr_protected :state
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
test 'transition does persists state when state is protected' do
|
176
|
-
protected_light = @light_with_protected_state.create!
|
177
|
-
protected_light.reset!
|
178
|
-
assert_equal :red, protected_light.current_state
|
179
|
-
protected_light.reload
|
180
|
-
assert_equal 'red', protected_light.state
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
class TestNewActiveRecord < TestActiveRecord
|
186
|
-
def setup
|
187
|
-
set_up_db CreateTrafficLights
|
188
|
-
@light = TrafficLight.new
|
189
|
-
end
|
190
|
-
|
191
|
-
test 'new active records defaults current state to the initial state' do
|
192
|
-
assert_equal :off, @light.current_state
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
class TestScopes < Test::Unit::TestCase
|
197
|
-
test 'scope returns correct object' do
|
198
|
-
@light = TrafficLight.create!
|
199
|
-
assert_respond_to TrafficLight, :off
|
200
|
-
assert_equal TrafficLight.off.first, @light
|
201
|
-
assert TrafficLight.red.empty?
|
202
|
-
end
|
203
|
-
|
204
|
-
test 'scopes exist' do
|
205
|
-
assert_respond_to TrafficLight, :off
|
206
|
-
assert_respond_to TrafficLight, :red
|
207
|
-
assert_respond_to TrafficLight, :green
|
208
|
-
assert_respond_to TrafficLight, :yellow
|
209
|
-
end
|
210
|
-
|
211
|
-
test 'scopes are only generated if we explicitly say so' do
|
212
|
-
assert_not_respond_to LightBulb, :off
|
213
|
-
assert_not_respond_to LightBulb, :on
|
214
|
-
end
|
215
|
-
|
216
|
-
test 'scope generation raises an exception if we try to overwrite an existing method' do
|
217
|
-
assert_raise(Transitions::InvalidMethodOverride) do
|
218
|
-
class Light < ActiveRecord::Base
|
219
|
-
include ActiveModel::Transitions
|
220
|
-
|
221
|
-
state_machine auto_scopes: true do
|
222
|
-
state :new
|
223
|
-
state :broken
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
class DifferentTrafficLight < ActiveRecord::Base
|
231
|
-
include ActiveModel::Transitions
|
232
|
-
|
233
|
-
state_machine attribute_name: :different_state, auto_scopes: true do
|
234
|
-
state :off
|
235
|
-
|
236
|
-
state :red
|
237
|
-
state :green
|
238
|
-
state :yellow
|
239
|
-
|
240
|
-
event :red_on do
|
241
|
-
transitions to: :red, from: [:yellow]
|
242
|
-
end
|
243
|
-
|
244
|
-
event :green_on do
|
245
|
-
transitions to: :green, from: [:red]
|
246
|
-
end
|
247
|
-
|
248
|
-
event :yellow_on do
|
249
|
-
transitions to: :yellow, from: [:green]
|
250
|
-
end
|
251
|
-
|
252
|
-
event :reset do
|
253
|
-
transitions to: :red, from: [:off]
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
class TestActiveRecordWithDifferentColumnName < Test::Unit::TestCase
|
259
|
-
def setup
|
260
|
-
set_up_db CreateDifferentTrafficLights
|
261
|
-
@light = DifferentTrafficLight.create!
|
262
|
-
end
|
263
|
-
|
264
|
-
test 'new record has the initial state set' do
|
265
|
-
@light = DifferentTrafficLight.new
|
266
|
-
assert_equal 'off', @light.different_state
|
267
|
-
end
|
268
|
-
|
269
|
-
test 'states initial state' do
|
270
|
-
assert @light.off?
|
271
|
-
assert_equal :off, @light.current_state
|
272
|
-
end
|
273
|
-
|
274
|
-
test 'transition to a valid state' do
|
275
|
-
@light.reset
|
276
|
-
assert @light.red?
|
277
|
-
assert_equal :red, @light.current_state
|
278
|
-
|
279
|
-
@light.green_on
|
280
|
-
assert @light.green?
|
281
|
-
assert_equal :green, @light.current_state
|
282
|
-
end
|
283
|
-
|
284
|
-
test 'transition does not persist state' do
|
285
|
-
@light.reset
|
286
|
-
assert_equal :red, @light.current_state
|
287
|
-
@light.reload
|
288
|
-
assert_equal 'off', @light.different_state
|
289
|
-
end
|
290
|
-
|
291
|
-
test 'transition does persists state' do
|
292
|
-
@light.reset!
|
293
|
-
assert_equal :red, @light.current_state
|
294
|
-
@light.reload
|
295
|
-
assert_equal 'red', @light.different_state
|
296
|
-
end
|
297
|
-
|
298
|
-
test 'transition to an invalid state' do
|
299
|
-
assert_raise(Transitions::InvalidTransition) { @light.yellow_on }
|
300
|
-
assert_equal :off, @light.current_state
|
301
|
-
end
|
302
|
-
|
303
|
-
test 'transition with wrong state will not validate' do
|
304
|
-
for s in @light.class.state_machine.states
|
305
|
-
@light.different_state = s.name
|
306
|
-
assert @light.valid?
|
307
|
-
end
|
308
|
-
@light.different_state = 'invalid_one'
|
309
|
-
assert_false @light.valid?
|
310
|
-
end
|
311
|
-
|
312
|
-
test 'reloading model resets current state' do
|
313
|
-
@light.reset
|
314
|
-
assert @light.red?
|
315
|
-
@light.update_attribute(:different_state, 'green')
|
316
|
-
assert @light.reload.green?, 'reloaded state should come from database, not instance variable'
|
317
|
-
end
|
318
|
-
|
319
|
-
test 'calling non-bang event updates state attribute' do
|
320
|
-
@light.reset!
|
321
|
-
assert @light.red?
|
322
|
-
@light.green_on
|
323
|
-
assert_equal 'green', @light.different_state
|
324
|
-
assert_equal 'red', @light.reload.different_state
|
325
|
-
end
|
326
|
-
end
|