ripe 0.2.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.travis.yml +0 -5
- data/Guardfile +2 -4
- data/README.md +1 -0
- data/bin/ripe +1 -59
- data/lib/ripe.rb +8 -1
- data/lib/ripe/blocks.rb +13 -0
- data/lib/ripe/blocks/block.rb +142 -0
- data/lib/ripe/blocks/liquid_block.rb +48 -0
- data/lib/ripe/blocks/multi_block.rb +71 -0
- data/lib/ripe/blocks/parallel_block.rb +29 -0
- data/lib/ripe/blocks/serial_block.rb +61 -0
- data/lib/ripe/blocks/working_block.rb +101 -0
- data/lib/ripe/cli.rb +121 -0
- data/lib/ripe/cli/helper.rb +31 -0
- data/lib/ripe/db.rb +7 -0
- data/lib/ripe/db/task.rb +42 -0
- data/lib/ripe/db/task_migration.rb +33 -0
- data/lib/ripe/db/worker.rb +64 -0
- data/lib/ripe/db/worker_migration.rb +41 -0
- data/lib/ripe/dsl.rb +2 -4
- data/lib/ripe/dsl/task_dsl.rb +4 -2
- data/lib/ripe/dsl/workflow_dsl.rb +5 -0
- data/lib/ripe/library.rb +34 -45
- data/lib/ripe/repo.rb +24 -23
- data/lib/ripe/version.rb +1 -1
- data/lib/ripe/worker_controller.rb +72 -144
- data/lib/ripe/worker_controller/preparer.rb +172 -0
- data/lib/ripe/worker_controller/syncer.rb +118 -0
- data/spec/cli_spec.rb +14 -0
- data/spec/library_spec.rb +18 -18
- data/spec/spec_helper.rb +2 -0
- data/spec/testpack.rb +16 -5
- data/spec/testpack/.ripe/meta.db +0 -0
- data/spec/testpack/.ripe/tasks/bar.sh +3 -0
- data/spec/testpack/{ripe → .ripe}/tasks/foo.sh +0 -0
- data/spec/testpack/.ripe/workers/1/1.sh +16 -0
- data/spec/testpack/.ripe/workers/1/2.sh +16 -0
- data/spec/testpack/.ripe/workers/1/job.sh +54 -0
- data/spec/testpack/.ripe/workers/2/3.sh +16 -0
- data/spec/testpack/.ripe/workers/2/4.sh +16 -0
- data/spec/testpack/.ripe/workers/2/job.sh +54 -0
- data/spec/testpack/.ripe/workers/3/5.sh +16 -0
- data/spec/testpack/.ripe/workers/3/6.sh +16 -0
- data/spec/testpack/.ripe/workers/3/job.sh +54 -0
- data/spec/testpack/.ripe/workflows/foobar.rb +23 -0
- data/spec/testpack/{case/Sample1 → Sample1}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample1 → Sample1}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample1 → Sample1}/foo_output.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/foo_output.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/foo_output.txt +0 -0
- data/spec/worker_controller_spec.rb +143 -0
- metadata +66 -40
- data/lib/ripe/block.rb +0 -41
- data/lib/ripe/liquid_block.rb +0 -17
- data/lib/ripe/multi_block.rb +0 -35
- data/lib/ripe/parallel_block.rb +0 -13
- data/lib/ripe/serial_block.rb +0 -37
- data/lib/ripe/task.rb +0 -21
- data/lib/ripe/task_migration.rb +0 -18
- data/lib/ripe/worker.rb +0 -44
- data/lib/ripe/worker_migration.rb +0 -26
- data/lib/ripe/working_block.rb +0 -41
- data/spec/block_spec.rb +0 -7
- data/spec/ripe_spec.rb +0 -7
- data/spec/testpack/ripe/tasks/bar.sh +0 -3
- data/spec/testpack/ripe/workflows/foobar.rb +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28ae834d0a84d2072400169910c39825c1c37aa3
|
|
4
|
+
data.tar.gz: 2b1be6510c88ad3679dc69e4b198eea81d050734
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cac0941044a07fe4b97a8fda9f68e52881bc6be0943efafb6d104e0fa6e0c45e4f219ad25431b6099aa30e6fac3847fa79cc28d472b13f3cce59f852fe52fb60
|
|
7
|
+
data.tar.gz: c43fcd8a697350737a8b02fef384d40bcc6666954f0ce2e8204efb1a88f9a4661099c4c2598cbe654d1ca86dcc9e89d8c28ab456b1ea34c4a4dd5b59e8780603
|
data/.travis.yml
CHANGED
data/Guardfile
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
guard :rspec, cmd: 'rspec' do
|
|
2
|
-
watch(%r{^spec
|
|
3
|
-
watch(%r{^lib/ripe/(.+)\.rb$}) { |m| "spec
|
|
4
|
-
watch('spec/spec_helper.rb') { "spec" }
|
|
5
|
-
watch('spec/testpack.rb') { "spec" }
|
|
2
|
+
watch(%r{^spec/.+\.rb$}) { 'spec' }
|
|
3
|
+
watch(%r{^lib/ripe/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
6
4
|
end
|
data/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# Ripe
|
|
2
|
+
[](http://badge.fury.io/rb/ripe)
|
|
2
3
|
[](https://travis-ci.org/ndejay/ripe)
|
|
3
4
|
[](https://codeclimate.com/github/ndejay/ripe)
|
|
4
5
|
[](https://codeclimate.com/github/ndejay/ripe)
|
data/bin/ripe
CHANGED
|
@@ -1,63 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
require_relative '../lib/ripe'
|
|
4
|
-
require_relative '../lib/ripe/dsl'
|
|
5
|
-
require 'ripl' # REPL
|
|
6
|
-
require 'hirb' # Pretty output for +ActiveRecord+ objects
|
|
7
|
-
require 'thor'
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
include Ripe::DSL
|
|
11
|
-
|
|
12
|
-
class CLI < Thor
|
|
13
|
-
desc 'console', 'Enter ripe console'
|
|
14
|
-
def console
|
|
15
|
-
repo = Repo.new
|
|
16
|
-
repo.attach
|
|
17
|
-
|
|
18
|
-
# Do not send arguments to the REPL
|
|
19
|
-
ARGV.clear
|
|
20
|
-
|
|
21
|
-
Ripl.config[:prompt] = proc do
|
|
22
|
-
# This is the only place I could think of placing +Hirb#enable+.
|
|
23
|
-
Hirb.enable unless Hirb::View.enabled?
|
|
24
|
-
'ripe> '
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Launch the REPL session in the context of +WorkerController+.
|
|
28
|
-
Ripl.start :binding => repo.controller.instance_eval { binding }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
desc 'prepare SAMPLES', 'Prepare jobs from template workflow'
|
|
32
|
-
option :workflow, :aliases => '-w', :type => :string, :required => true,
|
|
33
|
-
:desc => 'Workflow to be applied'
|
|
34
|
-
option :options, :aliases => '-o', :type => :string, :required => false,
|
|
35
|
-
:desc => 'Options', :default => ''
|
|
36
|
-
def prepare(*samples)
|
|
37
|
-
abort "No samples specified." if (samples.length == 0)
|
|
38
|
-
|
|
39
|
-
additional_vars = options[:options].split(/,/).map do |pair|
|
|
40
|
-
key, value = pair.split(/=/)
|
|
41
|
-
{ key.to_sym => value }
|
|
42
|
-
end
|
|
43
|
-
additional_vars = additional_vars.inject(&:merge) || {}
|
|
44
|
-
|
|
45
|
-
repo = Repo.new
|
|
46
|
-
|
|
47
|
-
filename = repo.library.find_workflow(options[:workflow])
|
|
48
|
-
abort "Could not find workflow #{@handle}." if filename == nil
|
|
49
|
-
require_relative filename # Imports +$workflow+ from the workflow component
|
|
50
|
-
|
|
51
|
-
repo.attach_or_create # Create .ripe if it doesn't exist
|
|
52
|
-
repo.controller.prepare(samples,
|
|
53
|
-
$workflow.callback,
|
|
54
|
-
$workflow.params.merge(additional_vars))
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
desc 'version', 'Retrieve ripe version'
|
|
58
|
-
def version
|
|
59
|
-
puts "ripe version #{Ripe::VERSION}"
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
CLI.start(ARGV)
|
|
5
|
+
Ripe::CLI.start(ARGV)
|
data/lib/ripe.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
require_relative 'ripe/
|
|
1
|
+
require_relative 'ripe/blocks'
|
|
2
|
+
require_relative 'ripe/db'
|
|
3
|
+
require_relative 'ripe/dsl'
|
|
4
|
+
require_relative 'ripe/library'
|
|
2
5
|
require_relative 'ripe/repo'
|
|
6
|
+
require_relative 'ripe/worker_controller'
|
|
7
|
+
|
|
8
|
+
require_relative 'ripe/cli'
|
|
9
|
+
require_relative 'ripe/version'
|
|
3
10
|
|
|
4
11
|
module Ripe
|
|
5
12
|
PATH = File.expand_path('..', File.dirname(__FILE__))
|
data/lib/ripe/blocks.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
module Blocks
|
|
3
|
+
# Forward declaration to prevent cyclic dependencies
|
|
4
|
+
class Block; end
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require_relative 'blocks/multi_block'
|
|
9
|
+
require_relative 'blocks/block'
|
|
10
|
+
require_relative 'blocks/parallel_block'
|
|
11
|
+
require_relative 'blocks/serial_block'
|
|
12
|
+
require_relative 'blocks/working_block'
|
|
13
|
+
require_relative 'blocks/liquid_block'
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module Blocks
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents the fundamental building block of ripe.
|
|
7
|
+
#
|
|
8
|
+
# @abstract
|
|
9
|
+
#
|
|
10
|
+
# @attr_reader id [String] a mandatory, but optionally unique identifier
|
|
11
|
+
# for the block
|
|
12
|
+
# @attr_reader blocks [Array<Block>] list of children blocks
|
|
13
|
+
# @attr vars [Hash<Symbol, String>] key-value pairs
|
|
14
|
+
#
|
|
15
|
+
# @see Ripe::WorkerController::Preparer
|
|
16
|
+
|
|
17
|
+
class Block
|
|
18
|
+
|
|
19
|
+
attr_reader :id, :blocks
|
|
20
|
+
|
|
21
|
+
attr_accessor :vars
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# @param id [String] a mandatory, but optionally unique identifier
|
|
25
|
+
# for the block
|
|
26
|
+
# @param blocks [Array<Block>] list of children blocks
|
|
27
|
+
# @param vars [Hash<Symbol, String>] key-value pairs
|
|
28
|
+
|
|
29
|
+
def initialize(id, blocks = [], vars = {})
|
|
30
|
+
@id, @blocks, @vars = id, blocks, vars
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Return the string command of the subtree starting at the current block.
|
|
35
|
+
#
|
|
36
|
+
# @return [String] subtree command
|
|
37
|
+
|
|
38
|
+
def command
|
|
39
|
+
''
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Prune the subtree starting at the current block.
|
|
44
|
+
#
|
|
45
|
+
# @param protect [Boolean] if the current block (and recursively, its
|
|
46
|
+
# children) should be protected from pruning -- setting this parameter
|
|
47
|
+
# to +true+ guarantees that the block will not be pruned
|
|
48
|
+
# @param depend [Boolean] if the current block is unprotected because
|
|
49
|
+
# its parent (serially) needs to be executed
|
|
50
|
+
# @return [Block, nil] a +Block+ representing the subtree that has not
|
|
51
|
+
# been pruned, and +nil+ otherwise
|
|
52
|
+
|
|
53
|
+
def prune(protect, depend)
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Test whether all targets for the current block exist.
|
|
59
|
+
#
|
|
60
|
+
# @return [Boolean] whether all targets exist
|
|
61
|
+
|
|
62
|
+
def targets_exist?
|
|
63
|
+
# {Block} is an abstract class. By default, assume that no targets
|
|
64
|
+
# exist.
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Return the topology of the subtree starting at the current block in a
|
|
70
|
+
# nested list format. The first element of any nested list is the
|
|
71
|
+
# identifier of the corresponding block in the subtree, and the
|
|
72
|
+
# subsequent elements are each a subtree corresponding to the children
|
|
73
|
+
# blocks of the current subtree.
|
|
74
|
+
#
|
|
75
|
+
# @return [Array<Symbol, Array>] topology nested list
|
|
76
|
+
|
|
77
|
+
def topology
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
# Compose a new parallel block from two blocks. This method provides
|
|
83
|
+
# syntactic sugar in the form:
|
|
84
|
+
#
|
|
85
|
+
# Block1 | Block2 | Block3
|
|
86
|
+
#
|
|
87
|
+
# @param block [Block] a block
|
|
88
|
+
# @return [Block] parallel block composition of the current block with
|
|
89
|
+
# the block passed in the argument list
|
|
90
|
+
|
|
91
|
+
def |(block)
|
|
92
|
+
ParallelBlock.new(self, block)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Compose a new serial block from two blocks. This method provides
|
|
97
|
+
# syntactic sugar in the form:
|
|
98
|
+
#
|
|
99
|
+
# Block1 + Block2 + Block3
|
|
100
|
+
#
|
|
101
|
+
# @param (see #|)
|
|
102
|
+
# @return [Block] serial block composition of the current block with
|
|
103
|
+
# the block passed in the argument list
|
|
104
|
+
|
|
105
|
+
def +(block)
|
|
106
|
+
SerialBlock.new(self, block)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
##
|
|
116
|
+
# +NilClass+ is monkey-patched+ to provide syntactic sugar for +Block#|+ and
|
|
117
|
+
# +Block#\++ by treating +nil+ like an empty block.
|
|
118
|
+
#
|
|
119
|
+
# @see Ripe::Blocks::Block
|
|
120
|
+
|
|
121
|
+
class NilClass
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# If attempting to compose a new block with a +nil+ element, ignore the +nil+
|
|
125
|
+
# element.
|
|
126
|
+
#
|
|
127
|
+
# @param (see Ripe::Blocks::Block#|)
|
|
128
|
+
# @return [Block] the +block+ parameter
|
|
129
|
+
|
|
130
|
+
def |(block)
|
|
131
|
+
raise NoMethodError unless Ripe::Blocks::Block > block.class
|
|
132
|
+
block
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
##
|
|
136
|
+
# (see #|)
|
|
137
|
+
|
|
138
|
+
def +(block)
|
|
139
|
+
self.|(block)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'liquid'
|
|
2
|
+
|
|
3
|
+
module Ripe
|
|
4
|
+
|
|
5
|
+
module Blocks
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# This class represents a working block that should be processed using the
|
|
9
|
+
# Liquid templating engine, rather than the simple +bash+ engine defined in
|
|
10
|
+
# {WorkingBlock}.
|
|
11
|
+
#
|
|
12
|
+
# @see Ripe::Blocks::WorkingBlock
|
|
13
|
+
|
|
14
|
+
class LiquidBlock < WorkingBlock
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# @param filename [String] filename of the template file
|
|
18
|
+
# @param vars [Hash<Symbol, String>] key-value pairs
|
|
19
|
+
|
|
20
|
+
def initialize(filename, vars = {})
|
|
21
|
+
super(filename, vars)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Return liquid block +parameters+ as a +Hash<Symbol, Object>+.
|
|
26
|
+
#
|
|
27
|
+
# @return [Hash<Symbol, Object>] liquid block +parameters+
|
|
28
|
+
|
|
29
|
+
def declarations
|
|
30
|
+
@vars.inject({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# (see Block#command)
|
|
35
|
+
#
|
|
36
|
+
# The resulting string contains the render result of the liquid template
|
|
37
|
+
# based on the parameters specified in +vars+.
|
|
38
|
+
|
|
39
|
+
def command
|
|
40
|
+
template = Liquid::Template.parse(File.new(@filename).read)
|
|
41
|
+
template.render(declarations)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module Blocks
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a block composition, that is, a placeholder block
|
|
7
|
+
# that joins multiple blocks together.
|
|
8
|
+
#
|
|
9
|
+
# This class only exists to provide a superclass for {ParallelBlock} and
|
|
10
|
+
# {SerialBlock}.
|
|
11
|
+
#
|
|
12
|
+
# @abstract
|
|
13
|
+
#
|
|
14
|
+
# @see Ripe::Blocks::ParallelBlock
|
|
15
|
+
# @see Ripe::Blocks::SerialBlock
|
|
16
|
+
|
|
17
|
+
class MultiBlock < Block
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# @param id [String] a mandatory, but optionally unique identifier
|
|
21
|
+
# for the block
|
|
22
|
+
# @param blocks [Array<Block>] list of children blocks
|
|
23
|
+
|
|
24
|
+
def initialize(id, *blocks)
|
|
25
|
+
# Ignore nil objects
|
|
26
|
+
super(id, blocks.compact, {})
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# (see Block#prune)
|
|
31
|
+
#
|
|
32
|
+
# Unless the block is protected, attempt to prune all children blocks.
|
|
33
|
+
# If all blocks are pruned, return nothing. If a single block remains,
|
|
34
|
+
# return that block. If more than one block remains, return the current
|
|
35
|
+
# {MultiBlock}.
|
|
36
|
+
|
|
37
|
+
def prune(protect, depend)
|
|
38
|
+
if !protect
|
|
39
|
+
@blocks = @blocks.map { |block| block.prune(protect, depend) }.compact
|
|
40
|
+
case @blocks.length
|
|
41
|
+
when 0; nil
|
|
42
|
+
when 1; @blocks.first
|
|
43
|
+
else; self
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# (see Block#targets_exist?)
|
|
52
|
+
#
|
|
53
|
+
# A {MultiBlock}'s targets exist if the targets of all its # children
|
|
54
|
+
# exist.
|
|
55
|
+
|
|
56
|
+
def targets_exist?
|
|
57
|
+
@blocks.map(&:targets_exist?).inject(:&)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
# (see Block#topology)
|
|
62
|
+
|
|
63
|
+
def topology
|
|
64
|
+
[@id] + @blocks.map(&:topology)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module Blocks
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a parallel composition of blocks, in that the
|
|
7
|
+
# children blocks of an instance of this class are to be run in parallel.
|
|
8
|
+
|
|
9
|
+
class ParallelBlock < MultiBlock
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# @param blocks [Array<Block>] list of children blocks
|
|
13
|
+
|
|
14
|
+
def initialize(*blocks)
|
|
15
|
+
super(:|, *blocks)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# (see Block#command)
|
|
20
|
+
|
|
21
|
+
def command
|
|
22
|
+
@blocks.map { |block| "(\n%s\n) & " % block.command }.join('') + 'wait'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module Blocks
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a parallel composition of blocks, in that the
|
|
7
|
+
# children blocks of an instance of this class are to be run in serial.
|
|
8
|
+
|
|
9
|
+
class SerialBlock < MultiBlock
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# @param blocks [Array<Block>] list of children blocks
|
|
13
|
+
|
|
14
|
+
def initialize(*blocks)
|
|
15
|
+
super(:+, *blocks)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# (see Block#command)
|
|
20
|
+
|
|
21
|
+
def command
|
|
22
|
+
@blocks.map { |block| "(\n%s\n)" % block.command }.join(' ; ')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias :super_prune :prune
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# (see MultiBlock#prune)
|
|
29
|
+
#
|
|
30
|
+
# A {SerialBlock} differs from a {MultiBlock} or {ParallelBlock} in that
|
|
31
|
+
# there is a linear dependency for its children blocks as they are to be
|
|
32
|
+
# run in serial. If a given block must be run, then all subsequent
|
|
33
|
+
# blocks that depend on it must be run as well.
|
|
34
|
+
|
|
35
|
+
def prune(protect, depend)
|
|
36
|
+
return super_prune(protect, depend) if !depend
|
|
37
|
+
return self if protect
|
|
38
|
+
|
|
39
|
+
@blocks = @blocks.map do |block|
|
|
40
|
+
new_protect = !block.targets_exist?
|
|
41
|
+
new_block = block.prune(protect, depend)
|
|
42
|
+
protect = new_protect
|
|
43
|
+
new_block
|
|
44
|
+
end
|
|
45
|
+
@blocks = @blocks.compact
|
|
46
|
+
|
|
47
|
+
case @blocks.length
|
|
48
|
+
when 0
|
|
49
|
+
nil
|
|
50
|
+
when 1
|
|
51
|
+
@blocks.first
|
|
52
|
+
else
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|