diff --git a/Rakefile b/Rakefile index ec7af1e..c3fa96b 100755 --- a/Rakefile +++ b/Rakefile @@ -17,11 +17,11 @@ short_name = full_name.downcase # Many of these tasks came from the ruby-hl7 project rakefile # -desc 'Default: Run RSpec Tests' +desc 'Default: Run RSpec Tests' task :default => :spec # Gem Specification -spec = Gem::Specification.new do |s| +spec = Gem::Specification.new do |s| s.name = short_name s.version = GEDCOM::VERSION s.author = "Phillip Davies" @@ -30,7 +30,7 @@ spec = Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.summary = "Ruby GEDCOM Parser Library" s.rubyforge_project = short_name - s.description = "A simple library to enable easy, callback-based parsing of GEDCOM data files" + s.description = "A simple library to enable easy, callback-based parsing of GEDCOM data files" s.files = FileList["{lib,ext,samples,tests}/**/*"].to_a s.require_path = "lib" s.autorequire = short_name @@ -42,8 +42,8 @@ spec = Gem::Specification.new do |s| end # Gem Task -Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_tar = true +Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_tar = true end # RSpec Test Task @@ -61,7 +61,7 @@ namespace :spec do t.libs << $: t.rcov = true end - + desc 'Heckle the Date tests' Spec::Rake::SpecTask.new('heckle_dates') do |t| t.warning = true @@ -69,7 +69,7 @@ namespace :spec do t.libs << $: t.spec_opts << " --heckle GEDCOM::Date" end - + desc 'Heckle the DatePart test' Spec::Rake::SpecTask.new('heckle_dateparts') do |t| t.warning = true @@ -77,9 +77,9 @@ namespace :spec do t.libs << $: t.spec_opts << " --heckle GEDCOM::DatePart" end - + end - + # Clean up Task desc 'Clean up all the extras' @@ -119,7 +119,7 @@ task :release => [:clean, :package] do |t| rf.add_release spec.rubyforge_project, spec.name, spec.version.to_s, *files end -# Task to install the gem locally +# Task to install the gem locally desc 'Install the package as a gem' task :install_gem => [:clean, :package] do sh "sudo gem install pkg/*.gem" diff --git a/ext/Makefile b/ext/Makefile index 3cddcc1..25c2c8e 100644 --- a/ext/Makefile +++ b/ext/Makefile @@ -40,15 +40,15 @@ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -RUBY_EXTCONF_H = -CFLAGS = -fPIC -O2 -fno-strict-aliasing -pipe -fPIC +RUBY_EXTCONF_H = +CFLAGS = -fPIC -O2 -fno-strict-aliasing -pipe -fPIC INCFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir) -CPPFLAGS = -CXXFLAGS = $(CFLAGS) -DLDFLAGS = -L. -rdynamic -Wl,-soname,$(.TARGET) +CPPFLAGS = +CXXFLAGS = $(CFLAGS) +DLDFLAGS = -L. -rdynamic -Wl,-soname,$(.TARGET) LDSHARED = cc -shared AR = ar -EXEEXT = +EXEEXT = RUBY_INSTALL_NAME = ruby18 RUBY_SO_NAME = ruby18 @@ -66,26 +66,26 @@ COPY = cp #### End of system configuration section. #### -preload = +preload = libpath = . $(libdir) LIBPATH = -L'.' -L'$(libdir)' -Wl,-R'$(libdir)' -DEFFILE = +DEFFILE = CLEANFILES = mkmf.log -DISTCLEANFILES = +DISTCLEANFILES = -extout = -extout_prefix = -target_prefix = -LOCAL_LIBS = +extout = +extout_prefix = +target_prefix = +LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lcrypt -lm -rpath=/usr/lib:/usr/local/lib -pthread -lc SRCS = gedcom.c gedcom_date.c OBJS = gedcom.o gedcom_date.o TARGET = _gedcom DLLIB = $(TARGET).so -EXTSTATIC = -STATIC_LIB = +EXTSTATIC = +STATIC_LIB = RUBYCOMMONDIR = $(sitedir)$(target_prefix) RUBYLIBDIR = $(sitelibdir)$(target_prefix) diff --git a/lib/gedcom.rb b/lib/gedcom.rb index 99a4508..a272b60 100644 --- a/lib/gedcom.rb +++ b/lib/gedcom.rb @@ -6,12 +6,12 @@ # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. -# +# # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. -# +# # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -26,7 +26,7 @@ module GEDCOM # Possibly a better way to do this? VERSION = "0.2.1" - + class Parser def initialize &block @before = {} @@ -71,7 +71,7 @@ def context protected - + def check_proc_or_block proc, &block unless proc or block_given? raise ArgumentError.new("proc or block required") @@ -125,7 +125,7 @@ def unwind_to level end def concat_data tag, rest - if @dataStack[-1].nil? + if @dataStack[-1].nil? @dataStack[-1] = rest else if @ctxStack[-1] == 'BLOB' diff --git a/lib/gedcom_date.rb b/lib/gedcom_date.rb index 85788dc..dded45f 100644 --- a/lib/gedcom_date.rb +++ b/lib/gedcom_date.rb @@ -21,7 +21,7 @@ module GEDCOM class DatePart < GEDCOM_DATE_PARSER::GEDDate - + # Flags NONE = GEDCOM_DATE_PARSER::GFNONE PHRASE = GEDCOM_DATE_PARSER::GFPHRASE @@ -31,102 +31,102 @@ class DatePart < GEDCOM_DATE_PARSER::GEDDate NOMONTH = GEDCOM_DATE_PARSER::GFNOMONTH NOYEAR = GEDCOM_DATE_PARSER::GFNOYEAR YEARSPAN = GEDCOM_DATE_PARSER::GFYEARSPAN - + def initialize(type=GEDCOM_DATE_PARSER::GCTGREGORIAN, flags=NONE, data=nil) super( type, flags, data ) end - + def calendar @type end - + def compliance @flags end - + def phrase raise DateFormatException if( @flags != PHRASE ) @data end - + def has_day? return false if ( @flags == PHRASE ) return ((@data.flags & NODAY) != 0 ? false : true) end - + def has_month? return false if ( @flags == PHRASE ) return ((@data.flags & NOMONTH) != 0 ? false : true) end - + def has_year? return false if ( @flags == PHRASE ) return ((@data.flags & NOYEAR) != 0 ? false : true) end - + def has_year_span? return false if ( @flags == PHRASE ) return ((@data.flags & YEARSPAN) != 0 ? true : false) end - + def day raise DateFormatException, "date has no day" if (@flags == PHRASE || (@data.flags & NODAY) != 0) @data.day end - + def month raise DateFormatException, "date has no month" if (@flags == PHRASE || (@data.flags & NOMONTH) != 0) @data.month end - + def year raise DateFormatException, "date has no year" if (@flags == PHRASE || (@data.flags & NOYEAR) != 0) @data.year end - + def to_year raise DateFormatException, "date has no year span" if (@flags == PHRASE || (@data.flags & YEARSPAN) == 0) @data.year2 end - + def epoch raise DateFormatException, "only gregorian dates have epoch" if ( @flags == PHRASE || @type != GEDCOM_DATE_PARSER::GCTGREGORIAN ) return (( @data.adbc == GEDCOM_DATE_PARSER::GEDADBCBC ) ? "BC" : "AD" ) end - + def to_s GEDCOM_DATE_PARSER::DateParser.build_gedcom_date_part_string( self ) end - + def <=>( dp ) return -1 if has_year? and !dp.has_year? return 1 if !has_year? and dp.has_year? - + if has_year? and dp.has_year? rc = ( year <=> dp.year ) return rc unless rc == 0 end - + return -1 if dp.has_month? and !dp.has_month? return 1 if !dp.has_month? and dp.has_month? - + if has_month? and dp.has_month? rc = ( month <=> dp.month ) return rc unless rc == 0 end - + return -1 if dp.has_day? and !dp.has_day? return 1 if !dp.has_day? and dp.has_day? - + if has_day? and dp.has_day? rc = ( day <=> dp.day ) return rc unless rc == 0 end - + return 0 end end #/ DatePart - + class Date < GEDCOM_DATE_PARSER::GEDDateValue # Calendar types NONE = GEDCOM_DATE_PARSER::GCNONE @@ -173,43 +173,43 @@ def initialize ( date_str, calendar=DateType::DEFAULT ) end err_msg += "'" if (block_given?) - yield( err_msg ) + yield( err_msg ) else raise DateFormatException, err_msg end end end - + def format @flags end - + def first @date1 end - + def last @date2 end - + def to_s GEDCOM_DATE_PARSER::DateParser.build_gedcom_date_string( self ) end - + def is_date? (@flags & (NONE | ABOUT | CALCULATED | ESTIMATED | BEFORE | AFTER | BETWEEN \ | FROM | TO | FROMTO | INTERPRETED)) != 0 ? false : true end - + def is_range? (@flags & (BETWEEN | FROMTO)) != 0 ? true : false end - + def <=>( d ) if is_date? and d.is_date? rc = ( first <=> d.first ) return rc unless rc == 0 - + if is_range? and d.is_range? return ( last <=> d.last ) elsif is_range? @@ -217,18 +217,18 @@ def <=>( d ) elsif d.is_range? return -1 end - + return 0 elsif is_date? return -1 elsif d.is_date? return 1 end - + return format <=> d.format end end - + class DateType GREGORIAN = GEDCOM_DATE_PARSER::GCTGREGORIAN JULIAN = GEDCOM_DATE_PARSER::GCTJULIAN @@ -238,8 +238,8 @@ class DateType UNKNOWN = GEDCOM_DATE_PARSER::GCTUNKNOWN DEFAULT = GEDCOM_DATE_PARSER::GCTDEFAULT end - + class DateFormatException < Exception - + end end diff --git a/lib/gedcom_date_parser.rb b/lib/gedcom_date_parser.rb index 6fecdd9..51434fc 100644 --- a/lib/gedcom_date_parser.rb +++ b/lib/gedcom_date_parser.rb @@ -105,7 +105,7 @@ module GEDCOM_DATE_PARSER TKDNS = 97 #Do Not Submit TKDNSCAN = 98 #Do Not Submit / Cancelled TKDEAD = 99 - + #states ST_DV_ERROR = -1 ST_DV_START = 1 @@ -127,8 +127,8 @@ module GEDCOM_DATE_PARSER ST_DT_SLASH = 4 ST_DT_BC = 5 ST_DT_END = 6 - - + + # After parsing, all flags should be available as booleans with accessors GCTGREGORIAN = 0 GCTJULIAN = 1 @@ -139,33 +139,33 @@ module GEDCOM_DATE_PARSER GCTDEFAULT = GCTGREGORIAN - # date constants + # date constants GCNONE = 0 - # approximated date constants + # approximated date constants GCABOUT = 1 GCCALCULATED = 2 GCESTIMATED = 3 - # date range constants + # date range constants GCBEFORE = 4 GCAFTER = 5 GCBETWEEN = 6 - # date period constants + # date period constants GCFROM = 7 GCTO = 8 GCFROMTO = 9 - # other date constants + # other date constants GCINTERPRETED = 10 - # LDS ordinance constants + # LDS ordinance constants GCCHILD = 11 GCCLEARED = 12 @@ -176,18 +176,18 @@ module GEDCOM_DATE_PARSER GCSTILLBORN = 17 GCSUBMITTED = 18 GCUNCLEARED = 19 - GCBIC = 20 # Born In the Covenant - GCDNS = 21 # Do Not Submit - GCDNSCAN = 22 # Do Not Submit / Cancelled + GCBIC = 20 # Born In the Covenant + GCDNS = 21 # Do Not Submit + GCDNSCAN = 22 # Do Not Submit / Cancelled GCDEAD = 23 - # date flags + # date flags GFNONE = 0 GFPHRASE = 1 GFNONSTANDARD = 2 - # date bit flags + # date bit flags GFNOFLAG = 0 GFNODAY = 1 @@ -195,14 +195,14 @@ module GEDCOM_DATE_PARSER GFNOYEAR = 4 GFYEARSPAN = 8 - # data type constants + # data type constants GCMAXPHRASEBUFFERSIZE = 35 - + # BC / AD GEDADBCBC = 0 GEDADBCAD = 1 - + Default_Months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] @@ -303,8 +303,8 @@ def initialize(lex, gen, spec) TokenTable << Token.new("VENDEMIAIRE", TKMONTH, TKVENDEMIAIRE ) TokenTable << Token.new("VENTOSE", TKMONTH, TKVENTOSE ) TokenTable << Token.new(0, 0, 0 ) - - + + class GEDStateEntry attr_accessor :state, :input, :nextState, :action def initialize(st, ip, ns, a) @@ -314,57 +314,57 @@ def initialize(st, ip, ns, a) @action = a end end - + DateValueStateTable = [] - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKAPPROXIMATED, ST_DV_DATE_APPROX, 1 ) # 1: set the approx type - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKRANGE, ST_DV_DATE_RANGE, 2 ) # 2: set the range type - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKTO, ST_DV_TO, 3 ) # 3: set the period type - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKPERIOD, ST_DV_DATE_PERIOD, 3 ) # 3: set the period type - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKINTERPRETED, ST_DV_DATE_INTERP, 4 ) # 4: set interpreted - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKLPAREN, ST_DV_DATE_PHRASE, 5 ) # 5: get remaining buffer as phrase - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKSTATUS, ST_DV_STATUS, 10 ) # 10: set status - DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKLPAREN, ST_DV_DATE_PHRASE, 7 ) # 7: if 'interpreted', get remaining buffer as phrase - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKAND, ST_DV_AND, 8 ) # 8: if 'between', prepare to read next date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKTO, ST_DV_TO, 9 ) # 9: if 'from', set FROMTO, prepare to read next date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_APPROX, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_APPROX, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_RANGE, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_RANGE, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PERIOD, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PERIOD, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_INTERP, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKAPPROXIMATED, ST_DV_DATE_APPROX, 1 ) # 1: set the approx type + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKRANGE, ST_DV_DATE_RANGE, 2 ) # 2: set the range type + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKTO, ST_DV_TO, 3 ) # 3: set the period type + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKPERIOD, ST_DV_DATE_PERIOD, 3 ) # 3: set the period type + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKINTERPRETED, ST_DV_DATE_INTERP, 4 ) # 4: set interpreted + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKLPAREN, ST_DV_DATE_PHRASE, 5 ) # 5: get remaining buffer as phrase + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKSTATUS, ST_DV_STATUS, 10 ) # 10: set status + DateValueStateTable << GEDStateEntry.new( ST_DV_START, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKLPAREN, ST_DV_DATE_PHRASE, 7 ) # 7: if 'interpreted', get remaining buffer as phrase + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKAND, ST_DV_AND, 8 ) # 8: if 'between', prepare to read next date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKTO, ST_DV_TO, 9 ) # 9: if 'from', set FROMTO, prepare to read next date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_APPROX, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_APPROX, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_RANGE, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_RANGE, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PERIOD, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PERIOD, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_INTERP, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_INTERP, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PHRASE, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate - DateValueStateTable << GEDStateEntry.new( ST_DV_AND, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_AND, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date - DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_DATE_PHRASE, TKEOF, ST_DV_END, 6 ) # 6: if 'between' and not second date read, error, else terminate + DateValueStateTable << GEDStateEntry.new( ST_DV_AND, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_AND, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKNUMBER, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date + DateValueStateTable << GEDStateEntry.new( ST_DV_TO, TKMONTH, ST_DV_DATE, 0 ) # 0: inc dates read, parse a date DateValueStateTable << GEDStateEntry.new( ST_DV_STATUS, TKEOF, ST_DV_END, 6 ) DateValueStateTable << GEDStateEntry.new( 0, 0, 0, 0 ) DateStateTable = [] - DateStateTable << GEDStateEntry.new( ST_DT_START, TKNUMBER, ST_DT_NUMBER, 0 ) # 0: store number, set NUMBER - DateStateTable << GEDStateEntry.new( ST_DT_START, TKMONTH, ST_DT_MONTH, 1 ) # 1: if MONTH, then error, else set number to be day, set month, set MONTH - DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKMONTH, ST_DT_MONTH, 1 ) # 1: if MONTH, then error, else set number to be day, set month, set MONTH - DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKSLASH, ST_DT_SLASH, 2 ) # 2: if SLASH, then error, else set SLASH, set number to be year - DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKBC, ST_DT_BC, 3 ) # 3: if not SLASH set number to be year, set bc + DateStateTable << GEDStateEntry.new( ST_DT_START, TKNUMBER, ST_DT_NUMBER, 0 ) # 0: store number, set NUMBER + DateStateTable << GEDStateEntry.new( ST_DT_START, TKMONTH, ST_DT_MONTH, 1 ) # 1: if MONTH, then error, else set number to be day, set month, set MONTH + DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKMONTH, ST_DT_MONTH, 1 ) # 1: if MONTH, then error, else set number to be day, set month, set MONTH + DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKSLASH, ST_DT_SLASH, 2 ) # 2: if SLASH, then error, else set SLASH, set number to be year + DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKBC, ST_DT_BC, 3 ) # 3: if not SLASH set number to be year, set bc DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKEOF, ST_DT_END, 4 ) # 4: if not SLASH set number to be year, terminate DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKTO, ST_DT_END, 4 ) # 4: if TO set number to be year, terminate DateStateTable << GEDStateEntry.new( ST_DT_NUMBER, TKAND, ST_DT_END, 4 ) # 4: if AND set number to be year, terminate - DateStateTable << GEDStateEntry.new( ST_DT_MONTH, TKNUMBER, ST_DT_NUMBER, 5 ) # 5: if NUMBER, set number to be day. set number to be year, store number, set NUMBER + DateStateTable << GEDStateEntry.new( ST_DT_MONTH, TKNUMBER, ST_DT_NUMBER, 5 ) # 5: if NUMBER, set number to be day. set number to be year, store number, set NUMBER DateStateTable << GEDStateEntry.new( ST_DT_MONTH, TKEOF, ST_DT_END, 6 ) # 6: terminate DateStateTable << GEDStateEntry.new( ST_DT_MONTH, TKTO, ST_DT_END, 6 ) # 6: if TO, terminate DateStateTable << GEDStateEntry.new( ST_DT_MONTH, TKAND, ST_DT_END, 6 ) # 6: if AND, terminate - DateStateTable << GEDStateEntry.new( ST_DT_SLASH, TKNUMBER, ST_DT_NUMBER, 7 ) # 7: set number to be year2 - DateStateTable << GEDStateEntry.new( ST_DT_BC, TKEOF, ST_DT_END, 6 ) # 6: terminate + DateStateTable << GEDStateEntry.new( ST_DT_SLASH, TKNUMBER, ST_DT_NUMBER, 7 ) # 7: set number to be year2 + DateStateTable << GEDStateEntry.new( ST_DT_BC, TKEOF, ST_DT_END, 6 ) # 6: terminate DateStateTable << GEDStateEntry.new( 0, 0, 0, 0 ) - + class GEDParserState attr_accessor :buffer, :lastGeneralToken, :lastSpecificToken, :pos def initialize( buf, lgt, lst, p ) @@ -374,7 +374,7 @@ def initialize( buf, lgt, lst, p ) @pos = p end end - + # Gregorian Date Class class GEDDateGreg attr_accessor :flags, :day, :month, :year, :year2, :adbc @@ -386,8 +386,8 @@ def initialize(flg, d, m, y, y2, adbc) @year2 = y2 @adbc = adbc end - end - + end + # General Date Class class GEDDateGeneral attr_accessor :flags, :day, :month, :year @@ -425,7 +425,7 @@ class DateParser GEDFNUMBER = 8 GEDFMONTH = 16 GEDFSLASH = 32 - + def self.get_token( parser ) # Get a single token from this parser state (class method) # Inputs: parser - parser state (GEDParserState) @@ -475,11 +475,11 @@ def self.get_token( parser ) if( lexeme[ lexPos-1, 1 ] != TokenTable[ currentToken ].lexeme[ lexPos-1, 1 ] ) currentToken+=1 while( ( TokenTable[ currentToken ].lexeme != 0 ) && ( (TokenTable[ currentToken ].lexeme[0, lexPos] <=> lexeme[0, lexPos] ) < 0 ) ) - + #if the lexeme does not appear in the table, exit with an error break if ( TokenTable[ currentToken ].lexeme == 0 || \ (TokenTable[ currentToken ].lexeme[0, lexPos] <=> lexeme[0, lexPos] ) != 0 ) - + end #if the lexeme terminates, return the value of the current token @@ -492,14 +492,14 @@ def self.get_token( parser ) #if the current token terminates before the lexeme, then we have an error break if ( TokenTable[ currentToken ].lexeme[ lexPos, 1 ] == nil ) - + end parser.pos = startPos specific = TKNONE general = TKERROR - + return general, specific end @@ -518,11 +518,11 @@ def self.get_date_text( date ) # Inputs: date - Date Part (GEDDate) # Outputs: buffer - Output string buffer = "" - + if ( (date.flags & (GFPHRASE | GFNONSTANDARD)) != 0) buffer += date.data return buffer - end + end case ( date.type ) when GCTHEBREW @@ -532,7 +532,7 @@ def self.get_date_text( date ) else months = Default_Months end - + return buffer if not (date.data) if ( date.data.flags && (( date.data.flags & GFNODAY ) == 0) ) @@ -556,7 +556,7 @@ def self.get_date_text( date ) buffer += " BC" if ( (date.type == GCTGREGORIAN) && (date.data.adbc != GEDADBCAD) ) buffer end - + def self.validate_month_for_type( month, calType ) # Make sure this is a valid month for this calendar type (class method) # Inputs: parser - parser state @@ -565,16 +565,16 @@ def self.validate_month_for_type( month, calType ) case calType when GCTGREGORIAN || GCTJULIAN return ( month - TKJANUARY + 1 ) if( month >= TKJANUARY && month <= TKDECEMBER ) - + when GCTHEBREW return ( month - TKTISHRI + 1 ) if( month >= TKTISHRI && month <= TKELUL ) - + when GCTFRENCH return ( month - TKVENDEMIAIRE + 1 )if( month >= TKVENDEMIAIRE && month <= TKJOUR_COMP ) end return -1 end - + def self.parse_date_part( parser, datePart, type ) # Parse out a date part (class method) # Inputs: parser - parser state @@ -587,14 +587,14 @@ def self.parse_date_part( parser, datePart, type ) # Initialize the datePart, in case it contains old data datePart.type = type datePart.flags = GFNONE - if (type == GCTGREGORIAN) + if (type == GCTGREGORIAN) datePart.data = GEDDateGreg.new(flags, 0, 0, 0, 0, GEDADBCAD) else datePart.data = GEDDateGeneral.new(flags, 0, 0, 0) end number = 0 - while ( ( state != ST_DT_END ) && ( state != ST_DT_ERROR ) ) + while ( ( state != ST_DT_END ) && ( state != ST_DT_ERROR ) ) general, specific = get_token( parser ) raise DateParseException, "error parsing datepart, pre-transition" if (general == TKERROR) transitionFound = 0 @@ -617,11 +617,11 @@ def self.parse_date_part( parser, datePart, type ) DateStateTable.each do |dateState| break if dateState.state < 1 - + if( ( dateState.state == state ) && ( dateState.input == general ) ) state = dateState.nextState transitionFound = 1 - + case dateState.action # 0: store number, set NUMBER when 0 @@ -662,7 +662,7 @@ def self.parse_date_part( parser, datePart, type ) end if ( ( flags & GEDFMONTH ) != 0 ) - state = ST_DT_ERROR + state = ST_DT_ERROR else month = validate_month_for_type( specific, type ) if ( month < 1 ) @@ -681,7 +681,7 @@ def self.parse_date_part( parser, datePart, type ) state = ST_DT_ERROR else datePart.data.year = number if ( number > 0 ) - + datePart.data.flags |= GFYEARSPAN number = 0 flags |= GEDFSLASH @@ -698,7 +698,7 @@ def self.parse_date_part( parser, datePart, type ) end datePart.data.adbc = GEDADBCBC end - + if (dateState.action == 3 || dateState.action == 4) if( ( number > 0 ) && ( ( flags & GEDFSLASH ) == 0 ) ) datePart.data.year = number @@ -706,13 +706,13 @@ def self.parse_date_part( parser, datePart, type ) end end - + datePart.data.flags |= GFNODAY if( datePart.data.day < 1 ) datePart.data.flags |= GFNOMONTH if( datePart.data.month < 1 ) datePart.data.flags |= GFNOYEAR if( datePart.data.year < 1 ) - + # 5: if NUMBER, set number to be day. set number to be year, store number, set NUMBER when 5 @@ -739,8 +739,8 @@ def self.parse_date_part( parser, datePart, type ) raise DateParseException, "error parsing datepart, general" if( state == ST_DT_ERROR ) end - - + + def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) # Parse out a GEDCOM date (class method) # Inputs: dateString - String containing GEDCOM date @@ -767,14 +767,14 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) DateValueStateTable.each do |dateValueState| break if dateValueState.state < 1 - + if( ( dateValueState.state == state ) && ( dateValueState.input == general ) ) - + transitionFound = 1 state = dateValueState.nextState - case ( dateValueState.action ) - # 0: inc dates read, parse a date + case ( dateValueState.action ) + # 0: inc dates read, parse a date when 0 put_token( parser, general, specific ) begin @@ -785,13 +785,13 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) end parse_date_part( parser, datePart, type ) datesRead+=1 - rescue + rescue state = ST_DV_ERROR end - # 1: set the approx type + # 1: set the approx type when 1 - case ( specific ) + case ( specific ) when TKABOUT date.flags = GCABOUT when TKCALCULATED @@ -800,9 +800,9 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) date.flags = GCESTIMATED end - # 2: set the range type + # 2: set the range type when 2 - case ( specific ) + case ( specific ) when TKBEFORE date.flags = GCBEFORE when TKAFTER @@ -814,27 +814,27 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) # 3: set the period type when 3 - if( general == TKTO ) + if( general == TKTO ) date.flags = GCTO - elsif( specific == TKFROM ) + elsif( specific == TKFROM ) date.flags = GCFROM flags |= GEDFFROM end - # 4: set interpreted + # 4: set interpreted when 4 date.flags = GCINTERPRETED flags |= GEDFINTERP # 5: get remaining buffer as phrase - # 7: if 'interpreted', get remaining buffer as phrase + # 7: if 'interpreted', get remaining buffer as phrase when 5, 7 # This is kind of a sucky way to handle this, but the shared functionality - # between action 5 and 7 doesn't seem like enough to warrant breaking out - # into it's own method. - if( dateValueState.action == 7 && ( flags & GEDFINTERP ) == 0 ) + # between action 5 and 7 doesn't seem like enough to warrant breaking out + # into it's own method. + if( dateValueState.action == 7 && ( flags & GEDFINTERP ) == 0 ) state = ST_DV_ERROR - break + break end # Strip off trailing whitespace and closing parenthesis @@ -845,27 +845,27 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) # 6: if 'between' and not second date read, error, else terminate when 6 - state = ST_DV_ERROR if( ( ( flags & GEDFBETWEEN ) != 0 ) && datesRead < 2 ) - + state = ST_DV_ERROR if( ( ( flags & GEDFBETWEEN ) != 0 ) && datesRead < 2 ) + # else -- nextState is ST_DV_END, so we're done! # 7: see above 5 - # 8: if 'between', prepare to read next date + # 8: if 'between', prepare to read next date when 8 - state = ST_DV_ERROR if( ( flags & GEDFBETWEEN ) == 0 ) + state = ST_DV_ERROR if( ( flags & GEDFBETWEEN ) == 0 ) - # 9: if 'from', set FROMTO, prepare to read next date + # 9: if 'from', set FROMTO, prepare to read next date when 9 - if( ( flags & GEDFFROM ) == 0 ) + if( ( flags & GEDFFROM ) == 0 ) state = ST_DV_ERROR - else + else date.flags = GCFROMTO end - # 10: set status + # 10: set status when 10 - case ( specific ) + case ( specific ) when TKCHILD date.flags = GCCHILD when TKCLEARED @@ -893,23 +893,23 @@ def self.parse_gedcom_date( dateString, date, type = GCTDEFAULT ) when TKDEAD date.flags = GCDEAD end - + end break # ... Out of the DateValueStateTable.each block end end - state = ST_DV_ERROR if( !transitionFound ) + state = ST_DV_ERROR if( !transitionFound ) end - if( state == ST_DV_ERROR ) + if( state == ST_DV_ERROR ) parser.pos = savePos datePart.flags = GFNONSTANDARD datePart.data = parser.buffer.slice( parser.pos, parser.buffer.length ) raise DateParseException, "error parsing date, general" end end - + def self.build_gedcom_date_string( date ) # Stringify a GEDCOM date (class method) # Inputs: date - date (GEDDateValue) @@ -949,7 +949,7 @@ def self.build_gedcom_date_string( date ) when GCBETWEEN then buffer += " and " when GCFROMTO then buffer += " to " end - + buffer += get_date_text( date.date2 ) if (date.date2) buffer end @@ -964,8 +964,8 @@ def self.build_gedcom_date_part_string( date ) end end - + class DateParseException < Exception - + end end diff --git a/tests/date_spec.rb b/tests/date_spec.rb index ed7d0df..b841ddf 100644 --- a/tests/date_spec.rb +++ b/tests/date_spec.rb @@ -9,33 +9,33 @@ @date_bc = GEDCOM::Date.new("25 JANUARY 1 BC") @date_year_span = GEDCOM::Date.new("1 APRIL 2007/08") end - - ## ! Could definitely stand to beef this test up. About, Estimated, etc. + + ## ! Could definitely stand to beef this test up. About, Estimated, etc. ## Lot's of flags to test. it "makes flags available" do (@date_range_from.format & GEDCOM::Date::FROMTO).should_not == 0 (@date_range_between.format & GEDCOM::Date::BETWEEN).should_not == 0 end - + it "does comparison" do (@date <=> @date_bc).should == 1 (@date_bc <=> @date).should == -1 (@date <=> @date).should == 0 end - + it "gets first and last date from ranges" do @date_range_from.is_range?.should == true @date_range_between.is_range?.should == true - + @date_range_from.first.nil?.should == false @date_range_from.last.nil?.should == false @date_range_between.first.nil?.should == false @date_range_between.last.nil?.should == false - + (@date_range_from.first <=> @date_range_from.last).should == -1 (@date_range_between.first <=> @date_range_between.last).should == -1 end - + # to_s currently works differently in the Ruby vs. C extension # code, therefore this test is failing (in C) it "converts to string" do diff --git a/tests/datepart_spec.rb b/tests/datepart_spec.rb index b9465c5..0f6d158 100644 --- a/tests/datepart_spec.rb +++ b/tests/datepart_spec.rb @@ -11,12 +11,12 @@ @nonstandard = GEDCOM::Date.safe_new("FIRST DAY OF 2008") @phrase = GEDCOM::Date.safe_new("(independance day)") end - + it "makes date type and flags available" do (@date.first.compliance | GEDCOM::DatePart::NONE).should == 0 #(@nonstandard.first.compliance & GEDCOM::DatePart::NONSTANDARD).should_not == 0 (@phrase.first.compliance & GEDCOM::DatePart::PHRASE).should_not == 0 - + (@date_range_from.first.calendar | GEDCOM::DateType::DEFAULT).should == 0 (@date_range_from.last.calendar | GEDCOM::DateType::DEFAULT).should == 0 end @@ -24,68 +24,68 @@ it "finds days" do @date.first.has_day?.should == true @date.first.day.should == 1 - + @date_range_between.first.has_day?.should == true @date_range_between.first.day.should == 1 - + @date_range_between.last.has_day?.should == true @date_range_between.last.day.should == 1 - - @date_bc.first.has_day?.should == true + + @date_bc.first.has_day?.should == true @date_bc.first.day.should == 25 end - + it "finds months" do @date.first.has_month?.should == true @date.first.month.should == 4 - + @date_range_between.first.has_month?.should == true @date_range_between.first.month.should == 1 - + @date_range_between.last.has_month?.should == true @date_range_between.last.month.should == 4 - + @date_bc.first.has_month?.should == true @date_bc.first.month.should == 1 end - + it "finds years" do @date.first.has_year?.should == true @date.first.year.should == 2008 - + @date_range_between.first.has_year?.should == true @date_range_between.first.year.should == 1970 - + @date_range_between.last.has_year?.should == true @date_range_between.last.year.should == 2008 - + @date_bc.first.has_year?.should == true @date_bc.first.year.should == 1 end - + it "finds the epoch" do @date.first.epoch.should == "AD" @date_bc.first.epoch.should == "BC" - end + end it "finds year span" do @date_year_span.first.has_year_span?.should == true @date.first.has_year_span?.should == false end - + # to_s currently works differently in the Ruby vs. C extension # code, therefore this test is failing (in C) it "converts to string" do @date.first.to_s.should == "1 Apr 2008" - + @date_range_from.first.to_s.should == "Apr 2007" @date_range_from.last.to_s.should == "Jun 2008" - + @date_range_between.first.to_s.should == "1 Jan 1970" @date_range_between.last.to_s.should == "1 Apr 2008" - + @date_bc.first.to_s.should == "25 Jan 1 BC" - + @date_year_span.to_s.should == "1 Apr 2007-8" end diff --git a/tests/parser_spec.rb b/tests/parser_spec.rb index e99befb..280ef6e 100644 --- a/tests/parser_spec.rb +++ b/tests/parser_spec.rb @@ -15,7 +15,7 @@ @tag_count[:all] += 1 end end - + it "can be initialized with block" do parser = GEDCOM::Parser.new do before 'INDI' do @@ -26,10 +26,10 @@ it "can count individual tags, before and after" do count_before = 0 count_after = 0 - @parser.before 'INDI' do |data| + @parser.before 'INDI' do |data| count_before += 1 end - @parser.after 'INDI' do |data| + @parser.after 'INDI' do |data| count_after += 1 end @parser.parse SIMPLE