inverse_of 0.0.1 → 0.1.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/CHANGELOG +8 -0
- data/LICENSE +1 -1
- data/Rakefile +1 -38
- data/lib/inverse_of.rb +220 -221
- data/lib/inverse_of/version.rb +11 -0
- metadata +88 -69
- data/.document +0 -5
- data/.gitignore +0 -21
- data/MIT-LICENSE +0 -20
- data/VERSION +0 -1
- data/install.rb +0 -1
- data/inverse_of.gemspec +0 -76
- data/rails/init.rb +0 -1
- data/tasks/inverse_of_tasks.rake +0 -4
- data/test/cases/helper.rb +0 -28
- data/test/cases/inverse_associations_test.rb +0 -567
- data/test/fixtures/clubs.yml +0 -6
- data/test/fixtures/faces.yml +0 -11
- data/test/fixtures/interests.yml +0 -33
- data/test/fixtures/men.yml +0 -5
- data/test/fixtures/sponsors.yml +0 -9
- data/test/fixtures/zines.yml +0 -5
- data/test/models/club.rb +0 -13
- data/test/models/face.rb +0 -7
- data/test/models/interest.rb +0 -5
- data/test/models/man.rb +0 -9
- data/test/models/sponsor.rb +0 -4
- data/test/models/zine.rb +0 -3
- data/test/schema/schema.rb +0 -32
- data/uninstall.rb +0 -1
data/CHANGELOG
ADDED
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,38 +1 @@
|
|
1
|
-
require '
|
2
|
-
require 'rake'
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "inverse_of"
|
8
|
-
gem.summary = "Backport of ActiveRecord 2.3.6's inverse associations."
|
9
|
-
gem.description = "Backport of ActiveRecord 2.3.6's inverse associations."
|
10
|
-
gem.email = "george.ogata@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/oggy/inverse_of"
|
12
|
-
gem.authors = ["George Ogata"]
|
13
|
-
end
|
14
|
-
Jeweler::GemcutterTasks.new
|
15
|
-
rescue LoadError
|
16
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
-
end
|
18
|
-
|
19
|
-
require 'rake/testtask'
|
20
|
-
|
21
|
-
desc "Run the test/unit tests for inverse associations, backported from ActiveRecord 2.3.6."
|
22
|
-
Rake::TestTask.new(:test => :check_dependencies) do |test|
|
23
|
-
test.libs << 'lib' << 'test'
|
24
|
-
test.pattern = 'test/**/*_test.rb'
|
25
|
-
test.verbose = true
|
26
|
-
end
|
27
|
-
|
28
|
-
task :default => :test
|
29
|
-
|
30
|
-
require 'rake/rdoctask'
|
31
|
-
Rake::RDocTask.new do |rdoc|
|
32
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
33
|
-
|
34
|
-
rdoc.rdoc_dir = 'rdoc'
|
35
|
-
rdoc.title = "inverse_of #{version}"
|
36
|
-
rdoc.rdoc_files.include('README*')
|
37
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
38
|
-
end
|
1
|
+
require 'ritual'
|
data/lib/inverse_of.rb
CHANGED
@@ -1,293 +1,292 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module InverseOf
|
2
|
+
class InverseOfAssociationNotFoundError < ActiveRecord::ActiveRecordError #:nodoc:
|
3
|
+
def initialize(reflection, associated_class = nil)
|
4
|
+
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Reflection
|
9
|
+
def self.included(base)
|
10
|
+
base::AssociationReflection.send :include, AssociationReflection
|
11
|
+
base::ThroughReflection.send :include, ThroughReflection
|
7
12
|
end
|
8
13
|
|
9
|
-
module
|
14
|
+
module AssociationReflection
|
10
15
|
def self.included(base)
|
11
|
-
base
|
12
|
-
base::ThroughReflection.send :include, ThroughReflection
|
16
|
+
base.alias_method_chain :check_validity!, :inverse_of
|
13
17
|
end
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def check_validity_with_inverse_of!
|
21
|
-
check_validity_of_inverse!
|
22
|
-
check_validity_without_inverse_of!
|
23
|
-
end
|
19
|
+
def check_validity_with_inverse_of!
|
20
|
+
check_validity_of_inverse!
|
21
|
+
check_validity_without_inverse_of!
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
24
|
+
def check_validity_of_inverse!
|
25
|
+
unless options[:polymorphic]
|
26
|
+
if has_inverse? && inverse_of.nil?
|
27
|
+
raise InverseOfAssociationNotFoundError.new(self)
|
30
28
|
end
|
31
29
|
end
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def has_inverse?
|
33
|
+
!@options[:inverse_of].nil?
|
34
|
+
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
36
|
+
def inverse_of
|
37
|
+
if has_inverse?
|
38
|
+
@inverse_of ||= klass.reflect_on_association(options[:inverse_of])
|
41
39
|
end
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
42
|
+
def polymorphic_inverse_of(associated_class)
|
43
|
+
if has_inverse?
|
44
|
+
if inverse_relationship = associated_class.reflect_on_association(options[:inverse_of])
|
45
|
+
inverse_relationship
|
46
|
+
else
|
47
|
+
raise InverseOfAssociationNotFoundError.new(self, associated_class)
|
50
48
|
end
|
51
49
|
end
|
52
50
|
end
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
module ThroughReflection
|
54
|
+
def self.included(base)
|
55
|
+
base.alias_method_chain :check_validity!, :inverse_of
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
58
|
+
def check_validity_with_inverse_of!
|
59
|
+
check_validity_of_inverse!
|
60
|
+
check_validity_without_inverse_of!
|
63
61
|
end
|
64
62
|
end
|
63
|
+
end
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
def find_target_with_inverse_of
|
74
|
-
records = find_target_without_inverse_of
|
75
|
-
records.each do |record|
|
76
|
-
set_inverse_instance(record, @owner)
|
77
|
-
end
|
78
|
-
records
|
79
|
-
end
|
65
|
+
module Associations
|
66
|
+
module AssociationCollection
|
67
|
+
def self.included(base)
|
68
|
+
base.alias_method_chain :find_target, :inverse_of
|
69
|
+
base.alias_method_chain :add_record_to_target_with_callbacks, :inverse_of
|
70
|
+
end
|
80
71
|
|
81
|
-
|
82
|
-
|
72
|
+
def find_target_with_inverse_of
|
73
|
+
records = find_target_without_inverse_of
|
74
|
+
records.each do |record|
|
83
75
|
set_inverse_instance(record, @owner)
|
84
|
-
record
|
85
76
|
end
|
77
|
+
records
|
86
78
|
end
|
87
79
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
80
|
+
def add_record_to_target_with_callbacks_with_inverse_of(record, &block)
|
81
|
+
record = add_record_to_target_with_callbacks_without_inverse_of(record, &block)
|
82
|
+
set_inverse_instance(record, @owner)
|
83
|
+
record
|
84
|
+
end
|
85
|
+
end
|
92
86
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
87
|
+
module AssociationProxy
|
88
|
+
def self.included(base)
|
89
|
+
base.alias_method_chain :initialize, :inverse_of
|
90
|
+
end
|
97
91
|
|
98
|
-
|
92
|
+
def initialize_with_inverse_of(owner, reflection)
|
93
|
+
reflection.check_validity!
|
94
|
+
initialize_without_inverse_of(owner, reflection)
|
95
|
+
end
|
99
96
|
|
100
|
-
|
101
|
-
return if record.nil? || !we_can_set_the_inverse_on_this?(record)
|
102
|
-
inverse_relationship = @reflection.inverse_of
|
103
|
-
unless inverse_relationship.nil?
|
104
|
-
record.send(:"set_#{inverse_relationship.name}_target", instance)
|
105
|
-
end
|
106
|
-
end
|
97
|
+
private
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
99
|
+
def set_inverse_instance(record, instance)
|
100
|
+
return if record.nil? || !we_can_set_the_inverse_on_this?(record)
|
101
|
+
inverse_relationship = @reflection.inverse_of
|
102
|
+
unless inverse_relationship.nil?
|
103
|
+
record.send(:"set_#{inverse_relationship.name}_target", instance)
|
111
104
|
end
|
112
105
|
end
|
113
106
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
107
|
+
# Override in subclasses
|
108
|
+
def we_can_set_the_inverse_on_this?(record)
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
119
112
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
113
|
+
module BelongsToAssociation
|
114
|
+
def self.included(base)
|
115
|
+
base.alias_method_chain :replace, :inverse_of
|
116
|
+
base.alias_method_chain :find_target, :inverse_of
|
117
|
+
end
|
125
118
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
119
|
+
def replace_with_inverse_of(record)
|
120
|
+
replace_without_inverse_of(record)
|
121
|
+
set_inverse_instance(record, @owner)
|
122
|
+
record
|
123
|
+
end
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
125
|
+
def find_target_with_inverse_of
|
126
|
+
target = find_target_without_inverse_of and
|
127
|
+
set_inverse_instance(target, @owner)
|
128
|
+
target
|
137
129
|
end
|
138
130
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
131
|
+
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
|
132
|
+
# has_one associations.
|
133
|
+
def we_can_set_the_inverse_on_this?(record)
|
134
|
+
@reflection.has_inverse? && @reflection.inverse_of.macro == :has_one
|
135
|
+
end
|
136
|
+
end
|
144
137
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
138
|
+
module BelongsToPolymorphicAssociation
|
139
|
+
def self.included(base)
|
140
|
+
base.alias_method_chain :replace, :inverse_of
|
141
|
+
base.alias_method_chain :find_target, :inverse_of
|
142
|
+
end
|
150
143
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
144
|
+
def replace_with_inverse_of(record)
|
145
|
+
replace_without_inverse_of(record)
|
146
|
+
set_inverse_instance(record, @owner)
|
147
|
+
record
|
148
|
+
end
|
156
149
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
inverse_association && inverse_association.macro == :has_one
|
163
|
-
else
|
164
|
-
false
|
165
|
-
end
|
166
|
-
end
|
150
|
+
def find_target_with_inverse_of
|
151
|
+
target = find_target_without_inverse_of
|
152
|
+
set_inverse_instance(target, @owner)
|
153
|
+
target
|
154
|
+
end
|
167
155
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
156
|
+
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
|
157
|
+
# has_one associations.
|
158
|
+
def we_can_set_the_inverse_on_this?(record)
|
159
|
+
if @reflection.has_inverse?
|
160
|
+
inverse_association = @reflection.polymorphic_inverse_of(record.class)
|
161
|
+
inverse_association && inverse_association.macro == :has_one
|
162
|
+
else
|
163
|
+
false
|
174
164
|
end
|
175
165
|
end
|
176
166
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
167
|
+
def set_inverse_instance(record, instance)
|
168
|
+
return if record.nil? || !we_can_set_the_inverse_on_this?(record)
|
169
|
+
inverse_relationship = @reflection.polymorphic_inverse_of(record.class)
|
170
|
+
unless inverse_relationship.nil?
|
171
|
+
record.send(:"set_#{inverse_relationship.name}_target", instance)
|
181
172
|
end
|
182
173
|
end
|
174
|
+
end
|
183
175
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
176
|
+
module HasManyAssociation
|
177
|
+
def we_can_set_the_inverse_on_this?(record)
|
178
|
+
inverse = @reflection.inverse_of
|
179
|
+
return !inverse.nil?
|
180
|
+
end
|
181
|
+
end
|
188
182
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
183
|
+
module HasManyThroughAssociation
|
184
|
+
def initialize(owner, reflection)
|
185
|
+
super
|
193
186
|
end
|
194
187
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
end
|
188
|
+
# NOTE - not sure that we can actually cope with inverses here
|
189
|
+
def we_can_set_the_inverse_on_this?(record)
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
201
193
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
194
|
+
module HasOneAssociation
|
195
|
+
def self.included(base)
|
196
|
+
base.alias_method_chain :find_target, :inverse_of
|
197
|
+
base.alias_method_chain :new_record, :inverse_of
|
198
|
+
base.alias_method_chain :replace, :inverse_of
|
199
|
+
end
|
207
200
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
201
|
+
def find_target_with_inverse_of
|
202
|
+
target = find_target_without_inverse_of
|
203
|
+
set_inverse_instance(target, @owner)
|
204
|
+
target
|
205
|
+
end
|
213
206
|
|
214
|
-
|
207
|
+
def replace_with_inverse_of(record, dont_save = false)
|
208
|
+
value = replace_without_inverse_of(record, dont_save)
|
209
|
+
set_inverse_instance(record, @owner)
|
210
|
+
value
|
211
|
+
end
|
215
212
|
|
216
|
-
|
217
|
-
record = new_record_without_inverse_of(replace_existing, &block)
|
218
|
-
set_inverse_instance(record, @owner) unless replace_existing
|
219
|
-
record
|
220
|
-
end
|
213
|
+
private
|
221
214
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
215
|
+
def new_record_with_inverse_of(replace_existing, &block)
|
216
|
+
record = new_record_without_inverse_of(replace_existing, &block)
|
217
|
+
set_inverse_instance(record, @owner) unless replace_existing
|
218
|
+
record
|
226
219
|
end
|
227
220
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
221
|
+
def we_can_set_the_inverse_on_this?(record)
|
222
|
+
inverse = @reflection.inverse_of
|
223
|
+
return !inverse.nil?
|
224
|
+
end
|
225
|
+
end
|
233
226
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
227
|
+
module ClassMethods
|
228
|
+
module JoinDependency
|
229
|
+
def self.included(base)
|
230
|
+
base.alias_method_chain :construct_association, :inverse_of
|
231
|
+
end
|
232
|
+
|
233
|
+
def construct_association_with_inverse_of(record, join, row)
|
234
|
+
association = construct_association_without_inverse_of(record, join, row) or
|
235
|
+
return nil
|
236
|
+
association_proxy = record.send(join.reflection.name)
|
237
|
+
association_proxy.__send__(:set_inverse_instance, association, record)
|
238
|
+
return association
|
240
239
|
end
|
241
240
|
end
|
242
241
|
end
|
242
|
+
end
|
243
243
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
244
|
+
module AssociationPreload
|
245
|
+
def self.included(base)
|
246
|
+
base.extend ClassMethods
|
247
|
+
base.metaclass.alias_method_chain :add_preloaded_records_to_collection, :inverse_of
|
248
|
+
base.metaclass.alias_method_chain :set_association_single_records, :inverse_of
|
249
|
+
end
|
250
250
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
end
|
258
|
-
value
|
251
|
+
module ClassMethods
|
252
|
+
def add_preloaded_records_to_collection_with_inverse_of(parent_records, reflection_name, associated_record)
|
253
|
+
value = add_preloaded_records_to_collection_without_inverse_of(parent_records, reflection_name, associated_record)
|
254
|
+
parent_records.each do |parent_record|
|
255
|
+
association_proxy = parent_record.send(reflection_name)
|
256
|
+
association_proxy.__send__(:set_inverse_instance, associated_record, parent_record)
|
259
257
|
end
|
258
|
+
value
|
259
|
+
end
|
260
260
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
261
|
+
def set_association_single_records_with_inverse_of(id_to_record_map, reflection_name, associated_records, key)
|
262
|
+
value = set_association_single_records_without_inverse_of(id_to_record_map, reflection_name, associated_records, key)
|
263
|
+
associated_records.each do |associated_record|
|
264
|
+
mapped_records = id_to_record_map[associated_record[key].to_s]
|
265
|
+
mapped_records.each do |mapped_record|
|
266
|
+
association_proxy = mapped_record.send(reflection_name)
|
267
|
+
association_proxy.__send__(:set_inverse_instance, associated_record, mapped_record)
|
269
268
|
end
|
270
|
-
value
|
271
269
|
end
|
270
|
+
value
|
272
271
|
end
|
273
272
|
end
|
274
273
|
end
|
274
|
+
end
|
275
275
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
276
|
+
ActiveRecord::InverseOfAssociationNotFoundError = InverseOf::InverseOfAssociationNotFoundError
|
277
|
+
ActiveRecord::Associations::AssociationCollection.send :include, InverseOf::Associations::AssociationCollection
|
278
|
+
ActiveRecord::Associations::AssociationProxy.send :include, InverseOf::Associations::AssociationProxy
|
279
|
+
ActiveRecord::Associations::BelongsToAssociation.send :include, InverseOf::Associations::BelongsToAssociation
|
280
|
+
ActiveRecord::Associations::BelongsToPolymorphicAssociation.send :include, InverseOf::Associations::BelongsToPolymorphicAssociation
|
281
|
+
ActiveRecord::Associations::HasManyAssociation.send :include, InverseOf::Associations::HasManyAssociation
|
282
|
+
ActiveRecord::Associations::HasManyThroughAssociation.send :include, InverseOf::Associations::HasManyThroughAssociation
|
283
|
+
ActiveRecord::Associations::HasOneAssociation.send :include, InverseOf::Associations::HasOneAssociation
|
284
|
+
ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, InverseOf::Associations::ClassMethods::JoinDependency
|
285
|
+
ActiveRecord::Reflection.send :include, InverseOf::Reflection
|
286
|
+
ActiveRecord::Base.send :include, InverseOf::AssociationPreload
|
287
|
+
|
288
|
+
module ActiveRecord::Associations::ClassMethods
|
289
|
+
@@valid_keys_for_has_many_association << :inverse_of
|
290
|
+
@@valid_keys_for_has_one_association << :inverse_of
|
291
|
+
@@valid_keys_for_belongs_to_association << :inverse_of
|
293
292
|
end
|