active_interaction 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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