ntl-orchestra 0.9.2 → 0.9.3

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.
@@ -5,61 +5,61 @@ module Orchestra
5
5
  attr_writer :command, :result
6
6
 
7
7
  def initialize
8
- @nodes = {}
8
+ @steps = {}
9
9
  end
10
10
 
11
11
  def build_operation
12
12
  raise ArgumentError, "Must supply a result" if @result.nil?
13
- raise ArgumentError, "Must supply at least one node" if @nodes.empty?
13
+ raise ArgumentError, "Must supply at least one step" if @steps.empty?
14
14
  Operation.new(
15
15
  :command => @command,
16
- :nodes => @nodes,
16
+ :steps => @steps,
17
17
  :result => @result,
18
18
  )
19
19
  end
20
20
 
21
- def add_node name_or_object, args = {}, &block
22
- name, node = case name_or_object
23
- when nil then build_anonymous_node block
24
- when Operation then build_embedded_operation_node name_or_object
25
- when ::String, ::Symbol then build_inline_node name_or_object, block
26
- else build_object_node name_or_object, args
21
+ def add_step name_or_object, args = {}, &block
22
+ name, step = case name_or_object
23
+ when nil then build_anonymous_step block
24
+ when Operation then build_embedded_operation_step name_or_object
25
+ when ::String, ::Symbol then build_inline_step name_or_object, block
26
+ else build_object_step name_or_object, args
27
27
  end
28
- node.provisions << name.to_sym if node.provisions.empty?
29
- set_node name.to_sym, node
28
+ step.provisions << name.to_sym if step.provisions.empty?
29
+ set_step name.to_sym, step
30
30
  end
31
31
 
32
- def set_node name, node
33
- if @nodes.has_key? name
34
- raise ArgumentError, "There are duplicate nodes named #{name.inspect}"
32
+ def set_step name, step
33
+ if @steps.has_key? name
34
+ raise ArgumentError, "There are duplicate steps named #{name.inspect}"
35
35
  end
36
- @nodes[name] = node
37
- node.freeze
36
+ @steps[name] = step
37
+ step.freeze
38
38
  end
39
39
 
40
- def build_anonymous_node block
41
- node = Node::InlineNode.build &block
42
- unless node.provisions.size == 1
43
- raise ArgumentError, "Could not infer name for node from a provision"
40
+ def build_anonymous_step block
41
+ step = Step::InlineStep.build &block
42
+ unless step.provisions.size == 1
43
+ raise ArgumentError, "Could not infer name for step from a provision"
44
44
  end
45
- name = node.provisions.fetch 0
46
- [name, node]
45
+ name = step.provisions.fetch 0
46
+ [name, step]
47
47
  end
48
48
 
49
- def build_embedded_operation_node operation
49
+ def build_embedded_operation_step operation
50
50
  name = object_name operation
51
51
  [name || operation.result, operation]
52
52
  end
53
53
 
54
- def build_inline_node name, block
55
- node = Node::InlineNode.build &block
56
- [name, node]
54
+ def build_inline_step name, block
55
+ step = Step::InlineStep.build &block
56
+ [name, step]
57
57
  end
58
58
 
59
- def build_object_node object, args
59
+ def build_object_step object, args
60
60
  name = object_name object
61
- node = ObjectAdapter.build_node object, args
62
- [name, node]
61
+ step = ObjectAdapter.build_step object, args
62
+ [name, step]
63
63
  end
64
64
 
65
65
  private
@@ -75,14 +75,14 @@ module Orchestra
75
75
  context.instance_eval &block
76
76
  end
77
77
 
78
- attr :nodes
78
+ attr :steps
79
79
 
80
80
  def initialize builder
81
81
  @builder = builder
82
82
  end
83
83
 
84
- def node *args, &block
85
- @builder.add_node *args, &block
84
+ def step *args, &block
85
+ @builder.add_step *args, &block
86
86
  nil
87
87
  end
88
88
 
@@ -92,13 +92,13 @@ module Orchestra
92
92
  end
93
93
 
94
94
  def result name = nil, &block
95
- node = @builder.add_node name, &block
96
- name ||= node.provisions.fetch 0
95
+ step = @builder.add_step name, &block
96
+ name ||= step.provisions.fetch 0
97
97
  self.result = name
98
98
  end
99
99
 
100
100
  def finally name = :__finally__, &block
101
- @builder.add_node name, &block
101
+ @builder.add_step name, &block
102
102
  @builder.command = true
103
103
  self.result = name
104
104
  end
@@ -1,8 +1,8 @@
1
1
  module Orchestra
2
2
  module DSL
3
- module Nodes
3
+ module Steps
4
4
  class Builder
5
- attr_accessor :collection, :perform_block
5
+ attr_accessor :collection, :execute_block
6
6
 
7
7
  attr :defaults, :dependencies, :provisions
8
8
 
@@ -12,12 +12,12 @@ module Orchestra
12
12
  @provisions = []
13
13
  end
14
14
 
15
- def build_node
16
- Node::InlineNode.new(
15
+ def build_step
16
+ Step::InlineStep.new(
17
17
  :collection => collection,
18
18
  :defaults => defaults,
19
19
  :dependencies => dependencies,
20
- :perform_block => perform_block,
20
+ :execute_block => execute_block,
21
21
  :provides => provisions,
22
22
  )
23
23
  end
@@ -29,8 +29,6 @@ module Orchestra
29
29
  context.instance_eval &block
30
30
  end
31
31
 
32
- attr :collection, :perform
33
-
34
32
  def initialize builder
35
33
  @builder = builder
36
34
  end
@@ -58,8 +56,8 @@ module Orchestra
58
56
  @builder.provisions.concat provisions
59
57
  end
60
58
 
61
- def perform &block
62
- @builder.perform_block = block
59
+ def execute &block
60
+ @builder.execute_block = block
63
61
  end
64
62
 
65
63
  def iterates_over dependency
@@ -0,0 +1,158 @@
1
+ module Orchestra
2
+ module Execution
3
+ extend self
4
+
5
+ def start_operation *args
6
+ Operation.new *args
7
+ end
8
+
9
+ def execute_step step, input
10
+ operation_execution = Operation.new Conductor.new, {}, input
11
+ Step.execute step, 'anonymous', operation_execution
12
+ end
13
+
14
+ class Operation
15
+ include Observable
16
+ extend Forwardable
17
+
18
+ def_delegators :@run_list, :provisions, :dependencies,
19
+ :optional_dependencies, :required_dependencies
20
+
21
+ attr :conductor, :input, :state, :registry, :run_list
22
+
23
+ def initialize conductor, run_list, input
24
+ @conductor = conductor
25
+ @input = input.dup
26
+ @run_list = run_list
27
+ @registry = conductor.build_registry self
28
+ @state = registry.merge input
29
+ end
30
+
31
+ def execute
32
+ ensure_inputs_are_present!
33
+ run_list.each do |name, step| process name, step end
34
+ rescue => error
35
+ publish :error_raised, error
36
+ raise error
37
+ end
38
+
39
+ def process name, step
40
+ output = Step.execute step, name, self
41
+ state.merge! output
42
+ end
43
+
44
+ def ensure_inputs_are_present!
45
+ has_dep = state.method :[]
46
+ missing_input = required_dependencies.reject &has_dep
47
+ raise MissingInputError.new missing_input unless missing_input.empty?
48
+ end
49
+
50
+ def extract_result result
51
+ state.fetch result
52
+ end
53
+
54
+ def publish event, *payload
55
+ changed
56
+ notify_observers event, *payload
57
+ end
58
+
59
+ def thread_pool
60
+ conductor.thread_pool
61
+ end
62
+ end
63
+
64
+ class Step
65
+ def self.execute step, *args
66
+ instance = new step, *args
67
+ instance.execute
68
+ end
69
+
70
+ def self.new step, *args
71
+ if step.is_a? Orchestra::Operation
72
+ klass = EmbeddedOperation
73
+ else
74
+ klass = step.collection ? CollectionStep : self
75
+ end
76
+ instance = klass.allocate
77
+ instance.send :initialize, step, *args
78
+ instance
79
+ end
80
+
81
+ attr :context, :name, :operation_execution, :step
82
+
83
+ def initialize step, name, operation_execution
84
+ @name = name
85
+ @operation_execution = operation_execution
86
+ @step = step
87
+ @context = build_context
88
+ end
89
+
90
+ def execute
91
+ operation_execution.publish :step_entered, name, input
92
+ output = step.process invoke
93
+ operation_execution.publish :step_exited, name, output
94
+ output
95
+ end
96
+
97
+ def input
98
+ registry = operation_execution.registry
99
+ operation_execution.state.reject do |key, val|
100
+ registry[key] == val or not step.dependencies.include? key
101
+ end
102
+ end
103
+
104
+ def invoke
105
+ context.execute
106
+ end
107
+
108
+ def build_context
109
+ step.build_context operation_execution.state
110
+ end
111
+ end
112
+
113
+ class CollectionStep < Step
114
+ def invoke
115
+ batch, output = prepare_collection
116
+ jobs = enqueue_jobs batch do |result, index| output[index] = result end
117
+ jobs.each &:wait
118
+ output
119
+ end
120
+
121
+ def enqueue_jobs batch, &block
122
+ batch.map.with_index do |element, index|
123
+ enqueue_job element, index, &block
124
+ end
125
+ end
126
+
127
+ def enqueue_job element, index
128
+ operation_execution.thread_pool.enqueue do
129
+ result = context.execute element
130
+ yield [result, index]
131
+ end
132
+ end
133
+
134
+ def prepare_collection
135
+ batch = context.fetch_collection
136
+ output = [nil] * batch.size
137
+ [batch, output]
138
+ end
139
+ end
140
+
141
+ class EmbeddedOperation < Step
142
+ def invoke
143
+ super
144
+ context.state.select do |k,_| k == step.result end
145
+ end
146
+
147
+ def build_context
148
+ conductor = operation_execution.registry[:conductor]
149
+ copy_observers = conductor.method :copy_observers
150
+ step.start_execution conductor, input, &copy_observers
151
+ end
152
+
153
+ def input
154
+ operation_execution.state
155
+ end
156
+ end
157
+ end
158
+ end
@@ -12,35 +12,35 @@ module Orchestra
12
12
 
13
13
  extend Forwardable
14
14
 
15
- def_delegators :@default_run_list, :node_names, :provisions, :dependencies,
15
+ def_delegators :@default_run_list, :provisions, :dependencies,
16
16
  :optional_dependencies, :required_dependencies
17
17
 
18
- attr :registry, :result, :nodes
18
+ attr :registry, :result, :steps
19
19
 
20
20
  def initialize args = {}
21
- @result, @command, @nodes = Util.extract_key_args args,
22
- :result, :command => false, :nodes => {}
23
- @default_run_list = RunList.build nodes, result, []
21
+ @result, @command, @steps = Util.extract_key_args args,
22
+ :result, :command => false, :steps => {}
23
+ @default_run_list = RunList.build steps, result, []
24
24
  end
25
25
 
26
26
  def process output
27
27
  output.select do |key, _| key = result end
28
28
  end
29
29
 
30
- def start_performance *args
30
+ def start_execution *args
31
31
  conductor, input = extract_args args
32
- run_list = RunList.build nodes, result, input.keys
33
- performance = Performance.new conductor, run_list, input
34
- yield performance if block_given?
35
- performance.publish :operation_entered, name, input
36
- performance
32
+ run_list = RunList.build steps, result, input.keys
33
+ execution = Execution.start_operation conductor, run_list, input
34
+ yield execution if block_given?
35
+ execution.publish :operation_entered, name, input
36
+ execution
37
37
  end
38
38
 
39
- def perform *args, &block
40
- performance = start_performance *args, &block
41
- performance.perform
42
- output = performance.extract_result result
43
- performance.publish :operation_exited, name, output
39
+ def execute *args, &block
40
+ execution = start_execution *args, &block
41
+ execution.execute
42
+ output = execution.extract_result result
43
+ execution.publish :operation_exited, name, output
44
44
  @command ? nil : output
45
45
  end
46
46
 
@@ -0,0 +1,47 @@
1
+ module Orchestra
2
+ class Recording
3
+ class Playback < BasicObject
4
+ attr :mocks
5
+
6
+ def initialize mocks
7
+ @mocks = mocks
8
+ end
9
+
10
+ def respond_to? meth
11
+ mocks.has_key? meth
12
+ end
13
+
14
+ def self.build service_recording
15
+ factory = Factory.new
16
+ factory.build service_recording
17
+ end
18
+
19
+ class Factory
20
+ attr :klass, :mocks
21
+
22
+ def initialize
23
+ @klass = Class.new Playback
24
+ @mocks = Hash.new do |hsh, meth| hsh[meth] = {} end
25
+ end
26
+
27
+ def build service_recording
28
+ record = method :<<
29
+ service_recording.each &record
30
+ klass.new mocks
31
+ end
32
+
33
+ def << record
34
+ method = record[:method].to_sym
35
+ unless klass.instance_methods.include? method
36
+ klass.send :define_method, method do |*args| mocks[method][args] end
37
+ end
38
+ mocks[method][record[:input]] = record[:output]
39
+ end
40
+
41
+ def singleton
42
+ singleton = class << instance ; self end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -27,57 +27,17 @@ module Orchestra
27
27
  }
28
28
  end
29
29
 
30
+ def to_json generator
31
+ generator.generate to_h
32
+ end
33
+
30
34
  def self.replay operation, input, service_recordings
31
35
  replayed_services = {}
32
36
  service_recordings.each do |svc, service_recording|
33
37
  replayed_services[svc] = Playback.build service_recording
34
38
  end
35
39
  conductor = Conductor.new replayed_services
36
- conductor.perform operation, input
37
- end
38
-
39
- class Playback < BasicObject
40
- attr :mocks
41
-
42
- def initialize mocks
43
- @mocks = mocks
44
- end
45
-
46
- def respond_to? meth
47
- mocks.has_key? meth
48
- end
49
-
50
- def self.build service_recording
51
- factory = Factory.new
52
- factory.build service_recording
53
- end
54
-
55
- class Factory
56
- attr :klass, :mocks
57
-
58
- def initialize
59
- @klass = Class.new Playback
60
- @mocks = Hash.new do |hsh, meth| hsh[meth] = {} end
61
- end
62
-
63
- def build service_recording
64
- record = method :<<
65
- service_recording.each &record
66
- klass.new mocks
67
- end
68
-
69
- def << record
70
- method = record[:method].to_sym
71
- unless klass.instance_methods.include? method
72
- klass.send :define_method, method do |*args| mocks[method][args] end
73
- end
74
- mocks[method][record[:input]] = record[:output]
75
- end
76
-
77
- def singleton
78
- singleton = class << instance ; self end
79
- end
80
- end
40
+ conductor.execute operation, input
81
41
  end
82
42
  end
83
43
  end