tenacity 0.1.1 → 0.2.0
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/.gitignore +1 -0
- data/EXTEND.rdoc +32 -22
- data/LICENSE.txt +1 -1
- data/README.rdoc +14 -16
- data/Rakefile +0 -37
- data/history.txt +21 -0
- data/lib/tenacity.rb +2 -1
- data/lib/tenacity/association.rb +82 -0
- data/lib/tenacity/associations/belongs_to.rb +9 -9
- data/lib/tenacity/associations/has_many.rb +19 -31
- data/lib/tenacity/associations/has_one.rb +7 -23
- data/lib/tenacity/class_methods.rb +136 -33
- data/lib/tenacity/instance_methods.rb +9 -13
- data/lib/tenacity/orm_ext/activerecord.rb +13 -30
- data/lib/tenacity/orm_ext/couchrest/couchrest_extended_document.rb +1 -4
- data/lib/tenacity/orm_ext/couchrest/couchrest_model.rb +1 -4
- data/lib/tenacity/orm_ext/couchrest/tenacity_class_methods.rb +8 -17
- data/lib/tenacity/orm_ext/couchrest/tenacity_instance_methods.rb +6 -6
- data/lib/tenacity/orm_ext/mongo_mapper.rb +15 -25
- data/lib/tenacity/version.rb +1 -1
- data/tenacity.gemspec +3 -3
- data/test/associations/belongs_to_test.rb +17 -1
- data/test/associations/has_many_test.rb +22 -0
- data/test/associations/has_one_test.rb +15 -0
- data/test/fixtures/active_record_car.rb +4 -0
- data/test/fixtures/active_record_engine.rb +5 -0
- data/test/fixtures/couch_rest_door.rb +10 -0
- data/test/fixtures/couch_rest_windshield.rb +10 -0
- data/test/fixtures/mongo_mapper_ash_tray.rb +8 -0
- data/test/fixtures/mongo_mapper_dashboard.rb +3 -0
- data/test/fixtures/mongo_mapper_vent.rb +8 -0
- data/test/fixtures/mongo_mapper_wheel.rb +1 -1
- data/test/helpers/active_record_test_helper.rb +34 -4
- data/test/orm_ext/activerecord_test.rb +15 -8
- data/test/orm_ext/couchrest_test.rb +15 -8
- data/test/orm_ext/mongo_mapper_test.rb +14 -8
- data/test/test_helper.rb +5 -2
- metadata +16 -11
- data/Gemfile.lock +0 -70
@@ -20,10 +20,7 @@
|
|
20
20
|
# == t_has_one
|
21
21
|
#
|
22
22
|
# The +t_has_one+ association will not define any new keys on the object, since
|
23
|
-
# the associated object holds the foreign key.
|
24
|
-
# is the target of a t_has_one association from another class, then a property
|
25
|
-
# named after the association will be created on the MongoMapper object to
|
26
|
-
# hold the foreign key to the other object.
|
23
|
+
# the associated object holds the foreign key.
|
27
24
|
#
|
28
25
|
#
|
29
26
|
# == t_has_many
|
@@ -49,25 +46,18 @@ module TenacityMongoMapperPlugin
|
|
49
46
|
all(property => id.to_s)
|
50
47
|
end
|
51
48
|
|
52
|
-
def _t_initialize_has_many_association(
|
53
|
-
unless self.respond_to?(
|
54
|
-
key
|
49
|
+
def _t_initialize_has_many_association(association)
|
50
|
+
unless self.respond_to?(association.foreign_keys_property)
|
51
|
+
key association.foreign_keys_property, Array
|
52
|
+
after_save { |record| _t_save_associates(record, association) }
|
55
53
|
end
|
56
|
-
after_save { |record| _t_save_associates(record, association_id) }
|
57
54
|
end
|
58
55
|
|
59
|
-
def _t_initialize_belongs_to_association(
|
60
|
-
unless self.respond_to?(
|
61
|
-
key
|
56
|
+
def _t_initialize_belongs_to_association(association)
|
57
|
+
unless self.respond_to?(association.foreign_key)
|
58
|
+
key association.foreign_key, String
|
59
|
+
before_save { |record| _t_stringify_belongs_to_value(record, association) }
|
62
60
|
end
|
63
|
-
before_save { |record| _t_stringify_belongs_to_value(record, association_id) }
|
64
|
-
end
|
65
|
-
|
66
|
-
def _t_initialize_has_one_association(association_id)
|
67
|
-
unless self.respond_to?("#{association_id}_id")
|
68
|
-
key "#{association_id}_id", String
|
69
|
-
end
|
70
|
-
before_save { |record| _t_stringify_has_one_value(record, association_id) }
|
71
61
|
end
|
72
62
|
end
|
73
63
|
|
@@ -78,16 +68,16 @@ module TenacityMongoMapperPlugin
|
|
78
68
|
nil
|
79
69
|
end
|
80
70
|
|
81
|
-
def _t_associate_many(
|
82
|
-
self.send(
|
71
|
+
def _t_associate_many(association, associate_ids)
|
72
|
+
self.send(association.foreign_keys_property + '=', associate_ids.map { |associate_id| associate_id.to_s })
|
83
73
|
end
|
84
74
|
|
85
|
-
def _t_get_associate_ids(
|
86
|
-
self.send(
|
75
|
+
def _t_get_associate_ids(association)
|
76
|
+
self.send(association.foreign_keys_property)
|
87
77
|
end
|
88
78
|
|
89
|
-
def _t_clear_associates(
|
90
|
-
self.send(
|
79
|
+
def _t_clear_associates(association)
|
80
|
+
self.send(association.foreign_keys_property + '=', [])
|
91
81
|
end
|
92
82
|
end
|
93
83
|
end
|
data/lib/tenacity/version.rb
CHANGED
data/tenacity.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["John Wood"]
|
10
10
|
s.email = ["john@johnpwood.net"]
|
11
11
|
s.homepage = "http://github.com/jwood/tenacity"
|
12
|
-
s.summary = %Q{A
|
13
|
-
s.description = %Q{Tenacity provides
|
12
|
+
s.summary = %Q{A database client independent way of specifying simple relationships between models backed by different databases.}
|
13
|
+
s.description = %Q{Tenacity provides a database client independent way of specifying simple relationships between models backed by different databases.}
|
14
14
|
|
15
15
|
s.rubyforge_project = "tenacity"
|
16
16
|
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_development_dependency "mongo_mapper", "~> 0.8.6"
|
26
26
|
s.add_development_dependency "bson_ext", "~> 1.1.3"
|
27
27
|
s.add_development_dependency "activerecord", "~> 3.0.0"
|
28
|
-
s.add_development_dependency "
|
28
|
+
s.add_development_dependency "sqlite3-ruby", "~> 1.3.1"
|
29
29
|
s.add_development_dependency "couchrest", "~> 1.0.0"
|
30
30
|
s.add_development_dependency "couchrest_model"
|
31
31
|
|
@@ -20,6 +20,23 @@ class BelongsToTest < Test::Unit::TestCase
|
|
20
20
|
assert_equal @car, @wheel.active_record_car
|
21
21
|
assert_equal other_car, @wheel.active_record_car(true)
|
22
22
|
end
|
23
|
+
|
24
|
+
should "be able to specify the class name of the associated class" do
|
25
|
+
dashboard = MongoMapperDashboard.create
|
26
|
+
ash_tray = MongoMapperAshTray.create(:dashboard => dashboard)
|
27
|
+
assert_equal dashboard, ash_tray.dashboard
|
28
|
+
end
|
29
|
+
|
30
|
+
should "be able to specify the foreign key to use for the associated class" do
|
31
|
+
car = ActiveRecordCar.create
|
32
|
+
windshield = CouchRestWindshield.create(:active_record_car => car)
|
33
|
+
assert_equal car.id.to_s, windshield.car_id
|
34
|
+
assert !windshield.respond_to?(:active_record_car_id)
|
35
|
+
|
36
|
+
engine = ActiveRecordEngine.create(:active_record_car => car)
|
37
|
+
assert_equal car.id, engine.car_id
|
38
|
+
assert !engine.respond_to?(:active_record_car_id)
|
39
|
+
end
|
23
40
|
end
|
24
41
|
|
25
42
|
context "A MongoMapper class with belongs_to association to an ActiveRecord class" do
|
@@ -113,7 +130,6 @@ class BelongsToTest < Test::Unit::TestCase
|
|
113
130
|
should "return nil if no association is set" do
|
114
131
|
assert_nil CouchRestRadio.find(@radio.id).mongo_mapper_dashboard
|
115
132
|
end
|
116
|
-
|
117
133
|
end
|
118
134
|
|
119
135
|
end
|
@@ -23,6 +23,28 @@ class HasManyTest < Test::Unit::TestCase
|
|
23
23
|
assert_equal @wheels, @car.mongo_mapper_wheels
|
24
24
|
assert_equal other_wheels, @car.mongo_mapper_wheels(true)
|
25
25
|
end
|
26
|
+
|
27
|
+
should "be able to specify the class name of the associated class" do
|
28
|
+
vent_1 = MongoMapperVent.create
|
29
|
+
vent_2 = MongoMapperVent.create
|
30
|
+
vent_3 = MongoMapperVent.create
|
31
|
+
dashboard = MongoMapperDashboard.create
|
32
|
+
dashboard.vents = [vent_1, vent_2, vent_3]
|
33
|
+
dashboard.save
|
34
|
+
assert_set_equal [vent_1, vent_2, vent_3], MongoMapperDashboard.find(dashboard.id).vents
|
35
|
+
end
|
36
|
+
|
37
|
+
should "be able to specify the foreign key to use for the class" do
|
38
|
+
car = ActiveRecordCar.create
|
39
|
+
door_1 = CouchRestDoor.create({})
|
40
|
+
door_2 = CouchRestDoor.create({})
|
41
|
+
door_3 = CouchRestDoor.create({})
|
42
|
+
car.couch_rest_doors = [door_1, door_2, door_3]
|
43
|
+
car.save
|
44
|
+
|
45
|
+
assert_set_equal [door_1, door_2, door_3], ActiveRecordCar.find(car.id).couch_rest_doors
|
46
|
+
assert_set_equal [door_1.id.to_s, door_2.id.to_s, door_3.id.to_s], ActiveRecordCar.find(car.id).couch_rest_door_ids
|
47
|
+
end
|
26
48
|
end
|
27
49
|
|
28
50
|
context "An ActiveRecord class with a has_many association to a MongoMapper class" do
|
@@ -21,6 +21,21 @@ class HasOneTest < Test::Unit::TestCase
|
|
21
21
|
assert_equal @climate_control_unit, @dashboard.active_record_climate_control_unit
|
22
22
|
assert_equal other_climate_control_unit, @dashboard.active_record_climate_control_unit(true)
|
23
23
|
end
|
24
|
+
|
25
|
+
should "be able to specify the class name of the associated class" do
|
26
|
+
ash_tray = MongoMapperAshTray.create
|
27
|
+
dashboard = MongoMapperDashboard.create(:ash_tray => ash_tray)
|
28
|
+
assert_equal ash_tray, dashboard.ash_tray
|
29
|
+
end
|
30
|
+
|
31
|
+
should "be able to specify the foreign key to use for the class" do
|
32
|
+
car = ActiveRecordCar.create
|
33
|
+
windshield = CouchRestWindshield.create(:active_record_car => car)
|
34
|
+
assert_equal windshield, car.couch_rest_windshield
|
35
|
+
|
36
|
+
engine = ActiveRecordEngine.create(:active_record_car => car)
|
37
|
+
assert_equal engine, car.active_record_engine
|
38
|
+
end
|
24
39
|
end
|
25
40
|
|
26
41
|
context "A MongoMapper class with a has_one association to an ActiveRecord class" do
|
@@ -3,4 +3,8 @@ class ActiveRecordCar < ActiveRecord::Base
|
|
3
3
|
|
4
4
|
t_has_many :mongo_mapper_wheels
|
5
5
|
t_has_one :mongo_mapper_dashboard
|
6
|
+
|
7
|
+
t_has_one :couch_rest_windshield, :foreign_key => :car_id
|
8
|
+
t_has_one :active_record_engine, :foreign_key => 'car_id'
|
9
|
+
t_has_many :couch_rest_doors, :foreign_key => 'automobile_id'
|
6
10
|
end
|
@@ -7,4 +7,7 @@ class MongoMapperDashboard
|
|
7
7
|
t_belongs_to :active_record_car
|
8
8
|
t_has_one :active_record_climate_control_unit
|
9
9
|
t_has_one :couch_rest_radio
|
10
|
+
|
11
|
+
t_has_many :vents, :class_name => 'MongoMapperVent', :foreign_keys_property => 'dashboard_vent_ids'
|
12
|
+
t_has_one :ash_tray, :class_name => 'MongoMapperAshTray'
|
10
13
|
end
|
@@ -1,7 +1,37 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
3
|
ActiveRecord::Base.establish_connection(
|
4
|
-
:adapter =>
|
5
|
-
:
|
6
|
-
|
7
|
-
|
4
|
+
:adapter => 'sqlite3',
|
5
|
+
:database => ':memory:')
|
6
|
+
|
7
|
+
ActiveRecord::Schema.define :version => 0 do
|
8
|
+
create_table :active_record_cars, :force => true do |t|
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :active_record_engines, :force => true do |t|
|
12
|
+
t.integer :car_id
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :active_record_climate_control_units, :force => true do |t|
|
16
|
+
t.string :mongo_mapper_dashboard_id
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table :active_record_cars_mongo_mapper_wheels, :force => true do |t|
|
20
|
+
t.integer :active_record_car_id
|
21
|
+
t.string :mongo_mapper_wheel_id
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :active_record_cars_couch_rest_doors, :force => true do |t|
|
25
|
+
t.integer :active_record_car_id
|
26
|
+
t.string :couch_rest_door_id
|
27
|
+
end
|
28
|
+
|
29
|
+
create_table :active_record_nuts, :force => true do |t|
|
30
|
+
t.string :mongo_mapper_wheel_id
|
31
|
+
end
|
32
|
+
|
33
|
+
create_table :nuts_and_wheels, :force => true do |t|
|
34
|
+
t.integer :nut_id
|
35
|
+
t.string :mongo_mapper_wheel_id
|
36
|
+
end
|
37
|
+
end
|
@@ -56,30 +56,37 @@ class ActiveRecordTest < Test::Unit::TestCase
|
|
56
56
|
|
57
57
|
should "be able to clear the associates of a given object" do
|
58
58
|
nut = ActiveRecordNut.create
|
59
|
-
nut._t_associate_many(
|
59
|
+
nut._t_associate_many(association, ['abc123', 'def456', 'ghi789'])
|
60
60
|
nut.save
|
61
|
-
nut._t_clear_associates(
|
62
|
-
assert_set_equal [], nut._t_get_associate_ids(
|
61
|
+
nut._t_clear_associates(association)
|
62
|
+
assert_set_equal [], nut._t_get_associate_ids(association)
|
63
63
|
end
|
64
64
|
|
65
65
|
should "be able to associate many objects with the given object" do
|
66
66
|
nut = ActiveRecordNut.create
|
67
|
-
nut._t_associate_many(
|
68
|
-
rows = ActiveRecordNut.connection.execute("select mongo_mapper_wheel_id from
|
67
|
+
nut._t_associate_many(association, ['abc123', 'def456', 'ghi789'])
|
68
|
+
rows = ActiveRecordNut.connection.execute("select mongo_mapper_wheel_id from nuts_and_wheels where nut_id = #{nut.id}")
|
69
69
|
ids = []; rows.each { |r| ids << r[0] }; ids
|
70
70
|
assert_set_equal ['abc123', 'def456', 'ghi789'], ids
|
71
71
|
end
|
72
72
|
|
73
73
|
should "be able to get the ids of the objects associated with the given object" do
|
74
74
|
nut = ActiveRecordNut.create
|
75
|
-
nut._t_associate_many(
|
76
|
-
assert_set_equal ['abc123', 'def456', 'ghi789'], nut._t_get_associate_ids(
|
75
|
+
nut._t_associate_many(association, ['abc123', 'def456', 'ghi789'])
|
76
|
+
assert_set_equal ['abc123', 'def456', 'ghi789'], nut._t_get_associate_ids(association)
|
77
77
|
end
|
78
78
|
|
79
79
|
should "return an empty array if there are no objects associated with the given object ids" do
|
80
80
|
nut = ActiveRecordNut.create
|
81
|
-
assert_set_equal [], nut._t_get_associate_ids(
|
81
|
+
assert_set_equal [], nut._t_get_associate_ids(association)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
private
|
86
|
+
|
87
|
+
def association
|
88
|
+
Tenacity::Association.new(:t_has_many, :mongo_mapper_wheels, ActiveRecordNut, :join_table => :nuts_and_wheels,
|
89
|
+
:association_key => :nut_id)
|
90
|
+
end
|
91
|
+
|
85
92
|
end
|
@@ -62,7 +62,7 @@ class CouchRestTest < Test::Unit::TestCase
|
|
62
62
|
button_2 = MongoMapperButton.create
|
63
63
|
button_3 = MongoMapperButton.create
|
64
64
|
radio = CouchRestRadio.create({})
|
65
|
-
radio._t_associate_many(
|
65
|
+
radio._t_associate_many(association, [button_1.id, button_2.id, button_3.id])
|
66
66
|
assert_set_equal [button_1.id.to_s, button_2.id.to_s, button_3.id.to_s], radio.t_mongo_mapper_button_ids
|
67
67
|
end
|
68
68
|
|
@@ -71,13 +71,14 @@ class CouchRestTest < Test::Unit::TestCase
|
|
71
71
|
button_2 = MongoMapperButton.create
|
72
72
|
button_3 = MongoMapperButton.create
|
73
73
|
radio = CouchRestRadio.create({})
|
74
|
-
|
75
|
-
|
74
|
+
|
75
|
+
radio._t_associate_many(association, [button_1.id, button_2.id, button_3.id])
|
76
|
+
assert_set_equal [button_1.id.to_s, button_2.id.to_s, button_3.id.to_s], radio._t_get_associate_ids(association)
|
76
77
|
end
|
77
78
|
|
78
79
|
should "return an empty array when trying to fetch associate ids for an object with no associates" do
|
79
80
|
radio = CouchRestRadio.create({})
|
80
|
-
assert_equal [], radio._t_get_associate_ids(
|
81
|
+
assert_equal [], radio._t_get_associate_ids(association)
|
81
82
|
end
|
82
83
|
|
83
84
|
should "be able to clear the associates of an object" do
|
@@ -85,11 +86,17 @@ class CouchRestTest < Test::Unit::TestCase
|
|
85
86
|
button_2 = MongoMapperButton.create
|
86
87
|
button_3 = MongoMapperButton.create
|
87
88
|
radio = CouchRestRadio.create({})
|
88
|
-
|
89
|
-
|
90
|
-
radio.
|
91
|
-
|
89
|
+
|
90
|
+
radio._t_associate_many(association, [button_1.id, button_2.id, button_3.id])
|
91
|
+
assert_set_equal [button_1.id.to_s, button_2.id.to_s, button_3.id.to_s], radio._t_get_associate_ids(association)
|
92
|
+
radio._t_clear_associates(association)
|
93
|
+
assert_equal [], radio._t_get_associate_ids(association)
|
92
94
|
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
93
98
|
|
99
|
+
def association
|
100
|
+
Tenacity::Association.new(:t_has_many, :mongo_mapper_buttons, CouchRestRadio)
|
94
101
|
end
|
95
102
|
end
|
@@ -60,7 +60,7 @@ class MongoMapperTest < Test::Unit::TestCase
|
|
60
60
|
nut_2 = ActiveRecordNut.create
|
61
61
|
nut_3 = ActiveRecordNut.create
|
62
62
|
wheel = MongoMapperWheel.create
|
63
|
-
wheel._t_associate_many(
|
63
|
+
wheel._t_associate_many(association, [nut_1.id, nut_2.id, nut_3.id])
|
64
64
|
assert_set_equal [nut_1.id.to_s, nut_2.id.to_s, nut_3.id.to_s], wheel.t_active_record_nut_ids
|
65
65
|
end
|
66
66
|
|
@@ -69,13 +69,14 @@ class MongoMapperTest < Test::Unit::TestCase
|
|
69
69
|
nut_2 = ActiveRecordNut.create
|
70
70
|
nut_3 = ActiveRecordNut.create
|
71
71
|
wheel = MongoMapperWheel.create
|
72
|
-
|
73
|
-
|
72
|
+
|
73
|
+
wheel._t_associate_many(association, [nut_1.id, nut_2.id, nut_3.id])
|
74
|
+
assert_set_equal [nut_1.id.to_s, nut_2.id.to_s, nut_3.id.to_s], wheel._t_get_associate_ids(association)
|
74
75
|
end
|
75
76
|
|
76
77
|
should "return an empty array when trying to fetch associate ids for an object with no associates" do
|
77
78
|
wheel = MongoMapperWheel.create
|
78
|
-
assert_equal [], wheel._t_get_associate_ids(
|
79
|
+
assert_equal [], wheel._t_get_associate_ids(association)
|
79
80
|
end
|
80
81
|
|
81
82
|
should "be able to clear the associates of an object" do
|
@@ -83,11 +84,16 @@ class MongoMapperTest < Test::Unit::TestCase
|
|
83
84
|
nut_2 = ActiveRecordNut.create
|
84
85
|
nut_3 = ActiveRecordNut.create
|
85
86
|
wheel = MongoMapperWheel.create
|
86
|
-
|
87
|
-
|
88
|
-
wheel.
|
89
|
-
|
87
|
+
|
88
|
+
wheel._t_associate_many(association, [nut_1.id, nut_2.id, nut_3.id])
|
89
|
+
assert_set_equal [nut_1.id.to_s, nut_2.id.to_s, nut_3.id.to_s], wheel._t_get_associate_ids(association)
|
90
|
+
wheel._t_clear_associates(association)
|
91
|
+
assert_equal [], wheel._t_get_associate_ids(association)
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
95
|
+
def association
|
96
|
+
Tenacity::Association.new(:t_has_many, :active_record_nuts, MongoMapperWheel)
|
97
|
+
end
|
98
|
+
|
93
99
|
end
|
data/test/test_helper.rb
CHANGED
@@ -19,17 +19,20 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
19
19
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
20
20
|
require 'tenacity'
|
21
21
|
|
22
|
-
Dir[File.join(File.dirname(__FILE__), 'fixtures
|
22
|
+
Dir[File.join(File.dirname(__FILE__), 'fixtures', '*.rb')].each { |file| require file }
|
23
23
|
|
24
24
|
def setup_fixtures
|
25
25
|
ActiveRecordCar.delete_all
|
26
26
|
ActiveRecordClimateControlUnit.delete_all
|
27
|
+
ActiveRecordEngine.delete_all
|
28
|
+
ActiveRecordClimateControlUnit.delete_all
|
27
29
|
ActiveRecordNut.delete_all
|
28
30
|
MongoMapperDashboard.delete_all
|
29
31
|
MongoMapperWheel.delete_all
|
30
32
|
|
31
33
|
ActiveRecordCar.connection.execute("delete from active_record_cars_mongo_mapper_wheels")
|
32
|
-
ActiveRecordCar.connection.execute("delete from
|
34
|
+
ActiveRecordCar.connection.execute("delete from active_record_cars_couch_rest_doors")
|
35
|
+
ActiveRecordCar.connection.execute("delete from nuts_and_wheels")
|
33
36
|
end
|
34
37
|
|
35
38
|
def setup_couchdb_fixtures
|