File Coverage

blib/lib/URI/ToDisk.pm
Criterion Covered Total %
statement 62 63 98.4
branch 18 28 64.2
condition 1 3 33.3
subroutine 19 19 100.0
pod 7 7 100.0
total 107 120 89.1


line stmt bran cond sub pod time code
1             package URI::ToDisk;
2              
3             =pod
4              
5             =head1 NAME
6              
7             URI::ToDisk - An object for mapping a URI to an on-disk storage directory
8              
9             =head1 SYNOPSIS
10              
11             # We have a directory on disk that is accessible via a web server
12             my $authors = URI::ToDisk->new( '/var/www/AUTHORS', 'http://ali.as/AUTHORS' );
13            
14             # We know where a particular generated file needs to go
15             my $about = $authors->catfile( 'A', 'AD', 'ADAMK', 'about.html' );
16            
17             # Save the file to disk
18             my $file = $about->path;
19             open( FILE, ">$file" ) or die "open: $!";
20             print FILE, $content;
21             close FILE;
22            
23             # Show the user where to see the file
24             my $uri = $about->uri;
25             print "Author information is at $uri\n";
26              
27             =head1 DESCRIPTION
28              
29             In several process relating to working with the web, we may need to keep
30             track of an area of disk that maps to a particular URL. From this location,
31             we should be able to derived both a filesystem path and URL for any given
32             directory or file under this location that we might need to work with.
33              
34             =head2 Implementation
35              
36             Internally each C object contains both a filesystem path,
37             which is altered using L, and a L object. When making a
38             change, the path section of the URI is altered using .
39              
40             =head2 Method Calling Conventions
41              
42             The main functional methods, such as C and C, do B
43             modify the original object, instead returning a new object containing the
44             new location.
45              
46             This means that it should be used in a somewhat similar way to L.
47              
48             # The File::Spec way
49             my $path = '/some/path';
50             $path = File::Spec->catfile( $path, 'some', 'file.txt' );
51            
52             # The URI::ToDisk way
53             my $location = URI::ToDisk->new( '/some/path', 'http://foo.com/blah' );
54             $location = $location->catfile( 'some', 'file.txt' );
55              
56             OK, well it's not exactly THAT close, but you get the idea. It also allows you
57             to do method chaining, which is basically
58              
59             URI::ToDisk->new( '/foo', 'http://foo.com/' )->catfile( 'bar.txt' )->uri
60              
61             Which may seem a little trivial now, but I expect it to get more useful later.
62             It also means you can do things like this.
63              
64             my $base = URI::ToDisk->new( '/my/cache', 'http://foo.com/' );
65             foreach my $path ( @some_files ) {
66             my $file = $base->catfile( $path );
67             print $file->path . ': ' . $file->uri . "\n";
68             }
69              
70             In the above example, you don't have to be continuously cloning the location,
71             because all that stuff happens internally as needed.
72              
73             =head1 METHODS
74              
75             =cut
76              
77 2     2   31314 use 5.005;
  2         7  
  2         75  
78 2     2   12 use strict;
  2         4  
  2         79  
79 2     2   20 use base 'Clone';
  2         4  
  2         1949  
80 2     2   9813 use URI ();
  2         14296  
  2         41  
81 2     2   17 use File::Spec ();
  2         3  
  2         29  
82 2     2   9 use File::Spec::Unix ();
  2         4  
  2         49  
83 2         403 use Params::Util '_INSTANCE',
84 2     2   2180 '_ARRAY';
  2         17947  
85              
86             # Overload stringification to the string form of the URL.
87             use overload 'bool' => sub () { 1 },
88 2         26 '""' => 'uri',
89 2     2   187 'eq' => '__eq';
  2         5  
90              
91 2     2   364 use vars qw{$VERSION};
  2         4  
  2         105  
92             BEGIN {
93 2     2   6343 $VERSION = '1.12';
94             }
95              
96              
97              
98              
99              
100             #####################################################################
101             # Constructors
102              
103             =pod
104              
105             =head2 new $path, $http_url
106              
107             The C constructor takes as argument a filesystem path and a http(s)
108             URL. Both are required, and the method will return C is either is
109             illegal. The URL is not required to have protocol, host or port sections,
110             and as such allows for host-relative URL to be used.
111              
112             Returns a new C object on success, or C on failure.
113              
114             =cut
115              
116             sub new {
117 6     6 1 45 my $class = shift;
118              
119             # Get the base file system path
120 6 50       50 my $path = File::Spec->canonpath(shift) or return undef;
121              
122             # Get the base URI. We only accept HTTP(s) URLs
123 6 50 33     41 return undef unless defined $_[0] and ! ref $_[0];
124 6 50       62 my $URI = URI->new( shift, 'http' ) or return undef;
125 6 50       11454 $URI->path( '/' ) unless length $URI->path;
126              
127             # Create the object
128 6         254 bless { path => $path, URI => $URI }, $class;
129             }
130              
131             =pod
132              
133             =head2 param $various
134              
135             C is provided as a mechanism for higher order modules to flexibly
136             accept URI::ToDisk's as parameters. In this case, it accepts either
137             an existing URI::ToDisk object, two arguments ($path, $http_url), or
138             a reference to an array containing the same two arguments.
139              
140             Returns a URI::ToDisk if possible, or C if one cannot be provided.
141              
142             =cut
143              
144             sub param {
145 3     3 1 1805 my $class = shift;
146 3 100       20 return shift if _INSTANCE($_[0], 'URI::ToDisk');
147 2 100       14 return URI::ToDisk->new(@_) if @_ == 2;
148 1 50       8 return URI::ToDisk->new(@{$_[0]}) if _ARRAY($_[0]);
  1         4  
149 0         0 return undef;
150             }
151              
152              
153              
154              
155              
156             #####################################################################
157             # Accessors
158              
159             =pod
160              
161             =head2 uri
162              
163             The C method gets and returns the current URI of the location, in
164             string form.
165              
166             =cut
167              
168             sub uri {
169 62     62 1 11950 $_[0]->{URI}->as_string;
170             }
171              
172             =pod
173              
174             =head2 URI
175              
176             The capitalised C method gets and returns a copy of the raw L,
177             held internally by the location. Note that only a copy is returned, and
178             as such as safe to further modify yourself without effecting the location.
179              
180             =cut
181              
182             sub URI {
183 32     32 1 623 Clone::clone $_[0]->{URI};
184             }
185              
186             =pod
187              
188             =head2 path
189              
190             The C method returns the filesystem path componant of the location.
191              
192             =cut
193              
194 44     44 1 4036 sub path { $_[0]->{path} }
195              
196              
197              
198              
199              
200             #####################################################################
201             # Manipulate Locations
202              
203             =pod
204              
205             =head2 catdir 'dir', 'dir', ...
206              
207             A L workalike, the C method acts in the same way as for
208             L, modifying both componants of the location. The C method
209             returns a B URI::ToDisk object representing the new location, or
210             C on error.
211              
212             =cut
213              
214             sub catdir {
215 1     1 1 316 my $self = shift;
216 1         2 my @args = @_;
217              
218             # Alter the URI and local paths
219 1 50       8 my $new_uri = File::Spec::Unix->catdir( $self->{URI}->path, @args ) or return undef;
220 1 50       29 my $new_path = File::Spec->catdir( $self->{path}, @args ) or return undef;
221              
222             # Clone and set the new values
223 1         11 my $changed = $self->clone;
224 1         4 $changed->{URI}->path( $new_uri );
225 1         29 $changed->{path} = $new_path;
226              
227 1         4 $changed;
228             }
229              
230             =pod
231              
232             =head2 catfile [ 'dir', ..., ] $file
233              
234             Like C, the C method acts in the same was as for
235             L, and returns a new URI::ToDisk object representing
236             the file, or C on error.
237              
238             =cut
239              
240             sub catfile {
241 1     1 1 319 my $self = shift;
242 1         2 my @args = @_;
243              
244             # Alter the URI and local paths
245 1 50       106 my $uri = File::Spec::Unix->catfile( $self->{URI}->path, @args ) or return undef;
246 1 50       38 my $fs = File::Spec->catfile( $self->{path}, @args ) or return undef;
247              
248             # Set both and return
249 1         15 my $changed = $self->clone;
250 1         5 $changed->{URI}->path( $uri );
251 1         26 $changed->{path} = $fs;
252              
253 1         4 $changed;
254             }
255              
256              
257              
258              
259              
260             #####################################################################
261             # Additional Overload Methods
262              
263             sub __eq {
264 14 50   14   2431 my $left = _INSTANCE(shift, 'URI::ToDisk') or return '';
265 14 100       86 my $right = _INSTANCE(shift, 'URI::ToDisk') or return '';
266 10 100       20 ($left->path eq $right->path) and ($left->uri eq $right->uri);
267             }
268              
269              
270              
271              
272              
273             #####################################################################
274             # Coercion Support
275              
276 1     1   5 sub __as_URI { shift->URI }
277              
278             1;
279              
280             =pod
281              
282             =head1 TO DO
283              
284             Add more File::Spec-y methods as needed. Ask if you need one.
285              
286             =head1 SUPPORT
287              
288             Bugs should be reported via the CPAN bug tracker at
289              
290             L
291              
292             For other issues, or commercial enhancement or support, contact the author.
293              
294             =head1 AUTHORS
295              
296             Adam Kennedy L, cpan@ali.as
297              
298             =head1 COPYRIGHT
299              
300             Copyright (c) 2003 - 2006 Adam Kennedy.
301              
302             This program is free software; you can redistribute
303             it and/or modify it under the same terms as Perl itself.
304              
305             The full text of the license can be found in the
306             LICENSE file included with this module.
307              
308             =cut