NAME

Genealogy::Relationship::Name - Return a genealogical relationship name from step counts

VERSION

Version 0.01

SYNOPSIS

use Genealogy::Relationship::Name;

my $namer = Genealogy::Relationship::Name->new();

my $name = $namer->name(
    steps_to_ancestor   => 2,
    steps_from_ancestor => 3,
    sex                 => 'F',
);
# Returns 'first cousin once-removed'

# With language
my $name_fr = $namer->name(
    steps_to_ancestor   => 2,
    steps_from_ancestor => 2,
    sex                 => 'M',
    language            => 'fr',
);
# Returns 'cousin germain'

DESCRIPTION

Genealogy::Relationship::Name maps a pair of step-counts (person A to common ancestor, common ancestor to person B) plus the sex of person B and an optional language code to a human-readable relationship name string.

The relationship tables were originally embedded in the gedcom and ged2site distributions inside Gedcom::Individual::relationship_up(); this module extracts them into a reusable, installable CPAN distribution.

Supported languages: en (English, default), fr (French), de (German).

METHODS

name

Returns the name of the relationship between person A and person B.

PURPOSE

Given the number of steps from person A up to the nearest common ancestor (steps_to_ancestor) and the number of steps from that ancestor down to person B (steps_from_ancestor), plus the sex of person B and a language code, returns a localised relationship-name string.

ARGUMENTS

RETURNS

A string containing the relationship name, or undef if the combination is not found in the lookup table.

EXAMPLE

my $namer = Genealogy::Relationship::Name->new();

# Person A is the grandparent (2 steps up) of the common ancestor,
# and person B is 3 steps below the ancestor; B is female => first cousin once-removed
my $rel = $namer->name(
    steps_to_ancestor   => 2,
    steps_from_ancestor => 3,
    sex                 => 'F',
);

API SPECIFICATION

Input

{
    steps_to_ancestor   => { type => 'integer', minimum => 0 },
    steps_from_ancestor => { type => 'integer', minimum => 0 },
    sex                 => { type => 'string', memberof => ['M', 'F'] },
    language            => { type => 'string', regex => qr/^(?:en|de|fr)/, optional => 1 },
}

Output

{
    type     => 'string',
    optional => 1,     # undef when the combination is not tabulated
}

FORMAL SPECIFICATION

name ______________________________________________________
[In]  steps_to_ancestor   : N0
      steps_from_ancestor : N0
      sex                 : {M, F}
      language            : {en, fr, de}?  (default en)
[Out] result              : String | undef

Let key == steps_to_ancestor ++ "," ++ steps_from_ancestor
Let table == RELATIONSHIP_TABLES(language)(sex)
result == table(key)  if key in dom table
       == undef       otherwise

supported_languages

Returns a sorted list of the language codes that the module supports.

PURPOSE

Allows calling code to enumerate the languages available for name() without hard-coding them.

ARGUMENTS

None.

RETURNS

A list (or array-ref in scalar context) of language code strings, currently ('de', 'en', 'fr').

EXAMPLE

my @langs = $namer->supported_languages();
# ( 'de', 'en', 'fr' )

API SPECIFICATION

Input

{}   # no arguments

Output

{
    type => ARRAYREF,   # sorted list of language codes
}

FORMAL SPECIFICATION

supported_languages ______________________________________
[In]  (none)
[Out] result : seq String

result == sort(dom RELATIONSHIP_TABLES)

known_sexes

Returns the list of sex codes accepted by name().

PURPOSE

Documents and exposes the set of valid sex values so that callers can validate their own input without duplicating knowledge.

ARGUMENTS

None.

RETURNS

A list (or array-ref in scalar context) of valid sex code strings: ('F', 'M').

SIDE EFFECTS

None.

EXAMPLE

my @sexes = $namer->known_sexes();
# ( 'F', 'M' )

API SPECIFICATION

Input

{}   # no arguments

Output

{
    type => ARRAYREF,
}

FORMAL SPECIFICATION

known_sexes ______________________________________________
[In]  (none)
[Out] result : seq String

result == sort { $SEX_FEMALE, $SEX_MALE }

CONFIGURATION

The constructor accepts an optional language key which sets the default language for all subsequent calls to name():

my $namer = Genealogy::Relationship::Name->new(language => 'fr');

This default can be overridden per-call by passing language to name(). The object is also compatible with Object::Configure for runtime reconfiguration.

DIAGNOSTICS

DEPENDENCIES

Carp, Params::Get, Params::Validate::Strict, Readonly

BUGS AND LIMITATIONS

The lookup tables currently cover steps 0-6 in both directions. Relationships further removed (seventh cousin, etc.) return undef. Pull requests adding deeper tables are welcome.

SEE ALSO

AUTHOR

Nigel Horne <njh@nigelhorne.com>

REPOSITORY

https://github.com/nigelhorne/Genealogy-Relationship-Name

SUPPORT

This module is provided as-is without any warranty.

Please report any bugs or feature requests to bug-genalogy-relationship-name at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Genealogy-Relationship-Name. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

You can find documentation for this module with the perldoc command.

perldoc Genealogy::Relationship::Name

You can also look for information at:

LICENCE AND COPYRIGHT

Copyright 2026 Nigel Horne.

Usage is subject to the GPL2 licence terms. If you use it, please let me know.