vex 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +112 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/config/README +2 -0
- data/config/dependencies.rb +10 -0
- data/config/gem.yml +7 -0
- data/init.rb +36 -0
- data/lib/nokogiri/nokogiri_ext.rb +96 -0
- data/lib/vex.rb +5 -0
- data/lib/vex/action_controller.rb +4 -0
- data/lib/vex/action_controller/verify_action.rb +97 -0
- data/lib/vex/action_controller/whitelisted_actions.rb +45 -0
- data/lib/vex/active_record.rb +3 -0
- data/lib/vex/active_record/__init__.rb +0 -0
- data/lib/vex/active_record/advisory_lock.rb +11 -0
- data/lib/vex/active_record/advisory_lock/mysql_adapter.rb +16 -0
- data/lib/vex/active_record/advisory_lock/sqlite_adapter.rb +78 -0
- data/lib/vex/active_record/belongs_to_many.rb +143 -0
- data/lib/vex/active_record/find_by_extension.rb +70 -0
- data/lib/vex/active_record/gem.rb +8 -0
- data/lib/vex/active_record/lite_table.rb +139 -0
- data/lib/vex/active_record/lite_view.rb +140 -0
- data/lib/vex/active_record/mass_load.rb +65 -0
- data/lib/vex/active_record/mysql_backup.rb +21 -0
- data/lib/vex/active_record/plugins/default_value_for/LICENSE.TXT +19 -0
- data/lib/vex/active_record/plugins/default_value_for/README.rdoc +421 -0
- data/lib/vex/active_record/plugins/default_value_for/Rakefile +6 -0
- data/lib/vex/active_record/plugins/default_value_for/init.rb +91 -0
- data/lib/vex/active_record/plugins/default_value_for/test.rb +279 -0
- data/lib/vex/active_record/plugins/default_value_for/test.sqlite3 +0 -0
- data/lib/vex/active_record/random_id.rb +56 -0
- data/lib/vex/active_record/resolver.rb +49 -0
- data/lib/vex/active_record/serialize_hash.rb +125 -0
- data/lib/vex/active_record/to_html.rb +53 -0
- data/lib/vex/active_record/validate.rb +76 -0
- data/lib/vex/active_record/validation_error_ext.rb +68 -0
- data/lib/vex/base.rb +2 -0
- data/lib/vex/base/app.rb +75 -0
- data/lib/vex/base/array/at_random.rb +17 -0
- data/lib/vex/base/array/cross.rb +26 -0
- data/lib/vex/base/array/each_batch.rb +32 -0
- data/lib/vex/base/array/parallel_map.rb +98 -0
- data/lib/vex/base/deprecation.rb +41 -0
- data/lib/vex/base/enumerable/deep.rb +95 -0
- data/lib/vex/base/enumerable/enumerable_ext.rb +59 -0
- data/lib/vex/base/enumerable/progress.rb +71 -0
- data/lib/vex/base/filesystem/fast_copy.rb +61 -0
- data/lib/vex/base/filesystem/grep.rb +34 -0
- data/lib/vex/base/filesystem/lock.rb +43 -0
- data/lib/vex/base/filesystem/lock.rb.test.lck +0 -0
- data/lib/vex/base/filesystem/lock.rb.test.pid +1 -0
- data/lib/vex/base/filesystem/make_dirs.rb +94 -0
- data/lib/vex/base/filesystem/parse_filename.rb +36 -0
- data/lib/vex/base/filesystem/tmp_file.rb +87 -0
- data/lib/vex/base/filesystem/write.rb +43 -0
- data/lib/vex/base/hash/compact.rb +38 -0
- data/lib/vex/base/hash/cross.rb +117 -0
- data/lib/vex/base/hash/easy_access.rb +141 -0
- data/lib/vex/base/hash/ensure_keys.rb +18 -0
- data/lib/vex/base/hash/extract.rb +71 -0
- data/lib/vex/base/hash/extras.rb +62 -0
- data/lib/vex/base/hash/inspect.rb +17 -0
- data/lib/vex/base/hash/simple_access_methods.rb +74 -0
- data/lib/vex/base/invalid_argument/invalid_argument.rb +97 -0
- data/lib/vex/base/local_conf.rb +35 -0
- data/lib/vex/base/net/http_ext.rb +227 -0
- data/lib/vex/base/net/socket_ext.rb +43 -0
- data/lib/vex/base/object/insp.rb +123 -0
- data/lib/vex/base/object/multiple_attributes.rb +58 -0
- data/lib/vex/base/object/singleton_methods.rb +23 -0
- data/lib/vex/base/object/with_benchmark.rb +110 -0
- data/lib/vex/base/range_array.rb +40 -0
- data/lib/vex/base/range_ext.rb +28 -0
- data/lib/vex/base/safe_token.rb +156 -0
- data/lib/vex/base/string/string_ext.rb +136 -0
- data/lib/vex/base/thread/deferred.rb +52 -0
- data/lib/vex/base/thread/sleep.rb +11 -0
- data/lib/vex/base/time/date_ext.rb +12 -0
- data/lib/vex/boot.rb +40 -0
- data/lib/vex/boot/array.rb +22 -0
- data/lib/vex/boot/blank.rb +41 -0
- data/lib/vex/boot/string.rb +60 -0
- data/migration/create_request_log.rb +28 -0
- data/r.rb +35 -0
- data/script/console +19 -0
- data/script/rebuild +7 -0
- data/tasks/echoe.rake +52 -0
- data/tasks/validate_db.rake +14 -0
- data/test/ar.rb +30 -0
- data/test/auto.rb +31 -0
- data/test/base-tests/local_conf.rb +25 -0
- data/test/base.rb +2 -0
- data/test/boot.rb +3 -0
- data/test/config/local.defaults.yml +4 -0
- data/test/config/local.yml +8 -0
- data/test/test.sqlite3 +0 -0
- data/test/test.sqlite3.Class#create.lck +0 -0
- data/test/test.sqlite3.Class#create.lck.lck +0 -0
- data/test/test.sqlite3.Class#create.lck.pid +1 -0
- data/test/test.sqlite3.Class#create.pid +1 -0
- data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck +0 -0
- data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck.lck +0 -0
- data/test/test.sqlite3.LiteView.make.holders__view_dummy.lck.pid +1 -0
- data/test/test.sqlite3.LiteView.make.holders__view_dummy.pid +1 -0
- data/test/test.sqlite3.vex.lck +0 -0
- data/test/test_helper.rb +49 -0
- data/test/tmp/copy.dat +1 -0
- data/test/tmp/lock.sqlite3 +0 -0
- data/test/tmp/lock.sqlite3.etest.lck +0 -0
- data/test/tmp/lock.sqlite3.etest.pid +1 -0
- data/test/tmp/somedata.dat +61 -0
- data/vex.gemspec +49 -0
- data/vex.tmproj +186 -0
- metadata +305 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module File::Grep
|
2
|
+
def grep(rex, *files)
|
3
|
+
files = files.flatten
|
4
|
+
|
5
|
+
unless block_given?
|
6
|
+
results = []
|
7
|
+
grep(rex, files) do |line, file, *args|
|
8
|
+
results << [ line, file ]
|
9
|
+
end
|
10
|
+
return results
|
11
|
+
end
|
12
|
+
|
13
|
+
files.each do |file|
|
14
|
+
File.readlines(file).each do |line|
|
15
|
+
next unless matches = (rex.match(line))
|
16
|
+
yield line, file, matches
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
File.extend File::Grep
|
23
|
+
|
24
|
+
module File::Grep::Etest
|
25
|
+
def test_grep
|
26
|
+
assert_equal 4, File.grep(/Etest/, __FILE__).length
|
27
|
+
assert_equal 5, File.grep(/ETEST/i, __FILE__).length
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_greps
|
31
|
+
assert_equal 8, File.grep(/Etest/, [ __FILE__, __FILE__ ]).length
|
32
|
+
assert_equal 8, File.grep(/Etest/, __FILE__, __FILE__ ).length
|
33
|
+
end
|
34
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module File::Lock
|
2
|
+
#
|
3
|
+
# File.locked implements recursive locking based on lock files.
|
4
|
+
def locked(path, &block)
|
5
|
+
file = File.open "#{path}.lck", "w+"
|
6
|
+
begin
|
7
|
+
# First try to lock the file nonblockingly.
|
8
|
+
# Failing that it might be already locked by *this* process.
|
9
|
+
# Otherwise it is locked by someone else.
|
10
|
+
if locked = file.flock(File::LOCK_EX | File::LOCK_NB)
|
11
|
+
File.write("#{path}.pid", Thread.uid)
|
12
|
+
elsif File.read("#{path}.pid") == Thread.uid
|
13
|
+
# already locked by us.
|
14
|
+
else
|
15
|
+
locked = file.flock(File::LOCK_EX)
|
16
|
+
end
|
17
|
+
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
file.flock(File::LOCK_UN) if locked
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
File.extend File::Lock
|
26
|
+
|
27
|
+
module File::Lock::Etest
|
28
|
+
TESTFILE = "#{__FILE__}.test"
|
29
|
+
|
30
|
+
def test_lock
|
31
|
+
i = 1
|
32
|
+
File.locked TESTFILE do
|
33
|
+
File.locked TESTFILE do
|
34
|
+
i = 2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_equal(2, i)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_lock_unsuccessful
|
42
|
+
end
|
43
|
+
end if VEX_TEST == "base"
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
7394.106710
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Dir::MakeDirs
|
2
|
+
def exists?(path)
|
3
|
+
begin
|
4
|
+
Dir.open(path) && true
|
5
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
6
|
+
false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def mkdirs(path)
|
11
|
+
paths = path.split("/")
|
12
|
+
paths.each_with_index do |path, idx|
|
13
|
+
p = paths[0..idx].join("/")
|
14
|
+
next if p.empty? # This is root
|
15
|
+
next if exists?(p)
|
16
|
+
mkdir(p)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def rmdirs(path)
|
21
|
+
Dir.glob("#{path}/**/*", File::FNM_DOTMATCH).sort.reverse.each do |file|
|
22
|
+
if File.directory?(file)
|
23
|
+
next if file =~ /\/\.\.?$/
|
24
|
+
Dir.rmdir(file)
|
25
|
+
else
|
26
|
+
File.unlink(file)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Dir.rmdir(path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def tmp(do_unlink = true, &block)
|
34
|
+
path = "#{App.tmpdir}/#{$$}_#{Thread.current.object_id}"
|
35
|
+
Dir.mkdirs path
|
36
|
+
|
37
|
+
r = yield(path)
|
38
|
+
ensure
|
39
|
+
Dir.rmdirs(path) if path && do_unlink
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Dir.extend Dir::MakeDirs
|
44
|
+
|
45
|
+
module Dir::MakeDirs::Etest
|
46
|
+
def test_mkdirs
|
47
|
+
base = File.dirname(__FILE__) + "/dirtest"
|
48
|
+
|
49
|
+
assert !Dir.exists?(base)
|
50
|
+
Dir.mkdirs "#{base}/a/b/c"
|
51
|
+
Dir.mkdirs "#{base}/a/b/.dot"
|
52
|
+
assert Dir.exists?(base)
|
53
|
+
assert Dir.exists?("#{base}/a/b/c")
|
54
|
+
|
55
|
+
File.touch "#{base}/a/b/x.y"
|
56
|
+
File.touch "#{base}/a/b/.x.y"
|
57
|
+
File.touch "#{base}/a/b/..x.y"
|
58
|
+
File.touch "#{base}/a/b/.dot/a"
|
59
|
+
|
60
|
+
Dir.rmdirs("#{base}")
|
61
|
+
assert !Dir.exists?(base)
|
62
|
+
assert !Dir.exists?("#{base}/a/b/c")
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_exists
|
66
|
+
assert Dir.exists?(File.dirname(__FILE__))
|
67
|
+
assert !Dir.exists?(__FILE__)
|
68
|
+
assert !Dir.exists?(__FILE__ + ".unknown")
|
69
|
+
assert !Dir.exists?(__FILE__ + ":invalid")
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_tmpdir
|
73
|
+
p = nil
|
74
|
+
Dir.tmp do |pdir|
|
75
|
+
p = pdir
|
76
|
+
end
|
77
|
+
|
78
|
+
assert p.starts_with?("#{App.tmpdir}/")
|
79
|
+
assert_file_doesnt_exist p
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_tmpdir_unlinks_on_raise
|
83
|
+
p = nil
|
84
|
+
assert_raise(RuntimeError) {
|
85
|
+
Dir.tmp do |pdir|
|
86
|
+
p = pdir
|
87
|
+
raise RuntimeError
|
88
|
+
end
|
89
|
+
}
|
90
|
+
|
91
|
+
assert p.starts_with?("#{App.tmpdir}/")
|
92
|
+
assert_file_doesnt_exist p
|
93
|
+
end
|
94
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class File
|
2
|
+
def self.basename_wo_ext(s)
|
3
|
+
bn = File.basename(s)
|
4
|
+
if bn =~ /^(.*)\.([^.]*)$/
|
5
|
+
$1
|
6
|
+
else
|
7
|
+
bn
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# File.extname_wo_dot("x.y") => "y"
|
13
|
+
# File.extname_wo_dot("x.") => ""
|
14
|
+
# File.extname_wo_dot(".y") => ""
|
15
|
+
# File.extname_wo_dot("x") => ""
|
16
|
+
#
|
17
|
+
def self.extname_wo_dot(s)
|
18
|
+
File.extname(s) =~ /^\.([^.]*)$/ ? $1 : ""
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module File::Etest
|
23
|
+
def test_extname_wo_dot
|
24
|
+
assert_equal "y", File.extname_wo_dot("x.y")
|
25
|
+
assert_equal "", File.extname_wo_dot("x.")
|
26
|
+
assert_equal "", File.extname_wo_dot(".y")
|
27
|
+
assert_equal "", File.extname_wo_dot("x")
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_basename_wo_ext
|
31
|
+
assert_equal "x", File.basename_wo_ext("x.y")
|
32
|
+
assert_equal "x", File.basename_wo_ext("x.")
|
33
|
+
assert_equal "", File.basename_wo_ext(".y")
|
34
|
+
assert_equal "x", File.basename_wo_ext("x")
|
35
|
+
end
|
36
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module FileUtils::TmpFile
|
2
|
+
def self.counter
|
3
|
+
Thread.current["tmpfiles"] ||= 0
|
4
|
+
Thread.current["tmpfiles"] += 1
|
5
|
+
end
|
6
|
+
|
7
|
+
#
|
8
|
+
# tmpfile("xx.jpg") do |dest|
|
9
|
+
# Net.download("http://xx.yy.zz/a.jpg", dest)
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# the block gets the temp file name, which is guaranteed to be
|
13
|
+
# unique amongst all running processes.
|
14
|
+
#
|
15
|
+
# If the path parameter is set the temporary file will be fastcopied
|
16
|
+
# to that output file.
|
17
|
+
def tmpfile(path=nil, &block)
|
18
|
+
raise ArgumentError, "This no longer supports Symbol parameters" if path.is_a?(Symbol)
|
19
|
+
ext = "#{Thread.uid}_#{FileUtils::TmpFile.counter}"
|
20
|
+
|
21
|
+
case path
|
22
|
+
when nil
|
23
|
+
tmp = "#{App.tmpdir}/data.#{ext}"
|
24
|
+
else
|
25
|
+
Dir.mkdirs(File.dirname(path))
|
26
|
+
tmp = "#{path}.tmp#{ext}"
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
result = yield(tmp)
|
31
|
+
if result != false && path && File.exist?(tmp)
|
32
|
+
FileUtils.fast_copy(tmp, path)
|
33
|
+
end
|
34
|
+
return result
|
35
|
+
ensure
|
36
|
+
File.unlink(tmp) if File.exists?(tmp)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
FileUtils.extend FileUtils::TmpFile
|
42
|
+
|
43
|
+
module FileUtils::TmpFile::Etest
|
44
|
+
def test_tmpfile
|
45
|
+
assert File.exist?(__FILE__)
|
46
|
+
|
47
|
+
# so something successfully via a tmp file
|
48
|
+
FileUtils.fast_copy __FILE__, "tmp/copy.dat"
|
49
|
+
assert File.exist?("tmp/copy.dat")
|
50
|
+
|
51
|
+
FileUtils.tmpfile "tmp/copy.dat" do |dest|
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
assert_equal File.size(__FILE__), File.size("tmp/copy.dat")
|
56
|
+
|
57
|
+
FileUtils.tmpfile "tmp/copy.dat" do |dest|
|
58
|
+
File.write(dest, "hey")
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_equal 3, File.size("tmp/copy.dat")
|
62
|
+
|
63
|
+
FileUtils.fast_copy __FILE__, "tmp/copy.dat"
|
64
|
+
assert_equal File.size(__FILE__), File.size("tmp/copy.dat")
|
65
|
+
|
66
|
+
FileUtils.tmpfile "tmp/copy.dat" do |dest|
|
67
|
+
File.write(dest, "hey")
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
assert_equal File.size(__FILE__), File.size("tmp/copy.dat")
|
72
|
+
|
73
|
+
FileUtils.tmpfile "tmp/copy.dat" do |dest|
|
74
|
+
File.write(dest, "hey")
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_equal 3, File.size("tmp/copy.dat")
|
79
|
+
|
80
|
+
r = FileUtils.tmpfile "tmp/copy.dat" do |dest|
|
81
|
+
File.write(dest, "hey")
|
82
|
+
"fourfour"
|
83
|
+
end
|
84
|
+
|
85
|
+
assert_equal "fourfour", r
|
86
|
+
end
|
87
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module File::Write
|
2
|
+
def touch(*files)
|
3
|
+
files.each do |file|
|
4
|
+
File.open(file, "w") do |f|
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(path, data)
|
10
|
+
File.open(path, "w+") do |file|
|
11
|
+
file.write(data)
|
12
|
+
end
|
13
|
+
path
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
File.extend File::Write
|
18
|
+
|
19
|
+
module File::Write::Etest
|
20
|
+
TESTFILE = "#{__FILE__}.test"
|
21
|
+
|
22
|
+
def test_touches
|
23
|
+
assert !File.exist?(TESTFILE)
|
24
|
+
File.touch TESTFILE
|
25
|
+
assert File.exist?(TESTFILE)
|
26
|
+
File.touch TESTFILE
|
27
|
+
assert File.exist?(TESTFILE)
|
28
|
+
File.unlink TESTFILE
|
29
|
+
assert !File.exist?(TESTFILE)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_writes
|
33
|
+
assert !File.exist?(TESTFILE)
|
34
|
+
File.write TESTFILE, "blabber"
|
35
|
+
assert_equal("blabber", File.read(TESTFILE))
|
36
|
+
File.write TESTFILE, "bla"
|
37
|
+
assert_equal("bla", File.read(TESTFILE))
|
38
|
+
File.write TESTFILE, ""
|
39
|
+
assert_equal("", File.read(TESTFILE))
|
40
|
+
File.unlink TESTFILE
|
41
|
+
assert !File.exist?(TESTFILE)
|
42
|
+
end
|
43
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hash::Compact
|
2
|
+
def compact
|
3
|
+
dup.compact!
|
4
|
+
end
|
5
|
+
|
6
|
+
def compact!
|
7
|
+
empty = []
|
8
|
+
each { |k,v| empty << k if v.nil? }
|
9
|
+
empty.each do |k| delete(k) end
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Hash
|
15
|
+
include Compact
|
16
|
+
end
|
17
|
+
|
18
|
+
module Hash::Compact::Etest
|
19
|
+
def test_compact_no
|
20
|
+
h = { 1 => 2 }
|
21
|
+
assert_equal(h.compact, h)
|
22
|
+
assert_not_equal(h.compact.object_id, h.object_id)
|
23
|
+
assert_equal(h.compact!.object_id, h.object_id)
|
24
|
+
assert_equal(h.compact!, h.compact)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_compact
|
28
|
+
h = { 1 => nil }
|
29
|
+
assert_equal(h.compact, {})
|
30
|
+
h.compact!
|
31
|
+
assert_equal(h, {})
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_compact_2
|
35
|
+
h = { nil => 1 }
|
36
|
+
assert_equal(h.compact, { nil => 1})
|
37
|
+
end
|
38
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Hash::Cross
|
2
|
+
#
|
3
|
+
# { :a => [ 1, 2], :b => [ "bb", "cc"], :c => :cc }.cross =>
|
4
|
+
#
|
5
|
+
# [
|
6
|
+
# { :a => 1, :b => "bb", :c => :cc },
|
7
|
+
# { :a => 2, :b => "bb", :c => :cc },
|
8
|
+
# { :a => 1, :b => "cc", :c => :cc },
|
9
|
+
# { :a => 2, :b => "cc", :c => :cc }
|
10
|
+
# ]
|
11
|
+
#
|
12
|
+
def cross(*keys)
|
13
|
+
dup.send :do_cross, *keys
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def do_cross(*keys)
|
19
|
+
keys = self.keys if keys.empty?
|
20
|
+
keys = keys.select { |key| self[key].is_a?(Array) }
|
21
|
+
|
22
|
+
crossing = self.extract! *keys
|
23
|
+
|
24
|
+
array = [ self ]
|
25
|
+
|
26
|
+
keys.each do |key|
|
27
|
+
r = []
|
28
|
+
|
29
|
+
values = crossing[key]
|
30
|
+
array.each do |obj|
|
31
|
+
values.each do |value|
|
32
|
+
# Note: the following (instead of the obj.dup.update() results in a ~10%
|
33
|
+
# faster cross implementation
|
34
|
+
o = obj.dup
|
35
|
+
o[key] = value
|
36
|
+
r << o
|
37
|
+
end
|
38
|
+
end
|
39
|
+
array = r
|
40
|
+
end
|
41
|
+
|
42
|
+
array
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Hash
|
47
|
+
include Cross
|
48
|
+
end
|
49
|
+
|
50
|
+
module Hash::Cross::Etest
|
51
|
+
def assert_equal_sets(a, b)
|
52
|
+
return assert_equal_sets(Set.new(a), b) unless a.is_a?(Set)
|
53
|
+
return assert_equal_sets(a, Set.new(b)) unless b.is_a?(Set)
|
54
|
+
|
55
|
+
assert_equal(a, b)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_cross_1
|
59
|
+
uncrossed = { :a => [ 1, 2], :b => [ "bb", "cc"], :c => :cc }
|
60
|
+
uncrossed_orig = uncrossed.dup
|
61
|
+
|
62
|
+
crossed = [
|
63
|
+
{ :a => [1, 2], :b => "bb", :c => :cc },
|
64
|
+
{ :a => [1, 2], :b => "cc", :c => :cc }
|
65
|
+
]
|
66
|
+
|
67
|
+
assert_equal_sets(crossed, uncrossed.cross(:b))
|
68
|
+
assert_equal(uncrossed_orig, uncrossed)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_cross_2
|
72
|
+
uncrossed = { :a => [ 1, 2], :b => [ "bb", "cc"], :c => :cc }
|
73
|
+
uncrossed_orig = uncrossed.dup
|
74
|
+
|
75
|
+
crossed = [
|
76
|
+
{ :a => 1, :b => "bb", :c => :cc },
|
77
|
+
{ :a => 2, :b => "bb", :c => :cc },
|
78
|
+
{ :a => 1, :b => "cc", :c => :cc },
|
79
|
+
{ :a => 2, :b => "cc", :c => :cc }
|
80
|
+
]
|
81
|
+
|
82
|
+
assert_equal_sets(crossed, uncrossed.cross)
|
83
|
+
assert_equal(uncrossed_orig, uncrossed)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_cross_2_w_order
|
87
|
+
uncrossed = { :a => [ 1, 2], :b => [ "bb", "cc"], :c => :cc }
|
88
|
+
uncrossed_orig = uncrossed.dup
|
89
|
+
|
90
|
+
crossed = [
|
91
|
+
{ :a => 1, :b => "bb", :c => :cc },
|
92
|
+
{ :a => 1, :b => "cc", :c => :cc },
|
93
|
+
{ :a => 2, :b => "bb", :c => :cc },
|
94
|
+
{ :a => 2, :b => "cc", :c => :cc }
|
95
|
+
]
|
96
|
+
|
97
|
+
assert_equal(crossed, uncrossed.cross(:a, :b))
|
98
|
+
assert_equal(uncrossed_orig, uncrossed)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_cross_simple
|
102
|
+
uncrossed = { :a => :b }
|
103
|
+
assert_equal([{:a=>:b}], uncrossed.cross)
|
104
|
+
|
105
|
+
uncrossed = { :a => [ 1, :b ] }
|
106
|
+
assert_equal([{:a=>1}, {:a=>:b}], uncrossed.cross)
|
107
|
+
end
|
108
|
+
|
109
|
+
# def xtest_benchmark_1
|
110
|
+
# benchmark do
|
111
|
+
# 5000.times do
|
112
|
+
# uncrossed = { :a => [ 1, 2], :b => [ "bb", "cc"], :c => :cc }
|
113
|
+
# uncrossed.cross
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
end if VEX_TEST == "base"
|