can_has_state 0.8.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b2d2008ba870961e06cebe22f027b133b46c5f078315938c9338edfd99678f5
4
- data.tar.gz: 2d4e7dbfd0bb896e01dfdaf66933b3b483f71915579f5d66d42fde1cbd0416de
3
+ metadata.gz: c5f5601e8f5a886f204c95bfab44e0f2331d48d1ddf1593915518a4506176731
4
+ data.tar.gz: 7dfb7c2a3f9601bbe495010f116051ebd5731f5425725204e1ff4c5aa7e3413b
5
5
  SHA512:
6
- metadata.gz: 9e18bb675dd1acc0b84bb8539f67ca9c483f7ff618927b9baef5cdc738ba7a723cac0cccbaed68dfd0291925a2af5a8cda4ebf22b250ead0d39d813e389ecd86
7
- data.tar.gz: 2cc03d656532de9061758242d7daaab074f979665323a071d432b1c220e050951da7750ca6f38c5ef1c8e1e4633f76ce16bd8f404fbe9e5e31ba8fe0a6426f17
6
+ metadata.gz: aa57e7f886fd54770f5b1031ff139346b616d7cc9445752fa20638c98b00530457f182973535710cf4db5effdebfd5bc4fb516fce195c7f84d0cca2ab8955b1a
7
+ data.tar.gz: 41adfafeecb3729facfa0f5a293219ca524382d2245af981674045d1a62a83482b78e371b0df89ff01fabeecb14a1c3a9c82337919d07aa9be1e6f7ea7feaeee
@@ -1,4 +1,4 @@
1
- Copyright 2012-2023 thomas morgan
1
+ Copyright 2012-2024 thomas morgan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -92,11 +92,7 @@ module CanHasState
92
92
  # copy that won't be reset.
93
93
 
94
94
  state_machines.each do |column, sm|
95
- if respond_to?("#{column}_before_last_save") # rails 5.1+
96
- from, to = send("#{column}_before_last_save"), send(column)
97
- else
98
- from, to = send("#{column}_was"), send(column)
99
- end
95
+ from, to = send("#{column}_before_last_save"), send(column)
100
96
  next if from == to
101
97
 
102
98
  tg[column] ||= []
@@ -111,23 +107,23 @@ module CanHasState
111
107
  end
112
108
  end
113
109
 
114
- def can_has_state_errors
115
- err = {}
110
+ def can_has_state_errors(reset: true)
111
+ @can_has_state_errors = {} if reset || !@can_has_state_errors
116
112
  state_machines.each do |column, sm|
117
113
  from, to = send("#{column}_was"), send(column)
118
114
  if !sm.known?(to)
119
- err[column] = [:invalid_state]
115
+ @can_has_state_errors[column] = [:invalid_state]
120
116
  elsif from == to
121
117
  next
122
118
  elsif !sm.allow?(self, to) #state_machine_allow?(column, to)
123
- err[column] = [sm.message(to), {from: "'#{from}'", to: "'#{to}'"}]
119
+ @can_has_state_errors[column] = [sm.message(to), {from: "'#{from}'", to: "'#{to}'"}]
124
120
  end
125
121
  end
126
- err
122
+ @can_has_state_errors
127
123
  end
128
124
 
129
125
  def validate_state_machines
130
- can_has_state_errors.each do |column, (msg, opts)|
126
+ can_has_state_errors(reset: false).each do |column, (msg, opts)|
131
127
  errors.add column, msg, **(opts||{})
132
128
  end
133
129
  end
@@ -1,3 +1,3 @@
1
1
  module CanHasState
2
- VERSION = '0.8.0'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -406,6 +406,74 @@ class CanHasStateTest < Minitest::Test
406
406
  end
407
407
 
408
408
 
409
+ def test_errors_resolved_in_later_callback_are_kept
410
+ # Triggers are skipped when the state_machine has validation errors.
411
+ # Whether or not to skip is decided in an early before_validation callback.
412
+ # Even if a later callback resolves the validation error, it's important to
413
+ # still bubble up the errors since triggers did not run.
414
+ kl = build_from_skeleton do
415
+ attr_accessor :have_beans, :coffee_in_hand
416
+ extend_state_machine :state do
417
+ state :incredible,
418
+ require: proc{ coffee_in_hand > 0 }
419
+ end
420
+ before_validation { self.coffee_in_hand += 1 if have_beans }
421
+ def initialize
422
+ @coffee_in_hand = 0
423
+ end
424
+ end
425
+ m = kl.new
426
+ m.state = 'incredible'
427
+ refute m.valid?
428
+ assert m.errors.of_kind?(:state, :invalid_transition)
429
+ assert_equal 0, m.coffee_in_hand
430
+
431
+ m = kl.new
432
+ m.have_beans = true
433
+ m.state = 'incredible'
434
+ refute m.valid?
435
+ assert m.errors.of_kind?(:state, :invalid_transition)
436
+ assert_equal 1, m.coffee_in_hand
437
+ end
438
+
439
+ def test_rerunning_triggers_clears_pre_callback_errors
440
+ # To resolve the issue above, it is possible to re-eval the state_machine
441
+ # and run triggers if validations now pass. This is highly discouraged as
442
+ # complex callback callback interactions like this should be refactored out
443
+ # if at all possible.
444
+ # Not an officially supported solution and subject to change, but
445
+ # documented here to show that it is (presently) possible.
446
+ kl = build_from_skeleton do
447
+ attr_accessor :have_beans, :coffee_in_hand, :we_are_incredible
448
+ extend_state_machine :state do
449
+ state :incredible,
450
+ require: proc{ coffee_in_hand > 0 },
451
+ on_enter: proc{ self.we_are_incredible = true }
452
+ end
453
+ before_validation do
454
+ self.coffee_in_hand += 1 if have_beans
455
+ run_state_triggers
456
+ end
457
+ def initialize
458
+ @coffee_in_hand = 0
459
+ end
460
+ end
461
+ m = kl.new
462
+ m.state = 'incredible'
463
+ refute m.valid?
464
+ assert m.errors.of_kind?(:state, :invalid_transition)
465
+ assert_equal 0, m.coffee_in_hand
466
+ refute m.we_are_incredible
467
+
468
+ m = kl.new
469
+ m.have_beans = true
470
+ m.state = 'incredible'
471
+ assert m.valid?
472
+ assert_equal 1, m.coffee_in_hand
473
+ assert m.we_are_incredible
474
+ end
475
+
476
+
409
477
 
410
478
  def build_from_skeleton(&block)
411
479
  Class.new(Skeleton).tap do |kl|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: can_has_state
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thomas morgan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-25 00:00:00.000000000 Z
11
+ date: 2024-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '7.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7.2'
22
+ version: '8.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '6.0'
29
+ version: '7.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7.2'
32
+ version: '8.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: minitest
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,7 @@ executables: []
81
81
  extensions: []
82
82
  extra_rdoc_files: []
83
83
  files:
84
- - MIT-LICENSE
84
+ - LICENSE.txt
85
85
  - README.md
86
86
  - Rakefile
87
87
  - lib/can_has_state.rb
@@ -116,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  requirements: []
119
- rubygems_version: 3.3.26
119
+ rubygems_version: 3.5.11
120
120
  signing_key:
121
121
  specification_version: 4
122
122
  summary: Super simple state machine for ActiveModel