gedcom 0.9.0 → 0.9.1

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.
Files changed (60) hide show
  1. data/.gemtest +0 -0
  2. data/History.txt +8 -2
  3. data/Manifest.txt +4 -0
  4. data/README.txt +1 -1
  5. data/Rakefile +13 -5
  6. data/lib/gedcom.rb +3 -1
  7. data/lib/gedcom/address_record.rb +0 -0
  8. data/lib/gedcom/adoption_record.rb +0 -0
  9. data/lib/gedcom/association_record.rb +3 -3
  10. data/lib/gedcom/cause_record.rb +0 -0
  11. data/lib/gedcom/change_date_record.rb +0 -0
  12. data/lib/gedcom/character_set_record.rb +0 -0
  13. data/lib/gedcom/citation_data_record.rb +0 -0
  14. data/lib/gedcom/citation_event_type_record.rb +0 -0
  15. data/lib/gedcom/corporate_record.rb +0 -0
  16. data/lib/gedcom/date_record.rb +18 -0
  17. data/lib/gedcom/encoded_line_record.rb +0 -0
  18. data/lib/gedcom/event_age_record.rb +0 -0
  19. data/lib/gedcom/event_record.rb +13 -3
  20. data/lib/gedcom/events_list_record.rb +0 -0
  21. data/lib/gedcom/families_individuals.rb +2 -2
  22. data/lib/gedcom/family_record.rb +165 -3
  23. data/lib/gedcom/ged_string.rb +49 -0
  24. data/lib/gedcom/gedcom_all.rb +2 -0
  25. data/lib/gedcom/gedcom_base.rb +45 -15
  26. data/lib/gedcom/gedcom_record.rb +0 -0
  27. data/lib/gedcom/header_data_record.rb +0 -0
  28. data/lib/gedcom/header_record.rb +0 -0
  29. data/lib/gedcom/header_source_record.rb +0 -0
  30. data/lib/gedcom/individual_attribute_record.rb +25 -2
  31. data/lib/gedcom/individual_record.rb +436 -13
  32. data/lib/gedcom/multimedia_citation_record.rb +0 -0
  33. data/lib/gedcom/multimedia_record.rb +0 -0
  34. data/lib/gedcom/name_record.rb +70 -0
  35. data/lib/gedcom/note_citation_record.rb +0 -0
  36. data/lib/gedcom/note_record.rb +0 -0
  37. data/lib/gedcom/place_record.rb +6 -0
  38. data/lib/gedcom/refn_record.rb +0 -0
  39. data/lib/gedcom/repository_caln.rb +0 -0
  40. data/lib/gedcom/repository_citation_record.rb +0 -0
  41. data/lib/gedcom/repository_record.rb +0 -0
  42. data/lib/gedcom/source_citation_record.rb +0 -0
  43. data/lib/gedcom/source_record.rb +0 -0
  44. data/lib/gedcom/source_scope_record.rb +0 -0
  45. data/lib/gedcom/submission_record.rb +0 -0
  46. data/lib/gedcom/submitter_record.rb +0 -0
  47. data/lib/gedcom/text_record.rb +0 -0
  48. data/lib/gedcom/trailer_record.rb +0 -0
  49. data/lib/gedcom/transmission.rb +9 -0
  50. data/lib/gedcom/transmission_base.rb +81 -37
  51. data/lib/gedcom/xref.rb +8 -0
  52. data/lib/parser/class_tracker.rb +0 -0
  53. data/lib/parser/ged_line.rb +0 -0
  54. data/lib/parser/gedcom_parser.rb +0 -0
  55. data/lib/parser/instruction.rb +0 -0
  56. data/lib/parser/parse_state.rb +0 -0
  57. data/test/lds_gedcom_test.rb +61 -0
  58. data/test/ruby_version.rb +43 -0
  59. data/test/test_gedcom.rb +0 -0
  60. metadata +57 -16
@@ -39,3 +39,5 @@ require 'submitter_record.rb'
39
39
  require 'text_record.rb'
40
40
  require 'trailer_record.rb'
41
41
  require 'transmission_base.rb'
42
+ require 'xref.rb'
43
+ require 'ged_string.rb'
@@ -3,7 +3,9 @@ require "instruction.rb"
3
3
 
4
4
  #base routines shared by all gedcom objects.
5
5
  class GEDCOMBase
6
- attr_accessor :class_stack, :indexes
6
+ #Restriction records only exist in some GEDCOM record types, and we do honor that.
7
+ #Internally though, my DB allows any record to be restricted, hence this global use of :restriction.
8
+ attr_accessor :restriction
7
9
  @@tabs = false #If true, indent gedcom lines on output a tab per level. Normally wouldn't have tabs in a transmission file.
8
10
 
9
11
  #Create a new GEDCOMBase or most likely a subclass of GEDCOMBase.
@@ -54,10 +56,12 @@ class GEDCOMBase
54
56
  #create a string from the objects instance variables, one per line, in the form "variable = value\n" ... .
55
57
  #For an ordered list, see to_s_ordered
56
58
  def to_s
59
+ #This might seem a little obscure, but this will find and print the attributes with get methods defined,
60
+ #not having prior knowledge of what those attributes are.
57
61
  s = ''
58
62
  self.instance_variables.each do |v| #look at each of the instance variables
59
63
  if self.class.method_defined?(v_sym = v[1..-1].to_sym) #see if there is a method defined for this symbol (strip the :)
60
- s += "#{v} = " + pv_byname(v_sym) + "\n" #print it
64
+ s += "#{v} = " + pv_byname(v_sym).to_s + "\n" #print it
61
65
  end
62
66
  end
63
67
  s
@@ -83,6 +87,30 @@ class GEDCOMBase
83
87
  to_db( level, @this_level, @sub_level)
84
88
  end
85
89
 
90
+ #Find a XREF within this transmission. All classes inheriting from GEDCOMBase record the parent transmission object.
91
+ def find(*a)
92
+ @transmission.find(*a) if @transmission != nil
93
+ end
94
+
95
+ #Test for a Restriction notice for privacy
96
+ #People may request that a records contents not be available for public consumption.
97
+ def private?
98
+ (@restriction != nil && @restriction == "privacy") ? true : false
99
+ end
100
+
101
+ #Test for a Restriction notice for a locked record.
102
+ #Locked records mean that the data is known to be correct, so shouldn't be
103
+ #altered without checking with the original source of the data.
104
+ def locked?
105
+ (@restriction != nil && @restriction == "locked") ? true : false
106
+ end
107
+
108
+ #All our values are stored as arrays of words. This is quite useful in word wrapping of NOTES, TEXT, etc, and further parsing records like dates.
109
+ #It isn't really that helpful when we want to use a value as a string. This is a utility function to join the words into a space separated string.
110
+ def token_to_s(token)
111
+ token
112
+ end
113
+
86
114
  private
87
115
 
88
116
  #Somewhat cryptic. This takes the symbol (variable name) and returns the object associatied with it.
@@ -125,7 +153,7 @@ class GEDCOMBase
125
153
  #printing aid for tags that can have CONT or CONC sub-tags
126
154
  s_out = "#{tabstop(level)}#{level} #{tag}"
127
155
  if data != nil
128
- data.each do |word|
156
+ data.each_word do |word|
129
157
  if word != "\n"
130
158
  s_out += " #{word}"
131
159
  end
@@ -156,10 +184,10 @@ class GEDCOMBase
156
184
  #printing aid for tags that can have CONT or CONC sub-tags
157
185
  s_out = "#{tabstop(level)}#{level} #{tag}"
158
186
  nlevel = level + (conc ? 0 : 1)
159
-
187
+
160
188
  if data != nil
161
189
  length = s_out.length
162
- data.each_with_index do |word,i|
190
+ data.each_word_with_index do |word,i|
163
191
  if length > 253 && word != "\n" && data.length != i #253 allows for CR LF or LF CR pairs as the line terminator.
164
192
  s_tmp = "#{tabstop(nlevel)}#{nlevel} CONC"
165
193
  length = s_tmp.length #new line, so reset length
@@ -188,7 +216,7 @@ class GEDCOMBase
188
216
  s_out = "#{tabstop(level)}#{level} CONT"
189
217
 
190
218
  if data != nil
191
- data.each_with_index do |word,i|
219
+ data.each_word_with_index do |word,i|
192
220
  s_out += " #{word}"
193
221
  if word == "\n"
194
222
  s_out += "#{tabstop(level)}#{level} CONT"
@@ -203,9 +231,9 @@ class GEDCOMBase
203
231
  #Level n GEDCOM records have the @XREF@ after the tag.
204
232
  def xref(level, tag, xref)
205
233
  if level == 0
206
- "#{tabstop(level)}#{level} @#{xref}@ #{tag}\n"
234
+ "#{tabstop(level)}#{level} @#{xref.xref_value}@ #{tag}\n"
207
235
  else
208
- "#{tabstop(level)}#{level} #{tag} @#{xref}@\n"
236
+ "#{tabstop(level)}#{level} #{tag} @#{xref.xref_value}@\n"
209
237
  end
210
238
  end
211
239
 
@@ -229,8 +257,8 @@ class GEDCOMBase
229
257
  def to_s_r_action(level, action, tag, data=nil)
230
258
  case action
231
259
  when :xref then
232
- xref_check(level, tag, data[0], data[1])
233
- xref(level, tag, data[1])
260
+ xref_check(level, tag, data)
261
+ xref(level, tag, data)
234
262
  when :print then single_line(level, tag, data )
235
263
  when :conc then cont_conc(level, tag, true, data )
236
264
  when :cont then cont_conc(level, tag, false, data )
@@ -246,10 +274,10 @@ class GEDCOMBase
246
274
 
247
275
  #validate that the record referenced by the XREF actually exists in this transmission.
248
276
  #Genearte a warning if it does not. It does not stop the processing of this line.
249
- def xref_check(level, tag, index, xref)
250
- if @transmission != nil && @transmission.find(index, xref) == nil
277
+ def xref_check( level, tag, xref )
278
+ if @transmission != nil && @transmission.find(xref.index, xref.xref_value) == nil
251
279
  #Warning message that reference points to an unknown target.
252
- print "#{level+1} NOTE ****************Key not found: #{index} #{xref}\n"
280
+ print "#{level+1} NOTE ****************#{level}, #{tag} Key not found: #{xref.index} #{xref.xref_value}\n"
253
281
  end
254
282
  end
255
283
 
@@ -277,8 +305,9 @@ class GEDCOMBase
277
305
  if this_level_instruction.data != nil
278
306
  data = self.send( this_level_instruction.data ) #gets the contents using the symbol, and sending "self" a message
279
307
  else
280
- data = [['']]
308
+ data = [GedString.new('')]
281
309
  end
310
+
282
311
  if data != nil #could be if the self.send targets a variable that doesn't exist.
283
312
  data.each do |data_instance|
284
313
  s_out += to_s_r_action(level, this_level_instruction.action, this_level_instruction.tag, data_instance)
@@ -288,8 +317,9 @@ class GEDCOMBase
288
317
  if sub_level_instruction.data != nil
289
318
  sub_level_data = self.send( sub_level_instruction.data ) #gets the contents using the symbol, and sending "self" a message
290
319
  else
291
- sub_level_data = [['']]
320
+ sub_level_data = [GedString.new('')]
292
321
  end
322
+
293
323
  if sub_level_data != nil #could be if the self.send targets a variable that doesn't exist.
294
324
  sub_level_data.each do |sub_data_instance|
295
325
  s_out += to_s_r_action(level+1, sub_level_instruction.action, sub_level_instruction.tag, sub_data_instance )
File without changes
File without changes
File without changes
File without changes
@@ -51,19 +51,42 @@ class Individual_attribute_record < Event_record
51
51
 
52
52
  ClassTracker << :Individual_attribute_record
53
53
 
54
+ #attr_type= stores the attribute type in the event_type field.
55
+ #this minor hack lets us share methods with the event class.
54
56
  def attr_type=(value)
55
57
  @event_type = value
56
58
  end
59
+
60
+ #attr_type retrieves the attribute type from the Event_record#event_type field.
61
+ #this minor hack lets us share methods with the event class.
57
62
  def attr_type
58
63
  @event_type
59
64
  end
65
+
66
+ #is_attribute? tests that this Individual_attribute_record is of this attribute type.
67
+ #The attribute type is stored in the the Event_record#event_type field.
68
+ #this minor hack lets us share methods with the event class.
69
+ #This make sense, as the GEDCOM INDIVIDUAL_ATTRIBUTE_STRUCTURE has GEDCOM <<EVENT_DETAIL>> tags at level +1.
70
+ def is_attribute?(attribute)
71
+ is_event?(attribute)
72
+ end
73
+
74
+ #value= stores the value in the Event_record#event_status.
75
+ #this minor hack lets us share methods with the event class.
60
76
  def value=(value)
61
- @event_status = value
77
+ @event_status = value
62
78
  end
79
+
80
+ #value retrieves the value from the Event_record#event_status.
81
+ #this minor hack lets us share methods with the event class.
63
82
  def value
64
83
  @event_status
65
84
  end
66
-
85
+
86
+ private
87
+
88
+ #actually attribute_tag, but we share code with the Event_record class,
89
+ #as the GEDCOM INDIVIDUAL_ATTRIBUTE_STRUCTURE has GEDCOM <<EVENT_DETAIL>> tags at level +1.
67
90
  def event_tag(tag)
68
91
  case tag
69
92
  when "SEX" then tag
@@ -98,31 +98,454 @@ class Individual_record < GEDCOMBase
98
98
  @individual_ref
99
99
  end
100
100
 
101
+ #Finds the parent's family record(s) and returns the Family_record object in an array.
102
+ #This allows for multiple parentage. There is usually only be one FAMC record, but their
103
+ #might be another recording an adoption or an alternate family, if parentage is not clear.
104
+ #Parents_family returns nil if there are no FAMC records (or the FAMC XREFs
105
+ #don't resolve to a FAM record in the transmission).
106
+ #
107
+ #If a block is passed, then each Family_record is yielded to the block.
101
108
  def parents_family
102
- parents_family = []
103
- @families_individuals.each { |m| parents_family << m.parents_family_ref if m.relationship_type == "FAMC"}
104
- parent_family
109
+ if @families_individuals
110
+ parent_families = []
111
+ @families_individuals.each do |p|
112
+ if p.relationship_type[0] == "FAMC"
113
+ if (parent_family = find(:family, p.parents_family_ref.first.xref_value)) != nil
114
+ parent_families << parent_family
115
+ yield parent_family if block_given?
116
+ end
117
+ end
118
+ end
119
+ return parent_families if parent_families.length > 0 #might be a 0 length array.
120
+ end
121
+ return nil
122
+ end
123
+
124
+ #child? is a consistency check, testing that this INDI record has a FAMC record to the given FAM record.
125
+ def child?(fam)
126
+ if (pf = parents_family) != nil
127
+ pf.each do |famc|
128
+ return true if famc == fam
129
+ end
130
+ end
131
+ return false
105
132
  end
106
133
 
134
+ #Finds the family record for each spouse (or fellow parent) and returns the Family_record objects in an array.
135
+ #This allows for being a parent of multiple families. Spouses will return nil if there are no
136
+ #FAMS records (or the FAMS XREFs don't resolve to a FAM record in the transmission).
137
+ #
138
+ #If a block is passed, then each Family_record is yielded to the block.
107
139
  def spouses
108
- spouses = []
109
- @families_individuals.each { |m| spouses << m.own_family if m.relationship_type == "FAMS"}
110
- spouses
140
+ if @families_individuals
141
+ spouses = []
142
+ @families_individuals.each do |s|
143
+ if s.relationship_type[0] == "FAMS"
144
+ #Make sure we can find the spouse's Family_record.
145
+ if (spouse_family = find(:family, s.family_ref.first.xref_value)) != nil
146
+ spouses << spouse_family
147
+ yield spouse_family if block_given?
148
+ end
149
+ end
150
+ end
151
+ return spouses if spouses.length > 0 #might be a 0 length array.
152
+ end
153
+ return nil
111
154
  end
112
155
 
113
- def birth
156
+ #spouse? is a consistency check, testing that this INDI record has a FAMS record to the given FAM record.
157
+ def spouse?(fam)
158
+ if (pf = spouses) != nil
159
+ pf.each do |fams|
160
+ return true if fams == fam
161
+ end
162
+ end
163
+ return false
164
+ end
165
+
166
+ #Event looks in the Individual_record for events, as specified by the type argument,
167
+ #returning an array of the events found. Returns nil if there were
168
+ #no events of this type in this Individual_record.
169
+ #
170
+ #If a block is given, then yields each event to the block.
171
+ def event(type)
114
172
  if @event_record != nil
115
- @event_record.each { |e| if e.is_event('BIRT') then return e end }
173
+ events = []
174
+ @event_record.each do |e|
175
+ if e.is_event?(type)
176
+ yield e if block_given?
177
+ events << e
178
+ end
179
+ end
180
+ return events if events.length > 0
181
+ end
182
+ return nil
183
+ end
184
+
185
+ #Short hand for event('BIRT')
186
+ #passes on any block to the event method.
187
+ #(The block is the &p argument, so you don't pass any arguments to this method).
188
+ def birth(&p)
189
+ if block_given? then event('BIRT',&p) else event('BIRT') end
190
+ end
191
+
192
+ #Short hand for event('CHR')
193
+ #passes on any block to the event method.
194
+ #(The block is the &p argument, so you don't pass any arguments to this method).
195
+ def christening(&p)
196
+ if block_given? then event('CHR',&p) else event('CHR') end
197
+ end
198
+
199
+ #Short hand for event('ADOP')
200
+ #passes on any block to the event method.
201
+ #(The block is the &p argument, so you don't pass any arguments to this method).
202
+ def adoption(&p)
203
+ if block_given? then event('ADOP',&p) else event('ADOP') end
204
+ end
205
+
206
+ #Short hand for event('DEAT')
207
+ #passes on any block to the event method.
208
+ #(The block is the &p argument, so you don't pass any arguments to this method).
209
+ def death(&p)
210
+ if block_given? then event('DEAT',&p) else event('DEAT') end
211
+ end
212
+
213
+ #Short hand for event('BURI')
214
+ #passes on any block to the event method.
215
+ #(The block is the &p argument, so you don't pass any arguments to this method).
216
+ def burial(&p)
217
+ if block_given? then event('BURI',&p) else event('BURI') end
218
+ end
219
+
220
+ #Short hand for event('CREM')
221
+ #passes on any block to the event method.
222
+ #(The block is the &p argument, so you don't pass any arguments to this method).
223
+ def cremation(&p)
224
+ if block_given? then event('CREM',&p) else event('CREM') end
225
+ end
226
+
227
+ #Short hand for event('WILL')
228
+ #passes on any block to the event method.
229
+ #(The block is the &p argument, so you don't pass any arguments to this method).
230
+ def will(&p)
231
+ if block_given? then event('WILL',&p) else event('WILL') end
232
+ end
233
+
234
+ #Short hand for event('PROB')
235
+ #passes on any block to the event method.
236
+ #(The block is the &p argument, so you don't pass any arguments to this method).
237
+ def probate(&p)
238
+ if block_given? then event('PROB',&p) else event('PROB') end
239
+ end
240
+
241
+ #Short hand for event('CENS')
242
+ #passes on any block to the event method.
243
+ #(The block is the &p argument, so you don't pass any arguments to this method).
244
+ def census(&p)
245
+ if block_given? then event('CENS',&p) else event('CENS') end
246
+ end
247
+
248
+ #Short hand for event('GRAD')
249
+ #passes on any block to the event method.
250
+ #(The block is the &p argument, so you don't pass any arguments to this method).
251
+ def graduation(&p)
252
+ if block_given? then event('GRAD',&p) else event('GRAD') end
253
+ end
254
+
255
+ #Short hand for event('RETI')
256
+ #passes on any block to the event method.
257
+ #(The block is the &p argument, so you don't pass any arguments to this method).
258
+ def retirement(&p)
259
+ if block_given? then event('RETI',&p) else event('RETI') end
260
+ end
261
+
262
+ #Short hand for event('BAPM')
263
+ #passes on any block to the event method.
264
+ #(The block is the &p argument, so you don't pass any arguments to this method).
265
+ def baptism(&p)
266
+ if block_given? then event('BAPM',&p) else event('BAPM') end
267
+ end
268
+
269
+ #Short hand for event('BARM')
270
+ #passes on any block to the event method.
271
+ #(The block is the &p argument, so you don't pass any arguments to this method).
272
+ def bar_mitzvah(&p)
273
+ if block_given? then event('BARM',&p) else event('BARM') end
274
+ end
275
+
276
+ #Short hand for event('BASM')
277
+ #passes on any block to the event method.
278
+ #(The block is the &p argument, so you don't pass any arguments to this method).
279
+ def bas_mitzvah(&p)
280
+ if block_given? then event('BASM',&p) else event('BASM') end
281
+ end
282
+
283
+ #Short hand for event('BLES')
284
+ #passes on any block to the event method.
285
+ #(The block is the &p argument, so you don't pass any arguments to this method).
286
+ def blessing(&p)
287
+ if block_given? then event('BLES',&p) else event('BLES') end
288
+ end
289
+
290
+ #Short hand for event('ORDN')
291
+ #passes on any block to the event method.
292
+ #(The block is the &p argument, so you don't pass any arguments to this method).
293
+ def ordination(&p)
294
+ if block_given? then event('ORDN',&p) else event('ORDN') end
295
+ end
296
+
297
+ #Short hand for event('CHRA')
298
+ #passes on any block to the event method.
299
+ #(The block is the &p argument, so you don't pass any arguments to this method).
300
+ def adult_christening(&p)
301
+ if block_given? then event('CHRA',&p) else event('CHRA') end
302
+ end
303
+
304
+ #Short hand for event('CONF')
305
+ #passes on any block to the event method.
306
+ #(The block is the &p argument, so you don't pass any arguments to this method).
307
+ def confirmation(&p)
308
+ if block_given? then event('CONF',&p) else event('CONF') end
309
+ end
310
+
311
+ #Short hand for event('FCOM')
312
+ #passes on any block to the event method.
313
+ #(The block is the &p argument, so you don't pass any arguments to this method).
314
+ def first_communion(&p)
315
+ if block_given? then event('FCOM',&p) else event('FCOM') end
316
+ end
317
+
318
+ #Short hand for event('NATU')
319
+ #passes on any block to the event method.
320
+ #(The block is the &p argument, so you don't pass any arguments to this method).
321
+ def naturalization(&p)
322
+ if block_given? then event('NATU',&p) else event('NATU') end
323
+ end
324
+
325
+ #Short hand for event('EMIG')
326
+ #passes on any block to the event method.
327
+ #(The block is the &p argument, so you don't pass any arguments to this method).
328
+ def emigration(&p)
329
+ if block_given? then event('EMIG',&p) else event('EMIG') end
330
+ end
331
+
332
+ #Short hand for event('IMMI')
333
+ #passes on any block to the event method.
334
+ #(The block is the &p argument, so you don't pass any arguments to this method).
335
+ def immigration(&p)
336
+ if block_given? then event('IMMI',&p) else event('IMMI') end
337
+ end
338
+
339
+ #Short hand for the event('BAPL') LDS Ordinance
340
+ #passes on any block to the event method.
341
+ #(The block is the &p argument, so you don't pass any arguments to this method).
342
+ def lds_baptism(&p)
343
+ if block_given? then event('BAPL',&p) else event('BAPL') end
344
+ end
345
+
346
+ #Short hand for the event('CONL') LDS Ordinance
347
+ #passes on any block to the event method.
348
+ #(The block is the &p argument, so you don't pass any arguments to this method).
349
+ def lds_confirmation(&p)
350
+ if block_given? then event('CONL',&p) else event('CONL') end
351
+ end
352
+
353
+ #Short hand for the event('ENDL') LDS Ordinance
354
+ #passes on any block to the event method.
355
+ #(The block is the &p argument, so you don't pass any arguments to this method).
356
+ def lds_endowment(&p)
357
+ if block_given? then event('ENDL',&p) else event('ENDL') end
358
+ end
359
+
360
+ #Short hand for the event('SLGC') LDS Ordinance
361
+ #passes on any block to the event method.
362
+ #(The block is the &p argument, so you don't pass any arguments to this method).
363
+ def lds_child_sealing(&p)
364
+ if block_given? then event('SLGC',&p) else event('SLGC') end
365
+ end
366
+
367
+ #Short hand for the event('SLGS') LDS Sealing
368
+ #passes on any block to the event method.
369
+ #(The block is the &p argument, so you don't pass any arguments to this method).
370
+ def lds_spouse_sealing(&p)
371
+ if block_given? then event('SLGS',&p) else event('SLGS') end
372
+ end
373
+
374
+ #Attribute looks in the Individual_record for attributes, as specified by the attribute argument,
375
+ #returning an array of the attrbutes found. This may be a 0 length array, if there were
376
+ #no attrbutes of this type in this Individual_record.
377
+ #
378
+ #If a block is given, then yields each event to the block.
379
+ def attribute(attribute)
380
+ if @individual_attribute_record != nil
381
+ attributes = [] #collect the individual_attribute_record's of type attribute in this array.
382
+ @individual_attribute_record.each do |a|
383
+ #Look for the attribute in question.
384
+ if a.is_attribute?(attribute)
385
+ yield a if block_given?
386
+ attributes << a #add this record to the attributes array.
387
+ end
388
+ end
389
+ return attributes if attributes.length > 0 #if we found any, return the array.
390
+ end
391
+ return nil #if we found none, then return nil.
392
+ end
393
+
394
+ #Short hand for attribute('SEX')
395
+ #passes on any block to the event method.
396
+ #(The block is the &p argument, so you don't pass any arguments to this method).
397
+ def sex(&p)
398
+ if block_given? then attribute('SEX',&p) else attribute('SEX') end
399
+ end
400
+
401
+ #Short hand for attribute('CAST')
402
+ #passes on any block to the event method.
403
+ #(The block is the &p argument, so you don't pass any arguments to this method).
404
+ def caste_name(&p)
405
+ if block_given? then attribute('CAST',&p) else attribute('CAST') end
406
+ end
407
+
408
+ #Short hand for attribute('DSCR')
409
+ #passes on any block to the event method.
410
+ #(The block is the &p argument, so you don't pass any arguments to this method).
411
+ def physical_description(&p)
412
+ if block_given? then attribute('DSCR',&p) else attribute('DSCR') end
413
+ end
414
+
415
+ #Short hand for attribute('EDUC')
416
+ #passes on any block to the event method.
417
+ #(The block is the &p argument, so you don't pass any arguments to this method).
418
+ def education(&p)
419
+ if block_given? then attribute('EDUC',&p) else attribute('EDUC') end
420
+ end
421
+
422
+ #Short hand for attribute('IDNO')
423
+ #passes on any block to the event method.
424
+ #(The block is the &p argument, so you don't pass any arguments to this method).
425
+ def national_id_number(&p)
426
+ if block_given? then attribute('IDNO',&p) else attribute('IDNO') end
427
+ end
428
+
429
+ #Short hand for attribute('NATI')
430
+ #passes on any block to the event method.
431
+ #(The block is the &p argument, so you don't pass any arguments to this method).
432
+ def national_origin(&p)
433
+ if block_given? then attribute('NATI',&p) else attribute('NATI') end
434
+ end
435
+
436
+ #Short hand for attribute('NCHI')
437
+ #passes on any block to the event method.
438
+ #(The block is the &p argument, so you don't pass any arguments to this method).
439
+ def number_children(&p)
440
+ if block_given? then attribute('NCHI',&p) else attribute('NCHI') end
441
+ end
442
+
443
+ #Short hand for attribute('NMR')
444
+ #passes on any block to the event method.
445
+ #(The block is the &p argument, so you don't pass any arguments to this method).
446
+ def marriage_count(&p)
447
+ if block_given? then attribute('NMR',&p) else attribute('NMR') end
448
+ end
449
+
450
+ #Short hand for attribute('OCCU')
451
+ #passes on any block to the event method.
452
+ #(The block is the &p argument, so you don't pass any arguments to this method).
453
+ def occupation(&p)
454
+ if block_given? then attribute('OCCU',&p) else attribute('OCCU') end
455
+ end
456
+
457
+ #Short hand for attribute('PROP')
458
+ #passes on any block to the event method.
459
+ #(The block is the &p argument, so you don't pass any arguments to this method).
460
+ def possessions(&p)
461
+ if block_given? then attribute('PROP',&p) else attribute('PROP') end
462
+ end
463
+
464
+ #Short hand for attribute('RELI')
465
+ #passes on any block to the event method.
466
+ #(The block is the &p argument, so you don't pass any arguments to this method).
467
+ def religion(&p)
468
+ if block_given? then attribute('RELI',&p) else attribute('RELI') end
469
+ end
470
+
471
+ #Short hand for attribute('RESI')
472
+ #passes on any block to the event method.
473
+ #(The block is the &p argument, so you don't pass any arguments to this method).
474
+ def residence(&p)
475
+ if block_given? then attribute('RESI',&p) else attribute('RESI') end
476
+ end
477
+
478
+ #Short hand for attribute('SSN')
479
+ #passes on any block to the event method.
480
+ #(The block is the &p argument, so you don't pass any arguments to this method).
481
+ def social_security_number(&p)
482
+ if block_given? then attribute('SSN',&p) else attribute('SSN') end
483
+ end
484
+
485
+ #Short hand for attribute('TITL')
486
+ #passes on any block to the event method
487
+ #(The block is the &p argument, so you don't pass any arguments to this method).
488
+ def title(&p)
489
+ if block_given? then attribute('TITL',&p) else attribute('TITL') end
490
+ end
491
+
492
+ #Test to see if we have a NAME record stored for this individual.
493
+ def has_name?
494
+ @name_record != nil && @name_record.length > 0
495
+ end
496
+
497
+ #Names looks in the Individual_record for Name_records, returning an array of the Name_records found.
498
+ #This may be a 0 length array, if there were no NAME tags in this GEDCOM record for this Individual_record.
499
+ #
500
+ #If a block is given, then yields each event to the block.
501
+ def names
502
+ if has_name?
503
+ if block_given?
504
+ @name_record.each { |n| yield n }
505
+ end
506
+ return @name_record
116
507
  else
117
- nil
508
+ return []
118
509
  end
119
510
  end
120
511
 
121
- def death
122
- if @event_record != nil
123
- @event_record.each { |e| if e.is_event('DEAT') then return e end }
512
+ #Primary_name returns the first name (as a string) defined in the @name_record array (and probably the only name defined).
513
+ #The GEDCOM standard states that if multiple TAGS of the same type are present, then the first is the most
514
+ #preferred, with the last the least preferred. I'm not certain that programs generating GEDCOM follow that rule,
515
+ #but if there are multiple NAME records, and you want one to display, then picking the first is what the standard
516
+ #says to do.
517
+ #
518
+ #Returns "" if no name is recorded in this Individual_record and if the individual requested privacy for this record.
519
+ def primary_name
520
+ if has_name?
521
+ if self.private? || @name_record[0].private?
522
+ ""
523
+ else
524
+ @name_record[0].name
525
+ end
526
+ else
527
+ ""
528
+ end
529
+ end
530
+
531
+ def self_check
532
+ if @families_individuals
533
+ @families_individuals.each do |p|
534
+ if p.relationship_type[0] == "FAMC"
535
+ if find(:family, p.parents_family_ref.first.xref_value) == nil
536
+ puts "INDI #{@individual_ref.first.xref_value} FAMC #{p.parents_family_ref.first.xref_value} record has no FAM record"
537
+ end
538
+ elsif p.relationship_type[0] == "FAMS"
539
+ if find(:family, p.family_ref.first.xref_value) == nil
540
+ puts "INDI #{@individual_ref.first.xref_value} FAMS #{p.family_ref.first.xref_value} record has no FAM record"
541
+ end
542
+ else
543
+ puts "Unrecognised relationship #{p.relationship_type[0]}"
544
+ end
545
+ end
124
546
  else
125
- nil
547
+ puts "INDI #{@individual_ref.first.xref_value} has no FAMC or FAMS record"
126
548
  end
127
549
  end
550
+
128
551
  end