NAME
MOP4Import::Declare - map import args to $meta->declare_...()
pragma methods.
SYNOPSIS
#-------------------
# To implement an exporter with MOP4Import::Declare,
# just use it in YourExporter.pm "as base" like following:
package YourExporter {
use MOP4Import::Declare -as_base; # "use strict" is turned on too.
use MOP4Import::Util qw/globref/; # encapsulates "no strict 'refs'".
# This method implements '-foo' pragma,
# and adds method named 'foo()' in $callpack.
sub declare_foo {
my ($myPack, $opts, $callpack) = @_;
*{globref($callpack, 'foo')} = sub (@) { join("! ", "FOOOOOO", @_) };
}
# This method implements [bar => $x, $y, @z] pragma,
# and adds variables $bar, %bar and @bar in $callpack.
sub declare_bar {
my ($myPack, $opts, $callpack, $x, $y, @z) = @_;
my $glob = globref($callpack, 'bar');
*$glob = \ $x;
*$glob = +{bar => $y};
*$glob = \@z;
}
};
1
#-------------------
# Then you can use above from command line like:
% perl -MYourExporter=-foo -le 'print foo bar => 3'
FOOOOOO! bar! 3
%
#-------------------
# Or in another file:
package MyApp;
use YourExporter -foo, [bar => "A", "x", 1..3];
# Above means you called:
# use strict;
# use warnings;
# YourExporter->declare_foo($opts, 'MyApp');
# YourExporter->declare_bar($opts, 'MyApp', "A", "x", 1..3);
print "scalar=$bar\t", "hash=$bar{bar}\t", "array=@bar\n";
# So, you will get:
# scalar=A hash=x array=1 2 3
DESCRIPTION
MOP4Import::Declare is one protocol implementation of MOP4Import family. You can use this module to implement your own exporter in an extensible way.
With MOP4Import::Declare, arguments of import() are mapped into method calls starting with declare_...()
.
"MetaObject Protocol for Import" in this module
import()
method of MOP4Import::Declare briefly does following:
sub import {
my ($myPack, @pragma) = @_;
my $callpack = caller;
$myPack->dispatch_declare(+{}, $callpack, -strict, @pragma);
}
dispatch_declare() dispatches declare_PRAGMA()
pragma handlers based on each pragma argument types (string, arrayref or coderef).
- -PRAGMA
-
use YourExporter -PRAGMA;
-Identifier
, word starting with-
, is dispatched as:$myPack->declare_PRAGMA($opts, $callpack);
Note: You don't need to quote this pragma because perl has special support for this kind of syntax (bareword lead by
-
). - [PRAGMA => ARGS...]
-
use YourExporter [PRAGMA => @ARGS];
ARRAY ref is dispatched as:
$myPack->declare_PRAGMA($opts, $callpack, @ARGS);
- NAME, *NAME, $NAME, %NAME, @NAME, &NAME
-
use YourExporter qw/NAME *NAME $NAME %NAME @NAME &NAME/;
These kind of words (optionally starting with sigil) just behaves as ordinally export/import.
- sub {...}
-
use YourExporter sub { ... };
You can pass callback too.
sub { my ($yourExporterPackage, $opts, $callpack) = @_; # do rest of job }
PRAGMAS
All pragmas below are actually implemented as "declare_PRAGMA" method, so you can override them in your subclass, as you like.
-strict
This pragma turns on use strict; use warnings;
.
-fatal
This pragma turns on use warnings qw(FATAL all NONFATAL misc);
.
[base => CLASS...]
Establish an ISA relationship with base classes at compile time. Like base, this imports %FIELDS
from base classes too.
Note: when target module uses c3 mro, this pragma adds given classes in front of @ISA
.
[parent => CLASS...]
Establish an ISA relationship with base classes at compile time. In addition to "base", this loads requested classes at compile time, like parent.
-as_base, [as_base => FIELD_SPECs...]
This pragma sets YourExporter as base class of target module. Optional arguments are passed to "fields" in fields pragma.
Note: as noted in "base", this pragma cares mro of target module. You can simply inherit classes with "generic" to "specific" order.
[fields => SPEC...]
This pragma adds %FIELDS
definitions to target module, based on given field specs. Each fields specs are either single string or array ref like [FIELD_NAME => SPEC => value, ...]
.
use MOP4Import::Declare
[fields =>
qw/
foo bar baz
/
];
use MOP4Import::Declare
[fields =>
[debug => doc => 'debug level'],
[dbi_dsn => doc => 'DBI connection string'],
qw/dbi_user dbi_password/
];
For more about fields, see whyfields.
field spec hooks.
You can define special hook for field spec. That should named starting with declare___field_with_...
.
sub declare___field_with_foo {
(my $myPack, my $opts, my $callpack, my FieldSpec $fs, my ($k, $v)) = @_;
$fs->{$k} = $v;
# Do other jobs...
}
default
When field bar
in class Foo
has spec default => $VALUE
, method Foo::default_bar
is defined with $VALUE.
sub Foo::default_bar { $VALUE }
If VALUE is CODE ref, it is directly assigned to method symbol.
Note: This spec only cares about defining above default_...
method. To make default value assignment really work, you must have constructor which cooperate well with this. You can use MOP4Import::Base::Configure for that purpose but are not restricted to it. Anyway MOP4Import::Declare itself will be kept constructor agnostic.
[constant => NAME => VALUE]
use YourExporter [constant => FOO => 'BAR', or_ignore => 1];
This pragma adds constant sub NAME
to target module.
or_ignore => BOOL
-
If this option is given and given NAME already defined in target module, skip adding.
-inc
This pragma adds target module to %INC
so that make the module require
safe.
[map_methods => [FROM => TO]...]
This pragma looks up actual sub of TO
and set it to target module with name FROM
. For example:
package MyStore {
use MOP4Import::Declare
[parent => qw/Plack::Session::Store::File/]
, [map_methods => [get => 'fetch'], [set => 'store']];
}
use Plack::Builder;
builder {
enable 'Session::Simple', store => MyStore->new(dir => $sess_dir);
$app
};
METHODS
dispatch_declare($opts, $callpack, PRAGMA...)
This implements MOP4Import::Declare
style type-based pragma dispatching.
YourExporter->dispatch_declare($opts, $callpack, -foo, [bar => 'baz'], '*FOO');
is same as
YourExporter->declare_foo($opts, $callpack);
YourExporter->declare_bar($opts, $callpack, 'baz');
YourExporter->dispatch_import($opts, $callpack, '*FOO');
dispatch_import($opts, $callpack, $STRING)
This mimics Exporter like sigil based import. Actually this dispatches import_...
method with respect to leading sigil. (This means you can override each cases in your subclass). If $STRING
has no sigil, "import_NAME" will be called.
use YourExporter qw/*FOO $BAR @BAZ %QUX &QUUX/;
is same as
BEGIN {
YourExporter->import_GLOB(+{}, $callpack, GLOB => 'FOO');
YourExporter->import_SCALAR(+{}, $callpack, SCALAR => 'BAR');
YourExporter->import_ARRAY(+{}, $callpack, ARRAY => 'BAZ');
YourExporter->import_HASH(+{}, $callpack, HASH => 'QUX');
YourExporter->import_CODE(+{}, $callpack, CODE => 'QUUX');
}
Note: some complex features like export list @EXPORT
, @EXPORT_OK
and :TAG
based import are not implemented.
If you really want to implement those features, you can inherit this module and simply override dispatch_import
. It will be called for all non reference pragmas.
import_NAME($opts, $callpack, $name)
This method (hook) is called when simple word (matches /^\w+$/
) is given as import list.
use YourExporter qw/FOO/;
is same as:
BEGIN {
YourExporter->import_NAME(+{}, __PACKAGE__, 'Foo');
}
import_SIGIL($opts, $callpack, $type, $name)
Actual implementation of import_GLOB
, import_SCALAR
, import_ARRAY
, import_CODE
.
TYPES
Opts
This type of object is always given as a second argument of each invocation of declare_PRAGMA
. This object carries complex info such as caller filename, lineno to each pragma handlers. In simple cases, you don't need to care about these.
Note: field names of this type are about to change, so please do not rely them for now.
FieldSpec
fields pragma in this module creates this type of object for each field specs. Currently, only name
, doc
and default
are declared. But you can extend FieldSpec in your exporter like following:
use YourBaseObject {
use MOP4Import::Declare -as_base;
use MOP4Import::Types
FieldSpec => [[fields => qw/readonly required validator/]];
}
package MyApp {
use YourBaseObject -as_base,
[fields => [app_name => readonly => 1, required => 1]]
}
AUTHOR
KOBAYASHI, Hiroaki <hkoba@cpan.org>
SEE ALSO
MOP4Import, MOP4Import::Types, MOP4Import::PSGIEnv
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.