Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
File::ShareDir::ProjecUsertContributed Perl DFile::ShareDir::ProjectDistDir(3)

NAME
       File::ShareDir::ProjectDistDir -	Simple set-and-forget using of a
       '/share'	directory in your projects root

VERSION
       version 1.000008

DETERRENT
       STOP!. Before using this	distribution, some warnings MUST be
       considered.

       The primary use-case for	this module is targeted	at development
       projects	that are NOT intended for "CPAN".

       As such,	using it for "CPAN" is generally a bad idea, and better
       solutions generally involve the less fragile "Test::File::ShareDir",
       constraining any	magical	behavior exclusively to	where it is needed:
       Tests.

       Why?

       o   Determining whether or not we are "dev" during "runtime" is a
	   perilous heuristic that routinely fails with	even slightly unusual
	   file	system layouts.

       o   Auto-magical	changing of behavior at	"runtime" based	on the above
	   leads to many surprising and	hard to	debug problems.

       For these reason, it is dangerous to rely on this distribution while
       striving	to produce quality code.

       If this documentation is	not sufficient to dissuade you,	I must
       strongly	implore	you to choose the "strict" mechanism, because that
       substantially reduces the possibilities with regards to false-positive
       of potential "dev" directories.

       I have in mind to find a	better mechanism to deliver the	same
       objective, but no solutions are forthcoming at this time.

SYNOPSIS
	 package An::Example::Package;

	 use File::ShareDir::ProjectDistDir;

	 # during development, $dir will be $projectroot/share
	 # but once installed, it will be wherever File::Sharedir thinks it is.
	 my $dir = dist_dir('An-Example')

       Project layout requirements:

	 $project/
	 $project/lib/An/Example/Package.pm
	 $project/share/   # files for package 'An-Example' go here.

       You can use a directory name other than 'share' ( Assuming you make
       sure when you install that, you specify the different directory there
       also ) as follows:

	 use File::ShareDir::ProjectDistDir ':all', defaults =>	{
	   projectdir => 'templates',
	 };

METHODS
   import
	   use File::ShareDir::ProjectDistDir (@args);

       This uses "Sub::Exporter" to do the heavy lifting, so most usage	of
       this module can be maximized by understanding that first.

       o   ":all"

	       ->import( ':all'	, .... )

	   Import both "dist_dir" and "dist_file"

       o   "dist_dir"

	       ->import('dist_dir' , .... )

	   Import the dist_dir method

       o   "dist_file"

	       ->import('dist_file' , .... )

	   Import the dist_file	method

       o   "projectdir"

	       ->import( .... ,	projectdir => 'share' )

	   Specify what	the project directory is as a path relative to the
	   base	of your	distributions source, and this directory will be used
	   as a	"ShareDir" simulation path for the exported methods During
	   development.

	   If not specified, the default value 'share' is used.

       o   "filename"

	       ->import( .... ,	filename => 'some/path/to/foo.pm' );

	   Generally you don't want to set this, as its	worked out by caller()
	   to work out the name	of the file its	being called from. This	file's
	   path	is walked up to	find the 'lib' element with a sibling of the
	   name	of your	"projectdir".

       o   "distname"

	       ->import( .... ,	distname => 'somedistname' );

	   Specifying this argument changes the	way the	functions are emitted
	   at installed	"runtime", so that instead of taking the standard
	   arguments File::ShareDir does, the specification of the "distname"
	   in those functions is eliminated.

	   i.e:

	       # without this flag
	       use File::ShareDir::ProjectDistDir qw( :all );

	       my $dir = dist_dir('example');
	       my $file	= dist_file('example', 'path/to/file.pm' );

	       # with this flag
	       use File::ShareDir::ProjectDistDir ( qw(	:all ),	distname => 'example' );

	       my $dir = dist_dir();
	       my $file	= dist_file('path/to/file.pm' );

       o   "strict"

	       ->import( ... , strict => 1 );

	   This	parameter specifies that all "dist" "sharedirs"	will occur
	   within the "projectdir" directory using the following layout:

	       <root>/<projectdir>/dist/<DISTNAME>/

	   As opposed to

	       <root>/<projectdir>

	   This	means if Heuristics misfire and	accidentally find another
	   distributions "share" directory, it will not	pick up	on it unless
	   that	"share"	directory also has that	layout,	and will instead
	   revert to the "installdir" path in @INC

	   This	parameter may become the default option	in the future

	   Specifying this parameter also mandates you MUST declare the
	   "DISTNAME" value in your file somewhere. Doing otherwise is
	   considered insanity anyway.

       o   "defaults"

	       ->import( ... , defaults	=> {
		   filename => ....,
		   projectdir => ....,
	       });

	   This	is mostly an alternative syntax	for specifying "filename" and
	   "projectdir", which is mostly used internally, and their
	   corresponding other values are packed into this one.

       Sub::Exporter tricks of note.

       Make your own sharedir util

	   package Foo::Util;

	   sub import {
	       my ($caller_class, $caller_file,	$caller_line )	= caller();
	       if ( grep { /share/ } @_	) {
		   require File::ShareDir::ProjectDistDir;
		   File::ShareDir::ProjectDistDir->import(
		       filename	=> $caller_file,
		       dist_dir	=> { distname => 'myproject' , -as => 'share' },
		       dist_dir	=> { distname => 'otherproject'	, -as => 'other_share' , projectdir => 'share2'	},
		       -into =>	$caller_class,
		   );
	       }
	   }

	   ....

	   package Foo;
	   use Foo::Util qw( share );

	   my $dir = share();
	   my $other_dir => other_share();

   build_dist_dir
	   use File::ShareDir::ProjectDirDir ( : all );

	   #  this calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
	     'dist_dir'	=> {},
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
	   );

	   use File::ShareDir::ProjectDirDir ( qw( :all	), distname => 'example-dist' );

	   #  this calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
	     'dist_dir'	=> {},
	     { distname	=> 'example-dist', defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
	   );

	   use File::ShareDir::ProjectDirDir
	     dist_dir => { distname => 'example-dist', -as => 'mydistdir' },
	     dist_dir => { distname => 'other-dist',   -as => 'otherdistdir' };

	   # This calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
	     'dist_dir',
	     { distname	=> 'example-dist' },
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
	   );
	   my $othercoderef = File::ShareDir::ProjectDistDir->build_dist_dir(
	     'dist_dir',
	     { distname	=> 'other-dist'	},
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
	   );

	   # And leverages Sub::Exporter to create 2 subs in your package.

       Generates the exported 'dist_dir' method. In development	environments,
       the generated method will return	a path to the development directories
       'share' directory. In non-development environments, this	simply returns
       "File::ShareDir::dist_dir".

       As a result of this, specifying the Distribution	name is	not required
       during development ( unless in "strict" mode ), however,	it will	start
       to matter once it is installed. This is a potential avenues for bugs if
       you happen to name it wrong.

       In "strict" mode, the distribution name is ALWAYS REQUIRED, either at
       least at	"import" or "dist_dir()" time.

   build_dist_file
	   use File::ShareDir::ProjectDirDir ( : all );

	   #  this calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
	     'dist_file' => {},
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
	   );

	   use File::ShareDir::ProjectDirDir ( qw( :all	), distname => 'example-dist' );

	   #  this calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
	     'dist_file' => {},
	     { distname	=> 'example-dist', defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
	   );

	   use File::ShareDir::ProjectDirDir
	     dist_file => { distname =>	'example-dist',	-as => 'mydistfile' },
	     dist_file => { distname =>	'other-dist',	-as => 'otherdistfile' };

	   # This calls
	   my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
	     'dist_file',
	     { distname	=> 'example-dist' },
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
	   );
	   my $othercoderef = File::ShareDir::ProjectDistDir->build_dist_file(
	     'dist_file',
	     { distname	=> 'other-dist'	},
	     { defaults	=> { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
	   );

	   # And leverages Sub::Exporter to create 2 subs in your package.

       Generates the 'dist_file' method.

       In development environments, the	generated method will return a path to
       the development directories 'share' directory. In non-development
       environments, this simply returns "File::ShareDir::dist_file".

       Caveats as a result of package-name as stated in	"build_dist_dir" also
       apply to	this method.

SIGNIFICANT CHANGES
   1.000000
       Strict Mode.

       Using Strict Mode

	   use File::ShareDir::ProjectDistDir ':all', strict =>	1;
	   use File::ShareDir::ProjectDistDir 'dist_dir' => { strict =>	1 };

       Why you should use strict mode

       Starting	with 1.000000, there is	a parameter "strict" that changes how
       "sharedir" resolution performs.

       Without strict:

	   lib/...
	   share/...

       With strict

	   lib/...
	   share/dist/Dist-Name-Here/...

       This technique greatly builds resilience	to the long standing problem
       with "develop" vs "install" heuristic ambiguity.

       Here at least,

	   dist_dir('Dist-Name')

       Will instead fall back to

	   @INC/auto/share/dist/Dist-Name

       When

	   share/dist/Dist-Name

       Does not	exist.

       This means if you have a	layout like this:

	   <DEVROOT>/inc/<a local::lib path here>
	   <DEVROOT>/lib/<development files here>

       Then when "Foo-Bar-Baz" is installed as:

	   <DEVROOT>/inc/lib/Foo/Bar/Baz.pm
	   <DEVROOT>/inc/lib/auto/share/dist/Foo-Bar-Baz

       Then "Baz.pm" will not see the "DEVROOT"	and assume "Hey, this is
       development" and	then proceed to	try finding files in "DEVROOT/share"

       Instead,	"DEVROOT" must have "DEVROOT/share/dist/Foo-Bar-Baz" too,
       otherwise it reverts to "DEVROOT/inc/lib/auto..."

       "Path::Class" interfaces	deprecated and dependency dropped.

       If you have any dependence on this function, now	is the time to get
       yourself	off it.

       Minimum Changes to stay with "Path::Class" short	term.

       As the dependency has been dropped on "Path::Class", if you have	"CPAN"
       modules relying on "Path::Class"	interface, you should now at a very
       minimum start declaring

	   { requires => "Path::Class" }

       This will keep your dist	working, but will not be future	proof against
       further changes.

       Staying with "Path::Class" long term.

       Recommended approach if you want	to stay	using the "Path::Class"
       interface:

	   use File::ShareDir::... etc
	   use Path::Class qw( dir file	);

	   my $dir = dir( dist_dir('Dist-Name')	);

       This should future-proof	you against anything File::ShareDir may	do in
       the future.

       "Versioning Scheme arbitrary converted to float"

       This change is a	superficial one, and should have no bearing on how
       significant you think this release is.

       It is a significant release, but	the primary reason for the version
       change is simply	to avoid compatibility issues in versions themselves.

       However,	outside	that, "x.y.z" semantics	are still intended to be semi-
       meaningful, just	with less "." and more 0 ao

       "dev" path determination	now deferred to	call time instead of "use"

       This was	essentially a required change to make "strict" mode plausible,
       because strict mode _requires_ the "distname" to	be known, even in the
       development environment.

       This should not have any	user visible effects, but please, if you have
       any problems, file a bug.

       "file" component	determination wrested from "File::ShareDir".

	   dist_file('foo','bar')

       Is now simply sugar syntax for

	   path(dist_dir('foo'))->child('bar')

       This should have	no side	effects	in your	code, but please file any bugs
       you experience.

       ( return	value is still "undef" if the file does	not exist, and still
       "croak"'s if the	file is	not a file, or unreadable, but these may both
       be subject to change )

   0.5.0 - Heuristics and Return type changes
       New "devdir" heuristic

       Starting	with 0.5.0, instead of using our simple	"lib/../share" pattern
       heuristic, a more advanced heuristic is used from the new
       "Path::FindDev" and "Path::IsDev".

       This relies on a	more "concrete"	marker somewhere at the	top of your
       development tree, and more importantly, checks for the existence	of
       specific	files that are not likely to occur outside a project root.

       "lib" and "share" based heuristics were a little	fragile, for a few
       reasons:

       o   "lib" can, and does appear all over UNIX file systems, for purposes
	   other than development project roots.

	   For instance, have a	look in	"/usr/"

	       /usr/bin
	       /usr/lib
	       /usr/share  ## UHOH.

	   This	would have the very bad	side effect of anything	installed in
	   "/usr/lib" thinking its "in development".

	   Fortunately,	nobody seems to	have hit this specific bug, which I
	   suspect is due only to "/usr/lib" being a symbolic link on most
	   x86_64 systems.

       o   "lib" is also reasonably common within "CPAN" package names.

	   For instance:

	       lib::abs

	   Which means you'll have a hierarchy like:

	       $PREFIX/lib/lib/abs

	   All you need	for something to go horribly wrong would be for
	   somebody to install a "CPAN"	module named:

	       share::mystuff

	   Or similar, and instantly, you have:

	       $PREFIX/lib/lib/
	       $PREFIX/lib/share/

	   Which would mean any	module calling itself "lib::*" would be	unable
	   to use this module.

       So instead, as of 0.5.0,	the heuristic revolves around certain specific
       files being in the "dev"	directory.

       Which is	hopefully a more fault resilient mechanism.

       New Return Types

       Starting	with 0.5.0, the	internals are now based	on "Path::Tiny"
       instead of "Path::Class", and as	a result, there	may be a few glitches
       in transition.

       Also, previously	you could get a	"Path::Class::*" object	back from
       "dist_dir" and "dist_file" by importing it as such:

	   use File::ShareDir::ProjectDistDir
	       qw( dist_dir dist_file ),
	       defaults	=> { pathclass => 1 };

       Now you can also	get "Path::Tiny" objects back, by passing:

	   use File::ShareDir::ProjectDistDir
	       qw( dist_dir dist_file ),
	       defaults	=> { pathtiny => 1 };

       For the time being, you can still get Path::Class objects back, it is
       deprecated since	1.000000

       ( In fact, I may	even make 2 specific sub-classes of "PDD" for people
       who want	objects	back, as it will make the "API"	and the	code much
       cleaner )

AUTHOR
       Kent Fredric <kentnl@cpan.org>

COPYRIGHT AND LICENSE
       This software is	copyright (c) 2015 by Kent Fredric <kentnl@cpan.org>.

       This is free software; you can redistribute it and/or modify it under
       the same	terms as the Perl 5 programming	language system	itself.

perl v5.24.1			  2015-07-12 File::ShareDir::ProjectDistDir(3)

NAME | VERSION | DETERRENT | SYNOPSIS | METHODS | SIGNIFICANT CHANGES | AUTHOR | COPYRIGHT AND LICENSE

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=File::ShareDir::ProjectDistDir&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports>

home | help