File Coverage

blib/lib/App/Zip/X.pm
Criterion Covered Total %
statement 40 54 74.0
branch 8 24 33.3
condition 6 23 26.0
subroutine 9 10 90.0
pod 0 3 0.0
total 63 114 55.2


line stmt bran cond sub pod time code
1             package App::Zip::X;
2              
3 1     1   84949 use strict;
  1         2  
  1         23  
4 1     1   5 use warnings;
  1         1  
  1         23  
5              
6 1     1   628 use Getopt::Long qw(GetOptionsFromArray);
  1         10847  
  1         5  
7 1     1   876 use Archive::Zip qw(AZ_OK);
  1         69967  
  1         47  
8 1     1   549 use XML::LibXML;
  1         32035  
  1         7  
9              
10             our $VERSION = '1.0';
11              
12              
13             # constant integers to specify indentation modes -- see L
14 1     1   136 use constant XML_NO_INDENT => 0;
  1         2  
  1         59  
15 1     1   5 use constant XML_SIMPLE_INDENT => 1;
  1         2  
  1         500  
16              
17              
18             sub run { # no new() method -- this method both creates the instance and executes the request
19 1     1 0 1412 my ($class, @args) = @_;
20              
21 1         3 my $self = bless {}, $class;
22              
23 1         7 GetOptionsFromArray \@args, $self,
24             'unzip!', # unzip mode (default)
25             'zip!', # zip mode
26             'xml_indent!', # handle indentation of XML extracted files (default)
27              
28             'archive=s', # archive name (or first arg on command line)
29             'member=s', # member to extract (or second arg on command line)
30             ;
31              
32             # other syntax : archive name and member name from command line without options
33 1 50 33     650 $self->{archive} //= shift @args or die "unspecified ZIP archive";
34 1 50 33     5 $self->{member} //= shift @args or die "unspecified member to extract from $self->{zip}";
35 1 50       3 !@args or die "don't undestand these args: ", join(", ", @args);
36              
37             # default flags and consistency check
38 1 0 33     2 !($self->{zip} && $self->{unzip}) or die "options -zip and -unzip are mutually exclusive";
39 1 50 50     18 $self->{unzip} //= 1 unless $self->{zip};
40              
41             # open ZIP archive
42 1         8 $self->{zipper} = Archive::Zip->new;
43 1 50       39 $self->{zipper}->read($self->{archive}) == AZ_OK
44             or die "cannot open ZIP archive $self->{archive}";
45              
46             # decide what to do
47 1 50       2521 if ($self->{unzip}) { $self->extract() }
  1 0       5  
48 0         0 elsif ($self->{zip}) { $self->replace() }
49 0         0 else { die "neither -zip nor -unzip .. not clear what you want to do"}
50              
51             }
52              
53              
54              
55             sub extract {
56 1     1 0 3 my ($self) = @_;
57              
58             # get member contents
59             my $contents = $self->{zipper}->contents($self->{member})
60 1 50       5 or die "no member named '$self->{member}' in $self->{archive}";
61              
62             # add XML indentation if necessary
63 1 50 33     1284 if ($self->{xml_indent} && ($self->{member} =~ /\.xml$/i || $contents =~ /^<\?xml/)) {
      33        
64 1         9 my $dom = XML::LibXML->load_xml(string => $contents);
65 1         1540 $contents = $dom->toString(XML_SIMPLE_INDENT); # already utf8-encoded
66             }
67              
68             # write on STDOUT
69 1         646 binmode STDOUT, ':raw';
70 1         125 print $contents;
71             }
72              
73              
74             sub replace {
75 0     0 0   my ($self) = @_;
76              
77             # slurp contents from file relative to current directory
78 0           local $/;
79 0 0         open my $fh, "<:raw", $self->{member} or die "open $self->{member}: $!";
80 0           my $contents = <$fh>;
81 0           close $fh;
82              
83             # remove XML indentation if necessary
84 0 0 0       if ($self->{xml_indent} && ($self->{member} =~ /\.xml$/i || $contents =~ /^<\?xml/)) {
      0        
85 0           my $dom = XML::LibXML->load_xml(string => $contents);
86 0           $contents = $dom->toString(XML_NO_INDENT);
87             }
88              
89             # replace member in archive and save
90 0           my $zipper = $self->{zipper};
91 0           $zipper->removeMember($self->{member});
92 0           $zipper->addString($contents, $self->{member});
93 0           $zipper->overwrite;
94             }
95              
96              
97             1; # End of App::Zip::X
98              
99             __END__