ruby_ex 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +51 -0
- data/ChangeLog +1763 -0
- data/NEWS +3 -0
- data/README +1 -0
- data/Rakefile +8 -0
- data/SPEC.dyn.yml +10 -0
- data/SPEC.gem.yml +269 -0
- data/SPEC.yml +36 -0
- data/src/abstract.rb +253 -0
- data/src/abstract_node.rb +85 -0
- data/src/algorithms.rb +12 -0
- data/src/algorithms/simulated_annealing.rb +142 -0
- data/src/ask.rb +100 -0
- data/src/attributed_class.rb +303 -0
- data/src/cache.rb +350 -0
- data/src/checkout.rb +12 -0
- data/src/choose.rb +271 -0
- data/src/commands.rb +20 -0
- data/src/commands/command.rb +492 -0
- data/src/commands/datas.rb +16 -0
- data/src/commands/datas/composite.rb +31 -0
- data/src/commands/datas/data.rb +65 -0
- data/src/commands/datas/factory.rb +69 -0
- data/src/commands/datas/temp.rb +26 -0
- data/src/commands/factory.rb +67 -0
- data/src/commands/helpers.rb +81 -0
- data/src/commands/pipe.rb +66 -0
- data/src/commands/runners.rb +16 -0
- data/src/commands/runners/exec.rb +50 -0
- data/src/commands/runners/fork.rb +130 -0
- data/src/commands/runners/runner.rb +140 -0
- data/src/commands/runners/system.rb +57 -0
- data/src/commands/seq.rb +32 -0
- data/src/config_file.rb +95 -0
- data/src/const_regexp.rb +57 -0
- data/src/daemon.rb +135 -0
- data/src/diff.rb +665 -0
- data/src/dlogger.rb +62 -0
- data/src/drb/drb_observable.rb +95 -0
- data/src/drb/drb_observable_pool.rb +27 -0
- data/src/drb/drb_service.rb +44 -0
- data/src/drb/drb_undumped_attributes.rb +56 -0
- data/src/drb/drb_undumped_indexed_object.rb +55 -0
- data/src/drb/insecure_protected_methods.rb +101 -0
- data/src/drb_ex.rb +12 -0
- data/src/dumpable_proc.rb +57 -0
- data/src/filetype.rb +229 -0
- data/src/generate_id.rb +44 -0
- data/src/histogram.rb +222 -0
- data/src/hookable.rb +283 -0
- data/src/hooker.rb +54 -0
- data/src/indexed_node.rb +65 -0
- data/src/io_marshal.rb +99 -0
- data/src/ioo.rb +193 -0
- data/src/labeled_node.rb +62 -0
- data/src/logger_observer.rb +24 -0
- data/src/md5sum.rb +70 -0
- data/src/module/autoload_tree.rb +65 -0
- data/src/module/hierarchy.rb +334 -0
- data/src/module/instance_method_visibility.rb +71 -0
- data/src/node.rb +81 -0
- data/src/object_monitor.rb +143 -0
- data/src/object_monitor_activity.rb +34 -0
- data/src/observable.rb +138 -0
- data/src/observable_pool.rb +291 -0
- data/src/orderedhash.rb +252 -0
- data/src/pp_hierarchy.rb +30 -0
- data/src/random_generators.rb +29 -0
- data/src/random_generators/random_generator.rb +33 -0
- data/src/random_generators/ruby.rb +25 -0
- data/src/ruby_ex.rb +124 -0
- data/src/safe_eval.rb +346 -0
- data/src/sendmail.rb +214 -0
- data/src/service_manager.rb +122 -0
- data/src/shuffle.rb +30 -0
- data/src/spring.rb +134 -0
- data/src/spring_set.rb +134 -0
- data/src/symtbl.rb +108 -0
- data/src/synflow.rb +474 -0
- data/src/thread_mutex.rb +11 -0
- data/src/timeout_ex.rb +79 -0
- data/src/trace.rb +26 -0
- data/src/uri/druby.rb +78 -0
- data/src/uri/file.rb +63 -0
- data/src/uri/ftp_ex.rb +36 -0
- data/src/uri/http_ex.rb +41 -0
- data/src/uri/pgsql.rb +136 -0
- data/src/uri/ssh.rb +87 -0
- data/src/uri/svn.rb +113 -0
- data/src/uri_ex.rb +71 -0
- data/src/verbose_object.rb +70 -0
- data/src/yaml/basenode_ext.rb +63 -0
- data/src/yaml/chop_header.rb +24 -0
- data/src/yaml/transform.rb +450 -0
- data/src/yaml/yregexpath.rb +76 -0
- data/test/algorithms/simulated_annealing_test.rb +102 -0
- data/test/check-pkg-ruby_ex.yml +15 -0
- data/test/check-ruby_ex.yml +12 -0
- data/test/resources/autoload_tree/A.rb +11 -0
- data/test/resources/autoload_tree/B.rb +10 -0
- data/test/resources/autoload_tree/foo/C.rb +18 -0
- data/test/resources/foo.txt +6 -0
- data/test/sanity-suite.yml +12 -0
- data/test/sanity/multiple-requires.yml +20 -0
- data/test/sanity/single-requires.yml +24 -0
- data/test/test-unit-setup.rb +6 -0
- data/test/unit-suite.yml +14 -0
- metadata +269 -0
data/src/ioo.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Pouillard. All rights reserved.
|
2
|
+
# Author: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: ioo.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
require 'delegate'
|
9
|
+
require 'ruby_ex'
|
10
|
+
|
11
|
+
# With this class you can easily overwrite only write or read methods
|
12
|
+
# to change the whole IO.
|
13
|
+
#
|
14
|
+
# This is very usefull to produce a crypted IO for example.
|
15
|
+
module ImplIOO
|
16
|
+
|
17
|
+
def << ( obj )
|
18
|
+
write obj
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def each ( sep_string=$/, &block )
|
23
|
+
begin
|
24
|
+
loop { block[readline(sep_string)] }
|
25
|
+
rescue EOFError
|
26
|
+
return self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias :each_line :each
|
30
|
+
|
31
|
+
def each_byte ( &block )
|
32
|
+
begin
|
33
|
+
loop { block[readchar] }
|
34
|
+
rescue EOFError
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def getc
|
40
|
+
begin
|
41
|
+
readchar
|
42
|
+
rescue EOFError
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def gets ( sep_string=$/ )
|
48
|
+
begin
|
49
|
+
readline(sep_string)
|
50
|
+
rescue EOFError
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def print ( *args )
|
56
|
+
if args.empty?
|
57
|
+
write $_
|
58
|
+
else
|
59
|
+
args.each { |x| write x }
|
60
|
+
end
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def printf ( fmt, *args )
|
65
|
+
write Kernel.sprintf(fmt, *args)
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def putc ( c )
|
70
|
+
case c
|
71
|
+
when Numeric then write c.chr
|
72
|
+
when String
|
73
|
+
if c.size == 1
|
74
|
+
write c
|
75
|
+
else
|
76
|
+
c = c[0].chr
|
77
|
+
write c
|
78
|
+
end
|
79
|
+
else
|
80
|
+
c = c.to_s[0].chr
|
81
|
+
write c
|
82
|
+
end
|
83
|
+
c
|
84
|
+
end
|
85
|
+
|
86
|
+
def puts ( *args )
|
87
|
+
if args.size == 0
|
88
|
+
write "\n"
|
89
|
+
else
|
90
|
+
args.each do |x|
|
91
|
+
x = x.to_s
|
92
|
+
write x
|
93
|
+
write "\n" unless x[-1] == ?\n
|
94
|
+
end
|
95
|
+
end
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def readchar
|
100
|
+
raise EOFError if eof?
|
101
|
+
read(1)[0]
|
102
|
+
end
|
103
|
+
|
104
|
+
def readline ( sep_string=$/ )
|
105
|
+
raise EOFError if eof?
|
106
|
+
buf = ''
|
107
|
+
begin
|
108
|
+
while (char = readchar) != ?\n
|
109
|
+
buf += char.chr
|
110
|
+
end
|
111
|
+
return buf + char.chr
|
112
|
+
rescue EOFError
|
113
|
+
return buf
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def readlines ( sep_string=$/ )
|
118
|
+
res = []
|
119
|
+
each_line(sep_string) { |line| res << line }
|
120
|
+
res
|
121
|
+
end
|
122
|
+
|
123
|
+
end # module ImplIOO
|
124
|
+
|
125
|
+
class IOO < DelegateClass(IO)
|
126
|
+
include ImplIOO
|
127
|
+
end # class IOO
|
128
|
+
|
129
|
+
require 'socket'
|
130
|
+
class TCPSocket
|
131
|
+
alias :real_send :send
|
132
|
+
alias :real_recv :recv
|
133
|
+
end
|
134
|
+
|
135
|
+
class IOOTCPSocket < DelegateClass(TCPSocket)
|
136
|
+
include ImplIOO
|
137
|
+
|
138
|
+
def recv ( integer, flags=nil )
|
139
|
+
read(integer)
|
140
|
+
end
|
141
|
+
|
142
|
+
def read ( integer=nil, buffer='' )
|
143
|
+
raise ArgumentError unless buffer.is_a? String
|
144
|
+
raise NotImplementedError if integer.nil?
|
145
|
+
raise ArgumentError unless integer.is_a? Numeric
|
146
|
+
buffer += real_recv(integer, 0)
|
147
|
+
return buffer
|
148
|
+
end
|
149
|
+
|
150
|
+
def send ( obj, flags=nil )
|
151
|
+
write(obj)
|
152
|
+
end
|
153
|
+
|
154
|
+
def write ( obj )
|
155
|
+
real_send(obj.to_s, 0)
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
159
|
+
end # class IOOTCPSocket
|
160
|
+
|
161
|
+
|
162
|
+
test_section __FILE__ do
|
163
|
+
|
164
|
+
class TestIOO < Test::Unit::TestCase
|
165
|
+
|
166
|
+
def setup
|
167
|
+
@tmp = TempPath.new('ioo')
|
168
|
+
@tmp.open('w') do |tmp|
|
169
|
+
tmp.puts 'foo'
|
170
|
+
tmp.puts
|
171
|
+
tmp.puts 'bar'
|
172
|
+
end
|
173
|
+
@readlines = @tmp.readlines
|
174
|
+
end
|
175
|
+
|
176
|
+
def teardown
|
177
|
+
@tmp.clean
|
178
|
+
@tmp = nil
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_readlines
|
182
|
+
@tmp.open do |tmp|
|
183
|
+
assert_not_nil(tmp)
|
184
|
+
f = nil
|
185
|
+
assert_nothing_raised { f = IOO.new(tmp) }
|
186
|
+
assert_not_nil(f)
|
187
|
+
assert_equal(@readlines, f.readlines)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end # class TestIOO
|
192
|
+
|
193
|
+
end
|
data/src/labeled_node.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: polrop $
|
6
|
+
# $Id: node.rb 171 2005-03-29 09:12:47Z polrop $
|
7
|
+
|
8
|
+
|
9
|
+
require 'ruby_ex'
|
10
|
+
require 'abstract_node'
|
11
|
+
|
12
|
+
|
13
|
+
class LabeledNode < AbstractNode
|
14
|
+
include Concrete
|
15
|
+
|
16
|
+
def initialize(data=nil, *sub_nodes)
|
17
|
+
if sub_nodes.empty?
|
18
|
+
@sub_nodes = {}
|
19
|
+
else
|
20
|
+
@sub_nodes = sub_nodes.first
|
21
|
+
end
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge!(sub_nodes)
|
26
|
+
sub_nodes.each { |index, sub_node| check_sub_node_type(sub_node) }
|
27
|
+
@sub_nodes.merge(sub_nodes)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # class LabeledNode
|
31
|
+
|
32
|
+
|
33
|
+
test_section __FILE__ do
|
34
|
+
|
35
|
+
class LabeledNodeTest < Test::Unit::TestCase
|
36
|
+
|
37
|
+
def test_simple
|
38
|
+
s11 = LabeledNode.new(11)
|
39
|
+
s12 = LabeledNode.new(12)
|
40
|
+
s = LabeledNode.new(1, 0 => s11, 1 => s12)
|
41
|
+
assert_equal(1, s.data)
|
42
|
+
assert_equal(s11, s.sub_nodes[0])
|
43
|
+
assert_equal(s12, s.sub_nodes[1])
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_crochet_equal
|
47
|
+
s = LabeledNode.new(1)
|
48
|
+
assert_nothing_raised { s[0] = LabeledNode.new(10) }
|
49
|
+
assert_raises(TypeError) { s[1] = nil }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_merge
|
53
|
+
s = LabeledNode.new(1)
|
54
|
+
s11 = LabeledNode.new(11)
|
55
|
+
s12 = LabeledNode.new(12)
|
56
|
+
s.merge!({ 0 => s11, 1 => s12 })
|
57
|
+
end
|
58
|
+
|
59
|
+
end # class LabeledNodeTest
|
60
|
+
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: logger_observer.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'ruby_ex'
|
10
|
+
require 'logger'
|
11
|
+
|
12
|
+
|
13
|
+
class Logger
|
14
|
+
|
15
|
+
def update(*args, &block)
|
16
|
+
severity = UNKNOWN
|
17
|
+
if args.size > 0
|
18
|
+
(severity = Severity.cons_get(args[0].to_s.upcase)) rescue NameError
|
19
|
+
end
|
20
|
+
add(severity, "#{args.inspect} #{block.inspect if block}", $PROGRAME_NAME)
|
21
|
+
end
|
22
|
+
|
23
|
+
end # class Logger
|
24
|
+
|
data/src/md5sum.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: md5sum.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'ruby_ex'
|
10
|
+
require 'md5'
|
11
|
+
|
12
|
+
|
13
|
+
class File
|
14
|
+
|
15
|
+
def self.md5sum(filename)
|
16
|
+
md5 = Digest::MD5.new
|
17
|
+
IO.foreach(filename) { |l| md5 << l }
|
18
|
+
md5
|
19
|
+
end
|
20
|
+
|
21
|
+
def md5sum
|
22
|
+
md5 = Digest::MD5.new
|
23
|
+
each { |l| md5 << l }
|
24
|
+
md5
|
25
|
+
end
|
26
|
+
|
27
|
+
end # module File
|
28
|
+
|
29
|
+
|
30
|
+
class Pathname
|
31
|
+
|
32
|
+
def md5sum
|
33
|
+
md5 = Digest::MD5.new
|
34
|
+
each_line { |l| md5 << l }
|
35
|
+
md5
|
36
|
+
end
|
37
|
+
|
38
|
+
end # class Pathname
|
39
|
+
|
40
|
+
|
41
|
+
#
|
42
|
+
# Unit test suite
|
43
|
+
#
|
44
|
+
test_section __FILE__ do
|
45
|
+
|
46
|
+
|
47
|
+
require 'ruby_ex'
|
48
|
+
|
49
|
+
|
50
|
+
class MD5SumTest < Test::Unit::TestCase
|
51
|
+
|
52
|
+
def setup
|
53
|
+
@source = __FILE__.to_path.dirname.parent + 'test/resources/foo.txt'
|
54
|
+
@ref = '9508b4f53cff19cf42c5a0f0fc127602'
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Tests
|
59
|
+
#
|
60
|
+
def test_simple
|
61
|
+
assert_equal(@ref, @source.md5sum.to_s)
|
62
|
+
assert_equal(@ref, File.md5sum(@source).to_s)
|
63
|
+
assert_equal(@ref, @source.open { |f| f.md5sum.to_s })
|
64
|
+
end
|
65
|
+
|
66
|
+
end # class MD5SumTest
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: autoload_tree.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'ruby_ex'
|
10
|
+
|
11
|
+
|
12
|
+
class Module
|
13
|
+
|
14
|
+
def autoload_tree(dir, recursive=true, &block)
|
15
|
+
pdir = Pathname.new(dir)
|
16
|
+
pdir.each_entry do |p|
|
17
|
+
next if p.to_s =~ /^\./
|
18
|
+
pfull = pdir + p
|
19
|
+
if pfull.directory? and recursive
|
20
|
+
name = p.to_s.capitalize!
|
21
|
+
const_set(name, Module.new) unless const_defined?(name)
|
22
|
+
const_get(name).autoload_tree(pfull, recursive, &block)
|
23
|
+
elsif pfull.file? and p.to_s =~ /\.rb$/
|
24
|
+
autoload(name.to_sym, pfull.to_s) if name = block[p]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def autoloaded_module ( file, recursive=true )
|
30
|
+
dir = file.sub(/\.rb$/, '').to_path
|
31
|
+
autoload_tree(dir) do |path|
|
32
|
+
path.basename.to_s.sub(/\.rb$/, '').gsub(/(?:^|_)([a-z])/) { $1.upcase }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end # class Module
|
37
|
+
|
38
|
+
|
39
|
+
test_section __FILE__ do
|
40
|
+
|
41
|
+
class AutoloadTreeTest < Test::Unit::TestCase
|
42
|
+
|
43
|
+
REPO_DIR = __FILE__.to_path.dirname.parent.parent + 'test/resources/autoload_tree'
|
44
|
+
|
45
|
+
module AutoloadTree; end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Test
|
49
|
+
#
|
50
|
+
def test_autoload_tree
|
51
|
+
$: << REPO_DIR
|
52
|
+
AutoloadTree.autoload_tree(REPO_DIR) { |p| p.to_s.sub!(/\.rb$/, '') }
|
53
|
+
["Foo", "B", "A"].each do |x|
|
54
|
+
assert(AutoloadTree.constants.include?(x), "#{x} is missing")
|
55
|
+
end
|
56
|
+
assert_equal(["C"], AutoloadTree::Foo.constants)
|
57
|
+
$:.delete(REPO_DIR)
|
58
|
+
end
|
59
|
+
|
60
|
+
end # class AutoloadTreeTest
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,334 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: polrop $
|
6
|
+
# $Id: hierarchy.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
require 'ruby_ex'
|
9
|
+
|
10
|
+
# Extend the Module class with method to manipulate inheritance relation
|
11
|
+
# between constants of a module.
|
12
|
+
class Module
|
13
|
+
|
14
|
+
# Return the list of all sub classes of base_class (including itself).
|
15
|
+
# If force_autoload is false, not yet loaded constants will be ignored.
|
16
|
+
# If recursive is true sub modules will also be traversed.
|
17
|
+
def sub_classes(base_class, force_autoload=false, recursive=false)
|
18
|
+
check_const_is_class?(base_class)
|
19
|
+
result = []
|
20
|
+
constants.each do |const_name|
|
21
|
+
if autoload?(const_name).nil? or force_autoload
|
22
|
+
const = const_get(const_name)
|
23
|
+
if const.is_a?(Module)
|
24
|
+
if const.is_a?(Class)
|
25
|
+
result << const if const.ancestors.include?(base_class)
|
26
|
+
elsif recursive
|
27
|
+
result += const.sub_classes(base_class, force_autoload, recursive)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
# Remove a class from the hierarchy using remove_const. Sub classes of this
|
36
|
+
# class are also removed. It returns an array of the removed class name.
|
37
|
+
# See sub_classes for a description of the recursive argument.
|
38
|
+
def remove_class(base_class, recursive=false)
|
39
|
+
subs = sub_classes(base_class, true, recursive)
|
40
|
+
re = Regexp.new("^#{name}::")
|
41
|
+
result = []
|
42
|
+
subs.each do |sub|
|
43
|
+
sub_name = sub.to_s.sub!(re, '')
|
44
|
+
if sub_name =~ /^(.+)::(.+)$/
|
45
|
+
const_get($1).module_eval { remove_const($2.to_sym) }
|
46
|
+
else
|
47
|
+
remove_const(sub_name.to_sym)
|
48
|
+
end
|
49
|
+
result << sub_name
|
50
|
+
end
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return the inheritance tree of the base_class.
|
55
|
+
# Example:
|
56
|
+
#
|
57
|
+
# module M
|
58
|
+
# class A; end
|
59
|
+
# class B < A; end
|
60
|
+
# class C < B; end
|
61
|
+
# class D < B; end
|
62
|
+
# class E < A; end
|
63
|
+
# module N
|
64
|
+
# class F < A; end
|
65
|
+
# class G < F; end
|
66
|
+
# class H < D; end
|
67
|
+
# class I < H; end
|
68
|
+
# class J < E; end
|
69
|
+
# class Y; end
|
70
|
+
# end
|
71
|
+
# class Z; end
|
72
|
+
# FOO = 42
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# M.sub_classes_tree(M::A)
|
76
|
+
#
|
77
|
+
# produces:
|
78
|
+
#
|
79
|
+
# {
|
80
|
+
# M::A => {
|
81
|
+
# M::B => {
|
82
|
+
# M::D => {},
|
83
|
+
# M::C => {}
|
84
|
+
# },
|
85
|
+
# M::E => {}
|
86
|
+
# }
|
87
|
+
# }
|
88
|
+
#
|
89
|
+
# and
|
90
|
+
#
|
91
|
+
# M.sub_classes_tree(M::A, false, true)
|
92
|
+
#
|
93
|
+
# produces:
|
94
|
+
#
|
95
|
+
# {
|
96
|
+
# M::A => {
|
97
|
+
# M::N::F => {
|
98
|
+
# M::N::G => {}
|
99
|
+
# },
|
100
|
+
# M::B => {
|
101
|
+
# M::C => {},
|
102
|
+
# M::D => {
|
103
|
+
# M::N::H => {
|
104
|
+
# M::N::I => {}
|
105
|
+
# }
|
106
|
+
# }
|
107
|
+
# },
|
108
|
+
# M::E => {
|
109
|
+
# M::N::J => {}
|
110
|
+
# }
|
111
|
+
# }
|
112
|
+
# }
|
113
|
+
def sub_classes_tree(base_class, force_autoload=false, recursive=false)
|
114
|
+
subs = sub_classes(base_class, force_autoload, recursive)
|
115
|
+
sub_classes_tree_rec([base_class], subs)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def sub_classes_tree_rec(base_classes, csts)
|
120
|
+
result = {}
|
121
|
+
next_csts = []
|
122
|
+
base_classes.each do |b|
|
123
|
+
next_base_classes = []
|
124
|
+
csts.each do |c|
|
125
|
+
c.superclass == b ? next_base_classes << c : next_csts << c;
|
126
|
+
end
|
127
|
+
result[b] = sub_classes_tree_rec(next_base_classes, next_csts)
|
128
|
+
end
|
129
|
+
result
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
def check_const_is_class?(*base_classes)
|
134
|
+
base_classes.each do |b|
|
135
|
+
raise(TypeError, "`#{b}' - not a class") unless b.is_a?(Class)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end # class Module
|
140
|
+
|
141
|
+
|
142
|
+
test_section __FILE__ do
|
143
|
+
|
144
|
+
require 'diff'
|
145
|
+
|
146
|
+
|
147
|
+
class HierarchyTest < Test::Unit::TestCase
|
148
|
+
|
149
|
+
module M
|
150
|
+
|
151
|
+
class A; end
|
152
|
+
class B < A; end
|
153
|
+
class C; end
|
154
|
+
FOO = 42
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_sub_classes
|
159
|
+
sub_classes = M.sub_classes(HierarchyTest::M::A)
|
160
|
+
assert_equal(2, sub_classes.size)
|
161
|
+
[HierarchyTest::M::B, HierarchyTest::M::A].each do |x|
|
162
|
+
assert(sub_classes.include?(x))
|
163
|
+
end
|
164
|
+
assert_equal([HierarchyTest::M::C], M.sub_classes(M::C))
|
165
|
+
end
|
166
|
+
|
167
|
+
module Mautoload
|
168
|
+
|
169
|
+
class A; end
|
170
|
+
class B < A; end
|
171
|
+
autoload(:C, '/foo')
|
172
|
+
FOO = 42
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_sub_classes_force_autoload
|
177
|
+
sub_classes = Mautoload.sub_classes(Mautoload::A)
|
178
|
+
assert_equal(2, sub_classes.size)
|
179
|
+
[Mautoload::B, Mautoload::A].each do |x|
|
180
|
+
assert(sub_classes.include?(x))
|
181
|
+
end
|
182
|
+
assert_equal(4, Mautoload.constants.size)
|
183
|
+
assert_not_nil(Mautoload.autoload?(:C))
|
184
|
+
assert_raises(LoadError) { Mautoload.sub_classes(Mautoload::A, true) }
|
185
|
+
assert_equal(3, Mautoload.constants.size)
|
186
|
+
assert_nil(Mautoload.autoload?(:C))
|
187
|
+
end
|
188
|
+
|
189
|
+
module Mrec
|
190
|
+
class A; end
|
191
|
+
class B < A; end
|
192
|
+
module M
|
193
|
+
class C < A; end
|
194
|
+
class D < B; end
|
195
|
+
class E < D; end
|
196
|
+
class Y; end
|
197
|
+
end
|
198
|
+
class Z; end
|
199
|
+
FOO = 42
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_sub_classes_recursive
|
203
|
+
sub_classes = Mrec.sub_classes(Mrec::A)
|
204
|
+
assert_equal(2, sub_classes.size)
|
205
|
+
[Mrec::B, Mrec::A].each do |x|
|
206
|
+
assert(sub_classes.include?(x))
|
207
|
+
end
|
208
|
+
sub_classes = Mrec.sub_classes(Mrec::A, false, true)
|
209
|
+
assert_equal(5, sub_classes.size)
|
210
|
+
[Mrec::B, Mrec::A, Mrec::M::C, Mrec::M::D, Mrec::M::E].each do |x|
|
211
|
+
assert(sub_classes.include?(x))
|
212
|
+
end
|
213
|
+
r = Mrec.remove_class(Mrec::A, true)
|
214
|
+
assert_equal(5, r.size)
|
215
|
+
['B', 'A', 'M::E', 'M::C', 'M::D'].each do |x|
|
216
|
+
assert(r.include?(x))
|
217
|
+
end
|
218
|
+
assert_equal(3, Mrec.constants.size)
|
219
|
+
['FOO', 'M', 'Z'].each { |x| assert(Mrec.constants.include?(x)) }
|
220
|
+
assert_equal(1, Mrec::M.constants.size)
|
221
|
+
['Y'].each { |x| assert(Mrec::M.constants.include?(x)) }
|
222
|
+
end
|
223
|
+
|
224
|
+
module Tree
|
225
|
+
|
226
|
+
class A; end
|
227
|
+
class B < A; end
|
228
|
+
class C < B; end
|
229
|
+
class D < B; end
|
230
|
+
class E < A; end
|
231
|
+
module M
|
232
|
+
class F < A; end
|
233
|
+
class G < F; end
|
234
|
+
class H < D; end
|
235
|
+
class I < H; end
|
236
|
+
class J < E; end
|
237
|
+
class Y; end
|
238
|
+
end
|
239
|
+
class Z; end
|
240
|
+
FOO = 42
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_sub_classes_tree_rec
|
245
|
+
r = Tree.sub_classes_tree(HierarchyTest::Tree::A, false, true)
|
246
|
+
ref = {
|
247
|
+
HierarchyTest::Tree::A => {
|
248
|
+
HierarchyTest::Tree::M::F => {
|
249
|
+
HierarchyTest::Tree::M::G => {}
|
250
|
+
},
|
251
|
+
HierarchyTest::Tree::B => {
|
252
|
+
HierarchyTest::Tree::C => {},
|
253
|
+
HierarchyTest::Tree::D => {
|
254
|
+
HierarchyTest::Tree::M::H => {
|
255
|
+
HierarchyTest::Tree::M::I=>{}
|
256
|
+
}
|
257
|
+
}
|
258
|
+
},
|
259
|
+
HierarchyTest::Tree::E=> {
|
260
|
+
HierarchyTest::Tree::M::J=>{}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
d = r.diff(ref)
|
265
|
+
assert_equal({}, d[:different])
|
266
|
+
assert_equal({}, d[:additional])
|
267
|
+
assert_equal({}, d[:missing])
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_sub_classes_tree
|
271
|
+
r = Tree.sub_classes_tree(HierarchyTest::Tree::A)
|
272
|
+
ref = {
|
273
|
+
HierarchyTest::Tree::A => {
|
274
|
+
HierarchyTest::Tree::B => {
|
275
|
+
HierarchyTest::Tree::D => {},
|
276
|
+
HierarchyTest::Tree::C => {}
|
277
|
+
},
|
278
|
+
HierarchyTest::Tree::E => {}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
d = r.diff(ref)
|
282
|
+
assert_equal({}, d[:different])
|
283
|
+
assert_equal({}, d[:additional])
|
284
|
+
assert_equal({}, d[:missing])
|
285
|
+
end
|
286
|
+
|
287
|
+
module Error
|
288
|
+
module M; end
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_sub_classes_error
|
292
|
+
assert_raises(TypeError) do
|
293
|
+
Error.sub_classes_tree(HierarchyTest::Error::M)
|
294
|
+
end
|
295
|
+
assert_raises(TypeError) do
|
296
|
+
Error.sub_classes(HierarchyTest::Error::M)
|
297
|
+
end
|
298
|
+
assert_raises(TypeError) do
|
299
|
+
Error.remove_class(HierarchyTest::Error::M)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
module RemoveClass
|
304
|
+
|
305
|
+
class A; end
|
306
|
+
class B < A; end
|
307
|
+
class C < B; end
|
308
|
+
class D < B; end
|
309
|
+
class E < D; end
|
310
|
+
class F < A; end
|
311
|
+
class Z; end
|
312
|
+
module M
|
313
|
+
class Y; end
|
314
|
+
end
|
315
|
+
BAR = 51
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_remove_class
|
320
|
+
r = RemoveClass.remove_class(HierarchyTest::RemoveClass::B)
|
321
|
+
assert_equal(4, r.size)
|
322
|
+
['B', 'D', 'E', 'C'].each { |x| assert(r.include?(x)) }
|
323
|
+
assert_equal(5, RemoveClass.constants.size)
|
324
|
+
['A', 'F', 'Z', 'M', 'BAR'].each do |x|
|
325
|
+
assert(RemoveClass.constants.include?(x))
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
end # class HierarchyTest
|
330
|
+
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
|