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/cache.rb
ADDED
@@ -0,0 +1,350 @@
|
|
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: cache.rb 273 2005-06-03 00:00:26Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'ruby_ex'
|
10
|
+
require 'md5sum'
|
11
|
+
|
12
|
+
|
13
|
+
class Cache
|
14
|
+
|
15
|
+
#
|
16
|
+
# Constants
|
17
|
+
#
|
18
|
+
REPOSITORY = '/var/cache/ruby_ex_cache'
|
19
|
+
MAX_SIZE = 50 * 1024 * 1024 # 50 MB
|
20
|
+
BLOCK_SIZE = 1024 # octets
|
21
|
+
|
22
|
+
#
|
23
|
+
# Attributs
|
24
|
+
#
|
25
|
+
attr_reader :repository, :max_size, :size
|
26
|
+
|
27
|
+
#
|
28
|
+
# Constructor
|
29
|
+
#
|
30
|
+
def initialize(repository=REPOSITORY, max_size=MAX_SIZE)
|
31
|
+
@repository = Pathname.new(repository)
|
32
|
+
@max_size = check_max_size(max_size)
|
33
|
+
create
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Methods
|
38
|
+
#
|
39
|
+
def create
|
40
|
+
@size = 0
|
41
|
+
@atime = []
|
42
|
+
if @repository.directory?
|
43
|
+
@repository.each_entry do |p|
|
44
|
+
next if p.to_s =~ /^\./
|
45
|
+
full_p = @repository + p
|
46
|
+
@atime << full_p
|
47
|
+
@size += full_p.size
|
48
|
+
end
|
49
|
+
@atime.sort! { |a, b| a.atime <=> b.atime }
|
50
|
+
else
|
51
|
+
@repository.mkdir
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear
|
56
|
+
@repository.each_entry do |p|
|
57
|
+
(@repository + p).delete unless p.to_s =~ /^\./
|
58
|
+
end
|
59
|
+
@size = 0
|
60
|
+
@atime.clear
|
61
|
+
end
|
62
|
+
|
63
|
+
def recreate
|
64
|
+
clear
|
65
|
+
create
|
66
|
+
end
|
67
|
+
|
68
|
+
def open(md5sum=nil, mode='r', perm=0644, &block)
|
69
|
+
case mode
|
70
|
+
when 'r': read(md5sum, &block)
|
71
|
+
when 'w': write(perm, &block)
|
72
|
+
else
|
73
|
+
raise(ArgumentError, "`#{mode}' - bad mode")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def read(md5sum, &block)
|
78
|
+
p = @repository + md5sum.to_s
|
79
|
+
p.open('r', &block)
|
80
|
+
@atime.delete(p)
|
81
|
+
@atime << p
|
82
|
+
p
|
83
|
+
end
|
84
|
+
|
85
|
+
def write(perm=0644, &block)
|
86
|
+
TempPath.new('cache_file') do |tmp|
|
87
|
+
md5 = Digest::MD5.new
|
88
|
+
new_size = 0
|
89
|
+
tmp.open('w') do |out|
|
90
|
+
while (str = block[])
|
91
|
+
out.write(str)
|
92
|
+
md5 << str
|
93
|
+
new_size += str.size
|
94
|
+
end
|
95
|
+
end
|
96
|
+
p = @repository + md5.to_s
|
97
|
+
if p.exist?
|
98
|
+
@atime.delete(p)
|
99
|
+
else
|
100
|
+
@size += new_size
|
101
|
+
end
|
102
|
+
FileUtils.move(tmp.to_s, p.to_s)
|
103
|
+
p.chmod(perm)
|
104
|
+
@atime << p
|
105
|
+
adjust_size
|
106
|
+
return p
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def import(filename)
|
111
|
+
p = nil
|
112
|
+
pathname = filename.to_path
|
113
|
+
pathname.open do |f|
|
114
|
+
p = write(pathname.stat.mode) { f.eof? ? nil : f.read(BLOCK_SIZE) }
|
115
|
+
end
|
116
|
+
p
|
117
|
+
end
|
118
|
+
|
119
|
+
def export(md5sum, dst_filename)
|
120
|
+
p = @repository + md5sum.to_s
|
121
|
+
FileUtils.copy_entry(p, dst_filename)
|
122
|
+
update_entry(p)
|
123
|
+
p
|
124
|
+
end
|
125
|
+
|
126
|
+
def present?(md5sum)
|
127
|
+
p = @repository + md5sum.to_s
|
128
|
+
p.exist? ? p : nil;
|
129
|
+
end
|
130
|
+
|
131
|
+
def each
|
132
|
+
@atime.each { |p| yield(p) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def [](index)
|
136
|
+
@atime[index]
|
137
|
+
end
|
138
|
+
|
139
|
+
def max_size=(max_size)
|
140
|
+
@max_size = check_max_size(max_size)
|
141
|
+
adjust_size
|
142
|
+
end
|
143
|
+
|
144
|
+
def nb_files
|
145
|
+
@atime.size
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
def adjust_size
|
150
|
+
while @size > @max_size
|
151
|
+
p = @atime.shift
|
152
|
+
@size -= p.size
|
153
|
+
p.delete
|
154
|
+
end
|
155
|
+
@size
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
def check_max_size(max_size)
|
160
|
+
unless max_size > 0
|
161
|
+
raise(ArgumentError, "`#{max_size}' - bad cache maximum size")
|
162
|
+
end
|
163
|
+
max_size
|
164
|
+
end
|
165
|
+
|
166
|
+
end # class Cache
|
167
|
+
|
168
|
+
|
169
|
+
#
|
170
|
+
# Unit test suite
|
171
|
+
#
|
172
|
+
test_section __FILE__ do
|
173
|
+
|
174
|
+
|
175
|
+
class CacheTest < Test::Unit::TestCase
|
176
|
+
|
177
|
+
#
|
178
|
+
# Tests
|
179
|
+
#
|
180
|
+
def test_simple
|
181
|
+
# FIXME factor me using #setup, #teardown, and @cache instead of cache.
|
182
|
+
TempPath.new('cache') do |repo|
|
183
|
+
cache = nil
|
184
|
+
assert_nothing_raised { cache = Cache.new(repo) }
|
185
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
186
|
+
assert_nothing_raised { cache.create }
|
187
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
188
|
+
assert_nothing_raised { cache.clear }
|
189
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
190
|
+
assert_nothing_raised { cache.create }
|
191
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
192
|
+
assert_raises(Errno::ENOENT) { cache.open('toto', 'r') { |f| f.gets } }
|
193
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
194
|
+
assert_equal(0, cache.size)
|
195
|
+
|
196
|
+
data = [ "toto\n", "tata\n" ]
|
197
|
+
p1 = cache.open(nil, 'w') do
|
198
|
+
data.shift
|
199
|
+
end
|
200
|
+
assert(p1)
|
201
|
+
assert_equal(p1.md5sum.to_s, p1.basename.to_s, 'bad md5 open')
|
202
|
+
assert_equal(1, cache.nb_files, 'bad nb_files')
|
203
|
+
assert_equal(p1, cache[0])
|
204
|
+
assert_equal(10, cache.size)
|
205
|
+
assert_equal(p1, cache.present?(p1.basename))
|
206
|
+
tmp_p = cache.read(p1) do |f|
|
207
|
+
assert_equal("toto\n", f.gets)
|
208
|
+
assert_equal("tata\n", f.gets)
|
209
|
+
assert(f.eof?)
|
210
|
+
end
|
211
|
+
assert_equal(tmp_p, p1)
|
212
|
+
check_atime(cache)
|
213
|
+
assert_equal(1, cache.nb_files, 'bad nb_files')
|
214
|
+
assert(cache.present?(p1))
|
215
|
+
assert_equal(p1, cache[0])
|
216
|
+
assert(! cache.present?('foo'))
|
217
|
+
|
218
|
+
# FIXME man printf + Tempfile + File::md5sum
|
219
|
+
# resources/foo.txt + TempPath + Path#md5sum
|
220
|
+
tmp_file = Tempfile.new('cache')
|
221
|
+
system("man printf > #{tmp_file.path} 2> /dev/null")
|
222
|
+
md5 = File.md5sum(tmp_file.path)
|
223
|
+
p2 = cache.import(tmp_file.path)
|
224
|
+
assert_equal(md5.to_s, p2.basename.to_s, 'bad name after import')
|
225
|
+
assert(p2.exist?, 'file do not exist after import')
|
226
|
+
assert(FileUtils.cmp(tmp_file.path, p2.to_s), 'bad import')
|
227
|
+
assert_equal(md5.to_s, File.md5sum(p2.to_s).to_s, 'bad md5 import')
|
228
|
+
tmp_file.delete
|
229
|
+
assert_equal(2, cache.nb_files, 'bad nb_files')
|
230
|
+
assert_equal(p2, cache[1])
|
231
|
+
check_atime(cache)
|
232
|
+
|
233
|
+
data = [ "foo\n", "bar\n" ]
|
234
|
+
p3 = cache.open(nil, 'w') do
|
235
|
+
data.shift
|
236
|
+
end
|
237
|
+
assert_equal(File.md5sum(p3.to_s).to_s, p3.basename.to_s, 'bad md5 open')
|
238
|
+
assert_equal(3, cache.nb_files, 'bad nb_files')
|
239
|
+
assert_equal(p3, cache[2])
|
240
|
+
assert_equal(p3, cache.present?(p3.basename))
|
241
|
+
|
242
|
+
assert_equal(p1, cache[0], 'p1 first')
|
243
|
+
assert_equal(p2, cache[1], 'p2 second')
|
244
|
+
assert_equal(p3, cache[2], 'p3 third')
|
245
|
+
assert_equal(p1, cache.read(p1) { |f| f.gets })
|
246
|
+
assert_equal(p2, cache[0], 'p2 first')
|
247
|
+
assert_equal(p3, cache[1], 'p3 second')
|
248
|
+
assert_equal(p1, cache[2], 'p1 third')
|
249
|
+
check_atime(cache)
|
250
|
+
assert_equal(3, cache.nb_files, 'bad nb_files')
|
251
|
+
|
252
|
+
|
253
|
+
new_cache = nil
|
254
|
+
assert_nothing_raised { new_cache = Cache.new(repo) }
|
255
|
+
assert_equal(3, new_cache.nb_files, 'bad nb_files in new cache')
|
256
|
+
check_atime(new_cache)
|
257
|
+
assert_equal(cache.size, new_cache.size)
|
258
|
+
|
259
|
+
assert_equal(3, cache.nb_files, 'bad nb_files')
|
260
|
+
assert(cache.size > 1024)
|
261
|
+
cache.max_size = 1024
|
262
|
+
assert(cache.size < 1024)
|
263
|
+
assert_equal(p1.size + p3.size, cache.size)
|
264
|
+
assert_equal(2, cache.nb_files, 'bad nb_files')
|
265
|
+
assert_equal(p3, cache[0], 'p3 first')
|
266
|
+
assert_equal(p1, cache[1], 'p1 second')
|
267
|
+
|
268
|
+
cache.clear
|
269
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
270
|
+
assert_equal(0, cache.size)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_write_twice_the_same
|
275
|
+
TempPath.new('cache') do |repo|
|
276
|
+
cache = nil
|
277
|
+
assert_nothing_raised { cache = Cache.new(repo) }
|
278
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
279
|
+
assert_equal(0, cache.size)
|
280
|
+
|
281
|
+
data = [ "toto\n", "tata\n" ]
|
282
|
+
d = data.dup
|
283
|
+
p1 = cache.open(nil, 'w') do
|
284
|
+
d.shift
|
285
|
+
end
|
286
|
+
|
287
|
+
assert_kind_of(Pathname, p1)
|
288
|
+
assert_equal(p1.md5sum.to_s, p1.basename.to_s, 'bad md5 open')
|
289
|
+
assert_equal(1, cache.nb_files, 'bad nb_files')
|
290
|
+
assert_equal(p1, cache[0])
|
291
|
+
assert_equal(10, cache.size)
|
292
|
+
assert_equal(p1, cache.present?(p1.basename))
|
293
|
+
|
294
|
+
data = [ "toto\n", "tata\n" ]
|
295
|
+
d = data.dup
|
296
|
+
p2 = cache.open(nil, 'w') do
|
297
|
+
d.shift
|
298
|
+
end
|
299
|
+
|
300
|
+
assert_equal(File.md5sum(p1.to_s).to_s, p1.basename.to_s, 'bad md5 open')
|
301
|
+
assert_equal(1, cache.nb_files, 'bad nb_files')
|
302
|
+
assert_equal(p1, cache[0])
|
303
|
+
assert_equal(10, cache.size)
|
304
|
+
assert_equal(p1, cache.present?(p1.basename))
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_nested_write
|
309
|
+
TempPath.new('cache') do |repo|
|
310
|
+
cache = nil
|
311
|
+
assert_nothing_raised { cache = Cache.new(repo) }
|
312
|
+
assert_equal(0, cache.nb_files, 'bad nb_files')
|
313
|
+
assert_equal(0, cache.size)
|
314
|
+
|
315
|
+
data = [ "toto\n", "tata\n" ]
|
316
|
+
d1 = data.dup
|
317
|
+
p1 = cache.open(nil, 'w') do
|
318
|
+
d2 = data.dup
|
319
|
+
p2 = cache.open(nil, 'w') do
|
320
|
+
d2.shift
|
321
|
+
end
|
322
|
+
d1.shift
|
323
|
+
end
|
324
|
+
|
325
|
+
assert(p1)
|
326
|
+
assert_equal(p1.md5sum.to_s, p1.basename.to_s, 'bad md5 open')
|
327
|
+
assert_equal(1, cache.nb_files, 'bad nb_files')
|
328
|
+
assert_equal(p1, cache[0])
|
329
|
+
assert_equal(10, cache.size)
|
330
|
+
assert_equal(p1, cache.present?(p1.basename))
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
#
|
335
|
+
# Utilities
|
336
|
+
#
|
337
|
+
protected
|
338
|
+
def check_atime(cache)
|
339
|
+
j = 0
|
340
|
+
for i in 1...cache.nb_files do
|
341
|
+
assert(cache[j].atime <= cache[i].atime, "bad atime order for #{i}")
|
342
|
+
j = i
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
end # class CacheTest
|
347
|
+
|
348
|
+
|
349
|
+
end
|
350
|
+
|
data/src/checkout.rb
ADDED
@@ -0,0 +1,12 @@
|
|
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: checkout.rb 159 2005-02-18 12:07:23Z polrop $
|
7
|
+
|
8
|
+
require 'uri_ex'
|
9
|
+
require 'uri/http_ex'
|
10
|
+
require 'uri/ftp_ex'
|
11
|
+
require 'uri/file'
|
12
|
+
require 'uri/svn'
|
data/src/choose.rb
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
# Revision:: $Id: choose.rb 258 2005-06-01 00:22:51Z ertai $
|
5
|
+
|
6
|
+
|
7
|
+
require 'random_generators'
|
8
|
+
|
9
|
+
|
10
|
+
class Integer
|
11
|
+
|
12
|
+
def self.choose ( limit=nil, generator=nil )
|
13
|
+
limit.to_i.choose(generator)
|
14
|
+
end
|
15
|
+
|
16
|
+
def choose ( generator=nil )
|
17
|
+
(generator || RandomGenerators.default).choose_integer(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # class Integer
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
class Float
|
25
|
+
|
26
|
+
def self.choose ( limit=nil, generator=nil )
|
27
|
+
(limit || 1.0).to_f.choose(generator)
|
28
|
+
end
|
29
|
+
|
30
|
+
def choose ( generator=nil )
|
31
|
+
(generator || RandomGenerators.default).choose_float(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class Float
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
class Hash
|
39
|
+
|
40
|
+
def choose ( limit=nil, generator=nil )
|
41
|
+
self[keys.choose(limit, generator)]
|
42
|
+
end
|
43
|
+
|
44
|
+
end # class Hash
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
class Array
|
49
|
+
|
50
|
+
def choose ( limit=nil, generator=nil )
|
51
|
+
n = size
|
52
|
+
|
53
|
+
# Out of limits: limit > size (FIXME warn)
|
54
|
+
limit = n if limit.nil? or limit > n
|
55
|
+
|
56
|
+
self[limit.choose(generator)]
|
57
|
+
end
|
58
|
+
|
59
|
+
end # class Array
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
module Enumerable
|
64
|
+
|
65
|
+
def choose ( limit=nil, generator=nil )
|
66
|
+
to_a.choose(limit, generator)
|
67
|
+
end
|
68
|
+
|
69
|
+
end # module Enumerable
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
class Range
|
74
|
+
|
75
|
+
def choose ( generator=nil )
|
76
|
+
case first
|
77
|
+
when Integer
|
78
|
+
first + (last + 1 - first).choose(generator)
|
79
|
+
else
|
80
|
+
super(nil, generator)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end # class Array
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
test_section __FILE__ do
|
89
|
+
|
90
|
+
class MockRandomGenerator < RandomGenerators::RandomGenerator
|
91
|
+
concrete
|
92
|
+
attr_reader :ref
|
93
|
+
def initialize ( tab_i, tab_f )
|
94
|
+
raise unless tab_i.is_a? Array
|
95
|
+
raise unless tab_f.is_a? Array
|
96
|
+
@ref, @ref_f, @pos = tab_i, tab_f, -1
|
97
|
+
end
|
98
|
+
def get ( tab )
|
99
|
+
tab[@pos = (@pos + 1) % tab.size]
|
100
|
+
end
|
101
|
+
def choose_integer ( n )
|
102
|
+
check_choose_integer(n)
|
103
|
+
get(@ref) % n
|
104
|
+
end
|
105
|
+
def choose_float ( f=1.0 )
|
106
|
+
check_choose_float(f)
|
107
|
+
get(@ref_f) * f
|
108
|
+
end
|
109
|
+
end # class MockRandomGenerator
|
110
|
+
|
111
|
+
class RandomMockRandomGenerator < MockRandomGenerator
|
112
|
+
def initialize ( n )
|
113
|
+
tab_i = (0 .. n - 1).to_a.shuffle
|
114
|
+
tab_f = []
|
115
|
+
n.times { tab_f << Float.choose() }
|
116
|
+
super(tab_i, tab_f)
|
117
|
+
end
|
118
|
+
end # class RandomMockRandomGenerator
|
119
|
+
|
120
|
+
|
121
|
+
require 'test/unit'
|
122
|
+
require 'set'
|
123
|
+
|
124
|
+
class ChooseTest < Test::Unit::TestCase
|
125
|
+
|
126
|
+
REF_5 = [1, 2, 4, 0, 3]
|
127
|
+
REF_F_5 = [0.187528345035389, 0.368857819121331, 0.06954449811019,
|
128
|
+
0.188887464581057, 0.213757352204993]
|
129
|
+
REF_50 = [
|
130
|
+
28, 12, 17, 10, 1, 37, 46, 25, 47, 2, 45, 36, 20, 5, 30, 14, 18, 39,
|
131
|
+
8, 15, 16, 43, 27, 33, 22, 7, 32, 3, 35, 9, 19, 13, 21, 6, 23, 26, 4,
|
132
|
+
40, 44, 11, 49, 29, 42, 24, 31, 48, 34, 0, 38, 41
|
133
|
+
]
|
134
|
+
REF_F_50 = [
|
135
|
+
0.643785412423313, 0.765736325876787, 0.604515956481919,
|
136
|
+
0.133839202811942, 0.350400971015915, 0.966710213804618,
|
137
|
+
0.904755113180727, 0.88459848286584, 0.163951952941716,
|
138
|
+
0.808023529592901, 0.387806572020054, 0.659689131658524,
|
139
|
+
0.289974238490686, 0.813535830006003, 0.565311754588038,
|
140
|
+
0.889200099511072, 0.0668127918615937, 0.992091996129602,
|
141
|
+
0.604403987759724, 0.89254002738744, 0.601499371463433,
|
142
|
+
0.754795648856089, 0.751190354581922, 0.434389552799985,
|
143
|
+
0.761369747575372, 0.174903159961104, 0.940325234550983,
|
144
|
+
0.536097376374528, 0.957906004507095, 0.693120914744213,
|
145
|
+
0.23448576242663, 0.638284107437357, 0.423910334473476,
|
146
|
+
0.251349127152935, 0.457931924844161, 0.20579389645718,
|
147
|
+
0.256057573715225, 0.584466924890876, 0.609375598141924,
|
148
|
+
0.0856487881392241, 0.437958877766505, 0.432312048738822,
|
149
|
+
0.81560374982655, 0.142059376928955, 0.118824432371184,
|
150
|
+
0.958816710859537, 0.69899930502288, 0.118259542621672,
|
151
|
+
0.52218786906451, 0.339233995880932
|
152
|
+
]
|
153
|
+
|
154
|
+
def checker_n ( n, ref_i, ref_f, inp, ref, lim=nil )
|
155
|
+
mrg = MockRandomGenerator.new(ref_i, ref_f)
|
156
|
+
my = []
|
157
|
+
if lim == :no
|
158
|
+
n.times { my << inp.choose(mrg) }
|
159
|
+
else
|
160
|
+
n.times { my << inp.choose(lim, mrg) }
|
161
|
+
end
|
162
|
+
assert_equal(ref, my)
|
163
|
+
end
|
164
|
+
|
165
|
+
def checker_5 ( inp, ref, lim=nil )
|
166
|
+
checker_n(5, REF_5, REF_F_5, inp, ref, lim)
|
167
|
+
end
|
168
|
+
|
169
|
+
def checker_50 ( inp, ref, lim=nil )
|
170
|
+
checker_n(50, REF_50, REF_F_50, inp, ref, lim)
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
def test_integer
|
177
|
+
checker_5 Integer, REF_5, 5
|
178
|
+
checker_50 Integer, REF_50, 50
|
179
|
+
assert(Integer.choose(1000) < 1000)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_float
|
183
|
+
checker_5 Float, REF_F_5, 1.0
|
184
|
+
checker_50 Float, REF_F_50, 1.0
|
185
|
+
assert(Float.choose(2.0) < 2)
|
186
|
+
assert(Float.choose < 1)
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_array_5
|
190
|
+
checker_5 [4], [4] * 5, 5
|
191
|
+
checker_5 [4, 5], [5, 4, 4, 4, 5], 5
|
192
|
+
checker_5 [4, 5, 6], [5, 6, 5, 4, 4], 5
|
193
|
+
checker_5 [2, 1, 0, 5, 4, 3], [1, 0, 4, 2, 5], 5
|
194
|
+
10.times { assert(REF_50.include?(REF_50.choose)) }
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_set_5
|
198
|
+
checker_5 Set[4], [4] * 5, 5
|
199
|
+
checker_5 Set[4, 5], [4, 5, 5, 5, 4], 5
|
200
|
+
checker_5 Set[4, 5, 6], [6, 4, 6, 5, 5], 5
|
201
|
+
checker_5 Set[2, 1, 0, 5, 4, 3], [0, 1, 3, 5, 2], 5
|
202
|
+
set = REF_50.to_set
|
203
|
+
10.times { assert(set.include?(set.choose)) }
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_hash
|
207
|
+
checker_5({ 1 => 2 }, [2] * 5, 5)
|
208
|
+
checker_5({ 1 => 2, 3 => 4 }, [4, 2, 2, 2, 4], 5)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_array_50
|
212
|
+
checker_50 [4], [4] * 50, 50
|
213
|
+
checker_50 [
|
214
|
+
36, 16, 15, 6, 27, 33, 17, 10, 18, 39, 8, 43, 19, 23, 49, 40, 46, 37,
|
215
|
+
9, 41, 35, 0, 38, 26, 22, 4, 7, 25, 21, 12, 42, 45, 28, 5, 31, 24, 34,
|
216
|
+
48, 32, 30, 13, 29, 11, 2, 1, 20, 3, 44, 47, 14
|
217
|
+
], [
|
218
|
+
21, 19, 37, 8, 16, 48, 3, 4, 44, 15, 20, 34, 35, 33, 42, 49, 9, 30,
|
219
|
+
18, 40, 46, 2, 25, 5, 38, 10, 28, 6, 24, 39, 41, 23, 0, 17, 26, 7, 27,
|
220
|
+
13, 1, 43, 14, 12, 11, 22, 45, 47, 31, 36, 32, 29
|
221
|
+
], 50
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_integer_instances
|
225
|
+
assert_raise(ArgumentError) { checker_5 0, [], :no }
|
226
|
+
checker_5 1, [0] * 5, :no
|
227
|
+
checker_5 4, [1, 2, 0, 0, 3], :no
|
228
|
+
checker_5 10, REF_5, :no
|
229
|
+
assert(1000.choose < 1000)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_float_instances
|
233
|
+
assert_raise(ArgumentError) { checker_5 0.0, [], :no }
|
234
|
+
checker_5 1.0, [ 0.187528345035389, 0.368857819121331, 0.06954449811019,
|
235
|
+
0.188887464581057, 0.213757352204993 ], :no
|
236
|
+
assert(2.0.choose < 2)
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_integer_range_instances
|
240
|
+
checker_5 1..1, [1] * 5, :no
|
241
|
+
checker_5 1..2, [2, 1, 1, 1, 2], :no
|
242
|
+
checker_5 0..1, [1, 0, 0, 0, 1], :no
|
243
|
+
checker_5 0..4, [1, 2, 4, 0, 3], :no
|
244
|
+
end
|
245
|
+
|
246
|
+
class Xs
|
247
|
+
include Comparable
|
248
|
+
attr_reader :length
|
249
|
+
def initialize ( n )
|
250
|
+
@length = n
|
251
|
+
end
|
252
|
+
def succ
|
253
|
+
Xs.new(@length.succ)
|
254
|
+
end
|
255
|
+
def <=> ( rhs )
|
256
|
+
@length <=> rhs.length
|
257
|
+
end
|
258
|
+
def inspect
|
259
|
+
'x' * @length
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_range_instances
|
264
|
+
checker_5 'a'..'a', ['a'] * 5, :no
|
265
|
+
checker_5 'a'..'b', ['b', 'a', 'a', 'a', 'b'], :no
|
266
|
+
checker_5 Xs.new(1)..Xs.new(4), [2, 3, 1, 1, 4].map { |x| Xs.new(x) }, :no
|
267
|
+
end
|
268
|
+
|
269
|
+
end # class ChooseTest
|
270
|
+
|
271
|
+
end
|