File Coverage

blib/lib/Lingua/Poetry/Haiku/Finder.pm
Criterion Covered Total %
statement 76 79 96.2
branch 10 12 83.3
condition 2 2 100.0
subroutine 15 16 93.7
pod 3 3 100.0
total 106 112 94.6


line stmt bran cond sub pod time code
1 1     1   884 use 5.012;
  1         4  
2 1     1   6 use strict;
  1         1  
  1         21  
3 1     1   5 use warnings;
  1         2  
  1         80  
4              
5             package Lingua::Poetry::Haiku::Finder;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10 1     1   732 use Moo;
  1         12938  
  1         16  
11 1     1   2362 use Types::Standard -types;
  1         109034  
  1         15  
12 1     1   5537 use List::Util 'sum0';
  1         2  
  1         99  
13 1     1   658 use Lingua::Sentence;
  1         65835  
  1         40  
14 1     1   562 use namespace::autoclean;
  1         13009  
  1         4  
15              
16 1     1   582 use Lingua::Poetry::Haiku::Finder::Sentence;
  1         5  
  1         1064  
17              
18             my @LINE_LENGTHS = ( 5, 7, 5 );
19             my $HAIKU_LENGTH = sum0 @LINE_LENGTHS;
20              
21             has text => (
22             is => 'ro',
23             isa => Str,
24             required => !!1,
25             );
26              
27             has sentences => (
28             is => 'lazy',
29             isa => ArrayRef[ InstanceOf[ __PACKAGE__ . '::Sentence' ] ],
30             init_arg => undef,
31             );
32              
33             has haikus => (
34             is => 'lazy',
35             isa => ArrayRef[ Str ],
36             init_arg => undef,
37             );
38              
39             has _splitter => (
40             is => 'lazy',
41             isa => Object,
42 1     1   47 builder => sub { 'Lingua::Sentence'->new("en") },
43             handles => {
44             '_split_array' => 'split_array',
45             },
46             );
47              
48             {
49             my $class = __PACKAGE__ . '::Sentence';
50            
51             sub _build_sentences {
52 1     1   13 my ( $self ) = ( shift );
53            
54 1         6 my $text = $self->text;
55 1         1318 $text =~ s/\s+/ /sg;
56 1         7 $text =~ s/^\s+//s;
57 1         486 $text =~ s/\s+$//s;
58            
59             return [
60 1         38 map $class->new( text => $_ ), $self->_split_array( $text )
61             ];
62             }
63             }
64              
65             sub _format_haiku {
66 3     3   12 my ( $self, $sentences ) = ( shift, @_ );
67             my @parts = map {
68 4         129 my $end = ( __PACKAGE__ . '::NonWord' )->new( text => ' ' );
69 4         191 @{ $_->parts }, $end;
  4         79  
70 3         10 } @{ $sentences };
  3         10  
71            
72 3         57 my @lines;
73 3         7 my $current_line = 0;
74            
75 3         18 while ( @parts ) {
76 84         133 my $part = shift @parts;
77 84 100       190 if ( $part->is_word ) {
78 40 100       58 my $current_line_length = sum0 map $_->syllables, @{ $lines[$current_line] || [] };
  40         701  
79 40 100       103 if ( $current_line_length >= $LINE_LENGTHS[$current_line] ) {
80 6         67 ++$current_line;
81             }
82             }
83 84   100     132 push @{ $lines[$current_line] ||= [] }, $part;
  84         278  
84             }
85            
86             return join "\n", map {
87 3         11 my @line = @$_;
  9         21  
88 9         123 my $text = join "", map $_->text, @line;
89 9         55 $text =~ s/\s+/ /sg;
90 9         23 $text =~ s/^\s+//s;
91 9         34 $text =~ s/\s+$//s;
92 9         58 $text;
93             } @lines;
94             }
95              
96             sub _build_haikus {
97 1     1   2947 my ( $self ) = ( shift );
98            
99 1         3 my @sentences = @{ $self->sentences };
  1         22  
100 1         34817 my @found;
101 1         10 STARTER: for my $start_index ( 0 .. $#sentences ) {
102 138         750 ENDER: for my $end_index ( $start_index .. $#sentences ) {
103 176         806 my @slice = @sentences[ $start_index .. $end_index ];
104 176         3560 my $slice_syllables = sum0 map $_->syllables, @slice;
105            
106 176 100       6240 if ( $slice_syllables == $HAIKU_LENGTH ) {
    100          
107 3         27 push @found, $self->_format_haiku( \@slice );
108             }
109             elsif ( $slice_syllables > $HAIKU_LENGTH ) {
110 138         782 next STARTER;
111             }
112             }
113             }
114            
115 1         42 return \@found;
116             }
117              
118             sub from_text {
119 1     1 1 5 my ( $class, $text ) = ( shift, @_ );
120 1         8 return $class->new( text => $text );
121             }
122              
123             sub from_filehandle {
124 1     1 1 644 my ( $class, $fh ) = ( shift, @_ );
125 1         2 my $text = do { local $/; <$fh> };
  1         6  
  1         112  
126 1         8 return $class->from_text( $text );
127             }
128              
129             sub from_filename {
130 0     0 1   my ( $class, $filename ) = ( shift, @_ );
131 0 0         open my $fh, '<', $filename or die "Cannot open $filename: $!";
132 0           return $class->from_filehandle( $fh );
133             }
134              
135             1;
136              
137             __END__