Utility Ruby Subroutines and Methods

This page lists some utility subroutines that may be used by more than one tutorial:

These utilities are written to be as general as possible so then can be reused in different scripts. You can copy and paste the script code in the boxes on this page into your own scripts.

CheckAvailable(gedit,sName) Subroutine

CheckAvailable()
# Verify GEDitCOM II is running and a document is open.
# Return 1 or 0 if script can run or not.
def CheckAvailable(gedit,sName)
    if gedit.documents().count()<1
        errMsg = "The script '"+sName+"' requires requires a document to be"\
        + " open\nPlease open a document and try again."
        puts errMsg
        return 0
    end

    return 1
end

Nearly all GEDitCOM II scripts will start by calling this subroutine to verify that a document is open (because most scripts work on data in one or more documents). You can optionally add other checks to this method before the script is allowed to run.

This subroutine returns 1 if it passes all tests or returns 0 if any test fails. Note that the script name is passed in the variable sName. If needed, that name is displayed in a message window that explains the reason the script will not run.

Prior to GEDitCOM II, version 2.0, this subroutine would also check the version number and verify it was new enough for the current script. You should still check version number, but once you package the script in an extension, you can specify a minimum version number and that check will be done automatically before running the script.


notifyProgressFraction_message_() Command

notify progress logic
# set progress variables
fractionStepSize = nextFraction = 0.01
  
# main script loop
for i in 1...numTasks
    # the script code
      
    # time for progress
    fractionDone = Float(i)/Float(numTasks)
    if fractionDone > nextFraction:
        gdoc.notifyProgressFraction_message_(fractionDone,nil)
        nextFraction = nextFraction + fractionStepSize
    end
end

Scripting of GEDitCOM II is a great tool, but it can get slow for large calculations in large files. For this reason, all good GEDitCOM II scripts should inform the user of the progress of the calculations. The code on the right gives the logic

At the beginning of the script you define two variables. The fractionStepSize defines how often to inform the user of progress. There is no point in sending too many notifications since the progress is rounded to the nearest percent. A good choice is usually to notify the user after each percent is completed and thus fractionStepSize is set to 0.01. The nextFraction variable defines the next time the notification should be sent to GEDitCOM II. It is initialized to the same value as fractionStepSize to define the point for the first notification.

Periodically during the script, you should then calculate the fraction of the script that has finished. This sample code shows a script with a repeat loop that will execute numTasks times. At the end the each pass through the loop, the fractionDone is easily calculated to be i/numTasks (converted to floating point). If this fraction has passed a predetermined notification point (stored in nextFraction), a notification is sent to a document (here it is assumed gdoc references a document) using the notifyProgressFraction_message_() command and nextFraction is advanced by the fractionStepSize defined at the start of the script.

For other scripts, it may be harder to determine the fraction completed (such as a script searching for ancestors when you do not know how many ancestors will be found). For these scripts, you have three options. First, you can periodically guess the fraction done and send a notifyProgressFraction_message_() to a document. Second, you can post a message to the user with the second argument to the notifyProgressFraction_message_(); it can be any string. Third, you can do nothing. The scripting palette in GEDitCOM II will still show a spinning progress wheel to indicate the script is still running. For Ruby scripts, that palette will also have an abort button (with an "X") that can be clicked to stop any script.


GetAgeSpan(beginDate, endDate) Subroutine

GetAgeSpan()
# Convert two date SDNs to years from first date to second date
def GetAgeSpan(beginDate, endDate)
    return (endDate - beginDate) / 365.25
end

This simple subrouting converts the time between two day numbers into the number of years. The time span is from the beginDate to the endDate.


GCConstant(constantName) Subroutine

GCConstant()
# convert string to AppleScript enumerated constant
def GCConstant(uniqueStr)
    if uniqueStr=="chart"
        byteForm = 0x74724348			# trCH
    elsif uniqueStr=="outline"
        byteForm = 0x74724F55			# trOU
    elsif uniqueStr=="the children"
        byteForm = 0x736B4348			# skCH
    elsif uniqueStr=="the events" 
        byteForm = 0x736B4556			# skEV
    elsif uniqueStr=="the spouses"
        byteForm = 0x736B5350			# skSP
    elsif uniqueStr=="char_MacOS"
        byteForm = 0x784F7031			# xOp1
    elsif uniqueStr=="char_ANSEL"
        byteForm = 0x784F7032			# xOp2
    elsif uniqueStr=="char_UTF8"
        byteForm = 0x784F7033			# xOp3
    elsif uniqueStr=="char_UTF16"
        byteForm = 0x784F7034			# xOp4
    elsif uniqueStr=="char_Windows"
        byteForm = 0x784F7035			# xOp5
    elsif uniqueStr=="lines_LF"
        byteForm = 0x784F7036			# xOp6
    elsif uniqueStr=="lines_CR"
        byteForm = 0x784F7037			# xOp7
    elsif uniqueStr=="lines_CRLF"
        byteForm = 0x784F7038			# xOp8
    elsif uniqueStr=="mm_GEDitCOM"
        byteForm = 0x784F7039			# xOp9
    elsif uniqueStr=="mm_Embed"
        byteForm = 0x784F7041			# xOpA
    elsif uniqueStr=="mm_PhpGedView"
        byteForm = 0x784F7042			# xOpB
    elsif uniqueStr=="logs_Include"
        byteForm = 0x784F7043			# xOpC
    elsif uniqueStr=="logs_Omit"
        byteForm = 0x784F7044			# xOpD
    elsif uniqueStr=="places_Include"
        byteForm = 0x784F7045			# xOpE
    elsif uniqueStr=="places_Omit"
        byteForm = 0x784F7046			# xOpF
    elsif uniqueStr=="books_Include"
        byteForm = 0x784F7047			# xOpG
    elsif uniqueStr=="books_Omit"
        byteForm = 0x784F7048			# xOpH
    elsif uniqueStr=="settings_Embed"
        byteForm = 0x784F7049			# xOpI
    elsif uniqueStr=="settings_Omit"
        byteForm = 0x784F7050			# xOpJ
    elsif uniqueStr=="thumbnails_Embed"
        byteForm = 0x784F7051			# xOpK
    elsif uniqueStr=="thumbnails_Omit"
        byteForm = 0x784F7052			# xOpL
    elsif uniqueStr=="locked"
        byteForm = 0x724C636B			# rLck
    elsif uniqueStr=="privacy"
        byteForm = 0x72507276			# rPrv
    elsif uniqueStr=="unlocked"
        byteForm = 0x72556E6C			# rUnl
    else
        byteForm = 0
    end
    return byteForm
end

Some commands take arguments that select among two or more defined constants (such as chart and outline for family trees). Similarly, the restriction property of individual records returns a defined constant (amoung unlocked, locked, and privacy). These constants are used in AppleScript by their name, but in Ruby scripts, you have to use the underlying numeric codes instead. The GCConstant() subroutine solves this problem by translating any constant to its numeric value. The constant's name is passed as the subroutine's single argument as a string variable. For example. GCConstant("chart") will return the numeric value for the chart constant.