File Coverage

blib/lib/Path/Resource.pm
Criterion Covered Total %
statement 66 73 90.4
branch 14 26 53.8
condition 7 24 29.1
subroutine 17 17 100.0
pod 9 9 100.0
total 113 149 75.8


line stmt bran cond sub pod time code
1             package Path::Resource;
2              
3 4     4   420801 use warnings;
  4         11  
  4         123  
4 4     4   20 use strict;
  4         9  
  4         277  
5              
6             =head1 NAME
7              
8             Path::Resource - URI/Path::Class combination
9              
10             =head1 VERSION
11              
12             Version 0.072
13              
14             =head1 SYNOPSIS
15              
16             use Path::Resource;
17              
18             # Map a resource on the local disk to a URI.
19             # Its (disk) directory is "/var/dir" and its uri is "http://hostname/loc"
20             my $rsc = new Path::Resource dir => "/var/dir", uri => "http://hostname/loc";
21             # uri: http://hostname/loc
22             # dir: /var/dir
23              
24             my $apple_rsc = $rsc->child("apple");
25             # uri: http://hostname/loc/apple
26             # dir: /var/dir/apple
27              
28             my $banana_txt_rsc = $apple_rsc->child("banana.txt");
29             # uri: http://hostname/loc/apple/banana.txt
30             # file: /var/dir/apple/banana.txt
31              
32             my $size = -s $banana_txt_rsc->file;
33              
34             redirect($banana_txt_rsc->uri);
35             # Redirect to "http://hostname/loc/apple/banana.txt"
36              
37             =head1 DESCRIPTION
38              
39             Path::Resource is a module for combining local file and directory manipulation with URI manipulation. It allows you to
40             effortlessly map local file locations to their URI equivalent.
41              
42             It combines Path::Class and URI into one object.
43              
44             Given a base Path::Resource, you can descend (using ->child) or ascend (using ->parent) the path tree while maintaining
45             URI equivalency, all in one object.
46              
47             As a convenience, if you do not need the full URI, you can use the ->loc method to just return the URI path.
48              
49             =cut
50              
51             our $VERSION = '0.072';
52              
53 4     4   963 use Path::Class();
  4         86944  
  4         68  
54 4     4   2305 use Path::Resource::Base();
  4         12  
  4         98  
55 4     4   31 use Path::Abstract;
  4         9  
  4         38  
56 4     4   1067 use Scalar::Util qw/blessed/;
  4         19  
  4         251  
57 4     4   23 use Carp;
  4         8  
  4         296  
58 4     4   23 use base qw/Class::Accessor::Fast/;
  4         8  
  4         4099  
59             __PACKAGE__->mk_accessors(qw(_path base));
60              
61             =head1 METHODS
62              
63             =over 4
64              
65             =item $rsc = Path::Resource->new
66              
67             =item $rsc = Path::Resource->new( dir => $dir, uri => $uri, [ path => $path ] )
68              
69             Create and return a new Path::Resource object using $dir as the base dir and $uri as the base uri.
70              
71             The URI path of $uri will be automatically extracted and used as the base loc.
72              
73             If $path is given, then the $rsc will start at that point on the path.
74              
75             # For example, if the following $rsc is created like so:
76             my $rsc = Path::Resource->new(uri => "http://example.com/a", dir => "/home/b/htdocs", path => "xyzzy");
77              
78             my $dir = $rsc->dir; # The dir "/home/b/htdocs/xyzzy"
79             my $uri = $rsc->uri; # The uri "http://example.com/a/xyzzy"
80              
81             # Note that path doesn't have to be a dir.
82             # You can give it a file path if you like (Path::Resource doesn't care)
83             $rsc = Path::Resource->new(uri => "http://example.com/a", dir => "/home/b/htdocs", path => "xyzzy/nothing.txt");
84              
85             my $file = $rsc->file; # The file "/home/b/htdocs/xyzzy/nothing.txt"
86             $uri = $rsc->uri; # The uri "http://example.com/a/xyzzy/nothing.txt"
87              
88             =item $rsc = Path::Resource->new( dir => $dir, uri => $uri, loc => $loc, [ path => $path ] )
89              
90             Create and return a new Path::Resource object using $dir as the base dir, $uri as the base uri, and
91             using $loc as the base loc (the uri path).
92              
93             If $loc is relative, then it will be appended to $uri->path, otherwise (being absolute) it will replace $uri->path.
94              
95             If $path is given, then the $rsc will start at that point on the path.
96              
97             # For example, if the following $rsc is created like so:
98             my $rsc = Path::Resource->new(uri => "http://example.com/a", dir => "/home/b/htdocs", loc => "c");
99              
100             my $dir = $rsc->dir; # The dir "/home/b/htdocs"
101             my $uri = $rsc->uri; # The uri "http://example.com/a/c"
102              
103             # On the other hand:
104             $rsc = Path::Resource->new(uri => "http://example.com/a", dir => "/home/b/htdocs", loc => "/g/h");
105              
106             $dir = $rsc->dir; # The dir "/home/b/htdocs"
107             $uri = $rsc->uri; # The uri "http://example.com/g/h
108              
109             =item $rsc = Path::Resource->new( file => $file, dir => $dir, uri => $uri, [ loc => $loc, path => $path ] )
110              
111             Create and return a new Path::Resource object using $dir as the base dir, $uri as the base uri, and
112             the difference between $file and $dir as the path (literally: $path = $file->relative($dir))
113              
114             If $loc is given then if it is relative, then it will be appended to $uri->path, otherwise (being absolute) it will replace $uri->path.
115              
116             =cut
117              
118             sub new {
119 93     93 1 38696 my $self = bless {}, shift;
120 93         401 local %_ = @_;
121 93         164 my $dir = $_{dir};
122 93         143 my $file = $_{file};
123 93         131 my $path = $_{path};
124 93         158 my $loc = $_{loc};
125 93         122 my $uri = $_{uri};
126              
127 93         196 my $base;
128 93 100       235 if ($base = $_{base}) {
129             # Use supplied base object
130 54 50       227 croak "\$base ($base) is not of Path::Resource::Base" unless $base->isa("Path::Resource::Base");
131             }
132             else {
133             # Make a new base object from @_
134 39 50 33     429 if ($dir && $file && $path) {
    50 33        
    50 33        
    0          
135 0         0 croak "Can't initialize a dir ($dir), a file ($file), and a path ($path) at the same time"
136             }
137             elsif ($dir && $file) {
138             # We were given a dir and file, so keep the dir and determine the path by finding difference between the two.
139 0 0 0     0 $dir = Path::Class::dir($dir) unless blessed $dir && $dir->isa("Path::Class::Dir");
140 0 0 0     0 $file = Path::Class::file($file) unless blessed $file && $file->isa("Path::Class::File");
141 0         0 croak "Can't initialize since dir ($dir) does not contain file ($file) unless $dir->subsumes($file)";
142 0         0 $path = $file->relative($dir);
143             }
144             elsif ($dir) {
145 39 50 33     282 $dir = Path::Class::dir($dir) unless blessed $dir && $dir->isa("Path::Class::Dir");
146             }
147             elsif ($file) {
148 0         0 $dir = Path::Class::dir('/');
149             }
150             else {
151 0         0 $dir = Path::Class::dir('/');
152             }
153              
154 39         3437 $base = new Path::Resource::Base(dir => $dir, uri => $uri, loc => $loc);
155             }
156 93         269 $self->base($base);
157              
158 93 100 66     1177 $path = Path::Abstract->new($path) unless blessed $path && $path->isa("Path::Abstract");
159 93         1406 $self->_path($path);
160              
161 93         767 return $self;
162             }
163              
164             =item $rsc->path
165              
166             =item $rsc->path( <part>, [ <part>, ..., <part> ] )
167              
168             Return a clone of $rsc->path based on $rsc->path and any optional <part> passed through
169              
170             my $rsc = Path::Resource->new(path => "b/c");
171              
172             # $path is "b/c"
173             my $path = $rsc->path;
174              
175             # $path is "b/c/d"
176             my $path = $rsc->path("d");
177              
178             =cut
179              
180             sub path {
181 14     14 1 2105 my $self = shift;
182 14         44 my $path = $self->_path->child(@_);
183 14         691 return $path;
184             }
185              
186             =item $rsc->clone
187              
188             =item $rsc->clone( <path> )
189              
190             Return a Path::Resource object that is a copy of $rsc
191              
192             The optional argument will change (not append) the path of the cloned object
193              
194             =cut
195              
196             sub clone {
197 54     54 1 2692 my $self = shift;
198 54   33     165 my $path = shift || $self->_path->clone;
199 54         550 return __PACKAGE__->new(base => $self->base->clone, path => $path);
200             }
201              
202             =item $rsc->subdir( <part>, [ <part>, ..., <part> ] )
203              
204             =item $rsc->child( <part>, [ <part>, ..., <part> ] )
205              
206             Return a clone Path::Resource object whose path is the child of $rsc->path
207              
208             my $rsc = Path::Resource->new(dir => "/a", path => "b");
209              
210             # $rsc->path is "b/c/d.tmp"
211             $rsc = $rsc->child("c/d.tmp");
212              
213             # ->subdir is an alias for ->child
214             $rsc = $rsc->parent->subdir("e");
215              
216             =cut
217              
218             sub child {
219 46     46 1 2694 my $self = shift;
220 46         166 my $clone = $self->clone($self->_path->child(@_));
221 46         179 return $clone;
222             }
223             *subdir = \&child;
224              
225             =item $rsc->parent
226              
227             Return a clone Path::Resource object whose path is the parent of $rsc->path
228              
229             my $rsc = Path::Resource->new(dir => "/a", path => "b/c");
230              
231             # $rsc->path is "b"
232             $rsc = $rsc->parent;
233              
234             # $rsc->path is ""
235             $rsc = $rsc->parent;
236              
237             # $dir is "/a/f"
238             my $dir = $rsc->parent->parent->dir("f");
239              
240             =cut
241              
242             sub parent {
243 8     8 1 14 my $self = shift;
244 8         24 my $clone = $self->clone($self->_path->parent);
245 8         42 return $clone;
246             }
247              
248             =item $rsc->loc
249              
250             =item $rsc->loc( <part>, [ <part>, ..., <part> ] )
251              
252             Return a Path::Abstract object based on the path part of $rsc->base->uri ($rsc->base->loc), $rsc->path, and any optional <part> passed through
253              
254             my $rsc = Path::Resource->new(uri => "http://example.com/a", path => "b/c");
255              
256             # $loc is "/a/b/c"
257             my $loc = $rsc->loc;
258              
259             # $dir is "/a/b/c/d.tmp"
260             $loc = $rsc->loc("d.tmp");
261              
262             =cut
263              
264             sub loc {
265 35     35 1 3685 my $self = shift;
266 35 100       107 unshift @_, $self->_path unless $self->_path->is_empty;
267 35         506 return $self->base->loc->child(@_);
268             }
269              
270              
271             =item $rsc->uri
272              
273             =item $rsc->uri( <part>, [ <part>, ..., <part> ] )
274              
275             Return a URI object based on $rsc->base->uri, $rsc->path, and any optional <part> passed through
276              
277             my $rsc = Path::Resource->new(uri => "http://example.com/a", path => "b/c");
278              
279             # $uri is "http://example.com/a/b/c"
280             my $uri = $rsc->uri;
281              
282             # $uri is "http://example.com/a/b/c/d.tmp"
283             $uri = $rsc->uri("d.tmp");
284              
285             # $uri is "https://example.com/a/b/c/d.tmp"
286             $uri->scheme("https");
287              
288             =cut
289              
290             sub uri {
291 21     21 1 5510 my $self = shift;
292 21         73 my $uri = $self->base->uri->clone;
293 21         283 $uri->path($self->loc(@_)->get);
294 21         1974 return $uri;
295             }
296              
297             =item $rsc->file
298              
299             =item $rsc->file( [ <part>, <part>, ..., <part> ] )
300              
301             Return a Path::Class::File object based on $rsc->base->dir, $rsc->path, and any optional <part> passed through
302              
303             NOTE: This method will return a Path::Class::File object, *NOT* a new Path::Resource object (use ->child for that functionality)
304              
305             my $rsc = Path::Resource->new(dir => "/a", path => "b");
306             $rsc = $rsc->child("c/d.tmp");
307              
308             # $file is "/a/b/c/d.tmp"
309             my $file = $rsc->file;
310              
311             # $file is "/a/b/c/d.tmp/e.txt"
312             $file = $rsc->file(qw/ e.txt /);
313              
314             =cut
315              
316             sub file {
317 2     2 1 390 my $self = shift;
318 2 50       7 unshift @_, $self->_path->get unless $self->_path->is_empty;
319 2         43 return $self->base->dir->file(@_);
320             }
321              
322             =item $rsc->dir
323              
324             =item $rsc->dir( <part>, [ <part>, ..., <part> ] )
325              
326             Return a Path::Class::Dir object based on $rsc->base->dir, $rsc->path, and any optional <part> passed through
327              
328             my $rsc = Path::Resource->new(dir => "/a", path => "b");
329             $rsc = $rsc->child("c/d.tmp");
330              
331             # $dir is "/a/b/c/d.tmp"
332             my $dir = $rsc->file;
333              
334             # $dir is "/a/b/c/d.tmp/e.tmp"
335             $dir = $rsc->file(qw/ e.tmp /);
336              
337             =cut
338              
339             sub dir {
340 19     19 1 1192 my $self = shift;
341 19 100       56 unshift @_, $self->_path->get unless $self->_path->is_empty;
342 19         917 return $self->base->dir->subdir(@_);
343             }
344              
345              
346             =item $rsc->base
347              
348             Return the Path::Resource::Base object for $rsc
349              
350             =back
351              
352             =head1 AUTHOR
353              
354             Robert Krimen, C<< <rkrimen at cpan.org> >>
355              
356             =head1 SEE ALSO
357              
358             URI::ToDisk
359              
360             =head1 BUGS
361              
362             Please report any bugs or feature requests to
363             C<bug-path-resource at rt.cpan.org>, or through the web interface at
364             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Path-Resource>.
365             I will be notified, and then you'll automatically be notified of progress on
366             your bug as I make changes.
367              
368             =head1 SUPPORT
369              
370             You can find documentation for this module with the perldoc command.
371              
372             perldoc Path::Resource
373              
374             You can also look for information at:
375              
376             =over 4
377              
378             =item * AnnoCPAN: Annotated CPAN documentation
379              
380             L<http://annocpan.org/dist/Path-Resource>
381              
382             =item * CPAN Ratings
383              
384             L<http://cpanratings.perl.org/d/Path-Resource>
385              
386             =item * RT: CPAN's request tracker
387              
388             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Path-Resource>
389              
390             =item * Search CPAN
391              
392             L<http://search.cpan.org/dist/Path-Resource>
393              
394             =back
395              
396             =head1 ACKNOWLEDGEMENTS
397              
398             =head1 COPYRIGHT & LICENSE
399              
400             Copyright 2007 Robert Krimen, all rights reserved.
401              
402             This program is free software; you can redistribute it and/or modify it
403             under the same terms as Perl itself.
404              
405             =cut
406              
407             1; # End of Path::Resource