genealogy 1.5.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/lib/genealogy.rb +4 -2
- data/lib/genealogy/alter_methods.rb +173 -112
- data/lib/genealogy/constants.rb +52 -21
- data/lib/genealogy/current_spouse_methods.rb +66 -0
- data/lib/genealogy/exceptions.rb +5 -8
- data/lib/genealogy/genealogy.rb +100 -63
- data/lib/genealogy/ineligible_methods.rb +116 -0
- data/lib/genealogy/query_methods.rb +194 -236
- data/lib/genealogy/util_methods.rb +180 -0
- data/lib/genealogy/version.rb +1 -1
- metadata +103 -30
- data/lib/genealogy/spouse_methods.rb +0 -53
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZTU5ZWM1OWI2NWE5MDc1MmNlOTM1MDhlMzg3YTFmN2YxZjJkNTIyZA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f135505bdbf0d836cdac669c1ee684c8959cedce
|
4
|
+
data.tar.gz: d90f6befee994c37e2a900d7c85e37e0c7f3229c
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MGI5NmYwZGE1OTNlY2JhNDU0YzM2ZGUzMjNhMmU3YWFkODZjMzcwZmQwNWMz
|
11
|
-
YTM4MmEwN2ZmZDJmNmQ5OGMxMGFlMmJhYmMzYTM5YjMwNzIxNWU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NDljNjIxODUzMDBmZjgxNzk5Y2RlMTk0ZWI3NTMxYTM3MDcxNjMwMjQxY2Qx
|
14
|
-
M2IxZDNiNzg5MDJlMDFhZWEzYjY2ZWY2MDc3ZmJmZWM4MjZjODU3YTkxYTJm
|
15
|
-
ZGU5ZDNmM2MwOWExY2E5YzgxZWYwMTlhM2M4OTllYjlmMTdkNGU=
|
6
|
+
metadata.gz: f1efa40c2b50b47caad8d4608157195d0a0d68f1659c08c1eb44d31381d61ec8bb738c61ada1369de74baad8f4c693aa3f0d54dd624c354897b7349eb2d0f081
|
7
|
+
data.tar.gz: 443d273ad5240f9a5ecad5c902f8535a421f7c3f46e5d37b5a8c363c42713c582ca498dc582748f13fd89cb64c26ee7fd616d3de332d5f0c790528706ee95554
|
data/lib/genealogy.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/constants')
|
2
2
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/exceptions')
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/util_methods')
|
4
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/ineligible_methods')
|
3
5
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/query_methods')
|
4
6
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/alter_methods')
|
5
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/
|
7
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/current_spouse_methods')
|
6
8
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'genealogy/genealogy')
|
7
9
|
|
8
|
-
ActiveRecord::Base.send :
|
10
|
+
ActiveRecord::Base.send :include, Genealogy
|
9
11
|
|
@@ -1,39 +1,54 @@
|
|
1
1
|
module Genealogy
|
2
|
+
# Module AlterMethods provides methods to alter genealogy. It's included by the genealogy enabled AR model
|
2
3
|
module AlterMethods
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
|
-
|
6
|
-
[:father, :mother].each do |parent|
|
6
|
+
include Constants
|
7
7
|
|
8
|
-
|
8
|
+
# @!macro [attach] generate
|
9
|
+
# @method add_$1(parent)
|
10
|
+
# Add $1
|
11
|
+
# @param [Object] parent
|
12
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
13
|
+
# @return [Boolean]
|
14
|
+
def self.generate_method_add_parent(parent)
|
9
15
|
define_method "add_#{parent}" do |relative|
|
10
|
-
|
11
|
-
|
12
|
-
incompatible_parents = self.offspring | self.siblings | [self]
|
13
|
-
raise IncompatibleRelationshipException, "#{relative} can't be #{parent} of #{self}" if incompatible_parents.include? relative
|
14
|
-
raise WrongSexException, "Can't add a #{relative.sex} #{parent}" unless (parent == :father and relative.is_male?) or (parent == :mother and relative.is_female?)
|
15
|
-
end
|
16
|
-
if perform_validation
|
16
|
+
check_incompatible_relationship(parent,relative)
|
17
|
+
if gclass.perform_validation_enabled
|
17
18
|
self.send("#{parent}=",relative)
|
18
19
|
save!
|
19
20
|
else
|
20
21
|
self.update_attribute(parent,relative)
|
21
22
|
end
|
22
23
|
end
|
23
|
-
|
24
|
-
|
24
|
+
end
|
25
|
+
generate_method_add_parent(:father)
|
26
|
+
generate_method_add_parent(:mother)
|
27
|
+
|
28
|
+
# @!macro [attach] generate
|
29
|
+
# @method remove_$1
|
30
|
+
# remove $1. Foreign_key set to nil
|
31
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
32
|
+
# @return [Boolean]
|
33
|
+
def self.generate_method_remove_parent(parent)
|
25
34
|
define_method "remove_#{parent}" do
|
26
|
-
if
|
35
|
+
if gclass.perform_validation_enabled
|
27
36
|
self.send("#{parent}=",nil)
|
28
37
|
save!
|
29
38
|
else
|
30
39
|
self.update_attribute(parent,nil)
|
31
40
|
end
|
32
41
|
end
|
33
|
-
|
34
42
|
end
|
35
|
-
|
36
|
-
|
43
|
+
generate_method_remove_parent(:father)
|
44
|
+
generate_method_remove_parent(:mother)
|
45
|
+
|
46
|
+
# add both parents calling #add_father and #add_mother in a transaction
|
47
|
+
# @param [Object] father
|
48
|
+
# @param [Object] mother
|
49
|
+
# @see #add_father
|
50
|
+
# @see #add_mother
|
51
|
+
# @return [Boolean]
|
37
52
|
def add_parents(father,mother)
|
38
53
|
transaction do
|
39
54
|
add_father(father)
|
@@ -41,7 +56,10 @@ module Genealogy
|
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
44
|
-
# remove both
|
59
|
+
# remove both parents calling #remove_father and #remove_mother in a transaction
|
60
|
+
# @see #remove_father
|
61
|
+
# @see #remove_mother
|
62
|
+
# @return [Boolean]
|
45
63
|
def remove_parents
|
46
64
|
transaction do
|
47
65
|
remove_father
|
@@ -49,37 +67,87 @@ module Genealogy
|
|
49
67
|
end
|
50
68
|
end
|
51
69
|
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
70
|
+
# @!macro [attach] generate
|
71
|
+
# @method add_$1_grand$2(grandparent)
|
72
|
+
# Add $1 grand$2
|
73
|
+
# @param [Object] gp grandparent
|
74
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
75
|
+
# @return [Boolean]
|
76
|
+
def self.generate_method_add_grandparent(lineage,grandparent)
|
77
|
+
relationship = "#{lineage}_grand#{grandparent}"
|
78
|
+
define_method "add_#{relationship}" do |gp|
|
79
|
+
parent = LINEAGE2PARENT[lineage]
|
80
|
+
raise_if_gap_on(parent)
|
81
|
+
check_incompatible_relationship(relationship,gp)
|
82
|
+
send(parent).send("add_#{grandparent}",gp)
|
66
83
|
end
|
67
84
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
85
|
+
generate_method_add_grandparent(:paternal,:father)
|
86
|
+
generate_method_add_grandparent(:paternal,:mother)
|
87
|
+
generate_method_add_grandparent(:maternal,:father)
|
88
|
+
generate_method_add_grandparent(:maternal,:mother)
|
89
|
+
|
90
|
+
# @!macro [attach] generate
|
91
|
+
# @method remove_$1_grand$2
|
92
|
+
# remove $1 grand$2
|
93
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
94
|
+
# @return [Boolean]
|
95
|
+
def self.generate_method_remove_grandparent(lineage,grandparent)
|
96
|
+
relationship = "#{lineage}_grand#{grandparent}"
|
97
|
+
define_method "remove_#{relationship}" do
|
98
|
+
parent = LINEAGE2PARENT[lineage]
|
72
99
|
raise_if_gap_on(parent)
|
73
|
-
send(parent).send("
|
100
|
+
send(parent).send("remove_#{grandparent}")
|
74
101
|
end
|
75
|
-
|
76
|
-
|
102
|
+
end
|
103
|
+
generate_method_remove_grandparent(:paternal,:father)
|
104
|
+
generate_method_remove_grandparent(:paternal,:mother)
|
105
|
+
generate_method_remove_grandparent(:maternal,:father)
|
106
|
+
generate_method_remove_grandparent(:maternal,:mother)
|
107
|
+
|
108
|
+
# @!macro [attach] generate
|
109
|
+
# @method add_$1_grandparents
|
110
|
+
# Add $1 grandparents
|
111
|
+
# @param [Object] gf grandfather
|
112
|
+
# @param [Object] gm grandmother
|
113
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
114
|
+
# @return [Boolean]
|
115
|
+
def self.generate_method_add_grandparents_by_lineage(lineage)
|
116
|
+
relationship = "#{lineage}_grandparents"
|
117
|
+
define_method "add_#{relationship}" do |gf,gm|
|
118
|
+
parent = LINEAGE2PARENT[lineage]
|
119
|
+
raise_if_gap_on(parent)
|
120
|
+
send(parent).send("add_parents",gf,gm)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
generate_method_add_grandparents_by_lineage(:paternal)
|
124
|
+
generate_method_add_grandparents_by_lineage(:maternal)
|
125
|
+
|
126
|
+
# @!macro [attach] generate
|
127
|
+
# @method remove_$1_grandparents
|
128
|
+
# remove $1 grandparents
|
129
|
+
# @raise [Exception] if perform validation is enabled and self is invalid
|
130
|
+
# @return [Boolean]
|
131
|
+
def self.generate_method_remove_grandparents_by_lineage(lineage)
|
132
|
+
relationship = "#{lineage}_grandparents"
|
133
|
+
define_method "remove_#{relationship}" do
|
134
|
+
parent = LINEAGE2PARENT[lineage]
|
77
135
|
raise_if_gap_on(parent)
|
78
136
|
send(parent).send("remove_parents")
|
79
137
|
end
|
80
138
|
end
|
81
|
-
|
82
|
-
|
139
|
+
generate_method_remove_grandparents_by_lineage(:paternal)
|
140
|
+
generate_method_remove_grandparents_by_lineage(:maternal)
|
141
|
+
|
142
|
+
|
143
|
+
# add all grandparents calling #add_paternal_grandparents and #add_maternal_grandparents in a transaction
|
144
|
+
# @param [Object] pgf paternal grandfather
|
145
|
+
# @param [Object] pgm paternal grandmother
|
146
|
+
# @param [Object] mgf maternal grandfather
|
147
|
+
# @param [Object] mgm maternal grandmother
|
148
|
+
# @see #add_paternal_grandparents
|
149
|
+
# @see #add_maternal_grandparents
|
150
|
+
# @return [Boolean]
|
83
151
|
def add_grandparents(pgf,pgm,mgf,mgm)
|
84
152
|
transaction do
|
85
153
|
add_paternal_grandparents(pgf,pgm)
|
@@ -87,160 +155,152 @@ module Genealogy
|
|
87
155
|
end
|
88
156
|
end
|
89
157
|
|
90
|
-
# remove all
|
91
|
-
|
158
|
+
# remove all grandparents calling #remove_paternal_grandparents and #remove_maternal_grandparents in a transaction
|
159
|
+
# @see #remove_paternal_grandparents
|
160
|
+
# @see #remove_maternal_grandparents
|
161
|
+
# @return [Boolean]
|
162
|
+
def remove_grandparents
|
92
163
|
transaction do
|
93
164
|
remove_paternal_grandparents
|
94
165
|
remove_maternal_grandparents
|
95
166
|
end
|
96
167
|
end
|
97
168
|
|
98
|
-
|
169
|
+
# add siblings by assigning same parents to individuals passed as arguments
|
170
|
+
# @overload add_siblings(*siblings,options={})
|
171
|
+
# @param [Object] siblings list of siblings
|
172
|
+
# @param [Hash] options
|
173
|
+
# @option options [Symbol] half :father for paternal half siblings and :mother for maternal half siblings
|
174
|
+
# @option options [Object] spouse if specified, passed individual will be used as mother in case of half sibling
|
175
|
+
# @return [Boolean]
|
99
176
|
def add_siblings(*args)
|
100
177
|
options = args.extract_options!
|
101
|
-
|
178
|
+
check_incompatible_relationship(:sibling, *args)
|
102
179
|
transaction do
|
103
180
|
args.inject(true) do |res,sib|
|
104
181
|
res &= case options[:half]
|
105
182
|
when :father
|
106
183
|
raise LineageGapException, "Can't add paternal halfsiblings without a father" unless father
|
107
|
-
sib.add_father(self.father)
|
108
184
|
sib.add_mother(options[:spouse]) if options[:spouse]
|
185
|
+
sib.add_father(father)
|
109
186
|
when :mother
|
110
187
|
raise LineageGapException, "Can't add maternal halfsiblings without a mother" unless mother
|
111
188
|
sib.add_father(options[:spouse]) if options[:spouse]
|
112
|
-
sib.add_mother(
|
189
|
+
sib.add_mother(mother)
|
113
190
|
when nil
|
114
191
|
raise LineageGapException, "Can't add siblings without parents" unless father and mother
|
115
|
-
sib.add_father(
|
116
|
-
sib.add_mother(
|
192
|
+
sib.add_father(father)
|
193
|
+
sib.add_mother(mother)
|
117
194
|
else
|
118
|
-
raise
|
195
|
+
raise ArgumentError, "Admitted values for :half options are: :father, :mother or nil"
|
119
196
|
end
|
120
197
|
end
|
121
198
|
end
|
122
199
|
end
|
123
200
|
|
124
|
-
|
125
|
-
|
201
|
+
# @see #add_siblings
|
202
|
+
def add_sibling(sibling,options={})
|
203
|
+
add_siblings(sibling,options)
|
126
204
|
end
|
127
205
|
|
206
|
+
|
207
|
+
# remove siblings by nullifying parents of passed individuals
|
208
|
+
# @overload remove_siblings(*siblings,options={})
|
209
|
+
# @param [Object] siblings list of siblings
|
210
|
+
# @param [Hash] options
|
211
|
+
# @option options [Symbol] half :father for paternal half siblings and :mother for maternal half siblings
|
212
|
+
# @option options [Boolean] remove_other_parent if specified, passed individuals' mother will also be nullified
|
213
|
+
# @return [Boolean] true if at least one sibling was affected, false otherwise
|
128
214
|
def remove_siblings(*args)
|
129
215
|
options = args.extract_options!
|
130
|
-
|
131
|
-
raise WrongOptionException.new("Unknown option value: :half => #{options[:half]}.") if (options[:half] and ![:father,:mother].include?(options[:half]))
|
132
|
-
|
216
|
+
raise ArgumentError.new("Unknown option value: half: #{options[:half]}.") if (options[:half] and ![:father,:mother].include?(options[:half]))
|
133
217
|
resulting_indivs = if args.blank?
|
134
218
|
siblings(options)
|
135
219
|
else
|
136
220
|
args & siblings(options)
|
137
221
|
end
|
138
|
-
|
139
222
|
transaction do
|
140
|
-
|
141
223
|
resulting_indivs.each do |sib|
|
142
224
|
case options[:half]
|
143
225
|
when :father
|
144
226
|
sib.remove_father
|
145
|
-
sib.remove_mother if options[:
|
227
|
+
sib.remove_mother if options[:remove_other_parent] == true
|
146
228
|
when :mother
|
147
|
-
sib.remove_father if options[:
|
229
|
+
sib.remove_father if options[:remove_other_parent] == true
|
148
230
|
sib.remove_mother
|
149
231
|
when nil
|
150
232
|
sib.remove_parents
|
151
233
|
end
|
152
234
|
end
|
153
|
-
|
154
235
|
end
|
155
|
-
|
156
236
|
!resulting_indivs.empty? #returned value must be true if self has at least a siblings to affect
|
157
|
-
|
158
237
|
end
|
159
238
|
|
239
|
+
# @see #remove_siblings
|
160
240
|
def remove_sibling(sib,options={})
|
161
241
|
remove_siblings(sib,options)
|
162
242
|
end
|
163
243
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
send("add_siblings",*args)
|
172
|
-
end
|
173
|
-
|
174
|
-
# add paternal/maternal half_sibling
|
175
|
-
define_method "add_#{Genealogy::PARENT2LINEAGE[parent]}_half_sibling" do | sib,options={} |
|
176
|
-
options[:half] = parent
|
177
|
-
send("add_sibling",sib,options)
|
178
|
-
end
|
179
|
-
|
180
|
-
# remove paternal/maternal half_siblings
|
181
|
-
define_method "remove_#{Genealogy::PARENT2LINEAGE[parent]}_half_siblings" do | *args |
|
182
|
-
options = args.extract_options!
|
183
|
-
options[:half] = parent
|
184
|
-
args << options
|
185
|
-
send("remove_siblings",*args)
|
186
|
-
end
|
187
|
-
|
188
|
-
# remove paternal/maternal half_sibling
|
189
|
-
define_method "remove_#{Genealogy::PARENT2LINEAGE[parent]}_half_sibling" do | sib,options={} |
|
190
|
-
options[:half] = parent
|
191
|
-
send("remove_sibling",sib,options)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# offspring
|
196
|
-
def add_offspring(*args)
|
244
|
+
# add children by assigning self as parent
|
245
|
+
# @overload add_children(*children,options={})
|
246
|
+
# @param [Object] children list of children
|
247
|
+
# @param [Hash] options
|
248
|
+
# @option options [Object] spouse if specified, children will have that spouse
|
249
|
+
# @return [Boolean]
|
250
|
+
def add_children(*args)
|
197
251
|
options = args.extract_options!
|
198
|
-
|
199
252
|
raise_if_sex_undefined
|
200
|
-
|
253
|
+
check_incompatible_relationship(:children, *args)
|
201
254
|
transaction do
|
202
|
-
args.
|
203
|
-
case sex
|
204
|
-
when sex_male_value
|
205
|
-
child.add_father(self)
|
255
|
+
args.inject(true) do |res,child|
|
256
|
+
res &= case sex
|
257
|
+
when gclass.sex_male_value
|
206
258
|
child.add_mother(options[:spouse]) if options[:spouse]
|
207
|
-
|
259
|
+
child.add_father(self)
|
260
|
+
when gclass.sex_female_value
|
208
261
|
child.add_father(options[:spouse]) if options[:spouse]
|
209
262
|
child.add_mother(self)
|
210
263
|
else
|
211
|
-
raise
|
264
|
+
raise SexError, "Sex value not valid for #{self}"
|
212
265
|
end
|
213
266
|
end
|
214
267
|
end
|
215
268
|
end
|
216
269
|
|
270
|
+
# see #add_children
|
217
271
|
def add_child(child,options={})
|
218
|
-
|
272
|
+
add_children(child,options)
|
219
273
|
end
|
220
274
|
|
221
|
-
|
275
|
+
# remove children by nullifying the parent corresponding to self
|
276
|
+
# @overload remove_children(*children,options={})
|
277
|
+
# @param [Object] children list of children
|
278
|
+
# @param [Hash] options
|
279
|
+
# @option options [Boolean] remove_other_parent if specified, passed individuals' mother will also be nullified
|
280
|
+
# @return [Boolean] true if at least one child was affected, false otherwise
|
281
|
+
def remove_children(*args)
|
222
282
|
options = args.extract_options!
|
223
283
|
|
224
284
|
raise_if_sex_undefined
|
225
285
|
|
226
286
|
resulting_indivs = if args.blank?
|
227
|
-
|
287
|
+
children(options)
|
228
288
|
else
|
229
|
-
args &
|
289
|
+
args & children(options)
|
230
290
|
end
|
231
291
|
|
232
292
|
transaction do
|
233
293
|
resulting_indivs.each do |child|
|
234
|
-
if options[:
|
294
|
+
if options[:remove_other_parent] == true
|
235
295
|
child.remove_parents
|
236
296
|
else
|
237
297
|
case sex
|
238
|
-
when sex_male_value
|
298
|
+
when gclass.sex_male_value
|
239
299
|
child.remove_father
|
240
|
-
when sex_female_value
|
300
|
+
when gclass.sex_female_value
|
241
301
|
child.remove_mother
|
242
302
|
else
|
243
|
-
raise
|
303
|
+
raise SexError, "Sex value not valid for #{self}"
|
244
304
|
end
|
245
305
|
end
|
246
306
|
end
|
@@ -248,8 +308,9 @@ module Genealogy
|
|
248
308
|
!resulting_indivs.empty? #returned value must be true if self has at least a siblings to affect
|
249
309
|
end
|
250
310
|
|
311
|
+
# see #remove_children
|
251
312
|
def remove_child(child,options={})
|
252
|
-
|
313
|
+
remove_children(child,options)
|
253
314
|
end
|
254
315
|
|
255
316
|
private
|
@@ -259,7 +320,7 @@ module Genealogy
|
|
259
320
|
end
|
260
321
|
|
261
322
|
def raise_if_sex_undefined
|
262
|
-
raise
|
323
|
+
raise SexError, "Can't proceed if sex undefined for #{self}" unless is_male? or is_female?
|
263
324
|
end
|
264
325
|
|
265
326
|
end
|