ruby_ex 0.1.1
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.
- 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
|
+
|