exel 0.9.0 → 1.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/.rubocop.yml +17 -0
- data/.rubocop_todo.yml +43 -0
- data/Guardfile +18 -11
- data/README.md +3 -0
- data/Rakefile +0 -1
- data/exel.gemspec +6 -5
- data/lib/exel/ast_node.rb +2 -2
- data/lib/exel/context.rb +16 -19
- data/lib/exel/deferred_context_value.rb +2 -2
- data/lib/exel/instruction.rb +2 -2
- data/lib/exel/job.rb +5 -5
- data/lib/exel/logging.rb +3 -3
- data/lib/exel/null_instruction.rb +1 -1
- data/lib/exel/processor_helper.rb +3 -5
- data/lib/exel/processors/async_processor.rb +3 -3
- data/lib/exel/providers/local_file_provider.rb +18 -0
- data/lib/exel/providers/threaded_async_provider.rb +13 -0
- data/lib/exel/{resource.rb → value.rb} +7 -11
- data/lib/exel/version.rb +1 -1
- data/lib/exel.rb +10 -1
- data/spec/exel/ast_node_spec.rb +3 -15
- data/spec/exel/context_spec.rb +40 -22
- data/spec/exel/job_spec.rb +8 -8
- data/spec/exel/logging_spec.rb +3 -3
- data/spec/exel/processors/async_processor_spec.rb +12 -4
- data/spec/exel/processors/split_processor_spec.rb +67 -67
- data/spec/exel/providers/local_async_provider_spec.rb +19 -0
- data/spec/exel/providers/local_file_provider_spec.rb +36 -0
- data/spec/exel/sequence_node_spec.rb +6 -13
- data/spec/exel/value_spec.rb +51 -0
- data/spec/exel_spec.rb +41 -0
- data/spec/spec_helper.rb +22 -3
- metadata +69 -40
- data/lib/exel/execution_worker.rb +0 -13
- data/lib/exel/handlers/s3_handler.rb +0 -43
- data/lib/exel/handlers/sidekiq_handler.rb +0 -21
- data/spec/exel/execution_worker_spec.rb +0 -13
- data/spec/exel/handlers/s3_handler_spec.rb +0 -49
- data/spec/exel/handlers/sidekiq_handler_spec.rb +0 -54
- data/spec/exel/resource_spec.rb +0 -51
data/spec/exel/context_spec.rb
CHANGED
@@ -1,29 +1,25 @@
|
|
1
1
|
module EXEL
|
2
2
|
describe Context do
|
3
|
-
subject(:context) { EXEL::Context.new(
|
3
|
+
subject(:context) { EXEL::Context.new(key1: '1', key2: 2) }
|
4
4
|
|
5
5
|
describe '#initialize' do
|
6
6
|
it 'should be able to initialize with a hash' do
|
7
|
-
expect(context.table[:
|
8
|
-
expect(context.table[:
|
7
|
+
expect(context.table[:key1]).to eq('1')
|
8
|
+
expect(context.table[:key2]).to eq(2)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '#serialize' do
|
13
|
-
|
14
|
-
|
15
|
-
before do
|
16
|
-
allow(Handlers::S3Handler).to receive(:new).and_return(handler) #TODO don't stub new
|
17
|
-
end
|
13
|
+
before { allow(Value).to receive(:upload) }
|
18
14
|
|
19
15
|
it 'should write the serialized context to a file and upload it' do
|
20
|
-
expect(
|
21
|
-
expect(
|
16
|
+
expect(Value).to receive(:remotize).with(context[:key1]).and_return('remote_value1')
|
17
|
+
expect(Value).to receive(:remotize).with(context[:key2]).and_return('remote_value2')
|
22
18
|
|
23
19
|
expect(SecureRandom).to receive(:uuid).and_return('uuid')
|
24
20
|
|
25
|
-
expect(
|
26
|
-
expect(file.read).to eq(Marshal.dump(Context.new(
|
21
|
+
expect(Value).to receive(:remotize) do |file|
|
22
|
+
expect(file.read).to eq(Marshal.dump(Context.new(key1: 'remote_value1', key2: 'remote_value2')))
|
27
23
|
expect(file.path).to include('uuid')
|
28
24
|
'file_uri'
|
29
25
|
end
|
@@ -40,26 +36,31 @@ module EXEL
|
|
40
36
|
|
41
37
|
describe '.deserialize' do
|
42
38
|
it 'should deserialize a given uri' do
|
43
|
-
uri = 'test_uri'
|
44
39
|
file = StringIO.new(Marshal.dump(context))
|
45
|
-
|
40
|
+
expect(Value).to receive(:localize).with('uri').and_return(file)
|
46
41
|
|
47
|
-
expect(Context.deserialize(uri)).to eq(context)
|
42
|
+
expect(Context.deserialize('uri')).to eq(context)
|
48
43
|
|
49
44
|
expect(file).to be_closed
|
50
45
|
end
|
51
46
|
end
|
52
47
|
|
53
48
|
describe '#[]' do
|
54
|
-
subject(:context) { EXEL::Context.new(key:
|
49
|
+
subject(:context) { EXEL::Context.new(key: 'value') }
|
55
50
|
|
56
|
-
it 'should return
|
51
|
+
it 'should return the value' do
|
57
52
|
expect(context[:key]).to eq('value')
|
58
53
|
end
|
59
54
|
|
55
|
+
it 'should localize the returned value' do
|
56
|
+
expect(Value).to receive(:localize).with('value').and_return('localized')
|
57
|
+
expect(context[:key]).to eq('localized')
|
58
|
+
end
|
59
|
+
|
60
60
|
it 'should store the localized value' do
|
61
|
+
allow(Value).to receive(:localize).with('value').and_return('localized')
|
61
62
|
context[:key]
|
62
|
-
expect(context.table[:key]).to eq('
|
63
|
+
expect(context.table[:key]).to eq('localized')
|
63
64
|
end
|
64
65
|
|
65
66
|
context 'DeferredContextValue object' do
|
@@ -70,7 +71,8 @@ module EXEL
|
|
70
71
|
expect(context[:deferred_value]).to eq(context[:key])
|
71
72
|
end
|
72
73
|
end
|
73
|
-
|
74
|
+
|
75
|
+
context 'in an array' do
|
74
76
|
it 'should return the lookup value from the context' do
|
75
77
|
deferred_context_value = DeferredContextValue.new[:key]
|
76
78
|
context[:array] = [1, 2, deferred_context_value]
|
@@ -78,11 +80,11 @@ module EXEL
|
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
|
-
context 'in hash' do
|
83
|
+
context 'in a hash' do
|
82
84
|
it 'should return the lookup value from the context' do
|
83
85
|
deferred_context_value = DeferredContextValue.new[:key]
|
84
86
|
context[:hash] = {hash_key: deferred_context_value}
|
85
|
-
expect(context[:hash]).to eq(
|
87
|
+
expect(context[:hash]).to eq(hash_key: context[:key])
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
@@ -92,10 +94,11 @@ module EXEL
|
|
92
94
|
context[:nested] = [{}, {hash_key: deferred_context_value}]
|
93
95
|
expect(context[:nested]).to eq([{}, {hash_key: context[:key]}])
|
94
96
|
end
|
97
|
+
|
95
98
|
it 'should lookup a deferred context value in an array nested in a hash' do
|
96
99
|
deferred_context_value = DeferredContextValue.new[:key]
|
97
100
|
context[:nested] = {hash_key: [1, deferred_context_value]}
|
98
|
-
expect(context[:nested]).to eq(
|
101
|
+
expect(context[:nested]).to eq(hash_key: [1, context[:key]])
|
99
102
|
end
|
100
103
|
end
|
101
104
|
end
|
@@ -147,5 +150,20 @@ module EXEL
|
|
147
150
|
it { is_expected.to eq(context.dup) }
|
148
151
|
end
|
149
152
|
|
153
|
+
describe 'include?' do
|
154
|
+
subject(:context) { EXEL::Context.new(key1: 1, key2: 2, key3: 3) }
|
155
|
+
|
156
|
+
context 'context contains all key value pairs' do
|
157
|
+
it 'should return true' do
|
158
|
+
expect(context).to include(key1: 1, key2: 2)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'context does not contain all key value pairs' do
|
163
|
+
it 'should return true' do
|
164
|
+
expect(context).not_to include(foo: 'bar', key2: 2)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
150
168
|
end
|
151
169
|
end
|
data/spec/exel/job_spec.rb
CHANGED
@@ -2,7 +2,7 @@ module EXEL
|
|
2
2
|
describe Job do
|
3
3
|
describe '.define' do
|
4
4
|
let(:ast) { instance_double(SequenceNode, run: nil, start: nil) }
|
5
|
-
let(:block) {
|
5
|
+
let(:block) { proc {} }
|
6
6
|
|
7
7
|
after { Job.registry.clear }
|
8
8
|
|
@@ -37,7 +37,7 @@ module EXEL
|
|
37
37
|
|
38
38
|
context 'with a job name' do
|
39
39
|
context 'of a defined job' do
|
40
|
-
let(:block) {
|
40
|
+
let(:block) { proc {} }
|
41
41
|
|
42
42
|
before do
|
43
43
|
allow(Job).to receive(:registry).and_return(test_job: block)
|
@@ -103,7 +103,7 @@ module EXEL
|
|
103
103
|
|
104
104
|
context 'given DSL code as a proc' do
|
105
105
|
it 'should eval the code as a block' do
|
106
|
-
dsl_proc =
|
106
|
+
dsl_proc = proc {}
|
107
107
|
expect(parser).to receive(:instance_eval) do |*_args, &block|
|
108
108
|
expect(block).to eq(dsl_proc)
|
109
109
|
end
|
@@ -122,12 +122,12 @@ module EXEL
|
|
122
122
|
end
|
123
123
|
|
124
124
|
it 'should return the parsed AST' do
|
125
|
-
expect(Job::Parser.parse(
|
125
|
+
expect(Job::Parser.parse(proc {})).to eq(ast)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
129
|
describe '#process' do
|
130
|
-
let(:block) {
|
130
|
+
let(:block) { proc {} }
|
131
131
|
|
132
132
|
before do
|
133
133
|
allow(Job::Parser).to receive(:parse).and_return(ast)
|
@@ -174,8 +174,8 @@ module EXEL
|
|
174
174
|
end
|
175
175
|
|
176
176
|
[
|
177
|
-
|
178
|
-
|
177
|
+
{method: :async, processor: Processors::AsyncProcessor},
|
178
|
+
{method: :split, processor: Processors::SplitProcessor}
|
179
179
|
].each do |data|
|
180
180
|
describe "##{data[:method]}" do
|
181
181
|
before do
|
@@ -184,7 +184,7 @@ module EXEL
|
|
184
184
|
|
185
185
|
it "should create a #{data[:method]} instruction" do
|
186
186
|
expect(Instruction).to receive(:new).with(data[:method].to_s, data[:processor], {arg1: 'arg1_value'}, ast)
|
187
|
-
parser.send(data[:method],
|
187
|
+
parser.send(data[:method], arg1: 'arg1_value') {}
|
188
188
|
end
|
189
189
|
|
190
190
|
it 'should parse the block given' do
|
data/spec/exel/logging_spec.rb
CHANGED
@@ -21,8 +21,8 @@ module EXEL
|
|
21
21
|
|
22
22
|
it 'should initialize the logger on first read if not already set' do
|
23
23
|
EXEL.configure do |config|
|
24
|
-
config
|
25
|
-
config
|
24
|
+
config.log_level = :warn
|
25
|
+
config.log_filename = 'log.txt'
|
26
26
|
end
|
27
27
|
|
28
28
|
logger = instance_double(Logger)
|
@@ -33,4 +33,4 @@ module EXEL
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
@@ -1,16 +1,24 @@
|
|
1
1
|
module EXEL
|
2
2
|
module Processors
|
3
3
|
describe AsyncProcessor do
|
4
|
-
subject(:processor) {
|
4
|
+
subject(:processor) { described_class.new(context) }
|
5
5
|
let(:context) { EXEL::Context.new }
|
6
6
|
let(:block) { instance_double(SequenceNode) }
|
7
7
|
|
8
|
+
before do
|
9
|
+
allow(EXEL).to receive(:async_provider).and_return(EXEL::Providers::DummyAsyncProvider)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'looks up the async provider on initialization' do
|
13
|
+
expect(processor.provider).to be_an_instance_of(EXEL::Providers::DummyAsyncProvider)
|
14
|
+
end
|
15
|
+
|
8
16
|
describe '#process' do
|
9
|
-
it '
|
10
|
-
expect(processor.
|
17
|
+
it 'calls do_async on the async provider' do
|
18
|
+
expect(processor.provider).to receive(:do_async).with(block)
|
11
19
|
processor.process(block)
|
12
20
|
end
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
16
|
-
end
|
24
|
+
end
|
@@ -1,90 +1,90 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
module EXEL
|
2
|
+
module Processors
|
3
|
+
describe SplitProcessor do
|
4
|
+
let(:chunk_file) { instance_double(File) }
|
5
|
+
let(:file) { create_file(1) }
|
6
|
+
let(:context) { Context.new(resource: file) }
|
7
|
+
let(:callback) { instance_double(SequenceNode) }
|
8
|
+
subject(:splitter) { SplitProcessor.new(context) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow_any_instance_of(StringIO).to receive(:path).and_return('/text.txt')
|
12
|
+
allow(File).to receive(:delete)
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
describe '#process' do
|
16
|
+
let(:file) { create_file(3) }
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
it 'should process file with 3 lines line by line' do
|
19
|
+
allow(CSV).to receive(:foreach).and_yield('line0').and_yield('line1').and_yield('line2')
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
3.times do |i|
|
22
|
+
expect(splitter).to receive(:process_line).with("line#{i}", callback)
|
23
|
+
end
|
24
|
+
expect(splitter).to receive(:process_line).with(:eof, callback)
|
25
25
|
|
26
|
-
|
26
|
+
expect(File).to receive(:delete).with(file.path)
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
splitter.process(callback)
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
it 'should abort parsing the csv file if it is malformed' do
|
32
|
+
allow(CSV).to receive(:foreach).and_raise(CSV::MalformedCSVError)
|
33
|
+
expect(splitter).to receive(:process_line).with(:eof, callback)
|
34
34
|
|
35
|
-
|
36
|
-
end
|
35
|
+
splitter.process(callback)
|
37
36
|
end
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
39
|
+
describe '#process_line' do
|
40
|
+
[
|
41
|
+
{input: 1, chunks: %W(0\n)},
|
42
|
+
{input: 3, chunks: %W(0\n1\n 2\n)},
|
43
|
+
{input: 4, chunks: %W(0\n1\n 2\n3\n)}
|
44
|
+
].each do |data|
|
45
|
+
it "should produce #{data[:chunks].size} chunks with #{data[:input]} input lines" do
|
46
|
+
splitter.chunk_size = 2
|
47
|
+
|
48
|
+
data[:chunks].each do |chunk|
|
49
|
+
expect(splitter).to receive(:generate_chunk).with(chunk).and_return(chunk_file)
|
50
|
+
expect(callback).to receive(:run).with(context) do
|
51
|
+
expect(context[:resource]).to eq(chunk_file)
|
53
52
|
end
|
54
|
-
|
55
|
-
data[:input].times { |i| splitter.process_line([i.to_s], callback) }
|
56
|
-
splitter.process_line(:eof, callback)
|
57
53
|
end
|
54
|
+
|
55
|
+
data[:input].times { |i| splitter.process_line([i.to_s], callback) }
|
56
|
+
splitter.process_line(:eof, callback)
|
58
57
|
end
|
59
58
|
end
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
describe '#generate_chunk' do
|
62
|
+
it 'should create a file with the contents of the given string' do
|
63
|
+
file = splitter.generate_chunk('abc')
|
64
|
+
content = file.read
|
65
|
+
expect(content).to eq('abc')
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
68
|
+
it 'should create a file with a unique name' do
|
69
|
+
3.times do |i|
|
70
|
+
index = i + 1
|
71
|
+
file = splitter.generate_chunk("#{index}")
|
72
|
+
file_name = splitter.filename(file)
|
73
|
+
expect(file_name).to include("text_#{index}_")
|
75
74
|
end
|
76
75
|
end
|
76
|
+
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
lines.times do |i|
|
82
|
-
line = CSV.generate_line(["line#{i}"])
|
83
|
-
content << line
|
84
|
-
end
|
78
|
+
def create_file(lines)
|
79
|
+
content = ''
|
85
80
|
|
86
|
-
|
81
|
+
lines.times do |i|
|
82
|
+
line = CSV.generate_line(["line#{i}"])
|
83
|
+
content << line
|
87
84
|
end
|
85
|
+
|
86
|
+
StringIO.new content
|
88
87
|
end
|
89
88
|
end
|
90
89
|
end
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module EXEL
|
2
|
+
module Providers
|
3
|
+
describe ThreadedAsyncProvider do
|
4
|
+
subject { described_class.new(context) }
|
5
|
+
let(:context) { EXEL::Context.new }
|
6
|
+
|
7
|
+
describe '#do_async' do
|
8
|
+
let(:dsl_block) { instance_double(ASTNode) }
|
9
|
+
|
10
|
+
it 'runs the block in a new thread' do
|
11
|
+
expect(dsl_block).to receive(:start).with(context)
|
12
|
+
expect(Thread).to receive(:new).and_yield
|
13
|
+
|
14
|
+
subject.do_async(dsl_block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module EXEL
|
2
|
+
module Providers
|
3
|
+
describe LocalFileProvider do
|
4
|
+
let(:file) { instance_double(File, path: '/path/to/file') }
|
5
|
+
|
6
|
+
describe '#upload' do
|
7
|
+
it 'returns a file:// URI for the file' do
|
8
|
+
expect(subject.upload(file)).to eq('file:///path/to/file')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#download' do
|
13
|
+
it 'returns the file indicated by the URI' do
|
14
|
+
expect(File).to receive(:open).with('/path/to/file').and_return(file)
|
15
|
+
expect(subject.download('file:///path/to/file')).to eq(file)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'doesn`t accept URIs for schemes other than file://' do
|
19
|
+
expect { subject.download('s3://') }.to raise_error 'URI must begin with "file://"'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.remote?' do
|
24
|
+
it 'returns true for file:// URIs' do
|
25
|
+
expect(LocalFileProvider.remote?('file:///path/to/file')).to be_truthy
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns false for anything else' do
|
29
|
+
expect(LocalFileProvider.remote?('s3://file')).to be_falsey
|
30
|
+
expect(LocalFileProvider.remote?(1)).to be_falsey
|
31
|
+
expect(LocalFileProvider.remote?(nil)).to be_falsey
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,23 +1,16 @@
|
|
1
1
|
module EXEL
|
2
2
|
describe SequenceNode do
|
3
|
-
|
3
|
+
subject(:node) { described_class.new(instance_double(ASTNode), instance_double(ASTNode)) }
|
4
|
+
let(:context) { instance_double(EXEL::Context) }
|
4
5
|
|
5
|
-
|
6
|
-
@node_2 = instance_double(ASTNode)
|
7
|
-
@node_3 = instance_double(ASTNode)
|
8
|
-
@node_1 = SequenceNode.new(@node_2, @node_3)
|
9
|
-
end
|
10
|
-
|
11
|
-
it { is_expected.to be_kind_of(ASTNode) }
|
6
|
+
it { is_expected.to be_an(ASTNode) }
|
12
7
|
|
13
8
|
describe '#run' do
|
14
|
-
before { build_tree }
|
15
|
-
|
16
9
|
it 'should run each child node in sequence' do
|
17
|
-
expect(
|
18
|
-
expect(
|
10
|
+
expect(node.children.first).to receive(:run).with(context).once.ordered
|
11
|
+
expect(node.children.last).to receive(:run).with(context).once.ordered
|
19
12
|
|
20
|
-
|
13
|
+
node.run(context)
|
21
14
|
end
|
22
15
|
end
|
23
16
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module EXEL
|
2
|
+
describe Value do
|
3
|
+
let(:uri) { 's3://test_file.csv' }
|
4
|
+
|
5
|
+
before { allow(EXEL).to receive(:remote_provider).and_return(EXEL::Providers::DummyRemoteProvider) }
|
6
|
+
|
7
|
+
describe '.remotize' do
|
8
|
+
context 'when the value is not a file' do
|
9
|
+
it 'returns the value' do
|
10
|
+
expect(Value.remotize('test')).to eq('test')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
[File, Tempfile].each do |file_class|
|
15
|
+
context "when the value is an instance of #{file_class}" do
|
16
|
+
let(:file) { instance_double(file_class) }
|
17
|
+
|
18
|
+
before { allow(file).to receive(:is_a?) { |klass| klass == file_class } }
|
19
|
+
|
20
|
+
it 'uploads the file using the remote provider' do
|
21
|
+
expect_any_instance_of(EXEL::Providers::DummyRemoteProvider).to receive(:upload).with(file)
|
22
|
+
Value.remotize(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns the URI of the uploaded file' do
|
26
|
+
allow_any_instance_of(EXEL::Providers::DummyRemoteProvider).to receive(:upload).with(file).and_return(uri)
|
27
|
+
expect(Value.remotize(file)).to eq(uri)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.localize' do
|
34
|
+
context 'with a local value' do
|
35
|
+
it 'returns the value' do
|
36
|
+
expect(Value.localize('test')).to eq('test')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with a remote file' do
|
41
|
+
it 'returns the downloaded file' do
|
42
|
+
expect(EXEL::Providers::DummyRemoteProvider).to receive(:remote?).with(uri).and_return(true)
|
43
|
+
file = double(:file)
|
44
|
+
expect_any_instance_of(EXEL::Providers::DummyRemoteProvider).to receive(:download).with(uri).and_return(file)
|
45
|
+
|
46
|
+
expect(Value.localize(uri)).to eq(file)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/spec/exel_spec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
describe EXEL do
|
2
|
+
describe '.async_provider' do
|
3
|
+
context 'with no async provider set in the configuration' do
|
4
|
+
it 'defaults to ThreadedAsyncProvider' do
|
5
|
+
expect(EXEL.async_provider).to eq(EXEL::Providers::ThreadedAsyncProvider)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'with an async provider set in the configuration' do
|
10
|
+
before do
|
11
|
+
EXEL.configure do |config|
|
12
|
+
config.async_provider = EXEL::Providers::DummyAsyncProvider
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns the configured async provider' do
|
17
|
+
expect(EXEL.async_provider).to eq(EXEL::Providers::DummyAsyncProvider)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.remote_provider' do
|
23
|
+
context 'with no remote provider set in the configuration' do
|
24
|
+
it 'defaults to NullRemoteProvider' do
|
25
|
+
expect(EXEL.remote_provider).to eq(EXEL::Providers::LocalFileProvider)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with no remote provider set in the configuration' do
|
30
|
+
before do
|
31
|
+
EXEL.configure do |config|
|
32
|
+
config.remote_provider = EXEL::Providers::DummyRemoteProvider
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns the configurated remote provider' do
|
37
|
+
expect(EXEL.remote_provider).to eq(EXEL::Providers::DummyRemoteProvider)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,25 @@ Dir[File.expand_path('../../lib/**/*.rb', __FILE__)].each { |f| require f }
|
|
2
2
|
|
3
3
|
EXEL.logger = nil
|
4
4
|
|
5
|
-
EXEL
|
6
|
-
|
7
|
-
|
5
|
+
module EXEL
|
6
|
+
module Providers
|
7
|
+
class DummyAsyncProvider
|
8
|
+
def initialize(_context)
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_async(_block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class DummyRemoteProvider
|
16
|
+
def upload(_file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def download(_uri)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.remote?(_uri)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|