tap 0.12.4 → 0.17.0

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