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/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
|