File Coverage

blib/lib/PDF/Collage/Template.pm
Criterion Covered Total %
statement 135 170 79.4
branch 12 24 50.0
condition 9 25 36.0
subroutine 24 30 80.0
pod 1 1 100.0
total 181 250 72.4


line stmt bran cond sub pod time code
1             package PDF::Collage::Template;
2 2     2   26 use v5.24;
  2         6  
3 2     2   11 use warnings;
  2         4  
  2         85  
4             { our $VERSION = '0.001' }
5              
6 2     2   11 use Carp;
  2         4  
  2         119  
7 2     2   1045 use Template::Perlish ();
  2         7955  
  2         47  
8 2     2   13 use Data::Resolver ();
  2         4  
  2         31  
9 2     2   2208 use PDF::Builder;
  2         569469  
  2         94  
10              
11 2     2   1177 use Moo;
  2         16160  
  2         19  
12 2     2   3015 use experimental qw< signatures >;
  2         6  
  2         17  
13 2     2   354 no warnings qw< experimental::signatures >;
  2         5  
  2         69  
14              
15 2     2   1018 use namespace::clean;
  2         30062  
  2         13  
16              
17             has commands => (is => ro => required => 1);
18             has functions => (is => 'lazy');
19             has logger => (is => 'lazy');
20             has metadata => (is => 'lazy');
21              
22             has _data => (is => 'lazy');
23             has _defaults => (is => 'lazy');
24             has _fonts => (is => 'lazy');
25             has _pdf => (is => 'lazy');
26              
27 0     0   0 sub _build_functions ($self) { return {} }
  0         0  
  0         0  
  0         0  
28 0     0   0 sub _build_logger ($self) {
  0         0  
  0         0  
29 0         0 eval { require Log::Any; Log::Any->get_logger }
  0         0  
  0         0  
30             }
31 0     0   0 sub _build_metadata ($self) { return {} }
  0         0  
  0         0  
  0         0  
32 0     0   0 sub _build__data ($self) { return {} }
  0         0  
  0         0  
  0         0  
33 17     17   245 sub _build__defaults ($self) { return {} }
  17         29  
  17         35  
  17         69  
34 16     16   257 sub _build__fonts ($self) { return {} }
  16         27  
  16         25  
  16         373  
35 16     16   193 sub _build__pdf ($self) { return PDF::Builder->new }
  16         47  
  16         28  
  16         121  
36              
37 17     17 1 4509 sub render ($self, $data) {
  17         44  
  17         40  
  17         42  
38 17         398 $self->new( # hand over to a disposable clone
39             commands => $self->commands,
40             functions => $self->functions,
41             _data => $data,
42             )->_real_render;
43             } ## end sub render
44              
45 17     17   1001 sub _real_render ($self) {
  17         32  
  17         29  
46 17         63 for my $command ($self->commands->@*) {
47 66         300394 my $op = $command->{op} =~ s{-}{_}rgmxs;
48 66 50       502 my $method = $self->can('_op_' . $op)
49             or croak "unsupported op<$command->{op}>";
50 66         273 $self->$method($command);
51             } ## end for my $command ($self->...)
52 16         470 return $self->_pdf;
53             } ## end sub _real_render
54              
55 194     194   284 sub _tpr ($self, $tmpl) {
  194         296  
  194         279  
  194         286  
56 194         4252 return Template::Perlish::render($tmpl, $self->_data,
57             {functions => $self->functions});
58             }
59              
60 49     49   108 sub _expand ($self, $command, @keys) {
  49         85  
  49         80  
  49         169  
  49         65  
61 49         114 my %auto_expand = map { $_ => 1 } @keys;
  260         620  
62 49         1264 my %overall = ($self->_defaults->%*, $command->%*);
63 49         852 my %retval;
64 49         279 for my $key (sort { $a cmp $b } keys %overall) {
  547         837  
65 309         125456 my $nkey = $key =~ s{-}{_}rgmxs;
66 309 50       792 next if exists $retval{$nkey};
67 309         518 my $value = $overall{$key};
68 309 100       1036 $retval{$nkey} = $auto_expand{$nkey} ? $self->_tpr($value) : $value;
69             } ## end for my $key (sort { $a ...})
70 49         38606 return \%retval;
71             } ## end sub _expand
72 65 100   65   609 sub __pageno ($input) { return $input eq 'last' ? 0 : $input }
  65         123  
  65         101  
  65         328  
73 16   33 16   45 sub _font ($s, $key) { $s->_fonts->{$key} //= $s->_pdf->font($key) }
  16         43  
  16         39  
  16         26  
  16         438  
74              
75 16     16   52 sub _op_add_image ($self, $command) {
  16         39  
  16         32  
  16         31  
76 16         72 my $opts = $self->_expand($command, qw< page path x y width height >);
77 16   50     387 my $page = $self->_pdf->open_page(__pageno($opts->{page} // 'last'));
78 16         1337 my $image = $self->_pdf->image($opts->{path});
79 16         543992 $page->object($image, $opts->@{qw< x y width height >});
80 16         11828 return;
81             } ## end sub _op_add_image
82              
83 17     17   30 sub _op_add_page ($self, $command) {
  17         21  
  17         37  
  17         20  
84 17         63 my $opts =
85             $self->_expand($command, qw< page from from_path from_page >);
86 17   50     198 my $target_n = __pageno($opts->{page} // 'last');
87             defined(my $source_path = $opts->{from} // $opts->{from_path})
88 17 50 33     97 or return $self->_pdf->page($target_n);
89 17         141 my $source = PDF::Builder->open($source_path);
90 16   50     150039 my $source_n = __pageno($opts->{from_page} // 'last');
91 16         421 return $self->_pdf->import_page($source, $source_n, $target_n);
92             } ## end sub _op_add_page
93              
94 16     16   46 sub _op_add_text ($self, $command) {
  16         39  
  16         36  
  16         33  
95 16         78 my $opts =
96             $self->_expand($command, qw< page font font_family font_size x y >);
97 16   50     384 my $page = $self->_pdf->open_page(__pageno($opts->{page} // 'last'));
98 16         786 my $text = $page->text;
99              
100 16   33     5310 my $font = $self->_font($opts->{font} // $opts->{font_family});
101 16         762948 $text->font($font, $opts->{font_size});
102              
103 16   50     4522 $text->position(map { $_ // 0 } $opts->@{qw< x y >});
  32         173  
104              
105             my $content =
106 16         1847 $self->_render_text($opts->@{qw< text text_template text_var >});
107 16   50     27218 $text->text($content // '');
108              
109 16         257500 return $self;
110             } ## end sub _op_add_text
111              
112 16     16   46 sub _render_text ($self, $plain, $template, $crumbs) {
  16         40  
  16         29  
  16         36  
  16         37  
  16         27  
113 16 50       50 return $plain if defined $plain;
114 16 50       83 return $self->_tpr($template) if defined $template;
115 0 0 0     0 return Template::Perlish::traverse($self->_data, $crumbs) // ''
116             if defined $crumbs;
117 0         0 return;
118             } ## end sub _render_text
119              
120 17     17   42 sub _op_set_defaults ($self, $command) {
  17         29  
  17         24  
  17         26  
121 17         371 my $defaults = $self->_defaults;
122 17         99 while (my ($key, $value) = each $command->%*) {
123 51 100       145 next if $key eq 'op';
124 34 50       75 if (defined $value) { $defaults->{$key} = $value }
  34         124  
125 0         0 else { delete $defaults->{$key} }
126             }
127 17         54 return;
128             } ## end sub _op_set_defaults
129              
130 0     0     sub _default_log ($self, $command) {
  0            
  0            
  0            
131 0           warn "[$command->{level}] $command->{message}\n";
132 0           return $self;
133             }
134              
135 0     0     sub _op_log ($self, $command) {
  0            
  0            
  0            
136 0 0         my $logger = $self->logger or return $self->_default_log($command);
137 0 0 0       my $method = $logger->can(lc($command->{level}) // 'info')
138             or return $self->_default_log($command);
139 0           $logger->$method($command->{message});
140 0           return $self;
141             }
142              
143             1;