File Coverage

blib/lib/Forest/Tree/Builder/SimpleTextFile.pm
Criterion Covered Total %
statement 32 38 84.2
branch 6 8 75.0
condition 1 3 33.3
subroutine 5 7 71.4
pod 0 2 0.0
total 44 58 75.8


line stmt bran cond sub pod time code
1             package Forest::Tree::Builder::SimpleTextFile;
2 10     10   67 use Moose;
  10         24  
  10         108  
3              
4             our $VERSION = '0.10';
5             our $AUTHORITY = 'cpan:STEVAN';
6              
7 10     10   116002 no warnings 'recursion';
  10         31  
  10         7573  
8              
9             with qw(Forest::Tree::Builder::Callback); # for compatibility with overriding create_new_subtree, otherwise invisible
10              
11             has fh => (
12             isa => "FileHandle",
13             is => "ro",
14             required => 1,
15             );
16              
17             has 'tab_width' => (
18             is => 'rw',
19             isa => 'Int',
20             default => 4
21             );
22              
23             has 'parser' => (
24             is => 'rw',
25             isa => 'CodeRef',
26             lazy => 1,
27             builder => 'build_parser',
28             );
29              
30             sub build_parser {
31             return sub {
32 0     0   0 my ($self, $line) = @_;
33 0         0 my ($indent, $node) = ($line =~ /^(\s*)(.*)$/);
34 0         0 my $depth = ((length $indent) / $self->tab_width);
35 0         0 return ($depth, $node);
36             }
37 0     0 0 0 }
38              
39 76     76 0 3844 sub parse_line { $_[0]->parser->(@_) }
40              
41             sub _build_subtrees {
42 8     8   19 my $self = shift;
43              
44 8         20 my $cur_children = [];
45 8         53 my @stack;
46              
47 8         665 my $fh = $self->fh;
48              
49 8         74 while ( defined(my $line = <$fh>) ) {
50              
51 76         138 chomp($line);
52              
53 76 50 33     422 next if !$line || $line =~ /^#/;
54              
55 76         214 my ($depth, $node, @rest) = $self->parse_line($line);
56              
57 76 100       740 if ( $depth > @stack ) {
    100          
58 38 50       123 if ( $depth = @stack + 1 ) {
59 38         60 push @stack, $cur_children;
60 38         117 $cur_children = $cur_children->[-1]{children} = [];
61             } else {
62 0         0 die "Parse Error : the difference between the depth ($depth) and " .
63             "the tree depth (" . scalar(@stack) . ") is too much (" .
64             ($depth - @stack) . ") at line:\n'$line'";
65             }
66             } elsif ( $depth < @stack ) {
67 14         56 while ( $depth < @stack ) {
68 21         46 foreach my $node ( @$cur_children ) {
69 28         144 $node = $self->create_new_subtree(%$node);
70             }
71              
72 21         73 $cur_children = pop @stack;
73             }
74             }
75              
76 76         593 push @$cur_children, { node => $node, @rest };
77             }
78              
79 8         38 while ( @stack ) {
80 17         114 $_ = $self->create_new_subtree(%$_) for @$cur_children;
81 17         66 $cur_children = pop @stack;
82             }
83              
84 8         427 return [ map { $self->create_new_subtree(%$_) } @$cur_children ];
  26         135  
85             }
86              
87              
88             __PACKAGE__->meta->make_immutable;
89              
90 10     10   77 no Moose; 1;
  10         21  
  10         74  
91              
92             __END__
93              
94             =head1 NAME
95              
96             Forest::Tree::Builder::SimpleTextFile - Parse trees from indented ASCII files
97              
98             =head1 SYNOPSIS
99              
100             use Path::Class;
101              
102             my $file = file($path);
103              
104             my $builder = Forest::Tree::Builder::SimpleTextFile->new(
105             fh => $file->openr,
106             );
107              
108             my $tree = $builder->tree;
109              
110             =head1 DESCRIPTION
111              
112             This module replaces L<Forest::Tree::Reader::SimpleTextFile> with a declarative
113             api instead of an imperative one.
114              
115             =head1 ATTRIBUTES
116              
117             =over 4
118              
119             =item fh
120              
121             The filehandle to read from.
122              
123             Required.
124              
125             =item parser
126              
127             A coderef that parses a single line from C<fh> and returns the node depth and
128             its value.
129              
130             Defaults to space indented text. See also L</tab_width>.
131              
132             =item tab_width
133              
134             The indentation level for the default parser. Defaults to 4, which means that
135             four spaces equate to one level of nesting.
136              
137             =back
138              
139             =head1 BUGS
140              
141             All complex software has bugs lurking in it, and this module is no
142             exception. If you find a bug please either email me, or add the bug
143             to cpan-RT.
144              
145             =head1 AUTHOR
146              
147             Yuval Kogman
148              
149             =head1 COPYRIGHT AND LICENSE
150              
151             Copyright 2008-2014 Infinity Interactive, Inc.
152              
153             L<http://www.iinteractive.com>
154              
155             This library is free software; you can redistribute it and/or modify
156             it under the same terms as Perl itself.
157              
158             =cut
159              
160