File Coverage

blib/lib/App/Zip/X.pm
Criterion Covered Total %
statement 42 56 75.0
branch 8 24 33.3
condition 6 23 26.0
subroutine 10 11 90.9
pod 0 3 0.0
total 66 117 56.4


line stmt bran cond sub pod time code
1             package App::Zip::X;
2 1     1   103637 use 5.10.0;
  1         4  
3 1     1   15 use strict;
  1         6  
  1         31  
4 1     1   7 use warnings;
  1         4  
  1         34  
5              
6 1     1   895 use Getopt::Long qw(GetOptionsFromArray);
  1         12623  
  1         5  
7 1     1   829 use Archive::Zip qw(AZ_OK);
  1         84269  
  1         80  
8 1     1   664 use XML::LibXML;
  1         31303  
  1         7  
9              
10             our $VERSION = '1.01';
11              
12              
13             # constant integers to specify indentation modes -- see L
14 1     1   189 use constant XML_NO_INDENT => 0;
  1         2  
  1         60  
15 1     1   11 use constant XML_SIMPLE_INDENT => 1;
  1         2  
  1         611  
16              
17              
18             sub run { # no new() method -- this method both creates the instance and executes the request
19 1     1 0 1903 my ($class, @args) = @_;
20              
21 1         4 my $self = bless {}, $class;
22              
23 1         8 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     946 $self->{archive} //= shift @args or die "unspecified ZIP archive";
34 1 50 33     7 $self->{member} //= shift @args or die "unspecified member to extract from $self->{zip}";
35 1 50       5 !@args or die "don't undestand these args: ", join(", ", @args);
36              
37             # default flags and consistency check
38 1 0 33     3 !($self->{zip} && $self->{unzip}) or die "options -zip and -unzip are mutually exclusive";
39 1 50 50     8 $self->{unzip} //= 1 unless $self->{zip};
40              
41             # open ZIP archive
42 1         9 $self->{zipper} = Archive::Zip->new;
43 1 50       51 $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       3205 if ($self->{unzip}) { $self->extract() }
  1 0       8  
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 5 my ($self) = @_;
57              
58             # get member contents
59             my $contents = $self->{zipper}->contents($self->{member})
60 1 50       7 or die "no member named '$self->{member}' in $self->{archive}";
61              
62             # add XML indentation if necessary
63 1 50 33     1861 if ($self->{xml_indent} && ($self->{member} =~ /\.xml$/i || $contents =~ /^<\?xml/)) {
      33        
64 1         19 my $dom = XML::LibXML->load_xml(string => $contents, recover => 1);
65 1         1952 $contents = $dom->toString(XML_SIMPLE_INDENT); # already utf8-encoded
66             }
67              
68             # write on STDOUT
69 1         889 binmode STDOUT, ':raw';
70 1         149 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__