File Coverage

blib/lib/Text/Markup/Rest.pm
Criterion Covered Total %
statement 32 46 69.5
branch 0 8 0.0
condition n/a
subroutine 11 13 84.6
pod n/a
total 43 67 64.1


line stmt bran cond sub pod time code
1             package Text::Markup::Rest;
2              
3 1     1   2753 use 5.8.1;
  1         3  
4 1     1   6 use strict;
  1         3  
  1         21  
5 1     1   6 use warnings;
  1         2  
  1         25  
6 1     1   4 use File::Spec;
  1         2  
  1         15  
7 1     1   38 use File::Basename ();
  1         2  
  1         30  
8 1     1   5 use constant WIN32 => $^O eq 'MSWin32';
  1         2  
  1         95  
9 1     1   8 use Symbol 'gensym';
  1         2  
  1         52  
10 1     1   558 use IPC::Open3;
  1         2917  
  1         150  
11              
12             our $VERSION = '0.25';
13              
14             # Find Python (process stolen from App::Info).
15             my ($PYTHON, $RST2HTML);
16             for my $exe (WIN32 ? 'python3.exe' : 'python3') {
17             my @path = (
18             File::Spec->path,
19             WIN32 ? (map { "C:\\Python$_" } '', 27, 26, 25) : ()
20             );
21              
22             for my $p (@path) {
23             my $path = File::Spec->catfile($p, $exe);
24             next unless -f $path && -x $path;
25             $PYTHON = $path;
26             last;
27             }
28              
29             unless ($PYTHON) {
30 1     1   9 use Carp;
  1         2  
  1         138  
31             my $sep = WIN32 ? ';' : ':';
32             Carp::croak(
33             "Cannot find $exe in path " . join $sep => @path
34             );
35             }
36              
37             # We have python, let's find out if we have docutils.
38             my $output = gensym;
39             my $pid = open3 undef, $output, $output, $PYTHON, '-c', 'import docutils';
40             waitpid $pid, 0;
41             if ($?) {
42 1     1   7 use Carp;
  1         2  
  1         129  
43             local $/;
44             Carp::croak(
45             qq{Missing required Python "docutils" module\n},
46             <$output>
47             );
48             }
49              
50             # We ship with our own rst2html that's lenient with unknown directives.
51             $RST2HTML = File::Spec->catfile(
52             File::Basename::dirname(__FILE__),
53             'rst2html_lenient.py'
54             );
55              
56             # Make sure it looks like it will work.
57             $pid = open3 undef, $output, $output, $PYTHON, $RST2HTML, '--test-patch';
58             waitpid $pid, 0;
59             if ($?) {
60 1     1   9 use Carp;
  1         3  
  1         492  
61             local $/;
62             Carp::croak(
63             qq{$RST2HTML will not execute\n},
64             <$output>
65             );
66             }
67             }
68              
69             # Optional arguments to pass to rst2html
70             my @OPTIONS = qw(
71             --no-raw
72             --no-file-insertion
73             --stylesheet=
74             --cloak-email-address
75             --no-generator
76             --quiet
77             );
78              
79             # Options to improve rendering of Sphinx documents
80             my @SPHINX_OPTIONS = qw(
81             --dir-ignore toctree
82             --dir-ignore highlight
83             --dir-ignore index
84             --dir-ignore default-domain
85              
86             --dir-nested note
87             --dir-nested warning
88             --dir-nested versionadded
89             --dir-nested versionchanged
90             --dir-nested deprecated
91             --dir-nested seealso
92             --dir-nested hlist
93             --dir-nested glossary
94              
95             --dir-notitle code-block
96              
97             --dir-nested module
98             --dir-nested function
99             --output-encoding utf-8
100             );
101             # note: domains directive (last 2 options) incomplete
102              
103             sub parser {
104 0     0     my ($file, $encoding, $opts) = @_;
105 0           my $html = do {
106 0           my $fh = _fh(
107             $PYTHON, $RST2HTML,
108             @OPTIONS, @SPHINX_OPTIONS,
109             '--input-encoding', $encoding,
110             $file
111             );
112 0           local $/;
113 0           <$fh>;
114             };
115              
116             # Make sure we have something.
117 0 0         return undef if $html =~ m{\s+}ms;
118              
119             # Alas, --no-generator does not remove the generator meta tag. :-(
120 0           $html =~ s{^\s*]+>\n}{}ms;
121              
122 0           return $html;
123             }
124              
125             # Stolen from SVN::Notify.
126             sub _fh {
127             # Ignored; looks like docutils always emits UTF-8.
128 0     0     if (WIN32) {
129             my $cmd = q{"} . join(q{" "}, @_) . q{"|};
130             open my $fh, $cmd or die "Cannot fork: $!\n";
131             return $fh;
132             }
133              
134 0           my $pid = open my $fh, '-|';
135 0 0         die "Cannot fork: $!\n" unless defined $pid;
136              
137 0 0         if ($pid) {
138             # Parent process, return the file handle.
139 0           return $fh;
140             } else {
141             # Child process. Execute the commands.
142 0 0         exec @_ or die "Cannot exec $_[0]: $!\n";
143             # Not reached.
144             }
145             }
146              
147             1;
148             __END__