=pod

=head1 NAME

File::PathInfo - oo access to path variables stat data about a file on disk

=head1 SYNOPSIS

	use File::PathInfo;
	
	my $f = new File::PathInfo;
   
	$f->set('/home/myself/public_html/folder/stew.txt) or die('file does not exist');
	
	$f->is_text; # returns 1
   
	$f->ext; # returns 'txt'
   
	$f->abs_loc; # returns '/home/myself/public_html/folder'

=head1 DESCRIPTION
	
This provides an object oriented interface to things you want to know about a file, such
as extension, absolute path, relative path, size, filename (without extension), etc.
It is a sort of swissarmy knife of file info.

A lot of times you need to know a file's absolute path, it's absolute
location, maybe it's relative location to something else (like DOCUMENT ROOT),
then you need to maybe know the relative path and relative location for a file.
You need to know if a file is a directory, what it's extension is. 
You can commonly use regexes to do this.

This module provides commonly needed variables.

Works with relative paths like in a website too:

	use File::PathInfo;
	
	my $f = new File::PathInfo;
   
	$f->set('folder/stew.txt) or die('file does not exist');
   
	$f->abs_path; # returns '/home/myself/public_html/folder/stew.txt'
   
	$f->rel_path; # returns 'folder/stew.txt'
	
	$f->rel_loc; # returns 'folder'
   
	$f->is_in_DOCUMENT_ROOT; # returns 1

Also safeguards from cgi accessing files outside of document root

	use File::PathInfo;
	
	my $f = new File::PathInfo;
   
	$f->set('/home/myself/stew.txt) or die('file does not exist');
   
	$f->rel_path; # throws exception and complains that it is not in document root


You can define also, that document root is something else. To
assure the files you are dealing with remain in a certain part of the 
filesystem tree.
Also lets you set a different document root, if you want an application to serve files
in some other place, but you still want to restrict what the script can access to
within that slice of the filesystem:

	use File::PathInfo;
	
	my $f = new File::PathInfo({ DOCUMENT_ROOT => '/home/myself/sharethese' });
   
	$f->set('/home/myself/sharethese/stew.txt) or die('file does not exist');
   
	$f->rel_path; # returns 'stew.txt'

Realize that for the rest of your cgi, ENV DOCUMENT ROOT is still your webshare, public
html, etc. It's just that you can override for the object instance, what the DOCUMENT
ROOT is. 



By default if you want to get path info on a file that is not on disk, an exception is thrown.
If you want to disable that:

	use File::PathInfo({ check_exist => 0 });
	
	my $f = new File::PathInfo;
   
	$f->set('/home/myself/html/sty54wyw5/4y54yy4ew.txt') ;
   
	$f->rel_path; # returns 'sty54wyw5/4y54yy4ew.txt'

Maybe this could be useful if you wanted to work with a path string that *was* present or *will be*.


Absolute path methods are accessible always. 
The relative path methods are accessible *if* you have DOCUMENT ROOT environment variable
set or if you pass the argument DOCUMENT_ROOT to object constructor.

If you are using cgi, ENV DOCUMENT_ROOT is set when you call the program via http (the 
browser). But when you call the program via the cli (command line) it will likely not
be set! This causes some programs to crash when you run then on the command line, and you
scratch your head and ask 'how come?'.
The same goes for the environment variable 'HOME', which is not set when you call your
cgi script via http (browser) but is set if you call it via cli (the command line, shell
access, etc.).

=head1 METHODS

=head2 new()

Argument is either a hash ref or an absolute or relative path to a file.

	my $fi = new File::PathInfo;
	$fi->set('/home/myself/html/file.txt');
   
	# or
   
	my $fi = new File::PathInfo('/home/myself/html/file.txt');

Optional parameters to constructor:

	my $fi = new File::PathInfo({ 
		DOCUMENT_ROOT => '/home/myself/html',
		check_exist => 0,
		time_format => 'yyyy/mm/dd hh::mm',
	});

=over 4

=item 'check_exist'

Defaults to true. If a file does not exist, methods return undef.	
	
=item 'DOCUMENT_ROOT'

Set a different document root variable from the one currently on server.
This variable must be set either in the server or via this argument if you will
use the relative file path methods.

=back

=head2 set()

Unless you provide an argument to the constructor, set() must be called.
You can use set() to iterate through a list of paths.
Argument is a relative or absolute file path.
	
	$f->set('/tmp/trashdir'); # absolute path
   
	$f->set('gfx/logo.gif'); # relative to DOCUMENT ROOT
   
	$f->set('./thisfile.png'); # relative to current working directory

Method C<set()> returns abs path. If the file cannot be resolved to disk
then it warns and returns undef.
If you then call any methods, exceptions are thrown with Carp::croak.

You can do this too:

	$f->set('/home/myself/html/documents/manual.pdf') or die( $File::PathInfo::errstr );
	
	$f->set('documents/manual.pdf') or print "Location: 404.html\n\n" and exit; 

Returns abs path resolved to item in question.

=head2 get_datahash()

Takes no argument. Returns all elements, in a hash. 

Try it out:

	#!/usr/bin/perl -w
	use File::PathInfo;
	use Smart::Comments '###';
	my $f = new File::PathInfo;	
	$f->set '/home/bubba'
	my $hash = $f->get_datahash;
	### $hash

Prints out:

	### $hash: {
	###          abs_loc => '/home',
	###          abs_path => '/home/bubba',
	###          atime => 1173859680,
	###          atime_pretty => '2007/03/14 04:08',
	###          blksize => 4096,
	###          blocks => 8,
	###          ctime => 1173216034,
	###          ctime_pretty => '2007/03/06 16:20',
	###          dev => 2049,
	###          filename => 'bubba',
	###          filename_only => 'bubba',
	###          filesize => '4096',
	###          filesize_pretty => '4k',
	###          gid => 0,
	###          ino => 3626597,
	###          is_binary => 1,
	###          is_dir => 1,
	###          is_file => 0,
	###          is_text => 0,
	###          is_topmost => 0,
	###          mode => 16877,
	###          mtime => 1173216034,
	###          mtime_pretty => '2007/03/06 16:20',
	###          nlink => 3,
	###          rdev => 0,
	###          size => '4096',
	###          uid => 0
	###        }



=head2 errstr()

Returns errot string or undef if no errors are present.

To check for errors you can query the error string.

	$f->set('/home/myself/this') or die($f->errstr);	
	
=head1 ABSOLUTE METHODS

The absolute path methods. 

=head2 abs_loc()

Returns absolute location on disk. Everything but the filename, no trailing file
delimiter (slash).

=head2 abs_path()

Returns absolute path on disk. Notice that all symlinks are resolved with Cwd::abs_path,
so any /../ etc are gone.

=head2 filename()

Returns filename, no leading directories, no leading file delimiter (slash).

=head2 filename_only()

Returns filename without extension. 
'/home/myself/this.txt' would return 'this'
Does not return undef.

=head2 ext()

Returns filename ext, if none found, returns undef.

=head1 RELATIVE METHODS

These methods are only available if a DOCUMENT ROOT is defined. 

=head2 rel_path()

relative to DOCUMENT_ROOT

=head2 rel_loc()

location relative to DOCUMENT_ROOT

=head2 is_DOCUMENT_ROOT()

if this *is* the document root
returns undef if DOCUMENT ROOT is not set.

=head2 is_topmost()

if the parent directory is document root.
boolean.
returns undef if DOCUMENT ROOT is not set.

=head2 is_in_DOCUMENT_ROOT()

does this file reside in the DOCUMENT_ROOT tree ?
note that DOCUMENT_ROOT itself *is* the document root, does is not
considered to be *in* the document root. this is partly for security
reasons.

=head2 DOCUMENT_ROOT()

Returns doc root, returns undef if not set, or if it cant resolve to abs path on disk.
You can override the DOCUMENT root like this:

	my $fi = new File::PathInfo('./path/to/file.tmp',{ DOCUMENT_ROOT => '/home/myself' });

Doc root is also resolved for symlinks and . and .. etc.

Using a custom DOCUMENT_ROOT variable for the object instance does not alter the variable
for other cgi programs, etc. Just for the object you created. It is only used internally,
If this class is inherited, $ENV{DOCUMENT_ROOT} is whatever it is set at on the server.
If you provide a different DOCUMENT_ROOT as an argument, $ENV{DOCUMENT_ROOT} still returns
the server set variable. It is method DOCUMENT_ROOT() that returns the internally used value.

You do not have to provide a DOCUMENT_ROOT value to the constructor, the variable is not needed
unless you use the relative path methods

Again, the order of priority to define what the DOCUMENT ROOT is for an instance
of File::PathInfo is:

First, in argument to contructor

Second, if your environment variable DOCUMENT_ROOT is set. 

You can also call DOCUMENT_ROOT_set() 

=head2 DOCUMENT_ROOT_set()

argumnent is abs path to document root
will warn if not a dir on disk

=head1 STAT METHODS

These methods ask useful things like, is the file a directory, is it binary,
is it text, what is the mtime, etc. These methods load data on call, they can 
be expensive if you are looping through thousands of files. So don't worry 
because if you don't need them, they are not called.
Using one or more of these methods makes one stat call only.

=head2 is_binary()

returns boolean true or false.

=head2 is_text()

returns boolean true or false.

=head2 is_dir()

returns boolean true or false.

=head2 is_file()

returns boolean true or false.

=head2 ctime()

=head2 atime()

=head2 mtime()

=head2 uid()

=head2 ino()

=head2 blksize()

=head2 blocks()

=head2 dev()

=head2 gid()

=head2 mode()

=head2 nlink()

=head2 rdev()

=head2 size()

=head2 filesize_pretty()

Returns filesize in k, with the letter k in the end returns 0k if filesize is 0 .

=head2 ctime_pretty()

=head2 atime_pretty()

=head2 mtime_pretty()

Returns these timestamps formatted to 'yyyy/mm/dd hh:mm' by default. 
To change the format, pass it as argument to object constructor as such:

	my $r = new File::PathInfo({ time_format => 'yyyy_mm_dd' });
	
	$r->set('/home/myself/archive1.zip');
	
	$r->ctime_pretty; # now holds 1999_11_13
   
=head2 filesize()

Returns filesize in bites.


=head1 PROCEDURAL SUBROUTINES

None of these functions are exported by default.
These subs are used by the oo methods internally, and you can use them in your code also
by the normal import ways:

	use File::PathInfo ':all';
   
	use File::PathInfo qw(abs_path_n);

=head2 abs_path_n()

just like Cwd::abs_path() but, does not resolve symlinks. Just cleans up the path.
argument is an absolute path.

=head1 PACKAGE SETTINGS

Resolve symlinks? Default is 1 ( Not Yet Implemented )

	File::PathInfo::RESOLVE_SYMLINKS = 0;	

Debug

	File::PathInfo::DEBUG = 1;	
	
=head1 CAVEATS

This is currently for unix filesystems. File::PathInfo will NOT work on non POSIX operating
systems. Trying to set an abs path like C:/something will throw an exception.

The module gets very angry when you set() seomthing like '/etc', anything that sits close to
the root of the filesystem. This is on purpose.

=head1 TODO

Let people specify a file delimiter for mac and windoze.

Maybe Time::Format is not appropriate here.

=head1 BUGS

Please report any bugs to AUTHOR. 
You can also fill a bug report with http:://rt.cpan.org

=head1 PREREQUISITES

L<Cwd>, L<Carp>, L<Time::Format> and possibly L<Smart::Comments> for testing.

=head1 SEE ALSO

L<File::PathInfo::Ext>
L<Cwd>
L<File::Basename>

=head1 AUTHOR

Leo Charre leocharre at cpan dot org

=head1 COPYRIGHT

Copyright (c) 2009 Leo Charre. All rights reserved.

=head1 LICENSE

This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself, i.e., under the terms of the "Artistic License" or the "GNU General Public License".

=head1 DISCLAIMER

This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the "GNU General Public License" for more details.
   
=cut

