File Coverage

blib/lib/App/optex/textconv.pm
Criterion Covered Total %
statement 35 94 37.2
branch 0 28 0.0
condition n/a
subroutine 12 23 52.1
pod 0 9 0.0
total 47 154 30.5


line stmt bran cond sub pod time code
1             package App::optex::textconv;
2              
3             our $VERSION = '0.1401';
4              
5 1     1   730 use v5.14;
  1         3  
6 1     1   5 use warnings;
  1         2  
  1         25  
7 1     1   565 use Encode;
  1         10532  
  1         75  
8              
9 1     1   450 use App::optex v0.5.2;
  1         114  
  1         47  
10              
11             =encoding utf-8
12              
13             =head1 NAME
14              
15             textconv - optex module to replace document file by its text contents
16              
17             =head1 VERSION
18              
19             Version 0.1401
20              
21             =head1 SYNOPSIS
22              
23             optex command -Mtextconv
24              
25             optex command -Mtc (alias module)
26              
27             optex command -Mtextconv::load=pandoc
28              
29             =head1 DESCRIPTION
30              
31             This module replaces several sort of filenames by node representing
32             its text information. File itself is not altered.
33              
34             For example, you can check the text difference between MS word files
35             like this:
36              
37             $ optex diff -Mtextconv OLD.docx NEW.docx
38              
39             If you have symbolic link named B to B, and following
40             setting in your F<~/.optex.d/diff.rc>:
41              
42             option default --textconv
43             option --textconv -Mtextconv $
44              
45             Next command simply produces the same result.
46              
47             $ diff OLD.docx NEW.docx
48              
49             =head2 FILE FORMATS
50              
51             =over 7
52              
53             =item msdoc
54              
55             Microsoft office format files in XML (.docx, .pptx, .xlsx, .docm,
56             .pptm, .xlsm).
57             See L.
58              
59             =item pdf
60              
61             Use L command to covert PDF format.
62             See L.
63              
64             =item jpeg
65              
66             JPEG files is converted to their exif information (.jpeg, .jpg).
67              
68             =item http
69              
70             Name start with C or C is converted to text data
71             translated by L command.
72              
73             =item pandoc
74              
75             Use L command to translate Microsoft
76             office document in XML format.
77             See L.
78              
79             =item tika
80              
81             Use L command to translate
82             Microsoft office document in XML and non-XML format.
83             See L.
84              
85             =back
86              
87             =head1 MICROSOFT DOCUMENTS
88              
89             Microsoft office document in XML format (.docx, .pptx, .xlsx) is
90             converted to plain text by original code implemented in
91             L module. Algorithm used in this module
92             is extremely simple, and consequently runs fast.
93              
94             Two module are included in this distribution to use other external
95             converter program, B and B, those implement much more
96             serious algorithm. They can be invoked by calling B function
97             with module declaration like:
98              
99             optex -Mtextconv::load=pandoc
100              
101             optex -Mtextconv::load=tika
102              
103             =head1 INSTALL
104              
105             =head2 CPANM
106              
107             $ cpanm App::optex::textconv
108             or
109             $ curl -sL http://cpanmin.us | perl - App::optex::textconv
110              
111             =head2 GIT
112              
113             These are sample configurations using L in git
114             environment.
115              
116             ~/.gitconfig
117             [diff "msdoc"]
118             textconv = optex -Mtextconv cat
119             [diff "pdf"]
120             textconv = optex -Mtextconv cat
121             [diff "jpg"]
122             textconv = optex -Mtextconv cat
123              
124             ~/.config/git/attributes
125             *.docx diff=msdoc
126             *.pptx diff=msdoc
127             *.xlmx diff=msdoc
128             *.pdf diff=pdf
129             *.jpg diff=jpg
130              
131             About other GIT related setting, see
132             L.
133              
134             =head1 SEE ALSO
135              
136             L
137              
138             L
139              
140             L
141              
142             L
143              
144             =head1 AUTHOR
145              
146             Kazumasa Utashiro
147              
148             =head1 LICENSE
149              
150             Copyright 2019-2021 Kazumasa Utashiro.
151              
152             This library is free software; you can redistribute it and/or modify
153             it under the same terms as Perl itself.
154              
155             =cut
156              
157 1     1   588 use Data::Dumper;
  1         6389  
  1         65  
158 1     1   8 use List::Util 1.45 qw(first);
  1         21  
  1         85  
159              
160             our @CONVERTER;
161 1     1   416 use App::optex::textconv::default;
  1         4  
  1         6  
162 1     1   433 use App::optex::textconv::msdoc;
  1         3  
  1         7  
163              
164 1     1   22 use Exporter 'import';
  1         11  
  1         629  
165              
166             our @EXPORT = ();
167             our @EXPORT_OK = qw(initialize finalize load);
168             our %EXPORT_TAGS = ( alias => \@EXPORT_OK );
169              
170             my($mod, $argv);
171             sub initialize {
172 0     0 0   ($mod, $argv) = @_;
173             }
174              
175             sub finalize {
176 0     0 0   textconv();
177             }
178              
179             sub argv (&) {
180 0     0 0   my $sub = shift;
181 0           @$argv = $sub->(@$argv);
182             }
183              
184             sub hit {
185 0     0 0   local $_ = shift;
186 0           my $check = shift;
187 0 0         if (ref $check eq 'CODE') {
188 0           $check->();
189             } else {
190 0           /$check/;
191             }
192             }
193              
194             sub converter {
195 0     0 0   my $filename = shift;
196 0 0   0     if (my $ent = first { hit $filename, $_->[0] } @CONVERTER) {
  0            
197 0           return $ent->[1];
198             }
199 0           undef;
200             }
201              
202             sub exec_command {
203 0     0 0   my($format, $file) = @_;
204 0           my $exec = sprintf $format, $file;
205 0           qx($exec);
206             }
207              
208             sub load_module {
209 0     0 0   my $name = shift;
210 0           my $module = __PACKAGE__ . "::$name";
211 0           eval "use $module";
212 0 0         if ($@) {
213 0 0         warn $@ unless $@ =~ /Can't locate/;
214 0           return 0;
215             }
216 0           $module;
217             }
218              
219             sub load {
220 0     0 0   while (my($mod, $val) = splice(@_, 0, 2)) {
221 0 0         load_module $mod if $val;
222             }
223             }
224              
225             my @persist;
226              
227             sub textconv {
228             argv {
229             ARGV:
230 0     0     for (@_) {
231             # check file existence
232 0           do {{
233 0 0         m[^https?://] and last; # skip URL
  0            
234 0 0         -f or next ARGV;
235             }};
236 0           my($suffix) = map { lc } /\.(\w+)$/x;
  0            
237 0           my $func = do {
238 0 0         if (my $converter = converter $_) {
    0          
239 0 0         if (ref $converter eq 'CODE') {
240 0           $converter;
241             }
242             else {
243 0           sub { exec_command $converter, $_ };
  0            
244             }
245             }
246             elsif ($suffix) {
247 0           state %loaded;
248 0           my $state = \$loaded{$suffix};
249 0           my $to_text = join '::', __PACKAGE__, $suffix, 'to_text';
250 0 0         if (not defined $$state) {
    0          
251 0           $$state = 0;
252 0 0         load_module $suffix or next;
253 0 0         $$state = 1 if defined &{$to_text};
  0            
254 0           redo;
255             } elsif ($$state) {
256 0           $to_text;
257             } else {
258 0           next;
259             }
260             } else {
261 0           next;
262             }
263             };
264 1     1   500 use App::optex::Tmpfile;
  1         882  
  1         52  
265 0           my $tmp = $persist[@persist] = App::optex::Tmpfile->new;
266 0           my $data = do {
267 1     1   7 no strict 'refs';
  1         3  
  1         30  
268 1     1   1692 use charnames ':full';
  1         28783  
  1         14  
269 0           local $_ = decode 'utf8', &$func($_);
270 0           s/[\p{Private_Use}\p{Unassigned}]/\N{GETA MARK}/g;
271 0           encode 'utf8', $_;
272             };
273 0           $_ = $tmp->write($data)->rewind->path;
274             }
275 0           @_;
276 0     0 0   };
277             }
278              
279             1;
280              
281             __DATA__