NAME
Syntax::Collector - collect a bundle of modules into one
SYNOPSIS
In lib/Example/ProjectX/Syntax.pm
package Example::ProjectX::Syntax;
use 5.010;
our $VERSION = 1;
use Syntax::Collector -collect => q/
use strict 0;
use warnings 0;
use feature 0 ':5.10';
use Scalar::Util 1.21 qw(blessed);
/;
1;
__END__
In projectx.pl:
#!/usr/bin/perl
use Example::ProjectX::Database;
use Example::ProjectX::Syntax 1;
# strict, warnings, feature ':5.10', etc are now enabled!
say "Welcome to ProjectX";
DESCRIPTION
Perl is such a flexible language that the language itself can be
extended from within. (Though much of the more interesting stuff needs
XS hooks like Devel::Declare.)
One problem with this is that it often requires a lot of declarations at
the top of your code, loading various syntax extensions. The syntax
module on CPAN addresses this somewhat by allowing you to load a bunch
of features in one line, provided each syntax feature implements the
necessary API:
use syntax qw/io maybe perform/;
However this introduces problems of its own. If we look at the code
above, it is non-obvious that it requires Syntax::Feature::Io,
Syntax::Feature::Maybe and Syntax::Feature::Perform, which makes it
difficult for automated tools such as Module::Install to automatically
calculate your code's dependencies.
Syntax::Collector to the rescue!
package Example::ProjectX::Syntax;
use 5.010;
use Syntax::Collector -collect => q/
use strict 0;
use warnings 0;
use feature 0 ':5.10';
use Scalar::Util 1.21 qw(blessed);
/;
When you "use Syntax::Collector", you provide a list of modules to
"collect" into a single package (notice the "q/.../"). This list of
modules looks like a big string of Perl code that is going to be passed
to "eval", but don't let that fool you - it is not.
Each line must conform to the following pattern:
(use|no) MODULENAME VERSION (OTHERSTUFF)? ;
(Actually hash comments, and blank lines are also allowed.) The
semantics of all that is pretty much what you'd expect, except that when
MODULENAME begins with "Syntax::Feature::" it's treated with some
DWIMmery, and "install" is called instead of "import". Note that VERSION
is required, but if you don't care which version of a module you use,
it's fine to set VERSION to 0. (Yes, VERSION is even required for
pragmata.)
Now, you ask... why stuff all that structured data into a string, and
parse it out again? Because to naive lexical analysis (e.g.
Module::Install) it really looks like a bunch of "use" lines, and not
just a single quoted string. This helps tools calculate the dependencies
of your collection; and thus the dependencies of other code that uses
your collection.
Because Syntax::Collector provides an "import" method for your
collection package, you cannot provide your own. However, the "import"
method provided will automatically call an "IMPORT" method if it exists.
"IMPORT" is passed a copy of the same arguments that were passed to
"import". (And indeed, it is invoked using "goto" so it should be safe
to check caller(0).)
As well as providing an "import" method for your collection,
Syntax::Collector also provides a "modules" method, which can be called
to find out which modules a collection includes. Called in list context,
it returns a list. Called in scalar context, it returns a reference to a
"{ module => version }" hash.
A SYNTAX COLLECTION AND A UTILS COLLECTION
Your project's syntax module is also a natural place to keep any
frequently used utility functions, constants, etc. Thanks to the
"IMPORT" method described above you can easily export these to the
caller's namespace.
Using with Sub::Exporter
Sub::Exporter has an awesome feature set, so it is better than
Exporter.pm.
package Example::ProjectX::Syntax;
our $VERSION = 1;
use Syntax::Collector -collect => q/
use strict 0;
use warnings 0;
use feature 0 ':5.10';
use Scalar::Util 1.21 qw(blessed);
/;
use Sub::Exporter ();
my $IMPORT = Sub::Exporter::build_exporter({
exports => [qw(true false)],
groups => { booleans => [qw(true false)] },
});
sub IMPORT {
goto $IMPORT;
}
sub true () { !!1 }
sub false () { !!0 }
1;
Using with Exporter.pm
Exporter.pm comes bundled with Perl, so it is better than Sub::Exporter.
package Example::ProjectX::Syntax;
our $VERSION = 1;
use Syntax::Collector -collect => q/
use strict 0;
use warnings 0;
use feature 0 ':5.10';
use Scalar::Util 1.21 qw(blessed);
/;
use Exporter ();
our @EXPORT_OK = qw( true false );
our %EXPORT_TAGS = (
booleans => [qw( true false )],
);
sub IMPORT {
goto &Exporter::import;
}
sub true () { !!1 }
sub false () { !!0 }
1;
CAVEATS
You should not rely on the "use" lines being processed in any particular
order.
BUGS
Please report any bugs to
<http://rt.cpan.org/Dist/Display.html?Queue=Syntax-Collector>.
SEE ALSO
syntax, Sub::Exporter.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2012 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.