casegen 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Enumerable
4
+
5
+ class Pipe
6
+ include Enumerable
7
+
8
+ attr_reader :enum, :filter_name, :filter_map, :args
9
+
10
+ def initialize enum, filter_spec = nil, *args, &filter_proc
11
+ @enum = enum
12
+ @args = args
13
+
14
+ case filter_spec
15
+ when Symbol
16
+ @filter_name = filter_spec
17
+ when String
18
+ @filter_name = filter_spec.intern
19
+ when nil
20
+ @filter_map = filter_proc
21
+ else
22
+ unless filter_spec.respond_to? :[]
23
+ raise ArgumentError,
24
+ "filter_spec must be a method name or respond to []."
25
+ end
26
+ @filter_map = filter_spec
27
+ end
28
+
29
+ unless @filter_name or @filter_map
30
+ raise ArgumentError,
31
+ "no filter specified."
32
+ end
33
+ end
34
+
35
+ def each
36
+ if @filter_name
37
+ filter_name = @filter_name
38
+ message = filter_name, *@args
39
+ @enum.each { |entry|
40
+ yield entry.send *message
41
+ }
42
+ elsif @filter_map
43
+ filter_map = @filter_map
44
+ args = *@args
45
+ @enum.each { |entry|
46
+ yield filter_map[entry, *args]
47
+ }
48
+ end
49
+ end
50
+
51
+ self
52
+ end
53
+
54
+ def pipe filter_spec = nil, *args, &filter_proc
55
+ Pipe.new self, filter_spec, *args, &filter_proc
56
+ end
57
+
58
+ end
59
+
60
+
61
+ =begin
62
+
63
+ ==class Enumerable
64
+ ===instance method
65
+ ---Enumerable#pipe filter_spec = nil, *args, &filter_proc
66
+
67
+ Can be used to "pipe" an (({Enumerable})) sequence through a filter.
68
+
69
+ (({Enumerable#pipe})) returns an (({Enumerable})) object whose (({each}))
70
+ method iterates over (({self})) and applies a filter to each enumerated
71
+ object, as specified by the arguments. Only the current element of the
72
+ sequence is kept in memory.
73
+
74
+ If (({filter_spec})) is a string or symbol, (({filter_proc})) is ignored
75
+ and (({filter_spec})) is treated as a method name. This method name is
76
+ sent, along with arguments (({args})), to each element of the sequence
77
+ being enumerated.
78
+
79
+ If (({filter_spec})) is anything else, except (({nil})), (({filter_proc}))
80
+ is ignored and (({filter_spec})) is required to be an object that responds
81
+ to (({[]})), such as a proc or a hash. The (({[]})) method of
82
+ (({filter_spec})) is called with each element of the sequence in turn as
83
+ an argument, along with (({args})).
84
+
85
+ If (({next_spec})) is not given, or is (({nil})), a block is required. In
86
+ this case, iteration proceeds as in the preceding paragraph.
87
+
88
+ Using (({#pipe})) has potential performance advantages. The iteration
89
+
90
+ e.collect { |x| x.m }.each { |y| ... }
91
+
92
+ can be rewritten as
93
+
94
+ e.pipe(:m).each { |y| ... }
95
+
96
+ which doesn't generate an intermediate array, and uses a send instead of a
97
+ proc call. Of course, it could also be written as
98
+
99
+ e.each { |x| y = x.m ... }
100
+
101
+ but that may be undesirable for readability or because the block is to be
102
+ taken from a proc contained in a variable:
103
+
104
+ pr = proc { ... }
105
+ e.pipe(:m).each &pr
106
+
107
+ Also, chains of (({collect})) and (({select})), such as
108
+
109
+ (1..100).collect { |x| x**2 }.select { |y| y > 1000 && y < 2000 }
110
+
111
+ can't be easily rewritten as a single (({select})).
112
+
113
+ ===examples
114
+
115
+ require 'enum/pipe'
116
+
117
+ [0,1,2,3,4].pipe { |x| x + 1 }.each { |x|
118
+ print x, " "
119
+ }
120
+
121
+ # prints: 1 2 3 4 5
122
+
123
+ stooges = ['lARRY', 'cURLY', 'mOE']
124
+ p stooges.pipe(:swapcase).reject { |x| x =~ /url/ }
125
+ p stooges.pipe(:tr, 'RlcOEL', 'gBboog').pipe(:capitalize).entries
126
+
127
+ # prints: ["Larry", "Moe"]
128
+ # ["Baggy", "Buggy", "Moo"]
129
+
130
+ ==version
131
+
132
+ Enumerable tools 1.6
133
+
134
+ The current version of this software can be found at
135
+ ((<"http://redshift.sourceforge.net/enum
136
+ "|URL:http://redshift.sourceforge.net/enum>)).
137
+
138
+ ==license
139
+ This software is distributed under the Ruby license.
140
+ See ((<"http://www.ruby-lang.org"|URL:http://www.ruby-lang.org>)).
141
+
142
+ ==author
143
+ Joel VanderWerf,
144
+ ((<vjoel@users.sourceforge.net|URL:mailto:vjoel@users.sourceforge.net>))
145
+
146
+ =end
147
+
148
+
149
+ if __FILE__ == $0
150
+
151
+ [0,1,2,3,4].pipe { |x| x + 1 }.each { |x|
152
+ print x, " "
153
+ }
154
+ puts
155
+
156
+ stooges = ['lARRY', 'cURLY', 'mOE']
157
+ p stooges.pipe(:swapcase).reject { |x| x =~ /url/ }
158
+ p stooges.pipe(:tr, 'RlcOEL', 'gBboog').pipe(:capitalize).entries
159
+
160
+ end
@@ -0,0 +1,442 @@
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