source: main/trunk/greenstone2/perllib/cpan/Mojo/Exception.pm@ 32205

Last change on this file since 32205 was 32205, checked in by ak19, 6 years ago

First set of commits to do with implementing the new 'paged_html' output option of PDFPlugin that uses using xpdftools' new pdftohtml. So far tested only on Linux (64 bit), but things work there so I'm optimistically committing the changes since they work. 2. Committing the pre-built Linux binaries of XPDFtools for both 32 and 64 bit built by the XPDF group. 2. To use the correct bitness variant of xpdftools, setup.bash now exports the BITNESS env var, consulted by gsConvert.pl. 3. All the perl code changes to do with using xpdf tools' pdftohtml to generate paged_html and feed it in the desired form into GS(3): gsConvert.pl, PDFPlugin.pm and its parent ConvertBinaryPFile.pm have been modified to make it all work. xpdftools' pdftohtml generates a folder containing an html file and a screenshot for each page in a PDF (as well as an index.html linking to each page's html). However, we want a single html file that contains each individual 'page' html's content in a div, and need to do some further HTML style, attribute and structure modifications to massage the xpdftool output to what we want for GS. In order to parse and manipulate the HTML 'DOM' to do this, we're using the Mojo::DOM package that Dr Bainbridge found and which he's compiled up. Mojo::DOM is therefore also committed in this revision. Some further changes and some display fixes are required, but need to check with the others about that.

File size: 5.3 KB
Line 
1package Mojo::Exception;
2use Mojo::Base -base;
3use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
4
5use Mojo::Util 'decode';
6
7has [qw(frames line lines_after lines_before)] => sub { [] };
8has message => 'Exception!';
9has 'verbose';
10
11sub inspect {
12 my ($self, @sources) = @_;
13
14 # Extract file and line from message
15 my @files;
16 my $msg = $self->lines_before([])->line([])->lines_after([])->message;
17 while ($msg =~ /at\s+(.+?)\s+line\s+(\d+)/g) { unshift @files, [$1, $2] }
18
19 # Extract file and line from stack trace
20 if (my $zero = $self->frames->[0]) { push @files, [$zero->[1], $zero->[2]] }
21
22 # Search for context in files
23 for my $file (@files) {
24 next unless -r $file->[0] && open my $handle, '<', $file->[0];
25 $self->_context($file->[1], [[<$handle>]]);
26 return $self;
27 }
28
29 # Search for context in sources
30 $self->_context($files[-1][1], [map { [split "\n"] } @sources]) if @sources;
31
32 return $self;
33}
34
35sub new { @_ > 1 ? shift->SUPER::new(message => shift) : shift->SUPER::new }
36
37sub to_string {
38 my $self = shift;
39
40 my $str = $self->message;
41 return $str unless $self->verbose;
42
43 $str .= "\n" unless $str =~ /\n$/;
44 $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_before};
45 $str .= $self->line->[0] . ': ' . $self->line->[1] . "\n" if $self->line->[0];
46 $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_after};
47
48 return $str;
49}
50
51sub throw { CORE::die shift->new(shift)->trace(2)->inspect }
52
53sub trace {
54 my ($self, $start) = (shift, shift // 1);
55 my @frames;
56 while (my @trace = caller($start++)) { push @frames, \@trace }
57 return $self->frames(\@frames);
58}
59
60sub _append {
61 my ($stack, $line) = @_;
62 $line = decode('UTF-8', $line) // $line;
63 chomp $line;
64 push @$stack, $line;
65}
66
67sub _context {
68 my ($self, $num, $sources) = @_;
69
70 # Line
71 return unless defined $sources->[0][$num - 1];
72 $self->line([$num]);
73 _append($self->line, $_->[$num - 1]) for @$sources;
74
75 # Before
76 for my $i (2 .. 6) {
77 last if ((my $previous = $num - $i) < 0);
78 unshift @{$self->lines_before}, [$previous + 1];
79 _append($self->lines_before->[0], $_->[$previous]) for @$sources;
80 }
81
82 # After
83 for my $i (0 .. 4) {
84 next if ((my $next = $num + $i) < 0);
85 next unless defined $sources->[0][$next];
86 push @{$self->lines_after}, [$next + 1];
87 _append($self->lines_after->[-1], $_->[$next]) for @$sources;
88 }
89}
90
911;
92
93=encoding utf8
94
95=head1 NAME
96
97Mojo::Exception - Exceptions with context
98
99=head1 SYNOPSIS
100
101 use Mojo::Exception;
102
103 # Throw exception and show stack trace
104 eval { Mojo::Exception->throw('Something went wrong!') };
105 say "$_->[1]:$_->[2]" for @{$@->frames};
106
107 # Customize exception
108 eval {
109 my $e = Mojo::Exception->new('Died at test.pl line 3.');
110 die $e->trace(2)->inspect->verbose(1);
111 };
112 say $@;
113
114=head1 DESCRIPTION
115
116L<Mojo::Exception> is a container for exceptions with context information.
117
118=head1 ATTRIBUTES
119
120L<Mojo::Exception> implements the following attributes.
121
122=head2 frames
123
124 my $frames = $e->frames;
125 $e = $e->frames([$frame1, $frame2]);
126
127Stack trace if available.
128
129 # Extract information from the last frame
130 my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext,
131 $is_require, $hints, $bitmask, $hinthash) = @{$e->frames->[-1]};
132
133=head2 line
134
135 my $line = $e->line;
136 $e = $e->line([3, 'die;']);
137
138The line where the exception occurred if available.
139
140=head2 lines_after
141
142 my $lines = $e->lines_after;
143 $e = $e->lines_after([[4, 'say $foo;'], [5, 'say $bar;']]);
144
145Lines after the line where the exception occurred if available.
146
147=head2 lines_before
148
149 my $lines = $e->lines_before;
150 $e = $e->lines_before([[1, 'my $foo = 23;'], [2, 'my $bar = 24;']]);
151
152Lines before the line where the exception occurred if available.
153
154=head2 message
155
156 my $msg = $e->message;
157 $e = $e->message('Died at test.pl line 3.');
158
159Exception message, defaults to C<Exception!>.
160
161=head2 verbose
162
163 my $bool = $e->verbose;
164 $e = $e->verbose($bool);
165
166Enable context information for L</"to_string">.
167
168=head1 METHODS
169
170L<Mojo::Exception> inherits all methods from L<Mojo::Base> and implements the
171following new ones.
172
173=head2 inspect
174
175 $e = $e->inspect;
176 $e = $e->inspect($source1, $source2);
177
178Inspect L</"message">, L</"frames"> and optional additional sources to fill
179L</"lines_before">, L</"line"> and L</"lines_after"> with context information.
180
181=head2 new
182
183 my $e = Mojo::Exception->new;
184 my $e = Mojo::Exception->new('Died at test.pl line 3.');
185
186Construct a new L<Mojo::Exception> object and assign L</"message"> if necessary.
187
188=head2 to_string
189
190 my $str = $e->to_string;
191
192Render exception.
193
194 # Render exception with context
195 say $e->verbose(1)->to_string;
196
197=head2 throw
198
199 Mojo::Exception->throw('Something went wrong!');
200
201Throw exception from the current execution context.
202
203 # Longer version
204 die Mojo::Exception->new('Something went wrong!')->trace->inspect;
205
206=head2 trace
207
208 $e = $e->trace;
209 $e = $e->trace($skip);
210
211Generate stack trace and store all L</"frames">, defaults to skipping C<1> call
212frame.
213
214 # Skip 3 call frames
215 $e->trace(3);
216
217 # Skip no call frames
218 $e->trace(0);
219
220=head1 OPERATORS
221
222L<Mojo::Exception> overloads the following operators.
223
224=head2 bool
225
226 my $bool = !!$e;
227
228Always true.
229
230=head2 stringify
231
232 my $str = "$e";
233
234Alias for L</"to_string">.
235
236=head1 SEE ALSO
237
238L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
239
240=cut
Note: See TracBrowser for help on using the repository browser.