Code::Style::Kit - build composable bulk exporters
version 1.0.2
To build a "part":
package My::Kit::Part; use strict; use warnings; sub feature_trytiny_default { 1 } sub feature_trytiny_export_list { 'Try::Tiny' } 1;
To build the kit:
package My::Kit; use parent qw(Code::Style::Kit My::Kit::Part My::Kit::OtherPart); 1;
To use the kit:
package My::App; use My::Kit; # you now have Try::Tiny imported, plus whatever OtherPart did
This package simplifies writing "code style kits". A kit (also known as a "policy") is a module that encapsulates the common pragmas and modules that every package in a project should use. For instance, it might be a good idea to always use strict, enable method signatures, and use true, but it's cumbersome to put that boilerplate in every single file in your project. Now you can do that with a single line of code.
use strict
use true
Code::Style::Kit is not to be used directly: you must write a package that inherits from it. Your package can (and probably should) also inherit from one or more "parts". See Code::Style::Kit::Parts for information about the parts included in this distribution.
Code::Style::Kit
use
Code::Style::Kit::Parts
Please don't use this for libraries you intend to distribute on CPAN: you'd be forcing a bunch of dependencies on every user. These kits are intended for applications, or "internal" libraries that don't get released publicly.
A kit provides a set of "features" (like "tags" in Exporter or "groups" in Sub::Exporter). Feature names must match ^\w+$. Some features may be exported by default.
Exporter
Sub::Exporter
^\w+$
A simple example of a feature, from the synopsis:
sub feature_trytiny_default { 1 } sub feature_trytiny_export_list { 'Try::Tiny' }
or, equivalently:
sub feature_trytiny_default { 1 } sub feature_trytiny_export { my ($self, $caller) = @_; require Try::Tiny; Try::Tiny->import::into($caller); }
The feature_*_default method says that this feature should always be exported (unless the user explicitly asks us not to). The feature_*_export_list is a shortcut for the simple case of re-exporting one or more entire packages. Alternatively, the feature_*_export sub provides full flexibility, when you need it.
feature_*_default
feature_*_export_list
feature_*_export
Sometimes you need features to be exported in a certain order:
package My::Kit; use parent qw(Code::Style::Kit Code::Style::Kit::Parts::Common); sub feature_class_export_list { 'Moo' } sub feature_class_order { 200 } sub feature_singleton_export { require Role::Tiny; Role::Tiny->apply_roles_to_package($_[1], 'MooX::Singleton'); } sub feature_singleton_order { 210 }
If someone says either:
package My::Class; use My::Kit 'class', 'singleton';
or:
package My::Class; use My::Kit 'singleton', 'class';
then Moo will be imported first, then MooX::Singleton will be applied.
Moo
MooX::Singleton
All features that don't have a feature_*_order sub are assumed to have order 100.
feature_*_order
Sometimes you want to make sure that a certain feature is exported whenever another one is.
sub feature_class_export_list { 'Moo' } sub feature_singleton_export { my ($self, $caller) = @_; $self->also_export('class'); require Role::Tiny; Role::Tiny->apply_roles_to_package($caller, 'MooX::Singleton'); }
Now:
package My::Class; use My::Kit 'singleton';
will work. Notice that you don't have to worry whether the feature was defined via "export" or "export_list": it just works.
Also, a feature can be imported only once, so
will not create problems.
Maybe you'd like for another feature to be exported, but you're not sure if it's provided by the kit. This can happen when writing reusable parts.
sub feature_class_export { my ($self, $caller) = @_; require Moo; Moo->import::into($caller); $self->maybe_also_export('types'); }
now, if the final kit provides a "types" feature, it will be exported whenever the "class" feature is requested.
Different "parts" can provide the same feature. Their export functions will be invoked in method resolution order (usually, the order they appear in @ISA).
@ISA
So, having:
package My::Kit::Part; sub feature_test_export_list { 'Test::Most' }
and:
package My::Kit::OtherPart; sub feature_test_export_list { 'Test::Failure' }
this kit:
will export Test::Most first, then Test::Failure, when used as use My::Kit 'test'.
Test::Most
Test::Failure
use My::Kit 'test'
Defaults are also affected by this, and the last one wins: if My::Kit::OtherPart::feature_test_default returned 1, the feature would be exported by default.
My::Kit::OtherPart::feature_test_default
You may want to prevent two features from being exported at the same time:
sub feature_class_export { my ($self, $caller) = @_; croak "can't be a class and a role" if $self->is_feature_requested('role'); ... } sub feature_role_export { my ($self, $caller) = @_; croak "can't be a class and a role" if $self->is_feature_requested('class'); ... }
Sometimes you need to have a bit more information than just "import this feature". For example, Mojo::Base needs a superclass name on its import list. In that case you can do:
Mojo::Base
sub feature_mojo_takes_arguments { 1 } sub feature_mojo_export { my ($self, $caller, @arguments) = @_; require Mojo::Base; Mojo::Base->import::into( $caller, @arguments ? @arguments : '-base', ); }
and the user can do:
use My::Kit mojo => [ 'Some::Base::Class' ];
(the arrayref is needed to distinguish argument lists from feature names).
import
use My::Kit; use My::Kit 'feature_i_want', '-feature_i_dont_want';
When a package inheriting Code::Style::Kit get used, this method:
collects all the features that the kit exports by default
adds the features listed in the arguments
removes the features listed in the arguments with a - in front
-
exports the resulting set of features
is_feature_requested
if ($self->is_feature_requested($name)) { ... }
Returns true if the named feature is being exported (either because it's exported by default and not removed, or because it was asked for explicitly).
also_export
$self->also_export($name); $self->also_export($name, \@arguments);
Export the named feature to the caller (optionally with arguments). Dies if the feature is not provided by the kit.
maybe_also_export
$self->maybe_also_export($name); $self->maybe_also_export($name, \@arguments);
Export the named feature to the caller, same as "also_export", but if the feature is not provided by the kit, this method just returns.
Gianni Ceccarelli <gianni.ceccarelli@broadbean.com>
This software is copyright (c) 2019 by BroadBean UK, a CareerBuilder Company.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Code::Style::Kit, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Code::Style::Kit
CPAN shell
perl -MCPAN -e shell install Code::Style::Kit
For more information on module installation, please visit the detailed CPAN module installation guide.