-
Notifications
You must be signed in to change notification settings - Fork 2
/
has_many.rb
158 lines (137 loc) · 3.56 KB
/
has_many.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
module RDFMapper
module Associations
##
# [-]
##
class HasMany < Base
##
# Replaces the collections content by deleting and adding
# objects as appropriate.
##
def replace(objects)
unless objects.kind_of? Array
objects = [objects]
end
new_objects = filter(objects)
return self if new_objects.empty?
new_objects.each do |child|
self << child
end
@value ||= []
@value.each do |child|
delete(child) unless new_objects.include?(child)
end
self
end
##
# Adds one or more objects to the collection by setting their
# foreign keys to the collection's primary key.
##
def <<(*objects)
objects.to_a.select do |child|
child.kind_of? RDFMapper::Model
end.each do |child|
unless include?(child)
child[reverse] = @instance
@value << child
end
end
self
end
alias_method :push, :<<
##
# Removes one or more objects from the collection by removing
# the association between objects
##
def delete(*objects)
objects.each do |child|
if include?(child)
child[reverse] = nil
@value.delete(child)
end
end
self
end
##
# Removes every object from the collection.
##
def clear
delete(@value)
end
##
# Finds an associated object according to the same rules as
# RDFMapper::Model.find.
##
def find
raise NotImplementedError, '`find` not yet implemented' # TODO
end
##
# Returns one or more new objects of the collection type that
# have been instantiated with attributes and linked to this object
# through a foreign key, but have not yet been saved.
##
def build
raise NotImplementedError, '`build` not yet implemented' # TODO
end
##
# Returns a new object of the collection type that has been
# instantiated with attributes, linked to this object through
# a foreign key, and that has already been saved.
##
def create
raise NotImplementedError, '`create` not yet implemented' # TODO
end
##
# Returns true if a given object is present in the collection
##
def include?(object)
@value ||= []
@value.include?(object)
end
##
# [-]
##
def to_a
value
end
##
# [-]
##
def kind_of?(cls)
cls == self.class || cls == Enumerable || cls == Array
end
private
def filter(objects)
objects.select do |child|
child.kind_of? RDFMapper::Model
end
end
##
# [-]
##
def value
unless @value.nil?
return @value
end
if @instance.id.nil?
return []
end
replace @association.find(:all, {
:conditions => { reverse => @instance },
:skip => [reverse]
})
end
##
# [-]
##
def reverse
@reverse ||= @association.has?(nil, @instance)
if @reverse.nil?
raise RuntimeError, 'Expected %s to belong to %s' % [@association, @instance.class]
else
@reverse.name
end
end
end # HasMany
end # Associations
end # RDFMapper