NAME
Class::AutoGenerate::Declare - Declarations for an auto-generating class loader
SYNOPSIS
# Create a customized class loader (auto-generator)
package My::ClassLoader;
use Class::AutoGenerate -base;
# Define a matching rule that generates some code...
requiring 'Some::**::Class' => generates { qq{
sub print_my_middle_names { print $1,"\n" }
} };
DESCRIPTION
EXPERIMENTAL. I'm trying this idea out. Please let me know what you think by contacting me using the information listed under "AUTHOR". This is an experiment and any and all aspects of the API are up for revision at this point and I'm not even sure I'll maintain it, but I hope it will be found useful to myself and others.
You do not use this class directly, but it contains the documentation for how to declare a new auto-generating class loader. To use this class, just tell Class::AutoGenerate that you are building a base class:
package My::ClassLoader;
use Class::AutoGenerate -base;
This will then import the declarations described here into your class loader so that you can define your auto-generation rules.
DECLARATIONS
requiring PATTERN => generates { ... };
The requiring
rule tests the pattern against the given package name and runs the generates
block if there's a match. The pattern can be any of the following:
- Package Name
-
If you provide an exact package name (one containing only letters, numbers, underscores, and colons), then only that exact name will be matched.
For example:
requiring 'TestApp::Model::Flooble' => ...
would only match when exactly
TestApp::Model::Flooble
was required or used. - Package Glob
-
If you provide a pattern string containing one or more wildcards, the pattern will match any package matching the wildcard pattern. This is very similar to how file globs work, but we use "::" instead of "/" as our divider. There are three different wildcards available:
- 1 Single Asterisk (*). A single asterisk will match zero or more characters of a single package name component.
-
For example:
requiring '*::Model::*Collection' => ...
will match
TestApp::Model::Collection
andTestApp::Model::FloobleCollection
andSomeOtherApp::Model::WakkaCollection
. - 1 Double Asterisk (**). A double asterisk will match zero or more chaters of a package name, possibly spanning multiple double-colon (::) separators.
-
For example:
requiring '**::Model::**Collection' => ...
will match
TestApp::Plugin::Charts::Model::Deep::Model::NameCollection
andTestApp::Model::FloobleCollection
andSomeOtherApp::Model::Collection
. - 1 Question mark (?). A question mark will match exactly one character in a package name.
-
For example:
requiring 'TestApp??::Record' => ...
will match
TestAppAA::Record
andTestApp12::Record
.
Each occurrence of a wildcard will be captured for use in the "generates" block. The first wildcard will be
$1
, the second$2
, etc.For example:
requiring 'TestApp??::**::*' => ...
would match
TestApp38::A::Package::Name::Blah
and would have the following values available ingenerates
:$1 = '3'; $2 = '8'; $3 = 'A::Package::Name'; $4 = 'Blah';
- Regular Expression
-
You may use a regular expression to match anything more complicated than this. (In fact, the previous matching mechanism are converted to regular expressions, but are convenient for handling the common cases.)
For example:
requiring qr/^(.*)::(\w+)::(\w+)(\d{2})$/ => ...
Any captures performed in the regular expression will be available as
$1
,$2
, etc. in the "generates" block. - Array of Matches
-
Finally, you may also place a series of matches into an array. The given generates block will be used if any of the matches match a given module name.
requiring [ 'App', 'App::**', qr/^SomeOther::(Thing|Whatsit)$/ ] => ...
generates { ... }
This handles the second half of the requiring/generates statement. The code block may contain any code you need, but you'll probably want it to contain statements for generating code to go into the required class.
requiring 'My::*' => generates {
my $name = $1;
extends "My::Base::$name";
uses 'Scalar::Util', 'looks_like_number';
defines '$scalar' => 14;
defines '@array' => [ 1, 2, 3 ];
defines '%hash' => { x => 1, y => 2 };
defines 'package_name' => sub { $package };
defines 'short_name' => sub { $name };
};
If we included the rule above, intantiated the class loader, and then ran:
use My::Flipper;
A class would be generated named My::Flipper
that uses My::Base::Flipper
as its only base class, imports the looks_like_number
function from Scalar::Util, defines a scalar package variable $scalar
set to 14, an array package variable, @array
, set to (1, 2, 3)
, a hash package variable named %hash
set to (x =
1, y => 2)>, and two subroutines named package_name
and short_name
.
extends CLASSES
This subroutine is used with "generates" to mark the generated class as extending the named class or classes. This pushes the named classes into the @ISA
array for the class when it is generated.
uses CLASS, ARGS
This subroutine states that the generated class uses another package. The first argument is the class to use and the remaining arguments are passed to the import method of the used class (the first argument may also be a version number, see "use" in perlfunc).
requires EXPR
This is similar to "uses", but uses "require" in perlfunc instead of use
.
defines NAME => VALUE
This is the general purpose definition declaration. If the given name starts with a dollar sign ($), then a scalar value is created. If the given name starts with an at sign (@), then an array value is added to the class. If the given starts with a percent sign (%), then a hash value will be generated. Finally, if it starts with a letter, underscore, or ampersand (&), a subroutine is added to the package.
The given value must be appropriate for the type of definition being generated.
generate_from SOURCE
If you need to inject code directly into the package generated, this is the general purpose way to do it. Just pass a string (or use one of the helpers "source_file" or "source_file" below) and that code will be evaluated within the new package.
requiring 'Some::Class' => generates {
extends 'Class::Access::Fast';
generate_from source_code qq{
__PACKAGE__->mk_accessors( qw/ name title description / );
};
};
Caution: If user input has any effect on the code generated, you should make certain that all input is carefully validated to prevent code injection.
source_code SOURCE
This method is purely for use with making your code a little easier to read. It doesn't do anything but return the argument passed to it.
source_file FILENAME
Given a file name, this evalutes the Perl in that file within the context of the package.
requiring 'Another::Class' => generates {
generate_from source_file 'code_base.pl';
};
AUTHOR
Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
COPYRIGHT AND LICENSE
Copyright 2007 Boomer Consulting, Inc.
This program is free software and may be modified and distributed under the same terms as Perl itself.