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   61 use strict;
  11         17  
  11         376  
11              
12             require 5.005;
13              
14             package Gedcom::Grammar;
15              
16 11     11   45 use Data::Dumper;
  11         19  
  11         449  
17              
18 11     11   4321 use Gedcom::Item 1.21;
  11         164  
  11         292  
19              
20 11     11   68 use vars qw($VERSION @ISA);
  11         17  
  11         5393  
21             $VERSION = "1.21";
22             @ISA = qw( Gedcom::Item );
23              
24             sub structure {
25 519     519 0 601 my $self = shift;
26 519         681 my ($struct) = @_;
27 519 100       909 unless (exists $self->{top}{structures}) {
28             $self->{top}{structures} = {
29 232 50       501 map { $_->{structure} ? ($_->{structure} => $_) : () }
30 8         17 @{$self->{top}{items}}
  8         26  
31             };
32             }
33             # print Dumper $self->{top}{structures};
34 519         1404 $self->{top}{structures}{$struct}
35             }
36              
37             sub item {
38 6682     6682 1 7154 my $self = shift;
39 6682         8028 my ($tag) = @_;
40 6682 50       9267 return unless defined $tag;
41 6682         8194 my $valid_items = $self->valid_items;
42             # use Data::Dumper; print "[$tag] -- ", Dumper($self), Dumper $valid_items;
43 6682 100       10980 return unless exists $valid_items->{$tag};
44 6677         6451 map { $_->{grammar} } @{$valid_items->{$tag}}
  6696         15120  
  6677         9490  
45             }
46              
47             sub min {
48 1757     1757 1 1708 my $self = shift;
49 1757 50       3228 exists $self->{min} ? $self->{min} : 1
50             }
51              
52             sub max {
53 1757     1757 1 1716 my $self = shift;
54 1757 100       4107 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   650 my $self = shift;
64 595         602 my %valid_items;
65 595         588 for my $item (@{$self->{items}}) {
  595         1101  
66 1757         2648 my $min = $item->min;
67 1757         2378 my $max = $item->max;
68 1757 100       2552 if ($item->{tag}) {
69 1247         1190 push @{$valid_items{$item->{tag}}}, {
  1247         4447  
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       3121 unless my ($value) = $item->{value} =~ /<<(.*)>>/;
77 510 50       970 die "Can't find $value in Gedcom structures"
78             unless my $structure = $self->structure($value);
79 510         732 $item->{structure} = $structure;
80 510         598 while (my($tag, $g) = each %{$structure->valid_items}) {
  2667         3836  
81 2157         8964 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         2189 max => $_->{max} * $max
90             }, @$g;
91             }
92 510 100 66     973 if (exists $item->{items} && @{$item->{items}}) {
  510         1381  
93 8         22 my $extra_items = $item->_valid_items;
94 8         62 while (my ($sub_item, $sub_grammars) = each %valid_items) {
95 88         135 for my $sub_grammar (@$sub_grammars) {
96 88         160 $sub_grammar->{grammar}->valid_items;
97 88         198 while (my ($i, $g) = each %$extra_items) {
98             # print "adding $i to $sub_item\n";
99 176         500 $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         1811 \%valid_items
109             }
110              
111             sub valid_items {
112 62926     62926 1 67792 my $self = shift;
113 62926   66     115565 $self->{_valid_items} ||= $self->_valid_items
114             }
115              
116             1;
117              
118             __END__