Object-PadX-Enum
view release on metacpan or search on metacpan
lib/Object/PadX/Enum.pm view on Meta::CPAN
Declares a superclass; equivalent to L<Object::Pad>'s C<:isa>. The package is
loaded automatically. If a VERSION is given, C<< CLASS->VERSION(VERSION) >> is
called to enforce it.
An C<enum> may inherit from another C<enum>. Fields, methods, roles and
C<ADJUST> phasers from the parent are inherited normally. The parent's
B<items> are I<not> inherited: the child has its own ordinal-zero-based item
sequence, and accessing a parent item name on the child raises an error. The
child's C<values>, C<from_ordinal> and C<from_name> see only the child's
items. A parent enum must be finalized (i.e. its declaration must have
already executed at runtime) before a child enum that inherits from it; in
practice this is satisfied by normal source ordering and C<use> ordering.
=item C<:does(ROLE)>, C<:does(ROLE VERSION)>
Composes a role into the enum class. May be repeated for multiple roles. The
role package is loaded automatically.
=back
The class attributes C<:abstract>, C<:strict>, C<:repr> and C<:lexical_new>
are not supported. C<:abstract> is semantically incompatible with C<item>
(singletons cannot be constructed for an abstract class); the others have no
public L<Object::Pad::MOP::Class> entry point and would require reaching into
private Object::Pad internals.
=item * C<item NAME ( ARGS );>
Declares a named singleton instance of the enclosing C<enum>. C<ARGS> is the
key/value list passed to the auto-generated constructor; the parentheses (and
the arg list) are optional, so C<item FOO;> is equivalent to C<item FOO();>.
=back
After the C<enum> block closes, the following class-level methods are
installed on the enum class for each declared singleton C<NAME>:
$singleton = ClassName->NAME; # the named singleton
@all = ClassName->values; # all singletons in declaration order
$byord = ClassName->from_ordinal(0);
$byname = ClassName->from_name("RED");
Direct construction via C<< ClassName->new(...) >> is blocked after the
C<enum> block closes; the only ways to obtain a singleton are the per-item
accessor, C<from_name>, and C<from_ordinal>. Subclasses (whether plain
C<class> or another C<enum>) may still call C<new> on themselves; the block
applies only to direct invocation on the enum class itself.
=head1 CAVEATS
=over 4
=item *
User C<field>s require explicit C<:param> if you intend to set them via
C<item> args. C<Object::PadX::Enum> does I<not> inject C<:param> automatically.
=item *
Singletons are constructed at the runtime of the compilation unit that
contains the C<enum> declaration, after that unit's C<UNITCHECK> phase. They
are therefore not visible from earlier C<BEGIN>/C<UNITCHECK> blocks of the
same unit. Normal runtime code (including code inside C<do BLOCK> and
C<eval "STRING"> blocks executed during main runtime) sees them as expected.
=item *
C<enum>-level C<:abstract>, C<:strict>, C<:repr> and C<:lexical_new> are not
supported. See the description of the C<enum> keyword above for the rationale;
C<:isa> and C<:does> I<are> supported.
=item *
The names C<values>, C<from_ordinal>, C<from_name>, C<ordinal> and C<name> are
reserved and must not be used as C<item> names.
=back
=cut
# Per-class state captured during compilation.
# $Pending{$class} = { meta => $meta, items => [ [ $name, \@args, $line ], ... ], seen => { $name => 1 } }
my %Pending;
# Permanent per-class registry of finalized enum item names, in declaration
# order. Populated by `_finalize_enum`. Queried by descendant enum finalizes
# (to shadow inherited item accessors) and could be useful for introspection
# in the future. Keys are class names; values are arrayrefs of item names.
my %EnumItems;
my %RESERVED_ITEM_NAMES = map { $_ => 1 } qw(
values from_ordinal from_name ordinal name
new BUILD DOES META
);
sub import {
my $class = shift;
my $caller = caller;
$^H{ 'Object::PadX::Enum/enum' } = 1;
$^H{ 'Object::PadX::Enum/item' } = 1;
Object::Pad->import_into( $caller );
}
# Attributes that have a documented public-MOP entry point.
my %ENUM_ATTR_HANDLERS = (
isa => \&_attr_isa,
extends => \&_attr_isa,
does => \&_attr_does,
);
# Attributes that exist on Object::Pad's `class` keyword but are deliberately
# rejected here. The message explains why so users aren't left guessing.
my %ENUM_ATTR_REJECTED = (
abstract => "':abstract' is incompatible with enum: singleton values cannot be constructed for an abstract class",
strict => "':strict' is not supported on enum (no public Object::Pad MOP entry point); declare a plain 'class' instead",
repr => "':repr' is not supported on enum (no public Object::Pad MOP entry point); declare a plain 'class' instead",
lexical_new => "':lexical_new' is not supported on enum (no public Object::Pad MOP entry point); declare a plain 'class' instead",
);
# Load $pkg via `require`, mirroring Object::Pad's :isa/:does autoload. Returns
( run in 1.450 second using v1.01-cache-2.11-cpan-9581c071862 )