add image handling and prevent leaking temporary files (ourselves, Archive::Zip might be)
[HTML-AutoConvert.git] / lib / HTML / AutoConvert.pm
1 package HTML::AutoConvert;
2
3 use warnings;
4 use strict;
5
6 =head1 NAME
7
8 HTML::AutoConvert - Best-effort HTML conversion of arbitrary files to HTML.
9
10 =head1 VERSION
11
12 Version 0.01
13
14 =cut
15
16 our $VERSION = '0.01';
17
18 =head1 SYNOPSIS
19
20     use HTML::AutoConvert;
21
22     my $converter = HTML::AutoConvert->new();
23     #or to turn on debugging
24     my $converter = HTML::AutoConvert->new('debug'=>1);
25
26     my $html = $converter->html_convert( $file );
27     # OR 
28     my( $html, @images ) = $converter->html_convert( $file );
29
30     #turn on or off debugging later
31     $converter->debug(1);
32
33 =head1 DESCRIPTION
34
35 Convert arbitrary file types to HTML.
36
37 #=head1 EXPORT
38 #
39 #doc on also using html_convert functional interface
40
41 =head1 FUNCTIONS
42
43 =head2 new
44
45 =cut
46
47 sub new {
48   my $proto = shift;
49   my $class = ref($proto) || $proto;
50
51   my $opts = ref($_[0]) ? shift : { @_ };
52   my $self = $opts; #{};
53   bless ($self, $class);
54
55   $self->find_handlers;
56
57   $self;
58
59 }
60
61 =head2 html_convert FILENAME
62
63 Convert the given filename to HTML.
64
65 In a scalar context, simply returns the HTML output as a scalar.
66
67     my $html = $converter->html_convert( $file );
68
69 In a list context, returns a list consisting of the HTML output as a scalar,
70 followed by references for each image extracted, if any.  Each image reference
71 is a list reference consisting of two elements: the first is the filename and
72 the second is the image itself.
73
74     my( $html, @images ) = $converter->html_convert( $file );
75     foreach my $image ( @images ) {
76       my( $filename, $data ) = @$image;
77       #...
78     }
79
80 =cut
81
82 sub html_convert {
83   my( $self, $file ) = ( shift, shift );
84   my $opt = ref($_[0]) ? shift : { @_ };
85
86   $self->{'file'} = $file;
87
88   my @handlers = $self->handlers
89     or die "no registered handlers for filetype ". $self->filetype( $file );
90
91   my( $converted, $html, $errors ) = ( 0, '', '' );
92   my @imgs = ();
93   foreach my $handler ( @handlers ) {
94
95     my $module = 'HTML::AutoConvert::'. $handler->{'module'};
96
97     my $tmp_html = '';
98     my @tmp_imgs = ();
99     if ( $handler->{'returns_images'} && wantarray ) {
100       ( $tmp_html, @tmp_imgs ) =
101         eval { $module->html_convert( $self->{'file'} ) };
102     } else {
103       $tmp_html =
104         eval { $module->html_convert( $self->{'file'} ) };
105     }
106
107     if ( $@ ) {
108        my $tmp_err = "conversion with $module failed: $@\n";
109        warn $tmp_err if $self->{'debug'};
110        $errors .= $tmp_err;
111        next;
112     }
113
114     $converted = 1;
115     $html = $tmp_html;
116     @imgs = @tmp_imgs;
117     last;
118   }
119
120   die "couldn't convert $file:\n$errors" unless $converted;
121
122   if ( wantarray ) {
123     ( $html, @imgs );
124   } else {
125     $html;
126   }
127
128 }
129
130 =head2 debug
131
132 Get or set the debugging level
133
134 =cut
135
136 sub debug {
137   my $self = shift;
138   $self->{'debug'} = shift if @_;
139   $self->{'debug'};
140 }
141
142 =head1 INTERNAL FUNCTIONS
143
144 =head2 find_handlers
145
146 Search for installed HTML::AutoConvert::* plugins.
147
148 =cut
149
150 sub find_handlers {
151   my $self = shift;
152
153   my %types;
154   foreach my $INC ( @INC ) {
155     warn "globbing $INC/HTML/AutoConvert/*.pm\n" if $self->{'debug'};
156     foreach my $file ( glob("$INC/HTML/AutoConvert/*.pm") ) {
157       warn "attempting to load handler info from $file\n" if $self->{'debug'};
158       $file =~ /\/(\w+)\.pm$/ or do {
159         warn "unrecognized file in $INC/HTML/AutoConvert/: $file\n";
160         next;
161       };
162       my $mod = $1;
163       my $info = eval "use HTML::AutoConvert::$mod; ".
164                       "\\%HTML::AutoConvert::$mod\::info;";
165       if ( $@ ) {
166         die "error using HTML::AutoConvert::$mod (skipping): $@\n" if $@;
167         next;
168       }
169       unless ( keys %$info ) {
170         warn "no %info hash in HTML::AutoConvert::$mod, skipping\n" if $self->{'debug'};
171         next;
172       }
173       warn "got handler info from HTML::AutoConvert::$mod: $info\n" if $self->{'debug'};
174       if ( exists($info->{'disabled'}) && $info->{'disabled'} ) {
175         warn "skipping disabled handler HTML::AutoConvert::$mod" if $self->{'debug'};
176         next;
177       }
178
179       my $types = $info->{'types'};
180       $types = [ $types ] unless ref($types);
181
182       foreach my $type ( @$types ) {
183         $types{lc($type)}->{$mod} = { 'module' => $mod, %$info };
184       }
185
186     }
187   }
188
189   $self->{'handlers'} = \%types;
190
191 }
192
193 =head2 handlers
194
195 Return the available handlers for the current file.
196
197 =cut
198
199 sub handlers {
200   my( $self ) = @_;
201
202   my $types = $self->{'handlers'};
203
204   my $type = $self->filetype;
205
206   sort { $a->{'weight'} <=> $b->{'weight'} }
207        values %{ $types->{lc($type)} };
208 }
209
210 =head2
211
212
213 =head2 filetype
214
215 Determine the type of the current file.
216
217 =cut
218
219 #just use the file extension...  could also use File::MMagic or something
220 sub filetype {
221   my $self = shift;
222
223   my $file = $self->{'file'};
224   $file =~ /\.(\w{3,4})$/ or die "can't parse $file for extension";
225   lc($1);
226 }
227
228 =head1 AUTHOR
229
230 Ivan Kohler, C<< <ivan-html-autoconvert at 420.am> >>
231
232 =head1 BUGS
233
234 Please report any bugs or feature requests to C<bug-html-autoconvert at rt.cpan.org>, or through
235 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HTML-AutoConvert>.  I will be notified, and then you'll
236 automatically be notified of progress on your bug as I make changes.
237
238 =head1 SUPPORT
239
240 You can find documentation for this module with the perldoc command.
241
242     perldoc HTML::AutoConvert
243
244 You can also look for information at:
245
246 =over 4
247
248 =item * RT: CPAN's request tracker
249
250 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-AutoConvert>
251
252 =item * AnnoCPAN: Annotated CPAN documentation
253
254 L<http://annocpan.org/dist/HTML-AutoConvert>
255
256 =item * CPAN Ratings
257
258 L<http://cpanratings.perl.org/d/HTML-AutoConvert>
259
260 =item * Search CPAN
261
262 L<http://search.cpan.org/dist/HTML-AutoConvert>
263
264 =back
265
266
267 =head1 ACKNOWLEDGEMENTS
268
269
270
271 =head1 COPYRIGHT & LICENSE
272
273 Copyright 2008 Freeside Internet Services, Inc.
274 All rights reserved.
275
276 This program is free software; you can redistribute it and/or modify it
277 under the same terms as Perl itself.
278
279 =cut
280
281 1; # End of HTML::AutoConvert
282