state_machines-activerecord 0.9.0 → 0.31.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +10 -2
  4. data/lib/state_machines/integrations/active_record/locale.rb +12 -9
  5. data/lib/state_machines/integrations/active_record/version.rb +3 -1
  6. data/lib/state_machines/integrations/active_record.rb +59 -102
  7. data/lib/state_machines-activerecord.rb +2 -0
  8. metadata +36 -142
  9. data/test/files/en.yml +0 -5
  10. data/test/files/models/post.rb +0 -11
  11. data/test/integration_test.rb +0 -25
  12. data/test/machine_by_default_test.rb +0 -16
  13. data/test/machine_errors_test.rb +0 -19
  14. data/test/machine_multiple_test.rb +0 -17
  15. data/test/machine_nested_action_test.rb +0 -38
  16. data/test/machine_unmigrated_test.rb +0 -14
  17. data/test/machine_with_aliased_attribute_test.rb +0 -23
  18. data/test/machine_with_callbacks_test.rb +0 -172
  19. data/test/machine_with_column_state_attribute_test.rb +0 -44
  20. data/test/machine_with_complex_pluralization_scopes_test.rb +0 -16
  21. data/test/machine_with_conflicting_predicate_test.rb +0 -18
  22. data/test/machine_with_conflicting_state_name_test.rb +0 -29
  23. data/test/machine_with_custom_attribute_test.rb +0 -21
  24. data/test/machine_with_default_scope_test.rb +0 -18
  25. data/test/machine_with_different_column_default_test.rb +0 -27
  26. data/test/machine_with_different_integer_column_default_test.rb +0 -29
  27. data/test/machine_with_dirty_attribute_and_custom_attributes_during_loopback_test.rb +0 -24
  28. data/test/machine_with_dirty_attribute_and_state_events_test.rb +0 -20
  29. data/test/machine_with_dirty_attributes_and_custom_attribute_test.rb +0 -32
  30. data/test/machine_with_dirty_attributes_during_loopback_test.rb +0 -22
  31. data/test/machine_with_dirty_attributes_test.rb +0 -35
  32. data/test/machine_with_dynamic_initial_state_test.rb +0 -99
  33. data/test/machine_with_event_attributes_on_autosave_test.rb +0 -48
  34. data/test/machine_with_event_attributes_on_custom_action_test.rb +0 -41
  35. data/test/machine_with_event_attributes_on_save_bang_test.rb +0 -82
  36. data/test/machine_with_event_attributes_on_save_test.rb +0 -244
  37. data/test/machine_with_event_attributes_on_validation_test.rb +0 -143
  38. data/test/machine_with_events_test.rb +0 -13
  39. data/test/machine_with_failed_action_test.rb +0 -40
  40. data/test/machine_with_failed_after_callbacks_test.rb +0 -35
  41. data/test/machine_with_failed_before_callbacks_test.rb +0 -36
  42. data/test/machine_with_initialized_state_test.rb +0 -41
  43. data/test/machine_with_internationalization_test.rb +0 -180
  44. data/test/machine_with_loopback_test.rb +0 -22
  45. data/test/machine_with_non_column_state_attribute_defined_test.rb +0 -29
  46. data/test/machine_with_same_column_default_test.rb +0 -26
  47. data/test/machine_with_same_integer_column_default_test.rb +0 -30
  48. data/test/machine_with_scopes_and_joins_test.rb +0 -38
  49. data/test/machine_with_scopes_and_owner_subclass_test.rb +0 -27
  50. data/test/machine_with_scopes_test.rb +0 -70
  51. data/test/machine_with_state_driven_validations_test.rb +0 -30
  52. data/test/machine_with_states_test.rb +0 -13
  53. data/test/machine_with_static_initial_state_test.rb +0 -167
  54. data/test/machine_with_transactions_test.rb +0 -26
  55. data/test/machine_with_validations_and_custom_attribute_test.rb +0 -21
  56. data/test/machine_with_validations_test.rb +0 -47
  57. data/test/machine_without_database_test.rb +0 -20
  58. data/test/machine_without_transactions_test.rb +0 -26
  59. data/test/model_test.rb +0 -12
  60. data/test/test_helper.rb +0 -58
@@ -1,11 +0,0 @@
1
- ActiveRecord::Base.connection.create_table(:posts, :force => true) do |t|
2
- t.string :title
3
- t.string :content
4
- t.string :state
5
- end
6
-
7
- class Post < ActiveRecord::Base
8
- state_machine initial: :draft do
9
-
10
- end
11
- end
@@ -1,25 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class IntegrationTest < BaseTestCase
4
- def test_should_have_an_integration_name
5
- assert_equal :active_record, StateMachines::Integrations::ActiveRecord.integration_name
6
- end
7
-
8
- def test_should_be_before_activemodel
9
- integrations = StateMachines::Integrations.list.to_a
10
- assert StateMachines::Integrations::ActiveRecord, integrations.first
11
- assert StateMachines::Integrations::ActiveModel, integrations.last
12
- end
13
-
14
- def test_should_match_if_class_inherits_from_active_record
15
- assert StateMachines::Integrations::ActiveRecord.matches?(new_model)
16
- end
17
-
18
- def test_should_not_match_if_class_does_not_inherit_from_active_record
19
- refute StateMachines::Integrations::ActiveRecord.matches?(Class.new)
20
- end
21
-
22
- def test_should_have_defaults
23
- assert_equal({action: :save, use_transactions: true}, StateMachines::Integrations::ActiveRecord.defaults)
24
- end
25
- end
@@ -1,16 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineByDefaultTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model)
7
- end
8
-
9
- def test_should_use_save_as_action
10
- assert_equal :save, @machine.action
11
- end
12
-
13
- def test_should_use_transactions
14
- assert_equal true, @machine.use_transactions
15
- end
16
- end
@@ -1,19 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineErrorsTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model)
7
- @record = @model.new
8
- end
9
-
10
- def test_should_be_able_to_describe_current_errors
11
- @record.errors.add(:id, 'cannot be blank')
12
- @record.errors.add(:state, 'is invalid')
13
- assert_equal ['Id cannot be blank', 'State is invalid'], @machine.errors_for(@record).split(', ').sort
14
- end
15
-
16
- def test_should_describe_as_halted_with_no_errors
17
- assert_equal 'Transition halted', @machine.errors_for(@record)
18
- end
19
- end
@@ -1,17 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineMultipleTest < BaseTestCase
4
- def setup
5
- @model = new_model do
6
- connection.add_column table_name, :status, :string
7
- end
8
- @state_machine = StateMachines::Machine.new(@model, :initial => :parked)
9
- @status_machine = StateMachines::Machine.new(@model, :status, :initial => :idling)
10
- end
11
-
12
- def test_should_should_initialize_each_state
13
- record = @model.new
14
- assert_equal 'parked', record.state
15
- assert_equal 'idling', record.status
16
- end
17
- end
@@ -1,38 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineNestedActionTest < BaseTestCase
4
- def setup
5
- @callbacks = []
6
-
7
- @model = new_model
8
- @machine = StateMachines::Machine.new(@model)
9
- @machine.event :ignite do
10
- transition :parked => :idling
11
- end
12
-
13
- @record = @model.new(:state => 'parked')
14
- end
15
-
16
- def test_should_allow_transition_prior_to_creation_if_skipping_action
17
- record = @record
18
- @model.before_create { record.ignite(false) }
19
- result = @record.save
20
-
21
- assert_equal true, result
22
- assert_equal "idling", @record.state
23
- @record.reload
24
- assert_equal "idling", @record.state
25
- end
26
-
27
- def test_should_allow_transition_after_creation
28
- record = @record
29
- @model.after_create { record.ignite }
30
- result = @record.save
31
-
32
- assert_equal true, result
33
- assert_equal "idling", @record.state
34
- @record.reload
35
- assert_equal "idling", @record.state
36
- end
37
- end
38
-
@@ -1,14 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineUnmigratedTest < BaseTestCase
4
- def setup
5
- @model = new_model(false)
6
-
7
- # Drop the table so that it definitely doesn't exist
8
- @model.connection.drop_table(@model.table_name) if @model.table_exists?
9
- end
10
-
11
- def test_should_allow_machine_creation
12
- assert_nothing_raised { StateMachines::Machine.new(@model) }
13
- end
14
- end
@@ -1,23 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithAliasedAttributeTest < BaseTestCase
4
- def setup
5
- @model = new_model do
6
- alias_attribute :vehicle_status, :state
7
- end
8
-
9
- @machine = StateMachines::Machine.new(@model, :status, :attribute => :vehicle_status)
10
- @machine.state :parked
11
-
12
- @record = @model.new
13
- end
14
-
15
- def test_should_check_custom_attribute_for_predicate
16
- @record.vehicle_status = nil
17
- refute @record.status?(:parked)
18
-
19
- @record.vehicle_status = 'parked'
20
- assert @record.status?(:parked)
21
- end
22
- end
23
-
@@ -1,172 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithCallbacksTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :initial => :parked)
7
- @machine.other_states :idling
8
- @machine.event :ignite
9
-
10
- @record = @model.new(:state => 'parked')
11
- @transition = StateMachines::Transition.new(@record, @machine, :ignite, :parked, :idling)
12
- end
13
-
14
- def test_should_run_before_callbacks
15
- called = false
16
- @machine.before_transition { called = true }
17
-
18
- @transition.perform
19
- assert called
20
- end
21
-
22
- def test_should_pass_record_to_before_callbacks_with_one_argument
23
- record = nil
24
- @machine.before_transition { |arg| record = arg }
25
-
26
- @transition.perform
27
- assert_equal @record, record
28
- end
29
-
30
- def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
31
- callback_args = nil
32
- @machine.before_transition { |*args| callback_args = args }
33
-
34
- @transition.perform
35
- assert_equal [@record, @transition], callback_args
36
- end
37
-
38
- def test_should_run_before_callbacks_outside_the_context_of_the_record
39
- context = nil
40
- @machine.before_transition { context = self }
41
-
42
- @transition.perform
43
- assert_equal self, context
44
- end
45
-
46
- def test_should_run_after_callbacks
47
- called = false
48
- @machine.after_transition { called = true }
49
-
50
- @transition.perform
51
- assert called
52
- end
53
-
54
- def test_should_pass_record_to_after_callbacks_with_one_argument
55
- record = nil
56
- @machine.after_transition { |arg| record = arg }
57
-
58
- @transition.perform
59
- assert_equal @record, record
60
- end
61
-
62
- def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
63
- callback_args = nil
64
- @machine.after_transition { |*args| callback_args = args }
65
-
66
- @transition.perform
67
- assert_equal [@record, @transition], callback_args
68
- end
69
-
70
- def test_should_run_after_callbacks_outside_the_context_of_the_record
71
- context = nil
72
- @machine.after_transition { context = self }
73
-
74
- @transition.perform
75
- assert_equal self, context
76
- end
77
-
78
- def test_should_run_after_callbacks_if_model_callback_added_prior_to_state_machine_definition
79
- model = new_model do
80
- after_save { nil }
81
- end
82
- machine = StateMachines::Machine.new(model, :initial => :parked)
83
- machine.other_states :idling
84
- machine.event :ignite
85
- after_called = false
86
- machine.after_transition { after_called = true }
87
-
88
- record = model.new(:state => 'parked')
89
- transition = StateMachines::Transition.new(record, machine, :ignite, :parked, :idling)
90
- transition.perform
91
- assert_equal true, after_called
92
- end
93
-
94
- def test_should_run_around_callbacks
95
- before_called = false
96
- after_called = false
97
- ensure_called = 0
98
- @machine.around_transition do |block|
99
- before_called = true
100
- begin
101
- block.call
102
- ensure
103
- ensure_called += 1
104
- end
105
- after_called = true
106
- end
107
-
108
- @transition.perform
109
- assert before_called
110
- assert after_called
111
- assert_equal ensure_called, 1
112
- end
113
-
114
- def test_should_include_transition_states_in_known_states
115
- @machine.before_transition :to => :first_gear, :do => lambda {}
116
-
117
- assert_equal [:parked, :idling, :first_gear], @machine.states.map { |state| state.name }
118
- end
119
-
120
- def test_should_allow_symbolic_callbacks
121
- callback_args = nil
122
-
123
- klass = class << @record;
124
- self;
125
- end
126
- klass.send(:define_method, :after_ignite) do |*args|
127
- callback_args = args
128
- end
129
-
130
- @machine.before_transition(:after_ignite)
131
-
132
- @transition.perform
133
- assert_equal [@transition], callback_args
134
- end
135
-
136
- def test_should_allow_string_callbacks
137
- class << @record
138
- attr_reader :callback_result
139
- end
140
-
141
- @machine.before_transition('@callback_result = [1, 2, 3]')
142
- @transition.perform
143
-
144
- assert_equal [1, 2, 3], @record.callback_result
145
- end
146
-
147
- def test_should_run_in_expected_order
148
- expected = [
149
- :before_transition, :before_validation, :after_validation,
150
- :before_save, :before_create, :after_create, :after_save,
151
- :after_transition
152
- ]
153
-
154
- callbacks = []
155
- @model.before_validation { callbacks << :before_validation }
156
- @model.after_validation { callbacks << :after_validation }
157
- @model.before_save { callbacks << :before_save }
158
- @model.before_create { callbacks << :before_create }
159
- @model.after_create { callbacks << :after_create }
160
- @model.after_save { callbacks << :after_save }
161
- @model.after_commit { callbacks << :after_commit }
162
- expected << :after_commit
163
-
164
- @machine.before_transition { callbacks << :before_transition }
165
- @machine.after_transition { callbacks << :after_transition }
166
-
167
- @transition.perform
168
-
169
- assert_equal expected, callbacks
170
- end
171
- end
172
-
@@ -1,44 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithColumnStateAttributeTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :initial => :parked)
7
- @machine.other_states(:idling)
8
-
9
- @record = @model.new
10
- end
11
-
12
- def test_should_not_override_the_column_reader
13
- @record[:state] = 'parked'
14
- assert_equal 'parked', @record.state
15
- end
16
-
17
- def test_should_not_override_the_column_writer
18
- @record.state = 'parked'
19
- assert_equal 'parked', @record[:state]
20
- end
21
-
22
- def test_should_have_an_attribute_predicate
23
- assert @record.respond_to?(:state?)
24
- end
25
-
26
- def test_should_test_for_existence_on_predicate_without_parameters
27
- assert @record.state?
28
-
29
- @record.state = nil
30
- refute @record.state?
31
- end
32
-
33
- def test_should_return_false_for_predicate_if_does_not_match_current_value
34
- refute @record.state?(:idling)
35
- end
36
-
37
- def test_should_return_true_for_predicate_if_matches_current_value
38
- assert @record.state?(:parked)
39
- end
40
-
41
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
42
- assert_raises(IndexError) { @record.state?(:invalid) }
43
- end
44
- end
@@ -1,16 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithComplexPluralizationScopesTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :status)
7
- end
8
-
9
- def test_should_create_singular_with_scope
10
- assert @model.respond_to?(:with_status)
11
- end
12
-
13
- def test_should_create_plural_with_scope
14
- assert @model.respond_to?(:with_statuses)
15
- end
16
- end
@@ -1,18 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithConflictingPredicateTest < BaseTestCase
4
- def setup
5
- @model = new_model do
6
- def state?(*args)
7
- true
8
- end
9
- end
10
-
11
- @machine = StateMachines::Machine.new(@model)
12
- @record = @model.new
13
- end
14
-
15
- def test_should_not_define_attribute_predicate
16
- assert @record.state?
17
- end
18
- end
@@ -1,29 +0,0 @@
1
- require_relative 'test_helper'
2
- require 'stringio'
3
-
4
- class MachineWithConflictingStateNameTest < BaseTestCase
5
- def setup
6
- @original_stderr, $stderr = $stderr, StringIO.new
7
-
8
- @model = new_model
9
- end
10
-
11
- def test_should_output_warning_with_same_machine_name
12
- @machine = StateMachines::Machine.new(@model)
13
- @machine.state :state
14
-
15
- assert_match(/^Instance method "state\?" is already defined in Foo, use generic helper instead.*\n$/, $stderr.string)
16
- end
17
-
18
- def test_should_output_warning_with_same_machine_attribute
19
- @machine = StateMachines::Machine.new(@model, :public_state, :attribute => :state)
20
- @machine.state :state
21
-
22
- assert_match(/^Instance method "state\?" is already defined in Foo, use generic helper instead.*\n$/, $stderr.string)
23
- end
24
-
25
- def teardown
26
- $stderr = @original_stderr
27
- super
28
- end
29
- end
@@ -1,21 +0,0 @@
1
- require_relative 'test_helper'
2
- require 'stringio'
3
-
4
- class MachineWithCustomAttributeTest < BaseTestCase
5
- def setup
6
- @original_stderr, $stderr = $stderr, StringIO.new
7
-
8
- @model = new_model
9
- @machine = StateMachines::Machine.new(@model, :public_state, :attribute => :state)
10
- @record = @model.new
11
- end
12
-
13
- def test_should_not_delegate_attribute_predicate_with_different_attribute
14
- assert_raise(ArgumentError) { @record.public_state? }
15
- end
16
-
17
- def teardown
18
- $stderr = @original_stderr
19
- super
20
- end
21
- end
@@ -1,18 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithDefaultScopeTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :initial => :parked)
7
- @machine.state :idling
8
-
9
- @model.class_eval do
10
- default_scope { with_state(:parked, :idling) }
11
- end
12
- end
13
-
14
- def test_should_set_initial_state_on_created_object
15
- object = @model.new
16
- assert_equal 'parked', object.state
17
- end
18
- end
@@ -1,27 +0,0 @@
1
- require_relative 'test_helper'
2
- require 'stringio'
3
-
4
- class MachineWithDifferentColumnDefaultTest < BaseTestCase
5
- def setup
6
- @original_stderr, $stderr = $stderr, StringIO.new
7
-
8
- @model = new_model do
9
- connection.add_column table_name, :status, :string, :default => 'idling'
10
- end
11
- @machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
12
- @record = @model.new
13
- end
14
-
15
- def test_should_use_machine_default
16
- assert_equal 'parked', @record.status
17
- end
18
-
19
- def test_should_generate_a_warning
20
- assert_match(/Both Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
21
- end
22
-
23
- def teardown
24
- $stderr = @original_stderr
25
- super
26
- end
27
- end
@@ -1,29 +0,0 @@
1
- require_relative 'test_helper'
2
- require 'stringio'
3
-
4
- class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
5
- def setup
6
- @original_stderr, $stderr = $stderr, StringIO.new
7
-
8
- @model = new_model do
9
- connection.add_column table_name, :status, :integer, :default => 0
10
- end
11
- @machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
12
- @machine.state :parked, :value => 1
13
- @record = @model.new
14
- end
15
-
16
- def test_should_use_machine_default
17
- assert_equal 1, @record.status
18
- end
19
-
20
- def test_should_generate_a_warning
21
- assert_match(/Both Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
22
- end
23
-
24
- def teardown
25
- $stderr = @original_stderr
26
- super
27
- end
28
- end
29
-
@@ -1,24 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
4
- def setup
5
- @model = new_model do
6
- connection.add_column table_name, :status, :string
7
- end
8
- @machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
9
- @machine.event :park
10
-
11
- @record = @model.create
12
-
13
- @transition = StateMachines::Transition.new(@record, @machine, :park, :parked, :parked)
14
- @transition.perform(false)
15
- end
16
-
17
- def test_should_not_include_state_in_changed_attributes
18
- assert_equal [], @record.changed
19
- end
20
-
21
- def test_should_not_track_attribute_changes
22
- assert_nil @record.changes['status']
23
- end
24
- end
@@ -1,20 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :initial => :parked)
7
- @machine.event :ignite
8
-
9
- @record = @model.create
10
- @record.state_event = 'ignite'
11
- end
12
-
13
- def test_should_not_include_state_in_changed_attributes
14
- assert_equal [], @record.changed
15
- end
16
-
17
- def test_should_not_track_attribute_change
18
- assert_nil @record.changes['state']
19
- end
20
- end
@@ -1,32 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
4
- def setup
5
- @model = new_model do
6
- connection.add_column table_name, :status, :string
7
- end
8
- @machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
9
- @machine.event :ignite
10
- @machine.state :idling
11
-
12
- @record = @model.create
13
-
14
- @transition = StateMachines::Transition.new(@record, @machine, :ignite, :parked, :idling)
15
- @transition.perform(false)
16
- end
17
-
18
- def test_should_include_state_in_changed_attributes
19
- assert_equal %w(status), @record.changed
20
- end
21
-
22
- def test_should_track_attribute_change
23
- assert_equal %w(parked idling), @record.changes['status']
24
- end
25
-
26
- def test_should_not_reset_changes_on_multiple_transitions
27
- transition = StateMachines::Transition.new(@record, @machine, :ignite, :idling, :idling)
28
- transition.perform(false)
29
-
30
- assert_equal %w(parked idling), @record.changes['status']
31
- end
32
- end
@@ -1,22 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
4
- def setup
5
- @model = new_model
6
- @machine = StateMachines::Machine.new(@model, :initial => :parked)
7
- @machine.event :park
8
-
9
- @record = @model.create
10
-
11
- @transition = StateMachines::Transition.new(@record, @machine, :park, :parked, :parked)
12
- @transition.perform(false)
13
- end
14
-
15
- def test_should_not_include_state_in_changed_attributes
16
- assert_equal [], @record.changed
17
- end
18
-
19
- def test_should_not_track_attribute_changes
20
- assert_nil @record.changes['state']
21
- end
22
- end