active_interaction 0.1.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.
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +202 -0
- data/lib/active_interaction.rb +23 -0
- data/lib/active_interaction/base.rb +162 -0
- data/lib/active_interaction/errors.rb +6 -0
- data/lib/active_interaction/filter.rb +41 -0
- data/lib/active_interaction/filter_method.rb +17 -0
- data/lib/active_interaction/filter_methods.rb +26 -0
- data/lib/active_interaction/filters/array_filter.rb +56 -0
- data/lib/active_interaction/filters/boolean_filter.rb +30 -0
- data/lib/active_interaction/filters/date_filter.rb +31 -0
- data/lib/active_interaction/filters/date_time_filter.rb +31 -0
- data/lib/active_interaction/filters/file_filter.rb +38 -0
- data/lib/active_interaction/filters/float_filter.rb +32 -0
- data/lib/active_interaction/filters/hash_filter.rb +47 -0
- data/lib/active_interaction/filters/integer_filter.rb +31 -0
- data/lib/active_interaction/filters/model_filter.rb +40 -0
- data/lib/active_interaction/filters/string_filter.rb +25 -0
- data/lib/active_interaction/filters/time_filter.rb +44 -0
- data/lib/active_interaction/overload_hash.rb +11 -0
- data/lib/active_interaction/version.rb +3 -0
- data/spec/active_interaction/base_spec.rb +175 -0
- data/spec/active_interaction/filter_method_spec.rb +48 -0
- data/spec/active_interaction/filter_methods_spec.rb +30 -0
- data/spec/active_interaction/filter_spec.rb +29 -0
- data/spec/active_interaction/filters/array_filter_spec.rb +54 -0
- data/spec/active_interaction/filters/boolean_filter_spec.rb +40 -0
- data/spec/active_interaction/filters/date_filter_spec.rb +32 -0
- data/spec/active_interaction/filters/date_time_filter_spec.rb +32 -0
- data/spec/active_interaction/filters/file_filter_spec.rb +32 -0
- data/spec/active_interaction/filters/float_filter_spec.rb +40 -0
- data/spec/active_interaction/filters/hash_filter_spec.rb +57 -0
- data/spec/active_interaction/filters/integer_filter_spec.rb +32 -0
- data/spec/active_interaction/filters/model_filter_spec.rb +40 -0
- data/spec/active_interaction/filters/string_filter_spec.rb +16 -0
- data/spec/active_interaction/filters/time_filter_spec.rb +66 -0
- data/spec/active_interaction/integration/array_interaction_spec.rb +69 -0
- data/spec/active_interaction/integration/boolean_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/date_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/date_time_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/file_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/float_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/hash_interaction_spec.rb +69 -0
- data/spec/active_interaction/integration/integer_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/model_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/string_interaction_spec.rb +5 -0
- data/spec/active_interaction/integration/time_interaction_spec.rb +5 -0
- data/spec/active_interaction/overload_hash_spec.rb +41 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/filters.rb +37 -0
- data/spec/support/interactions.rb +79 -0
- metadata +278 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::Base do
|
4
|
+
let(:options) { {} }
|
5
|
+
subject(:interaction) { described_class.new(options) }
|
6
|
+
|
7
|
+
class InteractionWithAttribute < described_class
|
8
|
+
attr_reader :thing
|
9
|
+
|
10
|
+
validates :thing, presence: true
|
11
|
+
|
12
|
+
def execute
|
13
|
+
thing
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class InteractionWithFilter < described_class
|
18
|
+
float :thing
|
19
|
+
|
20
|
+
def execute
|
21
|
+
thing
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class InteractionWithFilters < described_class
|
26
|
+
float :thing1, :thing2
|
27
|
+
|
28
|
+
def execute; end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.new(options = {})' do
|
32
|
+
it 'does not allow :result as an option' do
|
33
|
+
options.merge!(result: nil)
|
34
|
+
expect { interaction }.to raise_error ArgumentError
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not allow "result" as an option' do
|
38
|
+
options.merge!('result' => nil)
|
39
|
+
expect { interaction }.to raise_error ArgumentError
|
40
|
+
end
|
41
|
+
|
42
|
+
describe InteractionWithAttribute do
|
43
|
+
let(:described_class) { InteractionWithAttribute }
|
44
|
+
let(:thing) { SecureRandom.hex }
|
45
|
+
|
46
|
+
context 'failing validations' do
|
47
|
+
before { options.merge!(thing: nil) }
|
48
|
+
|
49
|
+
it 'returns an invalid outcome' do
|
50
|
+
expect(interaction).to be_invalid
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'passing validations' do
|
55
|
+
before { options.merge!(thing: thing) }
|
56
|
+
|
57
|
+
it 'returns a valid outcome' do
|
58
|
+
expect(interaction).to be_valid
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'sets the attribute' do
|
62
|
+
expect(interaction.thing).to eq thing
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.method_missing(filter_type, *args, &block)' do
|
69
|
+
it 'raises an error for invalid filter types' do
|
70
|
+
expect {
|
71
|
+
class InteractionWithInvalidFilter < described_class
|
72
|
+
not_a_valid_filter_type :thing
|
73
|
+
def execute; end
|
74
|
+
end
|
75
|
+
}.to raise_error NoMethodError
|
76
|
+
end
|
77
|
+
|
78
|
+
describe InteractionWithFilter do
|
79
|
+
let(:described_class) { InteractionWithFilter }
|
80
|
+
|
81
|
+
it 'adds an attr_reader' do
|
82
|
+
expect(interaction).to respond_to :thing
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'adds an attr_writer' do
|
86
|
+
expect(interaction).to respond_to :thing=
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe InteractionWithFilters do
|
91
|
+
let(:described_class) { InteractionWithFilters }
|
92
|
+
|
93
|
+
%w(thing1 thing2).each do |thing|
|
94
|
+
it "adds an attr_reader for #{thing}" do
|
95
|
+
expect(interaction).to respond_to thing
|
96
|
+
end
|
97
|
+
|
98
|
+
it "adds an attr_writer for #{thing}" do
|
99
|
+
expect(interaction).to respond_to "#{thing}="
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe InteractionWithFilter do
|
106
|
+
let(:described_class) { InteractionWithFilter }
|
107
|
+
let(:thing) { rand }
|
108
|
+
|
109
|
+
describe '.run(options = {})' do
|
110
|
+
subject(:outcome) { described_class.run(options) }
|
111
|
+
|
112
|
+
it "returns an instance of #{described_class}" do
|
113
|
+
expect(outcome).to be_a described_class
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'failing validations' do
|
117
|
+
it 'returns an invalid outcome' do
|
118
|
+
expect(outcome).to be_invalid
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'sets the result to nil' do
|
122
|
+
expect(outcome.result).to be_nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'passing validations' do
|
127
|
+
before { options.merge!(thing: thing) }
|
128
|
+
|
129
|
+
it 'returns a valid outcome' do
|
130
|
+
expect(outcome).to be_valid
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'sets the result' do
|
134
|
+
expect(outcome.result).to eq thing
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '.run!(options = {})' do
|
140
|
+
subject(:result) { described_class.run!(options) }
|
141
|
+
|
142
|
+
context 'failing validations' do
|
143
|
+
it 'raises an error' do
|
144
|
+
expect { result }.to raise_error ActiveInteraction::InteractionInvalid
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'passing validations' do
|
149
|
+
before { options.merge!(thing: thing) }
|
150
|
+
|
151
|
+
it 'returns the result' do
|
152
|
+
expect(result).to eq thing
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#execute' do
|
159
|
+
it 'raises an error' do
|
160
|
+
expect { interaction.execute }.to raise_error NotImplementedError
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#new_record?' do
|
165
|
+
it 'returns true' do
|
166
|
+
expect(interaction).to be_new_record
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#persisted?' do
|
171
|
+
it 'returns false' do
|
172
|
+
expect(interaction).to_not be_persisted
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::FilterMethod do
|
4
|
+
describe '.new(method_name, *args, &block)' do
|
5
|
+
let(:method_name) { SecureRandom.hex }
|
6
|
+
let(:attribute) { nil }
|
7
|
+
let(:options) { {} }
|
8
|
+
let(:args) { [] }
|
9
|
+
let(:block) { nil }
|
10
|
+
subject(:filter_method) { described_class.new(method_name, *args, &block) }
|
11
|
+
|
12
|
+
shared_examples 'instance variable assignment' do
|
13
|
+
its(:method_name) { should equal method_name }
|
14
|
+
its(:attribute) { should equal attribute }
|
15
|
+
its(:options) { should eq options }
|
16
|
+
its(:block) { should equal block }
|
17
|
+
end
|
18
|
+
|
19
|
+
include_examples 'instance variable assignment'
|
20
|
+
|
21
|
+
context 'with an attribute' do
|
22
|
+
let(:attribute) { SecureRandom.hex.to_sym }
|
23
|
+
|
24
|
+
before { args << attribute }
|
25
|
+
|
26
|
+
include_examples 'instance variable assignment'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with options' do
|
30
|
+
let(:options) { { nil => nil } }
|
31
|
+
|
32
|
+
before { args << options }
|
33
|
+
|
34
|
+
include_examples 'instance variable assignment'
|
35
|
+
|
36
|
+
it 'does not allow :default' do
|
37
|
+
options.merge!(default: nil)
|
38
|
+
expect { filter_method }.to raise_error ArgumentError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with a block' do
|
43
|
+
let(:block) { Proc.new {} }
|
44
|
+
|
45
|
+
include_examples 'instance variable assignment'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::FilterMethods do
|
4
|
+
let(:block) { Proc.new {} }
|
5
|
+
subject(:filter_methods) { described_class.evaluate(&block) }
|
6
|
+
|
7
|
+
describe '.evaluate(&block)' do
|
8
|
+
it "returns an instance of #{described_class}" do
|
9
|
+
expect(filter_methods).to be_a described_class
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not add any filter methods' do
|
13
|
+
expect(filter_methods.count).to eq 0
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a filter method' do
|
17
|
+
let(:block) { Proc.new { boolean } }
|
18
|
+
|
19
|
+
it 'adds a filter method' do
|
20
|
+
expect(filter_methods.count).to eq 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#each' do
|
26
|
+
it 'returns an Enumerator' do
|
27
|
+
expect(filter_methods.each).to be_an Enumerator
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class TestFilter < Filter; end
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ActiveInteraction::Filter do
|
8
|
+
it_behaves_like 'a filter'
|
9
|
+
|
10
|
+
describe '.factory(type)' do
|
11
|
+
let(:result) { described_class.factory(type) }
|
12
|
+
|
13
|
+
context 'with a valid type' do
|
14
|
+
let(:type) { :test }
|
15
|
+
|
16
|
+
it 'returns the Class' do
|
17
|
+
expect(result).to eql ActiveInteraction::TestFilter
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with an invalid type' do
|
22
|
+
let(:type) { :not_a_valid_type }
|
23
|
+
|
24
|
+
it 'raises an error' do
|
25
|
+
expect { result }.to raise_error NoMethodError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::ArrayFilter do
|
4
|
+
include_context 'filters'
|
5
|
+
it_behaves_like 'a filter'
|
6
|
+
|
7
|
+
describe '.prepare(key, value, options = {}, &block)' do
|
8
|
+
context 'with an Array' do
|
9
|
+
let(:value) { [] }
|
10
|
+
|
11
|
+
it 'returns the Array' do
|
12
|
+
expect(result).to eql value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with block as a valid block' do
|
17
|
+
let(:block) { Proc.new { array } }
|
18
|
+
|
19
|
+
context 'with an Array of Arrays' do
|
20
|
+
let(:value) { [[]] }
|
21
|
+
|
22
|
+
it 'returns the Array' do
|
23
|
+
expect(result).to eql value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with an Array of anything else' do
|
28
|
+
let(:value) { [Object.new] }
|
29
|
+
|
30
|
+
it 'raises an error' do
|
31
|
+
expect { result }.to raise_error ActiveInteraction::InvalidValue
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with block as a nested block' do
|
37
|
+
let(:block) { Proc.new { array { array } } }
|
38
|
+
let(:value) { [[[]]] }
|
39
|
+
|
40
|
+
it 'returns the Array' do
|
41
|
+
expect(result).to eql value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with block as an invalid block' do
|
46
|
+
let(:block) { Proc.new { array; array } }
|
47
|
+
let(:value) { [] }
|
48
|
+
|
49
|
+
it 'raises an error' do
|
50
|
+
expect { result }.to raise_error ArgumentError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::BooleanFilter do
|
4
|
+
include_context 'filters'
|
5
|
+
it_behaves_like 'a filter'
|
6
|
+
|
7
|
+
describe '.prepare(key, value, options = {}, &block)' do
|
8
|
+
context 'with true' do
|
9
|
+
let(:value) { true }
|
10
|
+
|
11
|
+
it 'returns true' do
|
12
|
+
expect(result).to eql true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with false' do
|
17
|
+
let(:value) { false }
|
18
|
+
|
19
|
+
it 'returns false' do
|
20
|
+
expect(result).to eql false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with "1"' do
|
25
|
+
let(:value) { '1' }
|
26
|
+
|
27
|
+
it 'returns true' do
|
28
|
+
expect(result).to eql true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with "0"' do
|
33
|
+
let(:value) { '0' }
|
34
|
+
|
35
|
+
it 'returns false' do
|
36
|
+
expect(result).to eql false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::DateFilter do
|
4
|
+
include_context 'filters'
|
5
|
+
it_behaves_like 'a filter'
|
6
|
+
|
7
|
+
describe '.prepare(key, value, options = {}, &block)' do
|
8
|
+
context 'with a Date' do
|
9
|
+
let(:value) { Date.today }
|
10
|
+
|
11
|
+
it 'returns the Date' do
|
12
|
+
expect(result).to eql value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a valid String' do
|
17
|
+
let(:value) { '2001-01-01' }
|
18
|
+
|
19
|
+
it 'parses the String' do
|
20
|
+
expect(result).to eql Date.parse(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with an invalid String' do
|
25
|
+
let(:value) { 'not a valid Date' }
|
26
|
+
|
27
|
+
it 'raises an error' do
|
28
|
+
expect { result }.to raise_error ActiveInteraction::InvalidValue
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::DateTimeFilter do
|
4
|
+
include_context 'filters'
|
5
|
+
it_behaves_like 'a filter'
|
6
|
+
|
7
|
+
describe '.prepare(key, value, options = {}, &block)' do
|
8
|
+
context 'with a DateTime' do
|
9
|
+
let(:value) { DateTime.now }
|
10
|
+
|
11
|
+
it 'returns the DateTime' do
|
12
|
+
expect(result).to eql value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a valid String' do
|
17
|
+
let(:value) { '2001-01-01T01:01:01+01:01' }
|
18
|
+
|
19
|
+
it 'parses the String' do
|
20
|
+
expect(result).to eql DateTime.parse(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with an invalid String' do
|
25
|
+
let(:value) { 'not a valid DateTine' }
|
26
|
+
|
27
|
+
it 'raises an error' do
|
28
|
+
expect { result }.to raise_error ActiveInteraction::InvalidValue
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|