File Coverage

blib/lib/Pandoc/Filter/Multifilter.pm
Criterion Covered Total %
statement 33 61 54.1
branch 6 22 27.2
condition 5 22 22.7
subroutine 9 12 75.0
pod 4 4 100.0
total 57 121 47.1


line stmt bran cond sub pod time code
1             package Pandoc::Filter::Multifilter;
2 1     1   854 use strict;
  1         3  
  1         37  
3 1     1   8 use warnings;
  1         3  
  1         36  
4 1     1   24 use 5.010;
  1         4  
5              
6             our $VERSION = '0.34';
7              
8 1     1   8 use parent 'Pandoc::Filter';
  1         4  
  1         14  
9             our @EXPORT_OK = (qw(find_filter apply_filter));
10              
11 1     1   82 use Pandoc::Elements 'pandoc_json';
  1         4  
  1         56  
12 1     1   8 use Pandoc;
  1         4  
  1         9  
13 1     1   895 use IPC::Cmd 'can_run';
  1         60739  
  1         86  
14 1     1   13 use IPC::Run3;
  1         3  
  1         906  
15              
16             sub new {
17 0     0 1 0 bless { }, shift;
18             }
19              
20             sub apply {
21 0     0 1 0 my ( $self, $doc, $format, $meta ) = @_;
22 0 0       0 return $doc if $doc->name ne 'Document';
23              
24 0         0 my $multi = $doc->meta->{multifilter};
25 0 0 0     0 return $doc if !$multi or $multi->name ne 'MetaList';
26              
27             my @filters = map {
28 0 0 0     0 if ($_->name eq 'MetaMap' and $_->{filter}) {
    0 0        
29 0         0 $_->value
30             } elsif ($_->name eq 'MetaString' or $_->name eq 'MetaInlines') {
31 0         0 { filter => $_->value }
32             }
33 0         0 } @{$multi->content};
  0         0  
34              
35 0         0 foreach (@filters) {
36 0         0 my @filter = find_filter($_->{filter});
37 0         0 apply_filter($doc, $format, @filter);
38             }
39              
40 0         0 $doc;
41             }
42              
43             our %SCRIPTS = (
44             hs => 'runhaskell',
45             js => 'node',
46             php => 'php',
47             pl => 'perl',
48             py => 'python',
49             rb => 'ruby',
50             );
51              
52             sub find_filter {
53 4     4 1 146881 my $name = shift;
54 4   33     26 my $data_dir = shift // pandoc_data_dir;
55 4         66 $data_dir =~ s|/$||;
56              
57 4         21 foreach my $filter ("$data_dir/filters/$name", $name) {
58 8 100       135 return $filter if -x $filter;
59 7 100 66     106 if (-e $filter and $filter =~ /\.([a-z]+)$/i) {
60 1 50       14 if ( my $cmd = $SCRIPTS{lc($1)} ) {
61 1 50       7 die "cannot execute filter with $cmd\n" unless can_run($cmd);
62 1         497 return ($cmd, $filter);
63             }
64             }
65             }
66              
67 2   100     12 return (can_run($name) or die "filter not found: $name\n");
68             }
69              
70             sub apply_filter {
71 0     0 1   my ($doc, $format, @filter) = @_;
72              
73 0           my $stdin = $doc->to_json;
74 0           my $stdout = "";
75 0           my $stderr = "";
76              
77 0   0       run3 [@filter, $format // ''], \$stdin, \$stdout, \$stderr;
78 0 0         if ($?) {
79 0 0 0       $stderr .= "\n" if $stderr ne '' and $stderr !~ /\n\z/s;
80 0           die join(' ','filter failed:',@filter)."\n$stderr";
81             }
82              
83 0           my $transformed = eval { pandoc_json($stdout) };
  0            
84 0 0         die join(' ','filter emitted no valid JSON:',@filter)."\n" if $@;
85              
86             # modify original document
87 0           $doc->meta($transformed->meta);
88 0           $doc->content($transformed->content);
89              
90 0           return $doc;
91             }
92              
93             __END__