tap 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +12 -0
- data/MIT-LICENSE +0 -2
- data/README +23 -32
- data/bin/rap +116 -0
- data/bin/tap +6 -9
- data/cgi/run.rb +67 -0
- data/cmd/console.rb +1 -1
- data/cmd/destroy.rb +4 -4
- data/cmd/generate.rb +4 -4
- data/cmd/manifest.rb +61 -53
- data/cmd/run.rb +8 -75
- data/doc/Class Reference +130 -121
- data/doc/Command Reference +76 -124
- data/doc/Syntax Reference +290 -0
- data/doc/Tutorial +305 -237
- data/lib/tap/app.rb +140 -467
- data/lib/tap/constants.rb +2 -2
- data/lib/tap/declarations.rb +211 -0
- data/lib/tap/env.rb +171 -193
- data/lib/tap/exe.rb +100 -21
- data/lib/tap/file_task.rb +3 -3
- data/lib/tap/generator/base.rb +1 -1
- data/lib/tap/generator/destroy.rb +10 -10
- data/lib/tap/generator/generate.rb +29 -18
- data/lib/tap/generator/generators/command/command_generator.rb +2 -2
- data/lib/tap/generator/generators/command/templates/command.erb +2 -2
- data/lib/tap/generator/generators/config/config_generator.rb +3 -3
- data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
- data/lib/tap/generator/generators/file_task/templates/task.erb +1 -1
- data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
- data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
- data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
- data/lib/tap/generator/generators/root/root_generator.rb +13 -13
- data/lib/tap/generator/generators/root/templates/README +0 -0
- data/lib/tap/generator/generators/root/templates/Rakefile +2 -2
- data/lib/tap/generator/generators/root/templates/gemspec +4 -5
- data/lib/tap/generator/generators/root/templates/tapfile +11 -8
- data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
- data/lib/tap/generator/generators/task/task_generator.rb +1 -3
- data/lib/tap/generator/generators/task/templates/test.erb +1 -3
- data/lib/tap/patches/optparse/summarize.rb +62 -0
- data/lib/tap/root.rb +41 -29
- data/lib/tap/support/aggregator.rb +16 -3
- data/lib/tap/support/assignments.rb +10 -9
- data/lib/tap/support/audit.rb +58 -64
- data/lib/tap/support/class_configuration.rb +33 -44
- data/lib/tap/support/combinator.rb +125 -0
- data/lib/tap/support/configurable.rb +13 -14
- data/lib/tap/support/configurable_class.rb +21 -43
- data/lib/tap/support/configuration.rb +55 -9
- data/lib/tap/support/constant.rb +87 -13
- data/lib/tap/support/constant_manifest.rb +116 -0
- data/lib/tap/support/dependencies.rb +54 -0
- data/lib/tap/support/dependency.rb +44 -0
- data/lib/tap/support/executable.rb +247 -32
- data/lib/tap/support/executable_queue.rb +1 -1
- data/lib/tap/support/gems/rake.rb +29 -8
- data/lib/tap/support/gems.rb +10 -30
- data/lib/tap/support/instance_configuration.rb +29 -3
- data/lib/tap/support/intern.rb +46 -0
- data/lib/tap/support/join.rb +143 -0
- data/lib/tap/support/joins/fork.rb +19 -0
- data/lib/tap/support/joins/merge.rb +22 -0
- data/lib/tap/support/joins/sequence.rb +21 -0
- data/lib/tap/support/joins/switch.rb +25 -0
- data/lib/tap/support/joins/sync_merge.rb +63 -0
- data/lib/tap/support/joins.rb +15 -0
- data/lib/tap/support/lazy_attributes.rb +17 -2
- data/lib/tap/support/lazydoc/comment.rb +503 -0
- data/lib/tap/support/lazydoc/config.rb +17 -0
- data/lib/tap/support/lazydoc/definition.rb +36 -0
- data/lib/tap/support/lazydoc/document.rb +152 -0
- data/lib/tap/support/lazydoc/method.rb +24 -0
- data/lib/tap/support/lazydoc.rb +269 -343
- data/lib/tap/support/manifest.rb +121 -103
- data/lib/tap/support/minimap.rb +90 -0
- data/lib/tap/support/node.rb +56 -0
- data/lib/tap/support/parser.rb +436 -0
- data/lib/tap/support/schema.rb +359 -0
- data/lib/tap/support/shell_utils.rb +3 -5
- data/lib/tap/support/string_ext.rb +60 -0
- data/lib/tap/support/tdoc.rb +7 -2
- data/lib/tap/support/templater.rb +30 -16
- data/lib/tap/support/validation.rb +77 -8
- data/lib/tap/task.rb +431 -143
- data/lib/tap/tasks/dump.rb +15 -10
- data/lib/tap/tasks/load.rb +112 -0
- data/lib/tap/tasks/rake.rb +4 -41
- data/lib/tap/test/assertions.rb +38 -0
- data/lib/tap/test/env_vars.rb +1 -1
- data/lib/tap/test/extensions.rb +79 -0
- data/lib/tap/test/file_test.rb +420 -0
- data/lib/tap/test/file_test_class.rb +12 -0
- data/lib/tap/test/regexp_escape.rb +87 -0
- data/lib/tap/test/script_test.rb +46 -0
- data/lib/tap/test/script_tester.rb +115 -0
- data/lib/tap/test/subset_test.rb +260 -0
- data/lib/tap/test/subset_test_class.rb +99 -0
- data/lib/tap/test/{tap_methods.rb → tap_test.rb} +45 -43
- data/lib/tap/test/utils.rb +231 -0
- data/lib/tap/test.rb +53 -26
- data/lib/tap.rb +3 -20
- metadata +50 -27
- data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
- data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
- data/lib/tap/patches/rake/testtask.rb +0 -57
- data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
- data/lib/tap/patches/ruby19/parsedate.rb +0 -16
- data/lib/tap/support/batchable.rb +0 -47
- data/lib/tap/support/batchable_class.rb +0 -107
- data/lib/tap/support/command_line.rb +0 -98
- data/lib/tap/support/comment.rb +0 -270
- data/lib/tap/support/constant_utils.rb +0 -127
- data/lib/tap/support/declarations.rb +0 -111
- data/lib/tap/support/framework.rb +0 -83
- data/lib/tap/support/framework_class.rb +0 -180
- data/lib/tap/support/run_error.rb +0 -39
- data/lib/tap/support/summary.rb +0 -30
- data/lib/tap/test/file_methods.rb +0 -377
- data/lib/tap/test/script_methods/script_test.rb +0 -98
- data/lib/tap/test/script_methods.rb +0 -107
- data/lib/tap/test/subset_methods.rb +0 -420
- data/lib/tap/workflow.rb +0 -200
@@ -0,0 +1,436 @@
|
|
1
|
+
require 'tap/support/schema'
|
2
|
+
autoload(:Shellwords, 'shellwords')
|
3
|
+
|
4
|
+
module Tap
|
5
|
+
module Support
|
6
|
+
|
7
|
+
# == Syntax
|
8
|
+
#
|
9
|
+
# ==== Round Assignment
|
10
|
+
# Tasks can be defined and set to a round using the following:
|
11
|
+
#
|
12
|
+
# break assigns task(s) to round
|
13
|
+
# -- next 0
|
14
|
+
# --+ next 1
|
15
|
+
# --++ next 2
|
16
|
+
# --+2 next 2
|
17
|
+
# --+2[1,2,3] 1,2,3 2
|
18
|
+
#
|
19
|
+
# Here all task (except c) are parsed into round 0, then the
|
20
|
+
# final argument reassigns e to round 3.
|
21
|
+
#
|
22
|
+
# schema = Parser.new("a -- b --+ c -- d -- e --+3[4]").schema
|
23
|
+
# schema.rounds(true) # => [[0,1,3],[2], nil, [4]]
|
24
|
+
#
|
25
|
+
# ==== Workflow Assignment
|
26
|
+
# All simple workflow patterns except switch can be specified within
|
27
|
+
# the parse syntax (switch is the exception because there is no good
|
28
|
+
# way to define the switch block).
|
29
|
+
#
|
30
|
+
# break pattern source(s) target(s)
|
31
|
+
# --: sequence last next
|
32
|
+
# --[] fork last next
|
33
|
+
# --{} merge next last
|
34
|
+
# --() sync_merge next last
|
35
|
+
#
|
36
|
+
# example meaning
|
37
|
+
# --1:2 1.sequence(2)
|
38
|
+
# --1:2:3 1.sequence(2,3)
|
39
|
+
# --:2: last.sequence(2,next)
|
40
|
+
# --[] last.fork(next)
|
41
|
+
# --1{2,3,4} 1.merge(2,3,4)
|
42
|
+
# --(2,3,4) last.sync_merge(2,3,4)
|
43
|
+
#
|
44
|
+
# Note how all of the bracketed styles behave similarly; they are
|
45
|
+
# parsed with essentially the same code, but reverse the source
|
46
|
+
# and target in the case of merges.
|
47
|
+
#
|
48
|
+
# Here a and b are sequenced inline. Task c is assigned to no
|
49
|
+
# workflow until the final argument which sequenced b and c.
|
50
|
+
#
|
51
|
+
# schema = Parser.new("a --: b -- c --1:2i").schema
|
52
|
+
# schema.argvs # => [["a"], ["b"], ["c"], []]
|
53
|
+
# schema.joins(true) # => [[:sequence,0,[1],{}], [:sequence,1,[2],{:iterate => true}]]
|
54
|
+
#
|
55
|
+
# ==== Globals
|
56
|
+
# Global instances of task (used, for example, by dependencies) may
|
57
|
+
# be assigned in the parse syntax as well. The break for a global
|
58
|
+
# is '--*'.
|
59
|
+
#
|
60
|
+
# schema = Parser.new("a -- b --* global_name --config for --global").schema
|
61
|
+
# schema.globals(true) # => [2]
|
62
|
+
#
|
63
|
+
# ==== Escapes and End Flags
|
64
|
+
# Breaks can be escaped by enclosing them in '-.' and '.-' delimiters;
|
65
|
+
# any number of arguments may be enclosed within the escape. After the
|
66
|
+
# end delimiter, breaks are active once again.
|
67
|
+
#
|
68
|
+
# schema = Parser.new("a -- b -- c").schema
|
69
|
+
# schema.argvs # => [["a"], ["b"], ["c"]]
|
70
|
+
#
|
71
|
+
# schema = Parser.new("a -. -- b .- -- c").schema
|
72
|
+
# schema.argvs # => [["a", "--", "b"], ["c"]]
|
73
|
+
#
|
74
|
+
# Parsing continues until the end of argv, or a an end flag '---' is
|
75
|
+
# reached. The end flag may also be escaped.
|
76
|
+
#
|
77
|
+
# schema = Parser.new("a -- b --- c").schema
|
78
|
+
# schema.argvs # => [["a"], ["b"]]
|
79
|
+
#
|
80
|
+
class Parser
|
81
|
+
|
82
|
+
# A set of parsing routines used internally by Tap::Support::Parser,
|
83
|
+
# modularized for ease of testing, and potential re-use. These methods
|
84
|
+
# require that <tt>current_index</tt> and <tt>previous_index</tt> be
|
85
|
+
# implemented in the including class.
|
86
|
+
module Utils
|
87
|
+
module_function
|
88
|
+
|
89
|
+
# Defines a break regexp that matches a bracketed-pairs
|
90
|
+
# break. The left and right brackets are specified as
|
91
|
+
# inputs. After a match:
|
92
|
+
#
|
93
|
+
# $1:: The source string after the break.
|
94
|
+
# (ex: '[]' => '', '1[]' => '1')
|
95
|
+
# $2:: The target string.
|
96
|
+
# (ex: '[]' => '', '1[1,2,3]' => '1,2,3')
|
97
|
+
# $3:: The modifier string.
|
98
|
+
# (ex: '[]i' => 'i', '1[1,2,3]is' => 'is')
|
99
|
+
#
|
100
|
+
def bracket_regexp(l, r)
|
101
|
+
/\A(\d*)#{Regexp.escape(l)}([\d,]*)#{Regexp.escape(r)}([A-z]*)\z/
|
102
|
+
end
|
103
|
+
|
104
|
+
# The escape begin argument
|
105
|
+
ESCAPE_BEGIN = "-."
|
106
|
+
|
107
|
+
# The escape end argument
|
108
|
+
ESCAPE_END = ".-"
|
109
|
+
|
110
|
+
# The parser end flag
|
111
|
+
END_FLAG = "---"
|
112
|
+
|
113
|
+
# Matches any breaking arg (ex: '--', '--+', '--1:2')
|
114
|
+
# After the match:
|
115
|
+
#
|
116
|
+
# $1:: The string after the break
|
117
|
+
# (ex: '--' => '', '--++' => '++', '--1(2,3)' => '1(2,3)')
|
118
|
+
#
|
119
|
+
BREAK = /\A--(\z|[\+\d\:\*\[\{\(].*\z)/
|
120
|
+
|
121
|
+
# Matches an execution-round break. After the match:
|
122
|
+
#
|
123
|
+
# $2:: The round string, or nil.
|
124
|
+
# (ex: '' => nil, '++' => '++', '+1' => '+1')
|
125
|
+
# $5:: The target string, or nil.
|
126
|
+
# (ex: '+' => nil, '+[1,2,3]' => '1,2,3')
|
127
|
+
#
|
128
|
+
ROUND = /\A((\+(\d*|\+*))(\[([\d,]*)\])?)?\z/
|
129
|
+
|
130
|
+
# Matches a sequence break. After the match:
|
131
|
+
#
|
132
|
+
# $1:: The sequence string after the break.
|
133
|
+
# (ex: ':' => ':', '1:2' => '1:2', '1:' => '1:', ':2' => ':2')
|
134
|
+
# $3:: The modifier string.
|
135
|
+
# (ex: ':i' => 'i', '1:2is' => 'is')
|
136
|
+
#
|
137
|
+
SEQUENCE = /\A(\d*(:\d*)+)([A-z]*)\z/
|
138
|
+
|
139
|
+
# Matches an instance break. After the match:
|
140
|
+
#
|
141
|
+
# $1:: The index string after the break.
|
142
|
+
# (ex: '*' => '', '*1' => '1')
|
143
|
+
#
|
144
|
+
INSTANCE = /\A\*(\d*)\z/
|
145
|
+
|
146
|
+
# A break regexp using "[]"
|
147
|
+
FORK = bracket_regexp("[", "]")
|
148
|
+
|
149
|
+
# A break regexp using "{}"
|
150
|
+
MERGE = bracket_regexp("{", "}")
|
151
|
+
|
152
|
+
# A break regexp using "()"
|
153
|
+
SYNC_MERGE = bracket_regexp("(", ")")
|
154
|
+
|
155
|
+
# Parses an indicies str along commas, and collects the indicies
|
156
|
+
# as integers. Ex:
|
157
|
+
#
|
158
|
+
# parse_indicies('') # => []
|
159
|
+
# parse_indicies('1') # => [1]
|
160
|
+
# parse_indicies('1,2,3') # => [1,2,3]
|
161
|
+
#
|
162
|
+
def parse_indicies(str, regexp=/,+/)
|
163
|
+
indicies = []
|
164
|
+
str.split(regexp).each do |n|
|
165
|
+
indicies << n.to_i unless n.empty?
|
166
|
+
end
|
167
|
+
indicies
|
168
|
+
end
|
169
|
+
|
170
|
+
# Parses the match of a ROUND regexp into a round index
|
171
|
+
# and an array of task indicies that should be added to the
|
172
|
+
# round. The inputs correspond to $2 and $5 for the match.
|
173
|
+
#
|
174
|
+
# If $2 is nil, a round index of zero is assumed; if $5 is
|
175
|
+
# nil or empty, then indicies of [:current_index] are assumed.
|
176
|
+
#
|
177
|
+
# parse_round("+", "") # => [1, [:current_index]]
|
178
|
+
# parse_round("+2", "1,2,3") # => [2, [1,2,3]]
|
179
|
+
# parse_round(nil, nil) # => [0, [:current_index]]
|
180
|
+
#
|
181
|
+
def parse_round(two, five)
|
182
|
+
index = case two
|
183
|
+
when nil then 0
|
184
|
+
when /\d/ then two[1, two.length-1].to_i
|
185
|
+
else two.length
|
186
|
+
end
|
187
|
+
[index, five.to_s.empty? ? [current_index] : parse_indicies(five)]
|
188
|
+
end
|
189
|
+
|
190
|
+
# Parses the match of a SEQUENCE regexp into an [indicies, options]
|
191
|
+
# array. The inputs corresponds to $1 and $3 for the match. The
|
192
|
+
# previous and current index are assumed if $1 starts and/or ends
|
193
|
+
# with a semi-colon.
|
194
|
+
#
|
195
|
+
# parse_sequence("1:2:3", '') # => [[1,2,3], {}]
|
196
|
+
# parse_sequence(":1:2:", '') # => [[:previous_index,1,2,:current_index], {}]
|
197
|
+
#
|
198
|
+
def parse_sequence(one, three)
|
199
|
+
seq = parse_indicies(one, /:+/)
|
200
|
+
seq.unshift previous_index if one[0] == ?:
|
201
|
+
seq << current_index if one[-1] == ?:
|
202
|
+
[seq, parse_options(three)]
|
203
|
+
end
|
204
|
+
|
205
|
+
# Parses the match of an INSTANCE regexp into an index.
|
206
|
+
# The input corresponds to $1 for the match. The current
|
207
|
+
# index is assumed if $1 is empty.
|
208
|
+
#
|
209
|
+
# parse_instance("1") # => 1
|
210
|
+
# parse_instance("") # => :current_index
|
211
|
+
#
|
212
|
+
def parse_instance(one)
|
213
|
+
one.empty? ? current_index : one.to_i
|
214
|
+
end
|
215
|
+
|
216
|
+
# Parses the match of an bracket_regexp into a [source_index,
|
217
|
+
# target_indicies, options] array. The inputs corresponds to $1,
|
218
|
+
# $2, and $3 for the match. The previous and current index are
|
219
|
+
# assumed if $1 and/or $2 is empty.
|
220
|
+
#
|
221
|
+
# parse_bracket("1", "2,3", "") # => [1, [2,3], {}]
|
222
|
+
# parse_bracket("", "", "") # => [:previous_index, [:current_index], {}]
|
223
|
+
# parse_bracket("1", "", "") # => [1, [:current_index], {}]
|
224
|
+
# parse_bracket("", "2,3", "") # => [:previous_index, [2,3], {}]
|
225
|
+
#
|
226
|
+
def parse_bracket(one, two, three)
|
227
|
+
targets = parse_indicies(two)
|
228
|
+
targets << current_index if targets.empty?
|
229
|
+
[one.empty? ? previous_index : one.to_i, targets, parse_options(three)]
|
230
|
+
end
|
231
|
+
|
232
|
+
# Parses an options string into a hash. The input corresponds
|
233
|
+
# to $3 in a SEQUENCE or bracket_regexp match. Raises an error
|
234
|
+
# if the options string contains unknown options.
|
235
|
+
#
|
236
|
+
# parse_options("") # => {}
|
237
|
+
# parse_options("is") # => {:iterate => true, :stack => true}
|
238
|
+
#
|
239
|
+
def parse_options(three)
|
240
|
+
options = {}
|
241
|
+
0.upto(three.length - 1) do |char_index|
|
242
|
+
char = three[char_index, 1]
|
243
|
+
unless index = Join::SHORT_FLAGS.index(char)
|
244
|
+
raise "unknown option in: #{three} (#{char})"
|
245
|
+
end
|
246
|
+
|
247
|
+
options[Join::FLAGS[index]] = true
|
248
|
+
end
|
249
|
+
options
|
250
|
+
end
|
251
|
+
|
252
|
+
# Parses an arg hash into a schema argv. An arg hash is a hash
|
253
|
+
# using numeric keys to specify the [row][col] in a two-dimensional
|
254
|
+
# array where a set of values should go. Breaks are added between
|
255
|
+
# rows (if necessary) and the array is collapsed to yield the
|
256
|
+
# argv:
|
257
|
+
#
|
258
|
+
# argh = {
|
259
|
+
# 0 => {
|
260
|
+
# 0 => 'a',
|
261
|
+
# 1 => ['b', 'c']},
|
262
|
+
# 1 => 'z'
|
263
|
+
# }
|
264
|
+
# parse_argh(argh) # => ['--', 'a', 'b', 'c', '--', 'z']
|
265
|
+
#
|
266
|
+
# Non-numeric keys are converted to integers using to_i and
|
267
|
+
# existing breaks (such as workflow breaks) occuring at the
|
268
|
+
# start of a row are preseved.
|
269
|
+
#
|
270
|
+
# argh = {
|
271
|
+
# '0' => {
|
272
|
+
# '0' => 'a',
|
273
|
+
# '1' => ['b', 'c']},
|
274
|
+
# '1' => ['--:', 'z']
|
275
|
+
# }
|
276
|
+
# parse_argh(argh) # => ['--', 'a', 'b', 'c', '--:', 'z']
|
277
|
+
#
|
278
|
+
def parse_argh(argh)
|
279
|
+
rows = []
|
280
|
+
argh.each_pair do |row, values|
|
281
|
+
if values.kind_of?(Hash)
|
282
|
+
arry = []
|
283
|
+
values.each_pair {|col, value| arry[col.to_i] = value }
|
284
|
+
values = arry
|
285
|
+
end
|
286
|
+
|
287
|
+
rows[row.to_i] = values
|
288
|
+
end
|
289
|
+
|
290
|
+
argv = []
|
291
|
+
rows.each do |row|
|
292
|
+
row = [row].flatten.compact
|
293
|
+
if row.empty? || row[0] !~ BREAK
|
294
|
+
argv << '--'
|
295
|
+
end
|
296
|
+
argv.concat row
|
297
|
+
end
|
298
|
+
argv
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
include Utils
|
303
|
+
|
304
|
+
# The schema into which nodes are parsed
|
305
|
+
attr_reader :schema
|
306
|
+
|
307
|
+
def initialize(argv=[])
|
308
|
+
@current_index = 0
|
309
|
+
@schema = Schema.new
|
310
|
+
parse(argv)
|
311
|
+
end
|
312
|
+
|
313
|
+
# Iterates through the argv splitting out task and workflow definitions.
|
314
|
+
# Task definitions are split out (with configurations) along round and/or
|
315
|
+
# workflow break lines. Rounds and workflows are dynamically parsed;
|
316
|
+
# tasks may be reassigned to different rounds or workflows by later
|
317
|
+
# arguments.
|
318
|
+
#
|
319
|
+
# Parse is non-destructive to argv. If a string argv is provided, parse
|
320
|
+
# splits it into an array using Shellwords; if a hash argv is provided,
|
321
|
+
# parse converts it to an array using Parser::Utils#parse_argh.
|
322
|
+
#
|
323
|
+
def parse(argv)
|
324
|
+
parse!(argv.kind_of?(String) ? argv : argv.dup)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Same as parse, but removes parsed args from argv.
|
328
|
+
def parse!(argv)
|
329
|
+
argv = case argv
|
330
|
+
when Array then argv
|
331
|
+
when String then Shellwords.shellwords(argv)
|
332
|
+
when Hash then parse_argh(argv)
|
333
|
+
else argv
|
334
|
+
end
|
335
|
+
argv.unshift('--')
|
336
|
+
|
337
|
+
escape = false
|
338
|
+
current_argv = schema[current_index].argv
|
339
|
+
|
340
|
+
while !argv.empty?
|
341
|
+
arg = argv.shift
|
342
|
+
|
343
|
+
# if escaping, add escaped arguments
|
344
|
+
# until an escape-end argument
|
345
|
+
if escape
|
346
|
+
if arg == ESCAPE_END
|
347
|
+
escape = false
|
348
|
+
else
|
349
|
+
current_argv << arg
|
350
|
+
end
|
351
|
+
|
352
|
+
next
|
353
|
+
end
|
354
|
+
|
355
|
+
case arg
|
356
|
+
when ESCAPE_BEGIN
|
357
|
+
# begin escaping if indicated
|
358
|
+
escape = true
|
359
|
+
|
360
|
+
when END_FLAG
|
361
|
+
# break on an end-flag
|
362
|
+
break
|
363
|
+
|
364
|
+
when BREAK
|
365
|
+
# a breaking argument was reached:
|
366
|
+
# unless the current argv is empty,
|
367
|
+
# append and start a new definition
|
368
|
+
unless current_argv.empty?
|
369
|
+
self.current_index += 1
|
370
|
+
current_argv = schema[current_index].argv
|
371
|
+
end
|
372
|
+
|
373
|
+
# parse the break string for any
|
374
|
+
# schema modifications
|
375
|
+
parse_break($1)
|
376
|
+
|
377
|
+
else
|
378
|
+
# add all other non-breaking args to
|
379
|
+
# the current argv; this includes
|
380
|
+
# both inputs and configurations
|
381
|
+
current_argv << arg
|
382
|
+
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
schema
|
387
|
+
end
|
388
|
+
|
389
|
+
def load(argv)
|
390
|
+
argv.each do |arg|
|
391
|
+
case arg
|
392
|
+
when Array
|
393
|
+
schema.nodes << arg
|
394
|
+
self.current_index += 1
|
395
|
+
else
|
396
|
+
parse_break(arg)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
schema
|
401
|
+
end
|
402
|
+
|
403
|
+
protected
|
404
|
+
|
405
|
+
# The index of the node currently being parsed.
|
406
|
+
attr_accessor :current_index # :nodoc:
|
407
|
+
|
408
|
+
# Returns current_index-1, or raises an error if current_index < 1.
|
409
|
+
def previous_index # :nodoc:
|
410
|
+
raise ArgumentError, 'there is no previous index' if current_index < 1
|
411
|
+
current_index - 1
|
412
|
+
end
|
413
|
+
|
414
|
+
# determines the type of break and modifies self appropriately
|
415
|
+
def parse_break(arg) # :nodoc:
|
416
|
+
case arg
|
417
|
+
when ROUND
|
418
|
+
round, indicies = parse_round($2, $5)
|
419
|
+
indicies.each {|index| schema[index].round = round }
|
420
|
+
|
421
|
+
when SEQUENCE
|
422
|
+
indicies, options = parse_sequence($1, $3)
|
423
|
+
while indicies.length > 1
|
424
|
+
schema.set(Joins::Sequence, indicies.shift, indicies[0], options)
|
425
|
+
end
|
426
|
+
|
427
|
+
when INSTANCE then schema[parse_instance($1)].globalize
|
428
|
+
when FORK then schema.set(Joins::Fork, *parse_bracket($1, $2, $3))
|
429
|
+
when MERGE then schema.set(Joins::Merge, *parse_bracket($1, $2, $3))
|
430
|
+
when SYNC_MERGE then schema.set(Joins::SyncMerge, *parse_bracket($1, $2, $3))
|
431
|
+
else raise ArgumentError, "invalid break argument: #{arg}"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|