casegen 2.0.0 → 3.0.0

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +109 -0
  4. data/.ruby-version +1 -1
  5. data/Gemfile +3 -1
  6. data/Gemfile.lock +51 -6
  7. data/README.md +10 -119
  8. data/Rakefile +9 -7
  9. data/bin/casegen +2 -1
  10. data/casegen.gemspec +13 -9
  11. data/doc/bounding_box.rb +37 -0
  12. data/doc/cart.rb +43 -0
  13. data/doc/expect_only.rb +28 -0
  14. data/doc/pricing.rb +50 -0
  15. data/doc/ruby_array.rb +41 -0
  16. data/lib/case_gen/combination.rb +38 -0
  17. data/lib/case_gen/combo_matcher.rb +15 -0
  18. data/lib/case_gen/exclude_rule.rb +50 -0
  19. data/lib/case_gen/expect_rule.rb +24 -0
  20. data/lib/case_gen/generator.rb +40 -0
  21. data/lib/case_gen/output/exclude.rb +6 -0
  22. data/lib/case_gen/output/exclude_as_table.rb +13 -0
  23. data/lib/case_gen/output/exclude_as_text.rb +12 -0
  24. data/lib/case_gen/output/exclude_inline.rb +13 -0
  25. data/lib/case_gen/output/exclude_inline_footnotes.rb +20 -0
  26. data/lib/case_gen/output.rb +66 -0
  27. data/lib/case_gen/rule_description.rb +11 -0
  28. data/lib/case_gen/set.rb +16 -0
  29. data/lib/casegen.rb +15 -183
  30. data/spec/cart_sample_spec.rb +46 -0
  31. data/spec/case_gen/combination_spec.rb +11 -0
  32. data/spec/case_gen/exclude_rule_spec.rb +17 -0
  33. data/spec/exclude_as_table_spec.rb +39 -0
  34. data/spec/exclude_as_text_spec.rb +58 -0
  35. data/spec/exclude_inline_footnotes_spec.rb +58 -0
  36. data/spec/exclude_inline_spec.rb +50 -0
  37. data/spec/expect_only_spec.rb +30 -0
  38. data/spec/spec_helper.rb +113 -0
  39. metadata +101 -35
  40. data/.idea/encodings.xml +0 -5
  41. data/.idea/misc.xml +0 -5
  42. data/.idea/modules.xml +0 -9
  43. data/.idea/vcs.xml +0 -7
  44. data/doc/calc.sample.txt +0 -13
  45. data/doc/cart.sample.rb +0 -3
  46. data/doc/cart.sample.txt +0 -33
  47. data/doc/ruby_array.sample.rb +0 -26
  48. data/lib/agents/sets/enum/by.rb +0 -244
  49. data/lib/agents/sets/enum/cluster.rb +0 -164
  50. data/lib/agents/sets/enum/inject.rb +0 -50
  51. data/lib/agents/sets/enum/nest.rb +0 -117
  52. data/lib/agents/sets/enum/op.rb +0 -283
  53. data/lib/agents/sets/enum/pipe.rb +0 -160
  54. data/lib/agents/sets/enum/tree.rb +0 -442
  55. data/lib/agents/sets.rb +0 -313
  56. data/test/agents/console_output_test.rb +0 -27
  57. data/test/agents/sets.test.rb +0 -227
  58. data/test/agents_test.rb +0 -41
  59. data/test/casegen.tests.rb +0 -0
  60. data/test/parser_test.rb +0 -163
  61. data/test/test_helper.rb +0 -2
@@ -1,442 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- module Enumerable
4
-
5
- class TreeDelegator
6
- include Enumerable
7
-
8
- attr_reader :root, :child_name, :child_map,
9
- :args, :output_type
10
-
11
- def initialize root, child_spec = nil, *args, &child_proc
12
- @root = root
13
- @args = args
14
- @output_type = :nodes
15
-
16
- case child_spec
17
- when Symbol
18
- @child_name = child_spec
19
- when String
20
- @child_name = child_spec.intern
21
- when nil
22
- @child_map = child_proc
23
- else
24
- unless child_spec.respond_to? :[]
25
- raise ArgumentError,
26
- "child_spec must be a method name or respond to []."
27
- end
28
- @child_map = child_spec
29
- end
30
-
31
- unless @child_name or @child_map
32
- raise ArgumentError,
33
- "no child-getter specified."
34
- end
35
- end
36
-
37
- def get_children cur
38
- (if @child_name
39
- cur.send @child_name, *@args
40
- else
41
- @child_map[cur, *@args]
42
- end).to_a
43
- end
44
-
45
- end
46
-
47
- class ByBreadthDelegator < TreeDelegator
48
-
49
- def each level = [@root], &block
50
-
51
- children = []
52
- for node in level
53
- yield node
54
- children |= get_children(node) || []
55
- end
56
-
57
- if children and not children.empty?
58
- each children, &block
59
- end
60
-
61
- self
62
- end
63
-
64
- end
65
-
66
- class ByDepthDelegator < TreeDelegator
67
-
68
- def with_ancestors
69
- @output_type = :with_ancestors
70
- self
71
- end
72
-
73
- def branches
74
- @output_type = :branches
75
- self
76
- end
77
-
78
- def each(*args, &block)
79
- case @output_type
80
- when :nodes
81
- each_node *args, &block
82
- when :with_ancestors
83
- each_with_ancestors *args, &block
84
- when :branches
85
- each_branch *args, &block
86
- end
87
- end
88
-
89
- protected
90
- def each_node cur = @root, &block
91
-
92
- result = catch (:prune) do
93
- yield cur
94
-
95
- children = get_children cur
96
-
97
- if children
98
- for child in children
99
- each_node child, &block
100
- end
101
- end
102
-
103
- false
104
- end
105
-
106
- if result and result > 0
107
- throw :prune, result - 1
108
- end
109
-
110
- self
111
- end
112
-
113
- def each_with_ancestors cur = @root, ancestors = [], &block
114
-
115
- result = catch (:prune) do
116
- yield cur, ancestors
117
-
118
- children = get_children cur
119
-
120
- if children
121
- for child in children
122
- each_with_ancestors child, ancestors + [cur], &block
123
- end
124
- end
125
-
126
- false
127
- end
128
-
129
- if result and result > 0
130
- throw :prune, result - 1
131
- end
132
-
133
- self
134
- end
135
-
136
- def each_branch branch = [@root], &block
137
- cur = branch[-1]
138
-
139
- children = get_children cur
140
-
141
- if children and not children.empty?
142
- for child in children
143
- each_branch branch + [child], &block
144
- end
145
- else
146
- yield branch
147
- end
148
-
149
- self
150
- end
151
-
152
- end
153
-
154
- end
155
-
156
- class Object
157
- def by_depth child_spec = nil, *args, &child_proc
158
- Enumerable::ByDepthDelegator.new self, child_spec, *args, &child_proc
159
- end
160
- def by_breadth child_spec = nil, *args, &child_proc
161
- Enumerable::ByBreadthDelegator.new self, child_spec, *args, &child_proc
162
- end
163
- end
164
-
165
-
166
- =begin
167
-
168
- ==class Object
169
- ===instance methods
170
- ---Object#by_depth child_spec = nil, *args, &child_proc
171
- ---Object#by_breadth child_spec = nil, *args, &child_proc
172
-
173
- Allows use of (({Enumerable})) methods, such as (({each})), (({collect})),
174
- (({select})), etc., to iterate over objects which have a caller-specified tree
175
- structure (or, more generally, directed acyclic graph structure). The caller
176
- defines this structure by providing a way of calculating the children of each
177
- object, such as an accessor method for the array of children of a node in a
178
- tree.
179
-
180
- In order to yield a sequence of objects, the nonlinear structure of the tree is
181
- linearized in either a depth-first or a breadth-first way, depending on the
182
- method used, (({by_depth})) or (({by_breadth})). In a depth-first
183
- linearization, the iteration visits a node's children before continuing with
184
- the node's successive siblings. In a breadth-first linearization, the iteration
185
- visits all siblings before visiting any of their children. In either case, the
186
- parent is visited before its children, and the children are visited in an order
187
- consistent with their order in the sequence of children provided by their
188
- parent.
189
-
190
- Speaking loosely, one can think of a depth-first iteration as working branch by
191
- branch and a breadth-first iteration as working level by level, where a level
192
- consists of nodes of equal depth.
193
-
194
- ====usage
195
-
196
- require 'enum/tree'
197
-
198
- for node in root.by_depth :a_method, ...
199
-
200
- for node in root.by_depth a_proc, ...
201
-
202
- for node in root.by_depth { |node| ... return children }
203
-
204
- # by_breadth has the same form
205
-
206
- ====arguments
207
-
208
- The means of accessing the children of each node is specified in the
209
- argument list with a method name, a block, or an object that responds to
210
- (({[]})), such as a proc or a hash. In any case, the value returned must be an
211
- (({Enumerable})) object, typically an array.
212
-
213
- If (({child_spec})) is a string or symbol, (({child_proc})) is ignored and
214
- (({child_spec})) is treated as a method name. This method name is sent, along
215
- with arguments (({args})), to each node to generate the children. The node is
216
- considered childless when the method returns (({nil})) or (({false})) or an empty collection.
217
-
218
- If (({child_spec})) is anything else, except (({nil})), (({child_proc})) is
219
- ignored and (({child_spec})) is required to be an object that responds to
220
- (({[]})), such as a proc or a hash. The (({[]})) method of (({child_spec})) is
221
- called with each node as an argument, along with (({args})), to generate the
222
- children. The node is considered childless when (({[]})) returns (({nil})) or
223
- (({false})) or an empty collection.
224
-
225
- If (({child_spec})) is not given, or is (({nil})), a block is required. In this
226
- case, the block is converted to a proc and iteration proceeds as in the
227
- preceding paragraph.
228
-
229
- ====return value
230
-
231
- The return value is not an array, but an (({Enumerable})) object that refers
232
- to the original objects. In this sense, (({Object#by_depth})) and
233
- (({Object#by_breadth})) are ((*delegators*)). Typically, (({by_depth})) and
234
- (({by_breadth})) are used with the (({for ... in ...})) construct, or
235
- (equivalently) with (({each})), or with (({collect})), (({select})), and so on.
236
- In these cases, the dependence on the original data structure does not matter.
237
- To get the array of entries produced by (({by_depth})) or (({by_breadth})) as
238
- an independent data structure, use (({Enumerable#entries})) or
239
- (({Enumerable#to_a})).
240
-
241
- ====directed acyclic graphs
242
-
243
- If a node occurs as the child of two different parent nodes, the structure is
244
- not a tree. As long as no node is its own ancestor, these methods still produce
245
- a useful interation (it is the caller's responsibility to avoid cycles). The
246
- structure in this case is sometimes called a ((*directed acyclic graph*)). In a
247
- depth-first iteration, a node with two parents will be reached twice. In a
248
- breadth-first iteration, a node with two parents will be reaced once if the
249
- parents are at the same depth in the graph, but twice otherwise.
250
-
251
- ====modifiers
252
-
253
- The (({Object#by_depth})) method accepts two modifiers that affect the yielded
254
- values, but not the order of iteration:
255
-
256
- for node, ancestors in tree.by_depth(...).with_ancestors
257
-
258
- for branch in tree.by_depth(...).branches
259
-
260
- The (({with_ancestors})) modifier results in the same linearization, but
261
- returns, along with each node, the node's array of ancestors, starting with the
262
- root of the tree and ending with the immediate parent. In the non-tree case, the
263
- ancestor list doesn't contain all ancestors, but just one path from the root to
264
- the node. Each such path will occur once during the (({by_depth})) iteration.
265
-
266
- With the (({branches})) modifier, the iteration yields all branches of the tree
267
- (or directed acyclic graph). A ((*branch*)) is a path from the root to a leaf
268
- node.
269
-
270
- Note that a (({with_ancestors})) iteration yields at every node, but a
271
- (({branches})) iteration yields only at leaf nodes.
272
-
273
- ====prune
274
-
275
- Pruning the iteration means skipping a node and its descendants and continuing
276
- with the nodes that would normally follow them in the iteration. This can be
277
- done anywhere in dynamic scope during the iteration by simply throwing the
278
- (({:prune})) symbol:
279
-
280
- throw :prune
281
-
282
- If an additional integer argument is supplied:
283
-
284
- throw :prune, n
285
-
286
- then the pruning occurs not at the current node, but at the node (({n})) levels
287
- above the current node in the current ancestor list.
288
-
289
- Note that (({prune})) cannot used with the (({each_branch})) modifier discussed
290
- above; (({prune})) simply has no useful meaning in this context.
291
-
292
- ====examples
293
-
294
- require 'enum/tree'
295
-
296
- # Define a proc to compute the subclasses of a class
297
- # It would probably be better to make this a method of Class
298
- # and to implement it more efficiently, but for illustration...
299
-
300
- subclasses = proc { |cl|
301
- subs = []
302
- ObjectSpace.each_object(Class) { |sub|
303
- if sub.superclass == cl then subs << sub end
304
- }
305
- subs
306
- }
307
-
308
- print "Subclasses of Numeric:\n"
309
- for node in Numeric.by_depth subclasses
310
- print node, " "
311
- end
312
-
313
- # prints:
314
- # Subclasses of Numeric:
315
- # Numeric Float Integer Bignum Fixnum
316
-
317
- puts "\n\nBranches:"
318
- for branch in Numeric.by_depth(subclasses).branches
319
- p branch
320
- end
321
-
322
- # prints:
323
- # Branches:
324
- # [Numeric, Float]
325
- # [Numeric, Integer, Bignum]
326
- # [Numeric, Integer, Fixnum]
327
-
328
- puts "\nNodes with ancestors:"
329
- for x, a in Numeric.by_depth(subclasses).with_ancestors
330
- print "\t"*a.size, "node is #{x}, ancestors is #{a.inspect}.\n"
331
- end
332
-
333
- # prints:
334
- # Nodes with ancestors:
335
- # node is Numeric, ancestors is [].
336
- # node is Float, ancestors is [Numeric].
337
- # node is Integer, ancestors is [Numeric].
338
- # node is Bignum, ancestors is [Numeric, Integer].
339
- # node is Fixnum, ancestors is [Numeric, Integer].
340
-
341
- See the end of the source file for more examples.
342
-
343
- ===version
344
-
345
- Enumerable tools 1.6
346
-
347
- The current version of this software can be found at
348
- ((<"http://redshift.sourceforge.net/enum
349
- "|URL:http://redshift.sourceforge.net/enum>)).
350
-
351
- ===license
352
- This software is distributed under the Ruby license.
353
- See ((<"http://www.ruby-lang.org"|URL:http://www.ruby-lang.org>)).
354
-
355
- ===author
356
- Joel VanderWerf,
357
- ((<vjoel@users.sourceforge.net|URL:mailto:vjoel@users.sourceforge.net>))
358
-
359
- =end
360
-
361
-
362
- if __FILE__ == $0
363
-
364
- tree = [ [1,2,[3]], [4, [], 5] ]
365
- for x in tree.by_depth { |x| x.kind_of?(Array) ? x : [] }
366
- p x
367
- end
368
- puts
369
-
370
- class Node
371
-
372
- attr_reader :value, :children
373
-
374
- def initialize value, children = nil
375
- @value = value
376
- @children = children
377
- unless not children or children.respond_to? :each
378
- raise ArgumentError, "children must be nil or have an each method."
379
- end
380
- end
381
-
382
- end
383
-
384
- tree = Node.new(0,
385
- [Node.new(1,
386
- [Node.new(2,
387
- [Node.new(3)]),
388
- Node.new(4),
389
- Node.new(5)]),
390
- Node.new(6)])
391
-
392
- for node in tree.by_depth :children
393
- if node.value == 4
394
- throw :prune, 1
395
- end
396
- print node.value
397
- end
398
- puts
399
-
400
- for node in tree.by_breadth :children
401
- print node.value
402
- end
403
- puts
404
-
405
- # Define a proc to compute the subclasses of a Class
406
- # It would probably be better to make this a method of Class
407
- # and to implement it more efficiently, but for illustration...
408
- subclasses = proc { |cl|
409
- subs = []
410
- ObjectSpace.each_object(Class) { |sub|
411
- if sub.superclass == cl then subs << sub end
412
- }
413
- subs
414
- }
415
-
416
- print "\nSubclasses of Numeric:\n"
417
- for node in Numeric.by_depth subclasses
418
- print node, " "
419
- end
420
- print "\n\n"
421
-
422
- puts "Branches:"
423
- for branch in Numeric.by_depth(subclasses).branches
424
- p branch
425
- end
426
- puts
427
-
428
- puts "Nodes with ancestors:"
429
- for x, a in Numeric.by_depth(subclasses).with_ancestors
430
- print "\t"*a.size, "node is #{x}, ancestors is #{a.inspect}.\n"
431
- end
432
- puts
433
-
434
- # print the inheritance hierarchy of a given class
435
- if ARGV[0]
436
- root = Object.const_get(ARGV[0])
437
- for x, a in root.by_depth(subclasses).with_ancestors
438
- print "\t"*a.size, x, "\n"
439
- end
440
- end
441
-
442
- end
data/lib/agents/sets.rb DELETED
@@ -1,313 +0,0 @@
1
- require "#{File.dirname(__FILE__)}/../casegen"
2
- $LOAD_PATH << "#{File.expand_path(File.join(File.dirname(__FILE__), 'sets'))}"
3
- require 'enum/op'
4
- require 'tablesmith'
5
-
6
- class String
7
- def to_u
8
- self.gsub(/ /, '_')
9
- end
10
- end
11
-
12
- module CLabs::CaseGen
13
- class Set
14
- attr_reader :name, :data
15
-
16
- def initialize(name, data_array)
17
- @name = name
18
- @data = data_array
19
- strip_data
20
- end
21
-
22
- def strip_data
23
- @data.collect! do |datum| datum.strip end
24
- end
25
-
26
- def values
27
- @data
28
- end
29
- end
30
-
31
- class Sets < Agent
32
- attr_accessor :sets, :combinations, :set_titles
33
-
34
- def Sets.agent_id
35
- "casegen:sets"
36
- end
37
-
38
- def initialize(data, reference_agents=nil)
39
- @data = data
40
- @sets = []
41
- parse_sets
42
- end
43
-
44
- def parse_sets
45
- set_names = @data.scan(/^\s*(\w.*):/)
46
- set_data = @data.scan(/:(.*)/)
47
- sets = set_names.flatten.zip(set_data.flatten)
48
- sets.each do |set_array|
49
- @sets << Set.new(set_array[0], set_array[1].split(/, /))
50
- end
51
- generate_combinations
52
- end
53
-
54
- def generate_combinations
55
- arrays = []
56
- @set_titles = []
57
- @sets.each do |set| arrays << set.data; @set_titles << set.name end
58
- @combinations = all(*arrays)
59
- end
60
-
61
- def titles
62
- @set_titles
63
- end
64
-
65
- def all(*args)
66
- result = []
67
- EnumerableOperator::Product.new(*args).each { |tuple|
68
- result << tuple
69
- }
70
- result
71
- end
72
-
73
- def set_names
74
- names = []
75
- @sets.each do |set| names << set.name end
76
- names
77
- end
78
-
79
- def set_by_name(setname)
80
- @sets.detect do |set| set.name =~ /#{Regexp.escape(setname)}/ end
81
- end
82
-
83
- end
84
-
85
- class Criteria
86
- attr_reader :set_names, :set_values, :equalities
87
-
88
- def initialize(data)
89
- @data = data
90
- @equalities = {}
91
- parse
92
- end
93
-
94
- def parse
95
- @data.split(/AND/).each do |bit|
96
- set_name, set_value = bit.split(/==|=/)
97
- set_name.strip!; set_value.strip!
98
- if @equalities.keys.include?(set_name)
99
- raise ParserException.new("Rule cannot have the same set <#{set_name}> equal to different values <#{@equalities[set_name]}, #{set_value}>")
100
- end
101
- @equalities[set_name] = set_value
102
- end
103
- @set_names = @equalities.keys
104
- @set_values = @equalities.values
105
- end
106
-
107
- # hash keys should be valid set names and hash values should be valid
108
- # set values in the named set
109
- def match(hash)
110
- # must match all equalities
111
- @equalities.each_pair do |eq_name, eq_value|
112
- actual_value = hash[eq_name]
113
- return false if actual_value.nil?
114
- return false if actual_value != eq_value
115
- end
116
- return true
117
- end
118
-
119
- def to_s
120
- @data
121
- end
122
- end
123
-
124
- class Rule
125
- attr_reader :criteria, :description, :data
126
-
127
- def initialize(rule_data)
128
- @data = rule_data
129
- parse_rule
130
- end
131
-
132
- def parse_rule
133
- data = @data.sub(self.class.regexp, '')
134
- criteria_data, *@description = data.split(/\n/)
135
- criteria_data.strip!
136
- @criteria = Criteria.new(criteria_data)
137
- @description = (@description.join("\n") + "\n").outdent.strip
138
- end
139
- end
140
-
141
- class ExcludeRule < Rule
142
- def type_description
143
- "exclude"
144
- end
145
-
146
- def ExcludeRule.regexp
147
- /^exclude/i
148
- end
149
-
150
- def ExcludeRule.create(rule_data)
151
- return ExcludeRule.new(rule_data) if rule_data =~ regexp
152
- return nil
153
- end
154
- end
155
-
156
- class Rules < Agent
157
- def Rules.agent_id
158
- "casegen:rules"
159
- end
160
-
161
- def initialize(data, reference_agents=[])
162
- @data = data
163
- @agents = reference_agents
164
- @rules = []
165
- @rule_classes = []
166
- ObjectSpace.each_object(Class) do |obj|
167
- @rule_classes << obj if obj.ancestors.include?(Rule) && obj != Rule
168
- end
169
- parse_data
170
- end
171
-
172
- def parse_data
173
- raw_rules = @data.split(/(?=^\S)/)
174
-
175
- raw_rules.each do |rule|
176
- @rule_classes.each do |rule_class|
177
- @rules << rule_class.create(rule.strip)
178
- end
179
- end
180
- @rules.compact!
181
- @rules.flatten!
182
- validate_rules
183
- end
184
-
185
- def validate_rules
186
- @agents.each do |agent|
187
- if agent.class == Sets
188
- @rules.each do |rule|
189
- rule.criteria.equalities.each_pair do |set_name, set_value|
190
- set = agent.set_by_name(set_name)
191
- if set.nil?
192
- raise ParserException.new("Invalid set name <#{set_name}> " +
193
- "in rule <#{rule.criteria}>. Valid set names are <#{agent.set_names.join(', ')}>.")
194
- end
195
- if !set.values.include?(set_value)
196
- raise ParserException.new("Invalid set value <#{set_value}> " +
197
- "in rule <#{rule.criteria}>. Valid set values for <#{set.name}> " +
198
- "are <#{set.values.join(', ')}>.")
199
- end
200
- end
201
- end
202
- end
203
- end
204
- end
205
-
206
- def length
207
- @rules.length
208
- end
209
-
210
- def [](index)
211
- return @rules[index]
212
- end
213
-
214
- def each(&block)
215
- @rules.each(&block)
216
- end
217
-
218
- def combinations
219
- return @combinations if !@combinations.nil?
220
- if @agents[0].class == Sets
221
- agent = @agents[0]
222
- @combinations = []
223
- agent.combinations.each do |combo|
224
- delete = false
225
- combo_hash = {}
226
- i = 0
227
- # combo is an array of values, in the same order of the set_titles.
228
- # combo_hash will have set names matched with set values
229
- agent.set_titles.each do |title|
230
- combo_hash[title] = combo[i]
231
- i += 1
232
- end
233
- @rules.each do |rule|
234
- delete |= rule.criteria.match(combo_hash)
235
- end
236
- @combinations << combo if !delete
237
- end
238
- return @combinations
239
- end
240
- return []
241
- end
242
-
243
- def titles
244
- @agents[0].titles
245
- end
246
-
247
- def to_s
248
- puts @agents[0].combinations.inspect if !@agents[0].nil?
249
- puts
250
- puts @rules.inspect
251
- end
252
- end
253
-
254
- class ConsoleOutput < Agent
255
- def ConsoleOutput.agent_id
256
- "casegen:console"
257
- end
258
-
259
- def initialize(data, reference_agents, io=STDOUT)
260
- @data = data
261
- @agents = reference_agents
262
- table = [@agents[0].titles] + @agents[0].combinations
263
- io.puts table.to_table.pretty_inspect
264
- io.puts
265
- @agents[0].each do |rule|
266
- io.puts rule.data
267
- io.puts
268
- end if @agents[0].is_a?(Rules)
269
- end
270
- end
271
-
272
- class RubyArrayOutput < Agent
273
- def self.agent_id
274
- "casegen:ruby_array"
275
- end
276
-
277
- def initialize(data, reference_agents, io=STDOUT)
278
- @io = io
279
- @struct_name = "Case"
280
- @struct_name = data if !data.empty?
281
- @agents = reference_agents
282
- @agents.each do |agent| execute(agent) end
283
- end
284
-
285
- def execute(agent)
286
- struct_header = "#{@struct_name} = Struct.new("
287
- struct = ''
288
- agent.titles.each do |title|
289
- struct << ', ' if !struct.empty?
290
- struct << ":#{title.to_u.downcase}"
291
- end
292
- struct << ')'
293
-
294
- guts_header = 'cases = ['
295
- guts = ''
296
- agent.combinations.each do |combo|
297
- guts << ",\n#{' ' * guts_header.length}" if !guts.empty?
298
- guts << "#{@struct_name}.new#{combo.inspect.gsub(/\[/, '(').gsub(/\]/, ')')}"
299
- end
300
- @io.print(struct_header)
301
- @io.print(struct)
302
- @io.print("\n\n")
303
- @io.print(guts_header)
304
- @io.print(guts)
305
- @io.print("]\n")
306
- end
307
- end
308
- end
309
-
310
- if __FILE__ == $0
311
- sets = CLabs::CaseGen::Sets.new("a: 1, 2\nb: 3, 4")
312
- puts sets.combinations
313
- end