File: Zip.pm

package info (click to toggle)
libdemeter-perl 0.9.27%2Bds6-9
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid, trixie
  • size: 74,028 kB
  • sloc: perl: 73,233; python: 2,196; makefile: 1,999; ansic: 1,368; lisp: 454; sh: 74
file content (162 lines) | stat: -rw-r--r-- 4,930 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package Demeter::Plugins::Zip;  # -*- cperl -*-

use Moose;
extends 'Demeter::Plugins::FileType';

## use the standard CPAN module for opening/reading from zip files
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
local $Archive::Zip::UNICODE = 1;
use File::Path qw(remove_tree);
use Scalar::Util qw(looks_like_number);

has '+is_binary'   => (default => 0);
has '+description' => (default => "a zip file of data files");
has '+version'     => (default => 0.1);
has '+output'      => (default => 'list');

sub is {
  my ($self) = @_;
  my $file = $self->file;
  my $zip = Archive::Zip->new();
  {
    local $Archive::Zip::ErrorHandler = sub{1}; # turn off Archive::Zip errors for this check
    if ($zip->read($file) != AZ_OK) {
      undef $zip;
      return 0;
    };
  };
  undef $zip;
  return 1;
};


## note that this is a very simple example of a list-returning plugin.
## the contents of the zip file are written to a flat folder beneath
## the stash folder.  no effort is made to retain the internal
## structure of the zip file.  this is not a fundamental limitation --
## the return value of the fix method is an array reference of FULLY
## RESOLVED FILENAMES.  those could just as well replicate the
## structure of the zip file or show whatever other structure the fix
## method might choose to impose.
sub fix {
  my ($self) = @_;

  ## make a folder below the stash folder to hold the contents of the zip file
  ## here I have chosen to use a random, six-character string for the folder name
  ## this MUST be a place that can be safely discarded
  $self->folder(File::Spec->catfile($self->stash_folder, 'zip_'.Demeter->randomstring(6)));

  my $zip = Archive::Zip->new();
  $zip -> read($self->file);
  my @list = ();
  foreach my $file ($zip->memberNames) {
    my $target = File::Spec->catfile($self->folder, $file);
    $zip->extractMember($file, $target);
    ## accumulate a list of file names written to the stash folder
    push @list, $target;
  };

  ## set the fixed method to this array reference and return that array reference
  $self->fixed(\@list);
  return \@list;
};

sub suggest {
  return ();
};

sub clean {
  my ($self) = @_;
  my $err = q{};
  remove_tree($self->folder); #, {error=>\$err});
  return $err;
};

__PACKAGE__->meta->make_immutable;
1;
__END__


=head1 NAME

Demeter::Plugin::Zip - Open a zip file of data file

=head1 VERSION

This documentation refers to Demeter version 0.9.26.

=head1 SYNOPSIS

This plugin opens a zip file, writing the contents to the stash folder
so that each can be used as data.  This is B<very> simple, a proof of
concept, really.  It assumes that the zip file has no depth and the
contents will be splayed out into a single folder.  The return value
of the C<fix> method is an array reference containing a list of fully
resolved file paths to data files in the stash folder.


Here is a simple example of using this plugin.  Note that the C<fix>
method returns an array reference.  It is up to B<you> to actually do
something with its contents.  That "something" could be to test the
file against some other plygin.  Note also that B<you> need to clean
up the temporary files when you are done.

    #!/usr/bin/perl

    use Demeter qw(:data :p=gnuplot :ui=screen);
    use File::Path;

    my $this = Demeter::Plugins::Zip->new(file=>'examples/data/data.zip');
    ($this->is) ? print "this is a zip file\n" : print "this is not a zip file\n";
    my $fixed = $this->fix;

    Demeter->po->e_bkg(0);

    ## now do something whith each file extracted from the zip file
    ## note: that 'something' could be to test against some other plugin
    foreach my $f (@{$this->fixed}) {
       my $data = Demeter::Data -> new();
       $data -> set(file   =>  $f,  datatype  => 'xmu',
                    energy => '$1', numerator => '$2',
                    denominator => '$3', ln => 1, );
       $data->plot('E');
       $data->pause if ($f eq $this->fixed->[-1]); # pause on the last file
    };
    ## give a hoot! don't pollute!
    $this->clean;


=head1 Methods

=over 4

=item C<is>

The C<is> method is used to identify the file type, typically by some
information contained within the file.  In the case of a zip file, a
very simple check is made to determine whether the file is actually a
zip file and can be opened.  Absolutely no tests are made on the file
contents.

=item C<fix>

This extracts each file from the zip file, writing it to a subfolder
beneath the stash folder.  This location is stored in the C<folder>
attribute of this object.  A reference to this list is stored in the
C<fixed> attribute and is the return value of this method.

=item C<suggest>

This is an empty list.  Each constituent file will have to be
processed individually.

=item C<clean>

Removes the temporary folder to which the data were written.

=back

=head1 AUTHOR

  Bruce Ravel, L<http://bruceravel.github.io/home>
  http://bruceravel.github.io/demeter