casegen 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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