caruby-core 1.5.5 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -0
- data/History.md +5 -1
- data/lib/caruby.rb +3 -5
- data/lib/caruby/caruby-src.tar.gz +0 -0
- data/lib/caruby/database.rb +53 -69
- data/lib/caruby/database/application_service.rb +25 -0
- data/lib/caruby/database/cache.rb +60 -0
- data/lib/caruby/database/fetched_matcher.rb +52 -38
- data/lib/caruby/database/lazy_loader.rb +4 -4
- data/lib/caruby/database/operation.rb +34 -0
- data/lib/caruby/database/persistable.rb +171 -86
- data/lib/caruby/database/persistence_service.rb +32 -34
- data/lib/caruby/database/persistifier.rb +100 -43
- data/lib/caruby/database/reader.rb +107 -85
- data/lib/caruby/database/reader_template_builder.rb +60 -0
- data/lib/caruby/database/saved_matcher.rb +3 -3
- data/lib/caruby/database/sql_executor.rb +88 -17
- data/lib/caruby/database/writer.rb +213 -177
- data/lib/caruby/database/writer_template_builder.rb +334 -0
- data/lib/caruby/{util → helpers}/controlled_value.rb +0 -0
- data/lib/caruby/{util → helpers}/coordinate.rb +4 -4
- data/lib/caruby/{util → helpers}/person.rb +3 -3
- data/lib/caruby/{util → helpers}/properties.rb +7 -9
- data/lib/caruby/{util → helpers}/roman.rb +2 -2
- data/lib/caruby/{util → helpers}/version.rb +1 -1
- data/lib/caruby/json/deserializer.rb +2 -2
- data/lib/caruby/json/serializer.rb +49 -7
- data/lib/caruby/metadata.rb +30 -0
- data/lib/caruby/metadata/java_property.rb +21 -0
- data/lib/caruby/metadata/propertied.rb +191 -0
- data/lib/caruby/metadata/property.rb +22 -0
- data/lib/caruby/metadata/property_characteristics.rb +201 -0
- data/lib/caruby/migration/migratable.rb +11 -182
- data/lib/caruby/rdbi/driver/jdbc.rb +446 -0
- data/lib/caruby/resource.rb +20 -823
- data/lib/caruby/version.rb +1 -1
- data/test/lib/caruby/database/cache_test.rb +54 -0
- data/test/lib/caruby/{util → helpers}/controlled_value_test.rb +3 -5
- data/test/lib/caruby/{util → helpers}/person_test.rb +4 -6
- data/test/lib/caruby/helpers/properties_test.rb +34 -0
- data/test/lib/caruby/{util → helpers}/roman_test.rb +2 -3
- data/test/lib/caruby/{util → helpers}/version_test.rb +2 -3
- data/test/lib/helper.rb +7 -0
- metadata +161 -214
- data/lib/caruby/cli/application.rb +0 -36
- data/lib/caruby/cli/command.rb +0 -202
- data/lib/caruby/csv/csv_mapper.rb +0 -159
- data/lib/caruby/csv/csvio.rb +0 -203
- data/lib/caruby/database/search_template_builder.rb +0 -56
- data/lib/caruby/database/store_template_builder.rb +0 -278
- data/lib/caruby/domain.rb +0 -193
- data/lib/caruby/domain/attribute.rb +0 -584
- data/lib/caruby/domain/attributes.rb +0 -628
- data/lib/caruby/domain/dependency.rb +0 -225
- data/lib/caruby/domain/id_alias.rb +0 -22
- data/lib/caruby/domain/importer.rb +0 -183
- data/lib/caruby/domain/introspection.rb +0 -176
- data/lib/caruby/domain/inverse.rb +0 -172
- data/lib/caruby/domain/inversible.rb +0 -90
- data/lib/caruby/domain/java_attribute.rb +0 -173
- data/lib/caruby/domain/merge.rb +0 -185
- data/lib/caruby/domain/metadata.rb +0 -142
- data/lib/caruby/domain/mixin.rb +0 -35
- data/lib/caruby/domain/properties.rb +0 -95
- data/lib/caruby/domain/reference_visitor.rb +0 -428
- data/lib/caruby/domain/uniquify.rb +0 -50
- data/lib/caruby/import/java.rb +0 -387
- data/lib/caruby/migration/migrator.rb +0 -918
- data/lib/caruby/migration/resource_module.rb +0 -9
- data/lib/caruby/migration/uniquify.rb +0 -17
- data/lib/caruby/util/attribute_path.rb +0 -44
- data/lib/caruby/util/cache.rb +0 -56
- data/lib/caruby/util/class.rb +0 -149
- data/lib/caruby/util/collection.rb +0 -1152
- data/lib/caruby/util/domain_extent.rb +0 -46
- data/lib/caruby/util/file_separator.rb +0 -65
- data/lib/caruby/util/inflector.rb +0 -27
- data/lib/caruby/util/log.rb +0 -95
- data/lib/caruby/util/math.rb +0 -12
- data/lib/caruby/util/merge.rb +0 -59
- data/lib/caruby/util/module.rb +0 -18
- data/lib/caruby/util/options.rb +0 -97
- data/lib/caruby/util/partial_order.rb +0 -35
- data/lib/caruby/util/pretty_print.rb +0 -204
- data/lib/caruby/util/stopwatch.rb +0 -74
- data/lib/caruby/util/topological_sync_enumerator.rb +0 -62
- data/lib/caruby/util/transitive_closure.rb +0 -55
- data/lib/caruby/util/tree.rb +0 -48
- data/lib/caruby/util/trie.rb +0 -37
- data/lib/caruby/util/uniquifier.rb +0 -30
- data/lib/caruby/util/validation.rb +0 -20
- data/lib/caruby/util/visitor.rb +0 -365
- data/lib/caruby/util/weak_hash.rb +0 -36
- data/test/lib/caruby/csv/csv_mapper_test.rb +0 -40
- data/test/lib/caruby/csv/csvio_test.rb +0 -69
- data/test/lib/caruby/database/persistable_test.rb +0 -92
- data/test/lib/caruby/domain/domain_test.rb +0 -112
- data/test/lib/caruby/domain/inversible_test.rb +0 -99
- data/test/lib/caruby/domain/reference_visitor_test.rb +0 -130
- data/test/lib/caruby/import/java_test.rb +0 -80
- data/test/lib/caruby/import/mixed_case_test.rb +0 -14
- data/test/lib/caruby/migration/test_case.rb +0 -102
- data/test/lib/caruby/test_case.rb +0 -230
- data/test/lib/caruby/util/cache_test.rb +0 -23
- data/test/lib/caruby/util/class_test.rb +0 -61
- data/test/lib/caruby/util/collection_test.rb +0 -398
- data/test/lib/caruby/util/command_test.rb +0 -55
- data/test/lib/caruby/util/domain_extent_test.rb +0 -60
- data/test/lib/caruby/util/file_separator_test.rb +0 -30
- data/test/lib/caruby/util/inflector_test.rb +0 -12
- data/test/lib/caruby/util/lazy_hash_test.rb +0 -34
- data/test/lib/caruby/util/merge_test.rb +0 -83
- data/test/lib/caruby/util/module_test.rb +0 -25
- data/test/lib/caruby/util/options_test.rb +0 -59
- data/test/lib/caruby/util/partial_order_test.rb +0 -42
- data/test/lib/caruby/util/pretty_print_test.rb +0 -85
- data/test/lib/caruby/util/properties_test.rb +0 -50
- data/test/lib/caruby/util/stopwatch_test.rb +0 -18
- data/test/lib/caruby/util/topological_sync_enumerator_test.rb +0 -69
- data/test/lib/caruby/util/transitive_closure_test.rb +0 -67
- data/test/lib/caruby/util/tree_test.rb +0 -23
- data/test/lib/caruby/util/trie_test.rb +0 -14
- data/test/lib/caruby/util/visitor_test.rb +0 -278
- data/test/lib/caruby/util/weak_hash_test.rb +0 -45
- data/test/lib/examples/clinical_trials/migration/migration_test.rb +0 -58
- data/test/lib/examples/clinical_trials/migration/test_case.rb +0 -38
@@ -1,204 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
require 'date'
|
3
|
-
require 'pp'
|
4
|
-
require 'stringio'
|
5
|
-
require 'caruby/util/options'
|
6
|
-
require 'caruby/util/collection'
|
7
|
-
require 'caruby/util/inflector'
|
8
|
-
|
9
|
-
class PrettyPrint
|
10
|
-
# The standard +prettyprint+ gem SingleLine is adjusted to add an output accessor and an optional output argument to {#initialize}.
|
11
|
-
class SingleLine
|
12
|
-
# @return [String] the print target
|
13
|
-
attr_reader :output
|
14
|
-
|
15
|
-
alias :base__initialize :initialize
|
16
|
-
private :base__initialize
|
17
|
-
|
18
|
-
# Overrides the standard SingleLine initializer to supply an output parameter default.
|
19
|
-
def initialize(output='', maxwidth=nil, newline=nil)
|
20
|
-
base__initialize(output, maxwidth, newline)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# A PrintWrapper prints arguments by calling a printer proc.
|
26
|
-
class PrintWrapper < Proc
|
27
|
-
# Creates a new PrintWrapper on the given arguments.
|
28
|
-
def initialize(*args)
|
29
|
-
super()
|
30
|
-
@args = args
|
31
|
-
end
|
32
|
-
|
33
|
-
# @param args this wrapper's print block parameters
|
34
|
-
# @return [PrintWrapper] self
|
35
|
-
def wrap(*args)
|
36
|
-
@args = args
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
# Calls this PrintWrapper's print procedure on the arguments set in the initializer.
|
41
|
-
def to_s
|
42
|
-
@args.empty? ? 'nil' : call(*@args)
|
43
|
-
end
|
44
|
-
|
45
|
-
alias :inspect :to_s
|
46
|
-
end
|
47
|
-
|
48
|
-
class Object
|
49
|
-
# @return [String] this object's class demodulized name and object id
|
50
|
-
def print_class_and_id
|
51
|
-
"#{self.class.qp}@#{object_id}"
|
52
|
-
end
|
53
|
-
|
54
|
-
# qp, an abbreviation for quick-print, calls {#print_class_and_id} in this base implementation.
|
55
|
-
alias :qp :print_class_and_id
|
56
|
-
|
57
|
-
# Formats this object with the standard {PrettyPrint}.
|
58
|
-
#
|
59
|
-
# @param [Hash, Symbol, nil] opts the print options
|
60
|
-
# @option opts [Boolean] :single_line print the output on a single line
|
61
|
-
# @return [String] the formatted print result
|
62
|
-
def pp_s(opts=nil)
|
63
|
-
s = StringIO.new
|
64
|
-
if Options.get(:single_line, opts) then
|
65
|
-
PP.singleline_pp(self, s)
|
66
|
-
else
|
67
|
-
PP.pp(self, s)
|
68
|
-
end
|
69
|
-
s.rewind
|
70
|
-
s.read.chomp
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class Numeric
|
75
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
76
|
-
alias :qp :to_s
|
77
|
-
end
|
78
|
-
|
79
|
-
class String
|
80
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
81
|
-
alias :qp :to_s
|
82
|
-
end
|
83
|
-
|
84
|
-
class TrueClass
|
85
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
86
|
-
alias :qp :to_s
|
87
|
-
end
|
88
|
-
|
89
|
-
class FalseClass
|
90
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
91
|
-
alias :qp :to_s
|
92
|
-
end
|
93
|
-
|
94
|
-
class NilClass
|
95
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
96
|
-
alias :qp :inspect
|
97
|
-
end
|
98
|
-
|
99
|
-
class Symbol
|
100
|
-
# Alias #{Object#qp} to {#to_s} in this primitive class.
|
101
|
-
alias :qp :inspect
|
102
|
-
end
|
103
|
-
|
104
|
-
class Module
|
105
|
-
# @return [String ] the demodulized name
|
106
|
-
def qp
|
107
|
-
name[/\w+$/]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
module Enumerable
|
112
|
-
# Prints this Enumerable with a filter that calls qp on each item.
|
113
|
-
# Non-collection Enumerable classes override this method to delegate to {Object#qp}.
|
114
|
-
#
|
115
|
-
# Unlike {Object#qp}, this implementation accepts the {Object#pp_s} options.
|
116
|
-
# The options are used to format this Enumerable, but are not propagated to the
|
117
|
-
# enumerated items.
|
118
|
-
#
|
119
|
-
# @param (see Object#pp_s)
|
120
|
-
# @return [String] the formatted result
|
121
|
-
def qp(opts=nil)
|
122
|
-
wrap { |item| item.qp }.pp_s(opts)
|
123
|
-
end
|
124
|
-
|
125
|
-
# If a transformer block is given to this method, then the block is applied to each
|
126
|
-
# enumerated item before pretty-printing the result.
|
127
|
-
#
|
128
|
-
# @param (see Object#pp_s)
|
129
|
-
# @yield [item] transforms the item to print
|
130
|
-
# @yieldparam item the item to print
|
131
|
-
# @return (see Oblect#pp_s)
|
132
|
-
def pp_s(opts=nil)
|
133
|
-
# delegate to Object if no block
|
134
|
-
return super unless block_given?
|
135
|
-
# make a print wrapper
|
136
|
-
wrapper = PrintWrapper.new { |item| yield item }
|
137
|
-
# print using the wrapper on each item
|
138
|
-
wrap { |item| wrapper.wrap(item) }.pp_s(opts)
|
139
|
-
end
|
140
|
-
|
141
|
-
# Pretty-prints the content within brackets, as is done by the Array pretty printer.
|
142
|
-
def pretty_print(q)
|
143
|
-
q.group(1, '[', ']') {
|
144
|
-
q.seplist(self) { |v|
|
145
|
-
q.pp v
|
146
|
-
}
|
147
|
-
}
|
148
|
-
end
|
149
|
-
|
150
|
-
# Pretty-prints the cycle within brackets, as is done by the Array pretty printer.
|
151
|
-
def pretty_print_cycle(q)
|
152
|
-
q.text(empty? ? '[]' : '[...]')
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
module Hashable
|
157
|
-
# qp, short for quick-print, prints this Hashable with a filter that calls qp on each key and value.
|
158
|
-
#
|
159
|
-
# @return [String] the quick-print result
|
160
|
-
def qp
|
161
|
-
qph = {}
|
162
|
-
each { |k, v| qph[k.qp] = v.qp }
|
163
|
-
qph.pp_s
|
164
|
-
end
|
165
|
-
|
166
|
-
def pretty_print(q)
|
167
|
-
Hash === self ? q.pp_hash(self) : q.pp_hash(to_hash)
|
168
|
-
end
|
169
|
-
|
170
|
-
def pretty_print_cycle(q)
|
171
|
-
q.text(empty? ? '{}' : '{...}')
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
class String
|
176
|
-
# Pretty-prints this String using the Object pretty_print rather than Enumerable pretty_print.
|
177
|
-
def pretty_print(q)
|
178
|
-
q.text self
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
class DateTime
|
183
|
-
# @return [String] the formatted +strftime+
|
184
|
-
def pretty_print(q)
|
185
|
-
q.text(strftime)
|
186
|
-
end
|
187
|
-
|
188
|
-
# qp, an abbreviation for quick-print, is an alias for {#to_s} in this primitive class.
|
189
|
-
alias :qp :to_s
|
190
|
-
end
|
191
|
-
|
192
|
-
class Set
|
193
|
-
# Formats this set using {Enumerable#pretty_print}.
|
194
|
-
def pretty_print(q)
|
195
|
-
# mark this object as visited; this fragment is inferred from pp.rb and is necessary to detect a cycle
|
196
|
-
Thread.current[:__inspect_key__] << __id__
|
197
|
-
to_a.pretty_print(q)
|
198
|
-
end
|
199
|
-
|
200
|
-
# The pp.rb default pretty printing method for general objects that are detected as part of a cycle.
|
201
|
-
def pretty_print_cycle(q)
|
202
|
-
to_a.pretty_print_cycle(q)
|
203
|
-
end
|
204
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'benchmark'
|
2
|
-
|
3
|
-
# Stopwatch is a simple execution time accumulator.
|
4
|
-
class Stopwatch
|
5
|
-
# Time accumulates elapsed real time and total CPU time.
|
6
|
-
class Time
|
7
|
-
# @return [Benchmark::Tms] the Tms wrapped by this Time
|
8
|
-
attr_reader :tms
|
9
|
-
|
10
|
-
# @param [Benchmark::Tms, nil] the starting time (default is now)
|
11
|
-
def initialize(tms=nil)
|
12
|
-
@tms = tms || Benchmark::Tms.new
|
13
|
-
end
|
14
|
-
|
15
|
-
# @return [Numeric] the cumulative elapsed real clock time
|
16
|
-
def elapsed
|
17
|
-
@tms.real
|
18
|
-
end
|
19
|
-
|
20
|
-
# @return [Numeric] the cumulative CPU total time
|
21
|
-
def cpu
|
22
|
-
@tms.total
|
23
|
-
end
|
24
|
-
|
25
|
-
# Adds the time to execute the given block to this time.
|
26
|
-
#
|
27
|
-
# @return [Numeric] the split execution Time
|
28
|
-
def split(&block)
|
29
|
-
stms = Benchmark.measure(&block)
|
30
|
-
@tms += stms
|
31
|
-
Time.new(stms)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Sets this benchmark timer to zero.
|
35
|
-
def reset
|
36
|
-
@tms = Benchmark::Tms.new
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Executes the given block
|
41
|
-
#
|
42
|
-
# @return [Numeric] the execution Time
|
43
|
-
def self.measure(&block)
|
44
|
-
new.run(&block)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Creates a new idle Stopwatch.
|
48
|
-
def initialize
|
49
|
-
@time = Time.new
|
50
|
-
end
|
51
|
-
|
52
|
-
# Executes the given block. Accumulates the execution time in this Stopwatch.
|
53
|
-
#
|
54
|
-
# @return [Numeric] the execution run Time
|
55
|
-
def run(&block)
|
56
|
-
@time.split(&block)
|
57
|
-
end
|
58
|
-
|
59
|
-
# @return [Numeric] the cumulative elapsed real clock time spent in {#run} executions
|
60
|
-
def elapsed
|
61
|
-
@time.elapsed
|
62
|
-
end
|
63
|
-
|
64
|
-
# @return [Numeric] the cumulative CPU total time spent in {#run} executions for the
|
65
|
-
# current process and its children
|
66
|
-
def cpu
|
67
|
-
@time.cpu
|
68
|
-
end
|
69
|
-
|
70
|
-
# Resets this Stopwatch's cumulative time to zero.
|
71
|
-
def reset
|
72
|
-
@time.reset
|
73
|
-
end
|
74
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'caruby/util/collection'
|
2
|
-
|
3
|
-
# A TopologicalSyncEnumerator iterates over (target, source) pairs with the target matched
|
4
|
-
# to the source with a matcher block. Child targets are matched to child sources based on
|
5
|
-
# a topological order reference method. The iteration is performed in depth-first order.
|
6
|
-
class TopologicalSyncEnumerator
|
7
|
-
include Enumerable
|
8
|
-
|
9
|
-
# @param targets the objects to synch to
|
10
|
-
# @param sources the objects to synch from
|
11
|
-
# @param [Symbol] method the topological order reference method
|
12
|
-
# @yield (see #each)
|
13
|
-
def initialize(targets, sources, method, &matcher)
|
14
|
-
@tgts = targets
|
15
|
-
@srcs = sources
|
16
|
-
@mthd = method
|
17
|
-
@matcher = matcher || lambda { |tgt, srcs| srcs.first }
|
18
|
-
end
|
19
|
-
|
20
|
-
# Calls the given block on each matching target and source in depth-first order.
|
21
|
-
#
|
22
|
-
# @yield [target, source] the objects to synchronize
|
23
|
-
# @return [Hash] the matching target => source hash
|
24
|
-
def each
|
25
|
-
# the parent hashes for targets and sources
|
26
|
-
pt = @tgts.to_compact_hash { |tgt| tgt.send(@mthd) }
|
27
|
-
ps = @srcs.to_compact_hash { |src| src.send(@mthd) }
|
28
|
-
|
29
|
-
# the child hashes
|
30
|
-
ct = LazyHash.new { Array.new }
|
31
|
-
cs = LazyHash.new { Array.new }
|
32
|
-
|
33
|
-
# collect the chidren and roots
|
34
|
-
rt = @tgts.reject { |tgt| p = pt[tgt]; ct[p] << tgt if p }
|
35
|
-
rs = @srcs.reject { |src| p = ps[src]; cs[p] << src if p }
|
36
|
-
|
37
|
-
# the match hash
|
38
|
-
matches = {}
|
39
|
-
# match recursively
|
40
|
-
each_match_recursive(rt, rs, ct, cs) do |tgt, src|
|
41
|
-
yield(tgt, src)
|
42
|
-
matches[tgt] = src
|
43
|
-
end
|
44
|
-
|
45
|
-
matches
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def each_match_recursive(targets, sources, ct, cs, &block)
|
51
|
-
# copy the sources
|
52
|
-
srcs = sources.dup
|
53
|
-
# match each target, removing the matched source for the
|
54
|
-
# next iteration
|
55
|
-
targets.each do |tgt|
|
56
|
-
src = @matcher.call(tgt, srcs) || next
|
57
|
-
yield(tgt, src)
|
58
|
-
srcs.delete(src)
|
59
|
-
each_match_recursive(ct[tgt], cs[src], ct, cs, &block)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'caruby/util/visitor'
|
2
|
-
|
3
|
-
class Object
|
4
|
-
# Returns the transitive closure over a method or block. This method returns an array partially ordered
|
5
|
-
# by the children method or block, i.e. each node occurs before all other nodes referenced directly or
|
6
|
-
# indirectly by the children.
|
7
|
-
#
|
8
|
-
# If a method symbol or name is provided, then that method is called. Otherwise, the block is called.
|
9
|
-
# In either case, the call is expected to return an object or Enumerable of objects which also respond
|
10
|
-
# to the method or block.
|
11
|
-
#
|
12
|
-
# @param [Symbol, nil] method the child reference, or nil if a block is given
|
13
|
-
# @yield [node] the parent node's children
|
14
|
-
# @yieldparam node the parent node
|
15
|
-
# @example
|
16
|
-
# class Node
|
17
|
-
# attr_reader :parent, :children
|
18
|
-
# def initialize(name, parent=nil)
|
19
|
-
# super()
|
20
|
-
# @name = name
|
21
|
-
# @parent = parent
|
22
|
-
# @children = []
|
23
|
-
# parent.children << self if parent
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# def to_s;
|
27
|
-
# end
|
28
|
-
# a = Node.new('a'); b = Node.new('b', a), c = Node.new('c', a); d = Node.new('d', c)
|
29
|
-
# a.transitive_closure { |node| node.children }.to_a.join(", ") #=> a, b, c, d
|
30
|
-
# a.transitive_closure(:children).to_a.join(", ") #=> a, b, c, d
|
31
|
-
def transitive_closure(method=nil)
|
32
|
-
raise ArgumentError.new("Missing both a method argument and a block") if method.nil? and not block_given?
|
33
|
-
# If there is a method argument, then the transitive closure is based on that method.
|
34
|
-
# Otherwise, visit the closure in reverse depth-first order.
|
35
|
-
if method then
|
36
|
-
transitive_closure() { |node| node.send(method) }
|
37
|
-
else
|
38
|
-
CaRuby::Visitor.new(:depth_first) { |node| yield node }.to_enum(self).to_a.reverse
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
module Enumerable
|
44
|
-
# Returns the transitive closure over all items in this Enumerable.
|
45
|
-
#
|
46
|
-
# @see Object#transitive_closure
|
47
|
-
def transitive_closure(method=nil)
|
48
|
-
# delegate to Object if there is a method argument
|
49
|
-
return super(method) if method
|
50
|
-
# this Enumerable's children are this Enumerable's contents
|
51
|
-
closure = super() { |node| node.equal?(self) ? self : yield(node) }
|
52
|
-
# remove this collection from the closure
|
53
|
-
closure[1..-1]
|
54
|
-
end
|
55
|
-
end
|
data/lib/caruby/util/tree.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# A Tree consists of a root node and subtree children.
|
2
|
-
# A Tree can be decorated with an optional value.
|
3
|
-
class Tree
|
4
|
-
attr_reader :root, :children
|
5
|
-
|
6
|
-
attr_accessor :value
|
7
|
-
|
8
|
-
# Creates a Trie with the given root node.
|
9
|
-
def initialize(root=nil)
|
10
|
-
@root = root
|
11
|
-
@children = []
|
12
|
-
end
|
13
|
-
|
14
|
-
# Adds a subtree rooted at the given node as a child of this tree.
|
15
|
-
def <<(node)
|
16
|
-
@children << self.class.new(node)
|
17
|
-
self
|
18
|
-
end
|
19
|
-
|
20
|
-
# Returns the subtree at the given node path.
|
21
|
-
def subtree(*path)
|
22
|
-
return self if path.empty?
|
23
|
-
first = path.shift
|
24
|
-
tree = @children.detect { |child| child.root == first }
|
25
|
-
tree.subtree(*path) if tree
|
26
|
-
end
|
27
|
-
|
28
|
-
alias :[] :subtree
|
29
|
-
|
30
|
-
# Creates the given node path if it does not yet exist.
|
31
|
-
# Returns the subtree at the path.
|
32
|
-
def fill(*path)
|
33
|
-
return self if path.empty?
|
34
|
-
first = path.shift
|
35
|
-
tree = subtree(first)
|
36
|
-
if tree.nil? then
|
37
|
-
self << first
|
38
|
-
tree = @children.last
|
39
|
-
end
|
40
|
-
tree.fill(*path)
|
41
|
-
end
|
42
|
-
|
43
|
-
def to_s
|
44
|
-
root_s = @root.nil? || Symbol === root ? root.inspect : root.to_s
|
45
|
-
return "[#{root_s}]" if @children.empty?
|
46
|
-
"[#{root_s} -> #{@children.join(', ')}]"
|
47
|
-
end
|
48
|
-
end
|