Class: TransmissionBase
- Inherits:
-
GEDCOMBase
- Object
- GEDCOMBase
- TransmissionBase
- Defined in:
- lib/gedcom/transmission_base.rb
Overview
TransmissionBase is a subclass of GEDCOMBase, and contains methods used by the parsing process to build the other Gedcom classes, instantiate instances for each GEDCOM record type, and populate the fields based on the parsed GEDCOM file.
Direct Known Subclasses
Constant Summary collapse
- ACTION =
action_handler process the actions in the GedcomParser::TAGS hash, creating classes and populating attributes. Actions: [:class, :class_name] inidicates this line, and any further data, will be stored in the class :class_name [:pop] indicates that data will now be stored in the previous class. [:field, :fieldname] indicates that the data part of the line will be stored in the field :field_name [:field, [:fieldname, value]] fieldname stores the given value. [:append, :fieldname] indicates that the data part of the line will be appended to this field [:append_nl, :fieldname] indicates that the data part of the line will be appended to this field, after first appending a nl [:xref, [:field, :record_type]] indicates that the xref value of the line will get stored in the named field and points to the record_type. [:key, :index_name] means we need to create an index entry, in the index index_name, for this items xref value. nil in this field indicates that we should ignore this TAG and its children.
0
- DATA =
1
Instance Attribute Summary collapse
-
#class_stack ⇒ Object
Class_stack is for the parsing process to hold the classes we create as we walk down the levels of a gedcom record.
-
#indexes ⇒ Object
A hash to hold the indexes used in this transmission, each of which is also a hash (though that may change).
Attributes inherited from GEDCOMBase
Instance Method Summary collapse
- #action_handler(lineno, tokens, child_record = nil, min_occurances = 0, max_occurances = nil, data_type = nil, max_data_size = nil, action = nil, data_description = '') ⇒ Object
-
#add_to_class_field(lineno, record, data) ⇒ Object
add_to_class_field() is part of the parsing process, and checks to see if the field exists in the current states, target object.
-
#add_to_index(lineno, field_name, index_name, key) ⇒ Object
add_to_index is part of the parsing process, and adds references into the current target object to the index (i.e fills in the XREFs with index references].
-
#append_nl_field(lineno, field, data_type, data) ⇒ Object
append_nl_field is part of the parsing process, and inserts a 'n' character in front of the data, then calls append_to_field.
-
#append_sp_field(lineno, field, data_type, data) ⇒ Object
append_sp_field is part of the parsing process, and inserts a ' ' character in front of the data, then calls append_to_field.
-
#append_to_field(lineno, field, data_type, data) ⇒ Object
append_to_field is part of the parsing process, and adds the data to the end of the field's array.
-
#create_class(lineno, class_name) ⇒ Object
create_class() is part of the parsing process, and looks in the ClassTracker class to see if this class exists.
-
#create_index(lineno, index_name, key, value) ⇒ Object
create_index is part of the parsing process, and adds the key, value pair to the index index_name, creating the index if it didn't already exist.
- #define(class_name) ⇒ Object
- #defined(class_name) ⇒ Object
-
#initialize(*a) ⇒ TransmissionBase
constructor
new creates initializes the arrays for each of the GEDCOM level 0 record types.
-
#pop ⇒ Object
pop() is part of the parsing process, and removes target objects from their stack, which must remain aligned with the ParseState stack.
-
#summary ⇒ Object
summary() prints out the number of each level 0 record type the we have just parsed.
-
#update_field(lineno, field, data_type, data) ⇒ Object
update_field() is part of the parsing process, calls add_to_class_field.
-
#validate(lineno, tokens, max_data_size) ⇒ Object
validate() is part of the parsing process, and checks that the GEDCOM line falls within the data length specified by the standard A warning is printed if the data is longer than allowed by the standard.
Methods inherited from GEDCOMBase
#changed, #changed?, #created?, #find, #locked?, no_tabs, #private?, #save, tabs, #to_db, #to_gedcom, #to_s, #to_s_ordered, #to_s_r, #token_to_s, #xref_check
Constructor Details
#initialize(*a) ⇒ TransmissionBase
new creates initializes the arrays for each of the GEDCOM level 0 record types.
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 |
# File 'lib/gedcom/transmission_base.rb', line 20 def initialize(*a) super(*a) #Create the initial top level arrays of records that can exist in a transmission. @header_record = [] @submission_record = [] @submitter_record = [] @individual_record = [] @family_record = [] @source_record = [] @repository_record = [] @multimedia_record = [] @note_record = [] @trailer_record = [] #Class_stack is for the parsing process to hold the classes we create as we walk down the levels of a gedcom record. #The class we are currently working with is on the top of the stack. #The put ourselves on the top of the stack. The number represents the number of class to pop to go back one level of gedcom. @class_stack = [[self, 0]] #Create a hash to hold the indexes used in this transmission #Set up default indexes for the known level 0 types, so we can reference them even if they have no members. @indexes = { :individual => {}, :family => {}, :note => {}, :source => {}, :repository => {}, :multimedia => {}, :submitter => {}, :submission => {} } end |
Instance Attribute Details
#class_stack ⇒ Object
Class_stack is for the parsing process to hold the classes we create as we walk down the levels of a gedcom record. The class we are currently working with is on the top of the stack. The put ourselves on the top of the stack. The number represents the number of class to pop to go back one level of gedcom.
12 13 14 |
# File 'lib/gedcom/transmission_base.rb', line 12 def class_stack @class_stack end |
#indexes ⇒ Object
A hash to hold the indexes used in this transmission, each of which is also a hash (though that may change)
15 16 17 |
# File 'lib/gedcom/transmission_base.rb', line 15 def indexes @indexes end |
Instance Method Details
#action_handler(lineno, tokens, child_record = nil, min_occurances = 0, max_occurances = nil, data_type = nil, max_data_size = nil, action = nil, data_description = '') ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/gedcom/transmission_base.rb', line 254 def action_handler( lineno, tokens, child_record = nil, min_occurances = 0, max_occurances = nil, data_type = nil, max_data_size = nil, action = nil, data_description = '' ) validate(lineno, tokens, max_data_size) if action != nil nclasses = 1 new_class = nil action.each do |do_this| #We have instructions for handling this line. case do_this[ACTION] when :class #create a new class, making an instance of it, and making the instance the default one. new_class = create_class(lineno, do_this[DATA]) #Add this instance to an Array of records as an attribute named new_class of the current class. add_to_class_field(lineno, do_this[DATA], new_class) #Make this class the current one @class_stack << [new_class, nclasses] nclasses += 1 #We want to be able to unwind the stack in sync with the gedcom. #Hence we need to know how many classes we created at each point. when :field if do_this[DATA].class == Array #Then the value we are storing is given, rather than derived from the source file. update_field(lineno, do_this[DATA][0], data_type, do_this[DATA][1]) else update_field(lineno, do_this[DATA], data_type, tokens.data) end when :append_nl #We want to add a line terminator, then append the new data field from tokens #e.g. We do this with CONT lines being appended to a NOTE. append_nl_field(lineno, do_this[DATA], data_type, tokens.data) when :append #we want to append the data field in tokens, to the named field. #e.g. We do this with CONC lines being added to a NOTE. append_sp_field(lineno, do_this[DATA], data_type, tokens.data) when :xref #we want to record the reference (xref) from the token object. add_to_index(lineno, do_this[DATA][0], do_this[DATA][1], tokens.xref) when :key #will only occur after a class that is the thing we want the xref index to point to. ie xref => new_class #All the level 0 indexes should exist already, as it helps to have them, even if they are empty. create_index(lineno, do_this[DATA], tokens.xref, new_class ) when :pop @class_stack.pop #In this instance, we want to remove only the last item, even if there were several added. when :push @class_stack << @class_stack.last #We need to have dummy entries when the gedcom has another level, but we build no class for it. end end end end |
#add_to_class_field(lineno, record, data) ⇒ Object
add_to_class_field() is part of the parsing process, and checks to see if the field exists in the current states, target object. If the record exists, then the data is added to the record array. Each record is an array, so we can have multiple instances of a TAG in a GEDCOM record. If the record doesn't exist, the record is added to the target object, along with attr_accessors. The data is then added as above. * lineno is the current GEDCOM files line number, so we can report errors. * record is a symbol naming the attribute we want to store the data in in the class. * data is a word array, holding the GEDCOM lines data value
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/gedcom/transmission_base.rb', line 112 def add_to_class_field(lineno, record, data) #puts "#{lineno}: Add class instance '#{data.class}' to record #{record} of #{@class_stack.last[0]}" if @class_stack.last[0].class.method_defined?(record) == false #record is missing from the class, so add it using attr_accessor, thus getting the get and set methods. #Unlikely to ever see this case, as we precreated all fields for all class needed for GEDCOM 5.5 p "#{lineno}: create a record called #{record} in class #{@class_stack.last[0].class.to_s}" @class_stack.last[0].class.class_eval("attr_accessor :#{record}") #p "#{lineno}: Add the class #{data.class.to_s} as an array, to the record #{record} in class #{@class_stack.last[0].class.to_s}" @class_stack.last[0].send( record.to_s + "=", data ? [ data ] : []) #Much faster than eval("@class_stack.last[0].#{record} = [#{data}]") else #record exists, get a reference to it, so we can just add the data to the record's data array. if (a = @class_stack.last[0].send( record ) ) != nil #This way is much faster than eval("@class_stack.last[0].#{record} << #{data}") #p "#{lineno}: Add the class #{data.class.to_s} to the record #{record}[] in class #{@class_stack.last[0].class.to_s}" a << data if data != nil else #Got a reference to the attribute in the class, but no value stored as yet. #p "#{lineno}: Add the class #{data.class.to_s} as an array, to the record #{record} in class #{@class_stack.last[0].class.to_s}" @class_stack.last[0].send( record.to_s + "=", data ? [ data ] : [] ) end end end |
#add_to_index(lineno, field_name, index_name, key) ⇒ Object
add_to_index is part of the parsing process, and adds references into the current target object to the index (i.e fills in the XREFs with index references]
234 235 236 237 238 239 |
# File 'lib/gedcom/transmission_base.rb', line 234 def add_to_index(lineno, field_name, index_name, key) #p "#{lineno}: Add key #{key} to index #{index_name} to field #{field_name} of #{@class_stack.last[0]}" #There are many cases where there can be multiple records of the same GEDCOM type, in the parent record, so we store these in an array. #e.g. CHIL xrefs can occur multiple times in FAM record. add_to_class_field(lineno, field_name, Xref.new(index_name, *key) ) end |
#append_nl_field(lineno, field, data_type, data) ⇒ Object
append_nl_field is part of the parsing process, and inserts a 'n' character in front of the data, then calls append_to_field. * lineno is the current GEDCOM files line number, so we can report errors. * field is a symbol naming the attribute we want to store the data in in the class. * data is a word array, holding the GEDCOM lines data value * data_type gives hints to help validate the data (which we don't yet do).
172 173 174 175 176 177 |
# File 'lib/gedcom/transmission_base.rb', line 172 def append_nl_field(lineno, field, data_type, data) #p "#{lineno}: Append data '\n#{data}' to field #{field} of #{@class_stack.last[0]}" the_data = ["\n"] #want to add a new line to the existing data the_data += data if data != nil #add the new data only if it is not null. append_to_field(lineno, field, data_type, the_data) end |
#append_sp_field(lineno, field, data_type, data) ⇒ Object
append_sp_field is part of the parsing process, and inserts a ' ' character in front of the data, then calls append_to_field. * lineno is the current GEDCOM files line number, so we can report errors. * field is a symbol naming the attribute we want to store the data in in the class. * data is a word array, holding the GEDCOM lines data value * data_type gives hints to help validate the data (which we don't yet do).
160 161 162 163 164 165 |
# File 'lib/gedcom/transmission_base.rb', line 160 def append_sp_field(lineno, field, data_type, data) #p "#{lineno}: Append data ' #{data}' to field #{field} of #{@class_stack.last[0]}" the_data = [" "] #want to add a space to the existing data, before adding it to the string. the_data += data if data != nil #add the new data only if it is not null. append_to_field(lineno, field, data_type, the_data) end |
#append_to_field(lineno, field, data_type, data) ⇒ Object
append_to_field is part of the parsing process, and adds the data to the end of the field's array. Shared code between append_sp_field and append_nl_field. * lineno is the current GEDCOM files line number, so we can report errors. * field is a symbol naming the attribute we want to store the data in in the class. * data is a word array, holding the GEDCOM lines data value * data_type gives hints to help validate the data (which we don't yet do).
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/gedcom/transmission_base.rb', line 185 def append_to_field(lineno, field, data_type, data) #p "#{lineno}: Append data '#{data}' to field #{field} of #{@class_stack.last[0]}" begin if data != nil #Only bother if we have some data to append if ( a = @class_stack.last[0].send( field ) ) != nil #The field is not nil, then we need to add to the last value in the array if a != [] #The field is not an empty array if a[-1] != nil #The last element is not null, so we append to it. #p "Add the class #{data.class.to_s} to the field #{field}[] in class #{@class_stack.last[0].class.to_s}" a[-1] << GedString.new(data) else #The last element is null, so we replace is, rather than append to it. #p "Add the class #{data.class.to_s} as an array, to the field #{field} in class #{@class_stack.last[0].class.to_s}" a[-1] = GedString.new(data) end else #Was an empty array, the data will be the first member in the array. a[0] = GedString.new(data) end else #The field was null. We need to set the first value to our data value, in an array. #p "Add the class #{data.class.to_s} as an array, to the field #{field} in class #{@class_stack.last[0].class.to_s}" @class_stack.last[0].send( field.to_s + '=', [ GedString.new(data) ] ) end end rescue => exception p "#{exception} : Append data '#{data}' to field '#{field}' of class '#{@class_stack.last[0].class}'" raise exception end end |
#create_class(lineno, class_name) ⇒ Object
create_class() is part of the parsing process, and looks in the ClassTracker class to see if this class exists. if it doesn't already exist, the class is created and an instance is returned. if it already exists, then a new instance of the class is returned.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/gedcom/transmission_base.rb', line 89 def create_class(lineno, class_name) if class_name != nil new_class = class_name.to_s.capitalize if defined(new_class) == nil p "#{lineno}: Create class #{new_class}" define(new_class) new_class = Object.const_set("#{new_class}", Class.new) #creates a Class and assigns it the constant given end #p "#{lineno}: instance class #{class_name}" class_instance = eval "#{new_class}.new(self)" #create an instance of the new class. if class_instance == nil raise "class #{class_name} instance nil" end end class_instance end |
#create_index(lineno, index_name, key, value) ⇒ Object
create_index is part of the parsing process, and adds the key, value pair to the index index_name, creating the index if it didn't already exist. * lineno is the current GEDCOM files line number, so we can report errors. * index_name is the category of the index. e.g. it could be an index of individual records , or family records, etc. * key is a GEDCOM XREF we want to be able to track. * value is the target object that was created to hold the referenced GEDCOM record.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/gedcom/transmission_base.rb', line 217 def create_index(lineno, index_name, key, value) if index_name != nil if @indexes[index_name] == nil #puts "#{lineno}: create index #{index_name}" @indexes[index_name] = {} #empty hash end if key != nil #p "#{lineno}: Add (key,value) #{key} => #{@class_stack.last[0]} to index #{index_name}" if @indexes[index_name][key] != nil raise "duplicate key #{key} in index #{index_name}" end @indexes[index_name][key] = value end end end |
#define(class_name) ⇒ Object
306 307 308 |
# File 'lib/gedcom/transmission_base.rb', line 306 def define(class_name) ClassTracker << class_name end |
#defined(class_name) ⇒ Object
302 303 304 |
# File 'lib/gedcom/transmission_base.rb', line 302 def defined(class_name) ClassTracker::exists? class_name end |
#pop ⇒ Object
pop() is part of the parsing process, and removes target objects from their stack, which must remain aligned with the ParseState stack. Multiple object may be removed, as we may step back multiple levels in the ParseState stack. The object removed will have been placed into their parent GEDCOM records object before being removed from the stack.
138 139 140 141 142 |
# File 'lib/gedcom/transmission_base.rb', line 138 def pop #this is to catch multiple classes added to the stack, for one gedcom line. i = @class_stack.last[1] i.times { @class_stack.pop } end |
#summary ⇒ Object
summary() prints out the number of each level 0 record type the we have just parsed.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/gedcom/transmission_base.rb', line 54 def summary puts "HEAD count = #{@header_record.length}" puts "SUBM count = #{@submission_record.length}" puts "SUBN count = #{@submitter_record.length}" puts "INDI count = #{@individual_record.length}" puts "FAM count = #{@family_record.length}" puts "SOUR count = #{@source_record.length}" puts "REPO count = #{@repository_record.length}" puts "OBJE count = #{@multimedia_record.length}" puts "NOTE count = #{@note_record.length}" puts "TRLR count = #{@trailer_record.length}" #p ClassTracker #Debugging line. #pp @indexes[:individual]["IPB4"] #debugging test to find and print an indivual's record with xref @IPB4@ #pp @indexes[:family]["F1"] #debugging test to find and print a family record with the xref @F1@ #pp @indexes[:note] #debugging test to print all NOTE records #p find(:individual,"IB1024").to_gedcom #debugging test to find an individual record with xref @IB1024@ and print the record and its sub-records. end |
#update_field(lineno, field, data_type, data) ⇒ Object
update_field() is part of the parsing process, calls add_to_class_field. I'm sure there is a reason I did this. I just can't think what it was. * lineno is the current GEDCOM files line number, so we can report errors. * field is a symbol naming the attribute we want to store the data in in the class. * data is a word array, holding the GEDCOM lines data value * data_type gives hints to help validate the data (which we don't yet do).
150 151 152 153 |
# File 'lib/gedcom/transmission_base.rb', line 150 def update_field(lineno, field, data_type, data) #p "#{lineno}: Add data '#{data}' to field #{field} of #{@class_stack.last[0]}" add_to_class_field(lineno, field, data == nil ? nil : GedString.new(data)) end |
#validate(lineno, tokens, max_data_size) ⇒ Object
validate() is part of the parsing process, and checks that the GEDCOM line falls within the data length specified by the standard A warning is printed if the data is longer than allowed by the standard. As most programs seem to ignore the maximum data lengths, including the test file from LDS, the line is accepted regardless.
76 77 78 79 80 81 82 83 84 |
# File 'lib/gedcom/transmission_base.rb', line 76 def validate lineno, tokens, max_data_size #Validate the length of the data field is in bounds. if tokens.data != nil length = tokens.data.inject(0) { |l,element| l += element.length + 1 } if length - 1 > max_data_size p "Warning Line #{lineno}: Data portion may be too long for some databases. (Length = #{length - 1}, MAX = #{max_data_size})" end end end |