active_interaction 1.4.1 → 2.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 +4 -4
- data/CHANGELOG.md +65 -3
- data/CONTRIBUTING.md +19 -0
- data/README.md +1121 -180
- data/lib/active_interaction/backports.rb +58 -13
- data/lib/active_interaction/base.rb +16 -52
- data/lib/active_interaction/concerns/active_recordable.rb +57 -0
- data/lib/active_interaction/concerns/runnable.rb +4 -14
- data/lib/active_interaction/errors.rb +14 -66
- data/lib/active_interaction/filters/array_filter.rb +12 -9
- data/lib/active_interaction/filters/file_filter.rb +5 -24
- data/lib/active_interaction/filters/hash_filter.rb +11 -13
- data/lib/active_interaction/filters/interface_filter.rb +2 -2
- data/lib/active_interaction/filters/{model_filter.rb → object_filter.rb} +6 -6
- data/lib/active_interaction/locale/en.yml +1 -1
- data/lib/active_interaction/modules/validation.rb +2 -2
- data/lib/active_interaction/version.rb +1 -1
- data/lib/active_interaction.rb +25 -13
- data/spec/active_interaction/base_spec.rb +15 -39
- data/spec/active_interaction/concerns/active_recordable_spec.rb +51 -0
- data/spec/active_interaction/concerns/runnable_spec.rb +2 -34
- data/spec/active_interaction/errors_spec.rb +6 -89
- data/spec/active_interaction/filters/array_filter_spec.rb +2 -2
- data/spec/active_interaction/filters/file_filter_spec.rb +4 -4
- data/spec/active_interaction/filters/hash_filter_spec.rb +1 -17
- data/spec/active_interaction/filters/{model_filter_spec.rb → object_filter_spec.rb} +17 -17
- data/spec/active_interaction/i18n_spec.rb +1 -2
- data/spec/active_interaction/integration/array_interaction_spec.rb +10 -0
- data/spec/active_interaction/integration/hash_interaction_spec.rb +12 -2
- data/spec/active_interaction/integration/interface_interaction_spec.rb +10 -1
- data/spec/active_interaction/integration/object_interaction_spec.rb +16 -0
- data/spec/active_interaction/modules/validation_spec.rb +1 -2
- metadata +32 -29
- data/lib/active_interaction/concerns/transactable.rb +0 -79
- data/spec/active_interaction/concerns/transactable_spec.rb +0 -135
- data/spec/active_interaction/integration/model_interaction_spec.rb +0 -7
data/lib/active_interaction.rb
CHANGED
|
@@ -2,13 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_model'
|
|
4
4
|
|
|
5
|
+
# Manage application specific business logic.
|
|
6
|
+
#
|
|
7
|
+
# @author Aaron Lasseigne <aaron.lasseigne@gmail.com>
|
|
8
|
+
# @author Taylor Fausak <taylor@fausak.me>
|
|
9
|
+
#
|
|
10
|
+
# @since 1.0.0
|
|
11
|
+
#
|
|
12
|
+
# @version 2.0.0
|
|
13
|
+
module ActiveInteraction
|
|
14
|
+
DEPRECATOR =
|
|
15
|
+
if ::ActiveSupport::Deprecation.respond_to?(:new)
|
|
16
|
+
::ActiveSupport::Deprecation.new('2', 'ActiveInteraction')
|
|
17
|
+
end
|
|
18
|
+
private_constant :DEPRECATOR
|
|
19
|
+
|
|
20
|
+
def self.deprecate(klass, method, message = nil)
|
|
21
|
+
options = { method => message }
|
|
22
|
+
options.merge!(deprecator: DEPRECATOR) if DEPRECATOR
|
|
23
|
+
klass.deprecate(options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
5
27
|
require 'active_interaction/version'
|
|
6
28
|
require 'active_interaction/errors'
|
|
7
29
|
|
|
8
30
|
require 'active_interaction/concerns/active_modelable'
|
|
31
|
+
require 'active_interaction/concerns/active_recordable'
|
|
9
32
|
require 'active_interaction/concerns/hashable'
|
|
10
33
|
require 'active_interaction/concerns/missable'
|
|
11
|
-
require 'active_interaction/concerns/transactable'
|
|
12
34
|
require 'active_interaction/concerns/runnable'
|
|
13
35
|
|
|
14
36
|
require 'active_interaction/grouped_input'
|
|
@@ -19,6 +41,7 @@ require 'active_interaction/modules/validation'
|
|
|
19
41
|
require 'active_interaction/filter_column'
|
|
20
42
|
require 'active_interaction/filter'
|
|
21
43
|
require 'active_interaction/filters/abstract_filter'
|
|
44
|
+
require 'active_interaction/filters/interface_filter'
|
|
22
45
|
require 'active_interaction/filters/abstract_date_time_filter'
|
|
23
46
|
require 'active_interaction/filters/abstract_numeric_filter'
|
|
24
47
|
require 'active_interaction/filters/array_filter'
|
|
@@ -30,8 +53,7 @@ require 'active_interaction/filters/file_filter'
|
|
|
30
53
|
require 'active_interaction/filters/float_filter'
|
|
31
54
|
require 'active_interaction/filters/hash_filter'
|
|
32
55
|
require 'active_interaction/filters/integer_filter'
|
|
33
|
-
require 'active_interaction/filters/
|
|
34
|
-
require 'active_interaction/filters/model_filter'
|
|
56
|
+
require 'active_interaction/filters/object_filter'
|
|
35
57
|
require 'active_interaction/filters/string_filter'
|
|
36
58
|
require 'active_interaction/filters/symbol_filter'
|
|
37
59
|
require 'active_interaction/filters/time_filter'
|
|
@@ -42,13 +64,3 @@ require 'active_interaction/backports'
|
|
|
42
64
|
|
|
43
65
|
I18n.load_path.unshift(*Dir[File.expand_path(
|
|
44
66
|
File.join(%w[active_interaction locale *.yml]), File.dirname(__FILE__))])
|
|
45
|
-
|
|
46
|
-
# Manage application specific business logic.
|
|
47
|
-
#
|
|
48
|
-
# @author Aaron Lasseigne <aaron.lasseigne@gmail.com>
|
|
49
|
-
# @author Taylor Fausak <taylor@fausak.me>
|
|
50
|
-
#
|
|
51
|
-
# @since 1.0.0
|
|
52
|
-
#
|
|
53
|
-
# @version 1.4.1
|
|
54
|
-
module ActiveInteraction end
|
|
@@ -19,7 +19,7 @@ AddInteraction = Class.new(TestInteraction) do
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
InterruptInteraction = Class.new(TestInteraction) do
|
|
22
|
-
|
|
22
|
+
object :x, :y,
|
|
23
23
|
class: Object,
|
|
24
24
|
default: nil
|
|
25
25
|
|
|
@@ -248,8 +248,9 @@ describe ActiveInteraction::Base do
|
|
|
248
248
|
before do
|
|
249
249
|
@execute = described_class.instance_method(:execute)
|
|
250
250
|
described_class.send(:define_method, :execute) do
|
|
251
|
-
errors.add(:thing, '
|
|
252
|
-
errors.
|
|
251
|
+
errors.add(:thing, 'is invalid')
|
|
252
|
+
errors.add(:thing, :invalid)
|
|
253
|
+
true
|
|
253
254
|
end
|
|
254
255
|
end
|
|
255
256
|
|
|
@@ -263,16 +264,22 @@ describe ActiveInteraction::Base do
|
|
|
263
264
|
expect(outcome).to be_invalid
|
|
264
265
|
end
|
|
265
266
|
|
|
266
|
-
it 'sets the result
|
|
267
|
-
expect(result).to
|
|
267
|
+
it 'sets the result' do
|
|
268
|
+
expect(result).to be true
|
|
268
269
|
end
|
|
269
270
|
|
|
270
271
|
it 'has errors' do
|
|
271
|
-
expect(outcome.errors.messages[:thing]).to eql
|
|
272
|
+
expect(outcome.errors.messages[:thing]).to eql [
|
|
273
|
+
'is invalid',
|
|
274
|
+
'is invalid'
|
|
275
|
+
]
|
|
272
276
|
end
|
|
273
277
|
|
|
274
|
-
it 'has
|
|
275
|
-
expect(outcome.errors.
|
|
278
|
+
it 'has detailed errors' do
|
|
279
|
+
expect(outcome.errors.details[:thing]).to eql [
|
|
280
|
+
{ error: 'is invalid' },
|
|
281
|
+
{ error: :invalid }
|
|
282
|
+
]
|
|
276
283
|
end
|
|
277
284
|
end
|
|
278
285
|
|
|
@@ -283,12 +290,6 @@ describe ActiveInteraction::Base do
|
|
|
283
290
|
it 'sets the result' do
|
|
284
291
|
expect(result[:thing]).to eql thing
|
|
285
292
|
end
|
|
286
|
-
|
|
287
|
-
it 'calls #transaction' do
|
|
288
|
-
expect_any_instance_of(described_class).to receive(:transaction)
|
|
289
|
-
.once.with(no_args)
|
|
290
|
-
outcome
|
|
291
|
-
end
|
|
292
293
|
end
|
|
293
294
|
end
|
|
294
295
|
|
|
@@ -313,31 +314,6 @@ describe ActiveInteraction::Base do
|
|
|
313
314
|
end
|
|
314
315
|
end
|
|
315
316
|
|
|
316
|
-
describe '#column_for_attribute(name)' do
|
|
317
|
-
let(:described_class) { InteractionWithFilter }
|
|
318
|
-
let(:column) { outcome.column_for_attribute(name) }
|
|
319
|
-
|
|
320
|
-
context 'name is not an input name' do
|
|
321
|
-
let(:name) { SecureRandom.hex }
|
|
322
|
-
|
|
323
|
-
it 'returns nil if the attribute cannot be found' do
|
|
324
|
-
expect(column).to be_nil
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
context 'name is an input name' do
|
|
329
|
-
let(:name) { InteractionWithFilter.filters.keys.first }
|
|
330
|
-
|
|
331
|
-
it 'returns a FilterColumn' do
|
|
332
|
-
expect(column).to be_a ActiveInteraction::FilterColumn
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
it 'returns a FilterColumn of type boolean' do
|
|
336
|
-
expect(column.type).to eql :float
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
|
|
341
317
|
describe '#inputs' do
|
|
342
318
|
let(:described_class) { InteractionWithFilter }
|
|
343
319
|
let(:other_val) { SecureRandom.hex }
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
InteractionWithFloatFilter = Class.new(TestInteraction) do
|
|
6
|
+
float :thing
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe ActiveInteraction::ActiveRecordable do
|
|
10
|
+
include_context 'interactions'
|
|
11
|
+
|
|
12
|
+
let(:described_class) { InteractionWithFloatFilter }
|
|
13
|
+
|
|
14
|
+
describe '#column_for_attribute(name)' do
|
|
15
|
+
let(:column) { outcome.column_for_attribute(name) }
|
|
16
|
+
|
|
17
|
+
context 'name is not an input name' do
|
|
18
|
+
let(:name) { SecureRandom.hex }
|
|
19
|
+
|
|
20
|
+
it 'returns nil if the attribute cannot be found' do
|
|
21
|
+
expect(column).to be_nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'name is an input name' do
|
|
26
|
+
let(:name) { described_class.filters.keys.first }
|
|
27
|
+
|
|
28
|
+
it 'returns a FilterColumn' do
|
|
29
|
+
expect(column).to be_a ActiveInteraction::FilterColumn
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'returns a FilterColumn of type boolean' do
|
|
33
|
+
expect(column.type).to eql :float
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#has_attribute?' do
|
|
39
|
+
it 'returns true if the filter exists' do
|
|
40
|
+
expect(outcome.has_attribute?(:thing)).to be_truthy
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'works with strings' do
|
|
44
|
+
expect(outcome.has_attribute?('thing')).to be_truthy
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'returns false if the filter does not exist' do
|
|
48
|
+
expect(outcome.has_attribute?(:not_a_filter)).to be_falsey
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -101,9 +101,9 @@ describe ActiveInteraction::Runnable do
|
|
|
101
101
|
context 'with an error' do
|
|
102
102
|
include_context 'with an error'
|
|
103
103
|
|
|
104
|
-
it '
|
|
104
|
+
it 'sets the result' do
|
|
105
105
|
instance.result = result
|
|
106
|
-
expect(instance.result).to
|
|
106
|
+
expect(instance.result).to eql result
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
|
|
@@ -180,38 +180,6 @@ describe ActiveInteraction::Runnable do
|
|
|
180
180
|
end
|
|
181
181
|
end
|
|
182
182
|
|
|
183
|
-
context 'with an execute where composition fails' do
|
|
184
|
-
before do
|
|
185
|
-
interaction = Class.new(TestInteraction) do
|
|
186
|
-
validate { errors.add(:base) }
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
klass.send(:define_method, :execute) { compose(interaction) }
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
it 'rolls back the transaction' do
|
|
193
|
-
instance = klass.new
|
|
194
|
-
|
|
195
|
-
allow(instance).to receive(:raise)
|
|
196
|
-
instance.send(:run)
|
|
197
|
-
expect(instance).to have_received(:raise)
|
|
198
|
-
.with(ActiveRecord::Rollback)
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
context 'without a transaction' do
|
|
202
|
-
before { klass.transaction(false) }
|
|
203
|
-
|
|
204
|
-
it 'does not roll back' do
|
|
205
|
-
instance = klass.new
|
|
206
|
-
|
|
207
|
-
allow(instance).to receive(:raise)
|
|
208
|
-
instance.send(:run)
|
|
209
|
-
expect(instance).to_not have_received(:raise)
|
|
210
|
-
.with(ActiveRecord::Rollback)
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
183
|
context 'with invalid post-execution state' do
|
|
216
184
|
before do
|
|
217
185
|
klass.class_exec do
|
|
@@ -17,88 +17,6 @@ describe ActiveInteraction::Errors do
|
|
|
17
17
|
|
|
18
18
|
subject(:errors) { described_class.new(klass.new) }
|
|
19
19
|
|
|
20
|
-
describe '#add_sym' do
|
|
21
|
-
it 'defaults to :invalid' do
|
|
22
|
-
errors.add_sym(:attribute)
|
|
23
|
-
expect(errors.symbolic[:attribute]).to eql [:invalid]
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'adds a symbol' do
|
|
27
|
-
errors.add_sym(:attribute, :symbol)
|
|
28
|
-
expect(errors.symbolic[:attribute]).to eql [:symbol]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it 'accepts a message' do
|
|
32
|
-
errors.add_sym(:attribute, :symbol, 'message')
|
|
33
|
-
expect(errors.symbolic[:attribute]).to eql [:symbol]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it 'accepts a message and options' do
|
|
37
|
-
errors.add_sym(:attribute, :symbol, 'message', key: :value)
|
|
38
|
-
expect(errors.symbolic[:attribute]).to eql [:symbol]
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
context 'calling #add' do
|
|
42
|
-
before do
|
|
43
|
-
allow(errors).to receive(:add)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'with the default' do
|
|
47
|
-
errors.add_sym(:attribute)
|
|
48
|
-
expect(errors).to have_received(:add).once
|
|
49
|
-
.with(:attribute, :invalid, {})
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it 'with a symbol' do
|
|
53
|
-
errors.add_sym(:attribute, :symbol)
|
|
54
|
-
expect(errors).to have_received(:add).once
|
|
55
|
-
.with(:attribute, :symbol, {})
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'with a symbol and message' do
|
|
59
|
-
errors.add_sym(:attribute, :symbol, 'message')
|
|
60
|
-
expect(errors).to have_received(:add).once
|
|
61
|
-
.with(:attribute, 'message', {})
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'with a symbol, message and options' do
|
|
65
|
-
errors.add_sym(:attribute, :symbol, 'message', key: :value)
|
|
66
|
-
expect(errors).to have_received(:add).once
|
|
67
|
-
.with(:attribute, 'message', key: :value)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
describe '#initialize' do
|
|
73
|
-
it 'sets symbolic to an empty hash' do
|
|
74
|
-
expect(errors.symbolic).to eql({})
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
describe '#initialize_dup' do
|
|
79
|
-
let(:errors_dup) { errors.dup }
|
|
80
|
-
|
|
81
|
-
before do
|
|
82
|
-
errors.add_sym(:attribute)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'dups symbolic' do
|
|
86
|
-
expect(errors_dup.symbolic).to eql errors.symbolic
|
|
87
|
-
expect(errors_dup.symbolic).to_not equal errors.symbolic
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
describe '#clear' do
|
|
92
|
-
before do
|
|
93
|
-
errors.add_sym(:attribute)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it 'clears symbolic' do
|
|
97
|
-
errors.clear
|
|
98
|
-
expect(errors.symbolic).to be_empty
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
20
|
describe '#merge!' do
|
|
103
21
|
let(:other) { described_class.new(klass.new) }
|
|
104
22
|
|
|
@@ -119,18 +37,18 @@ describe ActiveInteraction::Errors do
|
|
|
119
37
|
end
|
|
120
38
|
end
|
|
121
39
|
|
|
122
|
-
context 'with a
|
|
40
|
+
context 'with a detailed error' do
|
|
123
41
|
before do
|
|
124
|
-
other.
|
|
42
|
+
other.add(:attribute)
|
|
125
43
|
end
|
|
126
44
|
|
|
127
45
|
it 'adds the error' do
|
|
128
46
|
errors.merge!(other)
|
|
129
|
-
expect(errors.
|
|
47
|
+
expect(errors.details[:attribute]).to eql [{ error: :invalid }]
|
|
130
48
|
end
|
|
131
49
|
end
|
|
132
50
|
|
|
133
|
-
context 'with an interpolated
|
|
51
|
+
context 'with an interpolated detailed error' do
|
|
134
52
|
before do
|
|
135
53
|
I18n.backend.store_translations('en',
|
|
136
54
|
activemodel: {
|
|
@@ -145,10 +63,9 @@ describe ActiveInteraction::Errors do
|
|
|
145
63
|
}
|
|
146
64
|
}
|
|
147
65
|
}
|
|
148
|
-
}
|
|
149
|
-
)
|
|
66
|
+
})
|
|
150
67
|
|
|
151
|
-
other.
|
|
68
|
+
other.add(:attribute, :invalid_type, type: nil)
|
|
152
69
|
end
|
|
153
70
|
|
|
154
71
|
it 'does not raise an error' do
|
|
@@ -84,8 +84,8 @@ describe ActiveInteraction::ArrayFilter, :filter do
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
context 'with a nested
|
|
88
|
-
let(:block) { proc {
|
|
87
|
+
context 'with a nested object filter' do
|
|
88
|
+
let(:block) { proc { object } }
|
|
89
89
|
let(:name) { :objects }
|
|
90
90
|
let(:value) { [Object.new] }
|
|
91
91
|
|
|
@@ -25,11 +25,11 @@ describe ActiveInteraction::FileFilter, :filter do
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
context 'with an object that responds to #
|
|
29
|
-
let(:value) { double(
|
|
28
|
+
context 'with an object that responds to #eof?' do
|
|
29
|
+
let(:value) { double(eof?: true) }
|
|
30
30
|
|
|
31
|
-
it 'returns the
|
|
32
|
-
expect(result).to eq value
|
|
31
|
+
it 'returns the object' do
|
|
32
|
+
expect(result).to eq value
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
@@ -37,7 +37,7 @@ describe ActiveInteraction::HashFilter, :filter do
|
|
|
37
37
|
let(:block) { proc { hash :a } }
|
|
38
38
|
|
|
39
39
|
context 'with a Hash' do
|
|
40
|
-
let(:value) { { a
|
|
40
|
+
let(:value) { { 'a' => {} } }
|
|
41
41
|
|
|
42
42
|
it 'returns the Hash' do
|
|
43
43
|
expect(result).to eql value
|
|
@@ -75,22 +75,6 @@ describe ActiveInteraction::HashFilter, :filter do
|
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
|
-
|
|
79
|
-
context 'keys are symbolized' do
|
|
80
|
-
let(:value) { { 'a' => 'a', 1 => 1 } }
|
|
81
|
-
|
|
82
|
-
before do
|
|
83
|
-
options.merge!(strip: false)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it 'symbolizes String keys' do
|
|
87
|
-
expect(result).to have_key :a
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it 'leaves other keys alone' do
|
|
91
|
-
expect(result).to have_key 1
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
78
|
end
|
|
95
79
|
|
|
96
80
|
describe '#default' do
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class Thing; end
|
|
6
6
|
class Things; end
|
|
7
7
|
|
|
8
|
-
describe ActiveInteraction::
|
|
8
|
+
describe ActiveInteraction::ObjectFilter, :filter do
|
|
9
9
|
include_context 'filters'
|
|
10
10
|
it_behaves_like 'a filter'
|
|
11
11
|
|
|
12
12
|
before do
|
|
13
|
-
options.merge!(class:
|
|
13
|
+
options.merge!(class: Thing)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
describe '#cast' do
|
|
17
|
-
let(:value) {
|
|
17
|
+
let(:value) { Thing.new }
|
|
18
18
|
let(:result) { filter.cast(value) }
|
|
19
19
|
|
|
20
20
|
context 'with class as a Class' do
|
|
@@ -25,9 +25,9 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
25
25
|
it 'handles reconstantizing' do
|
|
26
26
|
expect(result).to eql value
|
|
27
27
|
|
|
28
|
-
Object.send(:remove_const, :
|
|
29
|
-
class
|
|
30
|
-
value =
|
|
28
|
+
Object.send(:remove_const, :Thing)
|
|
29
|
+
class Thing; end
|
|
30
|
+
value = Thing.new
|
|
31
31
|
|
|
32
32
|
expect(filter.cast(value)).to eql value
|
|
33
33
|
end
|
|
@@ -35,10 +35,10 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
35
35
|
it 'handles reconstantizing subclasses' do
|
|
36
36
|
filter
|
|
37
37
|
|
|
38
|
-
Object.send(:remove_const, :
|
|
39
|
-
class
|
|
40
|
-
class
|
|
41
|
-
value =
|
|
38
|
+
Object.send(:remove_const, :Thing)
|
|
39
|
+
class Thing; end
|
|
40
|
+
class SubThing < Thing; end
|
|
41
|
+
value = SubThing.new
|
|
42
42
|
|
|
43
43
|
expect(filter.cast(value)).to eql value
|
|
44
44
|
end
|
|
@@ -46,7 +46,7 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
46
46
|
it 'does not overflow the stack' do
|
|
47
47
|
klass = Class.new do
|
|
48
48
|
def self.name
|
|
49
|
-
|
|
49
|
+
Thing.name
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -56,8 +56,8 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
context 'without the class available' do
|
|
59
|
-
before { Object.send(:remove_const, :
|
|
60
|
-
after { class
|
|
59
|
+
before { Object.send(:remove_const, :Thing) }
|
|
60
|
+
after { class Thing; end }
|
|
61
61
|
|
|
62
62
|
it 'does not raise an error on initialization' do
|
|
63
63
|
expect { filter }.to_not raise_error
|
|
@@ -69,7 +69,7 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
69
69
|
let(:class_equality) { false }
|
|
70
70
|
|
|
71
71
|
before do
|
|
72
|
-
allow(
|
|
72
|
+
allow(Thing).to receive(:===).and_return(case_equality)
|
|
73
73
|
allow(value).to receive(:is_a?).and_return(class_equality)
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -101,7 +101,7 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
101
101
|
|
|
102
102
|
context 'with class as a superclass' do
|
|
103
103
|
before do
|
|
104
|
-
options.merge!(class:
|
|
104
|
+
options.merge!(class: Thing.superclass)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
it 'returns the instance' do
|
|
@@ -111,7 +111,7 @@ describe ActiveInteraction::ModelFilter, :filter do
|
|
|
111
111
|
|
|
112
112
|
context 'with class as a String' do
|
|
113
113
|
before do
|
|
114
|
-
options.merge!(class:
|
|
114
|
+
options.merge!(class: Thing.name)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
it 'returns the instance' do
|
|
@@ -39,6 +39,16 @@ describe ArrayInteraction do
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
context 'with an invalid default as a proc' do
|
|
43
|
+
it 'does not raise an error' do
|
|
44
|
+
expect do
|
|
45
|
+
Class.new(ActiveInteraction::Base) do
|
|
46
|
+
array :a, default: -> { Object.new }
|
|
47
|
+
end
|
|
48
|
+
end.to_not raise_error
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
42
52
|
context 'with an invalid nested default' do
|
|
43
53
|
it 'raises an error' do
|
|
44
54
|
expect do
|
|
@@ -21,11 +21,11 @@ describe HashInteraction do
|
|
|
21
21
|
before { inputs.merge!(a: a) }
|
|
22
22
|
|
|
23
23
|
it 'returns the correct value for :a' do
|
|
24
|
-
expect(result[:a]).to eql a.
|
|
24
|
+
expect(result[:a]).to eql a.with_indifferent_access
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it 'returns the correct value for :b' do
|
|
28
|
-
expect(result[:b]).to eql(x
|
|
28
|
+
expect(result[:b]).to eql('x' => {})
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -39,6 +39,16 @@ describe HashInteraction do
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
context 'with an invalid default as a proc' do
|
|
43
|
+
it 'does not raise an error' do
|
|
44
|
+
expect do
|
|
45
|
+
Class.new(ActiveInteraction::Base) do
|
|
46
|
+
array :a, default: -> { Object.new }
|
|
47
|
+
end
|
|
48
|
+
end.to_not raise_error
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
42
52
|
context 'with an invalid nested default' do
|
|
43
53
|
it 'raises an error' do
|
|
44
54
|
expect do
|
|
@@ -4,9 +4,18 @@ require 'spec_helper'
|
|
|
4
4
|
require 'json'
|
|
5
5
|
require 'yaml'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
InterfaceInteraction = Class.new(TestInteraction) do
|
|
8
|
+
interface :anything
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe InterfaceInteraction do
|
|
12
|
+
include_context 'interactions'
|
|
8
13
|
it_behaves_like 'an interaction',
|
|
9
14
|
:interface,
|
|
10
15
|
-> { [JSON, YAML].sample },
|
|
11
16
|
methods: [:dump, :load]
|
|
17
|
+
|
|
18
|
+
it 'succeeds when given nil' do
|
|
19
|
+
expect { result }.to_not raise_error
|
|
20
|
+
end
|
|
12
21
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
ObjectInteraction = Class.new(TestInteraction) do
|
|
6
|
+
object :object
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe ObjectInteraction do
|
|
10
|
+
include_context 'interactions'
|
|
11
|
+
it_behaves_like 'an interaction', :object, -> { // }, class: Regexp
|
|
12
|
+
|
|
13
|
+
it 'succeeds when given nil' do
|
|
14
|
+
expect { result }.to_not raise_error
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -42,7 +42,7 @@ describe ActiveInteraction::Validation do
|
|
|
42
42
|
type = I18n.translate(
|
|
43
43
|
"#{ActiveInteraction::Base.i18n_scope}.types.#{filter.class.slug}")
|
|
44
44
|
|
|
45
|
-
expect(result).to eql [[filter.name, :invalid_type,
|
|
45
|
+
expect(result).to eql [[filter.name, :invalid_type, type: type]]
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -65,7 +65,6 @@ describe ActiveInteraction::Validation do
|
|
|
65
65
|
expect(result).to eql [[
|
|
66
66
|
filter.name,
|
|
67
67
|
:invalid_nested,
|
|
68
|
-
nil,
|
|
69
68
|
{ name: name.inspect, value: value.inspect }
|
|
70
69
|
]]
|
|
71
70
|
end
|