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,125 @@
|
|
1
|
+
__END__
|
2
|
+
|
3
|
+
module ActiveRecord::SerializeHash
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.alias_method_chain :reload, :serialize_hash
|
7
|
+
base.before_update :update_serialize_hashes
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.jsonize(data)
|
11
|
+
return nil if data.nil?
|
12
|
+
return data.to_json unless data.is_a?(Hash)
|
13
|
+
|
14
|
+
"{" + data.to_a.
|
15
|
+
map do |k,v| "#{k.to_json}:#{jsonize(v)}" end.
|
16
|
+
sort.
|
17
|
+
join(",") +
|
18
|
+
"}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.unjsonize(data)
|
22
|
+
r = data.blank? ? {} : JSON.parse(data)
|
23
|
+
r = r.with_indifferent_access if r.respond_to?(:with_indifferent_access)
|
24
|
+
r
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def serialize_hash_attributes
|
29
|
+
@serialize_hash_attributes ||= Set.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def serialize_hash(attr)
|
33
|
+
serialize_hash_attributes << attr
|
34
|
+
|
35
|
+
class_eval <<-RUBY
|
36
|
+
def #{attr}; @#{attr} ||= ActiveRecord::SerializeHash.unjsonize read_attribute(:#{attr}); end
|
37
|
+
def #{attr}=(d); write_attribute(:#{attr}, ActiveRecord::SerializeHash.jsonize(d)); @#{attr} = nil;
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
end
|
41
|
+
|
42
|
+
def hashed_attributes(*syms)
|
43
|
+
serialize_hash :hashed_attributes
|
44
|
+
|
45
|
+
syms.each do |sym|
|
46
|
+
define_method(sym) do hashed_attributes[sym] end
|
47
|
+
define_method("#{sym}=") do |val| hashed_attributes[sym] = val end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def reload_with_serialize_hash
|
53
|
+
self.class.serialize_hash_attributes.each do |attr|
|
54
|
+
instance_variable_set "@#{attr}", nil
|
55
|
+
end
|
56
|
+
reload_without_serialize_hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def update_serialize_hashes
|
60
|
+
self.class.serialize_hash_attributes.each do |attr|
|
61
|
+
next unless val = instance_variable_get("@#{attr}")
|
62
|
+
self.send "#{attr}=", val
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class ActiveRecord::Base
|
68
|
+
include ActiveRecord::SerializeHash
|
69
|
+
end
|
70
|
+
|
71
|
+
module ActiveRecord::SerializeHash::Etest
|
72
|
+
def test_serialize_hash
|
73
|
+
rb = RandomBase.create!
|
74
|
+
|
75
|
+
assert_equal({}, rb.parameters)
|
76
|
+
assert_nil(rb.parameters["test"])
|
77
|
+
|
78
|
+
rb.parameters[:test] = "bla"
|
79
|
+
assert_equal("bla", rb.parameters[:test])
|
80
|
+
assert_equal("bla", rb.parameters["test"])
|
81
|
+
|
82
|
+
rb.parameters["test"] = "lurk"
|
83
|
+
|
84
|
+
assert_equal("lurk", rb.parameters[:test])
|
85
|
+
assert_equal("lurk", rb.parameters["test"])
|
86
|
+
|
87
|
+
rb.reload
|
88
|
+
assert_nil(rb.parameters["test"])
|
89
|
+
rb.parameters["test"] = "lurk"
|
90
|
+
rb.save!
|
91
|
+
|
92
|
+
rb.reload
|
93
|
+
assert_equal("lurk", rb.parameters[:test])
|
94
|
+
assert_equal("lurk", rb.parameters["test"])
|
95
|
+
|
96
|
+
rb = RandomBase.find(rb.id)
|
97
|
+
assert_equal("lurk", rb.parameters[:test])
|
98
|
+
assert_equal("lurk", rb.parameters["test"])
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_hashed_attributes
|
102
|
+
rb = RandomBase.create!
|
103
|
+
rb.ha1 = "ha1"
|
104
|
+
assert_equal("ha1", rb.ha1)
|
105
|
+
|
106
|
+
rb.reload
|
107
|
+
assert_equal(nil, rb.ha1)
|
108
|
+
rb.ha1 = "ha1"
|
109
|
+
rb.save!
|
110
|
+
rb.reload
|
111
|
+
assert_equal("ha1", rb.ha1)
|
112
|
+
|
113
|
+
rb = RandomBase.find(rb.id)
|
114
|
+
assert_equal("ha1", rb.ha1)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_reload
|
118
|
+
rb = RandomBase.create!
|
119
|
+
rb.parameters[:test] = "bla"
|
120
|
+
|
121
|
+
assert_equal("bla", rb.parameters[:test])
|
122
|
+
rb.reload
|
123
|
+
assert_nil(rb.parameters["test"])
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module ActiveRecord::ToHtml
|
2
|
+
def to_html(options = {}, &block)
|
3
|
+
options = {
|
4
|
+
:skip_instruct => true,
|
5
|
+
}.update(options)
|
6
|
+
|
7
|
+
to_xml(options, &block).gsub( /<[^>]+>/ ) do |m|
|
8
|
+
if m.starts_with?("</")
|
9
|
+
"</div>"
|
10
|
+
else
|
11
|
+
m =~ /^<(\S+)\s*([^>]*)>$/
|
12
|
+
klass, args = $1, $2
|
13
|
+
"<div class='#{klass}'#{args.blank? ? "" : " #{args}"}>"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ActiveRecord::Base
|
20
|
+
include ActiveRecord::ToHtml
|
21
|
+
end
|
22
|
+
|
23
|
+
module ActiveRecord::ToHtml::Etest
|
24
|
+
class Data < ActiveRecord::Base
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup
|
28
|
+
Data.lite_table do
|
29
|
+
string :name
|
30
|
+
string :age
|
31
|
+
end
|
32
|
+
|
33
|
+
Data.create! :name => "name", :age => 2
|
34
|
+
|
35
|
+
assert_equal(1, Data.count)
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
Data.destroy_all
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_to_html
|
43
|
+
html = <<-HTML
|
44
|
+
<div class='active-record-to-html-etest-data'>
|
45
|
+
<div class='age'>2</div>
|
46
|
+
<div class='id' type="integer">25</div>
|
47
|
+
<div class='name'>name</div>
|
48
|
+
</div>
|
49
|
+
HTML
|
50
|
+
|
51
|
+
assert_equal html, Data.first.to_html
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ActiveRecord::Validate
|
2
|
+
def self.all(quiet=nil, &block)
|
3
|
+
klasses(quiet).inject(0) do |count, klass|
|
4
|
+
count += invalid_models(klass, quiet).length
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.purge
|
9
|
+
klasses(true).each do |klass|
|
10
|
+
invalids = invalid_models(klass, true)
|
11
|
+
klass.delete_all [ "id IN (?)", invalids.map(&:id) ] unless invalids.empty?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def self.set_klass_for(opts)
|
17
|
+
@klass_for_table ||= {}
|
18
|
+
@klass_for_table.update opts.with_indifferent_access
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.klass_for_table(table)
|
24
|
+
@klass_for_table ||= {}
|
25
|
+
if klass = @klass_for_table[table]
|
26
|
+
klass.constantize
|
27
|
+
else
|
28
|
+
table.singularize.camelize.constantize?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.klasses(quiet)
|
33
|
+
ActiveRecord::Base.connection.tables.map do |table|
|
34
|
+
klass = klass_for_table table
|
35
|
+
if !klass
|
36
|
+
STDERR.puts "* #{table}: table w/o class" unless quiet
|
37
|
+
elsif !klass.respond_to?(:table_name) || klass.table_name != table
|
38
|
+
STDERR.puts "Tablename mismatch #{table.inspect} vs #{klass.table_name.inspect}" unless quiet
|
39
|
+
else
|
40
|
+
klass
|
41
|
+
end
|
42
|
+
end.compact
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.invalid_models(klass, quiet)
|
46
|
+
validate_klass(klass) do |*args|
|
47
|
+
msg, force = *args
|
48
|
+
STDERR.puts(msg) if force || !quiet
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.validate_klass(klass)
|
53
|
+
yield "#{klass}: #{sum=klass.count} models"
|
54
|
+
|
55
|
+
invalid = []
|
56
|
+
|
57
|
+
klass.each do |model|
|
58
|
+
next if model.valid?
|
59
|
+
invalid << model
|
60
|
+
|
61
|
+
yield "\tInvalid model #{model.class}##{model.id}: #{model.errors.full_messages.join(", ")}"
|
62
|
+
end
|
63
|
+
|
64
|
+
yield "\r#{klass}: checked #{klass.count} models, #{invalid.length} invalid", :force
|
65
|
+
|
66
|
+
return invalid if invalid.empty?
|
67
|
+
|
68
|
+
invalid.group_by(&:class).to_a.
|
69
|
+
sort_by do |klass, ms| klass.name end.
|
70
|
+
each do |klass, ms|
|
71
|
+
yield "\t** #{klass}: Invalid models: #{ms.collect(&:id).inspect}"
|
72
|
+
end
|
73
|
+
|
74
|
+
invalid
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
# better error reporting: this is useful mainly for development cycles, as
|
3
|
+
# it adds an error message only once
|
4
|
+
module ActiveRecord::Errors::Unique
|
5
|
+
|
6
|
+
def delete(entry)
|
7
|
+
@errors.delete entry.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(attribute, message = nil, options = {})
|
11
|
+
add_with_unique_messages(attribute, message, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_with_unique_messages(error_or_attr, message = nil, options = {})
|
15
|
+
if error_or_attr.is_a?(ActiveRecord::Error)
|
16
|
+
error, attribute = error_or_attr, error_or_attr.attribute
|
17
|
+
else
|
18
|
+
attribute = error_or_attr
|
19
|
+
error = ActiveRecord::Error.new(@base, attribute, message, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
options[:message] = options.delete(:default) if options.has_key?(:default)
|
23
|
+
|
24
|
+
@errors[attribute.to_s] ||= []
|
25
|
+
|
26
|
+
existing = @errors[attribute.to_s].detect do |err|
|
27
|
+
err.message == message
|
28
|
+
end
|
29
|
+
|
30
|
+
existing || (@errors[attribute.to_s] << error)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ActiveRecord::Errors
|
35
|
+
include Unique
|
36
|
+
alias_method_chain :add, :unique_messages
|
37
|
+
end
|
38
|
+
|
39
|
+
module ActiveRecord::Errors::Unique::Etest
|
40
|
+
ActiveRecord::Base.connection.create_table :error_models do |t|
|
41
|
+
t.integer :value
|
42
|
+
end
|
43
|
+
|
44
|
+
class ErrorModels < ActiveRecord::Base
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_single_adds
|
48
|
+
obj = ErrorModels.new
|
49
|
+
|
50
|
+
obj.errors.add "value", "xxx"
|
51
|
+
assert_kind_of(String, obj.errors["value"])
|
52
|
+
|
53
|
+
obj.errors.add "value", "xxx"
|
54
|
+
assert_kind_of(String, obj.errors["value"])
|
55
|
+
|
56
|
+
obj.errors.add "value", "yyyy"
|
57
|
+
assert_equal(%w(xxx yyyy), obj.errors["value"])
|
58
|
+
|
59
|
+
obj.errors.add "value", "yyyy"
|
60
|
+
assert_equal(%w(xxx yyyy), obj.errors["value"])
|
61
|
+
|
62
|
+
obj.errors.add "value", "xxx"
|
63
|
+
assert_equal(%w(xxx yyyy), obj.errors["value"])
|
64
|
+
|
65
|
+
obj.errors.add "value", "zzz"
|
66
|
+
assert_equal(%w(xxx yyyy zzz), obj.errors["value"])
|
67
|
+
end
|
68
|
+
end
|
data/lib/vex/base.rb
ADDED
data/lib/vex/base/app.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module App
|
2
|
+
def self.rails?
|
3
|
+
defined?(RAILS_ROOT)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.revision
|
7
|
+
@revision ||= begin
|
8
|
+
"r#{File.read("#{root}/REVISION")}"
|
9
|
+
rescue Errno::ENOENT
|
10
|
+
""
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.env
|
15
|
+
if rails?
|
16
|
+
RAILS_ENV
|
17
|
+
elsif defined?(APP_ENV)
|
18
|
+
APP_ENV
|
19
|
+
else
|
20
|
+
"production"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.root
|
25
|
+
if defined?(RAILS_ROOT)
|
26
|
+
RAILS_ROOT
|
27
|
+
elsif defined?(APP_ROOT)
|
28
|
+
APP_ROOT
|
29
|
+
else
|
30
|
+
raise "Cannot determine application root"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.logger
|
35
|
+
if rails?
|
36
|
+
RAILS_DEFAULT_LOGGER
|
37
|
+
else
|
38
|
+
require "logger"
|
39
|
+
|
40
|
+
logdir = "#{root}/log"
|
41
|
+
FileUtils.mkdir_p logdir
|
42
|
+
Logger.new "#{logdir}/#{env}.log"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.tmpdir
|
47
|
+
@tmpdir ||= begin
|
48
|
+
tmpdir = if rails?
|
49
|
+
"#{root}/tmp"
|
50
|
+
else
|
51
|
+
ENV["TMPDIR"]
|
52
|
+
end
|
53
|
+
|
54
|
+
tmpdir = tmpdir.gsub(/\/$/, "")
|
55
|
+
|
56
|
+
raise "Cannot determine tmpdir setting" if tmpdir.blank?
|
57
|
+
tmpdir
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.local_conf
|
62
|
+
@local_conf = nil if App.env == "development"
|
63
|
+
@local_conf ||= LocalConf.new("local.yml")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module App::Etest
|
68
|
+
def test_app
|
69
|
+
assert_not_nil(App.root)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_app
|
73
|
+
assert_equal("", App.revision)
|
74
|
+
end
|
75
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Array::AtRandom
|
2
|
+
def at_random
|
3
|
+
self[Kernel.rand(length)] unless empty?
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
Array.send :include, Array::AtRandom
|
8
|
+
|
9
|
+
module Array::AtRandom::Etest
|
10
|
+
def test_at_random
|
11
|
+
array = [ 1, 2, 3, 4, 5 ]
|
12
|
+
5.times do
|
13
|
+
assert array.include?(array.at_random)
|
14
|
+
end
|
15
|
+
assert_equal nil, [].at_random
|
16
|
+
end
|
17
|
+
end if VEX_TEST == "base"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Array::Cross
|
2
|
+
def cross(other, &block)
|
3
|
+
if !block_given?
|
4
|
+
r = []
|
5
|
+
cross(other) do |mine, others|
|
6
|
+
r << [ mine, others ]
|
7
|
+
end
|
8
|
+
return r
|
9
|
+
else
|
10
|
+
each do |obj|
|
11
|
+
other.each do |oo| yield obj, oo end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Array.send :include, Array::Cross
|
18
|
+
|
19
|
+
module Array::Cross::Etest
|
20
|
+
def test_cross
|
21
|
+
assert_equal( [[1,1]], [1].cross([1]) )
|
22
|
+
assert_equal( [[1,1], [2,1]], [1, 2].cross([1]) )
|
23
|
+
assert_equal( [[1,1], [1,3], [2,1], [2,3]], [1, 2].cross([1, 3]) )
|
24
|
+
assert_equal( [], [1, 2].cross([]) )
|
25
|
+
end
|
26
|
+
end if VEX_TEST == "base"
|