active_interaction 0.9.0 → 0.9.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/README.md +4 -4
  4. data/lib/active_interaction.rb +2 -0
  5. data/lib/active_interaction/base.rb +26 -14
  6. data/lib/active_interaction/errors.rb +7 -10
  7. data/lib/active_interaction/filter.rb +10 -10
  8. data/lib/active_interaction/filters.rb +2 -0
  9. data/lib/active_interaction/filters/abstract_date_time_filter.rb +4 -2
  10. data/lib/active_interaction/filters/abstract_numeric_filter.rb +3 -1
  11. data/lib/active_interaction/filters/array_filter.rb +5 -3
  12. data/lib/active_interaction/filters/boolean_filter.rb +2 -0
  13. data/lib/active_interaction/filters/date_filter.rb +2 -0
  14. data/lib/active_interaction/filters/date_time_filter.rb +2 -0
  15. data/lib/active_interaction/filters/file_filter.rb +2 -0
  16. data/lib/active_interaction/filters/float_filter.rb +2 -0
  17. data/lib/active_interaction/filters/hash_filter.rb +7 -6
  18. data/lib/active_interaction/filters/integer_filter.rb +2 -0
  19. data/lib/active_interaction/filters/model_filter.rb +2 -0
  20. data/lib/active_interaction/filters/string_filter.rb +2 -0
  21. data/lib/active_interaction/filters/symbol_filter.rb +2 -0
  22. data/lib/active_interaction/filters/time_filter.rb +2 -0
  23. data/lib/active_interaction/modules/active_model.rb +2 -0
  24. data/lib/active_interaction/modules/core.rb +4 -1
  25. data/lib/active_interaction/modules/method_missing.rb +2 -0
  26. data/lib/active_interaction/modules/overload_hash.rb +2 -0
  27. data/lib/active_interaction/modules/validation.rb +10 -5
  28. data/lib/active_interaction/version.rb +4 -1
  29. data/spec/active_interaction/base_spec.rb +60 -35
  30. data/spec/active_interaction/errors_spec.rb +48 -14
  31. data/spec/active_interaction/filter_spec.rb +4 -2
  32. data/spec/active_interaction/filters/array_filter_spec.rb +13 -6
  33. data/spec/active_interaction/filters/boolean_filter_spec.rb +2 -0
  34. data/spec/active_interaction/filters/date_filter_spec.rb +6 -4
  35. data/spec/active_interaction/filters/date_time_filter_spec.rb +6 -4
  36. data/spec/active_interaction/filters/file_filter_spec.rb +2 -0
  37. data/spec/active_interaction/filters/float_filter_spec.rb +4 -2
  38. data/spec/active_interaction/filters/hash_filter_spec.rb +16 -4
  39. data/spec/active_interaction/filters/integer_filter_spec.rb +4 -2
  40. data/spec/active_interaction/filters/model_filter_spec.rb +4 -2
  41. data/spec/active_interaction/filters/string_filter_spec.rb +2 -0
  42. data/spec/active_interaction/filters/symbol_filter_spec.rb +2 -0
  43. data/spec/active_interaction/filters/time_filter_spec.rb +6 -4
  44. data/spec/active_interaction/filters_spec.rb +2 -0
  45. data/spec/active_interaction/i18n_spec.rb +9 -9
  46. data/spec/active_interaction/integration/array_interaction_spec.rb +10 -8
  47. data/spec/active_interaction/integration/boolean_interaction_spec.rb +2 -0
  48. data/spec/active_interaction/integration/date_interaction_spec.rb +2 -0
  49. data/spec/active_interaction/integration/date_time_interaction_spec.rb +2 -0
  50. data/spec/active_interaction/integration/file_interaction_spec.rb +2 -0
  51. data/spec/active_interaction/integration/float_interaction_spec.rb +2 -0
  52. data/spec/active_interaction/integration/hash_interaction_spec.rb +10 -8
  53. data/spec/active_interaction/integration/integer_interaction_spec.rb +2 -0
  54. data/spec/active_interaction/integration/model_interaction_spec.rb +3 -1
  55. data/spec/active_interaction/integration/string_interaction_spec.rb +2 -0
  56. data/spec/active_interaction/integration/symbol_interaction_spec.rb +2 -0
  57. data/spec/active_interaction/integration/time_interaction_spec.rb +9 -7
  58. data/spec/active_interaction/modules/active_model_spec.rb +2 -0
  59. data/spec/active_interaction/modules/core_spec.rb +12 -7
  60. data/spec/active_interaction/modules/method_missing_spec.rb +12 -10
  61. data/spec/active_interaction/modules/overload_hash_spec.rb +7 -5
  62. data/spec/active_interaction/modules/validation_spec.rb +5 -2
  63. data/spec/spec_helper.rb +4 -0
  64. data/spec/support/filters.rb +18 -16
  65. data/spec/support/interactions.rb +13 -11
  66. metadata +20 -6
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  module ActiveModel
@@ -1,5 +1,8 @@
1
+ # coding: utf-8
2
+
1
3
  begin
2
4
  require 'active_record'
5
+ # rubocop:disable HandleExceptions
3
6
  rescue LoadError
4
7
  # ActiveRecord is an optional dependency.
5
8
  end
@@ -49,7 +52,7 @@ module ActiveInteraction
49
52
  if outcome.valid?
50
53
  outcome.result
51
54
  else
52
- raise InvalidInteractionError, outcome.errors.full_messages.join(', ')
55
+ fail InvalidInteractionError, outcome.errors.full_messages.join(', ')
53
56
  end
54
57
  end
55
58
 
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  module MethodMissing
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  module OverloadHash
@@ -1,19 +1,24 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  module Validation
4
6
  def self.validate(filters, inputs)
5
- filters.reduce([]) do |errors, filter|
7
+ filters.each_with_object([]) do |filter, errors|
6
8
  begin
7
9
  filter.cast(inputs[filter.name])
8
-
9
- errors
10
10
  rescue InvalidValueError
11
- type = I18n.translate("#{Base.i18n_scope}.types.#{filter.class.slug}")
12
- errors << [filter.name, :invalid, nil, type: type]
11
+ errors << [filter.name, :invalid, nil, type: type(filter)]
13
12
  rescue MissingValueError
14
13
  errors << [filter.name, :missing]
15
14
  end
16
15
  end
17
16
  end
17
+
18
+ private
19
+
20
+ def self.type(filter)
21
+ I18n.translate("#{Base.i18n_scope}.types.#{filter.class.slug}")
22
+ end
18
23
  end
19
24
  end
@@ -1,3 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ # rubocop:disable Documentation
1
4
  module ActiveInteraction
2
- VERSION = Gem::Version.new('0.9.0')
5
+ VERSION = Gem::Version.new('0.9.1')
3
6
  end
@@ -1,33 +1,43 @@
1
+ # coding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe ActiveInteraction::Base do
4
- include_context 'interactions'
5
+ InteractionWithFilter = Class.new(TestInteraction) do
6
+ float :thing
5
7
 
6
- subject(:interaction) { described_class.new(options) }
8
+ def execute
9
+ thing
10
+ end
11
+ end
7
12
 
8
- class InteractionWithFilter < described_class
9
- float :thing
13
+ describe ActiveInteraction::Base do
14
+ include_context 'interactions'
10
15
 
11
- def execute
12
- thing
13
- end
14
- end
16
+ subject(:interaction) { described_class.new(inputs) }
15
17
 
16
- describe '.new(options = {})' do
18
+ describe '.new(inputs = {})' do
17
19
  it 'does not allow :_interaction_* as an option' do
18
20
  key = :"_interaction_#{SecureRandom.hex}"
19
- options.merge!(key => nil)
20
- expect {
21
+ inputs.merge!(key => nil)
22
+ expect do
21
23
  interaction
22
- }.to raise_error ActiveInteraction::InvalidValueError
24
+ end.to raise_error ActiveInteraction::InvalidValueError
23
25
  end
24
26
 
25
27
  it 'does not allow "_interaction_*" as an option' do
26
28
  key = "_interaction_#{SecureRandom.hex}"
27
- options.merge!(key => nil)
28
- expect {
29
+ inputs.merge!(key => nil)
30
+ expect do
29
31
  interaction
30
- }.to raise_error ActiveInteraction::InvalidValueError
32
+ end.to raise_error ActiveInteraction::InvalidValueError
33
+ end
34
+
35
+ context 'with invalid inputs' do
36
+ let(:inputs) { nil }
37
+
38
+ it 'raises an error' do
39
+ expect { interaction }.to raise_error ArgumentError
40
+ end
31
41
  end
32
42
 
33
43
  context 'with an attribute' do
@@ -45,7 +55,7 @@ describe ActiveInteraction::Base do
45
55
  let(:thing) { SecureRandom.hex }
46
56
 
47
57
  context 'failing validations' do
48
- before { options.merge!(thing: nil) }
58
+ before { inputs.merge!(thing: nil) }
49
59
 
50
60
  it 'returns an invalid outcome' do
51
61
  expect(interaction).to be_invalid
@@ -53,7 +63,7 @@ describe ActiveInteraction::Base do
53
63
  end
54
64
 
55
65
  context 'passing validations' do
56
- before { options.merge!(thing: thing) }
66
+ before { inputs.merge!(thing: thing) }
57
67
 
58
68
  it 'returns a valid outcome' do
59
69
  expect(interaction).to be_valid
@@ -69,7 +79,7 @@ describe ActiveInteraction::Base do
69
79
  let(:described_class) { InteractionWithFilter }
70
80
 
71
81
  context 'failing validations' do
72
- before { options.merge!(thing: thing) }
82
+ before { inputs.merge!(thing: thing) }
73
83
 
74
84
  context 'with an invalid value' do
75
85
  let(:thing) { 'a' }
@@ -89,7 +99,7 @@ describe ActiveInteraction::Base do
89
99
  end
90
100
 
91
101
  context 'passing validations' do
92
- before { options.merge!(thing: 1) }
102
+ before { inputs.merge!(thing: 1) }
93
103
 
94
104
  it 'sets the attribute to the filtered value' do
95
105
  expect(interaction.thing).to eql 1.0
@@ -100,11 +110,11 @@ describe ActiveInteraction::Base do
100
110
 
101
111
  describe '.method_missing(filter_type, *args, &block)' do
102
112
  it 'raises an error for an invalid filter type' do
103
- expect {
113
+ expect do
104
114
  Class.new(described_class) do
105
115
  not_a_valid_filter_type :thing
106
116
  end
107
- }.to raise_error NoMethodError
117
+ end.to raise_error NoMethodError
108
118
  end
109
119
 
110
120
  it do
@@ -152,7 +162,7 @@ describe ActiveInteraction::Base do
152
162
  let(:described_class) { InteractionWithFilter }
153
163
  let(:thing) { rand }
154
164
 
155
- describe '.run(options = {})' do
165
+ describe '.run(inputs = {})' do
156
166
  it "returns an instance of #{described_class}" do
157
167
  expect(outcome).to be_a described_class
158
168
  end
@@ -186,7 +196,7 @@ describe ActiveInteraction::Base do
186
196
  end
187
197
 
188
198
  context 'passing validations' do
189
- before { options.merge!(thing: thing) }
199
+ before { inputs.merge!(thing: thing) }
190
200
 
191
201
  context 'failing runtime validations' do
192
202
  before do
@@ -231,25 +241,25 @@ describe ActiveInteraction::Base do
231
241
  it 'calls transaction' do
232
242
  allow(described_class).to receive(:transaction)
233
243
  outcome
234
- expect(described_class).to have_received(:transaction).once.
235
- with(no_args)
244
+ expect(described_class).to have_received(:transaction).once
245
+ .with(no_args)
236
246
  end
237
247
  end
238
248
  end
239
249
 
240
- describe '.run!(options = {})' do
241
- subject(:result) { described_class.run!(options) }
250
+ describe '.run!(inputs = {})' do
251
+ subject(:result) { described_class.run!(inputs) }
242
252
 
243
253
  context 'failing validations' do
244
254
  it 'raises an error' do
245
- expect {
255
+ expect do
246
256
  result
247
- }.to raise_error ActiveInteraction::InvalidInteractionError
257
+ end.to raise_error ActiveInteraction::InvalidInteractionError
248
258
  end
249
259
  end
250
260
 
251
261
  context 'passing validations' do
252
- before { options.merge!(thing: thing) }
262
+ before { inputs.merge!(thing: thing) }
253
263
 
254
264
  it 'returns the result' do
255
265
  expect(result).to eq thing
@@ -261,7 +271,7 @@ describe ActiveInteraction::Base do
261
271
  describe '#inputs' do
262
272
  let(:described_class) { InteractionWithFilter }
263
273
  let(:other_val) { SecureRandom.hex }
264
- let(:options) { {thing: 1, other: other_val} }
274
+ let(:inputs) { { thing: 1, other: other_val } }
265
275
 
266
276
  it 'casts filtered inputs' do
267
277
  expect(interaction.inputs[:thing]).to eql 1.0
@@ -297,7 +307,7 @@ describe ActiveInteraction::Base do
297
307
 
298
308
  context 'with valid composition' do
299
309
  before do
300
- options.merge!(x: x, y: y)
310
+ inputs.merge!(x: x, y: y)
301
311
  end
302
312
 
303
313
  it 'is valid' do
@@ -315,8 +325,8 @@ describe ActiveInteraction::Base do
315
325
  end
316
326
 
317
327
  it 'has the correct errors' do
318
- expect(outcome.errors[:base]).
319
- to match_array ['X is required', 'Y is required']
328
+ expect(outcome.errors[:base])
329
+ .to match_array ['X is required', 'Y is required']
320
330
  end
321
331
  end
322
332
  end
@@ -326,4 +336,19 @@ describe ActiveInteraction::Base do
326
336
  expect { interaction.execute }.to raise_error NotImplementedError
327
337
  end
328
338
  end
339
+
340
+ context 'inheritance' do
341
+ it 'keeps the filters of the parent class' do
342
+ ParentInteraction = Class.new(ActiveInteraction::Base) do
343
+ boolean :x,
344
+ default: nil
345
+
346
+ def execute
347
+ inputs
348
+ end
349
+ end
350
+
351
+ expect(Class.new(ParentInteraction).run!).to eql(x: nil)
352
+ end
353
+ end
329
354
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe ActiveInteraction::Errors do
@@ -18,22 +20,22 @@ describe ActiveInteraction::Errors do
18
20
  describe '#add_sym' do
19
21
  it 'defaults to :invalid' do
20
22
  errors.add_sym(:attribute)
21
- expect(errors.symbolic).to eq({ attribute: [:invalid] })
23
+ expect(errors.symbolic[:attribute]).to eq [:invalid]
22
24
  end
23
25
 
24
26
  it 'adds a symbol' do
25
27
  errors.add_sym(:attribute, :symbol)
26
- expect(errors.symbolic).to eq({ attribute: [:symbol] })
28
+ expect(errors.symbolic[:attribute]).to eq [:symbol]
27
29
  end
28
30
 
29
31
  it 'accepts a message' do
30
32
  errors.add_sym(:attribute, :symbol, 'message')
31
- expect(errors.symbolic).to eq({ attribute: [:symbol] })
33
+ expect(errors.symbolic[:attribute]).to eq [:symbol]
32
34
  end
33
35
 
34
36
  it 'accepts a message and options' do
35
- errors.add_sym(:attribute, :symbol, 'message', { key: :value })
36
- expect(errors.symbolic).to eq({ attribute: [:symbol] })
37
+ errors.add_sym(:attribute, :symbol, 'message', key: :value)
38
+ expect(errors.symbolic[:attribute]).to eq [:symbol]
37
39
  end
38
40
 
39
41
  context 'calling #add' do
@@ -43,26 +45,26 @@ describe ActiveInteraction::Errors do
43
45
 
44
46
  it 'with the default' do
45
47
  errors.add_sym(:attribute)
46
- expect(errors).to have_received(:add).once.
47
- with(:attribute, :invalid, {})
48
+ expect(errors).to have_received(:add).once
49
+ .with(:attribute, :invalid, {})
48
50
  end
49
51
 
50
52
  it 'with a symbol' do
51
53
  errors.add_sym(:attribute, :symbol)
52
- expect(errors).to have_received(:add).once.
53
- with(:attribute, :symbol, {})
54
+ expect(errors).to have_received(:add).once
55
+ .with(:attribute, :symbol, {})
54
56
  end
55
57
 
56
58
  it 'with a symbol and message' do
57
59
  errors.add_sym(:attribute, :symbol, 'message')
58
- expect(errors).to have_received(:add).once.
59
- with(:attribute, 'message', {})
60
+ expect(errors).to have_received(:add).once
61
+ .with(:attribute, 'message', {})
60
62
  end
61
63
 
62
64
  it 'with a symbol, message and options' do
63
- errors.add_sym(:attribute, :symbol, 'message', { key: :value })
64
- expect(errors).to have_received(:add).once.
65
- with(:attribute, 'message', { key: :value })
65
+ errors.add_sym(:attribute, :symbol, 'message', key: :value)
66
+ expect(errors).to have_received(:add).once
67
+ .with(:attribute, 'message', key: :value)
66
68
  end
67
69
  end
68
70
  end
@@ -96,4 +98,36 @@ describe ActiveInteraction::Errors do
96
98
  expect(errors.symbolic).to be_empty
97
99
  end
98
100
  end
101
+
102
+ describe '#merge!' do
103
+ let(:other) { described_class.new(klass.new) }
104
+
105
+ context 'with an error' do
106
+ before do
107
+ other.add(:attribute)
108
+ end
109
+
110
+ it 'adds the error' do
111
+ errors.merge!(other)
112
+ expect(errors.messages[:attribute]).to eq ['is invalid']
113
+ end
114
+
115
+ it 'does not add duplicate errors' do
116
+ other.add(:attribute)
117
+ errors.merge!(other)
118
+ expect(errors.messages[:attribute]).to eq ['is invalid']
119
+ end
120
+ end
121
+
122
+ context 'with a symbolic error' do
123
+ before do
124
+ other.add_sym(:attribute)
125
+ end
126
+
127
+ it 'adds the error' do
128
+ errors.merge!(other)
129
+ expect(errors.symbolic[:attribute]).to eq [:invalid]
130
+ end
131
+ end
132
+ end
99
133
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  class ActiveInteraction::TestFilter < ActiveInteraction::Filter; end
@@ -7,9 +9,9 @@ describe ActiveInteraction::Filter, :filter do
7
9
 
8
10
  describe '.slug' do
9
11
  it 'raises an error' do
10
- expect {
12
+ expect do
11
13
  described_class.slug
12
- }.to raise_error ActiveInteraction::InvalidClassError
14
+ end.to raise_error ActiveInteraction::InvalidClassError
13
15
  end
14
16
  end
15
17
 
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe ActiveInteraction::ArrayFilter, :filter do
@@ -5,7 +7,12 @@ describe ActiveInteraction::ArrayFilter, :filter do
5
7
  it_behaves_like 'a filter'
6
8
 
7
9
  context 'with multiple nested filters' do
8
- let(:block) { Proc.new { array; array } }
10
+ let(:block) do
11
+ proc do
12
+ array
13
+ array
14
+ end
15
+ end
9
16
 
10
17
  it 'raises an error' do
11
18
  expect { filter }.to raise_error ActiveInteraction::InvalidFilterError
@@ -13,7 +20,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
13
20
  end
14
21
 
15
22
  context 'with a nested name' do
16
- let(:block) { Proc.new { array :a } }
23
+ let(:block) { proc { array :a } }
17
24
 
18
25
  it 'raises an error' do
19
26
  expect { filter }.to raise_error ActiveInteraction::InvalidFilterError
@@ -21,7 +28,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
21
28
  end
22
29
 
23
30
  context 'with a nested default' do
24
- let(:block) { Proc.new { array default: nil } }
31
+ let(:block) { proc { array default: nil } }
25
32
 
26
33
  it 'raises an error' do
27
34
  expect { filter }.to raise_error ActiveInteraction::InvalidDefaultError
@@ -46,7 +53,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
46
53
  end
47
54
 
48
55
  context 'with a nested filter' do
49
- let(:block) { Proc.new { array } }
56
+ let(:block) { proc { array } }
50
57
 
51
58
  context 'with an Array' do
52
59
  let(:value) { [] }
@@ -68,9 +75,9 @@ describe ActiveInteraction::ArrayFilter, :filter do
68
75
  let(:value) { [[], false, 0.0, {}, 0, '', :''] }
69
76
 
70
77
  it 'raises an error' do
71
- expect{
78
+ expect do
72
79
  filter.cast(value)
73
- }.to raise_error ActiveInteraction::InvalidValueError
80
+ end.to raise_error ActiveInteraction::InvalidValueError
74
81
  end
75
82
  end
76
83
  end