File Coverage

blib/lib/Gedcom/Grammar.pm
Criterion Covered Total %
statement 58 61 95.0
branch 16 22 72.7
condition 4 6 66.6
subroutine 10 11 90.9
pod 5 6 83.3
total 93 106 87.7


line stmt bran cond sub pod time code
1             # Copyright 1998-2019, Paul Johnson (paul@pjcj.net)
2              
3             # This software is free. It is licensed under the same terms as Perl itself.
4              
5             # The latest version of this software should be available from my homepage:
6             # http://www.pjcj.net
7              
8             # documentation at __END__
9              
10 11     11   59 use strict;
  11         19  
  11         391  
11              
12             require 5.005;
13              
14             package Gedcom::Grammar;
15              
16 11     11   58 use Data::Dumper;
  11         13  
  11         467  
17              
18 11     11   4394 use Gedcom::Item 1.22;
  11         221  
  11         305  
19              
20 11     11   55 use vars qw($VERSION @ISA);
  11         20  
  11         5460  
21             $VERSION = "1.22";
22             @ISA = qw( Gedcom::Item );
23              
24             sub structure {
25 519     519 0 627 my $self = shift;
26 519         707 my ($struct) = @_;
27 519 100       910 unless (exists $self->{top}{structures}) {
28             $self->{top}{structures} = {
29 232 50       513 map { $_->{structure} ? ($_->{structure} => $_) : () }
30 8         14 @{$self->{top}{items}}
  8         26  
31             };
32             }
33             # print Dumper $self->{top}{structures};
34 519         1357 $self->{top}{structures}{$struct}
35             }
36              
37             sub item {
38 6682     6682 1 6921 my $self = shift;
39 6682         8156 my ($tag) = @_;
40 6682 50       9184 return unless defined $tag;
41 6682         8393 my $valid_items = $self->valid_items;
42             # use Data::Dumper; print "[$tag] -- ", Dumper($self), Dumper $valid_items;
43 6682 100       10509 return unless exists $valid_items->{$tag};
44 6677         6474 map { $_->{grammar} } @{$valid_items->{$tag}}
  6696         14604  
  6677         9790  
45             }
46              
47             sub min {
48 1757     1757 1 1719 my $self = shift;
49 1757 50       3254 exists $self->{min} ? $self->{min} : 1
50             }
51              
52             sub max {
53 1757     1757 1 1740 my $self = shift;
54 1757 100       4002 exists $self->{max} ? $self->{max} eq "M" ? 0 : $self->{max} : 1
    50          
55             }
56              
57             sub items {
58 0     0 1 0 my $self = shift;
59 0         0 keys %{$self->valid_items}
  0         0  
60             }
61              
62             sub _valid_items {
63 595     595   629 my $self = shift;
64 595         617 my %valid_items;
65 595         581 for my $item (@{$self->{items}}) {
  595         1077  
66 1757         2719 my $min = $item->min;
67 1757         2207 my $max = $item->max;
68 1757 100       2526 if ($item->{tag}) {
69 1247         1199 push @{$valid_items{$item->{tag}}}, {
  1247         4527  
70             grammar => $item,
71             min => $min,
72             max => $max
73             };
74             } else {
75             die "What's a " . Data::Dumper->new([$item], ["grammar"])
76 510 50       2500 unless my ($value) = $item->{value} =~ /<<(.*)>>/;
77 510 50       882 die "Can't find $value in Gedcom structures"
78             unless my $structure = $self->structure($value);
79 510         719 $item->{structure} = $structure;
80 510         612 while (my($tag, $g) = each %{$structure->valid_items}) {
  2667         3857  
81 2157         8950 push @{$valid_items{$tag}}, map {
82             grammar => $_->{grammar},
83             # min and max can be calculated by multiplication because
84             # the grammar always permits multiple selection records, and
85             # selection records never have compulsory records. This may
86             # change in future grammars, but I would not expect it to -
87             # such a grammar would seem to have little practical use.
88             min => $_->{min} * $min,
89 2157         2152 max => $_->{max} * $max
90             }, @$g;
91             }
92 510 100 66     972 if (exists $item->{items} && @{$item->{items}}) {
  510         1381  
93 8         23 my $extra_items = $item->_valid_items;
94 8         46 while (my ($sub_item, $sub_grammars) = each %valid_items) {
95 88         131 for my $sub_grammar (@$sub_grammars) {
96 88         158 $sub_grammar->{grammar}->valid_items;
97 88         200 while (my ($i, $g) = each %$extra_items) {
98             # print "adding $i to $sub_item\n";
99 176         525 $sub_grammar->{grammar}{_valid_items}{$i} = $g;
100             }
101             }
102             # print "giving @{[keys %{$sub_grammar->{grammar}->valid_items}]}\n";
103             }
104             }
105             }
106             }
107             # print "valid items are @{[keys %valid_items]}\n";
108 595         1829 \%valid_items
109             }
110              
111             sub valid_items {
112 62926     62926 1 64914 my $self = shift;
113 62926   66     114972 $self->{_valid_items} ||= $self->_valid_items
114             }
115              
116             1;
117              
118             __END__