stator 0.8.0 → 0.9.0.beta

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +10 -5
  3. data/.gitignore +1 -0
  4. data/.ruby-version +1 -1
  5. data/Appraisals +12 -15
  6. data/Gemfile +7 -6
  7. data/README.md +4 -20
  8. data/gemfiles/{activerecord_7.2.gemfile → activerecord_5.1.gemfile} +2 -1
  9. data/gemfiles/activerecord_5.1.gemfile.lock +74 -0
  10. data/gemfiles/{activerecord_8.0.gemfile → activerecord_5.2.gemfile} +2 -1
  11. data/gemfiles/activerecord_5.2.gemfile.lock +74 -0
  12. data/gemfiles/{activerecord_7.1.gemfile → activerecord_5.gemfile} +2 -1
  13. data/gemfiles/activerecord_5.gemfile.lock +74 -0
  14. data/gemfiles/activerecord_6.0.gemfile +2 -2
  15. data/gemfiles/activerecord_6.0.gemfile.lock +41 -69
  16. data/gemfiles/activerecord_6.1.gemfile +2 -2
  17. data/gemfiles/activerecord_6.1.gemfile.lock +41 -68
  18. data/gemfiles/activerecord_7.0.gemfile +2 -2
  19. data/gemfiles/activerecord_7.0.gemfile.lock +40 -66
  20. data/lib/stator/alias.rb +51 -30
  21. data/lib/stator/integration.rb +42 -49
  22. data/lib/stator/machine.rb +59 -58
  23. data/lib/stator/model.rb +78 -73
  24. data/lib/stator/transition.rb +61 -60
  25. data/lib/stator/version.rb +3 -5
  26. data/lib/stator.rb +13 -0
  27. data/spec/model_spec.rb +203 -318
  28. data/spec/spec_helper.rb +6 -2
  29. data/spec/support/models.rb +26 -45
  30. data/spec/support/schema.rb +42 -42
  31. data/stator.gemspec +3 -10
  32. metadata +19 -75
  33. data/.github/CODEOWNERS +0 -1
  34. data/.github/dependabot.yml +0 -24
  35. data/gemfiles/activerecord_7.1.gemfile.lock +0 -114
  36. data/gemfiles/activerecord_7.2.gemfile.lock +0 -113
  37. data/gemfiles/activerecord_8.0.gemfile.lock +0 -116
@@ -1,62 +1,61 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- stator (0.8.0)
5
- activerecord (>= 6.0)
6
- base64
7
- benchmark
8
- bigdecimal
9
- logger
10
- mutex_m
4
+ stator (0.9.0.beta)
5
+ activerecord
6
+ activesupport
11
7
 
12
8
  GEM
13
9
  remote: https://rubygems.org/
14
10
  specs:
15
- activemodel (6.1.7.10)
16
- activesupport (= 6.1.7.10)
17
- activerecord (6.1.7.10)
18
- activemodel (= 6.1.7.10)
19
- activesupport (= 6.1.7.10)
20
- activerecord-nulldb-adapter (1.1.1)
21
- activerecord (>= 6.0, < 8.1)
22
- activesupport (6.1.7.10)
11
+ activemodel (6.1.6.1)
12
+ activesupport (= 6.1.6.1)
13
+ activerecord (6.1.6.1)
14
+ activemodel (= 6.1.6.1)
15
+ activesupport (= 6.1.6.1)
16
+ activerecord-nulldb-adapter (0.8.0)
17
+ activerecord (>= 5.2.0, < 7.1)
18
+ activesupport (6.1.6.1)
23
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
24
20
  i18n (>= 1.6, < 2)
25
21
  minitest (>= 5.1)
26
22
  tzinfo (~> 2.0)
27
23
  zeitwerk (~> 2.3)
28
- appraisal (2.5.0)
24
+ appraisal (2.4.1)
29
25
  bundler
30
26
  rake
31
27
  thor (>= 0.14.0)
32
- base64 (0.2.0)
33
- benchmark (0.4.0)
34
- bigdecimal (3.1.9)
35
- concurrent-ruby (1.3.4)
36
- diff-lcs (1.6.1)
37
- i18n (1.14.7)
28
+ concurrent-ruby (1.1.10)
29
+ debug (1.6.1)
30
+ irb (>= 1.3.6)
31
+ reline (>= 0.3.1)
32
+ diff-lcs (1.5.0)
33
+ i18n (1.12.0)
38
34
  concurrent-ruby (~> 1.0)
39
- logger (1.7.0)
40
- minitest (5.25.5)
41
- mutex_m (0.3.0)
42
- rake (13.2.1)
43
- rspec (3.13.0)
44
- rspec-core (~> 3.13.0)
45
- rspec-expectations (~> 3.13.0)
46
- rspec-mocks (~> 3.13.0)
47
- rspec-core (3.13.3)
48
- rspec-support (~> 3.13.0)
49
- rspec-expectations (3.13.3)
35
+ io-console (0.5.11)
36
+ irb (1.4.1)
37
+ reline (>= 0.3.0)
38
+ minitest (5.16.2)
39
+ rake (13.0.6)
40
+ reline (0.3.1)
41
+ io-console (~> 0.5)
42
+ rspec (3.11.0)
43
+ rspec-core (~> 3.11.0)
44
+ rspec-expectations (~> 3.11.0)
45
+ rspec-mocks (~> 3.11.0)
46
+ rspec-core (3.11.0)
47
+ rspec-support (~> 3.11.0)
48
+ rspec-expectations (3.11.0)
50
49
  diff-lcs (>= 1.2.0, < 2.0)
51
- rspec-support (~> 3.13.0)
52
- rspec-mocks (3.13.2)
50
+ rspec-support (~> 3.11.0)
51
+ rspec-mocks (3.11.1)
53
52
  diff-lcs (>= 1.2.0, < 2.0)
54
- rspec-support (~> 3.13.0)
55
- rspec-support (3.13.2)
56
- thor (1.3.2)
57
- tzinfo (2.0.6)
53
+ rspec-support (~> 3.11.0)
54
+ rspec-support (3.11.0)
55
+ thor (1.2.1)
56
+ tzinfo (2.0.5)
58
57
  concurrent-ruby (~> 1.0)
59
- zeitwerk (2.7.2)
58
+ zeitwerk (2.6.0)
60
59
 
61
60
  PLATFORMS
62
61
  ruby
@@ -65,36 +64,10 @@ DEPENDENCIES
65
64
  activerecord (~> 6.1.0)
66
65
  activerecord-nulldb-adapter
67
66
  appraisal
68
- concurrent-ruby (= 1.3.4)
67
+ debug
69
68
  rake
70
69
  rspec
71
70
  stator!
72
71
 
73
- CHECKSUMS
74
- activemodel (6.1.7.10) sha256=562d9b1d0597f450437ec7cd6540b13f3e074cce5c7b237ac76e7435a15d4b8c
75
- activerecord (6.1.7.10) sha256=db1719ef443a5437badcaa1d0fb5da7db985988fb69cc37085ca6bcc569fb31a
76
- activerecord-nulldb-adapter (1.1.1) sha256=034c91106183b954b072fba14c2786adf1a2b9e852ce04f85f823afaf03e9820
77
- activesupport (6.1.7.10) sha256=3f8e1f787a7bfbf765959ba509ef70af8293b35cb864078919365a12bf33d470
78
- appraisal (2.5.0) sha256=36989221be127913b0dba8d114da2001e6b2dceea7bd4951200eaba764eed3ce
79
- base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
80
- benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a
81
- bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc
82
- concurrent-ruby (1.3.4) sha256=d4aa926339b0a86b5b5054a0a8c580163e6f5dcbdfd0f4bb916b1a2570731c32
83
- diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
84
- i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
85
- logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
86
- minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756
87
- mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
88
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
89
- rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
90
- rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
91
- rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
92
- rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
93
- rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
94
- stator (0.8.0)
95
- thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
96
- tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
97
- zeitwerk (2.7.2) sha256=842e067cb11eb923d747249badfb5fcdc9652d6f20a1f06453317920fdcd4673
98
-
99
72
  BUNDLED WITH
100
- 2.6.7
73
+ 2.3.16
@@ -2,11 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "activerecord", "~> 7.0.0"
5
6
  gem "appraisal"
7
+ gem "debug"
6
8
  gem "activerecord-nulldb-adapter"
7
9
  gem "rake"
8
10
  gem "rspec"
9
- gem "activerecord", "~> 7.0.0"
10
- gem "concurrent-ruby", "1.3.4"
11
11
 
12
12
  gemspec path: "../"
@@ -1,59 +1,58 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- stator (0.8.0)
5
- activerecord (>= 6.0)
6
- base64
7
- benchmark
8
- bigdecimal
9
- logger
10
- mutex_m
4
+ stator (0.9.0.beta)
5
+ activerecord
6
+ activesupport
11
7
 
12
8
  GEM
13
9
  remote: https://rubygems.org/
14
10
  specs:
15
- activemodel (7.0.8.7)
16
- activesupport (= 7.0.8.7)
17
- activerecord (7.0.8.7)
18
- activemodel (= 7.0.8.7)
19
- activesupport (= 7.0.8.7)
20
- activerecord-nulldb-adapter (1.1.1)
21
- activerecord (>= 6.0, < 8.1)
22
- activesupport (7.0.8.7)
11
+ activemodel (7.0.3.1)
12
+ activesupport (= 7.0.3.1)
13
+ activerecord (7.0.3.1)
14
+ activemodel (= 7.0.3.1)
15
+ activesupport (= 7.0.3.1)
16
+ activerecord-nulldb-adapter (0.8.0)
17
+ activerecord (>= 5.2.0, < 7.1)
18
+ activesupport (7.0.3.1)
23
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
24
20
  i18n (>= 1.6, < 2)
25
21
  minitest (>= 5.1)
26
22
  tzinfo (~> 2.0)
27
- appraisal (2.5.0)
23
+ appraisal (2.4.1)
28
24
  bundler
29
25
  rake
30
26
  thor (>= 0.14.0)
31
- base64 (0.2.0)
32
- benchmark (0.4.0)
33
- bigdecimal (3.1.9)
34
- concurrent-ruby (1.3.4)
35
- diff-lcs (1.6.1)
36
- i18n (1.14.7)
27
+ concurrent-ruby (1.1.10)
28
+ debug (1.6.1)
29
+ irb (>= 1.3.6)
30
+ reline (>= 0.3.1)
31
+ diff-lcs (1.5.0)
32
+ i18n (1.12.0)
37
33
  concurrent-ruby (~> 1.0)
38
- logger (1.7.0)
39
- minitest (5.25.5)
40
- mutex_m (0.3.0)
41
- rake (13.2.1)
42
- rspec (3.13.0)
43
- rspec-core (~> 3.13.0)
44
- rspec-expectations (~> 3.13.0)
45
- rspec-mocks (~> 3.13.0)
46
- rspec-core (3.13.3)
47
- rspec-support (~> 3.13.0)
48
- rspec-expectations (3.13.3)
34
+ io-console (0.5.11)
35
+ irb (1.4.1)
36
+ reline (>= 0.3.0)
37
+ minitest (5.16.2)
38
+ rake (13.0.6)
39
+ reline (0.3.1)
40
+ io-console (~> 0.5)
41
+ rspec (3.11.0)
42
+ rspec-core (~> 3.11.0)
43
+ rspec-expectations (~> 3.11.0)
44
+ rspec-mocks (~> 3.11.0)
45
+ rspec-core (3.11.0)
46
+ rspec-support (~> 3.11.0)
47
+ rspec-expectations (3.11.0)
49
48
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.13.0)
51
- rspec-mocks (3.13.2)
49
+ rspec-support (~> 3.11.0)
50
+ rspec-mocks (3.11.1)
52
51
  diff-lcs (>= 1.2.0, < 2.0)
53
- rspec-support (~> 3.13.0)
54
- rspec-support (3.13.2)
55
- thor (1.3.2)
56
- tzinfo (2.0.6)
52
+ rspec-support (~> 3.11.0)
53
+ rspec-support (3.11.0)
54
+ thor (1.2.1)
55
+ tzinfo (2.0.5)
57
56
  concurrent-ruby (~> 1.0)
58
57
 
59
58
  PLATFORMS
@@ -63,35 +62,10 @@ DEPENDENCIES
63
62
  activerecord (~> 7.0.0)
64
63
  activerecord-nulldb-adapter
65
64
  appraisal
66
- concurrent-ruby (= 1.3.4)
65
+ debug
67
66
  rake
68
67
  rspec
69
68
  stator!
70
69
 
71
- CHECKSUMS
72
- activemodel (7.0.8.7) sha256=f13b04bb055c1e85b965ce40b0a2e671b8d97835083597bc7fbc04cde0f40a83
73
- activerecord (7.0.8.7) sha256=f94fc8510e58a18e462c5ee8862c9be75e2bfad0688e8d022b86a6e05df2a45a
74
- activerecord-nulldb-adapter (1.1.1) sha256=034c91106183b954b072fba14c2786adf1a2b9e852ce04f85f823afaf03e9820
75
- activesupport (7.0.8.7) sha256=df4702375de924aae81709c831605317c5417f0bd9e502a0373ff84a067204ff
76
- appraisal (2.5.0) sha256=36989221be127913b0dba8d114da2001e6b2dceea7bd4951200eaba764eed3ce
77
- base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
78
- benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a
79
- bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc
80
- concurrent-ruby (1.3.4) sha256=d4aa926339b0a86b5b5054a0a8c580163e6f5dcbdfd0f4bb916b1a2570731c32
81
- diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
82
- i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
83
- logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
84
- minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756
85
- mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
86
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
87
- rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
88
- rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
89
- rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
90
- rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
91
- rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
92
- stator (0.8.0)
93
- thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
94
- tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
95
-
96
70
  BUNDLED WITH
97
- 2.6.7
71
+ 2.3.16
data/lib/stator/alias.rb CHANGED
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stator
2
4
  class Alias
5
+ attr_reader :machine, :name, :namespace, :attr_name, :states, :not, :opposite_args, :constant, :scope
3
6
 
4
7
  def initialize(machine, name, options = {})
5
8
  @machine = machine
6
9
  @name = name
7
- @namespace = @machine.namespace
8
- @full_name = [@namespace, @name].compact.join('_')
10
+ @namespace = machine.namespace
9
11
  @states = []
10
12
  @not = false
11
13
  @opposite = nil
@@ -13,8 +15,12 @@ module Stator
13
15
  @scope = options[:scope]
14
16
  end
15
17
 
18
+ def attr_name
19
+ @attr_name ||= generate_attr_name
20
+ end
21
+
16
22
  def is(*args)
17
- @states |= args.map(&:to_s)
23
+ @states |= args.map(&:to_sym)
18
24
  end
19
25
 
20
26
  def is_not(*args)
@@ -22,60 +28,75 @@ module Stator
22
28
  is(*args)
23
29
  end
24
30
 
31
+ alias not? not
32
+
25
33
  def opposite(*args)
26
- @opposite = args
34
+ # set the incoming args for opposite as opposite
35
+ @opposite_args = args
27
36
  end
28
37
 
29
38
  def evaluate
30
39
  generate_methods
31
40
 
32
- if @opposite
33
- op = @machine.state_alias(*@opposite)
41
+ return if opposite_args.blank?
34
42
 
35
- op.is(*@states) if @not
36
- op.is_not(*@states) if !@not
37
- end
43
+ # this will generate the alias for the opposite
44
+ op = machine.state_alias(*opposite_args)
45
+
46
+ op.is(*states) if not?
47
+ op.is_not(*states) unless not?
38
48
  end
39
49
 
40
- protected
50
+ private
51
+
52
+ def inverse_states
53
+ (machine.states - states).map(&:to_sym)
54
+ end
41
55
 
42
56
  def inferred_constant_name
43
- [@full_name.upcase, @machine.field.to_s.pluralize.upcase].join('_')
57
+ [attr_name.upcase, machine.field.to_s.pluralize.upcase].join('_')
58
+ end
59
+
60
+ def generate_attr_name
61
+ if namespace == Stator.default_namespace
62
+ name
63
+ else
64
+ [namespace, name].compact.join('_').to_sym
65
+ end
44
66
  end
45
67
 
46
68
  def generate_methods
69
+ expected_states = (not? ? inverse_states : states)
47
70
 
48
- not_states = (@machine.states - @states)
71
+ if scope
72
+ name = (scope == true ? attr_name : scope)
49
73
 
50
- if @scope
51
- name = @scope == true ? @full_name : @scope
52
- @machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
53
- scope #{name.inspect}, lambda {
54
- where(_stator(#{@namespace.inspect}).field => #{(@not ? not_states : @states).inspect})
55
- }
74
+ machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
75
+ scope :#{name}, -> { where(_stator(#{namespace.inspect}).field => #{expected_states}) }
56
76
  EV
57
77
  end
58
78
 
59
- if @constant
60
- name = @constant == true ? inferred_constant_name : @constant.to_s.upcase
61
- if @not
62
- @machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
63
- #{name} = #{not_states.inspect}.freeze
79
+ if constant
80
+ name = (constant == true ? inferred_constant_name : constant.to_s.upcase)
81
+
82
+ if not?
83
+ machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
84
+ #{name} = #{inverse_states}.freeze
64
85
  EV
65
86
  else
66
- @machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
67
- #{name} = #{@states.inspect}.freeze
87
+ machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
88
+ #{name} = #{states}.freeze
68
89
  EV
69
90
  end
70
91
  end
71
92
 
72
- @machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
73
- def #{@full_name}?
74
- integration = _stator(#{@namespace.inspect}).integration(self)
75
- #{(@not ? not_states : @states).inspect}.include?(integration.state)
93
+ machine.klass.class_eval <<-EV, __FILE__, __LINE__ + 1
94
+ def #{attr_name}?
95
+ integration = _stator_integration(:#{namespace})
96
+
97
+ #{expected_states}.include?(integration.state.to_sym)
76
98
  end
77
99
  EV
78
100
  end
79
-
80
101
  end
81
102
  end
@@ -2,48 +2,48 @@
2
2
 
3
3
  module Stator
4
4
  class Integration
5
+ delegate :states, to: :machine
6
+ delegate :transitions, to: :machine
7
+ delegate :namespace, to: :machine
5
8
 
6
- delegate :states, to: :@machine
7
- delegate :transitions, to: :@machine
8
- delegate :namespace, to: :@machine
9
-
10
- attr_reader :skip_validations
11
- attr_reader :skip_transition_tracking
9
+ attr_reader :skip_validations, :skip_transition_tracking, :record, :machine
12
10
 
13
11
  def initialize(machine, record)
14
12
  @machine = machine
15
13
  @record = record
14
+ @skip_transition_tracking = false
16
15
  end
17
16
 
18
17
  def state=(new_value)
19
- @record.send("#{@machine.field}=", new_value)
18
+ record.send("#{machine.field}=", new_value)
20
19
  end
21
20
 
22
21
  def state
23
- @record.send(@machine.field)
22
+ record.send(machine.field)&.to_sym
24
23
  end
25
24
 
26
25
  def state_was(use_previous = false)
27
26
  if use_previous
28
- @record.attribute_before_last_save(@machine.field)
27
+ record.previous_changes[machine.field].try(:[], 0).to_sym
29
28
  else
30
- @record.attribute_in_database(@machine.field)
29
+ record.send("#{@machine.field}_was")
31
30
  end
32
31
  end
33
32
 
34
33
  def state_by?(state, time)
35
- field_name = "#{state}_#{@machine.field}_at"
36
- return false unless @record.respond_to?(field_name)
37
- return false if @record.send(field_name).nil?
34
+ field_name = "#{state}_#{machine.field}_at"
35
+ return false unless record.respond_to?(field_name)
36
+ return false if record.send(field_name).nil?
38
37
  return true if time.nil?
39
- @record.send(field_name) <= time
38
+
39
+ record.send(field_name) <= time
40
40
  end
41
41
 
42
42
  def state_changed?(use_previous = false)
43
43
  if use_previous
44
- @record.saved_change_to_attribute?(@machine.field)
44
+ !!record.previous_changes[machine.field.to_s]
45
45
  else
46
- @record.will_save_change_to_attribute?(@machine.field)
46
+ record.send("#{machine.field}_changed?")
47
47
  end
48
48
  end
49
49
 
@@ -51,23 +51,20 @@ module Stator
51
51
  return unless state_changed?
52
52
  return if skip_validations
53
53
 
54
- was = state_was
55
- is = state
56
-
57
- if @record.new_record?
58
- invalid_state! unless @machine.matching_transition(::Stator::Transition::ANY, is)
54
+ if record.new_record?
55
+ invalid_state! unless machine.matching_transition(Stator::ANY, state)
59
56
  else
60
- invalid_transition!(was, is) unless @machine.matching_transition(was, is)
57
+ invalid_transition!(state_was, state) unless machine.matching_transition(state_was, state)
61
58
  end
62
59
  end
63
60
 
64
61
  # TODO: i18n
65
62
  def invalid_state!
66
- @record.errors.add(@machine.field, "is not a valid state")
63
+ record.errors.add(machine.field, 'is not a valid state')
67
64
  end
68
65
 
69
66
  def invalid_transition!(was, is)
70
- @record.errors.add(@machine.field, "cannot transition to #{is.inspect} from #{was.inspect}")
67
+ record.errors.add(machine.field, "cannot transition to #{is} from #{was}")
71
68
  end
72
69
 
73
70
  def track_transition
@@ -83,7 +80,7 @@ module Stator
83
80
  state = state.to_s
84
81
  t = t.to_time
85
82
 
86
- state_at = @record.send("#{state}_#{@machine.field}_at")
83
+ state_at = record.send("#{state}_#{machine.field}_at")
87
84
 
88
85
  # if we've never been in the state, the answer is no
89
86
  return false if state_at.nil?
@@ -91,20 +88,18 @@ module Stator
91
88
  # if we came into this state later in life, the answer is no
92
89
  return false if state_at > t
93
90
 
94
- all_states = @machine.states.reverse
91
+ all_states = machine.states.reverse
95
92
 
96
93
  # grab all the states and their timestamps that occur on or after state_at and on or before the time in question
97
- later_states = all_states.map do |s|
94
+ later_states = all_states.filter_map do |s|
98
95
  next if state == s
99
96
 
100
- at = @record.send("#{s}_#{@machine.field}_at")
97
+ at = record.send("#{s}_#{machine.field}_at")
101
98
 
102
- next if at.nil?
103
- next if at < state_at
104
- next if at > t
99
+ next if at.nil? || at < state_at || at > t
105
100
 
106
101
  { state: s, at: at }
107
- end.compact
102
+ end
108
103
 
109
104
  # if there were no states on or after the state_at, the answer is yes
110
105
  return true if later_states.empty?
@@ -115,53 +110,51 @@ module Stator
115
110
  later_states = later_groups[later_group_key]
116
111
 
117
112
  # if the lowest timestamp is the same as the state's timestamp, evaluate based on state index
118
- if later_states[0][:at] == state_at
119
- return all_states.index(state) < all_states.index(later_states[0][:state])
120
- end
113
+ return all_states.index(state) < all_states.index(later_states[0][:state]) if later_states[0][:at] == state_at
121
114
 
122
115
  false
123
116
  end
124
117
 
125
118
  def likely_state_at(t)
126
- @machine.states.reverse.detect { |s| in_state_at?(s, t) }
119
+ machine.states.reverse.detect { |s| in_state_at?(s, t) }
127
120
  end
128
121
 
129
122
  def without_validation
130
- was = @skip_validations
123
+ was = skip_validations
131
124
  @skip_validations = true
132
- yield @record
125
+ yield record
133
126
  ensure
134
127
  @skip_validations = was
135
128
  end
136
129
 
137
130
  def without_transition_tracking
138
- was = @skip_transition_tracking
131
+ was = skip_transition_tracking
139
132
  @skip_transition_tracking = true
140
- yield @record
133
+ yield record
141
134
  ensure
142
135
  @skip_transition_tracking = was
143
136
  end
144
137
 
145
- protected
138
+ private
146
139
 
147
140
  def attempt_to_track_state(state_to_track)
148
141
  return unless state_to_track
149
142
 
150
- _attempt_to_track_change("#{state_to_track}_#{@machine.field}_at")
143
+ _attempt_to_track_change("#{state_to_track}_#{machine.field}_at")
151
144
  end
152
145
 
153
146
  def attempt_to_track_state_changed_timestamp
154
- _attempt_to_track_change("#{@machine.field}_changed_at")
147
+ _attempt_to_track_change("#{machine.field}_changed_at")
155
148
  end
156
149
 
157
150
  def _attempt_to_track_change(field_name)
158
- return unless @record.respond_to?(field_name)
159
- return unless @record.respond_to?("#{field_name}=")
160
- return unless @record.send(field_name.to_s).nil? || state_changed?
161
- return if @record.will_save_change_to_attribute?(field_name)
151
+ return unless record.respond_to?(field_name)
152
+ return unless record.respond_to?("#{field_name}=")
153
+ return unless record.send(field_name.to_s).nil? || state_changed?
162
154
 
163
- @record.send("#{field_name}=", (Time.zone || Time).now)
164
- end
155
+ return if record.send("#{field_name}_changed?")
165
156
 
157
+ record.send("#{field_name}=", (Time.zone || Time).now)
158
+ end
166
159
  end
167
160
  end