exel 1.2.1 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +4 -4
- data/.gitignore +1 -2
- data/.rubocop.yml +23 -14
- data/.rubocop_airbnb.yml +2 -0
- data/.rubocop_todo.yml +1 -13
- data/.travis.yml +26 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +118 -0
- data/Guardfile +1 -0
- data/README.md +96 -31
- data/Rakefile +2 -0
- data/exel.gemspec +7 -7
- data/lib/exel.rb +7 -1
- data/lib/exel/ast_node.rb +6 -10
- data/lib/exel/context.rb +4 -1
- data/lib/exel/deferred_context_value.rb +3 -1
- data/lib/exel/error/job_termination.rb +12 -0
- data/lib/exel/events.rb +6 -0
- data/lib/exel/instruction.rb +5 -2
- data/lib/exel/instruction_node.rb +2 -0
- data/lib/exel/job.rb +8 -4
- data/lib/exel/listen_instruction.rb +2 -0
- data/lib/exel/logging.rb +24 -1
- data/lib/exel/logging/logger_wrapper.rb +31 -0
- data/lib/exel/logging_helper.rb +36 -0
- data/lib/exel/middleware/chain.rb +67 -0
- data/lib/exel/middleware/logging.rb +30 -0
- data/lib/exel/null_instruction.rb +2 -0
- data/lib/exel/processor_helper.rb +9 -1
- data/lib/exel/processors/async_processor.rb +2 -8
- data/lib/exel/processors/run_processor.rb +2 -6
- data/lib/exel/processors/split_processor.rb +15 -10
- data/lib/exel/providers/local_file_provider.rb +9 -6
- data/lib/exel/providers/threaded_async_provider.rb +2 -0
- data/lib/exel/remote_value.rb +11 -0
- data/lib/exel/sequence_node.rb +2 -0
- data/lib/exel/value.rb +2 -0
- data/lib/exel/version.rb +3 -1
- data/spec/exel/ast_node_spec.rb +48 -27
- data/spec/exel/context_spec.rb +77 -77
- data/spec/exel/deferred_context_value_spec.rb +42 -42
- data/spec/exel/events_spec.rb +68 -59
- data/spec/exel/instruction_node_spec.rb +17 -16
- data/spec/exel/instruction_spec.rb +49 -42
- data/spec/exel/job_spec.rb +99 -84
- data/spec/exel/listen_instruction_spec.rb +11 -10
- data/spec/exel/logging/logger_wrapper_spec.rb +93 -0
- data/spec/exel/logging_helper_spec.rb +24 -0
- data/spec/exel/logging_spec.rb +69 -24
- data/spec/exel/middleware/chain_spec.rb +65 -0
- data/spec/exel/middleware/logging_spec.rb +31 -0
- data/spec/exel/middleware_spec.rb +68 -0
- data/spec/exel/null_instruction_spec.rb +4 -4
- data/spec/exel/processors/async_processor_spec.rb +17 -18
- data/spec/exel/processors/run_processor_spec.rb +10 -11
- data/spec/exel/processors/split_processor_spec.rb +99 -74
- data/spec/exel/providers/local_file_provider_spec.rb +26 -28
- data/spec/exel/providers/threaded_async_provider_spec.rb +37 -38
- data/spec/exel/sequence_node_spec.rb +12 -11
- data/spec/exel/value_spec.rb +33 -33
- data/spec/exel_spec.rb +9 -7
- data/spec/integration/integration_spec.rb +3 -1
- data/spec/spec_helper.rb +4 -2
- data/spec/support/integration_test_classes.rb +4 -3
- metadata +37 -48
@@ -1,65 +1,65 @@
|
|
1
|
-
|
2
|
-
describe DeferredContextValue do
|
3
|
-
subject(:deferred_value) { DeferredContextValue.new }
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
describe EXEL::DeferredContextValue do
|
4
|
+
subject(:deferred_value) { EXEL::DeferredContextValue.new }
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
describe '.resolve' do
|
7
|
+
subject(:deferred_value) { EXEL::DeferredContextValue.new[:key] }
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
context 'at the top level' do
|
10
|
+
let(:context) { {key: 'value', deferred_value: deferred_value} }
|
11
|
+
|
12
|
+
it 'returns the lookup value from the context' do
|
13
|
+
expect(EXEL::DeferredContextValue.resolve(context[:deferred_value], context)).to eq(context[:key])
|
14
14
|
end
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
context 'in an array' do
|
18
|
+
let(:context) { {key: 'value', array: [1, 2, deferred_value]} }
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
end
|
20
|
+
it 'returns the lookup value from the context' do
|
21
|
+
expect(EXEL::DeferredContextValue.resolve(context[:array], context)).to eq([1, 2, context[:key]])
|
22
22
|
end
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
context 'in a hash' do
|
26
|
+
let(:context) { {key: 'value', hash: {hash_key: deferred_value}} }
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
28
|
+
it 'returns the lookup value from the context' do
|
29
|
+
expect(EXEL::DeferredContextValue.resolve(context[:hash], context)).to eq(hash_key: context[:key])
|
30
30
|
end
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
context 'in a hash nested in an array' do
|
34
|
+
let(:context) { {key: 'value', nested: [{}, {hash_key: deferred_value}]} }
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
36
|
+
it 'looks up a deferred context value in a hash nested in an array' do
|
37
|
+
expect(EXEL::DeferredContextValue.resolve(context[:nested], context)).to eq([{}, {hash_key: context[:key]}])
|
38
38
|
end
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
context 'in an array nested in a hash' do
|
42
|
+
let(:context) { {key: 'value', nested: {hash_key: [1, deferred_value]}} }
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
44
|
+
it 'looks up a deferred context value in an array nested in a hash' do
|
45
|
+
expect(EXEL::DeferredContextValue.resolve(context[:nested], context)).to eq(hash_key: [1, context[:key]])
|
46
46
|
end
|
47
47
|
end
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
50
|
+
describe '#[]' do
|
51
|
+
it 'stores the given key in the keys attribute' do
|
52
|
+
deferred_value[:top_level_key]['sub_key']
|
53
|
+
expect(deferred_value.keys).to eq([:top_level_key, 'sub_key'])
|
54
54
|
end
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
57
|
+
describe '#get' do
|
58
|
+
it 'looks up the value of the keys attribute in the passed-in context' do
|
59
|
+
allow(deferred_value).to receive(:keys).and_return([:top_level_key, 'sub_key'])
|
60
|
+
value = 'example_value'
|
61
|
+
context = EXEL::Context.new(top_level_key: {'sub_key' => value})
|
62
|
+
expect(deferred_value.get(context)).to eq(value)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
data/spec/exel/events_spec.rb
CHANGED
@@ -1,88 +1,97 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe EXEL::Events do
|
4
|
+
class EventTest
|
5
|
+
include EXEL::Events
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
5
9
|
end
|
10
|
+
end
|
6
11
|
|
7
|
-
|
8
|
-
let(:event_listener) { double(:event_listener) }
|
9
|
-
let(:context) { EXEL::Context.new(Events::LISTENERS_KEY => {event: [event_listener]}) }
|
12
|
+
subject(:events) { EventTest.new(context) }
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
let(:context) { EXEL::Context.new }
|
14
|
+
let(:event_listener) { double(:event_listener) }
|
15
|
+
let(:context) { EXEL::Context.new(EXEL::Events::LISTENERS_KEY => {event: [event_listener]}) }
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|
17
|
+
it 'defines an attr_reader for context on the class it is included in' do
|
18
|
+
expect(events.context).to eq(context)
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
describe '#register_listener' do
|
22
|
+
context 'when no listeners have been defined' do
|
23
|
+
let(:context) { EXEL::Context.new }
|
24
|
+
|
25
|
+
it 'adds a new listener to the context' do
|
26
|
+
events.register_listener(context, :event, event_listener)
|
27
|
+
expect(context[EXEL::Events::LISTENERS_KEY].fetch(:event)).to contain_exactly(event_listener)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
it 'registers multiple listeners for the same event' do
|
32
|
+
new_listener = double(:event_listener2)
|
33
|
+
events.register_listener(context, :event, new_listener)
|
34
|
+
expect(context[EXEL::Events::LISTENERS_KEY].fetch(:event)).to contain_exactly(event_listener, new_listener)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#trigger' do
|
39
|
+
let(:context) { EXEL::Context.new }
|
40
|
+
let(:data) { {foo: 1} }
|
31
41
|
|
32
|
-
|
42
|
+
before { allow(events).to receive(:context).and_return(context) }
|
33
43
|
|
34
|
-
|
35
|
-
|
36
|
-
|
44
|
+
context 'when no events have been registered' do
|
45
|
+
it 'does not trigger anything' do
|
46
|
+
expect(event_listener).not_to receive(:event)
|
37
47
|
|
38
|
-
|
39
|
-
end
|
48
|
+
events.trigger(:event, data)
|
40
49
|
end
|
50
|
+
end
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
52
|
+
context 'with a single listener registered for the event' do
|
53
|
+
before do
|
54
|
+
events.register_listener(context, :event, event_listener)
|
55
|
+
end
|
46
56
|
|
47
|
-
|
48
|
-
|
57
|
+
it 'calls the listener with the context and event data' do
|
58
|
+
expect(event_listener).to receive(:event).with(context, data)
|
49
59
|
|
50
|
-
|
51
|
-
|
60
|
+
events.trigger(:event, data)
|
61
|
+
end
|
52
62
|
|
53
|
-
|
54
|
-
|
63
|
+
it 'passes an empty hash if no data was given' do
|
64
|
+
expect(event_listener).to receive(:event).with(context, {})
|
55
65
|
|
56
|
-
|
57
|
-
end
|
66
|
+
events.trigger(:event)
|
58
67
|
end
|
68
|
+
end
|
59
69
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
70
|
+
context 'with no listeners registered for the event' do
|
71
|
+
before do
|
72
|
+
events.register_listener(context, :other_event, event_listener)
|
73
|
+
end
|
64
74
|
|
65
|
-
|
66
|
-
|
75
|
+
it 'does not trigger anything' do
|
76
|
+
expect(event_listener).not_to receive(:event)
|
67
77
|
|
68
|
-
|
69
|
-
end
|
78
|
+
events.trigger(:event, data)
|
70
79
|
end
|
80
|
+
end
|
71
81
|
|
72
|
-
|
73
|
-
|
82
|
+
context 'with multiple listeners registered for the event' do
|
83
|
+
let(:event_listener2) { double(:event_listener2) }
|
74
84
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
85
|
+
before do
|
86
|
+
events.register_listener(context, :event, event_listener)
|
87
|
+
events.register_listener(context, :event, event_listener2)
|
88
|
+
end
|
79
89
|
|
80
|
-
|
81
|
-
|
82
|
-
|
90
|
+
it 'calls each listener with the context and event data' do
|
91
|
+
expect(event_listener).to receive(:event).with(context, data)
|
92
|
+
expect(event_listener2).to receive(:event).with(context, data)
|
83
93
|
|
84
|
-
|
85
|
-
end
|
94
|
+
events.trigger(:event, data)
|
86
95
|
end
|
87
96
|
end
|
88
97
|
end
|
@@ -1,22 +1,23 @@
|
|
1
|
-
|
2
|
-
describe InstructionNode do
|
3
|
-
let(:context) { {} }
|
4
|
-
let(:instruction) { instance_double(Instruction, execute: nil) }
|
5
|
-
let(:child) { instance_double(ASTNode) }
|
6
|
-
subject(:node) { InstructionNode.new(instruction, [child]) }
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
3
|
+
describe EXEL::InstructionNode do
|
4
|
+
subject(:node) { EXEL::InstructionNode.new(instruction, children: [child]) }
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
node.run(context)
|
14
|
-
end
|
6
|
+
let(:context) { {} }
|
7
|
+
let(:instruction) { instance_double(EXEL::Instruction, execute: nil) }
|
8
|
+
let(:child) { instance_double(EXEL::ASTNode) }
|
15
9
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
it { is_expected.to be_kind_of(EXEL::ASTNode) }
|
11
|
+
|
12
|
+
describe '#run' do
|
13
|
+
it 'only executes the instruction' do
|
14
|
+
expect(instruction).to receive(:execute).with(context).once
|
15
|
+
node.run(context)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'does not run it`s children' do
|
19
|
+
expect(child).not_to receive(:run)
|
20
|
+
node.run(context)
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
@@ -1,57 +1,64 @@
|
|
1
|
-
|
2
|
-
describe Instruction do
|
3
|
-
subject(:instruction) { EXEL::Instruction.new(processor_class, args) }
|
4
|
-
let(:processor_class) { double(:processor_class, new: processor_instance) }
|
5
|
-
let(:processor_instance) { double(:processor_instance, process: nil) }
|
6
|
-
let(:args) { {arg1: 'arg_value1', arg2: {}} }
|
7
|
-
let(:context) { {context_key: 'context_value'} }
|
8
|
-
|
9
|
-
describe '#execute' do
|
10
|
-
it 'calls process on an instance of the processor class' do
|
11
|
-
expect(processor_class).to receive(:new).and_return(processor_instance)
|
12
|
-
expect(processor_instance).to receive(:process)
|
1
|
+
# frozen_string_literal: true
|
13
2
|
|
14
|
-
|
15
|
-
|
3
|
+
describe EXEL::Instruction do
|
4
|
+
subject(:instruction) { EXEL::Instruction.new(processor_class, args) }
|
16
5
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
6
|
+
let(:processor_class) { double(:processor_class, new: processor_instance) }
|
7
|
+
let(:processor_instance) { double(:processor_instance, process: nil) }
|
8
|
+
let(:args) { {arg1: 'arg_value1', arg2: {}} }
|
9
|
+
let(:context) { {context_key: 'context_value'} }
|
22
10
|
|
23
|
-
|
24
|
-
|
11
|
+
describe '#execute' do
|
12
|
+
it 'calls process on an instance of the processor class' do
|
13
|
+
expect(processor_class).to receive(:new).and_return(processor_instance)
|
14
|
+
expect(processor_instance).to receive(:process)
|
25
15
|
|
26
|
-
|
27
|
-
|
28
|
-
|
16
|
+
instruction.execute(context)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'invokes the middleware chain' do
|
20
|
+
expect(EXEL.middleware).to receive(:invoke).with(processor_class, context, args)
|
21
|
+
instruction.execute(context)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does not pass a copy of the context' do
|
25
|
+
allow(processor_class).to receive(:new) do |context_arg|
|
26
|
+
expect(context_arg).to be(context)
|
27
|
+
processor_instance
|
29
28
|
end
|
30
29
|
|
31
|
-
context
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
instruction.execute(context)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'adds args to the context' do
|
34
|
+
instruction.execute(context)
|
35
|
+
expect(context.keys).to include(*args.keys)
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with args' do
|
39
|
+
it 'passes the args to the processor' do
|
40
|
+
expect(processor_class).to receive(:new).with(hash_including(args))
|
41
|
+
instruction.execute(context)
|
36
42
|
end
|
43
|
+
end
|
37
44
|
|
38
|
-
|
39
|
-
|
45
|
+
context 'without args' do
|
46
|
+
let(:args) { nil }
|
40
47
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
48
|
+
it 'passes only the context to the processor' do
|
49
|
+
expect(processor_class).to receive(:new).with(context)
|
50
|
+
instruction.execute(context)
|
45
51
|
end
|
52
|
+
end
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
subject(:instruction) { EXEL::Instruction.new(processor_class, args, subtree) }
|
54
|
+
context 'with a subtree' do
|
55
|
+
subject(:instruction) { EXEL::Instruction.new(processor_class, args, subtree: subtree) }
|
50
56
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
57
|
+
let(:subtree) { double(:subtree) }
|
58
|
+
|
59
|
+
it 'passes the subtree to the processor' do
|
60
|
+
expect(processor_instance).to receive(:process).with(subtree)
|
61
|
+
instruction.execute(context)
|
55
62
|
end
|
56
63
|
end
|
57
64
|
end
|
data/spec/exel/job_spec.rb
CHANGED
@@ -1,104 +1,119 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe EXEL::Job do
|
4
|
+
describe '.define' do
|
5
|
+
let(:ast) { instance_double(EXEL::SequenceNode, run: nil, start: nil) }
|
6
|
+
let(:block) { proc {} }
|
7
|
+
|
8
|
+
after { EXEL::Job.registry.clear }
|
9
|
+
|
10
|
+
it 'registers job definitions' do
|
11
|
+
EXEL::Job.define :test_job, &block
|
12
|
+
expect(EXEL::Job.registry[:test_job]).to eq(block)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises an exception if a job name is already in use' do
|
16
|
+
EXEL::Job.define :test_job, &block
|
17
|
+
expect { EXEL::Job.define :test_job, &block }.to raise_error 'Job :test_job is already defined'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.run' do
|
22
|
+
let(:ast) { instance_double(EXEL::SequenceNode, run: nil, start: nil) }
|
23
|
+
let(:context) { instance_double(EXEL::Context) }
|
6
24
|
|
7
|
-
|
25
|
+
context 'with a string of DSL code' do
|
26
|
+
it 'parses the code' do
|
27
|
+
dsl_code = 'code'
|
28
|
+
expect(EXEL::Job::Parser).to receive(:parse).with(dsl_code).and_return(ast)
|
29
|
+
EXEL::Job.run(dsl_code, context)
|
30
|
+
end
|
8
31
|
|
9
|
-
it '
|
10
|
-
Job.
|
11
|
-
expect(
|
32
|
+
it 'runs the AST returned by the parser' do
|
33
|
+
allow(EXEL::Job::Parser).to receive(:parse).and_return(ast)
|
34
|
+
expect(ast).to receive(:start).with(context)
|
35
|
+
EXEL::Job.run('code', context)
|
12
36
|
end
|
13
37
|
|
14
|
-
it '
|
15
|
-
Job.
|
16
|
-
|
38
|
+
it 'returns the context' do
|
39
|
+
allow(EXEL::Job::Parser).to receive(:parse).and_return(ast)
|
40
|
+
result = EXEL::Job.run('code', context)
|
41
|
+
expect(result).to be(context)
|
17
42
|
end
|
18
43
|
end
|
19
44
|
|
20
|
-
|
21
|
-
|
22
|
-
|
45
|
+
context 'with a job name' do
|
46
|
+
context 'of a defined job' do
|
47
|
+
let(:block) { proc {} }
|
23
48
|
|
24
|
-
|
25
|
-
|
26
|
-
dsl_code = 'code'
|
27
|
-
expect(Job::Parser).to receive(:parse).with(dsl_code).and_return(ast)
|
28
|
-
Job.run(dsl_code, context)
|
49
|
+
before do
|
50
|
+
allow(EXEL::Job).to receive(:registry).and_return(test_job: block)
|
29
51
|
end
|
30
52
|
|
31
|
-
it 'runs the
|
32
|
-
|
53
|
+
it 'runs the job' do
|
54
|
+
expect(EXEL::Job::Parser).to receive(:parse).with(block).and_return(ast)
|
33
55
|
expect(ast).to receive(:start).with(context)
|
34
|
-
Job.run(
|
56
|
+
EXEL::Job.run(:test_job, context)
|
35
57
|
end
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'with a job name' do
|
39
|
-
context 'of a defined job' do
|
40
|
-
let(:block) { proc {} }
|
41
58
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
it 'runs the job' do
|
47
|
-
expect(Job::Parser).to receive(:parse).with(block).and_return(ast)
|
48
|
-
expect(ast).to receive(:start).with(context)
|
49
|
-
Job.run(:test_job, context)
|
50
|
-
end
|
59
|
+
it 'returns the context' do
|
60
|
+
result = EXEL::Job.run(:test_job, context)
|
61
|
+
expect(result).to be(context)
|
51
62
|
end
|
63
|
+
end
|
52
64
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
65
|
+
context 'of a undefined job' do
|
66
|
+
it 'returns nil' do
|
67
|
+
expect { EXEL::Job.run(:test_job, context) }.to raise_error('Job "test_job" not found')
|
57
68
|
end
|
58
69
|
end
|
59
70
|
end
|
71
|
+
end
|
60
72
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
describe 'mutation of arguments' do
|
74
|
+
module EXEL
|
75
|
+
module Processors
|
76
|
+
class TestProcessor
|
77
|
+
def initialize(context)
|
78
|
+
context[:array] << context[:arg]
|
79
|
+
end
|
66
80
|
|
67
|
-
|
81
|
+
def process(_callback)
|
82
|
+
end
|
68
83
|
end
|
69
84
|
end
|
85
|
+
end
|
70
86
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
87
|
+
it 'does not persist between runs' do
|
88
|
+
EXEL::Job.define :test do
|
89
|
+
process with: EXEL::Processors::TestProcessor, array: [], arg: context[:value]
|
90
|
+
end
|
75
91
|
|
76
|
-
|
77
|
-
|
78
|
-
|
92
|
+
context = EXEL::Context.new(value: 1)
|
93
|
+
EXEL::Job.run(:test, context)
|
94
|
+
expect(context[:array]).to eq([1])
|
79
95
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
96
|
+
context = EXEL::Context.new(value: 2)
|
97
|
+
EXEL::Job.run(:test, context)
|
98
|
+
expect(context[:array]).to eq([2])
|
84
99
|
end
|
85
100
|
end
|
86
101
|
|
87
|
-
describe Job::Parser do
|
88
|
-
let(:parser) { Job::Parser.new }
|
89
|
-
let(:ast) { instance_double(SequenceNode, run: nil) }
|
102
|
+
describe EXEL::Job::Parser do
|
103
|
+
let(:parser) { EXEL::Job::Parser.new }
|
104
|
+
let(:ast) { instance_double(EXEL::SequenceNode, run: nil) }
|
90
105
|
|
91
106
|
describe '#initialize' do
|
92
107
|
it 'initializes a sequence node' do
|
93
|
-
expect(parser.ast).to be_kind_of(SequenceNode)
|
108
|
+
expect(parser.ast).to be_kind_of(EXEL::SequenceNode)
|
94
109
|
end
|
95
110
|
end
|
96
111
|
|
97
112
|
describe '.parse' do
|
98
|
-
let(:parser) { instance_double(Job::Parser, ast: ast, instance_eval: nil) }
|
113
|
+
let(:parser) { instance_double(EXEL::Job::Parser, ast: ast, instance_eval: nil) }
|
99
114
|
|
100
115
|
before do
|
101
|
-
allow(Job::Parser).to receive(:new).and_return(parser)
|
116
|
+
allow(EXEL::Job::Parser).to receive(:new).and_return(parser)
|
102
117
|
end
|
103
118
|
|
104
119
|
context 'given DSL code as a proc' do
|
@@ -108,7 +123,7 @@ module EXEL
|
|
108
123
|
expect(block).to eq(dsl_proc)
|
109
124
|
end
|
110
125
|
|
111
|
-
Job::Parser.parse(dsl_proc)
|
126
|
+
EXEL::Job::Parser.parse(dsl_proc)
|
112
127
|
end
|
113
128
|
end
|
114
129
|
|
@@ -117,12 +132,12 @@ module EXEL
|
|
117
132
|
dsl_code = 'code'
|
118
133
|
expect(parser).to receive(:instance_eval).with(dsl_code)
|
119
134
|
|
120
|
-
Job::Parser.parse(dsl_code)
|
135
|
+
EXEL::Job::Parser.parse(dsl_code)
|
121
136
|
end
|
122
137
|
end
|
123
138
|
|
124
139
|
it 'returns the parsed AST' do
|
125
|
-
expect(Job::Parser.parse(proc {})).to eq(ast)
|
140
|
+
expect(EXEL::Job::Parser.parse(proc {})).to eq(ast)
|
126
141
|
end
|
127
142
|
end
|
128
143
|
|
@@ -130,18 +145,18 @@ module EXEL
|
|
130
145
|
let(:block) { proc {} }
|
131
146
|
let(:processor_class) { class_double(Class) }
|
132
147
|
|
133
|
-
before { allow(Job::Parser).to receive(:parse).and_return(ast) }
|
148
|
+
before { allow(EXEL::Job::Parser).to receive(:parse).and_return(ast) }
|
134
149
|
|
135
150
|
context 'without a block' do
|
136
151
|
it 'creates a process instruction' do
|
137
|
-
expect(Instruction).to receive(:new).with(processor_class, {arg1: 'arg1_value'}, nil)
|
152
|
+
expect(EXEL::Instruction).to receive(:new).with(processor_class, {arg1: 'arg1_value'}, subtree: nil)
|
138
153
|
|
139
154
|
parser.process with: processor_class, arg1: 'arg1_value'
|
140
155
|
end
|
141
156
|
|
142
157
|
it 'appends an instruction node to the AST with no children' do
|
143
158
|
expect(parser.ast).to receive(:add_child) do |node|
|
144
|
-
expect(node).to be_a_kind_of(InstructionNode)
|
159
|
+
expect(node).to be_a_kind_of(EXEL::InstructionNode)
|
145
160
|
expect(node.children).to eq([])
|
146
161
|
end
|
147
162
|
|
@@ -151,15 +166,15 @@ module EXEL
|
|
151
166
|
|
152
167
|
context 'with a block' do
|
153
168
|
it 'passes the parsed subtree to the instruction' do
|
154
|
-
expect(Job::Parser).to receive(:parse).with(block).and_return(ast)
|
155
|
-
expect(Instruction).to receive(:new).with(processor_class, {arg1: 'arg1_value'}, ast)
|
169
|
+
expect(EXEL::Job::Parser).to receive(:parse).with(block).and_return(ast)
|
170
|
+
expect(EXEL::Instruction).to receive(:new).with(processor_class, {arg1: 'arg1_value'}, subtree: ast)
|
156
171
|
|
157
172
|
parser.process with: processor_class, arg1: 'arg1_value', &block
|
158
173
|
end
|
159
174
|
|
160
175
|
it 'appends an instruction node to the AST with the parsed block as its subtree' do
|
161
176
|
expect(parser.ast).to receive(:add_child) do |node|
|
162
|
-
expect(node).to be_a_kind_of(InstructionNode)
|
177
|
+
expect(node).to be_a_kind_of(EXEL::InstructionNode)
|
163
178
|
expect(node.children).to eq([ast])
|
164
179
|
end
|
165
180
|
|
@@ -169,30 +184,30 @@ module EXEL
|
|
169
184
|
end
|
170
185
|
|
171
186
|
[
|
172
|
-
|
173
|
-
|
174
|
-
|
187
|
+
{method: :async, processor: EXEL::Processors::AsyncProcessor},
|
188
|
+
{method: :split, processor: EXEL::Processors::SplitProcessor},
|
189
|
+
{method: :run, processor: EXEL::Processors::RunProcessor},
|
175
190
|
].each do |data|
|
176
191
|
describe "##{data[:method]}" do
|
177
192
|
before do
|
178
|
-
allow(Job::Parser).to receive(:parse).and_return(ast)
|
193
|
+
allow(EXEL::Job::Parser).to receive(:parse).and_return(ast)
|
179
194
|
end
|
180
195
|
|
181
196
|
it "creates a #{data[:method]} instruction" do
|
182
|
-
expect(Instruction).to receive(:new).with(data[:processor], {arg1: 'arg1_value'}, ast)
|
197
|
+
expect(EXEL::Instruction).to receive(:new).with(data[:processor], {arg1: 'arg1_value'}, subtree: ast)
|
183
198
|
parser.send(data[:method], arg1: 'arg1_value') {}
|
184
199
|
end
|
185
200
|
|
186
201
|
it 'parses the block given' do
|
187
202
|
block = -> {}
|
188
|
-
expect(Job::Parser).to receive(:parse).with(block).and_return(ast)
|
203
|
+
expect(EXEL::Job::Parser).to receive(:parse).with(block).and_return(ast)
|
189
204
|
|
190
205
|
parser.send(data[:method], &block)
|
191
206
|
end
|
192
207
|
|
193
208
|
it 'adds parsed subtree and instruction to the AST' do
|
194
209
|
expect(parser.ast).to receive(:add_child) do |node|
|
195
|
-
expect(node).to be_a_kind_of(InstructionNode)
|
210
|
+
expect(node).to be_a_kind_of(EXEL::InstructionNode)
|
196
211
|
expect(node.children).to eq([ast])
|
197
212
|
end
|
198
213
|
|
@@ -203,7 +218,7 @@ module EXEL
|
|
203
218
|
|
204
219
|
describe '#context' do
|
205
220
|
it 'returns a DeferredContextValue' do
|
206
|
-
expect(parser.context).to be_a_kind_of(DeferredContextValue)
|
221
|
+
expect(parser.context).to be_a_kind_of(EXEL::DeferredContextValue)
|
207
222
|
end
|
208
223
|
end
|
209
224
|
|
@@ -211,15 +226,15 @@ module EXEL
|
|
211
226
|
let(:listener_class) { class_double(Class) }
|
212
227
|
|
213
228
|
it 'creates a listen instruction' do
|
214
|
-
expect(ListenInstruction).to receive(:new).with(:event, listener_class)
|
229
|
+
expect(EXEL::ListenInstruction).to receive(:new).with(:event, listener_class)
|
215
230
|
parser.listen for: :event, with: listener_class
|
216
231
|
end
|
217
232
|
|
218
233
|
it 'adds an InstructionNode containing the listen instruction' do
|
219
234
|
parser.listen for: :event, with: listener_class
|
220
235
|
node = parser.ast.children.first
|
221
|
-
expect(node).to be_a_kind_of(InstructionNode)
|
222
|
-
expect(node.instruction).to be_a_kind_of(ListenInstruction)
|
236
|
+
expect(node).to be_a_kind_of(EXEL::InstructionNode)
|
237
|
+
expect(node.instruction).to be_a_kind_of(EXEL::ListenInstruction)
|
223
238
|
end
|
224
239
|
end
|
225
240
|
end
|