state_machines-activerecord 0.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 +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +20 -0
- data/Appraisals +11 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +23 -0
- data/README.md +65 -0
- data/Rakefile +9 -0
- data/gemfiles/active_record_4.1.gemfile +13 -0
- data/gemfiles/active_record_4.2.gemfile +13 -0
- data/lib/state_machines-activerecord.rb +1 -0
- data/lib/state_machines/integrations/active_record.rb +588 -0
- data/lib/state_machines/integrations/active_record/locale.rb +12 -0
- data/lib/state_machines/integrations/active_record/version.rb +7 -0
- data/log/.gitkeep +0 -0
- data/state_machines-activerecord.gemspec +27 -0
- data/test/files/en.yml +5 -0
- data/test/files/models/post.rb +11 -0
- data/test/integration_test.rb +23 -0
- data/test/machine_by_default_test.rb +16 -0
- data/test/machine_errors_test.rb +19 -0
- data/test/machine_multiple_test.rb +17 -0
- data/test/machine_nested_action_test.rb +38 -0
- data/test/machine_unmigrated_test.rb +14 -0
- data/test/machine_with_aliased_attribute_test.rb +23 -0
- data/test/machine_with_callbacks_test.rb +172 -0
- data/test/machine_with_column_state_attribute_test.rb +44 -0
- data/test/machine_with_complex_pluralization_scopes_test.rb +16 -0
- data/test/machine_with_conflicting_predicate_test.rb +18 -0
- data/test/machine_with_conflicting_state_name_test.rb +29 -0
- data/test/machine_with_custom_attribute_test.rb +21 -0
- data/test/machine_with_default_scope_test.rb +18 -0
- data/test/machine_with_different_column_default_test.rb +27 -0
- data/test/machine_with_different_integer_column_default_test.rb +29 -0
- data/test/machine_with_dirty_attribute_and_custom_attributes_during_loopback_test.rb +24 -0
- data/test/machine_with_dirty_attribute_and_state_events_test.rb +20 -0
- data/test/machine_with_dirty_attributes_and_custom_attribute_test.rb +32 -0
- data/test/machine_with_dirty_attributes_during_loopback_test.rb +22 -0
- data/test/machine_with_dirty_attributes_test.rb +35 -0
- data/test/machine_with_dynamic_initial_state_test.rb +99 -0
- data/test/machine_with_event_attributes_on_autosave_test.rb +48 -0
- data/test/machine_with_event_attributes_on_custom_action_test.rb +41 -0
- data/test/machine_with_event_attributes_on_save_bang_test.rb +82 -0
- data/test/machine_with_event_attributes_on_save_test.rb +184 -0
- data/test/machine_with_event_attributes_on_validation_test.rb +126 -0
- data/test/machine_with_events_test.rb +13 -0
- data/test/machine_with_failed_action_test.rb +40 -0
- data/test/machine_with_failed_after_callbacks_test.rb +35 -0
- data/test/machine_with_failed_before_callbacks_test.rb +36 -0
- data/test/machine_with_initialized_state_test.rb +35 -0
- data/test/machine_with_internationalization_test.rb +180 -0
- data/test/machine_with_loopback_test.rb +22 -0
- data/test/machine_with_non_column_state_attribute_defined_test.rb +35 -0
- data/test/machine_with_non_column_state_attribute_undefined_test.rb +33 -0
- data/test/machine_with_same_column_default_test.rb +26 -0
- data/test/machine_with_scopes_and_joins_test.rb +37 -0
- data/test/machine_with_scopes_and_owner_subclass_test.rb +27 -0
- data/test/machine_with_scopes_test.rb +70 -0
- data/test/machine_with_state_driven_validations_test.rb +30 -0
- data/test/machine_with_states_test.rb +13 -0
- data/test/machine_with_static_initial_state_test.rb +166 -0
- data/test/machine_with_transactions_test.rb +26 -0
- data/test/machine_with_validations_and_custom_attribute_test.rb +21 -0
- data/test/machine_with_validations_test.rb +47 -0
- data/test/machine_without_database_test.rb +20 -0
- data/test/machine_without_transactions_test.rb +26 -0
- data/test/model_test.rb +12 -0
- data/test/test_helper.rb +42 -0
- metadata +264 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithFailedActionTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@model = new_model do
|
6
|
+
validates_inclusion_of :state, :in => %w(first_gear)
|
7
|
+
end
|
8
|
+
|
9
|
+
@machine = StateMachines::Machine.new(@model)
|
10
|
+
@machine.state :parked, :idling
|
11
|
+
@machine.event :ignite
|
12
|
+
|
13
|
+
@callbacks = []
|
14
|
+
@machine.before_transition { @callbacks << :before }
|
15
|
+
@machine.after_transition { @callbacks << :after }
|
16
|
+
@machine.after_failure { @callbacks << :after_failure }
|
17
|
+
@machine.around_transition { |block| @callbacks << :around_before; block.call; @callbacks << :around_after }
|
18
|
+
|
19
|
+
@record = @model.new(:state => 'parked')
|
20
|
+
@transition = StateMachines::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
21
|
+
@result = @transition.perform
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_not_be_successful
|
25
|
+
refute @result
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_not_change_current_state
|
29
|
+
assert_equal 'parked', @record.state
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_not_save_record
|
33
|
+
assert @record.new_record?
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_should_run_before_callbacks_and_after_callbacks_with_failures
|
37
|
+
assert_equal [:before, :around_before, :after_failure], @callbacks
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithFailedAfterCallbacksTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@callbacks = []
|
6
|
+
|
7
|
+
@model = new_model
|
8
|
+
@machine = StateMachines::Machine.new(@model)
|
9
|
+
@machine.state :parked, :idling
|
10
|
+
@machine.event :ignite
|
11
|
+
@machine.after_transition { @callbacks << :after_1; false }
|
12
|
+
@machine.after_transition { @callbacks << :after_2 }
|
13
|
+
@machine.around_transition { |block| @callbacks << :around_before; block.call; @callbacks << :around_after }
|
14
|
+
|
15
|
+
@record = @model.new(:state => 'parked')
|
16
|
+
@transition = StateMachines::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
17
|
+
@result = @transition.perform
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_be_successful
|
21
|
+
assert @result
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_change_current_state
|
25
|
+
assert_equal 'idling', @record.state
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_save_record
|
29
|
+
refute @record.new_record?
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_not_run_further_after_callbacks
|
33
|
+
assert_equal [:around_before, :around_after, :after_1], @callbacks
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithFailedBeforeCallbacksTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@callbacks = []
|
6
|
+
|
7
|
+
@model = new_model
|
8
|
+
@machine = StateMachines::Machine.new(@model)
|
9
|
+
@machine.state :parked, :idling
|
10
|
+
@machine.event :ignite
|
11
|
+
@machine.before_transition { @callbacks << :before_1; false }
|
12
|
+
@machine.before_transition { @callbacks << :before_2 }
|
13
|
+
@machine.after_transition { @callbacks << :after }
|
14
|
+
@machine.around_transition { |block| @callbacks << :around_before; block.call; @callbacks << :around_after }
|
15
|
+
|
16
|
+
@record = @model.new(:state => 'parked')
|
17
|
+
@transition = StateMachines::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
18
|
+
@result = @transition.perform
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_not_be_successful
|
22
|
+
refute @result
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_not_change_current_state
|
26
|
+
assert_equal 'parked', @record.state
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_not_run_action
|
30
|
+
assert @record.new_record?
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_not_run_further_callbacks
|
34
|
+
assert_equal [:before_1], @callbacks
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithInitializedStateTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@model = new_model
|
6
|
+
@machine = StateMachines::Machine.new(@model, :initial => :parked)
|
7
|
+
@machine.state :idling
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_allow_nil_initial_state_when_static
|
11
|
+
@machine.state nil
|
12
|
+
|
13
|
+
record = @model.new(:state => nil)
|
14
|
+
assert_nil record.state
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_allow_nil_initial_state_when_dynamic
|
18
|
+
@machine.state nil
|
19
|
+
|
20
|
+
@machine.initial_state = lambda { :parked }
|
21
|
+
record = @model.new(:state => nil)
|
22
|
+
assert_nil record.state
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_allow_different_initial_state_when_static
|
26
|
+
record = @model.new(:state => 'idling')
|
27
|
+
assert_equal 'idling', record.state
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_allow_different_initial_state_when_dynamic
|
31
|
+
@machine.initial_state = lambda { :parked }
|
32
|
+
record = @model.new(:state => 'idling')
|
33
|
+
assert_equal 'idling', record.state
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithInternationalizationTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
I18n.backend = I18n::Backend::Simple.new
|
6
|
+
|
7
|
+
# Initialize the backend
|
8
|
+
StateMachines::Machine.new(new_model)
|
9
|
+
|
10
|
+
@model = new_model
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_use_defaults
|
14
|
+
I18n.backend.store_translations(:en, {
|
15
|
+
:activerecord => {:errors => {:messages => {:invalid_transition => "cannot #{interpolation_key('event')}"}}}
|
16
|
+
})
|
17
|
+
|
18
|
+
machine = StateMachines::Machine.new(@model)
|
19
|
+
machine.state :parked, :idling
|
20
|
+
machine.event :ignite
|
21
|
+
|
22
|
+
record = @model.new(:state => 'idling')
|
23
|
+
|
24
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
|
25
|
+
assert_equal ['State cannot transition via "ignite"'], record.errors.full_messages
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_allow_customized_error_key
|
29
|
+
I18n.backend.store_translations(:en, {
|
30
|
+
:activerecord => {:errors => {:messages => {:bad_transition => "cannot #{interpolation_key('event')}"}}}
|
31
|
+
})
|
32
|
+
|
33
|
+
machine = StateMachines::Machine.new(@model, :messages => {:invalid_transition => :bad_transition})
|
34
|
+
machine.state :parked, :idling
|
35
|
+
|
36
|
+
record = @model.new(:state => 'idling')
|
37
|
+
|
38
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
|
39
|
+
assert_equal ['State cannot ignite'], record.errors.full_messages
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_should_allow_customized_error_string
|
43
|
+
machine = StateMachines::Machine.new(@model, :messages => {:invalid_transition => "cannot #{interpolation_key('event')}"})
|
44
|
+
machine.state :parked, :idling
|
45
|
+
|
46
|
+
record = @model.new(:state => 'idling')
|
47
|
+
|
48
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
|
49
|
+
assert_equal ['State cannot ignite'], record.errors.full_messages
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_should_allow_customized_state_key_scoped_to_class_and_machine
|
53
|
+
I18n.backend.store_translations(:en, {
|
54
|
+
:activerecord => {:state_machines => {:'foo' => {:state => {:states => {:parked => 'shutdown'}}}}}
|
55
|
+
})
|
56
|
+
|
57
|
+
machine = StateMachines::Machine.new(@model)
|
58
|
+
machine.state :parked
|
59
|
+
|
60
|
+
assert_equal 'shutdown', machine.state(:parked).human_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_should_allow_customized_state_key_scoped_to_class
|
64
|
+
I18n.backend.store_translations(:en, {
|
65
|
+
:activerecord => {:state_machines => {:'foo' => {:states => {:parked => 'shutdown'}}}}
|
66
|
+
})
|
67
|
+
|
68
|
+
machine = StateMachines::Machine.new(@model)
|
69
|
+
machine.state :parked
|
70
|
+
|
71
|
+
assert_equal 'shutdown', machine.state(:parked).human_name
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_should_allow_customized_state_key_scoped_to_machine
|
75
|
+
I18n.backend.store_translations(:en, {
|
76
|
+
:activerecord => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
|
77
|
+
})
|
78
|
+
|
79
|
+
machine = StateMachines::Machine.new(@model)
|
80
|
+
machine.state :parked
|
81
|
+
|
82
|
+
assert_equal 'shutdown', machine.state(:parked).human_name
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_should_allow_customized_state_key_unscoped
|
86
|
+
I18n.backend.store_translations(:en, {
|
87
|
+
:activerecord => {:state_machines => {:states => {:parked => 'shutdown'}}}
|
88
|
+
})
|
89
|
+
|
90
|
+
machine = StateMachines::Machine.new(@model)
|
91
|
+
machine.state :parked
|
92
|
+
|
93
|
+
assert_equal 'shutdown', machine.state(:parked).human_name
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_should_support_nil_state_key
|
97
|
+
I18n.backend.store_translations(:en, {
|
98
|
+
:activerecord => {:state_machines => {:states => {:nil => 'empty'}}}
|
99
|
+
})
|
100
|
+
|
101
|
+
machine = StateMachines::Machine.new(@model)
|
102
|
+
|
103
|
+
assert_equal 'empty', machine.state(nil).human_name
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_should_allow_customized_event_key_scoped_to_class_and_machine
|
107
|
+
I18n.backend.store_translations(:en, {
|
108
|
+
:activerecord => {:state_machines => {:'foo' => {:state => {:events => {:park => 'stop'}}}}}
|
109
|
+
})
|
110
|
+
|
111
|
+
machine = StateMachines::Machine.new(@model)
|
112
|
+
machine.event :park
|
113
|
+
|
114
|
+
assert_equal 'stop', machine.event(:park).human_name
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_should_allow_customized_event_key_scoped_to_class
|
118
|
+
I18n.backend.store_translations(:en, {
|
119
|
+
:activerecord => {:state_machines => {:'foo' => {:events => {:park => 'stop'}}}}
|
120
|
+
})
|
121
|
+
|
122
|
+
machine = StateMachines::Machine.new(@model)
|
123
|
+
machine.event :park
|
124
|
+
|
125
|
+
assert_equal 'stop', machine.event(:park).human_name
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_should_allow_customized_event_key_scoped_to_machine
|
129
|
+
I18n.backend.store_translations(:en, {
|
130
|
+
:activerecord => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
|
131
|
+
})
|
132
|
+
|
133
|
+
machine = StateMachines::Machine.new(@model)
|
134
|
+
machine.event :park
|
135
|
+
|
136
|
+
assert_equal 'stop', machine.event(:park).human_name
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_should_allow_customized_event_key_unscoped
|
140
|
+
I18n.backend.store_translations(:en, {
|
141
|
+
:activerecord => {:state_machines => {:events => {:park => 'stop'}}}
|
142
|
+
})
|
143
|
+
|
144
|
+
machine = StateMachines::Machine.new(@model)
|
145
|
+
machine.event :park
|
146
|
+
|
147
|
+
assert_equal 'stop', machine.event(:park).human_name
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_only_add_locale_once_in_load_path
|
151
|
+
assert_equal 1, I18n.load_path.select { |path| path =~ %r{active_record/locale\.rb$} }.length
|
152
|
+
|
153
|
+
# Create another ActiveRecord model that will trigger the i18n feature
|
154
|
+
new_model
|
155
|
+
|
156
|
+
assert_equal 1, I18n.load_path.select { |path| path =~ %r{active_record/locale\.rb$} }.length
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_should_prefer_other_locales_first
|
160
|
+
@original_load_path = I18n.load_path
|
161
|
+
I18n.backend = I18n::Backend::Simple.new
|
162
|
+
I18n.load_path = [File.dirname(__FILE__) + '/files/en.yml']
|
163
|
+
|
164
|
+
machine = StateMachines::Machine.new(@model)
|
165
|
+
machine.state :parked, :idling
|
166
|
+
machine.event :ignite
|
167
|
+
|
168
|
+
record = @model.new(:state => 'idling')
|
169
|
+
|
170
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
|
171
|
+
assert_equal ['State cannot transition'], record.errors.full_messages
|
172
|
+
ensure
|
173
|
+
I18n.load_path = @original_load_path
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
def interpolation_key(key)
|
178
|
+
"%{#{key}}"
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithLoopbackTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@model = new_model do
|
6
|
+
connection.add_column table_name, :updated_at, :datetime
|
7
|
+
end
|
8
|
+
|
9
|
+
@machine = StateMachines::Machine.new(@model, :initial => :parked)
|
10
|
+
@machine.event :park
|
11
|
+
|
12
|
+
@record = @model.create(:updated_at => Time.now - 1)
|
13
|
+
@transition = StateMachines::Transition.new(@record, @machine, :park, :parked, :parked)
|
14
|
+
|
15
|
+
@timestamp = @record.updated_at
|
16
|
+
@transition.perform
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_not_update_record
|
20
|
+
assert_equal @timestamp, @record.updated_at
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@model = new_model do
|
6
|
+
def status=(value)
|
7
|
+
self['status'] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def status
|
11
|
+
self['status']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
@machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
|
16
|
+
@machine.other_states(:idling)
|
17
|
+
@record = @model.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
21
|
+
refute @record.status?(:idling)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_return_true_for_predicate_if_matches_current_value
|
25
|
+
assert @record.status?(:parked)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_raise_exception_for_predicate_if_invalid_state_specified
|
29
|
+
assert_raise(IndexError) { @record.status?(:invalid) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_set_initial_state_on_created_object
|
33
|
+
assert_equal 'parked', @record.status
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@model = new_model do
|
6
|
+
def initialize
|
7
|
+
# Skip attribute initialization
|
8
|
+
@initialized_state_machines = true
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
@machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
|
14
|
+
@machine.other_states(:idling)
|
15
|
+
@record = @model.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_not_define_a_column_for_the_attribute
|
19
|
+
assert_nil @model.columns_hash['status']
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_define_a_reader_attribute_for_the_attribute
|
23
|
+
assert @record.respond_to?(:status)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_should_define_a_writer_attribute_for_the_attribute
|
27
|
+
assert @record.respond_to?(:status=)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_define_an_attribute_predicate
|
31
|
+
assert @record.respond_to?(:status?)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MachineWithSameColumnDefaultTest < BaseTestCase
|
4
|
+
def setup
|
5
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
6
|
+
|
7
|
+
@model = new_model do
|
8
|
+
connection.add_column table_name, :status, :string, :default => 'parked'
|
9
|
+
end
|
10
|
+
@machine = StateMachines::Machine.new(@model, :status, :initial => :parked)
|
11
|
+
@record = @model.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_use_machine_default
|
15
|
+
assert_equal 'parked', @record.status
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_not_generate_a_warning
|
19
|
+
assert_no_match(/have defined a different default/, $stderr.string)
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
$stderr = @original_stderr
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|