diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-06-06 17:50:16 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-06-06 17:50:16 +0000 |
commit | 5ac2026f7eed78958d69d051e7a8e993dcf51205 (patch) | |
tree | 298c3d2f08bdfe5689998b11892d72a897985be1 /lib/Moose | |
download | Moose-tarball-5ac2026f7eed78958d69d051e7a8e993dcf51205.tar.gz |
Moose-2.1405HEADMoose-2.1405master
Diffstat (limited to 'lib/Moose')
411 files changed, 49766 insertions, 0 deletions
diff --git a/lib/Moose/Conflicts.pm b/lib/Moose/Conflicts.pm new file mode 100644 index 0000000..612dc9c --- /dev/null +++ b/lib/Moose/Conflicts.pm @@ -0,0 +1,113 @@ +package # hide from PAUSE + Moose::Conflicts; + +use strict; +use warnings; + +# this module was generated with Dist::Zilla::Plugin::Conflicts 0.17 + +use Dist::CheckConflicts + -dist => 'Moose', + -conflicts => { + 'Catalyst' => '5.90049999', + 'Config::MVP' => '2.200004', + 'Devel::REPL' => '1.003020', + 'Dist::Zilla::Plugin::Git' => '2.016', + 'Fey' => '0.36', + 'Fey::ORM' => '0.42', + 'File::ChangeNotify' => '0.15', + 'HTTP::Throwable' => '0.017', + 'KiokuDB' => '0.51', + 'Markdent' => '0.16', + 'Mason' => '2.18', + 'MooseX::ABC' => '0.05', + 'MooseX::Aliases' => '0.08', + 'MooseX::AlwaysCoerce' => '0.13', + 'MooseX::App' => '1.22', + 'MooseX::Attribute::Deflator' => '2.1.7', + 'MooseX::Attribute::Dependent' => '1.1.0', + 'MooseX::Attribute::Prototype' => '0.10', + 'MooseX::AttributeHelpers' => '0.22', + 'MooseX::AttributeIndexes' => '1.0.0', + 'MooseX::AttributeInflate' => '0.02', + 'MooseX::CascadeClearing' => '0.03', + 'MooseX::ClassAttribute' => '0.26', + 'MooseX::Constructor::AllErrors' => '0.021', + 'MooseX::Declare' => '0.35', + 'MooseX::FollowPBP' => '0.02', + 'MooseX::Getopt' => '0.56', + 'MooseX::InstanceTracking' => '0.04', + 'MooseX::LazyRequire' => '0.06', + 'MooseX::Meta::Attribute::Index' => '0.04', + 'MooseX::Meta::Attribute::Lvalue' => '0.05', + 'MooseX::Method::Signatures' => '0.44', + 'MooseX::MethodAttributes' => '0.22', + 'MooseX::NonMoose' => '0.24', + 'MooseX::Object::Pluggable' => '0.0011', + 'MooseX::POE' => '0.214', + 'MooseX::Params::Validate' => '0.05', + 'MooseX::PrivateSetters' => '0.03', + 'MooseX::Role::Cmd' => '0.06', + 'MooseX::Role::Parameterized' => '1.00', + 'MooseX::Role::WithOverloading' => '0.14', + 'MooseX::Runnable' => '0.03', + 'MooseX::Scaffold' => '0.05', + 'MooseX::SemiAffordanceAccessor' => '0.05', + 'MooseX::SetOnce' => '0.100473', + 'MooseX::Singleton' => '0.25', + 'MooseX::SlurpyConstructor' => '1.1', + 'MooseX::Storage' => '0.42', + 'MooseX::StrictConstructor' => '0.12', + 'MooseX::Traits' => '0.11', + 'MooseX::Types' => '0.19', + 'MooseX::Types::Parameterizable' => '0.05', + 'MooseX::Types::Set::Object' => '0.03', + 'MooseX::Types::Signal' => '1.101930', + 'MooseX::UndefTolerant' => '0.11', + 'PRANG' => '0.14', + 'Pod::Elemental' => '0.093280', + 'Pod::Weaver' => '3.101638', + 'Reaction' => '0.002003', + 'Test::Able' => '0.10', + 'Test::CleanNamespaces' => '0.03', + 'Test::Moose::More' => '0.022', + 'Test::TempDir' => '0.05', + 'Throwable' => '0.102080', + 'namespace::autoclean' => '0.08', + }, + -also => [ qw( + Carp + Class::Load + Class::Load::XS + Data::OptList + Devel::GlobalDestruction + Devel::OverloadInfo + Devel::StackTrace + Dist::CheckConflicts + Eval::Closure + List::MoreUtils + List::Util + MRO::Compat + Module::Runtime + Module::Runtime::Conflicts + Package::DeprecationManager + Package::Stash + Package::Stash::XS + Params::Util + Scalar::Util + Sub::Exporter + Sub::Identify + Sub::Name + Task::Weaken + Try::Tiny + parent + strict + warnings + ) ], + +; + +1; + +# ABSTRACT: Provide information on conflicts for Moose +# Dist::Zilla: -PodWeaver diff --git a/lib/Moose/Cookbook.pod b/lib/Moose/Cookbook.pod new file mode 100644 index 0000000..c967e09 --- /dev/null +++ b/lib/Moose/Cookbook.pod @@ -0,0 +1,289 @@ +# PODNAME: Moose::Cookbook +# ABSTRACT: How to cook a Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook - How to cook a Moose + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +The Moose cookbook is a series of recipes showing various Moose +features. Most recipes present some code demonstrating some feature, +and then explain the details of the code. + +You should probably read the L<Moose::Manual> first. The manual +explains Moose concepts without being too code-heavy. + +=head1 RECIPES + +=head2 Basic Moose + +These recipes will give you a good overview of Moose's capabilities, starting +with simple attribute declaration, and moving on to more powerful features like +laziness, types, type coercion, method modifiers, and more. + +=over 4 + +=item L<Moose::Cookbook::Basics::Point_AttributesAndSubclassing> + +A simple Moose-based class. Demonstrates basic Moose attributes and subclassing. + +=item L<Moose::Cookbook::Basics::BankAccount_MethodModifiersAndSubclassing> + +A slightly more complex Moose class. Demonstrates using a method modifier in a +subclass. + +=item L<Moose::Cookbook::Basics::BinaryTree_AttributeFeatures> + +Demonstrates several attribute features, including types, weak +references, predicates ("does this object have a foo?"), defaults, +laziness, and triggers. + +=item L<Moose::Cookbook::Basics::Company_Subtypes> + +Introduces the creation and use of custom types, a C<BUILD> method, and the +use of C<override> in a subclass. This recipe also shows how to model a set of +classes that could be used to model companies, people, employees, etc. + +=item L<Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion> + +This recipe covers more subtype creation, including the use of type coercions. + +=item L<Moose::Cookbook::Basics::Immutable> + +Making a class immutable greatly increases the speed of accessors and +object construction. + +=item L<Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild> - Builder methods and lazy_build + +The builder feature provides an inheritable and role-composable way to +provide a default attribute value. + +=item L<Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion> + +Demonstrates using operator overloading, coercion, and subtypes to +model how eye color is determined during reproduction. + +=item L<Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD> + +This recipe demonstrates the use of C<BUILDARGS> and C<BUILD> to hook +into object construction. + +=item L<Moose::Cookbook::Basics::DateTime_ExtendingNonMooseParent> + +In this recipe, we make a Moose-based subclass of L<DateTime>, a +module which does not use Moose itself. + +=item L<Moose::Cookbook::Basics::Document_AugmentAndInner> + +Demonstrates the use of C<augment> method modifiers, a way of turning +the usual method overriding style "inside-out". + +=back + +=head2 Moose Roles + +These recipes will show you how to use Moose roles. + +=over 4 + +=item L<Moose::Cookbook::Roles::Comparable_CodeReuse> + +Demonstrates roles, which are also sometimes known as traits or +mix-ins. Roles provide a method of code re-use which is orthogonal to +subclassing. + +=item L<Moose::Cookbook::Roles::Restartable_AdvancedComposition> + +Sometimes you just want to include part of a role in your +class. Sometimes you want the whole role but one of its methods +conflicts with one in your class. With method exclusion and aliasing, +you can work around these problems. + +=item L<Moose::Cookbook::Roles::ApplicationToInstance> + +In this recipe, we apply a role to an existing object instance. + +=back + +=head2 Meta Moose + +These recipes show you how to write your own meta classes, which lets +you extend the object system provided by Moose. + +=over 4 + +=item L<Moose::Cookbook::Meta::WhyMeta> + +If you're wondering what all this "meta" stuff is, and why you should +care about it, read this "recipe". + +=item L<Moose::Cookbook::Meta::Labeled_AttributeTrait> + +Extending Moose's attribute metaclass is a great way to add +functionality. However, attributes can only have one metaclass. +Applying roles to the attribute metaclass lets you provide +composable attribute functionality. + +=item L<Moose::Cookbook::Meta::Table_MetaclassTrait> + +This recipe takes the class metaclass we saw in the previous recipe +and reimplements it as a metaclass trait. + +=item L<Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass> + +This recipe shows a custom method metaclass that implements making a +method private. + +=item L<Moose::Cookbook::Meta::GlobRef_InstanceMetaclass> + +This recipe shows an example of how you create your own meta-instance +class. The meta-instance determines the internal structure of object +instances and provide access to attribute slots. + +In this particular instance, we use a blessed glob reference as the instance +instead of a blessed hash reference. + +=item Hooking into immutabilization (TODO) + +Moose has a feature known as "immutabilization". By calling C<< +__PACKAGE__->meta()->make_immutable() >> after defining your class +(attributes, roles, etc), you tell Moose to optimize things like +object creation, attribute access, and so on. + +If you are creating your own metaclasses, you may need to hook into +the immutabilization system. This cuts across a number of spots, +including the metaclass class, meta method classes, and possibly the +meta-instance class as well. + +This recipe shows you how to write extensions which immutabilize +properly. + +=back + +=head2 Extending Moose + +These recipes cover some more ways to extend Moose, and will be useful +if you plan to write your own C<MooseX> module. + +=over 4 + +=item L<Moose::Cookbook::Extending::ExtensionOverview> + +There are quite a few ways to extend Moose. This recipe provides an +overview of each method, and provides recommendations for when each is +appropriate. + +=item L<Moose::Cookbook::Extending::Debugging_BaseClassRole> + +Many base object class extensions can be implemented as roles. This +example shows how to provide a base object class debugging role that +is applied to any class that uses a notional C<MooseX::Debugging> +module. + +=item L<Moose::Cookbook::Extending::Mooseish_MooseSugar> + +This recipe shows how to provide a replacement for C<Moose.pm>. You +may want to do this as part of the API for a C<MooseX> module, +especially if you want to default to a new metaclass class or base +object class. + +=back + +=head1 SNACKS + +=over 4 + +=item L<Moose::Cookbook::Snack::Keywords> + +=item L<Moose::Cookbook::Snack::Types> + +=back + +=head1 Legacy Recipes + +These cover topics that are no longer considered best practice. We've kept +them in case in you encounter these usages in the wild. + +=over 4 + +=item L<Moose::Cookbook::Legacy::Labeled_AttributeMetaclass> + +=item L<Moose::Cookbook::Legacy::Table_ClassMetaclass> + +=item L<Moose::Cookbook::Legacy::Debugging_BaseClassReplacement> + +=back + +=head1 SEE ALSO + +=over 4 + +=item L<http://www.gsph.com/index.php?Lang=En&ID=291> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/BankAccount_MethodModifiersAndSubclassing.pod b/lib/Moose/Cookbook/Basics/BankAccount_MethodModifiersAndSubclassing.pod new file mode 100644 index 0000000..f4874e4 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/BankAccount_MethodModifiersAndSubclassing.pod @@ -0,0 +1,384 @@ +# PODNAME: Moose::Cookbook::Basics::BankAccount_MethodModifiersAndSubclassing +# ABSTRACT: Demonstrates the use of method modifiers in a subclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::BankAccount_MethodModifiersAndSubclassing - Demonstrates the use of method modifiers in a subclass + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package BankAccount; + use Moose; + + has 'balance' => ( isa => 'Int', is => 'rw', default => 0 ); + + sub deposit { + my ( $self, $amount ) = @_; + $self->balance( $self->balance + $amount ); + } + + sub withdraw { + my ( $self, $amount ) = @_; + my $current_balance = $self->balance(); + ( $current_balance >= $amount ) + || confess "Account overdrawn"; + $self->balance( $current_balance - $amount ); + } + + package CheckingAccount; + use Moose; + + extends 'BankAccount'; + + has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' ); + + before 'withdraw' => sub { + my ( $self, $amount ) = @_; + my $overdraft_amount = $amount - $self->balance(); + if ( $self->overdraft_account && $overdraft_amount > 0 ) { + $self->overdraft_account->withdraw($overdraft_amount); + $self->deposit($overdraft_amount); + } + }; + +=head1 DESCRIPTION + +The first recipe demonstrated how to build very basic Moose classes, +focusing on creating and manipulating attributes. The objects in that +recipe were very data-oriented, and did not have much in the way of +behavior (i.e. methods). In this recipe, we expand upon the concepts +from the first recipe to include some real behavior. In particular, we +show how you can use a method modifier to implement new behavior for a +method. + +The classes in the SYNOPSIS show two kinds of bank account. A simple +bank account has one attribute, the balance, and two behaviors, +depositing and withdrawing money. + +We then extend the basic bank account in the CheckingAccount +class. This class adds another attribute, an overdraft account. It +also adds overdraft protection to the withdraw method. If you try to +withdraw more than you have, the checking account attempts to +reconcile the difference by withdrawing money from the overdraft +account. (1) + +The first class, B<BankAccount>, introduces a new attribute feature, a +default value: + + has 'balance' => ( isa => 'Int', is => 'rw', default => 0 ); + +This says that a B<BankAccount> has a C<balance> attribute, which has +an C<Int> type constraint, a read/write accessor, and a default value +of C<0>. This means that every instance of B<BankAccount> that is +created will have its C<balance> slot initialized to C<0>, unless some +other value is provided to the constructor. + +The C<deposit> and C<withdraw> methods should be fairly +self-explanatory, as they are just plain old Perl 5 OO. (2) + +As you know from the first recipe, the keyword C<extends> sets a +class's superclass. Here we see that B<CheckingAccount> C<extends> +B<BankAccount>. The next line introduces yet another new attribute +feature, class-based type constraints: + + has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' ); + +Up until now, we have only seen the C<Int> type constraint, which (as +we saw in the first recipe) is a builtin type constraint. The +C<BankAccount> type constraint is new, and was actually defined the +moment we created the B<BankAccount> class itself. In fact, Moose +creates a corresponding type constraint for every class in your +program (3). + +This means that in the first recipe, constraints for both C<Point> and +C<Point3D> were created. In this recipe, both C<BankAccount> and +C<CheckingAccount> type constraints are created automatically. Moose +does this as a convenience so that your classes and type constraint +can be kept in sync with one another. In short, Moose makes sure that +it will just DWIM (4). + +In B<CheckingAccount>, we see another method modifier, the C<before> +modifier. + + before 'withdraw' => sub { + my ( $self, $amount ) = @_; + my $overdraft_amount = $amount - $self->balance(); + if ( $self->overdraft_account && $overdraft_amount > 0 ) { + $self->overdraft_account->withdraw($overdraft_amount); + $self->deposit($overdraft_amount); + } + }; + +Just as with the C<after> modifier from the first recipe, Moose will +handle calling the superclass method (in this case C<< +BankAccount->withdraw >>). + +The C<before> modifier will (obviously) run I<before> the code from +the superclass is run. Here, C<before> modifier implements overdraft +protection by first checking if there are available funds in the +checking account. If not (and if there is an overdraft account +available), it transfers the amount needed into the checking +account (5). + +As with the method modifier in the first recipe, we could use +C<SUPER::> to get the same effect: + + sub withdraw { + my ( $self, $amount ) = @_; + my $overdraft_amount = $amount - $self->balance(); + if ( $self->overdraft_account && $overdraft_amount > 0 ) { + $self->overdraft_account->withdraw($overdraft_amount); + $self->deposit($overdraft_amount); + } + $self->SUPER::withdraw($amount); + } + +The benefit of taking the method modifier approach is we do not need +to remember to call C<SUPER::withdraw> and pass it the C<$amount> +argument when writing C<< CheckingAccount->withdraw >>. + +This is actually more than just a convenience for forgetful +programmers. Using method modifiers helps isolate subclasses from +changes in the superclasses. For instance, if B<< +BankAccount->withdraw >> were to add an additional argument of some +kind, the version of B<< CheckingAccount->withdraw >> which uses +C<SUPER::withdraw> would not pass that extra argument correctly, +whereas the method modifier version would automatically pass along all +arguments correctly. + +Just as with the first recipe, object instantiation uses the C<new> +method, which accepts named parameters. + + my $savings_account = BankAccount->new( balance => 250 ); + + my $checking_account = CheckingAccount->new( + balance => 100, + overdraft_account => $savings_account, + ); + +And as with the first recipe, a more in-depth example can be found in +the F<t/recipes/moose_cookbook_basics_recipe2.t> test file. + +=head1 CONCLUSION + +This recipe expanded on the basic concepts from the first recipe with +a more "real world" use case. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +If you're paying close attention, you might realize that there's a +circular loop waiting to happen here. A smarter example would have to +make sure that we don't accidentally create a loop between the +checking account and its overdraft account. + +=item (2) + +Note that for simple methods like these, which just manipulate some +single piece of data, it is often not necessary to write them at all. +For instance, C<deposit> could be implemented via the C<inc> native +delegation for counters - see +L<Moose::Meta::Attribute::Native::Trait::Counter> for more specifics, +and L<Moose::Meta::Attribute::Native> for a broader overview. + +=item (3) + +In reality, this creation is sensitive to the order in which modules +are loaded. In more complicated cases, you may find that you need to +explicitly declare a class type before the corresponding class is +loaded. + +=item (4) + +Moose does not attempt to encode a class's is-a relationships within +the type constraint hierarchy. Instead, Moose just considers the class +type constraint to be a subtype of C<Object>, and specializes the +constraint check to allow for subclasses. This means that an instance +of B<CheckingAccount> will pass a C<BankAccount> type constraint +successfully. For more details, please refer to the +L<Moose::Util::TypeConstraints> documentation. + +=item (5) + +If the overdraft account does not have the amount needed, it will +throw an error. Of course, the overdraft account could also have +overdraft protection. See note 1. + +=back + +=head1 ACKNOWLEDGMENT + +The BankAccount example in this recipe is directly taken from the +examples in this chapter of "Practical Common Lisp": + +L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html> + +=begin testing + +my $savings_account; + +{ + $savings_account = BankAccount->new( balance => 250 ); + isa_ok( $savings_account, 'BankAccount' ); + + is( $savings_account->balance, 250, '... got the right savings balance' ); + is( + exception { + $savings_account->withdraw(50); + }, + undef, + '... withdrew from savings successfully' + ); + is( $savings_account->balance, 200, + '... got the right savings balance after withdrawal' ); + + $savings_account->deposit(150); + is( $savings_account->balance, 350, + '... got the right savings balance after deposit' ); +} + +{ + my $checking_account = CheckingAccount->new( + balance => 100, + overdraft_account => $savings_account + ); + isa_ok( $checking_account, 'CheckingAccount' ); + isa_ok( $checking_account, 'BankAccount' ); + + is( $checking_account->overdraft_account, $savings_account, + '... got the right overdraft account' ); + + is( $checking_account->balance, 100, + '... got the right checkings balance' ); + + is( + exception { + $checking_account->withdraw(50); + }, + undef, + '... withdrew from checking successfully' + ); + is( $checking_account->balance, 50, + '... got the right checkings balance after withdrawal' ); + is( $savings_account->balance, 350, + '... got the right savings balance after checking withdrawal (no overdraft)' + ); + + is( + exception { + $checking_account->withdraw(200); + }, + undef, + '... withdrew from checking successfully' + ); + is( $checking_account->balance, 0, + '... got the right checkings balance after withdrawal' ); + is( $savings_account->balance, 200, + '... got the right savings balance after overdraft withdrawal' ); +} + +{ + my $checking_account = CheckingAccount->new( + balance => 100 + + # no overdraft account + ); + isa_ok( $checking_account, 'CheckingAccount' ); + isa_ok( $checking_account, 'BankAccount' ); + + is( $checking_account->overdraft_account, undef, + '... no overdraft account' ); + + is( $checking_account->balance, 100, + '... got the right checkings balance' ); + + is( + exception { + $checking_account->withdraw(50); + }, + undef, + '... withdrew from checking successfully' + ); + is( $checking_account->balance, 50, + '... got the right checkings balance after withdrawal' ); + + isnt( + exception { + $checking_account->withdraw(200); + }, + undef, + '... withdrawal failed due to attempted overdraft' + ); + is( $checking_account->balance, 50, + '... got the right checkings balance after withdrawal failure' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/BinaryTree_AttributeFeatures.pod b/lib/Moose/Cookbook/Basics/BinaryTree_AttributeFeatures.pod new file mode 100644 index 0000000..09cdf3f --- /dev/null +++ b/lib/Moose/Cookbook/Basics/BinaryTree_AttributeFeatures.pod @@ -0,0 +1,397 @@ +# PODNAME: Moose::Cookbook::Basics::BinaryTree_AttributeFeatures +# ABSTRACT: Demonstrates various attribute features including lazy, predicates, weak refs, and more + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::BinaryTree_AttributeFeatures - Demonstrates various attribute features including lazy, predicates, weak refs, and more + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package BinaryTree; + use Moose; + + has 'node' => ( is => 'rw', isa => 'Any' ); + + has 'parent' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_parent', + weak_ref => 1, + ); + + has 'left' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_left', + lazy => 1, + default => sub { BinaryTree->new( parent => $_[0] ) }, + trigger => \&_set_parent_for_child + ); + + has 'right' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_right', + lazy => 1, + default => sub { BinaryTree->new( parent => $_[0] ) }, + trigger => \&_set_parent_for_child + ); + + sub _set_parent_for_child { + my ( $self, $child ) = @_; + + confess "You cannot insert a tree which already has a parent" + if $child->has_parent; + + $child->parent($self); + } + +=head1 DESCRIPTION + +This recipe shows how various advanced attribute features can be used +to create complex and powerful behaviors. In particular, we introduce +a number of new attribute options, including C<predicate>, C<lazy>, +and C<trigger>. + +The example class is a classic binary tree. Each node in the tree is +itself an instance of C<BinaryTree>. It has a C<node>, which holds +some arbitrary value. It has C<right> and C<left> attributes, which +refer to its child trees, and a C<parent>. + +Let's take a look at the C<node> attribute: + + has 'node' => ( is => 'rw', isa => 'Any' ); + +Moose generates a read-write accessor for this attribute. The type +constraint is C<Any>, which literally means it can contain anything. + +We could have left out the C<isa> option, but in this case, we are +including it for the benefit of other programmers, not the computer. + +Next, let's move on to the C<parent> attribute: + + has 'parent' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_parent', + weak_ref => 1, + ); + +Again, we have a read-write accessor. This time, the C<isa> option +says that this attribute must always be an instance of +C<BinaryTree>. In the second recipe, we saw that every time we create +a Moose-based class, we also get a corresponding class type +constraint. + +The C<predicate> option is new. It creates a method which can be used +to check whether or not a given attribute has been initialized. In +this case, the method is named C<has_parent>. + +This brings us to our last attribute option, C<weak_ref>. Since +C<parent> is a circular reference (the tree in C<parent> should +already have a reference to this one, in its C<left> or C<right> +attribute), we want to make sure that we weaken the reference to avoid +memory leaks. If C<weak_ref> is true, it alters the accessor function +so that the reference is weakened when it is set. + +Finally, we have the C<left> and C<right> attributes. They are +essentially identical except for their names, so we'll just look at +C<left>: + + has 'left' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_left', + lazy => 1, + default => sub { BinaryTree->new( parent => $_[0] ) }, + trigger => \&_set_parent_for_child + ); + +There are three new options here, C<lazy>, C<default>, and +C<trigger>. The C<lazy> and C<default> options are linked. In fact, +you cannot have a C<lazy> attribute unless it has a C<default> +(or a C<builder>, but we'll cover that later). If you try to make an +attribute lazy without a default, class creation will fail with an +exception. (2) + +In the second recipe the B<BankAccount>'s C<balance> attribute had a +default value of C<0>. Given a non-reference, Perl copies the +I<value>. However, given a reference, it does not do a deep clone, +instead simply copying the reference. If you just specified a simple +reference for a default, Perl would create it once and it would be +shared by all objects with that attribute. + +As a workaround, we use an anonymous subroutine to generate a new +reference every time the default is called. + + has 'foo' => ( is => 'rw', default => sub { [] } ); + +In fact, using a non-subroutine reference as a default is illegal in Moose. + + # will fail + has 'foo' => ( is => 'rw', default => [] ); + +This will blow up, so don't do it. + +You'll notice that we use C<$_[0]> in our default sub. When the +default subroutine is executed, it is called as a method on the +object. + +In our case, we're making a new C<BinaryTree> object in our default, +with the current tree as the parent. + +Normally, when an object is instantiated, any defaults are evaluated +immediately. With our C<BinaryTree> class, this would be a big +problem! We'd create the first object, which would immediately try to +populate its C<left> and C<right> attributes, which would create a new +C<BinaryTree>, which would populate I<its> C<left> and C<right> +slots. Kaboom! + +By making our C<left> and C<right> attributes C<lazy>, we avoid this +problem. If the attribute has a value when it is read, the default is +never executed at all. + +We still have one last bit of behavior to add. The autogenerated +C<right> and C<left> accessors are not quite correct. When one of +these is set, we want to make sure that we update the parent of the +C<left> or C<right> attribute's tree. + +We could write our own accessors, but then why use Moose at all? +Instead, we use a C<trigger>. A C<trigger> accepts a subroutine +reference, which will be called as a method whenever the attribute is +set. This can happen both during object construction or later by +passing a new object to the attribute's accessor method. However, it +is not called when a value is provided by a C<default> or C<builder>. + + sub _set_parent_for_child { + my ( $self, $child ) = @_; + + confess "You cannot insert a tree which already has a parent" + if $child->has_parent; + + $child->parent($self); + } + +This trigger does two things. First, it ensures that the new child +node does not already have a parent. This is done for the sake of +simplifying the example. If we wanted to be more clever, we would +remove the child from its old parent tree and add it to the new one. + +If the child has no parent, we will add it to the current tree, and we +ensure that is has the correct value for its C<parent> attribute. + +As with all the other recipes, B<BinaryTree> can be used just like any +other Perl 5 class. A more detailed example of its usage can be found +in F<t/recipes/moose_cookbook_basics_recipe3.t>. + +=head1 CONCLUSION + +This recipe introduced several of Moose's advanced features. We hope +that this inspires you to think of other ways these features can be +used to simplify your code. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +Weak references are tricky things, and should be used sparingly and +appropriately (such as in the case of circular refs). If you are not +careful, attribute values could disappear "mysteriously" because +Perl's reference counting garbage collector has gone and removed the +item you are weak-referencing. + +In short, don't use them unless you know what you are doing :) + +=item (2) + +You I<can> use the C<default> option without the C<lazy> option if you +like, as we showed in the second recipe. + +Also, you can use C<builder> instead of C<default>. See +L<Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild> for details. + +=back + +=begin testing + +use Scalar::Util 'isweak'; + +my $root = BinaryTree->new(node => 'root'); +isa_ok($root, 'BinaryTree'); + +is($root->node, 'root', '... got the right node value'); + +ok(!$root->has_left, '... no left node yet'); +ok(!$root->has_right, '... no right node yet'); + +ok(!$root->has_parent, '... no parent for root node'); + +# make a left node + +my $left = $root->left; +isa_ok($left, 'BinaryTree'); + +is($root->left, $left, '... got the same node (and it is $left)'); +ok($root->has_left, '... we have a left node now'); + +ok($left->has_parent, '... lefts has a parent'); +is($left->parent, $root, '... lefts parent is the root'); + +ok(isweak($left->{parent}), '... parent is a weakened ref'); + +ok(!$left->has_left, '... $left no left node yet'); +ok(!$left->has_right, '... $left no right node yet'); + +is($left->node, undef, '... left has got no node value'); + +is( + exception { + $left->node('left'); + }, + undef, + '... assign to lefts node' +); + +is($left->node, 'left', '... left now has a node value'); + +# make a right node + +ok(!$root->has_right, '... still no right node yet'); + +is($root->right->node, undef, '... right has got no node value'); + +ok($root->has_right, '... now we have a right node'); + +my $right = $root->right; +isa_ok($right, 'BinaryTree'); + +is( + exception { + $right->node('right'); + }, + undef, + '... assign to rights node' +); + +is($right->node, 'right', '... left now has a node value'); + +is($root->right, $right, '... got the same node (and it is $right)'); +ok($root->has_right, '... we have a right node now'); + +ok($right->has_parent, '... rights has a parent'); +is($right->parent, $root, '... rights parent is the root'); + +ok(isweak($right->{parent}), '... parent is a weakened ref'); + +# make a left node of the left node + +my $left_left = $left->left; +isa_ok($left_left, 'BinaryTree'); + +ok($left_left->has_parent, '... left does have a parent'); + +is($left_left->parent, $left, '... got a parent node (and it is $left)'); +ok($left->has_left, '... we have a left node now'); +is($left->left, $left_left, '... got a left node (and it is $left_left)'); + +ok(isweak($left_left->{parent}), '... parent is a weakened ref'); + +# make a right node of the left node + +my $left_right = BinaryTree->new; +isa_ok($left_right, 'BinaryTree'); + +is( + exception { + $left->right($left_right); + }, + undef, + '... assign to rights node' +); + +ok($left_right->has_parent, '... left does have a parent'); + +is($left_right->parent, $left, '... got a parent node (and it is $left)'); +ok($left->has_right, '... we have a left node now'); +is($left->right, $left_right, '... got a left node (and it is $left_left)'); + +ok(isweak($left_right->{parent}), '... parent is a weakened ref'); + +# and check the error + +isnt( + exception { + $left_right->right($left_left); + }, + undef, + '... cannot assign a node which already has a parent' +); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/BinaryTree_BuilderAndLazyBuild.pod b/lib/Moose/Cookbook/Basics/BinaryTree_BuilderAndLazyBuild.pod new file mode 100644 index 0000000..025968a --- /dev/null +++ b/lib/Moose/Cookbook/Basics/BinaryTree_BuilderAndLazyBuild.pod @@ -0,0 +1,176 @@ +# PODNAME: Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild +# ABSTRACT: Builder methods and lazy_build + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild - Builder methods and lazy_build + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package BinaryTree; + use Moose; + + has 'node' => (is => 'rw', isa => 'Any'); + + has 'parent' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_parent', + weak_ref => 1, + ); + + has 'left' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_left', + lazy => 1, + builder => '_build_child_tree', + ); + + has 'right' => ( + is => 'rw', + isa => 'BinaryTree', + predicate => 'has_right', + lazy => 1, + builder => '_build_child_tree', + ); + + before 'right', 'left' => sub { + my ($self, $tree) = @_; + $tree->parent($self) if defined $tree; + }; + + sub _build_child_tree { + my $self = shift; + + return BinaryTree->new( parent => $self ); + } + +=head1 DESCRIPTION + +If you've already read +L<Moose::Cookbook::Basics::BinaryTree_AttributeFeatures>, then this example +should look very familiar. In fact, all we've done here is replace the +attribute's C<default> parameter with a C<builder>. + +In this particular case, the C<default> and C<builder> options act in +exactly the same way. When the C<left> or C<right> attribute is read, +Moose calls the builder method to initialize the attribute. + +Note that Moose calls the builder method I<on the object which has the +attribute>. Here's an example: + + my $tree = BinaryTree->new(); + + my $left = $tree->left(); + +When C<< $tree->left() >> is called, Moose calls C<< +$tree->_build_child_tree() >> in order to populate the C<left> +attribute. If we had passed C<left> to the original constructor, the +builder would not be called. + +There are some differences between C<default> and C<builder>. Notably, +a builder is subclassable, and can be composed from a role. See +L<Moose::Manual::Attributes> for more details. + +=head2 The lazy_build shortcut + +The C<lazy_build> attribute option can be used as sugar to specify +a whole set of attribute options at once: + + has 'animal' => ( + is => 'ro', + isa => 'Animal', + lazy_build => 1, + ); + +This is a shorthand for: + + has 'animal' => ( + is => 'ro', + isa => 'Animal', + required => 1, + lazy => 1, + builder => '_build_animal', + predicate => 'has_animal', + clearer => 'clear_animal', + ); + +If your attribute starts with an underscore, Moose is smart and will +do the right thing with the C<predicate> and C<clearer>, making them +both start with an underscore. The C<builder> method I<always> starts +with an underscore. + +You can read more about C<lazy_build> in L<Moose::Meta::Attribute> + +=head1 CONCLUSION + +The C<builder> option is a more OO-friendly version of the C<default> +functionality. It also separates the default-generating code into a +well-defined method. Sprinkling your attribute definitions with +anonymous subroutines can be quite ugly and hard to follow. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Company_Subtypes.pod b/lib/Moose/Cookbook/Basics/Company_Subtypes.pod new file mode 100644 index 0000000..1b062f5 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Company_Subtypes.pod @@ -0,0 +1,602 @@ +# PODNAME: Moose::Cookbook::Basics::Company_Subtypes +# ABSTRACT: Demonstrates the use of subtypes and how to model classes related to companies, people, employees, etc. + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Company_Subtypes - Demonstrates the use of subtypes and how to model classes related to companies, people, employees, etc. + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Address; + use Moose; + use Moose::Util::TypeConstraints; + + use Locale::US; + use Regexp::Common 'zip'; + + my $STATES = Locale::US->new; + subtype 'USState' + => as Str + => where { + ( exists $STATES->{code2state}{ uc($_) } + || exists $STATES->{state2code}{ uc($_) } ); + }; + + subtype 'USZipCode' + => as Value + => where { + /^$RE{zip}{US}{-extended => 'allow'}$/; + }; + + has 'street' => ( is => 'rw', isa => 'Str' ); + has 'city' => ( is => 'rw', isa => 'Str' ); + has 'state' => ( is => 'rw', isa => 'USState' ); + has 'zip_code' => ( is => 'rw', isa => 'USZipCode' ); + + package Company; + use Moose; + use Moose::Util::TypeConstraints; + + has 'name' => ( is => 'rw', isa => 'Str', required => 1 ); + has 'address' => ( is => 'rw', isa => 'Address' ); + has 'employees' => ( + is => 'rw', + isa => 'ArrayRef[Employee]', + default => sub { [] }, + ); + + sub BUILD { + my ( $self, $params ) = @_; + foreach my $employee ( @{ $self->employees } ) { + $employee->employer($self); + } + } + + after 'employees' => sub { + my ( $self, $employees ) = @_; + return unless $employees; + foreach my $employee ( @$employees ) { + $employee->employer($self); + } + }; + + package Person; + use Moose; + + has 'first_name' => ( is => 'rw', isa => 'Str', required => 1 ); + has 'last_name' => ( is => 'rw', isa => 'Str', required => 1 ); + has 'middle_initial' => ( + is => 'rw', isa => 'Str', + predicate => 'has_middle_initial' + ); + has 'address' => ( is => 'rw', isa => 'Address' ); + + sub full_name { + my $self = shift; + return $self->first_name + . ( + $self->has_middle_initial + ? ' ' . $self->middle_initial . '. ' + : ' ' + ) . $self->last_name; + } + + package Employee; + use Moose; + + extends 'Person'; + + has 'title' => ( is => 'rw', isa => 'Str', required => 1 ); + has 'employer' => ( is => 'rw', isa => 'Company', weak_ref => 1 ); + + override 'full_name' => sub { + my $self = shift; + super() . ', ' . $self->title; + }; + +=head1 DESCRIPTION + +This recipe introduces the C<subtype> sugar function from +L<Moose::Util::TypeConstraints>. The C<subtype> function lets you +declaratively create type constraints without building an entire +class. + +In the recipe we also make use of L<Locale::US> and L<Regexp::Common> +to build constraints, showing how constraints can make use of existing +CPAN tools for data validation. + +Finally, we introduce the C<required> attribute option. + +In the C<Address> class we define two subtypes. The first uses the +L<Locale::US> module to check the validity of a state. It accepts +either a state abbreviation of full name. + +A state will be passed in as a string, so we make our C<USState> type +a subtype of Moose's builtin C<Str> type. This is done using the C<as> +sugar. The actual constraint is defined using C<where>. This function +accepts a single subroutine reference. That subroutine will be called +with the value to be checked in C<$_> (1). It is expected to return a +true or false value indicating whether the value is valid for the +type. + +We can now use the C<USState> type just like Moose's builtin types: + + has 'state' => ( is => 'rw', isa => 'USState' ); + +When the C<state> attribute is set, the value is checked against the +C<USState> constraint. If the value is not valid, an exception will be +thrown. + +The next C<subtype>, C<USZipCode>, uses +L<Regexp::Common>. L<Regexp::Common> includes a regex for validating +US zip codes. We use this constraint for the C<zip_code> attribute. + + subtype 'USZipCode' + => as Value + => where { + /^$RE{zip}{US}{-extended => 'allow'}$/; + }; + +Using a subtype instead of requiring a class for each type greatly +simplifies the code. We don't really need a class for these types, as +they're just strings, but we do want to ensure that they're valid. + +The type constraints we created are reusable. Type constraints are +stored by name in a global registry, which means that we can refer to +them in other classes. Because the registry is global, we do recommend +that you use some sort of namespacing in real applications, +like C<MyApp::Type::USState> (just as you would do with class names). + +These two subtypes allow us to define a simple C<Address> class. + +Then we define our C<Company> class, which has an address. As we saw +in earlier recipes, Moose automatically creates a type constraint for +each our classes, so we can use that for the C<Company> class's +C<address> attribute: + + has 'address' => ( is => 'rw', isa => 'Address' ); + +A company also needs a name: + + has 'name' => ( is => 'rw', isa => 'Str', required => 1 ); + +This introduces a new attribute option, C<required>. If an attribute +is required, then it must be passed to the class's constructor, or an +exception will be thrown. It's important to understand that a +C<required> attribute can still be false or C<undef>, if its type +constraint allows that. + +The next attribute, C<employees>, uses a I<parameterized> type +constraint: + + has 'employees' => ( + is => 'rw', + isa => 'ArrayRef[Employee]' + default => sub { [] }, + ); + +This constraint says that C<employees> must be an array reference +where each element of the array is an C<Employee> object. It's worth +noting that an I<empty> array reference also satisfies this +constraint, such as the value given as the default here. + +Parameterizable type constraints (or "container types"), such as +C<ArrayRef[`a]>, can be made more specific with a type parameter. In +fact, we can arbitrarily nest these types, producing something like +C<HashRef[ArrayRef[Int]]>. However, you can also just use the type by +itself, so C<ArrayRef> is legal. (2) + +If you jump down to the definition of the C<Employee> class, you will +see that it has an C<employer> attribute. + +When we set the C<employees> for a C<Company> we want to make sure +that each of these employee objects refers back to the right +C<Company> in its C<employer> attribute. + +To do that, we need to hook into object construction. Moose lets us do +this by writing a C<BUILD> method in our class. When your class +defines a C<BUILD> method, it will be called by the constructor +immediately after object construction, but before the object is returned +to the caller. Note that all C<BUILD> methods in your class hierarchy +will be called automatically; there is no need to (and you should not) +call the superclass C<BUILD> method. + +The C<Company> class uses the C<BUILD> method to ensure that each +employee of a company has the proper C<Company> object in its +C<employer> attribute: + + sub BUILD { + my ( $self, $params ) = @_; + foreach my $employee ( @{ $self->employees } ) { + $employee->employer($self); + } + } + +The C<BUILD> method is executed after type constraints are checked, so it is +safe to assume that if C<< $self->employees >> has a value, it will be an +array reference, and that the elements of that array reference will be +C<Employee> objects. + +We also want to make sure that whenever the C<employees> attribute for +a C<Company> is changed, we also update the C<employer> for each +employee. + +To do this we can use an C<after> modifier: + + after 'employees' => sub { + my ( $self, $employees ) = @_; + return unless $employees; + foreach my $employee ( @$employees ) { + $employee->employer($self); + } + }; + +Again, as with the C<BUILD> method, we know that the type constraint check has +already happened, so we know that if C<$employees> is defined it will contain +an array reference of C<Employee> objects. + +Note that C<employees> is a read/write accessor, so we must return early if +it's called as a reader. + +The B<Person> class does not really demonstrate anything new. It has several +C<required> attributes. It also has a C<predicate> method, which we +first used in L<Moose::Cookbook::Basics::BinaryTree_AttributeFeatures>. + +The only new feature in the C<Employee> class is the C<override> +method modifier: + + override 'full_name' => sub { + my $self = shift; + super() . ', ' . $self->title; + }; + +This is just a sugary alternative to Perl's built in C<SUPER::> +feature. However, there is one difference. You cannot pass any +arguments to C<super>. Instead, Moose simply passes the same +parameters that were passed to the method. + +A more detailed example of usage can be found in +F<t/recipes/moose_cookbook_basics_recipe4.t>. + +=for testing-SETUP use Test::Requires { + 'Locale::US' => '0', + 'Regexp::Common' => '0', +}; + +=head1 CONCLUSION + +This recipe was intentionally longer and more complex. It illustrates +how Moose classes can be used together with type constraints, as well +as the density of information that you can get out of a small amount +of typing when using Moose. + +This recipe also introduced the C<subtype> function, the C<required> +attribute, and the C<override> method modifier. + +We will revisit type constraints in future recipes, and cover type +coercion as well. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +The value being checked is also passed as the first argument to +the C<where> block, so it can be accessed as C<$_[0]>. + +=item (2) + +Note that C<ArrayRef[]> will not work. Moose will not parse this as a +container type, and instead you will have a new type named +"ArrayRef[]", which doesn't make any sense. + +=back + +=begin testing + +{ + package Company; + + sub get_employee_count { scalar @{(shift)->employees} } +} + +use Scalar::Util 'isweak'; + +my $ii; +is( + exception { + $ii = Company->new( + { + name => 'Infinity Interactive', + address => Address->new( + street => '565 Plandome Rd., Suite 307', + city => 'Manhasset', + state => 'NY', + zip_code => '11030' + ), + employees => [ + Employee->new( + first_name => 'Jeremy', + last_name => 'Shao', + title => 'President / Senior Consultant', + address => Address->new( + city => 'Manhasset', state => 'NY' + ) + ), + Employee->new( + first_name => 'Tommy', + last_name => 'Lee', + title => 'Vice President / Senior Developer', + address => + Address->new( city => 'New York', state => 'NY' ) + ), + Employee->new( + first_name => 'Stevan', + middle_initial => 'C', + last_name => 'Little', + title => 'Senior Developer', + address => + Address->new( city => 'Madison', state => 'CT' ) + ), + ] + } + ); + }, + undef, + '... created the entire company successfully' +); + +isa_ok( $ii, 'Company' ); + +is( $ii->name, 'Infinity Interactive', + '... got the right name for the company' ); + +isa_ok( $ii->address, 'Address' ); +is( $ii->address->street, '565 Plandome Rd., Suite 307', + '... got the right street address' ); +is( $ii->address->city, 'Manhasset', '... got the right city' ); +is( $ii->address->state, 'NY', '... got the right state' ); +is( $ii->address->zip_code, 11030, '... got the zip code' ); + +is( $ii->get_employee_count, 3, '... got the right employee count' ); + +# employee #1 + +isa_ok( $ii->employees->[0], 'Employee' ); +isa_ok( $ii->employees->[0], 'Person' ); + +is( $ii->employees->[0]->first_name, 'Jeremy', + '... got the right first name' ); +is( $ii->employees->[0]->last_name, 'Shao', '... got the right last name' ); +ok( !$ii->employees->[0]->has_middle_initial, '... no middle initial' ); +is( $ii->employees->[0]->middle_initial, undef, + '... got the right middle initial value' ); +is( $ii->employees->[0]->full_name, + 'Jeremy Shao, President / Senior Consultant', + '... got the right full name' ); +is( $ii->employees->[0]->title, 'President / Senior Consultant', + '... got the right title' ); +is( $ii->employees->[0]->employer, $ii, '... got the right company' ); +ok( isweak( $ii->employees->[0]->{employer} ), + '... the company is a weak-ref' ); + +isa_ok( $ii->employees->[0]->address, 'Address' ); +is( $ii->employees->[0]->address->city, 'Manhasset', + '... got the right city' ); +is( $ii->employees->[0]->address->state, 'NY', '... got the right state' ); + +# employee #2 + +isa_ok( $ii->employees->[1], 'Employee' ); +isa_ok( $ii->employees->[1], 'Person' ); + +is( $ii->employees->[1]->first_name, 'Tommy', + '... got the right first name' ); +is( $ii->employees->[1]->last_name, 'Lee', '... got the right last name' ); +ok( !$ii->employees->[1]->has_middle_initial, '... no middle initial' ); +is( $ii->employees->[1]->middle_initial, undef, + '... got the right middle initial value' ); +is( $ii->employees->[1]->full_name, + 'Tommy Lee, Vice President / Senior Developer', + '... got the right full name' ); +is( $ii->employees->[1]->title, 'Vice President / Senior Developer', + '... got the right title' ); +is( $ii->employees->[1]->employer, $ii, '... got the right company' ); +ok( isweak( $ii->employees->[1]->{employer} ), + '... the company is a weak-ref' ); + +isa_ok( $ii->employees->[1]->address, 'Address' ); +is( $ii->employees->[1]->address->city, 'New York', + '... got the right city' ); +is( $ii->employees->[1]->address->state, 'NY', '... got the right state' ); + +# employee #3 + +isa_ok( $ii->employees->[2], 'Employee' ); +isa_ok( $ii->employees->[2], 'Person' ); + +is( $ii->employees->[2]->first_name, 'Stevan', + '... got the right first name' ); +is( $ii->employees->[2]->last_name, 'Little', '... got the right last name' ); +ok( $ii->employees->[2]->has_middle_initial, '... got middle initial' ); +is( $ii->employees->[2]->middle_initial, 'C', + '... got the right middle initial value' ); +is( $ii->employees->[2]->full_name, 'Stevan C. Little, Senior Developer', + '... got the right full name' ); +is( $ii->employees->[2]->title, 'Senior Developer', + '... got the right title' ); +is( $ii->employees->[2]->employer, $ii, '... got the right company' ); +ok( isweak( $ii->employees->[2]->{employer} ), + '... the company is a weak-ref' ); + +isa_ok( $ii->employees->[2]->address, 'Address' ); +is( $ii->employees->[2]->address->city, 'Madison', '... got the right city' ); +is( $ii->employees->[2]->address->state, 'CT', '... got the right state' ); + +# create new company + +my $new_company + = Company->new( name => 'Infinity Interactive International' ); +isa_ok( $new_company, 'Company' ); + +my $ii_employees = $ii->employees; +foreach my $employee (@$ii_employees) { + is( $employee->employer, $ii, '... has the ii company' ); +} + +$new_company->employees($ii_employees); + +foreach my $employee ( @{ $new_company->employees } ) { + is( $employee->employer, $new_company, + '... has the different company now' ); +} + +## check some error conditions for the subtypes + +isnt( + exception { + Address->new( street => {} ),; + }, + undef, + '... we die correctly with bad args' +); + +isnt( + exception { + Address->new( city => {} ),; + }, + undef, + '... we die correctly with bad args' +); + +isnt( + exception { + Address->new( state => 'British Columbia' ),; + }, + undef, + '... we die correctly with bad args' +); + +is( + exception { + Address->new( state => 'Connecticut' ),; + }, + undef, + '... we live correctly with good args' +); + +isnt( + exception { + Address->new( zip_code => 'AF5J6$' ),; + }, + undef, + '... we die correctly with bad args' +); + +is( + exception { + Address->new( zip_code => '06443' ),; + }, + undef, + '... we live correctly with good args' +); + +isnt( + exception { + Company->new(),; + }, + undef, + '... we die correctly without good args' +); + +is( + exception { + Company->new( name => 'Foo' ),; + }, + undef, + '... we live correctly without good args' +); + +isnt( + exception { + Company->new( name => 'Foo', employees => [ Person->new ] ),; + }, + undef, + '... we die correctly with good args' +); + +is( + exception { + Company->new( name => 'Foo', employees => [] ),; + }, + undef, + '... we live correctly with good args' +); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/DateTime_ExtendingNonMooseParent.pod b/lib/Moose/Cookbook/Basics/DateTime_ExtendingNonMooseParent.pod new file mode 100644 index 0000000..89ef739 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/DateTime_ExtendingNonMooseParent.pod @@ -0,0 +1,134 @@ +# PODNAME: Moose::Cookbook::Basics::DateTime_ExtendingNonMooseParent +# ABSTRACT: Extending a non-Moose parent class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::DateTime_ExtendingNonMooseParent - Extending a non-Moose parent class + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package My::DateTime; + + use Moose; + use MooseX::NonMoose; + use DateTime::Calendar::Mayan; + extends qw( DateTime ); + + has 'mayan_date' => ( + is => 'ro', + isa => 'DateTime::Calendar::Mayan', + init_arg => undef, + lazy => 1, + builder => '_build_mayan_date', + clearer => '_clear_mayan_date', + predicate => 'has_mayan_date', + ); + + after 'set' => sub { + $_[0]->_clear_mayan_date; + }; + + sub _build_mayan_date { + DateTime::Calendar::Mayan->from_object( object => $_[0] ); + } + +=head1 DESCRIPTION + +This recipe demonstrates how to use Moose to subclass a parent which +is not Moose based. This recipe only works if the parent class uses a +blessed hash reference for object instances. If your parent is doing +something funkier, you should check out L<MooseX::NonMoose::InsideOut> and L<MooseX::InsideOut>. + +The meat of this recipe is contained in L<MooseX::NonMoose>, which does all +the grunt work for you. + +=begin testing-SETUP + +# because MooseX::NonMoose has a version requirement +BEGIN { $Moose::Role::VERSION = 9999 unless $Moose::Role::VERSION } + +use Test::Requires { + 'DateTime' => '0', + 'DateTime::Calendar::Mayan' => '0', + 'MooseX::NonMoose' => '0.25', +}; + +=end testing-SETUP + +=begin testing + +my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 ); + +can_ok( $dt, 'mayan_date' ); +isa_ok( $dt->mayan_date, 'DateTime::Calendar::Mayan' ); +is( $dt->mayan_date->date, '12.17.16.9.19', 'got expected mayan date' ); + +$dt->set( year => 2009 ); +ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' ); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Document_AugmentAndInner.pod b/lib/Moose/Cookbook/Basics/Document_AugmentAndInner.pod new file mode 100644 index 0000000..1551745 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Document_AugmentAndInner.pod @@ -0,0 +1,197 @@ +# PODNAME: Moose::Cookbook::Basics::Document_AugmentAndInner +# ABSTRACT: The augment modifier, which turns normal method overriding "inside-out" + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Document_AugmentAndInner - The augment modifier, which turns normal method overriding "inside-out" + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Document::Page; + use Moose; + + has 'body' => ( is => 'rw', isa => 'Str', default => sub {''} ); + + sub create { + my $self = shift; + $self->open_page; + inner(); + $self->close_page; + } + + sub append_body { + my ( $self, $appendage ) = @_; + $self->body( $self->body . $appendage ); + } + + sub open_page { (shift)->append_body('<page>') } + sub close_page { (shift)->append_body('</page>') } + + package Document::PageWithHeadersAndFooters; + use Moose; + + extends 'Document::Page'; + + augment 'create' => sub { + my $self = shift; + $self->create_header; + inner(); + $self->create_footer; + }; + + sub create_header { (shift)->append_body('<header/>') } + sub create_footer { (shift)->append_body('<footer/>') } + + package TPSReport; + use Moose; + + extends 'Document::PageWithHeadersAndFooters'; + + augment 'create' => sub { + my $self = shift; + $self->create_tps_report; + inner(); + }; + + sub create_tps_report { + (shift)->append_body('<report type="tps"/>'); + } + + # <page><header/><report type="tps"/><footer/></page> + my $report_xml = TPSReport->new->create; + +=head1 DESCRIPTION + +This recipe shows how the C<augment> method modifier works. This +modifier reverses the normal subclass to parent method resolution +order. With an C<augment> modifier the I<least> specific method is +called first. Each successive call to C<inner> descends the +inheritance tree, ending at the most specific subclass. + +The C<augment> modifier lets you design a parent class that can be +extended in a specific way. The parent provides generic wrapper +functionality, and the subclasses fill in the details. + +In the example above, we've created a set of document classes, with +the most specific being the C<TPSReport> class. + +We start with the least specific class, C<Document::Page>. Its create +method contains a call to C<inner()>: + + sub create { + my $self = shift; + $self->open_page; + inner(); + $self->close_page; + } + +The C<inner> function is exported by C<Moose>, and is like C<super> +for augmented methods. When C<inner> is called, Moose finds the next +method in the chain, which is the C<augment> modifier in +C<Document::PageWithHeadersAndFooters>. You'll note that we can call +C<inner> in our modifier: + + augment 'create' => sub { + my $self = shift; + $self->create_header; + inner(); + $self->create_footer; + }; + +This finds the next most specific modifier, in the C<TPSReport> class. + +Finally, in the C<TPSReport> class, the chain comes to an end: + + augment 'create' => sub { + my $self = shift; + $self->create_tps_report; + inner(); + }; + +We do call the C<inner> function one more time, but since there is no +more specific subclass, this is a no-op. Making this call means we can +easily subclass C<TPSReport> in the future. + +=head1 CONCLUSION + +The C<augment> modifier is a powerful tool for creating a set of +nested wrappers. It's not something you will need often, but when you +do, it is very handy. + +=begin testing + +my $tps_report = TPSReport->new; +isa_ok( $tps_report, 'TPSReport' ); + +is( + $tps_report->create, + q{<page><header/><report type="tps"/><footer/></page>}, + '... got the right TPS report' +); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Genome_OverloadingSubtypesAndCoercion.pod b/lib/Moose/Cookbook/Basics/Genome_OverloadingSubtypesAndCoercion.pod new file mode 100644 index 0000000..2311ac3 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Genome_OverloadingSubtypesAndCoercion.pod @@ -0,0 +1,325 @@ +# PODNAME: Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion +# ABSTRACT: Operator overloading, subtypes, and coercion + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion - Operator overloading, subtypes, and coercion + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Human; + + use Moose; + use Moose::Util::TypeConstraints; + + subtype 'Sex' + => as 'Str' + => where { $_ =~ m{^[mf]$}s }; + + has 'sex' => ( is => 'ro', isa => 'Sex', required => 1 ); + + has 'mother' => ( is => 'ro', isa => 'Human' ); + has 'father' => ( is => 'ro', isa => 'Human' ); + + use overload '+' => \&_overload_add, fallback => 1; + + sub _overload_add { + my ( $one, $two ) = @_; + + die('Only male and female humans may create children') + if ( $one->sex() eq $two->sex() ); + + my ( $mother, $father ) + = ( $one->sex eq 'f' ? ( $one, $two ) : ( $two, $one ) ); + + my $sex = 'f'; + $sex = 'm' if ( rand() >= 0.5 ); + + return Human->new( + sex => $sex, + mother => $mother, + father => $father, + ); + } + +=head1 DESCRIPTION + +This Moose cookbook recipe shows how operator overloading, coercion, +and subtypes can be used to mimic the human reproductive system +(well, the selection of genes at least). + +=head1 INTRODUCTION + +Our C<Human> class uses operator overloading to allow us to "add" two +humans together and produce a child. Our implementation does require +that the two objects be of opposite sex. Remember, we're talking +about biological reproduction, not marriage. + +While this example works as-is, we can take it a lot further by adding +genes into the mix. We'll add the two genes that control eye color, +and use overloading to combine the genes from the parent to model the +biology. + +=head2 What is Operator Overloading? + +Overloading is I<not> a Moose-specific feature. It's a general OO +concept that is implemented in Perl with the C<overload> +pragma. Overloading lets objects do something sane when used with +Perl's built in operators, like addition (C<+>) or when used as a +string. + +In this example we overload addition so we can write code like +C<$child = $mother + $father>. + +=head1 GENES + +There are many genes which affect eye color, but there are two which +are most important, I<gey> and I<bey2>. We will start by making a +class for each gene. + +=head2 Human::Gene::bey2 + + package Human::Gene::bey2; + + use Moose; + use Moose::Util::TypeConstraints; + + type 'bey2_color' => where { $_ =~ m{^(?:brown|blue)$} }; + + has 'color' => ( is => 'ro', isa => 'bey2_color' ); + +This class is trivial. We have a type constraint for the allowed +colors, and a C<color> attribute. + +=head2 Human::Gene::gey + + package Human::Gene::gey; + + use Moose; + use Moose::Util::TypeConstraints; + + type 'gey_color' => where { $_ =~ m{^(?:green|blue)$} }; + + has 'color' => ( is => 'ro', isa => 'gey_color' ); + +This is nearly identical to the C<Humane::Gene::bey2> class, except +that the I<gey> gene allows for different colors. + +=head1 EYE COLOR + +We could just give four attributes (two of each gene) to the +C<Human> class, but this is a bit messy. Instead, we'll abstract the +genes into a container class, C<Human::EyeColor>. Then a C<Human> can +have a single C<eye_color> attribute. + + package Human::EyeColor; + + use Moose; + use Moose::Util::TypeConstraints; + + coerce 'Human::Gene::bey2' + => from 'Str' + => via { Human::Gene::bey2->new( color => $_ ) }; + + coerce 'Human::Gene::gey' + => from 'Str' + => via { Human::Gene::gey->new( color => $_ ) }; + + has [qw( bey2_1 bey2_2 )] => + ( is => 'ro', isa => 'Human::Gene::bey2', coerce => 1 ); + + has [qw( gey_1 gey_2 )] => + ( is => 'ro', isa => 'Human::Gene::gey', coerce => 1 ); + +The eye color class has two of each type of gene. We've also created a +coercion for each class that coerces a string into a new object. Note +that a coercion will fail if it attempts to coerce a string like +"indigo", because that is not a valid color for either type of gene. + +As an aside, you can see that we can define several identical +attributes at once by supplying an array reference of names as the first +argument to C<has>. + +We also need a method to calculate the actual eye color that results +from a set of genes. The I<bey2> brown gene is dominant over both blue +and green. The I<gey> green gene is dominant over blue. + + sub color { + my ($self) = @_; + + return 'brown' + if ( $self->bey2_1->color() eq 'brown' + or $self->bey2_2->color() eq 'brown' ); + + return 'green' + if ( $self->gey_1->color() eq 'green' + or $self->gey_2->color() eq 'green' ); + + return 'blue'; + } + +We'd like to be able to treat a C<Human::EyeColor> object as a string, +so we define a string overloading for the class: + + use overload '""' => \&color, fallback => 1; + +Finally, we need to define overloading for addition. That way we can +add together two C<Human::EyeColor> objects and get a new one with a +new (genetically correct) eye color. + + use overload '+' => \&_overload_add, fallback => 1; + + sub _overload_add { + my ( $one, $two ) = @_; + + my $one_bey2 = 'bey2_' . _rand2(); + my $two_bey2 = 'bey2_' . _rand2(); + + my $one_gey = 'gey_' . _rand2(); + my $two_gey = 'gey_' . _rand2(); + + return Human::EyeColor->new( + bey2_1 => $one->$one_bey2->color(), + bey2_2 => $two->$two_bey2->color(), + gey_1 => $one->$one_gey->color(), + gey_2 => $two->$two_gey->color(), + ); + } + + sub _rand2 { + return 1 + int( rand(2) ); + } + +When two eye color objects are added together, the C<_overload_add()> +method will be passed two C<Human::EyeColor> objects. These are the +left and right side operands for the C<+> operator. This method +returns a new C<Human::EyeColor> object. + +=head1 ADDING EYE COLOR TO C<Human>s + +Our original C<Human> class requires just a few changes to incorporate +our new C<Human::EyeColor> class. + + use List::MoreUtils qw( zip ); + + coerce 'Human::EyeColor' + => from 'ArrayRef' + => via { my @genes = qw( bey2_1 bey2_2 gey_1 gey_2 ); + return Human::EyeColor->new( zip( @genes, @{$_} ) ); }; + + has 'eye_color' => ( + is => 'ro', + isa => 'Human::EyeColor', + coerce => 1, + required => 1, + ); + +We also need to modify C<_overload_add()> in the C<Human> class to +account for eye color: + + return Human->new( + sex => $sex, + eye_color => ( $one->eye_color() + $two->eye_color() ), + mother => $mother, + father => $father, + ); + +=head1 CONCLUSION + +The three techniques we used, overloading, subtypes, and coercion, +combine to provide a powerful interface. + +If you'd like to learn more about overloading, please read the +documentation for the L<overload> pragma. + +To see all the code we created together, take a look at +F<t/recipes/basics_recipe9.t>. + +=head1 NEXT STEPS + +Had this been a real project we'd probably want: + +=over 4 + +=item Better Randomization with Crypt::Random + +=item Characteristic Base Class + +=item Mutating Genes + +=item More Characteristics + +=item Artificial Life + +=back + +=head1 LICENSE + +This work is licensed under a Creative Commons Attribution 3.0 Unported License. + +License details are at: L<http://creativecommons.org/licenses/by/3.0/> + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/HTTP_SubtypesAndCoercion.pod b/lib/Moose/Cookbook/Basics/HTTP_SubtypesAndCoercion.pod new file mode 100644 index 0000000..8f0783b --- /dev/null +++ b/lib/Moose/Cookbook/Basics/HTTP_SubtypesAndCoercion.pod @@ -0,0 +1,345 @@ +# PODNAME: Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion +# ABSTRACT: Demonstrates subtypes and coercion use HTTP-related classes (Request, Protocol, etc.) + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion - Demonstrates subtypes and coercion use HTTP-related classes (Request, Protocol, etc.) + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Request; + use Moose; + use Moose::Util::TypeConstraints; + + use HTTP::Headers (); + use Params::Coerce (); + use URI (); + + subtype 'My::Types::HTTP::Headers' => as class_type('HTTP::Headers'); + + coerce 'My::Types::HTTP::Headers' + => from 'ArrayRef' + => via { HTTP::Headers->new( @{$_} ) } + => from 'HashRef' + => via { HTTP::Headers->new( %{$_} ) }; + + subtype 'My::Types::URI' => as class_type('URI'); + + coerce 'My::Types::URI' + => from 'Object' + => via { $_->isa('URI') + ? $_ + : Params::Coerce::coerce( 'URI', $_ ); } + => from 'Str' + => via { URI->new( $_, 'http' ) }; + + subtype 'Protocol' + => as 'Str' + => where { /^HTTP\/[0-9]\.[0-9]$/ }; + + has 'base' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 ); + has 'uri' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 ); + has 'method' => ( is => 'rw', isa => 'Str' ); + has 'protocol' => ( is => 'rw', isa => 'Protocol' ); + has 'headers' => ( + is => 'rw', + isa => 'My::Types::HTTP::Headers', + coerce => 1, + default => sub { HTTP::Headers->new } + ); + +=head1 DESCRIPTION + +This recipe introduces type coercions, which are defined with the +C<coerce> sugar function. Coercions are attached to existing type +constraints, and define a (one-way) transformation from one type to +another. + +This is very powerful, but it can also have unexpected consequences, so +you have to explicitly ask for an attribute to be coerced. To do this, +you must set the C<coerce> attribute option to a true value. + +First, we create the subtype to which we will coerce the other types: + + subtype 'My::Types::HTTP::Headers' => as class_type('HTTP::Headers'); + +We are creating a subtype rather than using C<HTTP::Headers> as a type +directly. The reason we do this is that coercions are global, and a +coercion defined for C<HTTP::Headers> in our C<Request> class would +then be defined for I<all> Moose-using classes in the current Perl +interpreter. It's a L<best practice|Moose::Manual::BestPractices> to +avoid this sort of namespace pollution. + +The C<class_type> sugar function is simply a shortcut for this: + + subtype 'HTTP::Headers' + => as 'Object' + => where { $_->isa('HTTP::Headers') }; + +Internally, Moose creates a type constraint for each Moose-using +class, but for non-Moose classes, the type must be declared +explicitly. + +We could go ahead and use this new type directly: + + has 'headers' => ( + is => 'rw', + isa => 'My::Types::HTTP::Headers', + default => sub { HTTP::Headers->new } + ); + +This creates a simple attribute which defaults to an empty instance of +L<HTTP::Headers>. + +The constructor for L<HTTP::Headers> accepts a list of key-value pairs +representing the HTTP header fields. In Perl, such a list could be +stored in an ARRAY or HASH reference. We want our C<headers> attribute +to accept those data structures instead of an B<HTTP::Headers> +instance, and just do the right thing. This is exactly what coercion +is for: + + coerce 'My::Types::HTTP::Headers' + => from 'ArrayRef' + => via { HTTP::Headers->new( @{$_} ) } + => from 'HashRef' + => via { HTTP::Headers->new( %{$_} ) }; + +The first argument to C<coerce> is the type I<to> which we are +coercing. Then we give it a set of C<from>/C<via> clauses. The C<from> +function takes some other type name and C<via> takes a subroutine +reference which actually does the coercion. + +However, defining the coercion doesn't do anything until we tell Moose +we want a particular attribute to be coerced: + + has 'headers' => ( + is => 'rw', + isa => 'My::Types::HTTP::Headers', + coerce => 1, + default => sub { HTTP::Headers->new } + ); + +Now, if we use an C<ArrayRef> or C<HashRef> to populate C<headers>, it +will be coerced into a new L<HTTP::Headers> instance. With the +coercion in place, the following lines of code are all equivalent: + + $foo->headers( HTTP::Headers->new( bar => 1, baz => 2 ) ); + $foo->headers( [ 'bar', 1, 'baz', 2 ] ); + $foo->headers( { bar => 1, baz => 2 } ); + +As you can see, careful use of coercions can produce a very open +interface for your class, while still retaining the "safety" of your +type constraint checks. (1) + +Our next coercion shows how we can leverage existing CPAN modules to +help implement coercions. In this case we use L<Params::Coerce>. + +Once again, we need to declare a class type for our non-Moose L<URI> +class: + + subtype 'My::Types::URI' => as class_type('URI'); + +Then we define the coercion: + + coerce 'My::Types::URI' + => from 'Object' + => via { $_->isa('URI') + ? $_ + : Params::Coerce::coerce( 'URI', $_ ); } + => from 'Str' + => via { URI->new( $_, 'http' ) }; + +The first coercion takes any object and makes it a C<URI> object. The +coercion system isn't that smart, and does not check if the object is +already a L<URI>, so we check for that ourselves. If it's not a L<URI> +already, we let L<Params::Coerce> do its magic, and we just use its +return value. + +If L<Params::Coerce> didn't return a L<URI> object (for whatever +reason), Moose would throw a type constraint error. + +The other coercion takes a string and converts it to a L<URI>. In this +case, we are using the coercion to apply a default behavior, where a +string is assumed to be an C<http> URI. + +Finally, we need to make sure our attributes enable coercion. + + has 'base' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 ); + has 'uri' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 ); + +Re-using the coercion lets us enforce a consistent API across multiple +attributes. + +=for testing-SETUP use Test::Requires { + 'HTTP::Headers' => '0', + 'Params::Coerce' => '0', + 'URI' => '0', +}; + +=head1 CONCLUSION + +This recipe showed the use of coercions to create a more flexible and +DWIM-y API. Like any powerful feature, we recommend some +caution. Sometimes it's better to reject a value than just guess at +how to DWIM. + +We also showed the use of the C<class_type> sugar function as a +shortcut for defining a new subtype of C<Object>. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +This particular example could be safer. Really we only want to coerce +an array with an I<even> number of elements. We could create a new +C<EvenElementArrayRef> type, and then coerce from that type, as +opposed to a plain C<ArrayRef> + +=back + +=begin testing + +my $r = Request->new; +isa_ok( $r, 'Request' ); + +{ + my $header = $r->headers; + isa_ok( $header, 'HTTP::Headers' ); + + is( $r->headers->content_type, '', + '... got no content type in the header' ); + + $r->headers( { content_type => 'text/plain' } ); + + my $header2 = $r->headers; + isa_ok( $header2, 'HTTP::Headers' ); + isnt( $header, $header2, '... created a new HTTP::Header object' ); + + is( $header2->content_type, 'text/plain', + '... got the right content type in the header' ); + + $r->headers( [ content_type => 'text/html' ] ); + + my $header3 = $r->headers; + isa_ok( $header3, 'HTTP::Headers' ); + isnt( $header2, $header3, '... created a new HTTP::Header object' ); + + is( $header3->content_type, 'text/html', + '... got the right content type in the header' ); + + $r->headers( HTTP::Headers->new( content_type => 'application/pdf' ) ); + + my $header4 = $r->headers; + isa_ok( $header4, 'HTTP::Headers' ); + isnt( $header3, $header4, '... created a new HTTP::Header object' ); + + is( $header4->content_type, 'application/pdf', + '... got the right content type in the header' ); + + isnt( + exception { + $r->headers('Foo'); + }, + undef, + '... dies when it gets bad params' + ); +} + +{ + is( $r->protocol, undef, '... got nothing by default' ); + + is( + exception { + $r->protocol('HTTP/1.0'); + }, + undef, + '... set the protocol correctly' + ); + + is( $r->protocol, 'HTTP/1.0', '... got nothing by default' ); + + isnt( + exception { + $r->protocol('http/1.0'); + }, + undef, + '... the protocol died with bar params correctly' + ); +} + +{ + $r->base('http://localhost/'); + isa_ok( $r->base, 'URI' ); + + $r->uri('http://localhost/'); + isa_ok( $r->uri, 'URI' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Immutable.pod b/lib/Moose/Cookbook/Basics/Immutable.pod new file mode 100644 index 0000000..c8dacbd --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Immutable.pod @@ -0,0 +1,99 @@ +# PODNAME: Moose::Cookbook::Basics::Immutable +# ABSTRACT: Making Moose fast by making your class immutable + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Immutable - Making Moose fast by making your class immutable + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Point; + use Moose; + + has 'x' => ( isa => 'Int', is => 'ro' ); + has 'y' => ( isa => 'Int', is => 'rw' ); + + __PACKAGE__->meta->make_immutable; + +=head1 DESCRIPTION + +The Moose metaclass API provides a C<make_immutable()> method. Calling +this method does two things to your class. First, it makes it +faster. In particular, object construction and destruction are +effectively "inlined" in your class, and no longer invoke the meta +API. + +Second, you can no longer make changes via the metaclass API, such as +adding attributes. In practice, this won't be a problem, as you rarely +need to do this after first loading the class. + +=head1 CONCLUSION + +We strongly recommend you make your classes immutable. It makes your +code much faster, with a small compile-time cost. This will be +especially noticeable when creating many objects. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Person_BUILDARGSAndBUILD.pod b/lib/Moose/Cookbook/Basics/Person_BUILDARGSAndBUILD.pod new file mode 100644 index 0000000..5262d06 --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Person_BUILDARGSAndBUILD.pod @@ -0,0 +1,180 @@ +# PODNAME: Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD +# ABSTRACT: Using BUILDARGS and BUILD to hook into object construction + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD - Using BUILDARGS and BUILD to hook into object construction + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Person; + + has 'ssn' => ( + is => 'ro', + isa => 'Str', + predicate => 'has_ssn', + ); + + has 'country_of_residence' => ( + is => 'ro', + isa => 'Str', + default => 'usa' + ); + + has 'first_name' => ( + is => 'ro', + isa => 'Str', + ); + + has 'last_name' => ( + is => 'ro', + isa => 'Str', + ); + + around BUILDARGS => sub { + my $orig = shift; + my $class = shift; + + if ( @_ == 1 && ! ref $_[0] ) { + return $class->$orig(ssn => $_[0]); + } + else { + return $class->$orig(@_); + } + }; + + sub BUILD { + my $self = shift; + + if ( $self->country_of_residence eq 'usa' ) { + die 'Cannot create a Person who lives in the USA without an ssn.' + unless $self->has_ssn; + } + } + +=head1 DESCRIPTION + +This recipe demonstrates the use of C<BUILDARGS> and C<BUILD>. By +defining these methods, we can hook into the object construction +process without overriding C<new>. + +The C<BUILDARGS> method is called I<before> an object has been +created. It is called as a class method, and receives all of the +parameters passed to the C<new> method. It is expected to do something +with these arguments and return a hash reference. The keys of the hash +must be attribute C<init_arg>s. + +The primary purpose of C<BUILDARGS> is to allow a class to accept +something other than named arguments. In the case of our C<Person> +class, we are allowing it to be called with a single argument, a +social security number: + + my $person = Person->new('123-45-6789'); + +The key part of our C<BUILDARGS> is this conditional: + + if ( @_ == 1 && ! ref $_[0] ) { + return $class->$orig(ssn => $_[0]); + } + +By default, Moose constructors accept a list of key-value pairs, or a +hash reference. We need to make sure that C<$_[0]> is not a reference +before assuming it is a social security number. + +We call the original C<BUILDARGS> method to handle all the other +cases. You should always do this in your own C<BUILDARGS> methods, +since L<Moose::Object> provides its own C<BUILDARGS> method that +handles hash references and a list of key-value pairs. + +The C<BUILD> method is called I<after> the object is constructed, but +before it is returned to the caller. The C<BUILD> method provides an +opportunity to check the object state as a whole. This is a good place +to put logic that cannot be expressed as a type constraint on a single +attribute. + +In the C<Person> class, we need to check the relationship between two +attributes, C<ssn> and C<country_of_residence>. We throw an exception +if the object is not logically consistent. + +=head1 MORE CONSIDERATIONS + +This recipe is made significantly simpler because all of the +attributes are read-only. If the C<country_of_residence> attribute +were settable, we would need to check that a Person had an C<ssn> if +the new country was C<usa>. This could be done with a C<before> +modifier. + +=head1 CONCLUSION + +We have repeatedly discouraged overriding C<new> in Moose +classes. This recipe shows how you can use C<BUILDARGS> and C<BUILD> +to hook into object construction without overriding C<new>. + +The C<BUILDARGS> method lets us expand on Moose's built-in parameter +handling for constructors. The C<BUILD> method lets us implement +logical constraints across the whole object after it is created. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Basics/Point_AttributesAndSubclassing.pod b/lib/Moose/Cookbook/Basics/Point_AttributesAndSubclassing.pod new file mode 100644 index 0000000..25a55aa --- /dev/null +++ b/lib/Moose/Cookbook/Basics/Point_AttributesAndSubclassing.pod @@ -0,0 +1,489 @@ +# PODNAME: Moose::Cookbook::Basics::Point_AttributesAndSubclassing +# ABSTRACT: Point and Point3D classes, showing basic attributes and subclassing. + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Basics::Point_AttributesAndSubclassing - Point and Point3D classes, showing basic attributes and subclassing. + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Point; + use Moose; + + has 'x' => (isa => 'Int', is => 'rw', required => 1); + has 'y' => (isa => 'Int', is => 'rw', required => 1); + + sub clear { + my $self = shift; + $self->x(0); + $self->y(0); + } + + package Point3D; + use Moose; + + extends 'Point'; + + has 'z' => (isa => 'Int', is => 'rw', required => 1); + + after 'clear' => sub { + my $self = shift; + $self->z(0); + }; + + package main; + + # hash or hashrefs are ok for the constructor + my $point1 = Point->new(x => 5, y => 7); + my $point2 = Point->new({x => 5, y => 7}); + + my $point3d = Point3D->new(x => 5, y => 42, z => -5); + +=head1 DESCRIPTION + +This is the classic Point example. It is taken directly from the Perl +6 Apocalypse 12 document, and is similar to the example found in the +classic K&R C book as well. + +As with all Perl 5 classes, a Moose class is defined in a package. +Moose handles turning on C<strict> and C<warnings> for us, so all we +need to do is say C<use Moose>, and no kittens will die. + +When Moose is loaded, it exports a set of sugar functions into our +package. This means that we import some functions which serve as Moose +"keywords". These aren't real language keywords, they're just Perl +functions exported into our package. + +Moose automatically makes our package a subclass of L<Moose::Object>. +The L<Moose::Object> class provides us with a constructor that +respects our attributes, as well other features. See L<Moose::Object> +for details. + +Now, onto the keywords. The first one we see here is C<has>, which +defines an instance attribute in our class: + + has 'x' => (isa => 'Int', is => 'rw', required => 1); + +This will create an attribute named C<x>. The C<isa> parameter says +that we expect the value stored in this attribute to pass the type +constraint for C<Int> (1). The accessor generated for this attribute +will be read-write. + +The C<< required => 1 >> parameter means that this attribute must be +provided when a new object is created. A point object without +coordinates doesn't make much sense, so we don't allow it. + +We have defined our attributes; next we define our methods. In Moose, +as with regular Perl 5 OO, a method is just a subroutine defined +within the package: + + sub clear { + my $self = shift; + $self->x(0); + $self->y(0); + } + +That concludes the B<Point> class. + +Next we have a subclass of B<Point>, B<Point3D>. To declare our +superclass, we use the Moose keyword C<extends>: + + extends 'Point'; + +The C<extends> keyword works much like C<use base>/C<use parent>. First, +it will attempt to load your class if needed. However, unlike C<base>, the +C<extends> keyword will I<overwrite> any previous values in your +package's C<@ISA>, where C<use base> will C<push> values onto the +package's C<@ISA>. + +It is my opinion that the behavior of C<extends> is more intuitive. +(2). + +Next we create a new attribute for B<Point3D> called C<z>. + + has 'z' => (isa => 'Int', is => 'rw', required => 1); + +This attribute is just like B<Point>'s C<x> and C<y> attributes. + +The C<after> keyword demonstrates a Moose feature called "method +modifiers" (or "advice" for the AOP inclined): + + after 'clear' => sub { + my $self = shift; + $self->z(0); + }; + +When C<clear> is called on a B<Point3D> object, our modifier method +gets called as well. Unsurprisingly, the modifier is called I<after> +the real method. + +In this case, the real C<clear> method is inherited from B<Point>. Our +modifier method receives the same arguments as those passed to the +modified method (just C<$self> here). + +Of course, using the C<after> modifier is not the only way to +accomplish this. This B<is> Perl, right? You can get the same results +with this code: + + sub clear { + my $self = shift; + $self->SUPER::clear(); + $self->z(0); + } + +You could also use another Moose method modifier, C<override>: + + override 'clear' => sub { + my $self = shift; + super(); + $self->z(0); + }; + +The C<override> modifier allows you to use the C<super> keyword to +dispatch to the superclass's method in a very Ruby-ish style. + +The choice of whether to use a method modifier, and which one to use, +is often a question of style as much as functionality. + +Since B<Point> inherits from L<Moose::Object>, it will also inherit +the default L<Moose::Object> constructor: + + my $point1 = Point->new(x => 5, y => 7); + my $point2 = Point->new({x => 5, y => 7}); + + my $point3d = Point3D->new(x => 5, y => 42, z => -5); + +The C<new> constructor accepts a named argument pair for each +attribute defined by the class, which you can provide as a hash or +hash reference. In this particular example, the attributes are +required, and calling C<new> without them will throw an error. + + my $point = Point->new( x => 5 ); # no y, kaboom! + +From here on, we can use C<$point> and C<$point3d> just as you would +any other Perl 5 object. For a more detailed example of what can be +done, you can refer to the +F<t/recipes/moose_cookbook_basics_point_attributesandsubclassing.t> test file. + +=head2 Moose Objects are Just Hashrefs + +While this all may appear rather magical, it's important to realize +that Moose objects are just hash references under the hood (3). For +example, you could pass C<$self> to C<Data::Dumper> and you'd get +exactly what you'd expect. + +You could even poke around inside the object's data structure, but +that is strongly discouraged. + +The fact that Moose objects are hashrefs means it is easy to use Moose +to extend non-Moose classes, as long as they too are hash +references. If you want to extend a non-hashref class, check out +C<MooseX::InsideOut>. + +=head1 CONCLUSION + +This recipe demonstrates some basic Moose concepts, attributes, +subclassing, and a simple method modifier. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +Moose provides a number of builtin type constraints, of which C<Int> +is one. For more information on the type constraint system, see +L<Moose::Util::TypeConstraints>. + +=item (2) + +The C<extends> keyword supports multiple inheritance. Simply pass all +of your superclasses to C<extends> as a list: + + extends 'Foo', 'Bar', 'Baz'; + +=item (3) + +Moose supports using instance structures other than blessed hash +references (such as glob references - see L<MooseX::GlobRef>). + +=back + +=head1 SEE ALSO + +=over 4 + +=item Method Modifiers + +The concept of method modifiers is directly ripped off from CLOS. A +great explanation of them can be found by following this link. + +L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html> + +=back + +=begin testing + +my $point = Point->new( x => 1, y => 2 ); +isa_ok( $point, 'Point' ); +isa_ok( $point, 'Moose::Object' ); + +is( $point->x, 1, '... got the right value for x' ); +is( $point->y, 2, '... got the right value for y' ); + +$point->y(10); +is( $point->y, 10, '... got the right (changed) value for y' ); + +isnt( + exception { + $point->y('Foo'); + }, + undef, + '... cannot assign a non-Int to y' +); + +isnt( + exception { + Point->new(); + }, + undef, + '... must provide required attributes to new' +); + +$point->clear(); + +is( $point->x, 0, '... got the right (cleared) value for x' ); +is( $point->y, 0, '... got the right (cleared) value for y' ); + +# check the type constraints on the constructor + +is( + exception { + Point->new( x => 0, y => 0 ); + }, + undef, + '... can assign a 0 to x and y' +); + +isnt( + exception { + Point->new( x => 10, y => 'Foo' ); + }, + undef, + '... cannot assign a non-Int to y' +); + +isnt( + exception { + Point->new( x => 'Foo', y => 10 ); + }, + undef, + '... cannot assign a non-Int to x' +); + +# Point3D + +my $point3d = Point3D->new( { x => 10, y => 15, z => 3 } ); +isa_ok( $point3d, 'Point3D' ); +isa_ok( $point3d, 'Point' ); +isa_ok( $point3d, 'Moose::Object' ); + +is( $point3d->x, 10, '... got the right value for x' ); +is( $point3d->y, 15, '... got the right value for y' ); +is( $point3d->{'z'}, 3, '... got the right value for z' ); + +$point3d->clear(); + +is( $point3d->x, 0, '... got the right (cleared) value for x' ); +is( $point3d->y, 0, '... got the right (cleared) value for y' ); +is( $point3d->z, 0, '... got the right (cleared) value for z' ); + +isnt( + exception { + Point3D->new( x => 10, y => 'Foo', z => 3 ); + }, + undef, + '... cannot assign a non-Int to y' +); + +isnt( + exception { + Point3D->new( x => 'Foo', y => 10, z => 3 ); + }, + undef, + '... cannot assign a non-Int to x' +); + +isnt( + exception { + Point3D->new( x => 0, y => 10, z => 'Bar' ); + }, + undef, + '... cannot assign a non-Int to z' +); + +isnt( + exception { + Point3D->new( x => 10, y => 3 ); + }, + undef, + '... z is a required attribute for Point3D' +); + +# test some class introspection + +can_ok( 'Point', 'meta' ); +isa_ok( Point->meta, 'Moose::Meta::Class' ); + +can_ok( 'Point3D', 'meta' ); +isa_ok( Point3D->meta, 'Moose::Meta::Class' ); + +isnt( + Point->meta, Point3D->meta, + '... they are different metaclasses as well' +); + +# poke at Point + +is_deeply( + [ Point->meta->superclasses ], + ['Moose::Object'], + '... Point got the automagic base class' +); + +my @Point_methods = qw(meta x y clear); +my @Point_attrs = ( 'x', 'y' ); + +is_deeply( + [ sort @Point_methods ], + [ sort Point->meta->get_method_list() ], + '... we match the method list for Point' +); + +is_deeply( + [ sort @Point_attrs ], + [ sort Point->meta->get_attribute_list() ], + '... we match the attribute list for Point' +); + +foreach my $method (@Point_methods) { + ok( Point->meta->has_method($method), + '... Point has the method "' . $method . '"' ); +} + +foreach my $attr_name (@Point_attrs) { + ok( Point->meta->has_attribute($attr_name), + '... Point has the attribute "' . $attr_name . '"' ); + my $attr = Point->meta->get_attribute($attr_name); + ok( $attr->has_type_constraint, + '... Attribute ' . $attr_name . ' has a type constraint' ); + isa_ok( $attr->type_constraint, 'Moose::Meta::TypeConstraint' ); + is( $attr->type_constraint->name, 'Int', + '... Attribute ' . $attr_name . ' has an Int type constraint' ); +} + +# poke at Point3D + +is_deeply( + [ Point3D->meta->superclasses ], + ['Point'], + '... Point3D gets the parent given to it' +); + +my @Point3D_methods = qw( meta z clear ); +my @Point3D_attrs = ('z'); + +is_deeply( + [ sort @Point3D_methods ], + [ sort Point3D->meta->get_method_list() ], + '... we match the method list for Point3D' +); + +is_deeply( + [ sort @Point3D_attrs ], + [ sort Point3D->meta->get_attribute_list() ], + '... we match the attribute list for Point3D' +); + +foreach my $method (@Point3D_methods) { + ok( Point3D->meta->has_method($method), + '... Point3D has the method "' . $method . '"' ); +} + +foreach my $attr_name (@Point3D_attrs) { + ok( Point3D->meta->has_attribute($attr_name), + '... Point3D has the attribute "' . $attr_name . '"' ); + my $attr = Point3D->meta->get_attribute($attr_name); + ok( $attr->has_type_constraint, + '... Attribute ' . $attr_name . ' has a type constraint' ); + isa_ok( $attr->type_constraint, 'Moose::Meta::TypeConstraint' ); + is( $attr->type_constraint->name, 'Int', + '... Attribute ' . $attr_name . ' has an Int type constraint' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Extending/Debugging_BaseClassRole.pod b/lib/Moose/Cookbook/Extending/Debugging_BaseClassRole.pod new file mode 100644 index 0000000..af1ba0a --- /dev/null +++ b/lib/Moose/Cookbook/Extending/Debugging_BaseClassRole.pod @@ -0,0 +1,152 @@ +# PODNAME: Moose::Cookbook::Extending::Debugging_BaseClassRole +# ABSTRACT: Providing a role for the base object class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Extending::Debugging_BaseClassRole - Providing a role for the base object class + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MooseX::Debugging; + + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( + base_class_roles => ['MooseX::Debugging::Role::Object'], + ); + + package MooseX::Debugging::Role::Object; + + use Moose::Role; + + sub BUILD {} + after BUILD => sub { + my $self = shift; + + warn "Made a new " . ( ref $self ) . " object\n"; + }; + +=head1 DESCRIPTION + +In this example, we provide a role for the base object class that adds +some simple debugging output. Every time an object is created, it +spits out a warning saying what type of object it was. + +Obviously, a real debugging role would do something more interesting, +but this recipe is all about how we apply that role. + +In this case, with the combination of L<Moose::Exporter> and +L<Moose::Util::MetaRole>, we ensure that when a module does C<S<use +MooseX::Debugging>>, it automatically gets the debugging role applied +to its base object class. + +There are a few pieces of code worth looking at more closely. + + Moose::Exporter->setup_import_methods( + base_class_roles => ['MooseX::Debugging::Role::Object'], + ); + +This creates an C<import> method in the C<MooseX::Debugging> package. Since we +are not actually exporting anything, we do not pass C<setup_import_methods> +any parameters related to exports, but we need to have an C<import> method to +ensure that our C<init_meta> method is called. The C<init_meta> is created by +C<setup_import_methods> for us, since we passed the C<base_class_roles> +parameter. The generated C<init_meta> will in turn call +L<Moose::Util::MetaRole::apply_base_class_roles|Moose::Util::MetaRole/apply_base_class_roles>. + + sub BUILD {} + after BUILD => sub { + ... + }; + +Due to the way role composition currently works, if the class that a role is +composed into contains a C<BUILD> method, then that will override the C<BUILD> +method in any roles it composes, which is typically not what you want. Using a +method modifier on C<BUILD> avoids this issue, since method modifiers compose +together rather than being overridden. Method modifiers require that a method +exists in order to wrap, however, so we also provide a stub method to wrap if +no C<BUILD> method exists in the class. + +=for testing-SETUP use Test::Requires 'Test::Output'; + +=begin testing + +{ + package Debugged; + + use Moose; + MooseX::Debugging->import; +} + +stderr_is( + sub { Debugged->new }, + "Made a new Debugged object\n", + 'got expected output from debugging role' +); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Extending/ExtensionOverview.pod b/lib/Moose/Cookbook/Extending/ExtensionOverview.pod new file mode 100644 index 0000000..2dbd898 --- /dev/null +++ b/lib/Moose/Cookbook/Extending/ExtensionOverview.pod @@ -0,0 +1,404 @@ +# PODNAME: Moose::Cookbook::Extending::ExtensionOverview +# ABSTRACT: Moose extension overview + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Extending::ExtensionOverview - Moose extension overview + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +Moose provides several ways in which extensions can hook into Moose +and change its behavior. Moose also has a lot of behavior that can be +changed. This recipe will provide an overview of each extension method +and give you some recommendations on what tools to use. + +If you haven't yet read the recipes on metaclasses, go read those +first. You can't write Moose extensions without understanding the +metaclasses, and those recipes also demonstrate some basic extension +mechanisms, such as metaclass subclasses and traits. + +=head2 Playing Nice With Others + +One of the goals of this overview is to help you build extensions that +cooperate well with other extensions. This is especially important if +you plan to release your extension to CPAN. + +Moose comes with several modules that exist to help your write +cooperative extensions. These are L<Moose::Exporter> and +L<Moose::Util::MetaRole>. By using these two modules, you will ensure +that your extension works with both the Moose core features and any +other CPAN extension using those modules. + +=head1 PARTS OF Moose YOU CAN EXTEND + +The types of things you might want to do in Moose extensions fall into +a few broad categories. + +=head2 Metaclass Extensions + +One way of extending Moose is by extending one or more Moose +metaclasses. For example, in L<Moose::Cookbook::Meta::Table_MetaclassTrait> we saw +a metaclass role that added a C<table> attribute to the +metaclass. If you were writing an ORM, this would be a logical +extension. + +Many of the Moose extensions on CPAN work by providing an attribute +metaclass role. For example, the L<MooseX::Aliases> module +provides an attribute metaclass trait that lets you specify aliases +to install for methods and attribute accessors. + +A metaclass extension can be packaged as a role/trait or a subclass. If you +can, we recommend using traits instead of subclasses, since it's much easier +to combine disparate traits than it is to combine a bunch of subclasses. + +When your extensions are implemented as roles, you can apply them with +the L<Moose::Util::MetaRole> module. + +=head2 Providing Sugar Functions + +As part of a metaclass extension, you may also want to provide some +sugar functions, just like L<Moose.pm|Moose> does. Moose provides a +helper module called L<Moose::Exporter> that makes this much +simpler. We will be use L<Moose::Exporter> in several of the extension +recipes. + +=head2 Object Class Extensions + +Another common Moose extension technique is to change the default object +class's behavior. As with metaclass extensions, this can be done with a +role/trait or with a subclass. For example, L<MooseX::StrictConstructor> +extension applies a trait that makes the constructor reject arguments which +don't match its attributes. + +Object class extensions often include metaclass extensions as well. In +particular, if you want your object extension to work when a class is +made immutable, you may need to modify the behavior of some or all of the +L<Moose::Meta::Instance>, L<Moose::Meta::Method::Constructor>, and +L<Moose::Meta::Method::Destructor> objects. + +The L<Moose::Util::MetaRole> module lets you apply roles to the base +object class, as well as the meta classes just mentioned. + +=head2 Providing a Role + +Some extensions come in the form of a role for you to consume. The +L<MooseX::Object::Pluggable> extension is a great example of this. In +fact, despite the C<MooseX> name, it does not actually change anything +about Moose's behavior. Instead, it is just a role that an object +which wants to be pluggable can consume. + +If you are implementing this sort of extension, you don't need to do +anything special. You simply create a role and document that it should +be used via the normal C<with> sugar: + + package MyApp::User; + + use Moose; + + with 'My::Role'; + +Don't use "MooseX" in the name for such packages. + +=head2 New Types + +Another common Moose extension is a new type for the Moose type +system. In this case, you simply create a type in your module. When +people load your module, the type is created, and they can refer to it +by name after that. The L<MooseX::Types::URI> and +L<MooseX::Types::DateTime> distributions are two good examples of how +this works. These both build on top of the L<MooseX::Types> extension. + +=head1 ROLES VS TRAITS VS SUBCLASSES + +It is important to understand that B<roles and traits are the same thing>. A +trait is simply a role applied to a instance. The only thing that may +distinguish the two is that a trait can be packaged in a way that lets Moose +resolve a short name to a class name. In other words, with a trait, the caller +can refer to it by a short name like "Big", and Moose will resolve it to a +class like C<MooseX::Embiggen::Meta::Attribute::Role::Big>. + +See L<Moose::Cookbook::Meta::Labeled_AttributeTrait> and +L<Moose::Cookbook::Meta::Table_MetaclassTrait> for examples of traits in +action. In particular, both of these recipes demonstrate the trait resolution +mechanism. + +Implementing an extension as a (set of) metaclass or base object +role(s) will make your extension more cooperative. It is hard for an +end-user to effectively combine together multiple metaclass +subclasses, but it is very easy to combine roles. + +=head1 USING YOUR EXTENSION + +There are a number of ways in which an extension can be applied. In +some cases you can provide multiple ways of consuming your extension. + +=head2 Extensions as Metaclass Traits + +If your extension is available as a trait, you can ask end users to +simply specify it in a list of traits. Currently, this only works for +(class) metaclass and attribute metaclass traits: + + use Moose -traits => [ 'Big', 'Blue' ]; + + has 'animal' => ( + traits => [ 'Big', 'Blue' ], + ... + ); + +If your extension applies to any other metaclass, or the object base +class, you cannot use the trait mechanism. + +The benefit of the trait mechanism is that is very easy to see where a +trait is applied in the code, and consumers have fine-grained control +over what the trait applies to. This is especially true for attribute +traits, where you can apply the trait to just one attribute in a +class. + +=head2 Extensions as Metaclass (and Base Object) Roles + +Implementing your extensions as metaclass roles makes your extensions +easy to apply, and cooperative with other role-based extensions for +metaclasses. + +Just as with a subclass, you will probably want to package your +extensions for consumption with a single module that uses +L<Moose::Exporter>. However, in this case, you will use +L<Moose::Util::MetaRole> to apply all of your roles. The advantage of +using this module is that I<it preserves any subclassing or roles +already applied to the user's metaclasses>. This means that your +extension is cooperative I<by default>, and consumers of your +extension can easily use it with other role-based extensions. Most +uses of L<Moose::Util::MetaRole> can be handled by L<Moose::Exporter> +directly; see the L<Moose::Exporter> docs. + + package MooseX::Embiggen; + + use Moose::Exporter; + + use MooseX::Embiggen::Role::Meta::Class; + use MooseX::Embiggen::Role::Meta::Attribute; + use MooseX::Embiggen::Role::Meta::Method::Constructor; + use MooseX::Embiggen::Role::Object; + + Moose::Exporter->setup_import_methods( + class_metaroles => { + class => ['MooseX::Embiggen::Role::Meta::Class'], + attribute => ['MooseX::Embiggen::Role::Meta::Attribute'], + constructor => + ['MooseX::Embiggen::Role::Meta::Method::Constructor'], + }, + base_class_roles => ['MooseX::Embiggen::Role::Object'], + ); + +As you can see from this example, you can use L<Moose::Util::MetaRole> +to apply roles to any metaclass, as well as the base object class. If +some other extension has already applied its own roles, they will be +preserved when your extension applies its roles, and vice versa. + +=head2 Providing Sugar + +With L<Moose::Exporter>, you can also export your own sugar functions: + + package MooseX::Embiggen; + + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( + with_meta => ['embiggen'], + class_metaroles => { + class => ['MooseX::Embiggen::Role::Meta::Class'], + }, + ); + + sub embiggen { + my $meta = shift; + $meta->embiggen(@_); + } + +And then the consumer of your extension can use your C<embiggen> sub: + + package Consumer; + + use Moose; + use MooseX::Embiggen; + + extends 'Thing'; + + embiggen ...; + +This can be combined with metaclass and base class roles quite easily. + +=head2 More advanced extensions + +Providing your extension simply as a set of traits that gets applied to the +appropriate metaobjects is easy, but sometimes not sufficient. For instance, +sometimes you need to supply not just a base object role, but an actual base +object class (due to needing to interact with existing systems that only +provide a base class). To write extensions like this, you will need to provide +a custom C<init_meta> method in your exporter. For instance: + + package MooseX::Embiggen; + + use Moose::Exporter; + + my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods( + install => ['import', 'unimport'], + with_meta => ['embiggen'], + class_metaroles => { + class => ['MooseX::Embiggen::Role::Meta::Class'], + }, + ); + + sub embiggen { + my $meta = shift; + $meta->embiggen(@_); + } + + sub init_meta { + my $package = shift; + my %options = @_; + if (my $meta = Class::MOP::class_of($options{for_class})) { + if ($meta->isa('Class::MOP::Class')) { + my @supers = $meta->superclasses; + $meta->superclasses('MooseX::Embiggen::Base::Class') + if @supers == 1 && $supers[0] eq 'Moose::Object'; + } + } + $package->$init_meta(%options); + } + +In the previous examples, C<init_meta> was generated for you, but here you must +override it in order to add additional functionality. Some differences to note: + +=over 4 + +=item C<build_import_methods> instead of C<setup_import_methods> + +C<build_import_methods> simply returns the C<import>, C<unimport>, and +C<init_meta> methods, rather than installing them under the appropriate names. +This way, you can write your own methods which wrap the functionality provided +by L<Moose::Exporter>. The C<build_import_methods> sub also takes an +additional C<install> parameter, which tells it to just go ahead and install +these methods (since we don't need to modify them). + +=item C<sub init_meta> + +Next, we must write our C<init_meta> wrapper. The important things to remember +are that it is called as a method, and that C<%options> needs to be passed +through to the existing implementation. We call the base implementation by +using the C<$init_meta> subroutine reference that was returned by +C<build_import_methods> earlier. + +=item Additional implementation + +This extension sets a different default base object class. To do so, it first +checks to see if it's being applied to a class, and then checks to see if +L<Moose::Object> is that class's only superclass, and if so, replaces that with +the superclass that this extension requires. + +Note that two extensions that do this same thing will not work together +properly (the second extension to be loaded won't see L<Moose::Object> as the +base object, since it has already been overridden). This is why using a base +object role is recommended for the general case. + +This C<init_meta> also works defensively, by only applying its functionality if +a metaclass already exists. This makes sure it doesn't break with legacy +extensions which override the metaclass directly (and so must be the first +extension to initialize the metaclass). This is likely not necessary, since +almost no extensions work this way anymore, but just provides an additional +level of protection. The common case of C<use Moose; use MooseX::Embiggen;> +is not affected regardless. + +=back + +This is just one example of what can be done with a custom C<init_meta> method. +It can also be used for preventing an extension from being applied to a role, +doing other kinds of validation on the class being applied to, or pretty much +anything that would otherwise be done in an C<import> method. + +=head1 LEGACY EXTENSION MECHANISMS + +Before the existence of L<Moose::Exporter> and +L<Moose::Util::MetaRole>, there were a number of other ways to extend +Moose. In general, these methods were less cooperative, and only +worked well with a single extension. + +These methods include L<metaclass.pm|metaclass>, L<Moose::Policy> +(which uses L<metaclass.pm|metaclass> under the hood), and various +hacks to do what L<Moose::Exporter> does. Please do not use these for +your own extensions. + +Note that if you write a cooperative extension, it should cooperate +with older extensions, though older extensions generally do not +cooperate with each other. + +=head1 CONCLUSION + +If you can write your extension as one or more metaclass and base +object roles, please consider doing so. Make sure to read the docs for +L<Moose::Exporter> and L<Moose::Util::MetaRole> as well. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Extending/Mooseish_MooseSugar.pod b/lib/Moose/Cookbook/Extending/Mooseish_MooseSugar.pod new file mode 100644 index 0000000..dcc4e90 --- /dev/null +++ b/lib/Moose/Cookbook/Extending/Mooseish_MooseSugar.pod @@ -0,0 +1,160 @@ +# PODNAME: Moose::Cookbook::Extending::Mooseish_MooseSugar +# ABSTRACT: Acting like Moose.pm and providing sugar Moose-style + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Extending::Mooseish_MooseSugar - Acting like Moose.pm and providing sugar Moose-style + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Mooseish; + + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( + with_meta => ['has_table'], + class_metaroles => { + class => ['MyApp::Meta::Class::Trait::HasTable'], + }, + ); + + sub has_table { + my $meta = shift; + $meta->table(shift); + } + + package MyApp::Meta::Class::Trait::HasTable; + use Moose::Role; + + has table => ( + is => 'rw', + isa => 'Str', + ); + +=head1 DESCRIPTION + +This recipe expands on the use of L<Moose::Exporter> we saw in +L<Moose::Cookbook::Extending::ExtensionOverview> and the class metaclass trait +we saw in L<Moose::Cookbook::Meta::Table_MetaclassTrait>. In this example we +provide our own metaclass trait, and we also export a C<has_table> sugar +function. + +The C<with_meta> parameter specifies a list of functions that should +be wrapped before exporting. The wrapper simply ensures that the +importing package's appropriate metaclass object is the first argument +to the function, so we can do C<S<my $meta = shift;>>. + +See the L<Moose::Exporter> docs for more details on its API. + +=head1 USING MyApp::Mooseish + +The purpose of all this code is to provide a Moose-like +interface. Here's what it would look like in actual use: + + package MyApp::User; + + use namespace::autoclean; + + use Moose; + use MyApp::Mooseish; + + has_table 'User'; + + has 'username' => ( is => 'ro' ); + has 'password' => ( is => 'ro' ); + + sub login { ... } + +=head1 CONCLUSION + +Providing sugar functions can make your extension look much more +Moose-ish. See L<Fey::ORM> for a more extensive example. + +=begin testing + +{ + package MyApp::User; + + use Moose; + MyApp::Mooseish->import; + + has_table( 'User' ); + + has( 'username' => ( is => 'ro' ) ); + has( 'password' => ( is => 'ro' ) ); + + sub login { } +} + +can_ok( MyApp::User->meta, 'table' ); +is( MyApp::User->meta->table, 'User', + 'MyApp::User->meta->table returns User' ); +ok( MyApp::User->can('username'), + 'MyApp::User has username method' ); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Legacy/Debugging_BaseClassReplacement.pod b/lib/Moose/Cookbook/Legacy/Debugging_BaseClassReplacement.pod new file mode 100644 index 0000000..521452f --- /dev/null +++ b/lib/Moose/Cookbook/Legacy/Debugging_BaseClassReplacement.pod @@ -0,0 +1,182 @@ +# PODNAME: Moose::Cookbook::Legacy::Debugging_BaseClassReplacement +# ABSTRACT: Providing an alternate base object class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Legacy::Debugging_BaseClassReplacement - Providing an alternate base object class + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Base; + use Moose; + + extends 'Moose::Object'; + + before 'new' => sub { warn "Making a new " . $_[0] }; + + no Moose; + + package MyApp::UseMyBase; + use Moose (); + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( also => 'Moose' ); + + sub init_meta { + shift; + return Moose->init_meta( @_, base_class => 'MyApp::Base' ); + } + +=head1 DESCRIPTION + +B<WARNING: Replacing the base class entirely, as opposed to applying roles to +the base class, is strongly discouraged. This recipe is provided solely for +reference when encountering older code that does this.> + +A common extension is to provide an alternate base class. One way to +do that is to make a C<MyApp::Base> and add C<S<extends +'MyApp::Base'>> to every class in your application. That's pretty +tedious. Instead, you can create a Moose-alike module that sets the +base object class to C<MyApp::Base> for you. + +Then, instead of writing C<S<use Moose>> you can write C<S<use +MyApp::UseMyBase>>. + +In this particular example, our base class issues some debugging +output every time a new object is created, but you can think of some +more interesting things to do with your own base class. + +This uses the magic of L<Moose::Exporter>. When we call C<< +Moose::Exporter->setup_import_methods( also => 'Moose' ) >> it builds +C<import> and C<unimport> methods for you. The C<< also => 'Moose' >> +bit says that we want to export everything that Moose does. + +The C<import> method that gets created will call our C<init_meta> +method, passing it C<< for_caller => $caller >> as its +arguments. The C<$caller> is set to the class that actually imported +us in the first place. + +See the L<Moose::Exporter> docs for more details on its API. + +=for testing-SETUP use Test::Requires 'Test::Output'; + +=head1 USING MyApp::UseMyBase + +To actually use our new base class, we simply use C<MyApp::UseMyBase> +I<instead> of C<Moose>. We get all the Moose sugar plus our new base +class. + + package Foo; + + use MyApp::UseMyBase; + + has 'size' => ( is => 'rw' ); + + no MyApp::UseMyBase; + +=head1 CONCLUSION + +This is an awful lot of magic for a simple base class. You will often +want to combine a metaclass trait with a base class extension, and +that's when this technique is useful. + +=begin testing + +{ + package Foo; + + MyApp::UseMyBase->import; + + has( 'size' => ( is => 'rw' ) ); +} + +ok( Foo->isa('MyApp::Base'), 'Foo isa MyApp::Base' ); + +ok( Foo->can('size'), 'Foo has a size method' ); + +my $foo; +stderr_like( + sub { $foo = Foo->new( size => 2 ) }, + qr/^Making a new Foo/, + 'got expected warning when calling Foo->new' +); + +is( $foo->size(), 2, '$foo->size is 2' ); + +=end testing + +=head1 AUTHOR + +Moose is maintained by the Moose Cabal, along with the help of many contributors. See L<Moose/CABAL> and L<Moose/CONTRIBUTORS> for details. + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2012 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Legacy/Labeled_AttributeMetaclass.pod b/lib/Moose/Cookbook/Legacy/Labeled_AttributeMetaclass.pod new file mode 100644 index 0000000..813b1d9 --- /dev/null +++ b/lib/Moose/Cookbook/Legacy/Labeled_AttributeMetaclass.pod @@ -0,0 +1,337 @@ +# PODNAME: Moose::Cookbook::Legacy::Labeled_AttributeMetaclass +# ABSTRACT: A meta-attribute, attributes with labels + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Legacy::Labeled_AttributeMetaclass - A meta-attribute, attributes with labels + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Meta::Attribute::Labeled; + use Moose; + extends 'Moose::Meta::Attribute'; + + has label => ( + is => 'rw', + isa => 'Str', + predicate => 'has_label', + ); + + package Moose::Meta::Attribute::Custom::Labeled; + sub register_implementation {'MyApp::Meta::Attribute::Labeled'} + + package MyApp::Website; + use Moose; + + has url => ( + metaclass => 'Labeled', + is => 'rw', + isa => 'Str', + label => "The site's URL", + ); + + has name => ( + is => 'rw', + isa => 'Str', + ); + + sub dump { + my $self = shift; + + my $meta = $self->meta; + + my $dump = ''; + + for my $attribute ( map { $meta->get_attribute($_) } + sort $meta->get_attribute_list ) { + + if ( $attribute->isa('MyApp::Meta::Attribute::Labeled') + && $attribute->has_label ) { + $dump .= $attribute->label; + } + else { + $dump .= $attribute->name; + } + + my $reader = $attribute->get_read_method; + $dump .= ": " . $self->$reader . "\n"; + } + + return $dump; + } + + package main; + + my $app = MyApp::Website->new( url => "http://google.com", name => "Google" ); + +=head1 SUMMARY + +B<WARNING: Subclassing metaclasses (as opposed to providing metaclass traits) +is strongly discouraged. This recipe is provided solely for reference when +encountering older code that does this.> + +In this recipe, we begin to delve into the wonder of meta-programming. +Some readers may scoff and claim that this is the arena of only the +most twisted Moose developers. Absolutely not! Any sufficiently +twisted developer can benefit greatly from going more meta. + +Our goal is to allow each attribute to have a human-readable "label" +attached to it. Such labels would be used when showing data to an end +user. In this recipe we label the C<url> attribute with "The site's +URL" and create a simple method showing how to use that label. + +The proper, modern way to extend attributes (using a role instead of a +subclass) is described in L<Moose::Cookbook::Meta::Recipe3>, but that recipe +assumes you've read and at least tried to understand this one. + +=head1 META-ATTRIBUTE OBJECTS + +All the attributes of a Moose-based object are actually objects +themselves. These objects have methods and attributes. Let's look at +a concrete example. + + has 'x' => ( isa => 'Int', is => 'ro' ); + has 'y' => ( isa => 'Int', is => 'rw' ); + +Internally, the metaclass for C<Point> has two +L<Moose::Meta::Attribute>. There are several methods for getting +meta-attributes out of a metaclass, one of which is +C<get_attribute_list>. This method is called on the metaclass object. + +The C<get_attribute_list> method returns a list of attribute names. You can +then use C<get_attribute> to get the L<Moose::Meta::Attribute> object itself. + +Once you have this meta-attribute object, you can call methods on it like this: + + print $point->meta->get_attribute('x')->type_constraint; + => Int + +To add a label to our attributes there are two steps. First, we need a +new attribute metaclass that can store a label for an +attribute. Second, we need to create attributes that use that +attribute metaclass. + +=head1 RECIPE REVIEW + +We start by creating a new attribute metaclass. + + package MyApp::Meta::Attribute::Labeled; + use Moose; + extends 'Moose::Meta::Attribute'; + +We can subclass a Moose metaclass in the same way that we subclass +anything else. + + has label => ( + is => 'rw', + isa => 'Str', + predicate => 'has_label', + ); + +Again, this is standard Moose code. + +Then we need to register our metaclass with Moose: + + package Moose::Meta::Attribute::Custom::Labeled; + sub register_implementation { 'MyApp::Meta::Attribute::Labeled' } + +This is a bit of magic that lets us use a short name, "Labeled", when +referring to our new metaclass. + +That was the whole attribute metaclass. + +Now we start using it. + + package MyApp::Website; + use Moose; + use MyApp::Meta::Attribute::Labeled; + +We have to load the metaclass to use it, just like any Perl class. + +Finally, we use it for an attribute: + + has url => ( + metaclass => 'Labeled', + is => 'rw', + isa => 'Str', + label => "The site's URL", + ); + +This looks like a normal attribute declaration, except for two things, +the C<metaclass> and C<label> parameters. The C<metaclass> parameter +tells Moose we want to use a custom metaclass for this (one) +attribute. The C<label> parameter will be stored in the meta-attribute +object. + +The reason that we can pass the name C<Labeled>, instead of +C<MyApp::Meta::Attribute::Labeled>, is because of the +C<register_implementation> code we touched on previously. + +When you pass a metaclass to C<has>, it will take the name you provide +and prefix it with C<Moose::Meta::Attribute::Custom::>. Then it calls +C<register_implementation> in the package. In this case, that means +Moose ends up calling +C<Moose::Meta::Attribute::Custom::Labeled::register_implementation>. + +If this function exists, it should return the I<real> metaclass +package name. This is exactly what our code does, returning +C<MyApp::Meta::Attribute::Labeled>. This is a little convoluted, and +if you don't like it, you can always use the fully-qualified name. + +We can access this meta-attribute and its label like this: + + $website->meta->get_attribute('url')->label() + + MyApp::Website->meta->get_attribute('url')->label() + +We also have a regular attribute, C<name>: + + has name => ( + is => 'rw', + isa => 'Str', + ); + +This is a regular Moose attribute, because we have not specified a new +metaclass. + +Finally, we have a C<dump> method, which creates a human-readable +representation of a C<MyApp::Website> object. It will use an +attribute's label if it has one. + + sub dump { + my $self = shift; + + my $meta = $self->meta; + + my $dump = ''; + + for my $attribute ( map { $meta->get_attribute($_) } + sort $meta->get_attribute_list ) { + + if ( $attribute->isa('MyApp::Meta::Attribute::Labeled') + && $attribute->has_label ) { + $dump .= $attribute->label; + } + +This is a bit of defensive code. We cannot depend on every +meta-attribute having a label. Even if we define one for every +attribute in our class, a subclass may neglect to do so. Or a +superclass could add an attribute without a label. + +We also check that the attribute has a label using the predicate we +defined. We could instead make the label C<required>. If we have a +label, we use it, otherwise we use the attribute name: + + else { + $dump .= $attribute->name; + } + + my $reader = $attribute->get_read_method; + $dump .= ": " . $self->$reader . "\n"; + } + + return $dump; + } + +The C<get_read_method> is part of the L<Moose::Meta::Attribute> +API. It returns the name of a method that can read the attribute's +value, I<when called on the real object> (don't call this on the +meta-attribute). + +=head1 CONCLUSION + +You might wonder why you'd bother with all this. You could just +hardcode "The Site's URL" in the C<dump> method. But we want to avoid +repetition. If you need the label once, you may need it elsewhere, +maybe in the C<as_form> method you write next. + +Associating a label with an attribute just makes sense! The label is a +piece of information I<about> the attribute. + +It's also important to realize that this was a trivial example. You +can make much more powerful metaclasses that I<do> things, as opposed +to just storing some more information. For example, you could +implement a metaclass that expires attributes after a certain amount +of time: + + has site_cache => ( + metaclass => 'TimedExpiry', + expires_after => { hours => 1 }, + refresh_with => sub { get( $_[0]->url ) }, + isa => 'Str', + is => 'ro', + ); + +The sky's the limit! + +=for testing my $app = MyApp::Website->new( url => "http://google.com", name => "Google" ); +is( + $app->dump, q{name: Google +The site's URL: http://google.com +}, '... got the expected dump value' +); + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Legacy/Table_ClassMetaclass.pod b/lib/Moose/Cookbook/Legacy/Table_ClassMetaclass.pod new file mode 100644 index 0000000..e264fea --- /dev/null +++ b/lib/Moose/Cookbook/Legacy/Table_ClassMetaclass.pod @@ -0,0 +1,132 @@ +# PODNAME: Moose::Cookbook::Legacy::Table_ClassMetaclass +# ABSTRACT: Adding a "table" attribute to the metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Legacy::Table_ClassMetaclass - Adding a "table" attribute to the metaclass + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Meta::Class; + use Moose; + extends 'Moose::Meta::Class'; + + has table => ( + is => 'rw', + isa => 'Str', + ); + +=head1 DESCRIPTION + +B<WARNING: Subclassing metaclasses (as opposed to providing metaclass traits) +is strongly discouraged. This recipe is provided solely for reference when +encountering older code that does this.> + +In this recipe, we'll create a new metaclass which has a "table" +attribute. This metaclass is for classes associated with a DBMS table, +as one might do for an ORM. + +In this example, the table name is just a string, but in a real ORM +the table might be an object describing the table. + +=head1 THE METACLASS + +This really is as simple as the recipe L</SYNOPSIS> shows. The trick +is getting your classes to use this metaclass, and providing some sort +of sugar for declaring the table. This is covered in +L<Moose::Cookbook::Extending::Recipe2>, which shows how to make a +module like C<Moose.pm> itself, with sugar like C<has_table()>. + +=head2 Using this Metaclass in Practice + +Accessing this new C<table> attribute is quite simple. Given a class +named C<MyApp::User>, we could simply write the following: + + my $table = MyApp::User->meta->table; + +As long as C<MyApp::User> has arranged to use C<MyApp::Meta::Class> as +its metaclass, this method call just works. If we want to be more +careful, we can check the metaclass's class: + + $table = MyApp::User->meta->table + if MyApp::User->meta->isa('MyApp::Meta::Class'); + +=head1 CONCLUSION + +Creating custom metaclass is trivial. Using it is a little harder, and +is covered in other recipes. We will also talk about applying traits +to a class metaclass, which is a more flexible and cooperative +implementation. + +=head1 SEE ALSO + +L<Moose::Cookbook::Meta::Recipe5> - The "table" attribute implemented +as a metaclass trait + +L<Moose::Cookbook::Extending::Recipe2> - Acting like Moose.pm and +providing sugar Moose-style + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod b/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod new file mode 100644 index 0000000..9ca9f68 --- /dev/null +++ b/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod @@ -0,0 +1,304 @@ +# PODNAME: Moose::Cookbook::Meta::GlobRef_InstanceMetaclass +# ABSTRACT: Creating a glob reference meta-instance class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Meta::GlobRef_InstanceMetaclass - Creating a glob reference meta-instance class + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package My::Meta::Instance; + + use Scalar::Util qw( weaken ); + use Symbol qw( gensym ); + + use Moose::Role; + + sub create_instance { + my $self = shift; + my $sym = gensym(); + bless $sym, $self->_class_name; + } + + sub clone_instance { + my ( $self, $instance ) = @_; + + my $new_sym = gensym(); + %{*$new_sym} = %{*$instance}; + + bless $new_sym, $self->_class_name; + } + + sub get_slot_value { + my ( $self, $instance, $slot_name ) = @_; + return *$instance->{$slot_name}; + } + + sub set_slot_value { + my ( $self, $instance, $slot_name, $value ) = @_; + *$instance->{$slot_name} = $value; + } + + sub deinitialize_slot { + my ( $self, $instance, $slot_name ) = @_; + delete *$instance->{$slot_name}; + } + + sub is_slot_initialized { + my ( $self, $instance, $slot_name ) = @_; + exists *$instance->{$slot_name}; + } + + sub weaken_slot_value { + my ( $self, $instance, $slot_name ) = @_; + weaken *$instance->{$slot_name}; + } + + sub inline_create_instance { + my ( $self, $class_variable ) = @_; + return 'do { my $sym = Symbol::gensym(); bless $sym, ' . $class_variable . ' }'; + } + + sub inline_slot_access { + my ( $self, $instance, $slot_name ) = @_; + return '*{' . $instance . '}->{' . $slot_name . '}'; + } + + package MyApp::User; + + use Moose; + Moose::Util::MetaRole::apply_metaroles( + for => __PACKAGE__, + class_metaroles => { + instance => ['My::Meta::Instance'], + }, + ); + + has 'name' => ( + is => 'rw', + isa => 'Str', + ); + + has 'email' => ( + is => 'rw', + isa => 'Str', + ); + +=head1 DESCRIPTION + +This recipe shows how to build your own meta-instance. The meta +instance is the metaclass that creates object instances and helps +manages access to attribute slots. + +In this example, we're creating a meta-instance that is based on a +glob reference rather than a hash reference. This example is largely +based on the Piotr Roszatycki's L<MooseX::GlobRef> module. + +Our extension is a role which will be applied to L<Moose::Meta::Instance>, +which creates hash reference based objects. We need to override all the methods +which make assumptions about the object's data structure. + +The first method we override is C<create_instance>: + + sub create_instance { + my $self = shift; + my $sym = gensym(); + bless $sym, $self->_class_name; + } + +This returns an glob reference which has been blessed into our +meta-instance's associated class. + +We also override C<clone_instance> to create a new array reference: + + sub clone_instance { + my ( $self, $instance ) = @_; + + my $new_sym = gensym(); + %{*$new_sym} = %{*$instance}; + + bless $new_sym, $self->_class_name; + } + +After that, we have a series of methods which mediate access to the +object's slots (attributes are stored in "slots"). In the default +instance class, these expect the object to be a hash reference, but we +need to change this to expect a glob reference instead. + + sub get_slot_value { + my ( $self, $instance, $slot_name ) = @_; + *$instance->{$slot_name}; + } + +This level of indirection probably makes our instance class I<slower> +than the default. However, when attribute access is inlined, this +lookup will be cached: + + sub inline_slot_access { + my ( $self, $instance, $slot_name ) = @_; + return '*{' . $instance . '}->{' . $slot_name . '}'; + } + +The code snippet that the C<inline_slot_access> method returns will +get C<eval>'d once per attribute. + +Finally, we use this meta-instance in our C<MyApp::User> class: + + Moose::Util::MetaRole::apply_metaroles( + for => __PACKAGE__, + class_metaroles => { + instance => ['My::Meta::Instance'], + }, + ); + +We actually don't recommend the use of L<Moose::Util::MetaRole> directly in +your class in most cases. Typically, this would be provided by a +L<Moose::Exporter>-based module which handles applying the role for you. + +=head1 CONCLUSION + +This recipe shows how to create your own meta-instance class. It's +unlikely that you'll need to do this yourself, but it's interesting to +take a peek at how Moose works under the hood. + +=head1 SEE ALSO + +There are a few meta-instance class extensions on CPAN: + +=over 4 + +=item * L<MooseX::Singleton> + +This module extends the instance class in order to ensure that the +object is a singleton. The instance it uses is still a blessed hash +reference. + +=item * L<MooseX::GlobRef> + +This module makes the instance a blessed glob reference. This lets you +use a handle as an object instance. + +=back + +=begin testing + +{ + package MyApp::Employee; + + use Moose; + extends 'MyApp::User'; + + has 'employee_number' => ( is => 'rw' ); +} + +for my $x ( 0 .. 1 ) { + MyApp::User->meta->make_immutable if $x; + + my $user = MyApp::User->new( + name => 'Faye', + email => 'faye@example.com', + ); + + ok( eval { *{$user} }, 'user object is an glob ref with some values' ); + + is( $user->name, 'Faye', 'check name' ); + is( $user->email, 'faye@example.com', 'check email' ); + + $user->name('Ralph'); + is( $user->name, 'Ralph', 'check name after changing it' ); + + $user->email('ralph@example.com'); + is( $user->email, 'ralph@example.com', 'check email after changing it' ); +} + +for my $x ( 0 .. 1 ) { + MyApp::Employee->meta->make_immutable if $x; + + my $emp = MyApp::Employee->new( + name => 'Faye', + email => 'faye@example.com', + employee_number => $x, + ); + + ok( eval { *{$emp} }, 'employee object is an glob ref with some values' ); + + is( $emp->name, 'Faye', 'check name' ); + is( $emp->email, 'faye@example.com', 'check email' ); + is( $emp->employee_number, $x, 'check employee_number' ); + + $emp->name('Ralph'); + is( $emp->name, 'Ralph', 'check name after changing it' ); + + $emp->email('ralph@example.com'); + is( $emp->email, 'ralph@example.com', 'check email after changing it' ); + + $emp->employee_number(42); + is( $emp->employee_number, 42, 'check employee_number after changing it' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod b/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod new file mode 100644 index 0000000..cebe091 --- /dev/null +++ b/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod @@ -0,0 +1,325 @@ +# PODNAME: Moose::Cookbook::Meta::Labeled_AttributeTrait +# ABSTRACT: Labels implemented via attribute traits + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Meta::Labeled_AttributeTrait - Labels implemented via attribute traits + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Meta::Attribute::Trait::Labeled; + use Moose::Role; + Moose::Util::meta_attribute_alias('Labeled'); + + has label => ( + is => 'rw', + isa => 'Str', + predicate => 'has_label', + ); + + package MyApp::Website; + use Moose; + + has url => ( + traits => [qw/Labeled/], + is => 'rw', + isa => 'Str', + label => "The site's URL", + ); + + has name => ( + is => 'rw', + isa => 'Str', + ); + + sub dump { + my $self = shift; + + my $meta = $self->meta; + + my $dump = ''; + + for my $attribute ( map { $meta->get_attribute($_) } + sort $meta->get_attribute_list ) { + + if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled') + && $attribute->has_label ) { + $dump .= $attribute->label; + } + else { + $dump .= $attribute->name; + } + + my $reader = $attribute->get_read_method; + $dump .= ": " . $self->$reader . "\n"; + } + + return $dump; + } + + package main; + + my $app = MyApp::Website->new( url => "http://google.com", name => "Google" ); + +=head1 SUMMARY + +In this recipe, we begin to delve into the wonder of meta-programming. +Some readers may scoff and claim that this is the arena of only the +most twisted Moose developers. Absolutely not! Any sufficiently +twisted developer can benefit greatly from going more meta. + +Our goal is to allow each attribute to have a human-readable "label" +attached to it. Such labels would be used when showing data to an end +user. In this recipe we label the C<url> attribute with "The site's +URL" and create a simple method showing how to use that label. + +=head1 META-ATTRIBUTE OBJECTS + +All the attributes of a Moose-based object are actually objects themselves. +These objects have methods and attributes. Let's look at a concrete example. + + has 'x' => ( isa => 'Int', is => 'ro' ); + has 'y' => ( isa => 'Int', is => 'rw' ); + +Internally, the metaclass for C<Point> has two L<Moose::Meta::Attribute> +objects. There are several methods for getting meta-attributes out of a +metaclass, one of which is C<get_attribute_list>. This method is called on the +metaclass object. + +The C<get_attribute_list> method returns a list of attribute names. You can +then use C<get_attribute> to get the L<Moose::Meta::Attribute> object itself. + +Once you have this meta-attribute object, you can call methods on it like +this: + + print $point->meta->get_attribute('x')->type_constraint; + => Int + +To add a label to our attributes there are two steps. First, we need a new +attribute metaclass trait that can store a label for an attribute. Second, we +need to apply that trait to our attributes. + +=head1 TRAITS + +Roles that apply to metaclasses have a special name: traits. Don't let +the change in nomenclature fool you, B<traits are just roles>. + +L<Moose/has> allows you to pass a C<traits> parameter for an +attribute. This parameter takes a list of trait names which are +composed into an anonymous metaclass, and that anonymous metaclass is +used for the attribute. + +Yes, we still have lots of metaclasses in the background, but they're +managed by Moose for you. + +Traits can do anything roles can do. They can add or refine +attributes, wrap methods, provide more methods, define an interface, +etc. The only difference is that you're now changing the attribute +metaclass instead of a user-level class. + +=head1 DISSECTION + +We start by creating a package for our trait. + + package MyApp::Meta::Attribute::Trait::Labeled; + use Moose::Role; + + has label => ( + is => 'rw', + isa => 'Str', + predicate => 'has_label', + ); + +You can see that a trait is just a L<Moose::Role>. In this case, our role +contains a single attribute, C<label>. Any attribute which does this trait +will now have a label. + +We also register our trait with Moose: + + Moose::Util::meta_attribute_alias('Labeled'); + +This allows Moose to find our trait by the short name C<Labeled> when passed +to the C<traits> attribute option, rather than requiring the full package +name to be specified. + +Finally, we pass our trait when defining an attribute: + + has url => ( + traits => [qw/Labeled/], + is => 'rw', + isa => 'Str', + label => "The site's URL", + ); + +The C<traits> parameter contains a list of trait names. Moose will build an +anonymous attribute metaclass from these traits and use it for this +attribute. + +The reason that we can pass the name C<Labeled>, instead of +C<MyApp::Meta::Attribute::Trait::Labeled>, is because of the +C<register_implementation> code we touched on previously. + +When you pass a metaclass to C<has>, it will take the name you provide and +prefix it with C<Moose::Meta::Attribute::Custom::Trait::>. Then it calls +C<register_implementation> in the package. In this case, that means Moose ends +up calling +C<Moose::Meta::Attribute::Custom::Trait::Labeled::register_implementation>. + +If this function exists, it should return the I<real> trait's package +name. This is exactly what our code does, returning +C<MyApp::Meta::Attribute::Trait::Labeled>. This is a little convoluted, and if +you don't like it, you can always use the fully-qualified name. + +We can access this meta-attribute and its label like this: + + $website->meta->get_attribute('url')->label() + + MyApp::Website->meta->get_attribute('url')->label() + +We also have a regular attribute, C<name>: + + has name => ( + is => 'rw', + isa => 'Str', + ); + +Finally, we have a C<dump> method, which creates a human-readable +representation of a C<MyApp::Website> object. It will use an attribute's label +if it has one. + + sub dump { + my $self = shift; + + my $meta = $self->meta; + + my $dump = ''; + + for my $attribute ( map { $meta->get_attribute($_) } + sort $meta->get_attribute_list ) { + + if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled') + && $attribute->has_label ) { + $dump .= $attribute->label; + } + +This is a bit of defensive code. We cannot depend on every meta-attribute +having a label. Even if we define one for every attribute in our class, a +subclass may neglect to do so. Or a superclass could add an attribute without +a label. + +We also check that the attribute has a label using the predicate we +defined. We could instead make the label C<required>. If we have a label, we +use it, otherwise we use the attribute name: + + else { + $dump .= $attribute->name; + } + + my $reader = $attribute->get_read_method; + $dump .= ": " . $self->$reader . "\n"; + } + + return $dump; + } + +The C<get_read_method> is part of the L<Moose::Meta::Attribute> API. It +returns the name of a method that can read the attribute's value, I<when +called on the real object> (don't call this on the meta-attribute). + +=head1 CONCLUSION + +You might wonder why you'd bother with all this. You could just hardcode "The +Site's URL" in the C<dump> method. But we want to avoid repetition. If you +need the label once, you may need it elsewhere, maybe in the C<as_form> method +you write next. + +Associating a label with an attribute just makes sense! The label is a piece +of information I<about> the attribute. + +It's also important to realize that this was a trivial example. You can make +much more powerful metaclasses that I<do> things, as opposed to just storing +some more information. For example, you could implement a metaclass that +expires attributes after a certain amount of time: + + has site_cache => ( + traits => ['TimedExpiry'], + expires_after => { hours => 1 }, + refresh_with => sub { get( $_[0]->url ) }, + isa => 'Str', + is => 'ro', + ); + +The sky's the limit! + +=for testing my $app + = MyApp::Website->new( url => 'http://google.com', name => 'Google' ); +is( + $app->dump, q{name: Google +The site's URL: http://google.com +}, '... got the expected dump value' +); + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod b/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod new file mode 100644 index 0000000..dab0a38 --- /dev/null +++ b/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod @@ -0,0 +1,224 @@ +# PODNAME: Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass +# ABSTRACT: A method metaclass for marking methods public or private + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass - A method metaclass for marking methods public or private + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Meta::Method::PrivateOrPublic; + + use Moose; + use Moose::Util::TypeConstraints; + + extends 'Moose::Meta::Method'; + + has '_policy' => ( + is => 'ro', + isa => enum( [ qw( public private ) ] ), + default => 'public', + init_arg => 'policy', + ); + + sub new { + my $class = shift; + my %options = @_; + + my $self = $class->SUPER::wrap(%options); + + $self->{_policy} = $options{policy}; + + $self->_add_policy_wrapper; + + return $self; + } + + sub _add_policy_wrapper { + my $self = shift; + + return if $self->is_public; + + my $name = $self->name; + my $package = $self->package_name; + my $real_body = $self->body; + + my $body = sub { + die "The $package\::$name method is private" + unless ( scalar caller() ) eq $package; + + goto &{$real_body}; + }; + + $self->{body} = $body; + } + + sub is_public { $_[0]->_policy eq 'public' } + sub is_private { $_[0]->_policy eq 'private' } + + package MyApp::User; + + use Moose; + + has 'password' => ( is => 'rw' ); + + __PACKAGE__->meta()->add_method( + '_reset_password', + MyApp::Meta::Method::PrivateOrPublic->new( + name => '_reset_password', + package_name => __PACKAGE__, + body => sub { $_[0]->password('reset') }, + policy => 'private', + ) + ); + +=head1 DESCRIPTION + +This example shows a custom method metaclass that models public versus +private methods. If a method is defined as private, it adds a wrapper +around the method which dies unless it is called from the class where +it was defined. + +The way the method is added to the class is rather ugly. If we wanted +to make this a real feature, we'd probably want to add some sort of +sugar to allow us to declare private methods, but that is beyond the +scope of this recipe. See the Extending recipes for more on this +topic. + +The core of our custom class is the C<policy> attribute, and +C<_add_policy_wrapper> method. + +You'll note that we have to explicitly set the C<policy> attribute in +our constructor: + + $self->{_policy} = $options{policy}; + +That is necessary because Moose metaclasses do not use the meta API to +create objects. Most Moose classes have a custom "inlined" constructor +for speed. + +In this particular case, our parent class's constructor is the C<wrap> +method. We call that to build our object, but it does not include +subclass-specific attributes. + +The C<_add_policy_wrapper> method is where the real work is done. If +the method is private, we construct a wrapper around the real +subroutine which checks that the caller matches the package in which +the subroutine was created. + +If they don't match, it dies. If they do match, the real method is +called. We use C<goto> so that the wrapper does not show up in the +call stack. + +Finally, we replace the value of C<< $self->{body} >>. This is another +case where we have to do something a bit gross because Moose does not +use Moose for its own implementation. + +When we pass this method object to the metaclass's C<add_method> +method, it will take the method body and make it available in the +class. + +Finally, when we retrieve these methods via the introspection API, we +can call the C<is_public> and C<is_private> methods on them to get +more information about the method. + +=head1 SUMMARY + +A custom method metaclass lets us add both behavior and +meta-information to methods. Unfortunately, because the Perl +interpreter does not provide easy hooks into method declaration, the +API we have for adding these methods is not very pretty. + +That can be improved with custom Moose-like sugar, or even by using a +tool like L<Devel::Declare> to create full-blown new keywords in Perl. + +=begin testing + +package main; +use strict; +use warnings; + +use Test::Fatal; + +my $user = MyApp::User->new( password => 'foo!' ); + +like( exception { $user->_reset_password }, +qr/The MyApp::User::_reset_password method is private/, + '_reset_password method dies if called outside MyApp::User class'); + +{ + package MyApp::User; + + sub run_reset { $_[0]->_reset_password } +} + +$user->run_reset; + +is( $user->password, 'reset', 'password has been reset' ); + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod b/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod new file mode 100644 index 0000000..cf352e7 --- /dev/null +++ b/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod @@ -0,0 +1,156 @@ +# PODNAME: Moose::Cookbook::Meta::Table_MetaclassTrait +# ABSTRACT: Adding a "table" attribute as a metaclass trait + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Meta::Table_MetaclassTrait - Adding a "table" attribute as a metaclass trait + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + # in lib/MyApp/Meta/Class/Trait/HasTable.pm + package MyApp::Meta::Class::Trait::HasTable; + use Moose::Role; + Moose::Util::meta_class_alias('HasTable'); + + has table => ( + is => 'rw', + isa => 'Str', + ); + + # in lib/MyApp/User.pm + package MyApp::User; + use Moose -traits => 'HasTable'; + + __PACKAGE__->meta->table('User'); + +=head1 DESCRIPTION + +In this recipe, we'll create a class metaclass trait which has a "table" +attribute. This trait is for classes associated with a DBMS table, as one +might do for an ORM. + +In this example, the table name is just a string, but in a real ORM +the table might be an object describing the table. + +=begin testing-SETUP + +BEGIN { + package MyApp::Meta::Class::Trait::HasTable; + use Moose::Role; + Moose::Util::meta_class_alias('HasTable'); + + has table => ( + is => 'rw', + isa => 'Str', + ); +} + +=end testing-SETUP + +=head1 THE METACLASS TRAIT + +This really is as simple as the recipe L</SYNOPSIS> shows. The trick is +getting your classes to use this metaclass, and providing some sort of sugar +for declaring the table. This is covered in +L<Moose::Cookbook::Extending::Debugging_BaseClassRole>, which shows how to +make a module like C<Moose.pm> itself, with sugar like C<has_table()>. + +=head2 Using this Metaclass Trait in Practice + +Accessing this new C<table> attribute is quite simple. Given a class +named C<MyApp::User>, we could simply write the following: + + my $table = MyApp::User->meta->table; + +As long as C<MyApp::User> has arranged to apply the +C<MyApp::Meta::Class::Trait::HasTable> to its metaclass, this method call just +works. If we want to be more careful, we can check that the class metaclass +object has a C<table> method: + + $table = MyApp::User->meta->table + if MyApp::User->meta->can('table'); + +In theory, this is not entirely correct, since the metaclass might be getting +its C<table> method from a I<different> trait. In practice, you are unlikely +to encounter this sort of problem. + +=head1 RECIPE CAVEAT + +This recipe doesn't work when you paste it all into a single file. This is +because the C<< use Moose -traits => 'HasTable'; >> line ends up being +executed before the C<table> attribute is defined. + +When the two packages are separate files, this just works. + +=head1 SEE ALSO + +L<Moose::Cookbook::Meta::Labeled_AttributeTrait> - Labels implemented via +attribute traits + +=for testing can_ok( MyApp::User->meta, 'table' ); +is( MyApp::User->meta->table, 'User', 'My::User table is User' ); + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Meta/WhyMeta.pod b/lib/Moose/Cookbook/Meta/WhyMeta.pod new file mode 100644 index 0000000..9ea83f3 --- /dev/null +++ b/lib/Moose/Cookbook/Meta/WhyMeta.pod @@ -0,0 +1,117 @@ +# PODNAME: Moose::Cookbook::Meta::WhyMeta +# ABSTRACT: Welcome to the meta world (Why Go Meta?) + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Meta::WhyMeta - Welcome to the meta world (Why Go Meta?) + +=head1 VERSION + +version 2.1405 + +=head1 SUMMARY + +You might want to read L<Moose::Manual::MOP> if you haven't done so +yet. + +If you've ever thought "Moose is great, but I wish it did X +differently", then you've gone meta. The meta recipes demonstrate how +to change and extend the way Moose works by extending and overriding +how the meta classes (L<Moose::Meta::Class>, +L<Moose::Meta::Attribute>, etc) work. + +The metaclass API is a set of classes that describe classes, roles, +attributes, etc. The metaclass API lets you ask questions about a +class, like "what attributes does it have?", or "what roles does the +class do?" + +The metaclass system also lets you make changes to a class, for +example by adding new methods or attributes. + +The interface presented by L<Moose.pm|Moose> (C<has>, C<with>, +C<extends>) is just a thin layer of syntactic sugar over the +underlying metaclass system. + +By extending and changing how this metaclass system works, you can +create your own Moose variant. + +=head2 Examples + +Let's say that you want to add additional properties to +attributes. Specifically, we want to add a "label" property to each +attribute, so we can write C<< +My::Class->meta()->get_attribute('size')->label() >>. The first +recipe shows how to do this using an attribute trait. + +You might also want to add additional properties to your +metaclass. For example, if you were writing an ORM based on Moose, you +could associate a table name with each class via the class's metaclass +object, letting you write C<< My::Class->meta()->table_name() >>. + +=head1 SEE ALSO + +Many of the MooseX modules on CPAN implement metaclass extensions. A +couple good examples include L<MooseX::Aliases> and +L<MooseX::UndefTolerant>. For a more complex example see +L<Fey::ORM> or L<Bread::Board::Declare>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Roles/ApplicationToInstance.pod b/lib/Moose/Cookbook/Roles/ApplicationToInstance.pod new file mode 100644 index 0000000..8a1d07b --- /dev/null +++ b/lib/Moose/Cookbook/Roles/ApplicationToInstance.pod @@ -0,0 +1,191 @@ +# PODNAME: Moose::Cookbook::Roles::ApplicationToInstance +# ABSTRACT: Applying a role to an object instance + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Roles::ApplicationToInstance - Applying a role to an object instance + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Role::Job::Manager; + + use List::Util qw( first ); + + use Moose::Role; + + has 'employees' => ( + is => 'rw', + isa => 'ArrayRef[Employee]', + ); + + sub assign_work { + my $self = shift; + my $work = shift; + + my $employee = first { !$_->has_work } @{ $self->employees }; + + die 'All my employees have work to do!' unless $employee; + + $employee->work($work); + } + + package main; + + my $lisa = Employee->new( name => 'Lisa' ); + MyApp::Role::Job::Manager->meta->apply($lisa); + + my $homer = Employee->new( name => 'Homer' ); + my $bart = Employee->new( name => 'Bart' ); + my $marge = Employee->new( name => 'Marge' ); + + $lisa->employees( [ $homer, $bart, $marge ] ); + $lisa->assign_work('mow the lawn'); + +=head1 DESCRIPTION + +In this recipe, we show how a role can be applied to an object. In +this specific case, we are giving an employee managerial +responsibilities. + +Applying a role to an object is simple. The L<Moose::Meta::Role> +object provides an C<apply> method. This method will do the right +thing when given an object instance. + + MyApp::Role::Job::Manager->meta->apply($lisa); + +We could also use the C<apply_all_roles> function from L<Moose::Util>. + + apply_all_roles( $person, MyApp::Role::Job::Manager->meta ); + +The main advantage of using C<apply_all_roles> is that it can be used +to apply more than one role at a time. + +We could also pass parameters to the role we're applying: + + MyApp::Role::Job::Manager->meta->apply( + $lisa, + -alias => { assign_work => 'get_off_your_lazy_behind' }, + ); + +We saw examples of how method exclusion and alias working in +L<Moose::Cookbook::Roles::Restartable_AdvancedComposition>. + +=begin testing-SETUP + +{ + # Not in the recipe, but needed for writing tests. + package Employee; + + use Moose; + + has 'name' => ( + is => 'ro', + isa => 'Str', + required => 1, + ); + + has 'work' => ( + is => 'rw', + isa => 'Str', + predicate => 'has_work', + ); +} + +=end testing-SETUP + +=head1 CONCLUSION + +Applying a role to an object instance is a useful tool for adding +behavior to existing objects. In our example, it is effective used to +model a promotion. + +It can also be useful as a sort of controlled monkey-patching for +existing code, particularly non-Moose code. For example, you could +create a debugging role and apply it to an object at runtime. + +=begin testing + +{ + my $lisa = Employee->new( name => 'Lisa' ); + MyApp::Role::Job::Manager->meta->apply($lisa); + + my $homer = Employee->new( name => 'Homer' ); + my $bart = Employee->new( name => 'Bart' ); + my $marge = Employee->new( name => 'Marge' ); + + $lisa->employees( [ $homer, $bart, $marge ] ); + $lisa->assign_work('mow the lawn'); + + ok( $lisa->does('MyApp::Role::Job::Manager'), + 'lisa now does the manager role' ); + + is( $homer->work, 'mow the lawn', + 'homer was assigned a task by lisa' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Roles/Comparable_CodeReuse.pod b/lib/Moose/Cookbook/Roles/Comparable_CodeReuse.pod new file mode 100644 index 0000000..2c59dcf --- /dev/null +++ b/lib/Moose/Cookbook/Roles/Comparable_CodeReuse.pod @@ -0,0 +1,379 @@ +# PODNAME: Moose::Cookbook::Roles::Comparable_CodeReuse +# ABSTRACT: Using roles for code reuse + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Roles::Comparable_CodeReuse - Using roles for code reuse + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Eq; + use Moose::Role; + + requires 'equal_to'; + + sub not_equal_to { + my ( $self, $other ) = @_; + not $self->equal_to($other); + } + + package Comparable; + use Moose::Role; + + with 'Eq'; + + requires 'compare'; + + sub equal_to { + my ( $self, $other ) = @_; + $self->compare($other) == 0; + } + + sub greater_than { + my ( $self, $other ) = @_; + $self->compare($other) == 1; + } + + sub less_than { + my ( $self, $other ) = @_; + $self->compare($other) == -1; + } + + sub greater_than_or_equal_to { + my ( $self, $other ) = @_; + $self->greater_than($other) || $self->equal_to($other); + } + + sub less_than_or_equal_to { + my ( $self, $other ) = @_; + $self->less_than($other) || $self->equal_to($other); + } + + package Printable; + use Moose::Role; + + requires 'to_string'; + + package US::Currency; + use Moose; + + with 'Comparable', 'Printable'; + + has 'amount' => ( is => 'rw', isa => 'Num', default => 0 ); + + sub compare { + my ( $self, $other ) = @_; + $self->amount <=> $other->amount; + } + + sub to_string { + my $self = shift; + sprintf '$%0.2f USD' => $self->amount; + } + +=head1 DESCRIPTION + +Roles have two primary purposes: as interfaces, and as a means of code +reuse. This recipe demonstrates the latter, with roles that define +comparison and display code for objects. + +Let's start with C<Eq>. First, note that we've replaced C<use Moose> +with C<use Moose::Role>. We also have a new sugar function, C<requires>: + + requires 'equal_to'; + +This says that any class which consumes this role must provide an +C<equal_to> method. It can provide this method directly, or by +consuming some other role. + +The C<Eq> role defines its C<not_equal_to> method in terms of the +required C<equal_to> method. This lets us minimize the methods that +consuming classes must provide. + +The next role, C<Comparable>, builds on the C<Eq> role. We include +C<Eq> in C<Comparable> using C<with>, another new sugar function: + + with 'Eq'; + +The C<with> function takes a list of roles to consume. In our example, +the C<Comparable> role provides the C<equal_to> method required by +C<Eq>. However, it could opt not to, in which case a class that +consumed C<Comparable> would have to provide its own C<equal_to>. In +other words, a role can consume another role I<without> providing any +required methods. + +The C<Comparable> role requires a method, C<compare>: + + requires 'compare'; + +The C<Comparable> role also provides a number of other methods, all of +which ultimately rely on C<compare>. + + sub equal_to { + my ( $self, $other ) = @_; + $self->compare($other) == 0; + } + + sub greater_than { + my ( $self, $other ) = @_; + $self->compare($other) == 1; + } + + sub less_than { + my ( $self, $other ) = @_; + $self->compare($other) == -1; + } + + sub greater_than_or_equal_to { + my ( $self, $other ) = @_; + $self->greater_than($other) || $self->equal_to($other); + } + + sub less_than_or_equal_to { + my ( $self, $other ) = @_; + $self->less_than($other) || $self->equal_to($other); + } + +Finally, we define the C<Printable> role. This role exists solely to +provide an interface. It has no methods, just a list of required methods. +In this case, it just requires a C<to_string> method. + +An interface role is useful because it defines both a method and a +I<name>. We know that any class which does this role has a +C<to_string> method, but we can also assume that this method has the +semantics we want. Presumably, in real code we would define those +semantics in the documentation for the C<Printable> role. (1) + +Finally, we have the C<US::Currency> class which consumes both the +C<Comparable> and C<Printable> roles. + + with 'Comparable', 'Printable'; + +It also defines a regular Moose attribute, C<amount>: + + has 'amount' => ( is => 'rw', isa => 'Num', default => 0 ); + +Finally we see the implementation of the methods required by our +roles. We have a C<compare> method: + + sub compare { + my ( $self, $other ) = @_; + $self->amount <=> $other->amount; + } + +By consuming the C<Comparable> role and defining this method, we gain +the following methods for free: C<equal_to>, C<greater_than>, +C<less_than>, C<greater_than_or_equal_to> and +C<less_than_or_equal_to>. + +Then we have our C<to_string> method: + + sub to_string { + my $self = shift; + sprintf '$%0.2f USD' => $self->amount; + } + +=head1 CONCLUSION + +Roles can be very powerful. They are a great way of encapsulating +reusable behavior, as well as communicating (semantic and interface) +information about the methods our classes provide. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +Consider two classes, C<Runner> and C<Process>, both of which define a +C<run> method. If we just require that an object implements a C<run> +method, we still aren't saying anything about what that method +I<actually does>. If we require an object that implements the +C<Executable> role, we're saying something about semantics. + +=back + +=begin testing + +ok( US::Currency->does('Comparable'), '... US::Currency does Comparable' ); +ok( US::Currency->does('Eq'), '... US::Currency does Eq' ); +ok( US::Currency->does('Printable'), '... US::Currency does Printable' ); + +my $hundred = US::Currency->new( amount => 100.00 ); +isa_ok( $hundred, 'US::Currency' ); + +ok( $hundred->DOES("US::Currency"), "UNIVERSAL::DOES for class" ); +ok( $hundred->DOES("Comparable"), "UNIVERSAL::DOES for role" ); + +can_ok( $hundred, 'amount' ); +is( $hundred->amount, 100, '... got the right amount' ); + +can_ok( $hundred, 'to_string' ); +is( $hundred->to_string, '$100.00 USD', + '... got the right stringified value' ); + +ok( $hundred->does('Comparable'), '... US::Currency does Comparable' ); +ok( $hundred->does('Eq'), '... US::Currency does Eq' ); +ok( $hundred->does('Printable'), '... US::Currency does Printable' ); + +my $fifty = US::Currency->new( amount => 50.00 ); +isa_ok( $fifty, 'US::Currency' ); + +can_ok( $fifty, 'amount' ); +is( $fifty->amount, 50, '... got the right amount' ); + +can_ok( $fifty, 'to_string' ); +is( $fifty->to_string, '$50.00 USD', '... got the right stringified value' ); + +ok( $hundred->greater_than($fifty), '... 100 gt 50' ); +ok( $hundred->greater_than_or_equal_to($fifty), '... 100 ge 50' ); +ok( !$hundred->less_than($fifty), '... !100 lt 50' ); +ok( !$hundred->less_than_or_equal_to($fifty), '... !100 le 50' ); +ok( !$hundred->equal_to($fifty), '... !100 eq 50' ); +ok( $hundred->not_equal_to($fifty), '... 100 ne 50' ); + +ok( !$fifty->greater_than($hundred), '... !50 gt 100' ); +ok( !$fifty->greater_than_or_equal_to($hundred), '... !50 ge 100' ); +ok( $fifty->less_than($hundred), '... 50 lt 100' ); +ok( $fifty->less_than_or_equal_to($hundred), '... 50 le 100' ); +ok( !$fifty->equal_to($hundred), '... !50 eq 100' ); +ok( $fifty->not_equal_to($hundred), '... 50 ne 100' ); + +ok( !$fifty->greater_than($fifty), '... !50 gt 50' ); +ok( $fifty->greater_than_or_equal_to($fifty), '... !50 ge 50' ); +ok( !$fifty->less_than($fifty), '... 50 lt 50' ); +ok( $fifty->less_than_or_equal_to($fifty), '... 50 le 50' ); +ok( $fifty->equal_to($fifty), '... 50 eq 50' ); +ok( !$fifty->not_equal_to($fifty), '... !50 ne 50' ); + +## ... check some meta-stuff + +# Eq + +my $eq_meta = Eq->meta; +isa_ok( $eq_meta, 'Moose::Meta::Role' ); + +ok( $eq_meta->has_method('not_equal_to'), '... Eq has_method not_equal_to' ); +ok( $eq_meta->requires_method('equal_to'), + '... Eq requires_method not_equal_to' ); + +# Comparable + +my $comparable_meta = Comparable->meta; +isa_ok( $comparable_meta, 'Moose::Meta::Role' ); + +ok( $comparable_meta->does_role('Eq'), '... Comparable does Eq' ); + +foreach my $method_name ( + qw( + equal_to not_equal_to + greater_than greater_than_or_equal_to + less_than less_than_or_equal_to + ) + ) { + ok( $comparable_meta->has_method($method_name), + '... Comparable has_method ' . $method_name ); +} + +ok( $comparable_meta->requires_method('compare'), + '... Comparable requires_method compare' ); + +# Printable + +my $printable_meta = Printable->meta; +isa_ok( $printable_meta, 'Moose::Meta::Role' ); + +ok( $printable_meta->requires_method('to_string'), + '... Printable requires_method to_string' ); + +# US::Currency + +my $currency_meta = US::Currency->meta; +isa_ok( $currency_meta, 'Moose::Meta::Class' ); + +ok( $currency_meta->does_role('Comparable'), + '... US::Currency does Comparable' ); +ok( $currency_meta->does_role('Eq'), '... US::Currency does Eq' ); +ok( $currency_meta->does_role('Printable'), + '... US::Currency does Printable' ); + +foreach my $method_name ( + qw( + amount + equal_to not_equal_to + compare + greater_than greater_than_or_equal_to + less_than less_than_or_equal_to + to_string + ) + ) { + ok( $currency_meta->has_method($method_name), + '... US::Currency has_method ' . $method_name ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Roles/Restartable_AdvancedComposition.pod b/lib/Moose/Cookbook/Roles/Restartable_AdvancedComposition.pod new file mode 100644 index 0000000..53069a2 --- /dev/null +++ b/lib/Moose/Cookbook/Roles/Restartable_AdvancedComposition.pod @@ -0,0 +1,230 @@ +# PODNAME: Moose::Cookbook::Roles::Restartable_AdvancedComposition +# ABSTRACT: Advanced Role Composition - method exclusion and aliasing + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Roles::Restartable_AdvancedComposition - Advanced Role Composition - method exclusion and aliasing + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Restartable; + use Moose::Role; + + has 'is_paused' => ( + is => 'rw', + isa => 'Bool', + default => 0, + ); + + requires 'save_state', 'load_state'; + + sub stop { 1 } + + sub start { 1 } + + package Restartable::ButUnreliable; + use Moose::Role; + + with 'Restartable' => { + -alias => { + stop => '_stop', + start => '_start' + }, + -excludes => [ 'stop', 'start' ], + }; + + sub stop { + my $self = shift; + + $self->explode() if rand(1) > .5; + + $self->_stop(); + } + + sub start { + my $self = shift; + + $self->explode() if rand(1) > .5; + + $self->_start(); + } + + package Restartable::ButBroken; + use Moose::Role; + + with 'Restartable' => { -excludes => [ 'stop', 'start' ] }; + + sub stop { + my $self = shift; + + $self->explode(); + } + + sub start { + my $self = shift; + + $self->explode(); + } + +=head1 DESCRIPTION + +In this example, we demonstrate how to exercise fine-grained control +over what methods we consume from a role. We have a C<Restartable> +role which provides an C<is_paused> attribute, and two methods, +C<stop> and C<start>. + +Then we have two more roles which implement the same interface, each +putting their own spin on the C<stop> and C<start> methods. + +In the C<Restartable::ButUnreliable> role, we want to provide a new +implementation of C<stop> and C<start>, but still have access to the +original implementation. To do this, we alias the methods from +C<Restartable> to private methods, and provide wrappers around the +originals (1). + +Note that aliasing simply I<adds> a name, so we also need to exclude the +methods with their original names. + + with 'Restartable' => { + -alias => { + stop => '_stop', + start => '_start' + }, + -excludes => [ 'stop', 'start' ], + }; + +In the C<Restartable::ButBroken> role, we want to provide an entirely +new behavior for C<stop> and C<start>. We exclude them entirely when +composing the C<Restartable> role into C<Restartable::ButBroken>. + +It's worth noting that the C<-excludes> parameter also accepts a single +string as an argument if you just want to exclude one method. + + with 'Restartable' => { -excludes => [ 'stop', 'start' ] }; + +=head1 CONCLUSION + +Exclusion and renaming are a power tool that can be handy, especially +when building roles out of other roles. In this example, all of our +roles implement the C<Restartable> role. Each role provides same API, +but each has a different implementation under the hood. + +You can also use the method aliasing and excluding features when +composing a role into a class. + +=head1 FOOTNOTES + +=over 4 + +=item (1) + +The mention of wrapper should tell you that we could do the same thing +using method modifiers, but for the sake of this example, we don't. + +=back + +=begin testing + +{ + my $unreliable = Moose::Meta::Class->create_anon_class( + superclasses => [], + roles => [qw/Restartable::ButUnreliable/], + methods => { + explode => sub { }, # nop. + 'save_state' => sub { }, + 'load_state' => sub { }, + }, + )->new_object(); + ok( $unreliable, 'made anon class with Restartable::ButUnreliable role' ); + can_ok( $unreliable, qw/start stop/ ); +} + +{ + my $cnt = 0; + my $broken = Moose::Meta::Class->create_anon_class( + superclasses => [], + roles => [qw/Restartable::ButBroken/], + methods => { + explode => sub { $cnt++ }, + 'save_state' => sub { }, + 'load_state' => sub { }, + }, + )->new_object(); + + ok( $broken, 'made anon class with Restartable::ButBroken role' ); + + $broken->start(); + + is( $cnt, 1, '... start called explode' ); + + $broken->stop(); + + is( $cnt, 2, '... stop also called explode' ); +} + +=end testing + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Snack/Keywords.pod b/lib/Moose/Cookbook/Snack/Keywords.pod new file mode 100644 index 0000000..a79cc57 --- /dev/null +++ b/lib/Moose/Cookbook/Snack/Keywords.pod @@ -0,0 +1,240 @@ +# PODNAME: Moose::Cookbook::Snack::Keywords +# ABSTRACT: Restricted "keywords" in Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Snack::Keywords - Restricted "keywords" in Moose + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +Moose exports a number of sugar functions in order to emulate Perl +built-in keywords. These can cause clashes with other user-defined +functions. This document provides a list of those keywords for easy +reference. + +=head2 The 'meta' keyword + +C<S<use Moose>> adds a method called C<meta> to your class. If this +conflicts with a method or function you are using, you can rename it, +or prevent it from being installed entirely. To do this, pass the +C<-meta_name> option when you C<S<use Moose>>. For instance: + + # install it under a different name + use Moose -meta_name => 'moose_meta'; + + # don't install it at all + use Moose -meta_name => undef; + +=head2 Moose Keywords + +If you are using L<Moose> or L<Moose::Role> it is best to avoid these +keywords: + +=over 4 + +=item extends + +=item with + +=item has + +=item before + +=item after + +=item around + +=item super + +=item override + +=item inner + +=item augment + +=item confess + +=item blessed + +=item meta + +=back + +=head2 Moose::Util::TypeConstraints Keywords + +If you are using L<Moose::Util::TypeConstraints> it is best to avoid +these keywords: + +=over 4 + +=item type + +=item subtype + +=item class_type + +=item role_type + +=item maybe_type + +=item duck_type + +=item as + +=item where + +=item message + +=item inline_as + +=item coerce + +=item from + +=item via + +=item enum + +=item find_type_constraint + +=item register_type_constraint + +=back + +=head2 Avoiding collisions + +=head3 Turning off Moose + +To remove the sugar functions L<Moose> exports, just add C<S<no Moose>> +at the bottom of your code: + + package Thing; + use Moose; + + # code here + + no Moose; + +This will unexport the sugar functions that L<Moose> originally +exported. The same will also work for L<Moose::Role> and +L<Moose::Util::TypeConstraints>. + +=head3 Sub::Exporter features + +L<Moose>, L<Moose::Role> and L<Moose::Util::TypeConstraints> all use +L<Sub::Exporter> to handle all their exporting needs. This means that +all the features that L<Sub::Exporter> provides are also available to +them. + +For instance, with L<Sub::Exporter> you can rename keywords, like so: + + package LOL::Cat; + use Moose 'has' => { -as => 'i_can_haz' }; + + i_can_haz 'cheeseburger' => ( + is => 'rw', + trigger => sub { print "NOM NOM" } + ); + + LOL::Cat->new->cheeseburger('KTHNXBYE'); + +See the L<Sub::Exporter> docs for more information. + +=head3 namespace::autoclean and namespace::clean + +You can also use L<namespace::autoclean> to clean up your namespace. +This will remove all imported functions from your namespace. Note +that if you are importing functions that are intended to be used as +methods (this includes L<overload>, due to internal implementation +details), it will remove these as well. + +Another option is to use L<namespace::clean> directly, but +you must be careful not to remove C<meta> when doing so: + + package Foo; + use Moose; + use namespace::clean -except => 'meta'; + # ... + +=head1 SEE ALSO + +=over 4 + +=item L<Moose> + +=item L<Moose::Role> + +=item L<Moose::Util::TypeConstraints> + +=item L<Sub::Exporter> + +=item L<namespace::autoclean> + +=item L<namespace::clean> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Snack/Types.pod b/lib/Moose/Cookbook/Snack/Types.pod new file mode 100644 index 0000000..44f9b5b --- /dev/null +++ b/lib/Moose/Cookbook/Snack/Types.pod @@ -0,0 +1,130 @@ +# PODNAME: Moose::Cookbook::Snack::Types +# ABSTRACT: Snippets of code for using Types and Type Constraints + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Snack::Types - Snippets of code for using Types and Type Constraints + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Point; + use Moose; + + has 'x' => ( isa => 'Int', is => 'ro' ); + has 'y' => ( isa => 'Int', is => 'rw' ); + + package main; + use Try::Tiny; + + my $point = try { + Point->new( x => 'fifty', y => 'forty' ); + } + catch { + print "Oops: $_"; + }; + + my $point; + my $xval = 'forty-two'; + my $xattribute = Point->meta->find_attribute_by_name('x'); + my $xtype_constraint = $xattribute->type_constraint; + + if ( $xtype_constraint->check($xval) ) { + $point = Point->new( x => $xval, y => 0 ); + } + else { + print "Value: $xval is not an " . $xtype_constraint->name . "\n"; + } + +=head1 DESCRIPTION + +This is the Point example from +L<Moose::Cookbook::Basics::Point_AttributesAndSubclassing> with type checking +added. + +If we try to assign a string value to an attribute that is an C<Int>, +Moose will die with an explicit error message. The error will include +the attribute name, as well as the type constraint name and the value +which failed the constraint check. + +We use L<Try::Tiny> to catch this error message. + +Later, we get the L<Moose::Meta::TypeConstraint> object from a +L<Moose::Meta::Attribute> and use the L<Moose::Meta::TypeConstraint> +to check a value directly. + +=head1 SEE ALSO + +=over 4 + +=item L<Moose::Cookbook::Basics::Point_AttributesAndSubclassing> + +=item L<Moose::Util::TypeConstraints> + +=item L<Moose::Meta::Attribute> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Cookbook/Style.pod b/lib/Moose/Cookbook/Style.pod new file mode 100644 index 0000000..be9334b --- /dev/null +++ b/lib/Moose/Cookbook/Style.pod @@ -0,0 +1,77 @@ +# PODNAME: Moose::Cookbook::Style +# ABSTRACT: Expanded into Moose::Manual::BestPractices, so go read that + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Cookbook::Style - Expanded into Moose::Manual::BestPractices, so go read that + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +The style cookbook has been replaced by +L<Moose::Manual::BestPractices>. This POD document still exists for +the benefit of anyone out there who might've linked to it in the past. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Deprecated.pm b/lib/Moose/Deprecated.pm new file mode 100644 index 0000000..cc7e2c0 --- /dev/null +++ b/lib/Moose/Deprecated.pm @@ -0,0 +1,98 @@ +package Moose::Deprecated; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Package::DeprecationManager 0.07 -deprecations => { + 'non-arrayref form of enum' => '2.1100', + 'non-arrayref form of duck_type' => '2.1100', + }, + -ignore => [qr/^(?:Class::MOP|Moose)(?:::)?/], + ; + +1; + +# ABSTRACT: Manages deprecation warnings for Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Deprecated - Manages deprecation warnings for Moose + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + + use Moose::Deprecated -api_version => $version; + +=head1 FUNCTIONS + +This module manages deprecation warnings for features that have been +deprecated in Moose. + +If you specify C<< -api_version => $version >>, you can use deprecated features +without warnings. Note that this special treatment is limited to the package +that loads C<Moose::Deprecated>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Exception.pm b/lib/Moose/Exception.pm new file mode 100644 index 0000000..b52c9d8 --- /dev/null +++ b/lib/Moose/Exception.pm @@ -0,0 +1,206 @@ +package Moose::Exception; +our $VERSION = '2.1405'; + +use Moose; +use Devel::StackTrace 1.33; + +has 'trace' => ( + is => 'ro', + isa => 'Devel::StackTrace', + builder => '_build_trace', + lazy => 1, + documentation => "This attribute is read-only and isa L<Devel::StackTrace>. ". + 'It is lazy & dependent on $exception->message.' +); + +has 'message' => ( + is => 'ro', + isa => 'Str', + builder => '_build_message', + lazy => 1, + documentation => "This attribute is read-only and isa Str. ". + "It is lazy and has a default value 'Error'." +); + +use overload( + q{""} => 'as_string', + fallback => 1, +); + +sub _build_trace { + my $self = shift; + + # skip frames that are method calls on the exception object, which include + # the object itself in the arguments (but Devel::LeakTrace really ought to + # be weakening all references in its frames) + my $skip = 0; + while (my @c = caller(++$skip)) { + last if $c[3] =~ /^(.*)::new$/ && $self->isa($1); + } + $skip++; + + Devel::StackTrace->new( + message => $self->message, + indent => 1, + skip_frames => $skip, + no_refs => 1, + ); +} + +sub _build_message { + "Error"; +} + +sub BUILD { + my $self = shift; + $self->trace; +} + +sub as_string { + my $self = shift; + + if ( $ENV{MOOSE_FULL_EXCEPTION} ) { + return $self->trace->as_string; + } + + my @frames; + my $last_frame; + my $in_moose = 1; + for my $frame ( $self->trace->frames ) { + if ( $in_moose && $frame->package =~ /^(?:Moose|Class::MOP)(?::|$)/ ) + { + $last_frame = $frame; + next; + } + elsif ($last_frame) { + push @frames, $last_frame; + undef $last_frame; + } + + $in_moose = 0; + push @frames, $frame; + } + + # This would be a somewhat pathological case, but who knows + return $self->trace->as_string unless @frames; + + my $message = ( shift @frames )->as_string( 1, {} ) . "\n"; + $message .= join q{}, map { $_->as_string( 0, {} ) . "\n" } @frames; + + return $message; +} + +1; + +# ABSTRACT: Superclass for Moose internal exceptions + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Exception - Superclass for Moose internal exceptions + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class contains attributes which are common to all Moose internal +exception classes. + +=head1 WARNING WARNING WARNING + +If you're writing your own exception classes, you should instead prefer +the L<Throwable> role or the L<Throwable::Error> superclass - this is +effectively a cut-down internal fork of the latter, and not designed +for use in user code. + +Of course if you're writing metaclass traits, it would then make sense to +subclass the relevant Moose exceptions - but only then. + +=head1 METHODS + +This class provides the following methods: + +=head2 $exception->message + +This methods returns the exception message. + +=head2 $exception->trace + +This method returns the stack trace for the given exception. + +=head2 $exception->as_string + +This method returns a stringified form of the exception, including a stack +trace. By default, this method skips Moose-internal stack frames until it sees +a caller outside of the Moose core. If the C<MOOSE_FULL_EXCEPTION> environment +variable is true, these frames are included. + +=head1 SEE ALSO + +=over 4 + +=item * L<Moose::Manual::Exceptions> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Exception/AccessorMustReadWrite.pm b/lib/Moose/Exception/AccessorMustReadWrite.pm new file mode 100644 index 0000000..d33d928 --- /dev/null +++ b/lib/Moose/Exception/AccessorMustReadWrite.pm @@ -0,0 +1,13 @@ +package Moose::Exception::AccessorMustReadWrite; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "Cannot define an accessor name on a read-only attribute, accessors are read/write"; +} + +1; diff --git a/lib/Moose/Exception/AddParameterizableTypeTakesParameterizableType.pm b/lib/Moose/Exception/AddParameterizableTypeTakesParameterizableType.pm new file mode 100644 index 0000000..8bd52f8 --- /dev/null +++ b/lib/Moose/Exception/AddParameterizableTypeTakesParameterizableType.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AddParameterizableTypeTakesParameterizableType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'type_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Type must be a Moose::Meta::TypeConstraint::Parameterizable not ".$self->type_name; +} + +1; diff --git a/lib/Moose/Exception/AddRoleTakesAMooseMetaRoleInstance.pm b/lib/Moose/Exception/AddRoleTakesAMooseMetaRoleInstance.pm new file mode 100644 index 0000000..b3ca1f3 --- /dev/null +++ b/lib/Moose/Exception/AddRoleTakesAMooseMetaRoleInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AddRoleTakesAMooseMetaRoleInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'role_to_be_added' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + "Roles must be instances of Moose::Meta::Role"; +} + +1; diff --git a/lib/Moose/Exception/AddRoleToARoleTakesAMooseMetaRole.pm b/lib/Moose/Exception/AddRoleToARoleTakesAMooseMetaRole.pm new file mode 100644 index 0000000..98a72ab --- /dev/null +++ b/lib/Moose/Exception/AddRoleToARoleTakesAMooseMetaRole.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AddRoleToARoleTakesAMooseMetaRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'role_to_be_added' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + "Roles must be instances of Moose::Meta::Role"; +} + +1; diff --git a/lib/Moose/Exception/ApplyTakesABlessedInstance.pm b/lib/Moose/Exception/ApplyTakesABlessedInstance.pm new file mode 100644 index 0000000..fa65f79 --- /dev/null +++ b/lib/Moose/Exception/ApplyTakesABlessedInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::ApplyTakesABlessedInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'param' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + "You must pass in an blessed instance"; +} + +1; diff --git a/lib/Moose/Exception/AttachToClassNeedsAClassMOPClassInstanceOrASubclass.pm b/lib/Moose/Exception/AttachToClassNeedsAClassMOPClassInstanceOrASubclass.pm new file mode 100644 index 0000000..f944577 --- /dev/null +++ b/lib/Moose/Exception/AttachToClassNeedsAClassMOPClassInstanceOrASubclass.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AttachToClassNeedsAClassMOPClassInstanceOrASubclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'class' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "You must pass a Class::MOP::Class instance (or a subclass)"; +} + +1; diff --git a/lib/Moose/Exception/AttributeConflictInRoles.pm b/lib/Moose/Exception/AttributeConflictInRoles.pm new file mode 100644 index 0000000..00d7b56 --- /dev/null +++ b/lib/Moose/Exception/AttributeConflictInRoles.pm @@ -0,0 +1,31 @@ +package Moose::Exception::AttributeConflictInRoles; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'second_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $role_name = $self->role_name; + my $second_role_name = $self->second_role_name; + my $attribute_name = $self->attribute_name; + "Role '$role_name' has encountered an attribute conflict" + . " while being composed into '$second_role_name'." + . " This is a fatal error and cannot be disambiguated." + . " The conflicting attribute is named '$attribute_name'."; +} + +1; diff --git a/lib/Moose/Exception/AttributeConflictInSummation.pm b/lib/Moose/Exception/AttributeConflictInSummation.pm new file mode 100644 index 0000000..81ba5b7 --- /dev/null +++ b/lib/Moose/Exception/AttributeConflictInSummation.pm @@ -0,0 +1,27 @@ +package Moose::Exception::AttributeConflictInSummation; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role', 'Moose::Exception::Role::AttributeName'; + +has 'second_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + + my $role1 = $self->role_name; + my $role2 = $self->second_role_name; + my $attr_name = $self->attribute_name; + + return "We have encountered an attribute conflict with '$attr_name'" + . " during role composition. " + . " This attribute is defined in both $role1 and $role2." + . " This is a fatal error and cannot be disambiguated."; +} + +1; diff --git a/lib/Moose/Exception/AttributeExtensionIsNotSupportedInRoles.pm b/lib/Moose/Exception/AttributeExtensionIsNotSupportedInRoles.pm new file mode 100644 index 0000000..8face5c --- /dev/null +++ b/lib/Moose/Exception/AttributeExtensionIsNotSupportedInRoles.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AttributeExtensionIsNotSupportedInRoles; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + "has '+attr' is not supported in roles"; +} + +1; diff --git a/lib/Moose/Exception/AttributeIsRequired.pm b/lib/Moose/Exception/AttributeIsRequired.pm new file mode 100644 index 0000000..fa852dd --- /dev/null +++ b/lib/Moose/Exception/AttributeIsRequired.pm @@ -0,0 +1,28 @@ +package Moose::Exception::AttributeIsRequired; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching attribute instance:\n". + " my \$class = Moose::Util::find_meta( \$exception->class_name );\n". + " my \$attribute = \$class->get_attribute( \$exception->attribute_name );\n", +); + +has 'params' => ( + is => 'ro', + isa => 'HashRef', + predicate => 'has_params', +); + +sub _build_message { + my $self = shift; + "Attribute (".$self->attribute_name.") is required"; +} + +1; diff --git a/lib/Moose/Exception/AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass.pm b/lib/Moose/Exception/AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass.pm new file mode 100644 index 0000000..8f89d97 --- /dev/null +++ b/lib/Moose/Exception/AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass.pm @@ -0,0 +1,18 @@ +package Moose::Exception::AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'attribute' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "Your attribute must be an instance of Class::MOP::Mixin::AttributeCore (or a subclass)"; +} + +1; diff --git a/lib/Moose/Exception/AttributeNamesDoNotMatch.pm b/lib/Moose/Exception/AttributeNamesDoNotMatch.pm new file mode 100644 index 0000000..4510eed --- /dev/null +++ b/lib/Moose/Exception/AttributeNamesDoNotMatch.pm @@ -0,0 +1,24 @@ +package Moose::Exception::AttributeNamesDoNotMatch; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has attribute_name => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +has attribute => ( + is => 'ro', + isa => 'Class::MOP::Attribute', + required => 1, +); + +sub _build_message { + my $self = shift; + "attribute_name (".$self-> attribute_name.") does not match attribute->name (".$self->attribute->name.")"; +} + +1; diff --git a/lib/Moose/Exception/AttributeValueIsNotAnObject.pm b/lib/Moose/Exception/AttributeValueIsNotAnObject.pm new file mode 100644 index 0000000..523a4a9 --- /dev/null +++ b/lib/Moose/Exception/AttributeValueIsNotAnObject.pm @@ -0,0 +1,27 @@ +package Moose::Exception::AttributeValueIsNotAnObject; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::Attribute'; + +has 'method' => ( + is => 'ro', + isa => 'Moose::Meta::Method::Delegation', + required => 1, +); + +has 'given_value' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + my $self = shift; + "Cannot delegate ".$self->method->name." to " + .$self->method->delegate_to_method." because the value of " + . $self->attribute->name . " is not an object (got '".$self->given_value."')"; +} + +1; diff --git a/lib/Moose/Exception/AttributeValueIsNotDefined.pm b/lib/Moose/Exception/AttributeValueIsNotDefined.pm new file mode 100644 index 0000000..95555a6 --- /dev/null +++ b/lib/Moose/Exception/AttributeValueIsNotDefined.pm @@ -0,0 +1,21 @@ +package Moose::Exception::AttributeValueIsNotDefined; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::Attribute'; + +has 'method' => ( + is => 'ro', + isa => 'Moose::Meta::Method::Delegation', + required => 1, +); + +sub _build_message { + my $self = shift; + "Cannot delegate ".$self->method->name." to " + .$self->method->delegate_to_method." because the value of " + . $self->attribute->name . " is not defined"; +} + +1; diff --git a/lib/Moose/Exception/AutoDeRefNeedsArrayRefOrHashRef.pm b/lib/Moose/Exception/AutoDeRefNeedsArrayRefOrHashRef.pm new file mode 100644 index 0000000..ef32986 --- /dev/null +++ b/lib/Moose/Exception/AutoDeRefNeedsArrayRefOrHashRef.pm @@ -0,0 +1,13 @@ +package Moose::Exception::AutoDeRefNeedsArrayRefOrHashRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/BadOptionFormat.pm b/lib/Moose/Exception/BadOptionFormat.pm new file mode 100644 index 0000000..cccee33 --- /dev/null +++ b/lib/Moose/Exception/BadOptionFormat.pm @@ -0,0 +1,24 @@ +package Moose::Exception::BadOptionFormat; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'option_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'option_value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref"; +} + +1; diff --git a/lib/Moose/Exception/BothBuilderAndDefaultAreNotAllowed.pm b/lib/Moose/Exception/BothBuilderAndDefaultAreNotAllowed.pm new file mode 100644 index 0000000..022268d --- /dev/null +++ b/lib/Moose/Exception/BothBuilderAndDefaultAreNotAllowed.pm @@ -0,0 +1,18 @@ +package Moose::Exception::BothBuilderAndDefaultAreNotAllowed; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "Setting both default and builder is not allowed."; +} + +1; diff --git a/lib/Moose/Exception/BuilderDoesNotExist.pm b/lib/Moose/Exception/BuilderDoesNotExist.pm new file mode 100644 index 0000000..6629352 --- /dev/null +++ b/lib/Moose/Exception/BuilderDoesNotExist.pm @@ -0,0 +1,13 @@ +package Moose::Exception::BuilderDoesNotExist; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute', 'Moose::Exception::Role::Instance'; + +sub _build_message { + my $self = shift; + blessed($self->instance)." does not support builder method '".$self->attribute->builder."' for attribute '".$self->attribute->name."'"; +} + +1; diff --git a/lib/Moose/Exception/BuilderMethodNotSupportedForAttribute.pm b/lib/Moose/Exception/BuilderMethodNotSupportedForAttribute.pm new file mode 100644 index 0000000..648d50c --- /dev/null +++ b/lib/Moose/Exception/BuilderMethodNotSupportedForAttribute.pm @@ -0,0 +1,13 @@ +package Moose::Exception::BuilderMethodNotSupportedForAttribute; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute', 'Moose::Exception::Role::Instance'; + +sub _build_message { + my $self = shift; + blessed($self->instance)." does not support builder method '". $self->attribute->builder ."' for attribute '" . $self->attribute->name . "'"; +} + +1; diff --git a/lib/Moose/Exception/BuilderMethodNotSupportedForInlineAttribute.pm b/lib/Moose/Exception/BuilderMethodNotSupportedForInlineAttribute.pm new file mode 100644 index 0000000..9757e65 --- /dev/null +++ b/lib/Moose/Exception/BuilderMethodNotSupportedForInlineAttribute.pm @@ -0,0 +1,25 @@ +package Moose::Exception::BuilderMethodNotSupportedForInlineAttribute; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::Class'; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'builder' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + $self->class_name." does not support builder method '". $self->builder ."' for attribute '" . $self->attribute_name . "'"; +} + +1; diff --git a/lib/Moose/Exception/BuilderMustBeAMethodName.pm b/lib/Moose/Exception/BuilderMustBeAMethodName.pm new file mode 100644 index 0000000..967ba5f --- /dev/null +++ b/lib/Moose/Exception/BuilderMustBeAMethodName.pm @@ -0,0 +1,18 @@ +package Moose::Exception::BuilderMustBeAMethodName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "builder must be a defined scalar value which is a method name"; +} + +1; diff --git a/lib/Moose/Exception/CallingMethodOnAnImmutableInstance.pm b/lib/Moose/Exception/CallingMethodOnAnImmutableInstance.pm new file mode 100644 index 0000000..6ac2d37 --- /dev/null +++ b/lib/Moose/Exception/CallingMethodOnAnImmutableInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CallingMethodOnAnImmutableInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "The '".$self->method_name."' method cannot be called on an immutable instance"; +} + +1; diff --git a/lib/Moose/Exception/CallingReadOnlyMethodOnAnImmutableInstance.pm b/lib/Moose/Exception/CallingReadOnlyMethodOnAnImmutableInstance.pm new file mode 100644 index 0000000..e880935 --- /dev/null +++ b/lib/Moose/Exception/CallingReadOnlyMethodOnAnImmutableInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CallingReadOnlyMethodOnAnImmutableInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "The '".$self->method_name."' method is read-only when called on an immutable instance"; +} + +1; diff --git a/lib/Moose/Exception/CanExtendOnlyClasses.pm b/lib/Moose/Exception/CanExtendOnlyClasses.pm new file mode 100644 index 0000000..9519aed --- /dev/null +++ b/lib/Moose/Exception/CanExtendOnlyClasses.pm @@ -0,0 +1,14 @@ +package Moose::Exception::CanExtendOnlyClasses; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +sub _build_message { + my $self = shift; + my $role_name = $self->role_name; + return "You cannot inherit from a Moose Role ($role_name)"; +} + +1; diff --git a/lib/Moose/Exception/CanOnlyConsumeRole.pm b/lib/Moose/Exception/CanOnlyConsumeRole.pm new file mode 100644 index 0000000..3cc7288 --- /dev/null +++ b/lib/Moose/Exception/CanOnlyConsumeRole.pm @@ -0,0 +1,17 @@ +package Moose::Exception::CanOnlyConsumeRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'role_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "You can only consume roles, ".$self->role_name." is not a Moose role"; +} +1; diff --git a/lib/Moose/Exception/CanOnlyWrapBlessedCode.pm b/lib/Moose/Exception/CanOnlyWrapBlessedCode.pm new file mode 100644 index 0000000..997b39e --- /dev/null +++ b/lib/Moose/Exception/CanOnlyWrapBlessedCode.pm @@ -0,0 +1,24 @@ +package Moose::Exception::CanOnlyWrapBlessedCode; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'code' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "Can only wrap blessed CODE"; +} + +1; diff --git a/lib/Moose/Exception/CanReblessOnlyIntoASubclass.pm b/lib/Moose/Exception/CanReblessOnlyIntoASubclass.pm new file mode 100644 index 0000000..fbc216c --- /dev/null +++ b/lib/Moose/Exception/CanReblessOnlyIntoASubclass.pm @@ -0,0 +1,14 @@ +package Moose::Exception::CanReblessOnlyIntoASubclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::InstanceClass'; + +sub _build_message { + my $self = shift; + my $instance_class = $self->instance_class; + "You may rebless only into a subclass of ($instance_class), of which (". $self->class_name .") isn't." +} + +1; diff --git a/lib/Moose/Exception/CanReblessOnlyIntoASuperclass.pm b/lib/Moose/Exception/CanReblessOnlyIntoASuperclass.pm new file mode 100644 index 0000000..b164381 --- /dev/null +++ b/lib/Moose/Exception/CanReblessOnlyIntoASuperclass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CanReblessOnlyIntoASuperclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::InstanceClass'; + +sub _build_message { + my $self = shift; + "You may rebless only into a superclass of (".blessed( $self->instance )."), of which (". $self->class_name .") isn't." +} + +1; diff --git a/lib/Moose/Exception/CannotAddAdditionalTypeCoercionsToUnion.pm b/lib/Moose/Exception/CannotAddAdditionalTypeCoercionsToUnion.pm new file mode 100644 index 0000000..7edba0f --- /dev/null +++ b/lib/Moose/Exception/CannotAddAdditionalTypeCoercionsToUnion.pm @@ -0,0 +1,17 @@ +package Moose::Exception::CannotAddAdditionalTypeCoercionsToUnion; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'type_coercion_union_object' => ( + is => 'ro', + isa => 'Moose::Meta::TypeCoercion::Union', + required => 1 +); + +sub _build_message { + return "Cannot add additional type coercions to Union types"; +} + +1; diff --git a/lib/Moose/Exception/CannotAddAsAnAttributeToARole.pm b/lib/Moose/Exception/CannotAddAsAnAttributeToARole.pm new file mode 100644 index 0000000..960d56c --- /dev/null +++ b/lib/Moose/Exception/CannotAddAsAnAttributeToARole.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CannotAddAsAnAttributeToARole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'attribute_class' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "Cannot add a ".$self->attribute_class." as an attribute to a role"; +} + +1; diff --git a/lib/Moose/Exception/CannotApplyBaseClassRolesToRole.pm b/lib/Moose/Exception/CannotApplyBaseClassRolesToRole.pm new file mode 100644 index 0000000..d38630a --- /dev/null +++ b/lib/Moose/Exception/CannotApplyBaseClassRolesToRole.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CannotApplyBaseClassRolesToRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Role'; + +sub _build_message { + "You can only apply base class roles to a Moose class, not a role."; +} + +1; diff --git a/lib/Moose/Exception/CannotAssignValueToReadOnlyAccessor.pm b/lib/Moose/Exception/CannotAssignValueToReadOnlyAccessor.pm new file mode 100644 index 0000000..37195a8 --- /dev/null +++ b/lib/Moose/Exception/CannotAssignValueToReadOnlyAccessor.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CannotAssignValueToReadOnlyAccessor; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::EitherAttributeOrAttributeName'; + +has 'value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "Cannot assign a value to a read-only accessor"; +} + +1; diff --git a/lib/Moose/Exception/CannotAugmentIfLocalMethodPresent.pm b/lib/Moose/Exception/CannotAugmentIfLocalMethodPresent.pm new file mode 100644 index 0000000..6a3339e --- /dev/null +++ b/lib/Moose/Exception/CannotAugmentIfLocalMethodPresent.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CannotAugmentIfLocalMethodPresent; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Method'; + +sub _build_message { + "Cannot add an augment method if a local method is already present"; +} + +1; diff --git a/lib/Moose/Exception/CannotAugmentNoSuperMethod.pm b/lib/Moose/Exception/CannotAugmentNoSuperMethod.pm new file mode 100644 index 0000000..5f36249 --- /dev/null +++ b/lib/Moose/Exception/CannotAugmentNoSuperMethod.pm @@ -0,0 +1,25 @@ +package Moose::Exception::CannotAugmentNoSuperMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You cannot augment '".$self->method_name."' because it has no super method"; +} + +1; diff --git a/lib/Moose/Exception/CannotAutoDerefWithoutIsa.pm b/lib/Moose/Exception/CannotAutoDerefWithoutIsa.pm new file mode 100644 index 0000000..f0952bf --- /dev/null +++ b/lib/Moose/Exception/CannotAutoDerefWithoutIsa.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotAutoDerefWithoutIsa; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You cannot auto-dereference without specifying a type constraint on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/CannotAutoDereferenceTypeConstraint.pm b/lib/Moose/Exception/CannotAutoDereferenceTypeConstraint.pm new file mode 100644 index 0000000..3266ce4 --- /dev/null +++ b/lib/Moose/Exception/CannotAutoDereferenceTypeConstraint.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotAutoDereferenceTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute', 'Moose::Exception::Role::Instance', 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Can not auto de-reference the type constraint '" . $self->type_name . "'"; +} + +1; diff --git a/lib/Moose/Exception/CannotCalculateNativeType.pm b/lib/Moose/Exception/CannotCalculateNativeType.pm new file mode 100644 index 0000000..2593cb4 --- /dev/null +++ b/lib/Moose/Exception/CannotCalculateNativeType.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotCalculateNativeType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +sub _build_message { + my $self = shift; + "Cannot calculate native type for " . ref $self->instance; +} + +1; diff --git a/lib/Moose/Exception/CannotCallAnAbstractBaseMethod.pm b/lib/Moose/Exception/CannotCallAnAbstractBaseMethod.pm new file mode 100644 index 0000000..3204c4e --- /dev/null +++ b/lib/Moose/Exception/CannotCallAnAbstractBaseMethod.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CannotCallAnAbstractBaseMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'package_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + $self->package_name. " is an abstract base class, you must provide a constructor."; +} + +1; diff --git a/lib/Moose/Exception/CannotCallAnAbstractMethod.pm b/lib/Moose/Exception/CannotCallAnAbstractMethod.pm new file mode 100644 index 0000000..1d076ad --- /dev/null +++ b/lib/Moose/Exception/CannotCallAnAbstractMethod.pm @@ -0,0 +1,11 @@ +package Moose::Exception::CannotCallAnAbstractMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "Abstract method"; +} + +1; diff --git a/lib/Moose/Exception/CannotCoerceAWeakRef.pm b/lib/Moose/Exception/CannotCoerceAWeakRef.pm new file mode 100644 index 0000000..bb4a18b --- /dev/null +++ b/lib/Moose/Exception/CannotCoerceAWeakRef.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotCoerceAWeakRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You cannot have a weak reference to a coerced value on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/CannotCoerceAttributeWhichHasNoCoercion.pm b/lib/Moose/Exception/CannotCoerceAttributeWhichHasNoCoercion.pm new file mode 100644 index 0000000..aabec96 --- /dev/null +++ b/lib/Moose/Exception/CannotCoerceAttributeWhichHasNoCoercion.pm @@ -0,0 +1,16 @@ +package Moose::Exception::CannotCoerceAttributeWhichHasNoCoercion; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions', 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + my $name = $self->attribute_name; + my $type = $self->type_name; + + return "You cannot coerce an attribute ($name) unless its type ($type) has a coercion"; +} + +1; diff --git a/lib/Moose/Exception/CannotCreateHigherOrderTypeWithoutATypeParameter.pm b/lib/Moose/Exception/CannotCreateHigherOrderTypeWithoutATypeParameter.pm new file mode 100644 index 0000000..fc7257b --- /dev/null +++ b/lib/Moose/Exception/CannotCreateHigherOrderTypeWithoutATypeParameter.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CannotCreateHigherOrderTypeWithoutATypeParameter; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + "You cannot create a Higher Order type without a type parameter"; +} + +1; diff --git a/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresent.pm b/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresent.pm new file mode 100644 index 0000000..fd3c85d --- /dev/null +++ b/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresent.pm @@ -0,0 +1,24 @@ +package Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresent; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role', 'Moose::Exception::Role::Method'; + +has 'role_being_applied_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'aliased_method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "Cannot create a method alias if a local method of the same name exists"; +} + +1; diff --git a/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresentInClass.pm b/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresentInClass.pm new file mode 100644 index 0000000..df3d191 --- /dev/null +++ b/lib/Moose/Exception/CannotCreateMethodAliasLocalMethodIsPresentInClass.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresentInClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role', 'Moose::Exception::Role::Method', 'Moose::Exception::Role::Class'; + +has 'aliased_method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "Cannot create a method alias if a local method of the same name exists"; +} + +1; diff --git a/lib/Moose/Exception/CannotDelegateLocalMethodIsPresent.pm b/lib/Moose/Exception/CannotDelegateLocalMethodIsPresent.pm new file mode 100644 index 0000000..6232437 --- /dev/null +++ b/lib/Moose/Exception/CannotDelegateLocalMethodIsPresent.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotDelegateLocalMethodIsPresent; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute', 'Moose::Exception::Role::Method'; + +sub _build_message { + my $self = shift; + "You cannot overwrite a locally defined method (".$self->method->name.") with a delegation"; +} + +1; diff --git a/lib/Moose/Exception/CannotDelegateWithoutIsa.pm b/lib/Moose/Exception/CannotDelegateWithoutIsa.pm new file mode 100644 index 0000000..e7ac308 --- /dev/null +++ b/lib/Moose/Exception/CannotDelegateWithoutIsa.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CannotDelegateWithoutIsa; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +sub _build_message { + "Cannot delegate methods based on a Regexp without a type constraint (isa)"; +} + +1; diff --git a/lib/Moose/Exception/CannotFindDelegateMetaclass.pm b/lib/Moose/Exception/CannotFindDelegateMetaclass.pm new file mode 100644 index 0000000..5cbb744 --- /dev/null +++ b/lib/Moose/Exception/CannotFindDelegateMetaclass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotFindDelegateMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +sub _build_message { + my $self = shift; + "Cannot find delegate metaclass for attribute ".$self->attribute->name; +} + +1; diff --git a/lib/Moose/Exception/CannotFindType.pm b/lib/Moose/Exception/CannotFindType.pm new file mode 100644 index 0000000..d9a3d89 --- /dev/null +++ b/lib/Moose/Exception/CannotFindType.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CannotFindType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'type_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Cannot find type '".$self->type_name."', perhaps you forgot to load it"; +} + +1; diff --git a/lib/Moose/Exception/CannotFindTypeGivenToMatchOnType.pm b/lib/Moose/Exception/CannotFindTypeGivenToMatchOnType.pm new file mode 100644 index 0000000..147231f --- /dev/null +++ b/lib/Moose/Exception/CannotFindTypeGivenToMatchOnType.pm @@ -0,0 +1,32 @@ +package Moose::Exception::CannotFindTypeGivenToMatchOnType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'to_match' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'action' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'type' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + my $type = $self->type; + + return "Cannot find or parse the type '$type'" +} + +1; diff --git a/lib/Moose/Exception/CannotFixMetaclassCompatibility.pm b/lib/Moose/Exception/CannotFixMetaclassCompatibility.pm new file mode 100644 index 0000000..8367213 --- /dev/null +++ b/lib/Moose/Exception/CannotFixMetaclassCompatibility.pm @@ -0,0 +1,25 @@ +package Moose::Exception::CannotFixMetaclassCompatibility; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'superclass' => ( + is => 'ro', + isa => 'Object', + required => 1 +); + +has 'metaclass_type' => ( + is => 'ro', + isa => 'Str', +); + +sub _build_message { + my $self = shift; + my $class_name = $self->class_name; + "Can't fix metaclass incompatibility for $class_name because it is not pristine."; +} + +1; diff --git a/lib/Moose/Exception/CannotGenerateInlineConstraint.pm b/lib/Moose/Exception/CannotGenerateInlineConstraint.pm new file mode 100644 index 0000000..55e5a1e --- /dev/null +++ b/lib/Moose/Exception/CannotGenerateInlineConstraint.pm @@ -0,0 +1,29 @@ +package Moose::Exception::CannotGenerateInlineConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +has 'parameterizable_type_object_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching parameterizable type constraint(Moose::Meta::TypeConstraint::Parameterizable):\n". + " my \$type_constraint = Moose::Util::TypeConstraints::find_type_constraint( \$exception->type_name );\n", +); + +has 'value' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $type = $self->type_name; + + return "Can't generate an inline constraint for $type, since none was defined"; +} + +1; diff --git a/lib/Moose/Exception/CannotInitializeMooseMetaRoleComposite.pm b/lib/Moose/Exception/CannotInitializeMooseMetaRoleComposite.pm new file mode 100644 index 0000000..e1a0a4e --- /dev/null +++ b/lib/Moose/Exception/CannotInitializeMooseMetaRoleComposite.pm @@ -0,0 +1,29 @@ +package Moose::Exception::CannotInitializeMooseMetaRoleComposite; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'role_composite' => ( + is => 'ro', + isa => 'Moose::Meta::Role::Composite', + required => 1 +); + +has 'old_meta' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'args' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + 'Moose::Meta::Role::Composite instances can only be reinitialized from an existing metaclass instance'; +} + +1; diff --git a/lib/Moose/Exception/CannotInlineTypeConstraintCheck.pm b/lib/Moose/Exception/CannotInlineTypeConstraintCheck.pm new file mode 100644 index 0000000..2a99985 --- /dev/null +++ b/lib/Moose/Exception/CannotInlineTypeConstraintCheck.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotInlineTypeConstraintCheck; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + 'Cannot inline a type constraint check for ' . $self->type_name; +} + +1; diff --git a/lib/Moose/Exception/CannotLocatePackageInINC.pm b/lib/Moose/Exception/CannotLocatePackageInINC.pm new file mode 100644 index 0000000..b910c16 --- /dev/null +++ b/lib/Moose/Exception/CannotLocatePackageInINC.pm @@ -0,0 +1,40 @@ +package Moose::Exception::CannotLocatePackageInINC; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'INC' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'possible_packages' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'metaclass_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'type' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + my $possible_packages = $self->possible_packages; + my @inc = @{$self->INC}; + + return "Can't locate $possible_packages in \@INC (\@INC contains: @INC)." +} + +1; diff --git a/lib/Moose/Exception/CannotMakeMetaclassCompatible.pm b/lib/Moose/Exception/CannotMakeMetaclassCompatible.pm new file mode 100644 index 0000000..c313888 --- /dev/null +++ b/lib/Moose/Exception/CannotMakeMetaclassCompatible.pm @@ -0,0 +1,22 @@ +package Moose::Exception::CannotMakeMetaclassCompatible; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'superclass_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $class_name = $self->class_name; + my $superclass = $self->superclass_name; + + return "Can't make $class_name compatible with metaclass $superclass"; +} + +1; diff --git a/lib/Moose/Exception/CannotOverrideALocalMethod.pm b/lib/Moose/Exception/CannotOverrideALocalMethod.pm new file mode 100644 index 0000000..0730185 --- /dev/null +++ b/lib/Moose/Exception/CannotOverrideALocalMethod.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CannotOverrideALocalMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "Cannot add an override of method '".$self->method_name."' because there is a local version of '".$self->method_name."'"; +} + +1; diff --git a/lib/Moose/Exception/CannotOverrideBodyOfMetaMethods.pm b/lib/Moose/Exception/CannotOverrideBodyOfMetaMethods.pm new file mode 100644 index 0000000..763779a --- /dev/null +++ b/lib/Moose/Exception/CannotOverrideBodyOfMetaMethods.pm @@ -0,0 +1,18 @@ +package Moose::Exception::CannotOverrideBodyOfMetaMethods; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "Overriding the body of meta methods is not allowed"; +} + +1; diff --git a/lib/Moose/Exception/CannotOverrideLocalMethodIsPresent.pm b/lib/Moose/Exception/CannotOverrideLocalMethodIsPresent.pm new file mode 100644 index 0000000..42815c2 --- /dev/null +++ b/lib/Moose/Exception/CannotOverrideLocalMethodIsPresent.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CannotOverrideLocalMethodIsPresent; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Method'; + +sub _build_message { + "Cannot add an override method if a local method is already present"; +} + +1; diff --git a/lib/Moose/Exception/CannotOverrideNoSuperMethod.pm b/lib/Moose/Exception/CannotOverrideNoSuperMethod.pm new file mode 100644 index 0000000..21fd873 --- /dev/null +++ b/lib/Moose/Exception/CannotOverrideNoSuperMethod.pm @@ -0,0 +1,25 @@ +package Moose::Exception::CannotOverrideNoSuperMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You cannot override '".$self->method_name."' because it has no super method"; +} + +1; diff --git a/lib/Moose/Exception/CannotRegisterUnnamedTypeConstraint.pm b/lib/Moose/Exception/CannotRegisterUnnamedTypeConstraint.pm new file mode 100644 index 0000000..0182b1d --- /dev/null +++ b/lib/Moose/Exception/CannotRegisterUnnamedTypeConstraint.pm @@ -0,0 +1,11 @@ +package Moose::Exception::CannotRegisterUnnamedTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "can't register an unnamed type constraint"; +} + +1; diff --git a/lib/Moose/Exception/CannotUseLazyBuildAndDefaultSimultaneously.pm b/lib/Moose/Exception/CannotUseLazyBuildAndDefaultSimultaneously.pm new file mode 100644 index 0000000..36a2021 --- /dev/null +++ b/lib/Moose/Exception/CannotUseLazyBuildAndDefaultSimultaneously.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CannotUseLazyBuildAndDefaultSimultaneously; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You can not use lazy_build and default for the same attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/CircularReferenceInAlso.pm b/lib/Moose/Exception/CircularReferenceInAlso.pm new file mode 100644 index 0000000..7306adf --- /dev/null +++ b/lib/Moose/Exception/CircularReferenceInAlso.pm @@ -0,0 +1,30 @@ +package Moose::Exception::CircularReferenceInAlso; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'also_parameter' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'stack' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + my $self = shift; + my $also_member = $self->also_parameter; + + my @stack = @{$self->stack}; + my $existing_stack = join( ', ', @stack); + + return "Circular reference in 'also' parameter to Moose::Exporter between " + ."$existing_stack and $also_member"; +} + +1; diff --git a/lib/Moose/Exception/ClassDoesNotHaveInitMeta.pm b/lib/Moose/Exception/ClassDoesNotHaveInitMeta.pm new file mode 100644 index 0000000..a4c06bb --- /dev/null +++ b/lib/Moose/Exception/ClassDoesNotHaveInitMeta.pm @@ -0,0 +1,21 @@ +package Moose::Exception::ClassDoesNotHaveInitMeta; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'traits' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + my $self = shift; + my $class = $self->class_name; + + return "Cannot provide traits when $class does not have an init_meta() method"; +} + +1; diff --git a/lib/Moose/Exception/ClassDoesTheExcludedRole.pm b/lib/Moose/Exception/ClassDoesTheExcludedRole.pm new file mode 100644 index 0000000..b53337f --- /dev/null +++ b/lib/Moose/Exception/ClassDoesTheExcludedRole.pm @@ -0,0 +1,21 @@ +package Moose::Exception::ClassDoesTheExcludedRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role', 'Moose::Exception::Role::Class'; + +has 'excluded_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $excluded_role_name = $self->excluded_role_name; + my $class_name = $self->class_name; + return "The class $class_name does the excluded role '$excluded_role_name'"; +} + +1; diff --git a/lib/Moose/Exception/ClassNamesDoNotMatch.pm b/lib/Moose/Exception/ClassNamesDoNotMatch.pm new file mode 100644 index 0000000..aca9dd8 --- /dev/null +++ b/lib/Moose/Exception/ClassNamesDoNotMatch.pm @@ -0,0 +1,24 @@ +package Moose::Exception::ClassNamesDoNotMatch; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has class_name => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +has class => ( + is => 'ro', + isa => 'Class::MOP::Class', + required => 1, +); + +sub _build_message { + my $self = shift; + "class_name (".$self-> class_name.") does not match class->name (".$self->class->name.")"; +} + +1; diff --git a/lib/Moose/Exception/CloneObjectExpectsAnInstanceOfMetaclass.pm b/lib/Moose/Exception/CloneObjectExpectsAnInstanceOfMetaclass.pm new file mode 100644 index 0000000..7ac0c8b --- /dev/null +++ b/lib/Moose/Exception/CloneObjectExpectsAnInstanceOfMetaclass.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CloneObjectExpectsAnInstanceOfMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'instance' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + my $self = shift; + "You must pass an instance of the metaclass (" .$self->class_name. "), not (".$self->instance.")"; +} + +1; diff --git a/lib/Moose/Exception/CodeBlockMustBeACodeRef.pm b/lib/Moose/Exception/CodeBlockMustBeACodeRef.pm new file mode 100644 index 0000000..5b50a79 --- /dev/null +++ b/lib/Moose/Exception/CodeBlockMustBeACodeRef.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CodeBlockMustBeACodeRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Instance'; + +sub _build_message { + "Your code block must be a CODE reference"; +} + +1; diff --git a/lib/Moose/Exception/CoercingWithoutCoercions.pm b/lib/Moose/Exception/CoercingWithoutCoercions.pm new file mode 100644 index 0000000..b2e3438 --- /dev/null +++ b/lib/Moose/Exception/CoercingWithoutCoercions.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CoercingWithoutCoercions; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Cannot coerce without a type coercion"; +} +1; diff --git a/lib/Moose/Exception/CoercionAlreadyExists.pm b/lib/Moose/Exception/CoercionAlreadyExists.pm new file mode 100644 index 0000000..53342d8 --- /dev/null +++ b/lib/Moose/Exception/CoercionAlreadyExists.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CoercionAlreadyExists; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +has 'constraint_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "A coercion action already exists for '".$self->constraint_name."'"; +} + +1; diff --git a/lib/Moose/Exception/CoercionNeedsTypeConstraint.pm b/lib/Moose/Exception/CoercionNeedsTypeConstraint.pm new file mode 100644 index 0000000..b385be9 --- /dev/null +++ b/lib/Moose/Exception/CoercionNeedsTypeConstraint.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CoercionNeedsTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You cannot have coercion without specifying a type constraint on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusions.pm b/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusions.pm new file mode 100644 index 0000000..06f7de9 --- /dev/null +++ b/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusions.pm @@ -0,0 +1,21 @@ +package Moose::Exception::ConflictDetectedInCheckRoleExclusions; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'excluded_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $role_name = $self->role_name; + my $excluded_role_name = $self->excluded_role_name; + return "Conflict detected: $role_name excludes role '$excluded_role_name'"; +} + +1; diff --git a/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusionsInToClass.pm b/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusionsInToClass.pm new file mode 100644 index 0000000..89b9baf --- /dev/null +++ b/lib/Moose/Exception/ConflictDetectedInCheckRoleExclusionsInToClass.pm @@ -0,0 +1,15 @@ +package Moose::Exception::ConflictDetectedInCheckRoleExclusionsInToClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Role'; + +sub _build_message { + my $self = shift; + my $class_name = $self->class_name; + my $role_name = $self->role_name; + return "Conflict detected: $class_name excludes role '$role_name'"; +} + +1; diff --git a/lib/Moose/Exception/ConstructClassInstanceTakesPackageName.pm b/lib/Moose/Exception/ConstructClassInstanceTakesPackageName.pm new file mode 100644 index 0000000..3e0954a --- /dev/null +++ b/lib/Moose/Exception/ConstructClassInstanceTakesPackageName.pm @@ -0,0 +1,11 @@ +package Moose::Exception::ConstructClassInstanceTakesPackageName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You must pass a package name"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotCreateMethod.pm b/lib/Moose/Exception/CouldNotCreateMethod.pm new file mode 100644 index 0000000..e9497b7 --- /dev/null +++ b/lib/Moose/Exception/CouldNotCreateMethod.pm @@ -0,0 +1,31 @@ +package Moose::Exception::CouldNotCreateMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'option_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'option_value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'error' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Could not create the '".$self->option_name."' method for " . $self->attribute->name . " because : ".$self->error; +} + +1; diff --git a/lib/Moose/Exception/CouldNotCreateWriter.pm b/lib/Moose/Exception/CouldNotCreateWriter.pm new file mode 100644 index 0000000..8bcb7fb --- /dev/null +++ b/lib/Moose/Exception/CouldNotCreateWriter.pm @@ -0,0 +1,23 @@ +package Moose::Exception::CouldNotCreateWriter; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::EitherAttributeOrAttributeName', 'Moose::Exception::Role::Instance'; + +has 'error' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $error = $self->error; + my $attribute_name = $self->attribute_name; + + return "Could not create writer for '$attribute_name' " + . "because $error"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotEvalConstructor.pm b/lib/Moose/Exception/CouldNotEvalConstructor.pm new file mode 100644 index 0000000..95f5738 --- /dev/null +++ b/lib/Moose/Exception/CouldNotEvalConstructor.pm @@ -0,0 +1,33 @@ +package Moose::Exception::CouldNotEvalConstructor; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'constructor_method' => ( + is => 'ro', + isa => 'Class::MOP::Method::Constructor', + required => 1 +); + +has 'source' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'error' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $error = $self->error; + my $source = $self->source; + + return "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$error"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotEvalDestructor.pm b/lib/Moose/Exception/CouldNotEvalDestructor.pm new file mode 100644 index 0000000..40ad749 --- /dev/null +++ b/lib/Moose/Exception/CouldNotEvalDestructor.pm @@ -0,0 +1,33 @@ +package Moose::Exception::CouldNotEvalDestructor; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'method_destructor_object' => ( + is => 'ro', + isa => 'Moose::Meta::Method::Destructor', + required => 1 +); + +has 'source' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'error' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $error = $self->error; + my $source = $self->source; + + return "Could not eval the destructor :\n\n$source\n\nbecause :\n\n$error"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotFindTypeConstraintToCoerceFrom.pm b/lib/Moose/Exception/CouldNotFindTypeConstraintToCoerceFrom.pm new file mode 100644 index 0000000..1e364b7 --- /dev/null +++ b/lib/Moose/Exception/CouldNotFindTypeConstraintToCoerceFrom.pm @@ -0,0 +1,19 @@ +package Moose::Exception::CouldNotFindTypeConstraintToCoerceFrom; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +has 'constraint_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Could not find the type constraint (".$self->constraint_name.") to coerce from"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotGenerateInlineAttributeMethod.pm b/lib/Moose/Exception/CouldNotGenerateInlineAttributeMethod.pm new file mode 100644 index 0000000..08ecc44 --- /dev/null +++ b/lib/Moose/Exception/CouldNotGenerateInlineAttributeMethod.pm @@ -0,0 +1,25 @@ +package Moose::Exception::CouldNotGenerateInlineAttributeMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +has 'option' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'error' => ( + is => 'ro', + isa => 'Str|Moose::Exception', + required => 1 +); + +sub _build_message { + my $self = shift; + "Could not generate inline ".$self->option." because : ".$self->error; +} + +1; diff --git a/lib/Moose/Exception/CouldNotLocateTypeConstraintForUnion.pm b/lib/Moose/Exception/CouldNotLocateTypeConstraintForUnion.pm new file mode 100644 index 0000000..7a52456 --- /dev/null +++ b/lib/Moose/Exception/CouldNotLocateTypeConstraintForUnion.pm @@ -0,0 +1,13 @@ +package Moose::Exception::CouldNotLocateTypeConstraintForUnion; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Could not locate type constraint (".$self->type_name.") for the union"; +} + +1; diff --git a/lib/Moose/Exception/CouldNotParseType.pm b/lib/Moose/Exception/CouldNotParseType.pm new file mode 100644 index 0000000..a87ecbc --- /dev/null +++ b/lib/Moose/Exception/CouldNotParseType.pm @@ -0,0 +1,29 @@ +package Moose::Exception::CouldNotParseType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'type' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'position' => ( + is => 'ro', + isa => 'Int', + required => 1 +); + +sub _build_message { + my $self = shift; + my $type = $self->type; + my $length = length($type); + my $position = $self->position; + + return "'$type' didn't parse (parse-pos=$position" + . " and str-length=$length)"; +} + +1; diff --git a/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfAttributes.pm b/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfAttributes.pm new file mode 100644 index 0000000..d266888 --- /dev/null +++ b/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfAttributes.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateMOPClassTakesArrayRefOfAttributes; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreateMOPClass'; + +sub _build_message { + "You must pass an ARRAY ref of attributes"; +} + +1; diff --git a/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfSuperclasses.pm b/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfSuperclasses.pm new file mode 100644 index 0000000..8a9f49a --- /dev/null +++ b/lib/Moose/Exception/CreateMOPClassTakesArrayRefOfSuperclasses.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateMOPClassTakesArrayRefOfSuperclasses; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreateMOPClass'; + +sub _build_message { + "You must pass an ARRAY ref of superclasses"; +} + +1; diff --git a/lib/Moose/Exception/CreateMOPClassTakesHashRefOfMethods.pm b/lib/Moose/Exception/CreateMOPClassTakesHashRefOfMethods.pm new file mode 100644 index 0000000..9c17f4d --- /dev/null +++ b/lib/Moose/Exception/CreateMOPClassTakesHashRefOfMethods.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateMOPClassTakesHashRefOfMethods; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreateMOPClass'; + +sub _build_message { + "You must pass an HASH ref of methods"; +} + +1; diff --git a/lib/Moose/Exception/CreateTakesArrayRefOfRoles.pm b/lib/Moose/Exception/CreateTakesArrayRefOfRoles.pm new file mode 100644 index 0000000..bd92403 --- /dev/null +++ b/lib/Moose/Exception/CreateTakesArrayRefOfRoles.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateTakesArrayRefOfRoles; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreate'; + +sub _build_message { + "You must pass an ARRAY ref of roles"; +} + +1; diff --git a/lib/Moose/Exception/CreateTakesHashRefOfAttributes.pm b/lib/Moose/Exception/CreateTakesHashRefOfAttributes.pm new file mode 100644 index 0000000..d0b451c --- /dev/null +++ b/lib/Moose/Exception/CreateTakesHashRefOfAttributes.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateTakesHashRefOfAttributes; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreate'; + +sub _build_message { + "You must pass a HASH ref of attributes"; +} + +1; diff --git a/lib/Moose/Exception/CreateTakesHashRefOfMethods.pm b/lib/Moose/Exception/CreateTakesHashRefOfMethods.pm new file mode 100644 index 0000000..6ef9000 --- /dev/null +++ b/lib/Moose/Exception/CreateTakesHashRefOfMethods.pm @@ -0,0 +1,12 @@ +package Moose::Exception::CreateTakesHashRefOfMethods; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::RoleForCreate'; + +sub _build_message { + "You must pass a HASH ref of methods"; +} + +1; diff --git a/lib/Moose/Exception/DefaultToMatchOnTypeMustBeCodeRef.pm b/lib/Moose/Exception/DefaultToMatchOnTypeMustBeCodeRef.pm new file mode 100644 index 0000000..74925ce --- /dev/null +++ b/lib/Moose/Exception/DefaultToMatchOnTypeMustBeCodeRef.pm @@ -0,0 +1,32 @@ +package Moose::Exception::DefaultToMatchOnTypeMustBeCodeRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'to_match' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'default_action' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'cases_to_be_matched' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + my $self = shift; + my $default = $self->default_action; + + return "Default case must be a CODE ref, not $default"; +} + +1; diff --git a/lib/Moose/Exception/DelegationToAClassWhichIsNotLoaded.pm b/lib/Moose/Exception/DelegationToAClassWhichIsNotLoaded.pm new file mode 100644 index 0000000..6e96c80 --- /dev/null +++ b/lib/Moose/Exception/DelegationToAClassWhichIsNotLoaded.pm @@ -0,0 +1,19 @@ +package Moose::Exception::DelegationToAClassWhichIsNotLoaded; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'class_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "The ".$self->attribute->name." attribute is trying to delegate to a class which has not been loaded - ".$self->class_name; +} + +1; diff --git a/lib/Moose/Exception/DelegationToARoleWhichIsNotLoaded.pm b/lib/Moose/Exception/DelegationToARoleWhichIsNotLoaded.pm new file mode 100644 index 0000000..96a04ac --- /dev/null +++ b/lib/Moose/Exception/DelegationToARoleWhichIsNotLoaded.pm @@ -0,0 +1,19 @@ +package Moose::Exception::DelegationToARoleWhichIsNotLoaded; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'role_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "The ".$self->attribute->name." attribute is trying to delegate to a role which has not been loaded - ".$self->role_name; +} + +1; diff --git a/lib/Moose/Exception/DelegationToATypeWhichIsNotAClass.pm b/lib/Moose/Exception/DelegationToATypeWhichIsNotAClass.pm new file mode 100644 index 0000000..055c685 --- /dev/null +++ b/lib/Moose/Exception/DelegationToATypeWhichIsNotAClass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::DelegationToATypeWhichIsNotAClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +sub _build_message { + my $self = shift; + "The ".$self->attribute->name." attribute is trying to delegate to a type (".$self->attribute->type_constraint->name.") that is not backed by a class"; +} + +1; diff --git a/lib/Moose/Exception/DoesRequiresRoleName.pm b/lib/Moose/Exception/DoesRequiresRoleName.pm new file mode 100644 index 0000000..f3437ca --- /dev/null +++ b/lib/Moose/Exception/DoesRequiresRoleName.pm @@ -0,0 +1,12 @@ +package Moose::Exception::DoesRequiresRoleName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must supply a role name to does()"; +} + +1; diff --git a/lib/Moose/Exception/EnumCalledWithAnArrayRefAndAdditionalArgs.pm b/lib/Moose/Exception/EnumCalledWithAnArrayRefAndAdditionalArgs.pm new file mode 100644 index 0000000..19fac8a --- /dev/null +++ b/lib/Moose/Exception/EnumCalledWithAnArrayRefAndAdditionalArgs.pm @@ -0,0 +1,23 @@ +package Moose::Exception::EnumCalledWithAnArrayRefAndAdditionalArgs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'array' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'args' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + "enum called with an array reference and additional arguments. Did you mean to parenthesize the enum call's parameters?"; +} + +1; diff --git a/lib/Moose/Exception/EnumValuesMustBeString.pm b/lib/Moose/Exception/EnumValuesMustBeString.pm new file mode 100644 index 0000000..6694e27 --- /dev/null +++ b/lib/Moose/Exception/EnumValuesMustBeString.pm @@ -0,0 +1,25 @@ +package Moose::Exception::EnumValuesMustBeString; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "Enum values must be strings, not ".( defined $self->value ? "'".$self->value."'" : "undef" ); +} + +1; diff --git a/lib/Moose/Exception/ExtendsMissingArgs.pm b/lib/Moose/Exception/ExtendsMissingArgs.pm new file mode 100644 index 0000000..7c34923 --- /dev/null +++ b/lib/Moose/Exception/ExtendsMissingArgs.pm @@ -0,0 +1,12 @@ +package Moose::Exception::ExtendsMissingArgs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "Must derive at least one class"; +} + +1; diff --git a/lib/Moose/Exception/HandlesMustBeAHashRef.pm b/lib/Moose/Exception/HandlesMustBeAHashRef.pm new file mode 100644 index 0000000..9eb11a5 --- /dev/null +++ b/lib/Moose/Exception/HandlesMustBeAHashRef.pm @@ -0,0 +1,19 @@ +package Moose::Exception::HandlesMustBeAHashRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +has 'given_handles' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "The 'handles' option must be a HASH reference, not ".$self->given_handles; +} + +1; diff --git a/lib/Moose/Exception/IllegalInheritedOptions.pm b/lib/Moose/Exception/IllegalInheritedOptions.pm new file mode 100644 index 0000000..2eae454 --- /dev/null +++ b/lib/Moose/Exception/IllegalInheritedOptions.pm @@ -0,0 +1,22 @@ +package Moose::Exception::IllegalInheritedOptions; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'illegal_options' => ( + is => 'ro', + traits => ['Array'], + handles => { + _join_options => 'join', + }, + required => 1, +); + +sub _build_message { + my $self = shift; + "Illegal inherited options => (".$self->_join_options(', ').")"; +} + +1; diff --git a/lib/Moose/Exception/IllegalMethodTypeToAddMethodModifier.pm b/lib/Moose/Exception/IllegalMethodTypeToAddMethodModifier.pm new file mode 100644 index 0000000..458a08b --- /dev/null +++ b/lib/Moose/Exception/IllegalMethodTypeToAddMethodModifier.pm @@ -0,0 +1,30 @@ +package Moose::Exception::IllegalMethodTypeToAddMethodModifier; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'class_or_object' => ( + is => 'ro', + isa => "Any", + required => 1, +); + +has 'params' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1, +); + +has 'modifier_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Methods passed to ".$self->modifier_name." must be provided as a list, arrayref or regex, not ".$self->params->[0]; +} + +1; diff --git a/lib/Moose/Exception/IncompatibleMetaclassOfSuperclass.pm b/lib/Moose/Exception/IncompatibleMetaclassOfSuperclass.pm new file mode 100644 index 0000000..98c8fb2 --- /dev/null +++ b/lib/Moose/Exception/IncompatibleMetaclassOfSuperclass.pm @@ -0,0 +1,26 @@ +package Moose::Exception::IncompatibleMetaclassOfSuperclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has [qw/superclass_name superclass_meta_type class_meta_type/] => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + my $class_name = $self->class_name; + my $class_meta_type = $self->class_meta_type; + my $superclass_name = $self->superclass_name; + my $supermeta_type = $self->superclass_meta_type; + + return "The metaclass of $class_name ($class_meta_type)" . + " is not compatible with the metaclass of its superclass, " . + "$superclass_name ($supermeta_type)"; +} + +1; diff --git a/lib/Moose/Exception/InitMetaRequiresClass.pm b/lib/Moose/Exception/InitMetaRequiresClass.pm new file mode 100644 index 0000000..ca2fb06 --- /dev/null +++ b/lib/Moose/Exception/InitMetaRequiresClass.pm @@ -0,0 +1,12 @@ +package Moose::Exception::InitMetaRequiresClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +sub _build_message { + "Cannot call init_meta without specifying a for_class"; +} + +1; diff --git a/lib/Moose/Exception/InitializeTakesUnBlessedPackageName.pm b/lib/Moose/Exception/InitializeTakesUnBlessedPackageName.pm new file mode 100644 index 0000000..26f782f --- /dev/null +++ b/lib/Moose/Exception/InitializeTakesUnBlessedPackageName.pm @@ -0,0 +1,17 @@ +package Moose::Exception::InitializeTakesUnBlessedPackageName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'package_name' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + "You must pass a package name and it cannot be blessed"; +} + +1; diff --git a/lib/Moose/Exception/InstanceBlessedIntoWrongClass.pm b/lib/Moose/Exception/InstanceBlessedIntoWrongClass.pm new file mode 100644 index 0000000..4d4faff --- /dev/null +++ b/lib/Moose/Exception/InstanceBlessedIntoWrongClass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::InstanceBlessedIntoWrongClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Instance'; + +sub _build_message { + my $self = shift; + "Objects passed as the __INSTANCE__ parameter must already be blessed into the correct class, but ".$self->instance." is not a " . $self->class_name; +} + +1; diff --git a/lib/Moose/Exception/InstanceMustBeABlessedReference.pm b/lib/Moose/Exception/InstanceMustBeABlessedReference.pm new file mode 100644 index 0000000..40b359d --- /dev/null +++ b/lib/Moose/Exception/InstanceMustBeABlessedReference.pm @@ -0,0 +1,19 @@ +package Moose::Exception::InstanceMustBeABlessedReference; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Class'; + +has 'instance' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "The __INSTANCE__ parameter must be a blessed reference, not ". $self->instance; +} + +1; diff --git a/lib/Moose/Exception/InvalidArgPassedToMooseUtilMetaRole.pm b/lib/Moose/Exception/InvalidArgPassedToMooseUtilMetaRole.pm new file mode 100644 index 0000000..2910e7a --- /dev/null +++ b/lib/Moose/Exception/InvalidArgPassedToMooseUtilMetaRole.pm @@ -0,0 +1,40 @@ +package Moose::Exception::InvalidArgPassedToMooseUtilMetaRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'argument' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + my $error = 'When using Moose::Util::MetaRole, you must pass a Moose class name,' + . ' role name, metaclass object, or metarole object.'; + + my $arg = $self->argument; + my $found = blessed $arg ? $arg : Class::MOP::class_of($arg); + + my $error2; + + if ( defined $found && blessed $found ) { + $error2 = " You passed ".$arg.", and we resolved this to a " + . ( blessed $found ) + . ' object.'; + } + elsif ( !defined $found ) { + $error2 = " You passed ".( defined $arg ? $arg : "undef" ).", and this did not resolve to a metaclass or metarole." + . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?'; + } + else { + $error2 = " You passed an undef." + . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?'; + } + + $error.$error2; +} + +1; diff --git a/lib/Moose/Exception/InvalidArgumentToMethod.pm b/lib/Moose/Exception/InvalidArgumentToMethod.pm new file mode 100644 index 0000000..df22ce7 --- /dev/null +++ b/lib/Moose/Exception/InvalidArgumentToMethod.pm @@ -0,0 +1,44 @@ +package Moose::Exception::InvalidArgumentToMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'argument' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has [qw(type type_of_argument method_name)] => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'ordinal' => ( + is => 'ro', + isa => 'Str', + predicate => 'is_ordinal_set' +); + +has 'argument_noun' => ( + is => 'ro', + isa => 'Str', + default => 'argument' +); + +sub _build_message { + my $self = shift; + my $article = ( $self->type_of_argument =~ /^[aeiou]/ ? 'an ' : 'a '); + my $arg_noun = $self->argument_noun; + + if( $self->is_ordinal_set ) { + "The ".$self->ordinal." $arg_noun passed to ".$self->method_name." must be ".$article.$self->type_of_argument; + } + else { + "The $arg_noun passed to ".$self->method_name." must be ".$article.$self->type_of_argument; + } +} + +1; diff --git a/lib/Moose/Exception/InvalidArgumentsToTraitAliases.pm b/lib/Moose/Exception/InvalidArgumentsToTraitAliases.pm new file mode 100644 index 0000000..c60af60 --- /dev/null +++ b/lib/Moose/Exception/InvalidArgumentsToTraitAliases.pm @@ -0,0 +1,31 @@ +package Moose::Exception::InvalidArgumentsToTraitAliases; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +use Scalar::Util qw(reftype); + +has 'alias' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'package_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $alias = $self->alias; + my $reftype_alias = reftype($alias); + + return "$reftype_alias references are not " + . "valid arguments to the 'trait_aliases' option"; +} + +1; diff --git a/lib/Moose/Exception/InvalidBaseTypeGivenToCreateParameterizedTypeConstraint.pm b/lib/Moose/Exception/InvalidBaseTypeGivenToCreateParameterizedTypeConstraint.pm new file mode 100644 index 0000000..48a29c9 --- /dev/null +++ b/lib/Moose/Exception/InvalidBaseTypeGivenToCreateParameterizedTypeConstraint.pm @@ -0,0 +1,13 @@ +package Moose::Exception::InvalidBaseTypeGivenToCreateParameterizedTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Could not locate the base type (".$self->type_name.")"; +} + +1; diff --git a/lib/Moose/Exception/InvalidHandleValue.pm b/lib/Moose/Exception/InvalidHandleValue.pm new file mode 100644 index 0000000..04b7c8f --- /dev/null +++ b/lib/Moose/Exception/InvalidHandleValue.pm @@ -0,0 +1,19 @@ +package Moose::Exception::InvalidHandleValue; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +has 'handle_value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "All values passed to handles must be strings or ARRAY references, not ".$self->handle_value; +} + +1; diff --git a/lib/Moose/Exception/InvalidHasProvidedInARole.pm b/lib/Moose/Exception/InvalidHasProvidedInARole.pm new file mode 100644 index 0000000..d933d72 --- /dev/null +++ b/lib/Moose/Exception/InvalidHasProvidedInARole.pm @@ -0,0 +1,18 @@ +package Moose::Exception::InvalidHasProvidedInARole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + "Usage: has 'name' => ( key => value, ... )"; +} + +1; diff --git a/lib/Moose/Exception/InvalidNameForType.pm b/lib/Moose/Exception/InvalidNameForType.pm new file mode 100644 index 0000000..500eff2 --- /dev/null +++ b/lib/Moose/Exception/InvalidNameForType.pm @@ -0,0 +1,17 @@ +package Moose::Exception::InvalidNameForType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + $self->name." contains invalid characters for a type name. Names can contain alphanumeric character, ':', and '.'"; +} +1; diff --git a/lib/Moose/Exception/InvalidOverloadOperator.pm b/lib/Moose/Exception/InvalidOverloadOperator.pm new file mode 100644 index 0000000..2a04f12 --- /dev/null +++ b/lib/Moose/Exception/InvalidOverloadOperator.pm @@ -0,0 +1,20 @@ +package Moose::Exception::InvalidOverloadOperator; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has operator => ( + is => 'ro', + isa => 'Defined', + required => 1, +); + +sub _build_message { + my $self = shift; + 'The operator parameter you passed to the Moose::Meta::Overload constructor (' + . $self->operator() + . ') was not a valid overloading operator'; +} + +1; diff --git a/lib/Moose/Exception/InvalidRoleApplication.pm b/lib/Moose/Exception/InvalidRoleApplication.pm new file mode 100644 index 0000000..361cd61 --- /dev/null +++ b/lib/Moose/Exception/InvalidRoleApplication.pm @@ -0,0 +1,18 @@ +package Moose::Exception::InvalidRoleApplication; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'application' => ( + is => 'ro', + isa => "Any", + required => 1, +); + +sub _build_message { + "Role applications must be instances of Moose::Meta::Role::Application::ToClass"; +} + +1; diff --git a/lib/Moose/Exception/InvalidTypeConstraint.pm b/lib/Moose/Exception/InvalidTypeConstraint.pm new file mode 100644 index 0000000..4979400 --- /dev/null +++ b/lib/Moose/Exception/InvalidTypeConstraint.pm @@ -0,0 +1,23 @@ +package Moose::Exception::InvalidTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'registry_object' => ( + is => 'ro', + isa => 'Moose::Meta::TypeConstraint::Registry', + required => 1 +); + +has 'type' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + return "No type supplied / type is not a valid type constraint"; +} + +1; diff --git a/lib/Moose/Exception/InvalidTypeGivenToCreateParameterizedTypeConstraint.pm b/lib/Moose/Exception/InvalidTypeGivenToCreateParameterizedTypeConstraint.pm new file mode 100644 index 0000000..296e4ea --- /dev/null +++ b/lib/Moose/Exception/InvalidTypeGivenToCreateParameterizedTypeConstraint.pm @@ -0,0 +1,13 @@ +package Moose::Exception::InvalidTypeGivenToCreateParameterizedTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Could not parse type name (".$self->type_name.") correctly"; +} + +1; diff --git a/lib/Moose/Exception/InvalidValueForIs.pm b/lib/Moose/Exception/InvalidValueForIs.pm new file mode 100644 index 0000000..a81e8fc --- /dev/null +++ b/lib/Moose/Exception/InvalidValueForIs.pm @@ -0,0 +1,13 @@ +package Moose::Exception::InvalidValueForIs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "I do not understand this option (is => ".$self->params->{is}.") on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/IsaDoesNotDoTheRole.pm b/lib/Moose/Exception/IsaDoesNotDoTheRole.pm new file mode 100644 index 0000000..3abc897 --- /dev/null +++ b/lib/Moose/Exception/IsaDoesNotDoTheRole.pm @@ -0,0 +1,13 @@ +package Moose::Exception::IsaDoesNotDoTheRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "Cannot have an isa option and a does option if the isa does not do the does on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/IsaLacksDoesMethod.pm b/lib/Moose/Exception/IsaLacksDoesMethod.pm new file mode 100644 index 0000000..1ba2a85 --- /dev/null +++ b/lib/Moose/Exception/IsaLacksDoesMethod.pm @@ -0,0 +1,13 @@ +package Moose::Exception::IsaLacksDoesMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "Cannot have an isa option which cannot ->does() on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/LazyAttributeNeedsADefault.pm b/lib/Moose/Exception/LazyAttributeNeedsADefault.pm new file mode 100644 index 0000000..0ba36fa --- /dev/null +++ b/lib/Moose/Exception/LazyAttributeNeedsADefault.pm @@ -0,0 +1,13 @@ +package Moose::Exception::LazyAttributeNeedsADefault; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::EitherAttributeOrAttributeName'; + +sub _build_message { + my $self = shift; + "You cannot have a lazy attribute (".$self->attribute_name.") without specifying a default value for it"; +} + +1; diff --git a/lib/Moose/Exception/Legacy.pm b/lib/Moose/Exception/Legacy.pm new file mode 100644 index 0000000..d960f18 --- /dev/null +++ b/lib/Moose/Exception/Legacy.pm @@ -0,0 +1,7 @@ +package Moose::Exception::Legacy; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +1; diff --git a/lib/Moose/Exception/MOPAttributeNewNeedsAttributeName.pm b/lib/Moose/Exception/MOPAttributeNewNeedsAttributeName.pm new file mode 100644 index 0000000..3b62a92 --- /dev/null +++ b/lib/Moose/Exception/MOPAttributeNewNeedsAttributeName.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MOPAttributeNewNeedsAttributeName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must provide a name for the attribute"; +} + +1; diff --git a/lib/Moose/Exception/MatchActionMustBeACodeRef.pm b/lib/Moose/Exception/MatchActionMustBeACodeRef.pm new file mode 100644 index 0000000..c0c7fb8 --- /dev/null +++ b/lib/Moose/Exception/MatchActionMustBeACodeRef.pm @@ -0,0 +1,27 @@ +package Moose::Exception::MatchActionMustBeACodeRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +has 'to_match' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +has 'action' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + my $action = $self->action; + + return "Match action must be a CODE ref, not $action"; +} + +1; diff --git a/lib/Moose/Exception/MessageParameterMustBeCodeRef.pm b/lib/Moose/Exception/MessageParameterMustBeCodeRef.pm new file mode 100644 index 0000000..c15f689 --- /dev/null +++ b/lib/Moose/Exception/MessageParameterMustBeCodeRef.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MessageParameterMustBeCodeRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "The 'message' parameter must be a coderef"; +} + +1; diff --git a/lib/Moose/Exception/MetaclassIsAClassNotASubclassOfGivenMetaclass.pm b/lib/Moose/Exception/MetaclassIsAClassNotASubclassOfGivenMetaclass.pm new file mode 100644 index 0000000..bbc90be --- /dev/null +++ b/lib/Moose/Exception/MetaclassIsAClassNotASubclassOfGivenMetaclass.pm @@ -0,0 +1,23 @@ +package Moose::Exception::MetaclassIsAClassNotASubclassOfGivenMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +use Moose::Util 'find_meta'; + +has 'metaclass' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $class = find_meta( $self->class_name ); + $self->class_name." already has a metaclass, but it does not inherit ".$self->metaclass. + " ($class). You cannot make the same thing a role and a class. Remove either Moose or Moose::Role."; +} + +1; diff --git a/lib/Moose/Exception/MetaclassIsARoleNotASubclassOfGivenMetaclass.pm b/lib/Moose/Exception/MetaclassIsARoleNotASubclassOfGivenMetaclass.pm new file mode 100644 index 0000000..b6dec64 --- /dev/null +++ b/lib/Moose/Exception/MetaclassIsARoleNotASubclassOfGivenMetaclass.pm @@ -0,0 +1,25 @@ +package Moose::Exception::MetaclassIsARoleNotASubclassOfGivenMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +use Moose::Util 'find_meta'; + +has 'metaclass' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $role_name = $self->role_name; + my $role = find_meta( $role_name ); + my $metaclass = $self->metaclass; + return "$role_name already has a metaclass, but it does not inherit $metaclass ($role). " + ."You cannot make the same thing a role and a class. Remove either Moose or Moose::Role."; +} + +1; diff --git a/lib/Moose/Exception/MetaclassIsNotASubclassOfGivenMetaclass.pm b/lib/Moose/Exception/MetaclassIsNotASubclassOfGivenMetaclass.pm new file mode 100644 index 0000000..53f939b --- /dev/null +++ b/lib/Moose/Exception/MetaclassIsNotASubclassOfGivenMetaclass.pm @@ -0,0 +1,22 @@ +package Moose::Exception::MetaclassIsNotASubclassOfGivenMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +use Moose::Util 'find_meta'; + +has 'metaclass' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $class = find_meta( $self->class_name ); + $self->class_name." already has a metaclass, but it does not inherit ".$self->metaclass." ($class)."; +} + +1; diff --git a/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaClass.pm b/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaClass.pm new file mode 100644 index 0000000..6b22e2d --- /dev/null +++ b/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaClass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::MetaclassMustBeASubclassOfMooseMetaClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + my $self = shift; + "The Metaclass ".$self->class_name." must be a subclass of Moose::Meta::Class." +} + +1; diff --git a/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaRole.pm b/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaRole.pm new file mode 100644 index 0000000..e638259 --- /dev/null +++ b/lib/Moose/Exception/MetaclassMustBeASubclassOfMooseMetaRole.pm @@ -0,0 +1,13 @@ +package Moose::Exception::MetaclassMustBeASubclassOfMooseMetaRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +sub _build_message { + my $self = shift; + "The Metaclass ".$self->role_name." must be a subclass of Moose::Meta::Role." +} + +1; diff --git a/lib/Moose/Exception/MetaclassMustBeDerivedFromClassMOPClass.pm b/lib/Moose/Exception/MetaclassMustBeDerivedFromClassMOPClass.pm new file mode 100644 index 0000000..f4d01f5 --- /dev/null +++ b/lib/Moose/Exception/MetaclassMustBeDerivedFromClassMOPClass.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MetaclassMustBeDerivedFromClassMOPClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'class_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "The metaclass (".$self->class_name.") must be derived from Class::MOP::Class"; +} + +1; diff --git a/lib/Moose/Exception/MetaclassNotLoaded.pm b/lib/Moose/Exception/MetaclassNotLoaded.pm new file mode 100644 index 0000000..35238a9 --- /dev/null +++ b/lib/Moose/Exception/MetaclassNotLoaded.pm @@ -0,0 +1,13 @@ +package Moose::Exception::MetaclassNotLoaded; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + my $self = shift; + "The Metaclass ".$self->class_name." must be loaded. (Perhaps you forgot to 'use ".$self->class_name."'?)"; +} + +1; diff --git a/lib/Moose/Exception/MetaclassTypeIncompatible.pm b/lib/Moose/Exception/MetaclassTypeIncompatible.pm new file mode 100644 index 0000000..c56b5c3 --- /dev/null +++ b/lib/Moose/Exception/MetaclassTypeIncompatible.pm @@ -0,0 +1,38 @@ +package Moose::Exception::MetaclassTypeIncompatible; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +use Moose::Util 'find_meta'; + +has [qw(superclass_name metaclass_type)] => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $class_name = $self->class_name; + my $superclass_name = $self->superclass_name; + my $metaclass_type = $self->metaclass_type; + + my $metaclass_type_name = $metaclass_type; + $metaclass_type_name =~ s/_(?:meta)?class$//; + $metaclass_type_name =~ s/_/ /g; + + my $class = find_meta( $class_name ); + + my $self_metaclass_type = $class->$metaclass_type; + + my $super_meta = Class::MOP::get_metaclass_by_name($superclass_name); + my $super_metatype = $super_meta->$metaclass_type; + + return "The $metaclass_type metaclass for $class_name" + . " ($self_metaclass_type) is not compatible with the $metaclass_type_name" + . " metaclass of its superclass, $superclass_name ($super_metatype)"; +} + +1; diff --git a/lib/Moose/Exception/MethodExpectedAMetaclassObject.pm b/lib/Moose/Exception/MethodExpectedAMetaclassObject.pm new file mode 100644 index 0000000..7994cfc --- /dev/null +++ b/lib/Moose/Exception/MethodExpectedAMetaclassObject.pm @@ -0,0 +1,23 @@ +package Moose::Exception::MethodExpectedAMetaclassObject; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'metaclass' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "The is_needed method expected a metaclass object as its arugment"; +} + +1; diff --git a/lib/Moose/Exception/MethodExpectsFewerArgs.pm b/lib/Moose/Exception/MethodExpectsFewerArgs.pm new file mode 100644 index 0000000..e591a67 --- /dev/null +++ b/lib/Moose/Exception/MethodExpectsFewerArgs.pm @@ -0,0 +1,26 @@ +package Moose::Exception::MethodExpectsFewerArgs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +has 'maximum_args' => ( + is => 'ro', + isa => 'Int', + required => 1, +); + +sub _build_message { + my $self = shift; + my $max = $self->maximum_args; + "Cannot call ".$self->method_name." with ". + ( $max ? "more than $max" : 'any'). " argument".( $max == 1 ? '' : 's' ); +} + +1; diff --git a/lib/Moose/Exception/MethodExpectsMoreArgs.pm b/lib/Moose/Exception/MethodExpectsMoreArgs.pm new file mode 100644 index 0000000..d0e82cf --- /dev/null +++ b/lib/Moose/Exception/MethodExpectsMoreArgs.pm @@ -0,0 +1,24 @@ +package Moose::Exception::MethodExpectsMoreArgs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'minimum_args' => ( + is => 'ro', + isa => 'Int', + required => 1 +); + +sub _build_message { + my $self = shift; + "Cannot call ".$self->method_name." without at least ".$self->minimum_args." argument".($self->minimum_args == 1 ? '' : 's'); +} + +1; diff --git a/lib/Moose/Exception/MethodModifierNeedsMethodName.pm b/lib/Moose/Exception/MethodModifierNeedsMethodName.pm new file mode 100644 index 0000000..c940608 --- /dev/null +++ b/lib/Moose/Exception/MethodModifierNeedsMethodName.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MethodModifierNeedsMethodName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must pass in a method name"; +} + +1; diff --git a/lib/Moose/Exception/MethodNameConflictInRoles.pm b/lib/Moose/Exception/MethodNameConflictInRoles.pm new file mode 100644 index 0000000..d6db656 --- /dev/null +++ b/lib/Moose/Exception/MethodNameConflictInRoles.pm @@ -0,0 +1,46 @@ +package Moose::Exception::MethodNameConflictInRoles; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'conflict' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Moose::Meta::Role::Method::Conflicting]', + handles => { conflict_methods_count => 'count', + get_method_at => 'get', + get_all_methods => 'elements', + }, + required => 1 +); + +sub _get_method_names { + my $self = shift; + + return ( $self->conflict_methods_count == 1 ? + "'".$self->get_method_at(0)->name."'": + Moose::Util::english_list( map { q{'} . $_->name . q{'} } $self->get_all_methods ) ); +} + +sub _build_message { + my $self = shift; + my $count = $self->conflict_methods_count; + my $roles = $self->get_method_at(0)->roles_as_english_list; + + if( $count == 1 ) + { + "Due to a method name conflict in roles " + .$roles.", the method ".$self->_get_method_names + ." must be implemented or excluded by '".$self->class_name."'"; + } + else + { + "Due to method name conflicts in roles " + .$roles.", the methods ".$self->_get_method_names + ." must be implemented or excluded by '".$self->class_name."'"; + } +} + +1; diff --git a/lib/Moose/Exception/MethodNameNotFoundInInheritanceHierarchy.pm b/lib/Moose/Exception/MethodNameNotFoundInInheritanceHierarchy.pm new file mode 100644 index 0000000..a724809 --- /dev/null +++ b/lib/Moose/Exception/MethodNameNotFoundInInheritanceHierarchy.pm @@ -0,0 +1,19 @@ +package Moose::Exception::MethodNameNotFoundInInheritanceHierarchy; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "The method '".$self->method_name."' was not found in the inheritance hierarchy for ".$self->class_name; +} + +1; diff --git a/lib/Moose/Exception/MethodNameNotGiven.pm b/lib/Moose/Exception/MethodNameNotGiven.pm new file mode 100644 index 0000000..e39ef0f --- /dev/null +++ b/lib/Moose/Exception/MethodNameNotGiven.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MethodNameNotGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must define a method name to find"; +} + +1; diff --git a/lib/Moose/Exception/MustDefineAMethodName.pm b/lib/Moose/Exception/MustDefineAMethodName.pm new file mode 100644 index 0000000..29d9114 --- /dev/null +++ b/lib/Moose/Exception/MustDefineAMethodName.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustDefineAMethodName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +sub _build_message { + "You must define a method name"; +} + +1; diff --git a/lib/Moose/Exception/MustDefineAnAttributeName.pm b/lib/Moose/Exception/MustDefineAnAttributeName.pm new file mode 100644 index 0000000..2d818f7 --- /dev/null +++ b/lib/Moose/Exception/MustDefineAnAttributeName.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustDefineAnAttributeName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must define an attribute name"; +} + +1; diff --git a/lib/Moose/Exception/MustDefineAnOverloadOperator.pm b/lib/Moose/Exception/MustDefineAnOverloadOperator.pm new file mode 100644 index 0000000..e133c90 --- /dev/null +++ b/lib/Moose/Exception/MustDefineAnOverloadOperator.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustDefineAnOverloadOperator; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Instance'; + +sub _build_message { + "You must define an overload operator"; +} + +1; diff --git a/lib/Moose/Exception/MustHaveAtLeastOneValueToEnumerate.pm b/lib/Moose/Exception/MustHaveAtLeastOneValueToEnumerate.pm new file mode 100644 index 0000000..0a9b599 --- /dev/null +++ b/lib/Moose/Exception/MustHaveAtLeastOneValueToEnumerate.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustHaveAtLeastOneValueToEnumerate; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must have at least one value to enumerate through"; +} + +1; diff --git a/lib/Moose/Exception/MustPassAHashOfOptions.pm b/lib/Moose/Exception/MustPassAHashOfOptions.pm new file mode 100644 index 0000000..db4a305 --- /dev/null +++ b/lib/Moose/Exception/MustPassAHashOfOptions.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustPassAHashOfOptions; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must pass a hash of options"; +} + +1; diff --git a/lib/Moose/Exception/MustPassAMooseMetaRoleInstanceOrSubclass.pm b/lib/Moose/Exception/MustPassAMooseMetaRoleInstanceOrSubclass.pm new file mode 100644 index 0000000..b18fab0 --- /dev/null +++ b/lib/Moose/Exception/MustPassAMooseMetaRoleInstanceOrSubclass.pm @@ -0,0 +1,23 @@ +package Moose::Exception::MustPassAMooseMetaRoleInstanceOrSubclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'role' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "You must pass a Moose::Meta::Role instance (or a subclass)"; +} + +1; diff --git a/lib/Moose/Exception/MustPassAPackageNameOrAnExistingClassMOPPackageInstance.pm b/lib/Moose/Exception/MustPassAPackageNameOrAnExistingClassMOPPackageInstance.pm new file mode 100644 index 0000000..7da9364 --- /dev/null +++ b/lib/Moose/Exception/MustPassAPackageNameOrAnExistingClassMOPPackageInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustPassAPackageNameOrAnExistingClassMOPPackageInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + "You must pass a package name or an existing Class::MOP::Package instance"; +} + +1; diff --git a/lib/Moose/Exception/MustPassEvenNumberOfArguments.pm b/lib/Moose/Exception/MustPassEvenNumberOfArguments.pm new file mode 100644 index 0000000..080645e --- /dev/null +++ b/lib/Moose/Exception/MustPassEvenNumberOfArguments.pm @@ -0,0 +1,24 @@ +package Moose::Exception::MustPassEvenNumberOfArguments; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'args' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You must pass an even number of arguments to ".$self->method_name; +} + +1; diff --git a/lib/Moose/Exception/MustPassEvenNumberOfAttributeOptions.pm b/lib/Moose/Exception/MustPassEvenNumberOfAttributeOptions.pm new file mode 100644 index 0000000..090227b --- /dev/null +++ b/lib/Moose/Exception/MustPassEvenNumberOfAttributeOptions.pm @@ -0,0 +1,23 @@ +package Moose::Exception::MustPassEvenNumberOfAttributeOptions; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'options' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + return 'You must pass an even number of attribute options'; +} + +1; diff --git a/lib/Moose/Exception/MustProvideANameForTheAttribute.pm b/lib/Moose/Exception/MustProvideANameForTheAttribute.pm new file mode 100644 index 0000000..d5a48ff --- /dev/null +++ b/lib/Moose/Exception/MustProvideANameForTheAttribute.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustProvideANameForTheAttribute; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must provide a name for the attribute"; +} + +1; diff --git a/lib/Moose/Exception/MustSpecifyAtleastOneMethod.pm b/lib/Moose/Exception/MustSpecifyAtleastOneMethod.pm new file mode 100644 index 0000000..006a4e6 --- /dev/null +++ b/lib/Moose/Exception/MustSpecifyAtleastOneMethod.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustSpecifyAtleastOneMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +sub _build_message { + "Must specify at least one method"; +} + +1; diff --git a/lib/Moose/Exception/MustSpecifyAtleastOneRole.pm b/lib/Moose/Exception/MustSpecifyAtleastOneRole.pm new file mode 100644 index 0000000..dee07fc --- /dev/null +++ b/lib/Moose/Exception/MustSpecifyAtleastOneRole.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustSpecifyAtleastOneRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +sub _build_message { + "Must specify at least one role"; +} + +1; diff --git a/lib/Moose/Exception/MustSpecifyAtleastOneRoleToApplicant.pm b/lib/Moose/Exception/MustSpecifyAtleastOneRoleToApplicant.pm new file mode 100644 index 0000000..38c5248 --- /dev/null +++ b/lib/Moose/Exception/MustSpecifyAtleastOneRoleToApplicant.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSpecifyAtleastOneRoleToApplicant; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'applicant' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + my $self = shift; + "Must specify at least one role to apply to ".$self->applicant; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyAClassMOPAttributeInstance.pm b/lib/Moose/Exception/MustSupplyAClassMOPAttributeInstance.pm new file mode 100644 index 0000000..d34a93d --- /dev/null +++ b/lib/Moose/Exception/MustSupplyAClassMOPAttributeInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSupplyAClassMOPAttributeInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply an attribute which is a 'Class::MOP::Attribute' instance"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyADelegateToMethod.pm b/lib/Moose/Exception/MustSupplyADelegateToMethod.pm new file mode 100644 index 0000000..f86f8d2 --- /dev/null +++ b/lib/Moose/Exception/MustSupplyADelegateToMethod.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSupplyADelegateToMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply a delegate_to_method which is a method name or a CODE reference"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyAMetaclass.pm b/lib/Moose/Exception/MustSupplyAMetaclass.pm new file mode 100644 index 0000000..fbb876a --- /dev/null +++ b/lib/Moose/Exception/MustSupplyAMetaclass.pm @@ -0,0 +1,19 @@ +package Moose::Exception::MustSupplyAMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You must pass a metaclass instance if you want to inline"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyAMooseMetaAttributeInstance.pm b/lib/Moose/Exception/MustSupplyAMooseMetaAttributeInstance.pm new file mode 100644 index 0000000..83d1c72 --- /dev/null +++ b/lib/Moose/Exception/MustSupplyAMooseMetaAttributeInstance.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSupplyAMooseMetaAttributeInstance; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply an attribute which is a 'Moose::Meta::Attribute' instance"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyAnAccessorTypeToConstructWith.pm b/lib/Moose/Exception/MustSupplyAnAccessorTypeToConstructWith.pm new file mode 100644 index 0000000..29b09ff --- /dev/null +++ b/lib/Moose/Exception/MustSupplyAnAccessorTypeToConstructWith.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSupplyAnAccessorTypeToConstructWith; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply an accessor_type to construct with"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyAnAttributeToConstructWith.pm b/lib/Moose/Exception/MustSupplyAnAttributeToConstructWith.pm new file mode 100644 index 0000000..c43b1a7 --- /dev/null +++ b/lib/Moose/Exception/MustSupplyAnAttributeToConstructWith.pm @@ -0,0 +1,18 @@ +package Moose::Exception::MustSupplyAnAttributeToConstructWith; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply an attribute to construct with"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyArrayRefAsCurriedArguments.pm b/lib/Moose/Exception/MustSupplyArrayRefAsCurriedArguments.pm new file mode 100644 index 0000000..65fb9f9 --- /dev/null +++ b/lib/Moose/Exception/MustSupplyArrayRefAsCurriedArguments.pm @@ -0,0 +1,12 @@ +package Moose::Exception::MustSupplyArrayRefAsCurriedArguments; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash', 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must supply a curried_arguments which is an ARRAY reference"; +} + +1; diff --git a/lib/Moose/Exception/MustSupplyPackageNameAndName.pm b/lib/Moose/Exception/MustSupplyPackageNameAndName.pm new file mode 100644 index 0000000..3533397 --- /dev/null +++ b/lib/Moose/Exception/MustSupplyPackageNameAndName.pm @@ -0,0 +1,19 @@ +package Moose::Exception::MustSupplyPackageNameAndName; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You must supply the package_name and name parameters"; +} + +1; diff --git a/lib/Moose/Exception/NeedsTypeConstraintUnionForTypeCoercionUnion.pm b/lib/Moose/Exception/NeedsTypeConstraintUnionForTypeCoercionUnion.pm new file mode 100644 index 0000000..c19b23d --- /dev/null +++ b/lib/Moose/Exception/NeedsTypeConstraintUnionForTypeCoercionUnion.pm @@ -0,0 +1,24 @@ +package Moose::Exception::NeedsTypeConstraintUnionForTypeCoercionUnion; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +# use Moose::Util::TypeConstraints 'find_type_constraint'; + +has 'type_coercion_union_object' => ( + is => 'ro', + isa => 'Moose::Meta::TypeCoercion::Union', + required => 1 +); + +sub _build_message { + my $self = shift; + my $type_constraint = $self->type_name; + + return "You can only create a Moose::Meta::TypeCoercion::Union for a " . + "Moose::Meta::TypeConstraint::Union, not a $type_constraint" +} + +1; diff --git a/lib/Moose/Exception/NeitherAttributeNorAttributeNameIsGiven.pm b/lib/Moose/Exception/NeitherAttributeNorAttributeNameIsGiven.pm new file mode 100644 index 0000000..c482bea --- /dev/null +++ b/lib/Moose/Exception/NeitherAttributeNorAttributeNameIsGiven.pm @@ -0,0 +1,11 @@ +package Moose::Exception::NeitherAttributeNorAttributeNameIsGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You need to give attribute or attribute_name or both"; +} + +1; diff --git a/lib/Moose/Exception/NeitherClassNorClassNameIsGiven.pm b/lib/Moose/Exception/NeitherClassNorClassNameIsGiven.pm new file mode 100644 index 0000000..e6c2a41 --- /dev/null +++ b/lib/Moose/Exception/NeitherClassNorClassNameIsGiven.pm @@ -0,0 +1,11 @@ +package Moose::Exception::NeitherClassNorClassNameIsGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You need to give class or class_name or both"; +} + +1; diff --git a/lib/Moose/Exception/NeitherRoleNorRoleNameIsGiven.pm b/lib/Moose/Exception/NeitherRoleNorRoleNameIsGiven.pm new file mode 100644 index 0000000..71cd416 --- /dev/null +++ b/lib/Moose/Exception/NeitherRoleNorRoleNameIsGiven.pm @@ -0,0 +1,11 @@ +package Moose::Exception::NeitherRoleNorRoleNameIsGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You need to give role or role_name or both"; +} + +1; diff --git a/lib/Moose/Exception/NeitherTypeNorTypeNameIsGiven.pm b/lib/Moose/Exception/NeitherTypeNorTypeNameIsGiven.pm new file mode 100644 index 0000000..115adc7 --- /dev/null +++ b/lib/Moose/Exception/NeitherTypeNorTypeNameIsGiven.pm @@ -0,0 +1,11 @@ +package Moose::Exception::NeitherTypeNorTypeNameIsGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You need to give type or type_name or both"; +} + +1; diff --git a/lib/Moose/Exception/NoAttributeFoundInSuperClass.pm b/lib/Moose/Exception/NoAttributeFoundInSuperClass.pm new file mode 100644 index 0000000..3cb66ed --- /dev/null +++ b/lib/Moose/Exception/NoAttributeFoundInSuperClass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::NoAttributeFoundInSuperClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "Could not find an attribute by the name of '".$self->attribute_name."' to inherit from in ".$self->class_name; +} + +1; diff --git a/lib/Moose/Exception/NoBodyToInitializeInAnAbstractBaseClass.pm b/lib/Moose/Exception/NoBodyToInitializeInAnAbstractBaseClass.pm new file mode 100644 index 0000000..55b88c9 --- /dev/null +++ b/lib/Moose/Exception/NoBodyToInitializeInAnAbstractBaseClass.pm @@ -0,0 +1,18 @@ +package Moose::Exception::NoBodyToInitializeInAnAbstractBaseClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'package_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "No body to initialize, " .$self->package_name. " is an abstract base class"; +} + +1; diff --git a/lib/Moose/Exception/NoCasesMatched.pm b/lib/Moose/Exception/NoCasesMatched.pm new file mode 100644 index 0000000..33672a0 --- /dev/null +++ b/lib/Moose/Exception/NoCasesMatched.pm @@ -0,0 +1,26 @@ +package Moose::Exception::NoCasesMatched; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'to_match' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'cases_to_be_matched' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + my $self = shift; + my $to_match = $self->to_match; + + return "No cases matched for $to_match"; +} + +1; diff --git a/lib/Moose/Exception/NoConstraintCheckForTypeConstraint.pm b/lib/Moose/Exception/NoConstraintCheckForTypeConstraint.pm new file mode 100644 index 0000000..d50cc5c --- /dev/null +++ b/lib/Moose/Exception/NoConstraintCheckForTypeConstraint.pm @@ -0,0 +1,13 @@ +package Moose::Exception::NoConstraintCheckForTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + my $self = shift; + "Could not compile type constraint '".$self->type_name."' because no constraint check"; +} + +1; diff --git a/lib/Moose/Exception/NoDestructorClassSpecified.pm b/lib/Moose/Exception/NoDestructorClassSpecified.pm new file mode 100644 index 0000000..8d90d12 --- /dev/null +++ b/lib/Moose/Exception/NoDestructorClassSpecified.pm @@ -0,0 +1,12 @@ +package Moose::Exception::NoDestructorClassSpecified; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::ParamsHash'; + +sub _build_message { + "The 'inline_destructor' option is present, but no destructor class was specified"; +} + +1; diff --git a/lib/Moose/Exception/NoImmutableTraitSpecifiedForClass.pm b/lib/Moose/Exception/NoImmutableTraitSpecifiedForClass.pm new file mode 100644 index 0000000..2fe1c85 --- /dev/null +++ b/lib/Moose/Exception/NoImmutableTraitSpecifiedForClass.pm @@ -0,0 +1,16 @@ +package Moose::Exception::NoImmutableTraitSpecifiedForClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::ParamsHash'; + +use Moose::Util 'find_meta'; + +sub _build_message { + my $self = shift; + my $class = find_meta( $self->class_name ); + "no immutable trait specified for $class"; +} + +1; diff --git a/lib/Moose/Exception/NoParentGivenToSubtype.pm b/lib/Moose/Exception/NoParentGivenToSubtype.pm new file mode 100644 index 0000000..799320b --- /dev/null +++ b/lib/Moose/Exception/NoParentGivenToSubtype.pm @@ -0,0 +1,17 @@ +package Moose::Exception::NoParentGivenToSubtype; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "A subtype cannot consist solely of a name, it must have a parent"; +} + +1; diff --git a/lib/Moose/Exception/OnlyInstancesCanBeCloned.pm b/lib/Moose/Exception/OnlyInstancesCanBeCloned.pm new file mode 100644 index 0000000..3f0b899 --- /dev/null +++ b/lib/Moose/Exception/OnlyInstancesCanBeCloned.pm @@ -0,0 +1,19 @@ +package Moose::Exception::OnlyInstancesCanBeCloned; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::ParamsHash'; + +has 'instance' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + my $self = shift; + "You can only clone instances, (".$self->instance.") is not a blessed instance"; +} + +1; diff --git a/lib/Moose/Exception/OperatorIsRequired.pm b/lib/Moose/Exception/OperatorIsRequired.pm new file mode 100644 index 0000000..d14a846 --- /dev/null +++ b/lib/Moose/Exception/OperatorIsRequired.pm @@ -0,0 +1,18 @@ +package Moose::Exception::OperatorIsRequired; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "operator is required"; +} + +1; diff --git a/lib/Moose/Exception/OverloadConflictInSummation.pm b/lib/Moose/Exception/OverloadConflictInSummation.pm new file mode 100644 index 0000000..0292326 --- /dev/null +++ b/lib/Moose/Exception/OverloadConflictInSummation.pm @@ -0,0 +1,61 @@ +package Moose::Exception::OverloadConflictInSummation; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +use Moose::Util 'find_meta'; + +has 'role_application' => ( + is => 'ro', + isa => 'Moose::Meta::Role::Application::RoleSummation', + required => 1 +); + +has 'role_names' => ( + traits => ['Array'], + is => 'bare', + isa => 'ArrayRef[Str]', + handles => { + role_names => 'elements', + }, + required => 1, + documentation => + "This attribute is an ArrayRef containing role names, if you want metaobjects\n" + . "associated with these role names, then call method roles on the exception object.\n", +); + +has 'overloaded_op' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub roles { + my $self = shift; + my @role_names = $self->role_names; + my @roles = map { find_meta($_) } @role_names; + return @roles; +} + +sub _build_message { + my $self = shift; + + my @roles = $self->role_names; + my $role_names = join "|", @roles; + + my $op = $self->overloaded_op; + if ( $op eq 'fallback' ) { + return + 'We have encountered an overloading conflict for the fallback ' + . 'during composition. This is a fatal error.'; + } + else { + return + "Role '$role_names' has encountered an overloading conflict " + . "during composition. The two roles both overload the '$op' operator. " + . 'This is a fatal error.'; + } +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresAMetaClass.pm b/lib/Moose/Exception/OverloadRequiresAMetaClass.pm new file mode 100644 index 0000000..1f41861 --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresAMetaClass.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresAMetaClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'If you provide an associated_metaclass parameter to the Moose::Meta::Overload constructor it must be a Class::MOP::Module object'; +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresAMetaMethod.pm b/lib/Moose/Exception/OverloadRequiresAMetaMethod.pm new file mode 100644 index 0000000..67ee8ee --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresAMetaMethod.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresAMetaMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'If you provide a method parameter to the Moose::Meta::Overload constructor it must be a Class::MOP::Method object'; +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresAMetaOverload.pm b/lib/Moose/Exception/OverloadRequiresAMetaOverload.pm new file mode 100644 index 0000000..5545d74 --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresAMetaOverload.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresAMetaOverload; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'If you provide an original_overload parameter to the Moose::Meta::Overload constructor it must be a Moose::Meta::Overload object'; +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresAMethodNameOrCoderef.pm b/lib/Moose/Exception/OverloadRequiresAMethodNameOrCoderef.pm new file mode 100644 index 0000000..dd8c1f9 --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresAMethodNameOrCoderef.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresAMethodNameOrCoderef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'You must provide a method_name or coderef parameter when constructing a Moose::Meta::Overload object'; +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresAnOperator.pm b/lib/Moose/Exception/OverloadRequiresAnOperator.pm new file mode 100644 index 0000000..7952920 --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresAnOperator.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresAnOperator; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'You must provide an operator parameter when constructing a Moose::Meta::Overload object'; +} + +1; diff --git a/lib/Moose/Exception/OverloadRequiresNamesForCoderef.pm b/lib/Moose/Exception/OverloadRequiresNamesForCoderef.pm new file mode 100644 index 0000000..82401d0 --- /dev/null +++ b/lib/Moose/Exception/OverloadRequiresNamesForCoderef.pm @@ -0,0 +1,12 @@ +package Moose::Exception::OverloadRequiresNamesForCoderef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + my $self = shift; + 'If you provide a coderef parameter to the Moose::Meta::Overload constructor you must also provide coderef_package and coderef_name parameters'; +} + +1; diff --git a/lib/Moose/Exception/OverrideConflictInComposition.pm b/lib/Moose/Exception/OverrideConflictInComposition.pm new file mode 100644 index 0000000..44bfd78 --- /dev/null +++ b/lib/Moose/Exception/OverrideConflictInComposition.pm @@ -0,0 +1,42 @@ +package Moose::Exception::OverrideConflictInComposition; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'role_being_applied_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'two_overrides_found' => ( + is => 'ro', + isa => 'Bool', + required => 1, + default => 0 +); + +sub _build_message { + my $self = shift; + + if( $self->two_overrides_found ) { + return "Role '" . $self->role_being_applied_name . "' has encountered an 'override' method conflict " . + "during composition (Two 'override' methods of the same name encountered). " . + "This is a fatal error."; + } + else { + return "Role '".$self->role_being_applied_name."' has encountered an 'override' method conflict ". + "during composition (A local method of the same name as been found). ". + "This is a fatal error."; + } +} + +1; diff --git a/lib/Moose/Exception/OverrideConflictInSummation.pm b/lib/Moose/Exception/OverrideConflictInSummation.pm new file mode 100644 index 0000000..e88d9cc --- /dev/null +++ b/lib/Moose/Exception/OverrideConflictInSummation.pm @@ -0,0 +1,65 @@ +package Moose::Exception::OverrideConflictInSummation; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +use Moose::Util 'find_meta'; + +has 'role_application' => ( + is => 'ro', + isa => 'Moose::Meta::Role::Application::RoleSummation', + required => 1 +); + +has 'role_names' => ( + traits => ['Array'], + is => 'bare', + isa => 'ArrayRef[Str]', + handles => { + role_names => 'elements', + }, + required => 1, + documentation => "This attribute is an ArrayRef containing role names, if you want metaobjects\n". + "associated with these role names, then call method roles on the exception object.\n", +); + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'two_overrides_found' => ( + is => 'ro', + isa => 'Bool', + required => 1, + default => 0 +); + +sub roles { + my $self = shift; + my @role_names = $self->role_names; + my @roles = map { find_meta($_) } @role_names; + return @roles; +} + +sub _build_message { + my $self = shift; + + my @roles = $self->role_names; + my $role_names = join "|", @roles; + + if( $self->two_overrides_found ) { + return "We have encountered an 'override' method conflict ". + "during composition (Two 'override' methods of the same name encountered). ". + "This is a fatal error."; + } + else { + return "Role '$role_names' has encountered an 'override' method conflict " . + "during composition (A local method of the same name has been found). This " . + "is a fatal error." ; + } +} + +1; diff --git a/lib/Moose/Exception/PackageDoesNotUseMooseExporter.pm b/lib/Moose/Exception/PackageDoesNotUseMooseExporter.pm new file mode 100644 index 0000000..acd8ea6 --- /dev/null +++ b/lib/Moose/Exception/PackageDoesNotUseMooseExporter.pm @@ -0,0 +1,27 @@ +package Moose::Exception::PackageDoesNotUseMooseExporter; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'package' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'is_loaded' => ( + is => 'ro', + isa => 'Bool', + required => 1 +); + +sub _build_message { + my $self = shift; + my $package = $self->package; + return "Package in also ($package) does not seem to " + . "use Moose::Exporter" + . ( $self->is_loaded ? "" : " (is it loaded?)" ); +} + +1; diff --git a/lib/Moose/Exception/PackageNameAndNameParamsNotGivenToWrap.pm b/lib/Moose/Exception/PackageNameAndNameParamsNotGivenToWrap.pm new file mode 100644 index 0000000..efdb7ef --- /dev/null +++ b/lib/Moose/Exception/PackageNameAndNameParamsNotGivenToWrap.pm @@ -0,0 +1,24 @@ +package Moose::Exception::PackageNameAndNameParamsNotGivenToWrap; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'code' => ( + is => 'ro', + isa => 'CodeRef', + required => 1 +); + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "You must supply the package_name and name parameters"; +} + +1; diff --git a/lib/Moose/Exception/PackagesAndModulesAreNotCachable.pm b/lib/Moose/Exception/PackagesAndModulesAreNotCachable.pm new file mode 100644 index 0000000..901f635 --- /dev/null +++ b/lib/Moose/Exception/PackagesAndModulesAreNotCachable.pm @@ -0,0 +1,25 @@ +package Moose::Exception::PackagesAndModulesAreNotCachable; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::ParamsHash'; + +has 'is_module' => ( + is => 'ro', + isa => 'Bool', + required => 1 +); + +sub _build_message { + my $self = shift; + my $is_module = $self->is_module; + + if( $is_module ) { + return "Modules are not cacheable"; + } else { + return "Packages are not cacheable"; + } +} + +1; diff --git a/lib/Moose/Exception/ParameterIsNotSubtypeOfParent.pm b/lib/Moose/Exception/ParameterIsNotSubtypeOfParent.pm new file mode 100644 index 0000000..edc7280 --- /dev/null +++ b/lib/Moose/Exception/ParameterIsNotSubtypeOfParent.pm @@ -0,0 +1,25 @@ +package Moose::Exception::ParameterIsNotSubtypeOfParent; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +use Moose::Util::TypeConstraints qw/find_type_constraint/; + +has 'type_parameter' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $type_parameter = $self->type_parameter; + my $type = find_type_constraint( $self->type_name ); + my $parent = $type->parent->type_parameter; + + return "$type_parameter is not a subtype of $parent"; +} + +1; diff --git a/lib/Moose/Exception/ReferencesAreNotAllowedAsDefault.pm b/lib/Moose/Exception/ReferencesAreNotAllowedAsDefault.pm new file mode 100644 index 0000000..1a460c1 --- /dev/null +++ b/lib/Moose/Exception/ReferencesAreNotAllowedAsDefault.pm @@ -0,0 +1,26 @@ +package Moose::Exception::ReferencesAreNotAllowedAsDefault; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "References are not allowed as default values, you must wrap the default of '". + $self->attribute_name."' in a CODE reference (ex: sub { [] } and not [])"; +} + +1; diff --git a/lib/Moose/Exception/RequiredAttributeLacksInitialization.pm b/lib/Moose/Exception/RequiredAttributeLacksInitialization.pm new file mode 100644 index 0000000..9282048 --- /dev/null +++ b/lib/Moose/Exception/RequiredAttributeLacksInitialization.pm @@ -0,0 +1,18 @@ +package Moose::Exception::RequiredAttributeLacksInitialization; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + "A required attribute must have either 'init_arg', 'builder', or 'default'"; +} + +1; diff --git a/lib/Moose/Exception/RequiredAttributeNeedsADefault.pm b/lib/Moose/Exception/RequiredAttributeNeedsADefault.pm new file mode 100644 index 0000000..d823852 --- /dev/null +++ b/lib/Moose/Exception/RequiredAttributeNeedsADefault.pm @@ -0,0 +1,13 @@ +package Moose::Exception::RequiredAttributeNeedsADefault; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "You cannot have a required attribute (".$self->attribute_name.") without a default, builder, or an init_arg"; +} + +1; diff --git a/lib/Moose/Exception/RequiredMethodsImportedByClass.pm b/lib/Moose/Exception/RequiredMethodsImportedByClass.pm new file mode 100644 index 0000000..262883e --- /dev/null +++ b/lib/Moose/Exception/RequiredMethodsImportedByClass.pm @@ -0,0 +1,45 @@ +package Moose::Exception::RequiredMethodsImportedByClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Role'; + +has 'missing_methods' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Moose::Meta::Role::Method::Required]', + handles => { method_count => 'count', + get_method_at => 'get', + get_all_methods => 'elements', + }, + required => 1 +); + +has 'imported_method' => ( + is => 'ro', + isa => 'Moose::Meta::Role::Method::Required', + required => 1 +); + +sub _build_message { + my $self = shift; + + my $noun = $self->method_count == 1 ? 'method' : 'methods'; + my $list = Moose::Util::english_list( map { q{'} . $_ . q{'} } $self->get_all_methods ); + + my ($class, $role, $method) = ($self->class_name, + $self->role_name, + $self->imported_method); + + my ($class_quoted, $role_quoted) = ("'".$class."'","'".$role."'"); + + "$role_quoted requires the $noun $list " + . "to be implemented by $class_quoted. " + . "If you imported functions intending to use them as " + . "methods, you need to explicitly mark them as such, via " + . "$class->meta->add_method($method" + . " => \\&$method)"; +} + +1; diff --git a/lib/Moose/Exception/RequiredMethodsNotImplementedByClass.pm b/lib/Moose/Exception/RequiredMethodsNotImplementedByClass.pm new file mode 100644 index 0000000..541c169 --- /dev/null +++ b/lib/Moose/Exception/RequiredMethodsNotImplementedByClass.pm @@ -0,0 +1,30 @@ +package Moose::Exception::RequiredMethodsNotImplementedByClass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class', 'Moose::Exception::Role::Role'; + +has 'missing_methods' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Moose::Meta::Role::Method::Required]', + handles => { method_count => 'count', + get_method_at => 'get', + get_all_methods => 'elements', + }, + required => 1 +); + +sub _build_message { + my $self = shift; + + my $noun = $self->method_count == 1 ? 'method' : 'methods'; + my $list = Moose::Util::english_list( map { q{'} . $_ . q{'} } $self->get_all_methods ); + my ($role_name, $class_name) = ($self->role_name, $self->class_name); + + return "'$role_name' requires the $noun $list " + . "to be implemented by '$class_name'"; +} + +1; diff --git a/lib/Moose/Exception/Role/Attribute.pm b/lib/Moose/Exception/Role/Attribute.pm new file mode 100644 index 0000000..02d0c5d --- /dev/null +++ b/lib/Moose/Exception/Role/Attribute.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::Attribute; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'attribute' => ( + is => 'ro', + isa => 'Class::MOP::Attribute', + predicate => 'is_attribute_set' +); + +1; diff --git a/lib/Moose/Exception/Role/AttributeName.pm b/lib/Moose/Exception/Role/AttributeName.pm new file mode 100644 index 0000000..b00f41e --- /dev/null +++ b/lib/Moose/Exception/Role/AttributeName.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::AttributeName; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +1; diff --git a/lib/Moose/Exception/Role/Class.pm b/lib/Moose/Exception/Role/Class.pm new file mode 100644 index 0000000..c523997 --- /dev/null +++ b/lib/Moose/Exception/Role/Class.pm @@ -0,0 +1,14 @@ +package Moose::Exception::Role::Class; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'class_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching metaclass instance:\n". + " my \$metaclass_instance = Moose::Util::find_meta( \$exception->class_name );\n", +); + +1; diff --git a/lib/Moose/Exception/Role/EitherAttributeOrAttributeName.pm b/lib/Moose/Exception/Role/EitherAttributeOrAttributeName.pm new file mode 100644 index 0000000..5b76867 --- /dev/null +++ b/lib/Moose/Exception/Role/EitherAttributeOrAttributeName.pm @@ -0,0 +1,49 @@ +package Moose::Exception::Role::EitherAttributeOrAttributeName; +our $VERSION = '2.1405'; + +use Moose::Util 'throw_exception'; +use Moose::Role; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + lazy_build => 1 +); + +has 'attribute' => ( + is => 'ro', + isa => 'Class::MOP::Attribute', + predicate => 'has_attribute' +); + +has 'params' => ( + is => 'ro', + isa => 'HashRef', + predicate => 'has_params', +); + +sub _build_attribute_name { + my $self = shift; + + if( !$self->has_attribute ) + { + throw_exception("NeitherAttributeNorAttributeNameIsGiven"); + } + + return $self->attribute->name; +} + +after "BUILD" => sub { + my $self = $_[0]; + + if( $self->has_attribute_name && + $self->has_attribute && + ( $self->attribute->name ne $self->attribute_name ) ) + { + throw_exception( AttributeNamesDoNotMatch => attribute_name => $self->attribute_name, + attribute => $self->attribute + ); + } +}; + +1; diff --git a/lib/Moose/Exception/Role/Instance.pm b/lib/Moose/Exception/Role/Instance.pm new file mode 100644 index 0000000..e3c094e --- /dev/null +++ b/lib/Moose/Exception/Role/Instance.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::Instance; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'instance' => ( + is => 'ro', + isa => 'Object', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/InstanceClass.pm b/lib/Moose/Exception/Role/InstanceClass.pm new file mode 100644 index 0000000..e74a33f --- /dev/null +++ b/lib/Moose/Exception/Role/InstanceClass.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::InstanceClass; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'instance_class' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/InvalidAttributeOptions.pm b/lib/Moose/Exception/Role/InvalidAttributeOptions.pm new file mode 100644 index 0000000..9a754ac --- /dev/null +++ b/lib/Moose/Exception/Role/InvalidAttributeOptions.pm @@ -0,0 +1,13 @@ +package Moose::Exception::Role::InvalidAttributeOptions; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Exception::Role::ParamsHash'; + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/Method.pm b/lib/Moose/Exception/Role/Method.pm new file mode 100644 index 0000000..b2a1f4b --- /dev/null +++ b/lib/Moose/Exception/Role/Method.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::Method; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'method' => ( + is => 'ro', + isa => 'Moose::Meta::Method', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/ParamsHash.pm b/lib/Moose/Exception/Role/ParamsHash.pm new file mode 100644 index 0000000..02b6bf9 --- /dev/null +++ b/lib/Moose/Exception/Role/ParamsHash.pm @@ -0,0 +1,12 @@ +package Moose::Exception::Role::ParamsHash; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'params' => ( + is => 'ro', + isa => 'HashRef', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/Role.pm b/lib/Moose/Exception/Role/Role.pm new file mode 100644 index 0000000..c787234 --- /dev/null +++ b/lib/Moose/Exception/Role/Role.pm @@ -0,0 +1,16 @@ +package Moose::Exception::Role::Role; +our $VERSION = '2.1405'; + +# use Moose::Util 'throw_exception'; +use Moose::Role; + +has 'role_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching metaclass instance:\n". + " my \$metaclass_instance = Moose::Util::find_meta( \$exception->role_name );\n", + +); + +1; diff --git a/lib/Moose/Exception/Role/RoleForCreate.pm b/lib/Moose/Exception/Role/RoleForCreate.pm new file mode 100644 index 0000000..23e6b12 --- /dev/null +++ b/lib/Moose/Exception/Role/RoleForCreate.pm @@ -0,0 +1,13 @@ +package Moose::Exception::Role::RoleForCreate; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Exception::Role::ParamsHash'; + +has 'attribute_class' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/RoleForCreateMOPClass.pm b/lib/Moose/Exception/Role/RoleForCreateMOPClass.pm new file mode 100644 index 0000000..a9a07c0 --- /dev/null +++ b/lib/Moose/Exception/Role/RoleForCreateMOPClass.pm @@ -0,0 +1,13 @@ +package Moose::Exception::Role::RoleForCreateMOPClass; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +1; diff --git a/lib/Moose/Exception/Role/TypeConstraint.pm b/lib/Moose/Exception/Role/TypeConstraint.pm new file mode 100644 index 0000000..cd73986 --- /dev/null +++ b/lib/Moose/Exception/Role/TypeConstraint.pm @@ -0,0 +1,14 @@ +package Moose::Exception::Role::TypeConstraint; +our $VERSION = '2.1405'; + +use Moose::Role; + +has 'type_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching type constraint(Moose::Meta::TypeConstraint):\n". + " my \$type_constraint = Moose::Util::TypeConstraints::find_type_constraint( \$exception->type_name );\n", +); + +1; diff --git a/lib/Moose/Exception/RoleDoesTheExcludedRole.pm b/lib/Moose/Exception/RoleDoesTheExcludedRole.pm new file mode 100644 index 0000000..e0f5d3a --- /dev/null +++ b/lib/Moose/Exception/RoleDoesTheExcludedRole.pm @@ -0,0 +1,27 @@ +package Moose::Exception::RoleDoesTheExcludedRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'excluded_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'second_role_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + my $role_name = $self->role_name; + my $excluded_role_name = $self->excluded_role_name; + return "The role $role_name does the excluded role '$excluded_role_name'"; +} + +1; diff --git a/lib/Moose/Exception/RoleExclusionConflict.pm b/lib/Moose/Exception/RoleExclusionConflict.pm new file mode 100644 index 0000000..210ec90 --- /dev/null +++ b/lib/Moose/Exception/RoleExclusionConflict.pm @@ -0,0 +1,26 @@ +package Moose::Exception::RoleExclusionConflict; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'roles' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1, +); + +sub _build_message { + my $self = shift; + + my @roles_array = @{$self->roles}; + my $role_noun = "Role".( @roles_array == 1 ? '' : 's'); + my $all_roles = join(', ', @roles_array); + my $verb = "exclude".( @roles_array == 1 ? 's' : '' ); + my $role_name = $self->role_name; + + return "Conflict detected: $role_noun $all_roles $verb role '$role_name'"; +} + +1; diff --git a/lib/Moose/Exception/RoleNameRequired.pm b/lib/Moose/Exception/RoleNameRequired.pm new file mode 100644 index 0000000..7a90e04 --- /dev/null +++ b/lib/Moose/Exception/RoleNameRequired.pm @@ -0,0 +1,12 @@ +package Moose::Exception::RoleNameRequired; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +sub _build_message { + "You must supply a role name to look for"; +} + +1; diff --git a/lib/Moose/Exception/RoleNameRequiredForMooseMetaRole.pm b/lib/Moose/Exception/RoleNameRequiredForMooseMetaRole.pm new file mode 100644 index 0000000..54f1340 --- /dev/null +++ b/lib/Moose/Exception/RoleNameRequiredForMooseMetaRole.pm @@ -0,0 +1,12 @@ +package Moose::Exception::RoleNameRequiredForMooseMetaRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +sub _build_message { + "You must supply a role name to look for"; +} + +1; diff --git a/lib/Moose/Exception/RolesDoNotSupportAugment.pm b/lib/Moose/Exception/RolesDoNotSupportAugment.pm new file mode 100644 index 0000000..91f366c --- /dev/null +++ b/lib/Moose/Exception/RolesDoNotSupportAugment.pm @@ -0,0 +1,11 @@ +package Moose::Exception::RolesDoNotSupportAugment; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "Roles cannot support 'augment'"; +} + +1; diff --git a/lib/Moose/Exception/RolesDoNotSupportExtends.pm b/lib/Moose/Exception/RolesDoNotSupportExtends.pm new file mode 100644 index 0000000..a18ceac --- /dev/null +++ b/lib/Moose/Exception/RolesDoNotSupportExtends.pm @@ -0,0 +1,11 @@ +package Moose::Exception::RolesDoNotSupportExtends; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "Roles do not support 'extends' (you can use 'with' to specialize a role)"; +} + +1; diff --git a/lib/Moose/Exception/RolesDoNotSupportInner.pm b/lib/Moose/Exception/RolesDoNotSupportInner.pm new file mode 100644 index 0000000..d075ae4 --- /dev/null +++ b/lib/Moose/Exception/RolesDoNotSupportInner.pm @@ -0,0 +1,11 @@ +package Moose::Exception::RolesDoNotSupportInner; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "Roles cannot support 'inner'"; +} + +1; diff --git a/lib/Moose/Exception/RolesDoNotSupportRegexReferencesForMethodModifiers.pm b/lib/Moose/Exception/RolesDoNotSupportRegexReferencesForMethodModifiers.pm new file mode 100644 index 0000000..89e5046 --- /dev/null +++ b/lib/Moose/Exception/RolesDoNotSupportRegexReferencesForMethodModifiers.pm @@ -0,0 +1,19 @@ +package Moose::Exception::RolesDoNotSupportRegexReferencesForMethodModifiers; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Role'; + +has 'modifier_type' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Roles do not currently support regex references for ".$self->modifier_type." method modifiers"; +} + +1; diff --git a/lib/Moose/Exception/RolesInCreateTakesAnArrayRef.pm b/lib/Moose/Exception/RolesInCreateTakesAnArrayRef.pm new file mode 100644 index 0000000..70ca26c --- /dev/null +++ b/lib/Moose/Exception/RolesInCreateTakesAnArrayRef.pm @@ -0,0 +1,13 @@ +package Moose::Exception::RolesInCreateTakesAnArrayRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +sub _build_message { + my $self = shift; + "You must pass an ARRAY ref of roles"; +} + +1; diff --git a/lib/Moose/Exception/RolesListMustBeInstancesOfMooseMetaRole.pm b/lib/Moose/Exception/RolesListMustBeInstancesOfMooseMetaRole.pm new file mode 100644 index 0000000..d06354a --- /dev/null +++ b/lib/Moose/Exception/RolesListMustBeInstancesOfMooseMetaRole.pm @@ -0,0 +1,25 @@ +package Moose::Exception::RolesListMustBeInstancesOfMooseMetaRole; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'role' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + "The list of roles must be instances of Moose::Meta::Role, not ".$self->role; +} + +1; diff --git a/lib/Moose/Exception/SingleParamsToNewMustBeHashRef.pm b/lib/Moose/Exception/SingleParamsToNewMustBeHashRef.pm new file mode 100644 index 0000000..d61073c --- /dev/null +++ b/lib/Moose/Exception/SingleParamsToNewMustBeHashRef.pm @@ -0,0 +1,11 @@ +package Moose::Exception::SingleParamsToNewMustBeHashRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "Single parameters to new() must be a HASH ref"; +} + +1; diff --git a/lib/Moose/Exception/TriggerMustBeACodeRef.pm b/lib/Moose/Exception/TriggerMustBeACodeRef.pm new file mode 100644 index 0000000..3af0d3f --- /dev/null +++ b/lib/Moose/Exception/TriggerMustBeACodeRef.pm @@ -0,0 +1,13 @@ +package Moose::Exception::TriggerMustBeACodeRef; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::InvalidAttributeOptions'; + +sub _build_message { + my $self = shift; + "Trigger must be a CODE ref on attribute (".$self->attribute_name.")"; +} + +1; diff --git a/lib/Moose/Exception/TypeConstraintCannotBeUsedForAParameterizableType.pm b/lib/Moose/Exception/TypeConstraintCannotBeUsedForAParameterizableType.pm new file mode 100644 index 0000000..337a7df --- /dev/null +++ b/lib/Moose/Exception/TypeConstraintCannotBeUsedForAParameterizableType.pm @@ -0,0 +1,24 @@ +package Moose::Exception::TypeConstraintCannotBeUsedForAParameterizableType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +has 'parent_type_name' => ( + is => 'ro', + isa => 'Str', + required => 1, + documentation => "This attribute can be used for fetching type constraint(Moose::Meta::TypeConstraint):\n". + " my \$type_constraint = Moose::Util::TypeConstraints::find_type_constraint( \$exception->parent_type_name );\n", +); + +sub _build_message { + my $self = shift; + my $type_name = $self->type_name; + my $parent_type_name = $self->parent_type_name; + "The $type_name constraint cannot be used, because " + . "$parent_type_name doesn't subtype or coerce from a parameterizable type."; +} + +1; diff --git a/lib/Moose/Exception/TypeConstraintIsAlreadyCreated.pm b/lib/Moose/Exception/TypeConstraintIsAlreadyCreated.pm new file mode 100644 index 0000000..47d36a5 --- /dev/null +++ b/lib/Moose/Exception/TypeConstraintIsAlreadyCreated.pm @@ -0,0 +1,25 @@ +package Moose::Exception::TypeConstraintIsAlreadyCreated; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +use Moose::Util::TypeConstraints 'find_type_constraint'; + +has 'package_defined_in' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + my $type_name = $self->type_name; + my $type = find_type_constraint( $type_name ); + my $type_package_defined_in = $type->_package_defined_in; + my $package_defined_in = $self->package_defined_in; + return "The type constraint '$type_name' has already been created in $type_package_defined_in and cannot be created again in $package_defined_in"; +} + +1; diff --git a/lib/Moose/Exception/TypeParameterMustBeMooseMetaType.pm b/lib/Moose/Exception/TypeParameterMustBeMooseMetaType.pm new file mode 100644 index 0000000..f582290 --- /dev/null +++ b/lib/Moose/Exception/TypeParameterMustBeMooseMetaType.pm @@ -0,0 +1,12 @@ +package Moose::Exception::TypeParameterMustBeMooseMetaType; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::TypeConstraint'; + +sub _build_message { + "The type parameter must be a Moose meta type"; +} + +1; diff --git a/lib/Moose/Exception/UnableToCanonicalizeHandles.pm b/lib/Moose/Exception/UnableToCanonicalizeHandles.pm new file mode 100644 index 0000000..f546936 --- /dev/null +++ b/lib/Moose/Exception/UnableToCanonicalizeHandles.pm @@ -0,0 +1,19 @@ +package Moose::Exception::UnableToCanonicalizeHandles; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'handles' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +sub _build_message { + my $self = shift; + "Unable to canonicalize the 'handles' option with ".$self->handles; +} + +1; diff --git a/lib/Moose/Exception/UnableToCanonicalizeNonRolePackage.pm b/lib/Moose/Exception/UnableToCanonicalizeNonRolePackage.pm new file mode 100644 index 0000000..a6ef63a --- /dev/null +++ b/lib/Moose/Exception/UnableToCanonicalizeNonRolePackage.pm @@ -0,0 +1,19 @@ +package Moose::Exception::UnableToCanonicalizeNonRolePackage; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'handles' => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +sub _build_message { + my $self = shift; + "Unable to canonicalize the 'handles' option with ".$self->handles." because its metaclass is not a Moose::Meta::Role"; +} + +1; diff --git a/lib/Moose/Exception/UnableToRecognizeDelegateMetaclass.pm b/lib/Moose/Exception/UnableToRecognizeDelegateMetaclass.pm new file mode 100644 index 0000000..1a09b9e --- /dev/null +++ b/lib/Moose/Exception/UnableToRecognizeDelegateMetaclass.pm @@ -0,0 +1,21 @@ +package Moose::Exception::UnableToRecognizeDelegateMetaclass; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'delegate_metaclass' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +sub _build_message { + my $self = shift; + my $meta = $self->delegate_metaclass; + + return "Unable to recognize the delegate metaclass '$meta'"; +} + +1; diff --git a/lib/Moose/Exception/UndefinedHashKeysPassedToMethod.pm b/lib/Moose/Exception/UndefinedHashKeysPassedToMethod.pm new file mode 100644 index 0000000..c8349bf --- /dev/null +++ b/lib/Moose/Exception/UndefinedHashKeysPassedToMethod.pm @@ -0,0 +1,24 @@ +package Moose::Exception::UndefinedHashKeysPassedToMethod; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'hash_keys' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'method_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "Hash keys passed to ".$self->method_name." must be defined"; +} + +1; diff --git a/lib/Moose/Exception/UnionCalledWithAnArrayRefAndAdditionalArgs.pm b/lib/Moose/Exception/UnionCalledWithAnArrayRefAndAdditionalArgs.pm new file mode 100644 index 0000000..6aabad1 --- /dev/null +++ b/lib/Moose/Exception/UnionCalledWithAnArrayRefAndAdditionalArgs.pm @@ -0,0 +1,23 @@ +package Moose::Exception::UnionCalledWithAnArrayRefAndAdditionalArgs; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +has 'array' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +has 'args' => ( + is => 'ro', + isa => 'ArrayRef', + required => 1 +); + +sub _build_message { + "union called with an array reference and additional arguments"; +} + +1; diff --git a/lib/Moose/Exception/UnionTakesAtleastTwoTypeNames.pm b/lib/Moose/Exception/UnionTakesAtleastTwoTypeNames.pm new file mode 100644 index 0000000..282718d --- /dev/null +++ b/lib/Moose/Exception/UnionTakesAtleastTwoTypeNames.pm @@ -0,0 +1,11 @@ +package Moose::Exception::UnionTakesAtleastTwoTypeNames; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; + +sub _build_message { + "You must pass in at least 2 type names to make a union"; +} + +1; diff --git a/lib/Moose/Exception/ValidationFailedForInlineTypeConstraint.pm b/lib/Moose/Exception/ValidationFailedForInlineTypeConstraint.pm new file mode 100644 index 0000000..3ca0a7f --- /dev/null +++ b/lib/Moose/Exception/ValidationFailedForInlineTypeConstraint.pm @@ -0,0 +1,48 @@ +package Moose::Exception::ValidationFailedForInlineTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Class'; + +has 'type_constraint_message' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'attribute_name' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has 'value' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'new_member' => ( + is => 'ro', + isa => 'Bool', + default => 0, + predicate => 'is_a_new_member' +); + +sub _build_message { + my $self = shift; + + my $line1; + + if( $self->new_member ) { + $line1 = "A new member value for ".$self->attribute_name." does not pass its type constraint because: " + } + else { + $line1 = "Attribute (".$self->attribute_name.") does not pass the type constraint because: "; + } + + return $line1 . $self->type_constraint_message; +} + +1; diff --git a/lib/Moose/Exception/ValidationFailedForTypeConstraint.pm b/lib/Moose/Exception/ValidationFailedForTypeConstraint.pm new file mode 100644 index 0000000..d09b836 --- /dev/null +++ b/lib/Moose/Exception/ValidationFailedForTypeConstraint.pm @@ -0,0 +1,32 @@ +package Moose::Exception::ValidationFailedForTypeConstraint; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::Attribute'; + +has 'value' => ( + is => 'ro', + isa => 'Any', + required => 1, +); + +has 'type' => ( + is => 'ro', + isa => Moose::Util::TypeConstraints->duck_type(["get_message", "name"]), + required => 1 +); + +sub _build_message { + my $self = shift; + + my $error = $self->type->get_message( $self->value ); + + return $error unless $self->is_attribute_set; + + my $attribute_name = $self->attribute->name; + return + "Attribute ($attribute_name) does not pass the type constraint because: $error"; +} + +1; diff --git a/lib/Moose/Exception/WrapTakesACodeRefToBless.pm b/lib/Moose/Exception/WrapTakesACodeRefToBless.pm new file mode 100644 index 0000000..d833512 --- /dev/null +++ b/lib/Moose/Exception/WrapTakesACodeRefToBless.pm @@ -0,0 +1,25 @@ +package Moose::Exception::WrapTakesACodeRefToBless; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has 'code' => ( + is => 'ro', + isa => 'Any', + required => 1 +); + +has 'class' => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "You must supply a CODE reference to bless, not (" . ( $self->code ? $self->code : 'undef' ) . ")"; +} + +1; diff --git a/lib/Moose/Exception/WrongTypeConstraintGiven.pm b/lib/Moose/Exception/WrongTypeConstraintGiven.pm new file mode 100644 index 0000000..9c3ea18 --- /dev/null +++ b/lib/Moose/Exception/WrongTypeConstraintGiven.pm @@ -0,0 +1,20 @@ +package Moose::Exception::WrongTypeConstraintGiven; +our $VERSION = '2.1405'; + +use Moose; +extends 'Moose::Exception'; +with 'Moose::Exception::Role::ParamsHash'; + +has [qw/required_type given_type attribute_name/] => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_message { + my $self = shift; + "The type constraint for ".$self->attribute_name." must be a subtype of " + .$self->required_type." but it's a ".$self->given_type; +} + +1; diff --git a/lib/Moose/Exporter.pm b/lib/Moose/Exporter.pm new file mode 100644 index 0000000..de9e93b --- /dev/null +++ b/lib/Moose/Exporter.pm @@ -0,0 +1,1065 @@ +package Moose::Exporter; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::Load qw(is_class_loaded); +use Class::MOP; +use List::MoreUtils qw( first_index uniq ); +use Moose::Util::MetaRole; +use Scalar::Util 1.11 qw(reftype); +use Sub::Exporter 0.980; +use Sub::Name qw(subname); + +use Moose::Util 'throw_exception'; + +my %EXPORT_SPEC; + +sub setup_import_methods { + my ( $class, %args ) = @_; + + $args{exporting_package} ||= caller(); + + $class->build_import_methods( + %args, + install => [qw(import unimport init_meta)] + ); +} + +# A reminder to intrepid Moose hackers +# there may be more than one level of exporter +# don't make doy cry. -- perigrin + +sub build_import_methods { + my ( $class, %args ) = @_; + + my $exporting_package = $args{exporting_package} ||= caller(); + + my $meta_lookup = $args{meta_lookup} || sub { Class::MOP::class_of(shift) }; + + $EXPORT_SPEC{$exporting_package} = \%args; + + my @exports_from = $class->_follow_also($exporting_package); + + my $export_recorder = {}; + my $is_reexport = {}; + + my $exports = $class->_make_sub_exporter_params( + [ $exporting_package, @exports_from ], + $export_recorder, + $is_reexport, + $args{meta_lookup}, # so that we don't pass through the default + ); + + my $exporter = $class->_make_exporter( + $exports, + $is_reexport, + $meta_lookup, + ); + + my %methods; + $methods{import} = $class->_make_import_sub( + $exporting_package, + $exporter, + \@exports_from, + $is_reexport, + $meta_lookup, + ); + + $methods{unimport} = $class->_make_unimport_sub( + $exporting_package, + $exports, + $export_recorder, + $is_reexport, + $meta_lookup, + ); + + $methods{init_meta} = $class->_make_init_meta( + $exporting_package, + \%args, + $meta_lookup, + ); + + my $package = Class::MOP::Package->initialize($exporting_package); + for my $to_install ( @{ $args{install} || [] } ) { + my $symbol = '&' . $to_install; + + next + unless $methods{$to_install} + && !$package->has_package_symbol($symbol); + $package->add_package_symbol( + $symbol, + subname( + $exporting_package . '::' . $to_install, $methods{$to_install} + ) + ); + } + + return ( $methods{import}, $methods{unimport}, $methods{init_meta} ); +} + +sub _make_exporter { + my ($class, $exports, $is_reexport, $meta_lookup) = @_; + + return Sub::Exporter::build_exporter( + { + exports => $exports, + groups => { default => [':all'] }, + installer => sub { + my ($arg, $to_export) = @_; + my $meta = $meta_lookup->($arg->{into}); + + goto &Sub::Exporter::default_installer unless $meta; + + # don't overwrite existing symbols with our magically flagged + # version of it if we would install the same sub that's already + # in the importer + + my @filtered_to_export; + my %installed; + for (my $i = 0; $i < @{ $to_export }; $i += 2) { + my ($as, $cv) = @{ $to_export }[$i, $i + 1]; + + next if !ref($as) + && $meta->has_package_symbol('&' . $as) + && $meta->get_package_symbol('&' . $as) == $cv; + + push @filtered_to_export, $as, $cv; + $installed{$as} = 1 unless ref $as; + } + + Sub::Exporter::default_installer($arg, \@filtered_to_export); + + for my $name ( keys %{$is_reexport} ) { + no strict 'refs'; + no warnings 'once'; + next unless exists $installed{$name}; + _flag_as_reexport( \*{ join q{::}, $arg->{into}, $name } ); + } + }, + } + ); +} + +sub _follow_also { + my $class = shift; + my $exporting_package = shift; + + _die_if_cycle_found_in_also_list_for_package($exporting_package); + + return uniq( _follow_also_real($exporting_package) ); +} + +sub _follow_also_real { + my $exporting_package = shift; + my @also = _also_list_for_package($exporting_package); + + return map { $_, _follow_also_real($_) } @also; +} + +sub _also_list_for_package { + my $package = shift; + + if ( !exists $EXPORT_SPEC{$package} ) { + my $loaded = is_class_loaded($package); + + throw_exception( PackageDoesNotUseMooseExporter => package => $package, + is_loaded => $loaded + ); + } + + my $also = $EXPORT_SPEC{$package}{also}; + + return unless defined $also; + + return ref $also ? @$also : $also; +} + +# this is no Tarjan algorithm, but for the list sizes expected, +# brute force will probably be fine (and more maintainable) +sub _die_if_cycle_found_in_also_list_for_package { + my $package = shift; + _die_if_also_list_cycles_back_to_existing_stack( + [ _also_list_for_package($package) ], + [$package], + ); +} + +sub _die_if_also_list_cycles_back_to_existing_stack { + my ( $also_list, $existing_stack ) = @_; + + return unless @$also_list && @$existing_stack; + + for my $also_member (@$also_list) { + for my $stack_member (@$existing_stack) { + next unless $also_member eq $stack_member; + + throw_exception( CircularReferenceInAlso => also_parameter => $also_member, + stack => $existing_stack + ); + } + + _die_if_also_list_cycles_back_to_existing_stack( + [ _also_list_for_package($also_member) ], + [ $also_member, @$existing_stack ], + ); + } +} + +sub _parse_trait_aliases { + my $class = shift; + my ($package, $aliases) = @_; + + my @ret; + for my $alias (@$aliases) { + my $name; + if (ref($alias)) { + reftype($alias) eq 'ARRAY' + or throw_exception( InvalidArgumentsToTraitAliases => class_name => $class, + package_name => $package, + alias => $alias + ); + ($alias, $name) = @$alias; + } + else { + ($name = $alias) =~ s/.*:://; + } + push @ret, subname "${package}::${name}" => sub () { $alias }; + } + + return @ret; +} + +sub _make_sub_exporter_params { + my $class = shift; + my $packages = shift; + my $export_recorder = shift; + my $is_reexport = shift; + my $meta_lookup_override = shift; + + my %exports; + my $current_meta_lookup; + + for my $package ( @{$packages} ) { + my $args = $EXPORT_SPEC{$package} + or die "The $package package does not use Moose::Exporter\n"; + + $current_meta_lookup = $meta_lookup_override || $args->{meta_lookup}; + $meta_lookup_override = $current_meta_lookup; + + my $meta_lookup = $current_meta_lookup + || sub { Class::MOP::class_of(shift) }; + + for my $name ( @{ $args->{with_meta} } ) { + my $sub = $class->_sub_from_package( $package, $name ) + or next; + + my $fq_name = $package . '::' . $name; + + $exports{$name} = $class->_make_wrapped_sub_with_meta( + $fq_name, + $sub, + $export_recorder, + $meta_lookup, + ) unless exists $exports{$name}; + } + + for my $name ( @{ $args->{with_caller} } ) { + my $sub = $class->_sub_from_package( $package, $name ) + or next; + + my $fq_name = $package . '::' . $name; + + $exports{$name} = $class->_make_wrapped_sub( + $fq_name, + $sub, + $export_recorder, + ) unless exists $exports{$name}; + } + + my @extra_exports = $class->_parse_trait_aliases( + $package, $args->{trait_aliases}, + ); + for my $name ( @{ $args->{as_is} }, @extra_exports ) { + my ( $sub, $coderef_name ); + + if ( ref $name ) { + $sub = $name; + + my $coderef_pkg; + ( $coderef_pkg, $coderef_name ) + = Class::MOP::get_code_info($name); + + if ( $coderef_pkg ne $package ) { + $is_reexport->{$coderef_name} = 1; + } + } + elsif ( $name =~ /^(.*)::([^:]+)$/ ) { + $sub = $class->_sub_from_package( "$1", "$2" ) + or next; + + $coderef_name = "$2"; + + if ( $1 ne $package ) { + $is_reexport->{$coderef_name} = 1; + } + } + else { + $sub = $class->_sub_from_package( $package, $name ) + or next; + + $coderef_name = $name; + } + + $export_recorder->{$sub} = 1; + + $exports{$coderef_name} = sub { $sub } + unless exists $exports{$coderef_name}; + } + } + + return \%exports; +} + +sub _sub_from_package { + my $sclass = shift; + my $package = shift; + my $name = shift; + + my $sub = do { + no strict 'refs'; + \&{ $package . '::' . $name }; + }; + + return $sub if defined &$sub; + + Carp::cluck "Trying to export undefined sub ${package}::${name}"; + + return; +} + +our $CALLER; + +sub _make_wrapped_sub { + my $self = shift; + my $fq_name = shift; + my $sub = shift; + my $export_recorder = shift; + + # We need to set the package at import time, so that when + # package Foo imports has(), we capture "Foo" as the + # package. This lets other packages call Foo::has() and get + # the right package. This is done for backwards compatibility + # with existing production code, not because this is a good + # idea ;) + return sub { + my $caller = $CALLER; + + my $wrapper = $self->_curry_wrapper( $sub, $fq_name, $caller ); + + my $sub = subname( $fq_name => $wrapper ); + + $export_recorder->{$sub} = 1; + + return $sub; + }; +} + +sub _make_wrapped_sub_with_meta { + my $self = shift; + my $fq_name = shift; + my $sub = shift; + my $export_recorder = shift; + my $meta_lookup = shift; + + return sub { + my $caller = $CALLER; + + my $wrapper = $self->_late_curry_wrapper( + $sub, $fq_name, + $meta_lookup => $caller + ); + + my $sub = subname( $fq_name => $wrapper ); + + $export_recorder->{$sub} = 1; + + return $sub; + }; +} + +sub _curry_wrapper { + my $class = shift; + my $sub = shift; + my $fq_name = shift; + my @extra = @_; + + my $wrapper = sub { $sub->( @extra, @_ ) }; + if ( my $proto = prototype $sub ) { + + # XXX - Perl's prototype sucks. Use & to make set_prototype + # ignore the fact that we're passing "private variables" + &Scalar::Util::set_prototype( $wrapper, $proto ); + } + return $wrapper; +} + +sub _late_curry_wrapper { + my $class = shift; + my $sub = shift; + my $fq_name = shift; + my $extra = shift; + my @ex_args = @_; + + my $wrapper = sub { + + # resolve curried arguments at runtime via this closure + my @curry = ( $extra->(@ex_args) ); + return $sub->( @curry, @_ ); + }; + + if ( my $proto = prototype $sub ) { + + # XXX - Perl's prototype sucks. Use & to make set_prototype + # ignore the fact that we're passing "private variables" + &Scalar::Util::set_prototype( $wrapper, $proto ); + } + return $wrapper; +} + +sub _make_import_sub { + shift; + my $exporting_package = shift; + my $exporter = shift; + my $exports_from = shift; + my $is_reexport = shift; + my $meta_lookup = shift; + + return sub { + + # I think we could use Sub::Exporter's collector feature + # to do this, but that would be rather gross, since that + # feature isn't really designed to return a value to the + # caller of the exporter sub. + # + # Also, this makes sure we preserve backwards compat for + # _get_caller, so it always sees the arguments in the + # expected order. + my $traits; + ( $traits, @_ ) = _strip_traits(@_); + + my $metaclass; + ( $metaclass, @_ ) = _strip_metaclass(@_); + $metaclass + = Moose::Util::resolve_metaclass_alias( 'Class' => $metaclass ) + if defined $metaclass && length $metaclass; + + my $meta_name; + ( $meta_name, @_ ) = _strip_meta_name(@_); + + # Normally we could look at $_[0], but in some weird cases + # (involving goto &Moose::import), $_[0] ends as something + # else (like Squirrel). + my $class = $exporting_package; + + $CALLER = _get_caller(@_); + + # this works because both pragmas set $^H (see perldoc + # perlvar) which affects the current compilation - + # i.e. the file who use'd us - which is why we don't need + # to do anything special to make it affect that file + # rather than this one (which is already compiled) + + strict->import; + warnings->import; + + my $did_init_meta; + for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) { + + # init_meta can apply a role, which when loaded uses + # Moose::Exporter, which in turn sets $CALLER, so we need + # to protect against that. + local $CALLER = $CALLER; + $c->init_meta( + for_class => $CALLER, + metaclass => $metaclass, + meta_name => $meta_name, + ); + $did_init_meta = 1; + } + + { + # The metaroles will use Moose::Role, which in turn uses + # Moose::Exporter, which in turn sets $CALLER, so we need + # to protect against that. + local $CALLER = $CALLER; + _apply_metaroles( + $CALLER, + [$class, @$exports_from], + $meta_lookup + ); + } + + if ( $did_init_meta && @{$traits} ) { + + # The traits will use Moose::Role, which in turn uses + # Moose::Exporter, which in turn sets $CALLER, so we need + # to protect against that. + local $CALLER = $CALLER; + _apply_meta_traits( $CALLER, $traits, $meta_lookup ); + } + elsif ( @{$traits} ) { + throw_exception( ClassDoesNotHaveInitMeta => class_name => $class, + traits => $traits + ); + } + + my ( undef, @args ) = @_; + my $extra = shift @args if ref $args[0] eq 'HASH'; + + $extra ||= {}; + if ( !$extra->{into} ) { + $extra->{into_level} ||= 0; + $extra->{into_level}++; + } + + $class->$exporter( $extra, @args ); + }; +} + +sub _strip_traits { + my $idx = first_index { ( $_ || '' ) eq '-traits' } @_; + + return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1; + + my $traits = $_[ $idx + 1 ]; + + splice @_, $idx, 2; + + $traits = [$traits] unless ref $traits; + + return ( $traits, @_ ); +} + +sub _strip_metaclass { + my $idx = first_index { ( $_ || '' ) eq '-metaclass' } @_; + + return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1; + + my $metaclass = $_[ $idx + 1 ]; + + splice @_, $idx, 2; + + return ( $metaclass, @_ ); +} + +sub _strip_meta_name { + my $idx = first_index { ( $_ || '' ) eq '-meta_name' } @_; + + return ( 'meta', @_ ) unless $idx >= 0 && $#_ >= $idx + 1; + + my $meta_name = $_[ $idx + 1 ]; + + splice @_, $idx, 2; + + return ( $meta_name, @_ ); +} + +sub _apply_metaroles { + my ($class, $exports_from, $meta_lookup) = @_; + + my $metaroles = _collect_metaroles($exports_from); + my $base_class_roles = delete $metaroles->{base_class_roles}; + + my $meta = $meta_lookup->($class); + # for instance, Moose.pm uses Moose::Util::TypeConstraints + return unless $meta; + + Moose::Util::MetaRole::apply_metaroles( + for => $meta, + %$metaroles, + ) if keys %$metaroles; + + Moose::Util::MetaRole::apply_base_class_roles( + for => $meta, + roles => $base_class_roles, + ) if $meta->isa('Class::MOP::Class') + && $base_class_roles && @$base_class_roles; +} + +sub _collect_metaroles { + my ($exports_from) = @_; + + my @old_style_role_types = map { "${_}_roles" } qw( + metaclass + attribute_metaclass + method_metaclass + wrapped_method_metaclass + instance_metaclass + constructor_class + destructor_class + error_class + ); + + my %class_metaroles; + my %role_metaroles; + my @base_class_roles; + my %old_style_roles; + + for my $exporter (@$exports_from) { + my $data = $EXPORT_SPEC{$exporter}; + + if (exists $data->{class_metaroles}) { + for my $type (keys %{ $data->{class_metaroles} }) { + push @{ $class_metaroles{$type} ||= [] }, + @{ $data->{class_metaroles}{$type} }; + } + } + + if (exists $data->{role_metaroles}) { + for my $type (keys %{ $data->{role_metaroles} }) { + push @{ $role_metaroles{$type} ||= [] }, + @{ $data->{role_metaroles}{$type} }; + } + } + + if (exists $data->{base_class_roles}) { + push @base_class_roles, @{ $data->{base_class_roles} }; + } + + for my $type (@old_style_role_types) { + if (exists $data->{$type}) { + push @{ $old_style_roles{$type} ||= [] }, + @{ $data->{$type} }; + } + } + } + + return { + (keys(%class_metaroles) + ? (class_metaroles => \%class_metaroles) + : ()), + (keys(%role_metaroles) + ? (role_metaroles => \%role_metaroles) + : ()), + (@base_class_roles + ? (base_class_roles => \@base_class_roles) + : ()), + %old_style_roles, + }; +} + +sub _apply_meta_traits { + my ( $class, $traits, $meta_lookup ) = @_; + + return unless @{$traits}; + + my $meta = $meta_lookup->($class); + + my $type = $meta->isa('Moose::Meta::Role') ? 'Role' + : $meta->isa('Class::MOP::Class') ? 'Class' + : confess('Cannot determine metaclass type for ' + . 'trait application. Meta isa ' + . ref $meta); + + my @resolved_traits = map { + ref $_ + ? $_ + : Moose::Util::resolve_metatrait_alias( $type => $_ ) + } @$traits; + + return unless @resolved_traits; + + my %args = ( for => $class ); + + if ( $meta->isa('Moose::Meta::Role') ) { + $args{role_metaroles} = { role => \@resolved_traits }; + } + else { + $args{class_metaroles} = { class => \@resolved_traits }; + } + + Moose::Util::MetaRole::apply_metaroles(%args); +} + +sub _get_caller { + + # 1 extra level because it's called by import so there's a layer + # of indirection + my $offset = 1; + + return + ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into} + : ( ref $_[1] && defined $_[1]->{into_level} ) + ? caller( $offset + $_[1]->{into_level} ) + : caller($offset); +} + +sub _make_unimport_sub { + shift; + my $exporting_package = shift; + my $exports = shift; + my $export_recorder = shift; + my $is_reexport = shift; + my $meta_lookup = shift; + + return sub { + my $caller = scalar caller(); + Moose::Exporter->_remove_keywords( + $caller, + [ keys %{$exports} ], + $export_recorder, + $is_reexport, + ); + }; +} + +sub _remove_keywords { + shift; + my $package = shift; + my $keywords = shift; + my $recorded_exports = shift; + my $is_reexport = shift; + + no strict 'refs'; + + foreach my $name ( @{$keywords} ) { + if ( defined &{ $package . '::' . $name } ) { + my $sub = \&{ $package . '::' . $name }; + + # make sure it is from us + next unless $recorded_exports->{$sub}; + + if ( $is_reexport->{$name} ) { + no strict 'refs'; + next + unless _export_is_flagged( + \*{ join q{::} => $package, $name } ); + } + + # and if it is from us, then undef the slot + delete ${ $package . '::' }{$name}; + } + } +} + +# maintain this for now for backcompat +# make sure to return a sub to install in the same circumstances as previously +# but this functionality now happens at the end of ->import +sub _make_init_meta { + shift; + my $class = shift; + my $args = shift; + my $meta_lookup = shift; + + my %old_style_roles; + for my $role ( + map {"${_}_roles"} + qw( + metaclass + attribute_metaclass + method_metaclass + wrapped_method_metaclass + instance_metaclass + constructor_class + destructor_class + error_class + ) + ) { + $old_style_roles{$role} = $args->{$role} + if exists $args->{$role}; + } + + my %base_class_roles; + %base_class_roles = ( roles => $args->{base_class_roles} ) + if exists $args->{base_class_roles}; + + my %new_style_roles = map { $_ => $args->{$_} } + grep { exists $args->{$_} } qw( class_metaroles role_metaroles ); + + return unless %new_style_roles || %old_style_roles || %base_class_roles; + + return sub { + shift; + my %opts = @_; + $meta_lookup->($opts{for_class}); + }; +} + +sub import { + strict->import; + warnings->import; +} + +1; + +# ABSTRACT: make an import() and unimport() just like Moose.pm + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Exporter - make an import() and unimport() just like Moose.pm + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Moose; + + use Moose (); + use Moose::Exporter; + use Some::Random (); + + Moose::Exporter->setup_import_methods( + with_meta => [ 'has_rw', 'sugar2' ], + as_is => [ 'sugar3', \&Some::Random::thing, 'Some::Random::other_thing' ], + also => 'Moose', + ); + + sub has_rw { + my ( $meta, $name, %options ) = @_; + $meta->add_attribute( + $name, + is => 'rw', + %options, + ); + } + + # then later ... + package MyApp::User; + + use MyApp::Moose; + + has 'name' => ( is => 'ro' ); + has_rw 'size'; + thing; + other_thing; + + no MyApp::Moose; + +=head1 DESCRIPTION + +This module encapsulates the exporting of sugar functions in a +C<Moose.pm>-like manner. It does this by building custom C<import> and +C<unimport> methods for your module, based on a spec you provide. + +It also lets you "stack" Moose-alike modules so you can export Moose's sugar +as well as your own, along with sugar from any random C<MooseX> module, as +long as they all use C<Moose::Exporter>. This feature exists to let you bundle +a set of MooseX modules into a policy module that developers can use directly +instead of using Moose itself. + +To simplify writing exporter modules, C<Moose::Exporter> also imports +C<strict> and C<warnings> into your exporter module, as well as into +modules that use it. + +=head1 METHODS + +This module provides two public methods: + +=over 4 + +=item B<< Moose::Exporter->setup_import_methods(...) >> + +When you call this method, C<Moose::Exporter> builds custom C<import> and +C<unimport> methods for your module. The C<import> method +will export the functions you specify, and can also re-export functions +exported by some other module (like C<Moose.pm>). If you pass any parameters +for L<Moose::Util::MetaRole>, the C<import> method will also call +L<Moose::Util::MetaRole::apply_metaroles|Moose::Util::MetaRole/apply_metaroles> and +L<Moose::Util::MetaRole::apply_base_class_roles|Moose::Util::MetaRole/apply_base_class_roles> as needed, after making +sure the metaclass is initialized. + +The C<unimport> method cleans the caller's namespace of all the exported +functions. This includes any functions you re-export from other +packages. However, if the consumer of your package also imports those +functions from the original package, they will I<not> be cleaned. + +Note that if any of these methods already exist, they will not be +overridden, you will have to use C<build_import_methods> to get the +coderef that would be installed. + +This method accepts the following parameters: + +=over 8 + +=item * with_meta => [ ... ] + +This list of function I<names only> will be wrapped and then exported. The +wrapper will pass the metaclass object for the caller as its first argument. + +Many sugar functions will need to use this metaclass object to do something to +the calling package. + +=item * as_is => [ ... ] + +This list of function names or sub references will be exported as-is. You can +identify a subroutine by reference, which is handy to re-export some other +module's functions directly by reference (C<\&Some::Package::function>). + +If you do export some other package's function, this function will never be +removed by the C<unimport> method. The reason for this is we cannot know if +the caller I<also> explicitly imported the sub themselves, and therefore wants +to keep it. + +=item * trait_aliases => [ ... ] + +This is a list of package names which should have shortened aliases exported, +similar to the functionality of L<aliased>. Each element in the list can be +either a package name, in which case the export will be named as the last +namespace component of the package, or an arrayref, whose first element is the +package to alias to, and second element is the alias to export. + +=item * also => $name or \@names + +This is a list of modules which contain functions that the caller +wants to export. These modules must also use C<Moose::Exporter>. The +most common use case will be to export the functions from C<Moose.pm>. +Functions specified by C<with_meta> or C<as_is> take precedence over +functions exported by modules specified by C<also>, so that a module +can selectively override functions exported by another module. + +C<Moose::Exporter> also makes sure all these functions get removed +when C<unimport> is called. + +=item * meta_lookup => sub { ... } + +This is a function which will be called to provide the metaclass +to be operated upon by the exporter. This is an advanced feature +intended for use by package generator modules in the vein of +L<MooseX::Role::Parameterized> in order to simplify reusing sugar +from other modules that use C<Moose::Exporter>. This function is +used, for example, to select the metaclass to bind to functions +that are exported using the C<with_meta> option. + +This function will receive one parameter: the class name into which +the sugar is being exported. The default implementation is: + + sub { Class::MOP::class_of(shift) } + +Accordingly, this function is expected to return a metaclass. + +=back + +You can also provide parameters for L<Moose::Util::MetaRole::apply_metaroles|Moose::Util::MetaRole/apply_metaroles> +and L<Moose::Util::MetaRole::apply_base_class_roles|Moose::Util::MetaRole/apply_base_class_roles>. Specifically, valid parameters +are "class_metaroles", "role_metaroles", and "base_class_roles". + +=item B<< Moose::Exporter->build_import_methods(...) >> + +Returns three code refs, one for C<import>, one for C<unimport> and one for +C<init_meta>. + +Accepts the additional C<install> option, which accepts an arrayref of method +names to install into your exporting package. The valid options are C<import> +and C<unimport>. Calling C<setup_import_methods> is equivalent +to calling C<build_import_methods> with C<< install => [qw(import unimport)] >> +except that it doesn't also return the methods. + +The C<import> method is built using L<Sub::Exporter>. This means that it can +take a hashref of the form C<< { into => $package } >> to specify the package +it operates on. + +Used by C<setup_import_methods>. + +=back + +=head1 IMPORTING AND init_meta + +If you want to set an alternative base object class or metaclass class, see +above for details on how this module can call L<Moose::Util::MetaRole> for +you. + +If you want to do something that is not supported by this module, simply +define an C<init_meta> method in your class. The C<import> method that +C<Moose::Exporter> generates for you will call this method (if it exists). It +will always pass the caller to this method via the C<for_class> parameter. + +Most of the time, your C<init_meta> method will probably just call C<< +Moose->init_meta >> to do the real work: + + sub init_meta { + shift; # our class name + return Moose->init_meta( @_, metaclass => 'My::Metaclass' ); + } + +=head1 METACLASS TRAITS + +The C<import> method generated by C<Moose::Exporter> will allow the +user of your module to specify metaclass traits in a C<-traits> +parameter passed as part of the import: + + use Moose -traits => 'My::Meta::Trait'; + + use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ]; + +These traits will be applied to the caller's metaclass +instance. Providing traits for an exporting class that does not create +a metaclass for the caller is an error. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Intro.pod b/lib/Moose/Intro.pod new file mode 100644 index 0000000..689dd20 --- /dev/null +++ b/lib/Moose/Intro.pod @@ -0,0 +1,77 @@ +# PODNAME: Moose::Intro +# ABSTRACT: Expanded into Moose::Manual, so go read that + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Intro - Expanded into Moose::Manual, so go read that + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +The intro has been replaced by L<Moose::Manual>. This POD document +still exists for the benefit of anyone out there who might've linked +to it in the past. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual.pod b/lib/Moose/Manual.pod new file mode 100644 index 0000000..b944d8a --- /dev/null +++ b/lib/Moose/Manual.pod @@ -0,0 +1,334 @@ +# PODNAME: Moose::Manual +# ABSTRACT: What is Moose, and how do I use it? + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual - What is Moose, and how do I use it? + +=head1 VERSION + +version 2.1405 + +=head1 WHAT IS MOOSE? + +Moose is a I<complete> object system for Perl 5. Consider any modern +object-oriented language (which Perl 5 definitely isn't). It provides +keywords for attribute declaration, object construction, inheritance, +and maybe more. These keywords are part of the language, and you don't +care how they are implemented. + +Moose aims to do the same thing for Perl 5 OO. We can't actually +create new keywords, but we do offer "sugar" that looks a lot like +them. More importantly, with Moose, you I<define your class +declaratively>, without needing to know about blessed hashrefs, +accessor methods, and so on. + +With Moose, you can concentrate on the I<logical> structure of your +classes, focusing on "what" rather than "how". A class definition with +Moose reads like a list of very concise English sentences. + +Moose is built on top of C<Class::MOP>, a meta-object protocol (aka +MOP). Using the MOP, Moose provides complete introspection for all +Moose-using classes. This means you can ask classes about their +attributes, parents, children, methods, etc., all using a well-defined +API. The MOP abstracts away the symbol table, looking at C<@ISA> vars, +and all the other crufty Perl tricks we know and love(?). + +Moose is based in large part on the Perl 6 object system, as well as +drawing on the best ideas from CLOS, Smalltalk, and many other +languages. + +=head1 WHY MOOSE? + +Moose makes Perl 5 OO both simpler and more powerful. It encapsulates +Perl 5 power tools in high-level declarative APIs which are easy to +use. Best of all, you don't need to be a wizard to use it. + +But if you want to dig about in the guts, Moose lets you do that too, +by using and extending its powerful introspection API. + +=head1 AN EXAMPLE + + package Person; + + use Moose; + + has 'first_name' => ( + is => 'rw', + isa => 'Str', + ); + + has 'last_name' => ( + is => 'rw', + isa => 'Str', + ); + + no Moose; + __PACKAGE__->meta->make_immutable; + +This is a I<complete and usable> class definition! + + package User; + + use DateTime; + use Moose; + + extends 'Person'; + + has 'password' => ( + is => 'rw', + isa => 'Str', + ); + + has 'last_login' => ( + is => 'rw', + isa => 'DateTime', + handles => { 'date_of_last_login' => 'date' }, + ); + + sub login { + my $self = shift; + my $pw = shift; + + return 0 if $pw ne $self->password; + + $self->last_login( DateTime->now() ); + + return 1; + } + + no Moose; + __PACKAGE__->meta->make_immutable; + +When ready to instantiate your class in an application, use it in the +"traditional" Perl manner: + + use User; + + my $user = User->new( + first_name => 'Example', + last_name => 'User', + password => 'letmein', + ); + + $user->login('letmein'); + + say $user->date_of_last_login; + +We'll leave the line-by-line explanation of this code to other +documentation, but you can see how Moose reduces common OO idioms to +simple declarative constructs. + +=head1 TABLE OF CONTENTS + +This manual consists of a number of documents. + +=over 4 + +=item L<Moose::Manual::Concepts> + +Introduces Moose concepts, and contrasts them against "old school" +Perl 5 OO. + +=item L<Moose::Manual::Unsweetened> + +Shows two example classes, each written first with Moose and then with +"plain old Perl 5". + +=item L<Moose::Manual::Classes> + +How do you make use of Moose in your classes? Now that I'm a Moose, +how do I subclass something? + +=item L<Moose::Manual::Attributes> + +Attributes are a core part of the Moose OO system. An attribute is a +piece of data that an object has. Moose has a lot of attribute-related +features! + +=item L<Moose::Manual::Delegation> + +Delegation is a powerful way to make use of attributes which are +themselves objects. + +=item L<Moose::Manual::Construction> + +Learn how objects are built in Moose, and in particular about the +C<BUILD> and C<BUILDARGS> methods. Also covers object destruction +with C<DEMOLISH>. + +=item L<Moose::Manual::MethodModifiers> + +A method modifier lets you say "before calling method X, do this +first", or "wrap method X in this code". Method modifiers are +particularly handy in roles and with attribute accessors. + +=item L<Moose::Manual::Roles> + +A role is something a class does (like "Debuggable" or +"Printable"). Roles provide a way of adding behavior to classes that +is orthogonal to inheritance. + +=item L<Moose::Manual::Types> + +Moose's type system lets you strictly define what values an attribute +can contain. + +=item L<Moose::Manual::MOP> + +Moose's meta API system lets you ask classes about their parents, +children, methods, attributes, etc. + +=item L<Moose::Manual::MooseX> + +This document describes a few of the most useful Moose extensions on +CPAN. + +=item L<Moose::Manual::BestPractices> + +Moose has a lot of features, and there's definitely more than one way +to do it. However, we think that picking a subset of these features +and using them consistently makes everyone's life easier. + +=item L<Moose::Manual::FAQ> + +Frequently asked questions about Moose. + +=item L<Moose::Manual::Resources> + +Links to various tutorials, videos, blogs, presentations, interviews, etc... + +=item L<Moose::Manual::Contributing> + +Interested in hacking on Moose? Read this. + +=item L<Moose::Manual::Delta> + +This document details backwards-incompatibilities and other major +changes to Moose. + +=back + +=head1 JUSTIFICATION + +If you're still asking yourself "Why do I need this?", then this +section is for you. + +=over 4 + +=item Another object system!?!? + +Yes, we know there are many, many ways to build objects in Perl 5, +many of them based on inside-out objects and other such things. Moose +is different because it is not a new object system for Perl 5, but +instead an extension of the existing object system. + +Moose is built on top of L<Class::MOP>, which is a metaclass system +for Perl 5. This means that Moose not only makes building normal +Perl 5 objects better, but it also provides the power of metaclass +programming. + +=item Is this for real? Or is this just an experiment? + +Moose is I<based> on the prototypes and experiments Stevan did for the +Perl 6 meta-model. However, Moose is B<NOT> an experiment or +prototype; it is for B<real>. + +=item Is this ready for use in production? + +Yes. + +Moose has been used successfully in production environments by many +people and companies. There are Moose applications which have been in +production with little or no issue now for years. We consider it +highly stable and we are committed to keeping it stable. + +Of course, in the end, you need to make this call yourself. If you +have any questions or concerns, please feel free to email Stevan or +the moose@perl.org list, or just stop by irc.perl.org#moose and ask +away. + +=item Is Moose just Perl 6 in Perl 5? + +No. While Moose is very much inspired by Perl 6, it is not itself Perl +6. Instead, it is an OO system for Perl 5. Stevan built Moose because +he was tired of writing the same old boring Perl 5 OO code, and +drooling over Perl 6 OO. So instead of switching to Ruby, he wrote +Moose :) + +=item Wait, I<post> modern, I thought it was just I<modern>? + +Stevan read Larry Wall's talk from the 1999 Linux World entitled +"Perl, the first postmodern computer language" in which he talks about +how he picked the features for Perl because he thought they were cool +and he threw out the ones that he thought sucked. This got him +thinking about how we have done the same thing in Moose. For Moose, we +have "borrowed" features from Perl 6, CLOS (LISP), Smalltalk, Java, +BETA, OCaml, Ruby and more, and the bits we didn't like (cause they +sucked) we tossed aside. So for this reason (and a few others) Stevan +has re-dubbed Moose a I<postmodern> object system. + +Nuff Said. + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Attributes.pod b/lib/Moose/Manual/Attributes.pod new file mode 100644 index 0000000..cf41c83 --- /dev/null +++ b/lib/Moose/Manual/Attributes.pod @@ -0,0 +1,697 @@ +# PODNAME: Moose::Manual::Attributes +# ABSTRACT: Object attributes with Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Attributes - Object attributes with Moose + +=head1 VERSION + +version 2.1405 + +=head1 INTRODUCTION + +Moose attributes have many properties, and attributes are probably the +single most powerful and flexible part of Moose. You can create a +powerful class simply by declaring attributes. In fact, it's possible +to have classes that consist solely of attribute declarations. + +An attribute is a property that every member of a class has. For +example, we might say that "every C<Person> object has a first name and +last name". Attributes can be optional, so that we can say "some C<Person> +objects have a social security number (and some don't)". + +At its simplest, an attribute can be thought of as a named value (as +in a hash) that can be read and set. However, attributes can also have +defaults, type constraints, delegation and much more. + +In other languages, attributes are also referred to as slots or +properties. + +=head1 ATTRIBUTE OPTIONS + +Use the C<has> function to declare an attribute: + + package Person; + + use Moose; + + has 'first_name' => ( is => 'rw' ); + +This says that all C<Person> objects have an optional read-write +"first_name" attribute. + +=head2 Read-write vs. read-only + +The options passed to C<has> define the properties of the attribute. There are +many options, but in the simplest form you just need to set C<is>, which can +be either C<ro> (read-only) or C<rw> (read-write). When an attribute is C<rw>, +you can change it by passing a value to its accessor. When an attribute is +C<ro>, you may only read the current value of the attribute. + +In fact, you could even omit C<is>, but that gives you an attribute +that has no accessor. This can be useful with other attribute options, +such as C<handles>. However, if your attribute generates I<no> +accessors, Moose will issue a warning, because that usually means the +programmer forgot to say the attribute is read-only or read-write. If +you really mean to have no accessors, you can silence this warning by +setting C<is> to C<bare>. + +=head2 Accessor methods + +Each attribute has one or more accessor methods. An accessor lets you +read and write the value of that attribute for an object. + +By default, the accessor method has the same name as the attribute. If +you declared your attribute as C<ro> then your accessor will be +read-only. If you declared it as C<rw>, you get a read-write +accessor. Simple. + +Given our C<Person> example above, we now have a single C<first_name> +accessor that can read or write a C<Person> object's C<first_name> +attribute's value. + +If you want, you can also explicitly specify the method names to be +used for reading and writing an attribute's value. This is +particularly handy when you'd like an attribute to be publicly +readable, but only privately settable. For example: + + has 'weight' => ( + is => 'ro', + writer => '_set_weight', + ); + +This might be useful if weight is calculated based on other methods. +For example, every time the C<eat> method is called, we might adjust +weight. This lets us hide the implementation details of weight +changes, but still provide the weight value to users of the class. + +Some people might prefer to have distinct methods for reading and +writing. In I<Perl Best Practices>, Damian Conway recommends that +reader methods start with "get_" and writer methods start with "set_". + +We can do exactly that by providing names for both the C<reader> and +C<writer> methods: + + has 'weight' => ( + is => 'rw', + reader => 'get_weight', + writer => 'set_weight', + ); + +If you're thinking that doing this over and over would be insanely +tedious, you're right! Fortunately, Moose provides a powerful +extension system that lets you override the default naming +conventions. See L<Moose::Manual::MooseX> for more details. + +=head2 Predicate and clearer methods + +Moose allows you to explicitly distinguish between a false or +undefined attribute value and an attribute which has not been set. If +you want to access this information, you must define clearer and +predicate methods for an attribute. + +A predicate method tells you whether or not a given attribute is +currently set. Note that an attribute can be explicitly set to +C<undef> or some other false value, but the predicate will return +true. + +The clearer method unsets the attribute. This is I<not> the +same as setting the value to C<undef>, but you can only distinguish +between them if you define a predicate method! + +Here's some code to illustrate the relationship between an accessor, +predicate, and clearer method. + + package Person; + + use Moose; + + has 'ssn' => ( + is => 'rw', + clearer => 'clear_ssn', + predicate => 'has_ssn', + ); + + ... + + my $person = Person->new(); + $person->has_ssn; # false + + $person->ssn(undef); + $person->ssn; # returns undef + $person->has_ssn; # true + + $person->clear_ssn; + $person->ssn; # returns undef + $person->has_ssn; # false + + $person->ssn('123-45-6789'); + $person->ssn; # returns '123-45-6789' + $person->has_ssn; # true + + my $person2 = Person->new( ssn => '111-22-3333'); + $person2->has_ssn; # true + +By default, Moose does not make a predicate or clearer for you. You must +explicitly provide names for them, and then Moose will create the methods +for you. + +=head2 Required or not? + +By default, all attributes are optional, and do not need to be +provided at object construction time. If you want to make an attribute +required, simply set the C<required> option to true: + + has 'name' => ( + is => 'ro', + required => 1, + ); + +There are a couple caveats worth mentioning in regards to what +"required" actually means. + +Basically, all it says is that this attribute (C<name>) must be provided to +the constructor, or be lazy with either a default or a builder. It does not +say anything about its value, so it could be C<undef>. + +If you define a clearer method on a required attribute, the clearer +I<will> work, so even a required attribute can be unset after object +construction. + +This means that if you do make an attribute required, providing a +clearer doesn't make much sense. In some cases, it might be handy to +have a I<private> C<clearer> and C<predicate> for a required +attribute. + +=head2 Default and builder methods + +Attributes can have default values, and Moose provides two ways to +specify that default. + +In the simplest form, you simply provide a non-reference scalar value +for the C<default> option: + + has 'size' => ( + is => 'ro', + default => 'medium', + predicate => 'has_size', + ); + +If the size attribute is not provided to the constructor, then it ends +up being set to C<medium>: + + my $person = Person->new(); + $person->size; # medium + $person->has_size; # true + +You can also provide a subroutine reference for C<default>. This +reference will be called as a method on the object. + + has 'size' => ( + is => 'ro', + default => + sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] }, + predicate => 'has_size', + ); + +This is a trivial example, but it illustrates the point that the subroutine +will be called for every new object created. + +When you provide a C<default> subroutine reference, it is called as a +method on the object, with no additional parameters: + + has 'size' => ( + is => 'ro', + default => sub { + my $self = shift; + + return $self->height > 200 ? 'large' : 'average'; + }, + ); + +When the C<default> is called during object construction, it may be +called before other attributes have been set. If your default is +dependent on other parts of the object's state, you can make the +attribute C<lazy>. Laziness is covered in the next section. + +If you want to use a reference of any sort as the default value, you +must return it from a subroutine. + + has 'mapping' => ( + is => 'ro', + default => sub { {} }, + ); + +This is necessary because otherwise Perl would instantiate the reference +exactly once, and it would be shared by all objects: + + has 'mapping' => ( + is => 'ro', + default => {}, # wrong! + ); + +Moose will throw an error if you pass a bare non-subroutine reference +as the default. + +If Moose allowed this then the default mapping attribute could easily +end up shared across many objects. Instead, wrap it in a subroutine +reference as we saw above. + +This is a bit awkward, but it's just the way Perl works. + +As an alternative to using a subroutine reference, you can supply a C<builder> +method for your attribute: + + has 'size' => ( + is => 'ro', + builder => '_build_size', + predicate => 'has_size', + ); + + sub _build_size { + return ( 'small', 'medium', 'large' )[ int( rand 3 ) ]; + } + +This has several advantages. First, it moves a chunk of code to its own named +method, which improves readability and code organization. Second, because this +is a I<named> method, it can be subclassed or provided by a role. + +We strongly recommend that you use a C<builder> instead of a +C<default> for anything beyond the most trivial default. + +A C<builder>, just like a C<default>, is called as a method on the +object with no additional parameters. + +=head3 Builders allow subclassing + +Because the C<builder> is called I<by name>, it goes through Perl's +method resolution. This means that builder methods are both +inheritable and overridable. + +If we subclass our C<Person> class, we can override C<_build_size>: + + package Lilliputian; + + use Moose; + extends 'Person'; + + sub _build_size { return 'small' } + +=head3 Builders work well with roles + +Because builders are called by name, they work well with roles. For +example, a role could provide an attribute but require that the +consuming class provide the C<builder>: + + package HasSize; + use Moose::Role; + + requires '_build_size'; + + has 'size' => ( + is => 'ro', + lazy => 1, + builder => '_build_size', + ); + + package Lilliputian; + use Moose; + + with 'HasSize'; + + sub _build_size { return 'small' } + +Roles are covered in L<Moose::Manual::Roles>. + +=head2 Laziness + +Moose lets you defer attribute population by making an attribute +C<lazy>: + + has 'size' => ( + is => 'ro', + lazy => 1, + builder => '_build_size', + ); + +When C<lazy> is true, the default is not generated until the reader +method is called, rather than at object construction time. There are +several reasons you might choose to do this. + +First, if the default value for this attribute depends on some other +attributes, then the attribute I<must> be C<lazy>. During object +construction, defaults are not generated in a predictable order, so +you cannot count on some other attribute being populated when +generating a default. + +Second, there's often no reason to calculate a default before it's +needed. Making an attribute C<lazy> lets you defer the cost until the +attribute is needed. If the attribute is I<never> needed, you save +some CPU time. + +We recommend that you make any attribute with a builder or non-trivial +default C<lazy> as a matter of course. + +=head3 Lazy defaults and C<$_> + +Please note that a lazy default or builder can be called anywhere, even inside +a C<map> or C<grep>. This means that if your default sub or builder changes +C<$_>, something weird could happen. You can prevent this by adding C<local +$_> inside your default or builder. + +=head2 Constructor parameters (C<init_arg>) + +By default, each attribute can be passed by name to the class's +constructor. On occasion, you may want to use a different name for +the constructor parameter. You may also want to make an attribute +unsettable via the constructor. + +You can do either of these things with the C<init_arg> option: + + has 'bigness' => ( + is => 'ro', + init_arg => 'size', + ); + +Now we have an attribute named "bigness", but we pass C<size> to the +constructor. + +Even more useful is the ability to disable setting an attribute via +the constructor. This is particularly handy for private attributes: + + has '_genetic_code' => ( + is => 'ro', + lazy => 1, + builder => '_build_genetic_code', + init_arg => undef, + ); + +By setting the C<init_arg> to C<undef>, we make it impossible to set +this attribute when creating a new object. + +=head2 Weak references + +Moose has built-in support for weak references. If you set the +C<weak_ref> option to a true value, then it will call +C<Scalar::Util::weaken> whenever the attribute is set: + + has 'parent' => ( + is => 'rw', + weak_ref => 1, + ); + + $node->parent($parent_node); + +This is very useful when you're building objects that may contain +circular references. + +When the object in a weak reference goes out of scope, the attribute's value +will become C<undef> "behind the scenes". This is done by the Perl interpreter +directly, so Moose does not see this change. This means that triggers don't +fire, coercions aren't applied, etc. + +The attribute is not cleared, so a predicate method for that attribute will +still return true. Similarly, when the attribute is next accessed, a default +value will not be generated. + +=head2 Triggers + +A C<trigger> is a subroutine that is called whenever the attribute is +set: + + has 'size' => ( + is => 'rw', + trigger => \&_size_set, + ); + + sub _size_set { + my ( $self, $size, $old_size ) = @_; + + my $msg = $self->name; + + if ( @_ > 2 ) { + $msg .= " - old size was $old_size"; + } + + $msg .= " - size is now $size"; + warn $msg; + } + +The trigger is called I<after> an attribute's value is set. It is +called as a method on the object, and receives the new and old values as +its arguments. If the attribute had not previously been set at all, +then only the new value is passed. This lets you distinguish between +the case where the attribute had no value versus when the old value was C<undef>. + +This differs from an C<after> method modifier in two ways. First, a +trigger is only called when the attribute is set, as opposed to +whenever the accessor method is called (for reading or +writing). Second, it is also called when an attribute's value is +passed to the constructor. + +However, triggers are I<not> called when an attribute is populated +from a C<default> or C<builder>. + +=head2 Attribute types + +Attributes can be restricted to only accept certain types: + + has 'first_name' => ( + is => 'ro', + isa => 'Str', + ); + +This says that the C<first_name> attribute must be a string. + +Moose also provides a shortcut for specifying that an attribute only +accepts objects that do a certain role: + + has 'weapon' => ( + is => 'rw', + does => 'MyApp::Weapon', + ); + +See the L<Moose::Manual::Types> documentation for a complete +discussion of Moose's type system. + +=head2 Delegation + +An attribute can define methods which simply delegate to its value: + + has 'hair_color' => ( + is => 'ro', + isa => 'Graphics::Color::RGB', + handles => { hair_color_hex => 'as_hex_string' }, + ); + +This adds a new method, C<hair_color_hex>. When someone calls +C<hair_color_hex>, internally, the object just calls C<< +$self->hair_color->as_hex_string >>. + +See L<Moose::Manual::Delegation> for documentation on how to set up +delegation methods. + +=head2 Attribute traits and metaclasses + +One of Moose's best features is that it can be extended in all sorts of ways +through the use of metaclass traits and custom metaclasses. + +You can apply one or more traits to an attribute: + + use MooseX::MetaDescription; + + has 'size' => ( + is => 'ro', + traits => ['MooseX::MetaDescription::Meta::Trait'], + description => { + html_widget => 'text_input', + serialize_as => 'element', + }, + ); + +The advantage of traits is that you can mix more than one of them +together easily (in fact, a trait is just a role under the hood). + +There are a number of MooseX modules on CPAN which provide useful +attribute metaclasses and traits. See L<Moose::Manual::MooseX> for +some examples. You can also write your own metaclasses and traits. See +the "Meta" and "Extending" recipes in L<Moose::Cookbook> for examples. + +=head2 Native Delegations + +Native delegations allow you to delegate to standard Perl data structures as +if they were objects. + +For example, we can pretend that an array reference has methods like +C<push()>, C<shift()>, C<map()>, C<count()>, and more. + + has 'options' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Str]', + default => sub { [] }, + handles => { + all_options => 'elements', + add_option => 'push', + map_options => 'map', + option_count => 'count', + sorted_options => 'sort', + }, + ); + +See L<Moose::Manual::Delegation> for more details. + +=head1 ATTRIBUTE INHERITANCE + +By default, a child inherits all of its parent class(es)' attributes +as-is. However, you can change most aspects of the inherited attribute in the +child class. You cannot change any of its associated method names (reader, +writer, predicate, etc). + +To override an attribute, you simply prepend its name with a plus sign +(C<+>): + + package LazyPerson; + + use Moose; + + extends 'Person'; + + has '+first_name' => ( + lazy => 1, + default => 'Bill', + ); + +Now the C<first_name> attribute in C<LazyPerson> is lazy, and defaults +to C<'Bill'>. + +We recommend that you exercise caution when changing the type (C<isa>) +of an inherited attribute. + +=head1 MULTIPLE ATTRIBUTE SHORTCUTS + +If you have a number of attributes that differ only by name, you can declare +them all at once: + + package Point; + + use Moose; + + has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' ); + +Also, because C<has> is just a function call, you can call it in a loop: + + for my $name ( qw( x y ) ) { + my $builder = '_build_' . $name; + has $name => ( is => 'ro', isa => 'Int', builder => $builder ); + } + +=head1 MORE ON ATTRIBUTES + +Moose attributes are a big topic, and this document glosses over a few +aspects. We recommend that you read the L<Moose::Manual::Delegation> +and L<Moose::Manual::Types> documents to get a more complete +understanding of attribute features. + +=head1 A FEW MORE OPTIONS + +Moose has lots of attribute options. The ones listed below are +superseded by some more modern features, but are covered for the sake +of completeness. + +=head2 The C<documentation> option + +You can provide a piece of documentation as a string for an attribute: + + has 'first_name' => ( + is => 'rw', + documentation => q{The person's first (personal) name}, + ); + +Moose does absolutely nothing with this information other than store +it. + +=head2 The C<auto_deref> option + +If your attribute is an array reference or hash reference, the +C<auto_deref> option will make Moose dereference the value when it is +returned from the reader method I<in list context>: + + my %map = $object->mapping; + +This option only works if your attribute is explicitly typed as an +C<ArrayRef> or C<HashRef>. When the reader is called in I<scalar> context, +the reference itself is returned. + +However, we recommend that you use L<Moose::Meta::Attribute::Native> traits +for these types of attributes, which gives you much more control over how +they are accessed and manipulated. See also +L<Moose::Manual::BestPractices#Use_Moose::Meta::Attribute::Native_traits_instead_of_auto_deref>. + +=head2 Initializer + +Moose provides an attribute option called C<initializer>. This is called when +the attribute's value is being set in the constructor, and lets you change the +value before it is set. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/BestPractices.pod b/lib/Moose/Manual/BestPractices.pod new file mode 100644 index 0000000..0f102b4 --- /dev/null +++ b/lib/Moose/Manual/BestPractices.pod @@ -0,0 +1,292 @@ +# PODNAME: Moose::Manual::BestPractices +# ABSTRACT: Get the most out of Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::BestPractices - Get the most out of Moose + +=head1 VERSION + +version 2.1405 + +=head1 RECOMMENDATIONS + +Moose has a lot of features, and there's definitely more than one way +to do it. However, we think that picking a subset of these features +and using them consistently makes everyone's life easier. + +Of course, as with any list of "best practices", these are really just +opinions. Feel free to ignore us. + +=head2 C<namespace::autoclean> and immutabilize + +We recommend that you remove the Moose sugar and end your Moose class +definitions by making your class immutable. + + package Person; + + use Moose; + use namespace::autoclean; + + # extends, roles, attributes, etc. + + # methods + + __PACKAGE__->meta->make_immutable; + + 1; + +The C<use namespace::autoclean> bit is simply good code hygiene, as it removes +imported symbols from your class's namespace at the end of your package's +compile cycle, including Moose keywords. Once the class has been built, these +keywords are not needed. (This is preferred to placing C<no Moose> at the end +of your package). + +The C<make_immutable> call allows Moose to speed up a lot of things, most +notably object construction. The trade-off is that you can no longer change +the class definition. + +=head2 Never override C<new> + +Overriding C<new> is a very bad practice. Instead, you should use a +C<BUILD> or C<BUILDARGS> methods to do the same thing. When you +override C<new>, Moose can no longer inline a constructor when your +class is immutabilized. + +There are two good reasons to override C<new>. One, you are writing a +MooseX extension that provides its own L<Moose::Object> subclass +I<and> a subclass of L<Moose::Meta::Method::Constructor> to inline the +constructor. Two, you are subclassing a non-Moose parent. + +If you know how to do that, you know when to ignore this best practice +;) + +=head2 Always call the original/parent C<BUILDARGS> + +If you C<override> the C<BUILDARGS> method in your class, make sure to play +nice and call C<super()> to handle cases you're not checking for explicitly. + +The default C<BUILDARGS> method in L<Moose::Object> handles both a +list and hashref of named parameters correctly, and also checks for a +I<non-hashref> single argument. + +=head2 Provide defaults whenever possible, otherwise use C<required> + +When your class provides defaults, this makes constructing new objects +simpler. If you cannot provide a default, consider making the +attribute C<required>. + +If you don't do either, an attribute can simply be left unset, +increasing the complexity of your object, because it has more possible +states that you or the user of your class must account for. + +=head2 Use C<builder> instead of C<default> most of the time + +Builders can be inherited, they have explicit names, and they're just +plain cleaner. + +However, I<do> use a default when the default is a non-reference, +I<or> when the default is simply an empty reference of some sort. + +Also, keep your builder methods private. + +=head2 Be C<lazy> + +Lazy is good, and often solves initialization ordering problems. It's also +good for deferring work that may never have to be done. Make your attributes +C<lazy> unless they're C<required> or have trivial defaults. + +=head2 Consider keeping clearers and predicates private + +Does everyone I<really> need to be able to clear an attribute? +Probably not. Don't expose this functionality outside your class +by default. + +Predicates are less problematic, but there's no reason to make your +public API bigger than it has to be. + +=head2 Avoid C<lazy_build> + +As described above, you rarely actually need a clearer or a predicate. +C<lazy_build> adds both to your public API, which exposes you to use cases that +you must now test for. It's much better to avoid adding them until you really +need them - use explicit C<lazy> and C<builder> options instead. + +=head2 Default to read-only, and consider keeping writers private + +Making attributes mutable just means more complexity to account for in +your program. The alternative to mutable state is to encourage users +of your class to simply make new objects as needed. + +If you I<must> make an attribute read-write, consider making the +writer a separate private method. Narrower APIs are easy to maintain, +and mutable state is trouble. + +In order to declare such attributes, provide a private C<writer> +parameter: + + has pizza => ( + is => 'ro', + isa => 'Pizza', + writer => '_pizza', + ); + +=head2 Think twice before changing an attribute's type in a subclass + +Down this path lies great confusion. If the attribute is an object +itself, at least make sure that it has the same interface as the type +of object in the parent class. + +=head2 Don't use the C<initializer> feature + +Don't know what we're talking about? That's fine. + +=head2 Use L<Moose::Meta::Attribute::Native> traits instead of C<auto_deref> + +The C<auto_deref> feature is a bit troublesome. Directly exposing a complex +attribute is ugly. Instead, consider using L<Moose::Meta::Attribute::Native> +traits to define an API that only exposes the necessary pieces of +functionality. + +=head2 Always call C<inner> in the most specific subclass + +When using C<augment> and C<inner>, we recommend that you call +C<inner> in the most specific subclass of your hierarchy. This makes +it possible to subclass further and extend the hierarchy without +changing the parents. + +=head2 Namespace your types + +Use some sort of namespacing convention for type names. We recommend something +like "MyApp::Type::Foo". We also recommend considering L<MooseX::Types>. + +=head2 Do not coerce Moose built-ins directly + +If you define a coercion for a Moose built-in like C<ArrayRef>, this +will affect every application in the Perl interpreter that uses this +type. + + # very naughty! + coerce 'ArrayRef' + => from Str + => via { [ split /,/ ] }; + +Instead, create a subtype and coerce that: + + subtype 'My::ArrayRef' => as 'ArrayRef'; + + coerce 'My::ArrayRef' + => from 'Str' + => via { [ split /,/ ] }; + +=head2 Do not coerce class names directly + +Just as with Moose built-in types, a class type is global for the +entire interpreter. If you add a coercion for that class name, it can +have magical side effects elsewhere: + + # also very naughty! + coerce 'HTTP::Headers' + => from 'HashRef' + => via { HTTP::Headers->new( %{$_} ) }; + +Instead, we can create an "empty" subtype for the coercion: + + subtype 'My::HTTP::Headers' => as class_type('HTTP::Headers'); + + coerce 'My::HTTP::Headers' + => from 'HashRef' + => via { HTTP::Headers->new( %{$_} ) }; + +=head2 Use coercion instead of unions + +Consider using a type coercion instead of a type union. This was +covered in L<Moose::Manual::Types>. + +=head2 Define all your types in one module + +Define all your types and coercions in one module. This was also +covered in L<Moose::Manual::Types>. + +=head1 BENEFITS OF BEST PRACTICES + +Following these practices has a number of benefits. + +It helps ensure that your code will play nice with others, making it +more reusable and easier to extend. + +Following an accepted set of idioms will make maintenance easier, +especially when someone else has to maintain your code. It will also +make it easier to get support from other Moose users, since your code +will be easier to digest quickly. + +Some of these practices are designed to help Moose do the right thing, +especially when it comes to immutabilization. This means your code +will be faster when immutabilized. + +Many of these practices also help get the most out of meta +programming. If you used an overridden C<new> to do type coercion by +hand, rather than defining a real coercion, there is no introspectable +metadata. This sort of thing is particularly problematic for MooseX +extensions which rely on introspection to do the right thing. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Classes.pod b/lib/Moose/Manual/Classes.pod new file mode 100644 index 0000000..37553d0 --- /dev/null +++ b/lib/Moose/Manual/Classes.pod @@ -0,0 +1,218 @@ +# PODNAME: Moose::Manual::Classes +# ABSTRACT: Making your classes use Moose (and subclassing) + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Classes - Making your classes use Moose (and subclassing) + +=head1 VERSION + +version 2.1405 + +=head1 USING MOOSE + +Using Moose is very simple, you just C<use Moose>: + + package Person; + + use Moose; + +That's it, you've made a class with Moose! + +There's actually a lot going on here under the hood, so let's step +through it. + +When you load L<Moose>, a bunch of sugar functions are exported into your +class, such as C<extends>, C<has>, C<with>, and more. These functions are what +you use to define your class. For example, you might define an attribute ... + + package Person; + + use Moose; + + has 'ssn' => ( is => 'rw' ); + +Attributes are described in the L<Moose::Manual::Attributes> +documentation. + +Loading Moose also enables the C<strict> and C<warnings> pragmas in your +class. + +When you load Moose, your class will become a subclass of +L<Moose::Object>. The L<Moose::Object> class provides a default +constructor and destructor, as well as object construction helper +methods. You can read more about this in the +L<Moose::Manual::Construction> document. + +As a convenience, Moose creates a new class type for your class. See +the L<Moose::Manual::Types> document to learn more about types. + +It also creates a L<Moose::Meta::Class> object for your class. This +metaclass object is now available by calling a C<meta> method on your +class, for example C<< Person->meta >>. + +The metaclass object provides an introspection API for your class. It +is also used by Moose itself under the hood to add attributes, define +parent classes, and so on. In fact, all of Moose's sugar does the real +work by calling methods on this metaclass object (and other meta API +objects). + +=head1 SUBCLASSING + +Moose provides a simple sugar function for declaring your parent +classes, C<extends>: + + package User; + + use Moose; + + extends 'Person'; + + has 'username' => ( is => 'rw' ); + +Note that each call to C<extends> will I<reset> your parents. For +multiple inheritance you must provide all the parents at once, +C<extends 'Foo', 'Bar'>. + +When you call C<extends> Moose will try to load any classes you pass. + +You can use Moose to extend a non-Moose parent. However, when you do +this, you will inherit the parent class's constructor (assuming it is +also called C<new>). In that case, you will have to take care of +initializing attributes manually, either in the parent's constructor, +or in your subclass, and you will lose a lot of Moose magic. + +See the L<MooseX::NonMoose> module on CPAN if you're interested in extending +non-Moose parent classes with Moose child classes. + +=head1 CLEANING UP MOOSE DROPPINGS + +Moose exports a number of functions into your class. It's a good idea to +remove these sugar functions from your class's namespace, so that C<< +Person->can('has') >> will no longer return true. + +There are several ways to do this. We recommend using L<namespace::autoclean>, +a CPAN module. Not only will it remove Moose exports, it will also remove +any other exports. + + package Person; + + use namespace::autoclean; + + use Moose; + +If you absolutely can't use a CPAN module (but can use Moose?), you can write +C<no Moose> at the end of your class. This will remove any Moose exports in +your class. + + package Person; + + use Moose; + + has 'ssn' => ( is => 'rw' ); + + no Moose; + +=head1 MAKING IT FASTER + +Moose has a feature called "immutabilization" that you can use to +greatly speed up your classes at runtime. However, using it incurs +a cost when your class is first being loaded. When you make your class +immutable you tell Moose that you will not be changing it in the +future. You will not be adding any more attributes, methods, roles, etc. + +This allows Moose to generate code specific to your class. In +particular, it creates an "inline" constructor, making object +construction much faster. + +To make your class immutable you simply call C<make_immutable> on your +class's metaclass object. + + __PACKAGE__->meta->make_immutable; + +=head2 Immutabilization and C<new()> + +If you override C<new()> in your class, then the immutabilization code +will not be able to provide an optimized constructor for your +class. Instead, you should use a C<BUILD()> method, which will be +called from the inlined constructor. + +Alternately, if you really need to provide a different C<new()>, you +can also provide your own immutabilization method. Doing so requires +extending the Moose metaclasses, and is well beyond the scope of this +manual. + +=head1 INSTANTIATING CLASSES + +When you're ready to use Moose classes in an application, reference them in +your code in the regular Perl OO way by including a C<use> directive +at the top of the file where the objects should be created. + + use Person; + + my $person = Person->new( + # attribute values at instantiation + # go here + ssn => '123456789', + ); + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Concepts.pod b/lib/Moose/Manual/Concepts.pod new file mode 100644 index 0000000..d6211ef --- /dev/null +++ b/lib/Moose/Manual/Concepts.pod @@ -0,0 +1,439 @@ +# PODNAME: Moose::Manual::Concepts +# ABSTRACT: Moose OO concepts + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Concepts - Moose OO concepts + +=head1 VERSION + +version 2.1405 + +=head1 MOOSE CONCEPTS (VS "OLD SCHOOL" Perl) + +In the past, you may not have thought too much about the difference +between packages and classes, attributes and methods, constructors and +methods, etc. With Moose, these are all conceptually separate, +though under the hood they're implemented with plain old Perl. + +Our meta-object protocol (aka MOP) provides well-defined introspection +features for each of those concepts, and Moose in turn provides +distinct sugar for each of them. Moose also introduces additional +concepts such as roles, method modifiers, and declarative delegation. + +Knowing what these concepts mean in Moose-speak, and how they used to +be done in old school Perl 5 OO is a good way to start learning to use +Moose. + +=head2 Class + +When you say "use Moose" in a package, you are making your package a +class. At its simplest, a class will consist simply of attributes +and/or methods. It can also include roles, method modifiers, and more. + +A class I<has> zero or more B<attributes>. + +A class I<has> zero or more B<methods>. + +A class I<has> zero or more superclasses (aka parent classes). A +class inherits from its superclass(es). + +A class I<has> zero or more B<method modifiers>. These modifiers can +apply to its own methods or methods that are inherited from its +ancestors. + +A class I<does> (and I<consumes>) zero or more B<roles>. + +A class I<has> a B<constructor> and a B<destructor>. These are +provided for you "for free" by Moose. + +The B<constructor> accepts named parameters corresponding to the +class's attributes and uses them to initialize an B<object instance>. + +A class I<has> a B<metaclass>, which in turn has B<meta-attributes>, +B<meta-methods>, and B<meta-roles>. This metaclass I<describes> the +class. + +A class is usually analogous to a category of nouns, like "People" or +"Users". + + package Person; + + use Moose; + # now it's a Moose class! + +=head2 Attribute + +An attribute is a property of the class that defines it. It I<always> +has a name, and it I<may have> a number of other properties. + +These properties can include a read/write flag, a B<type>, accessor +method names, B<delegations>, a default value, and more. + +Attributes I<are not> methods, but defining them causes various +accessor methods to be created. At a minimum, a normal attribute will +have a reader accessor method. Many attributes have other +methods, such as a writer method, a clearer method, or a predicate method +("has it been set?"). + +An attribute may also define B<delegations>, which will create +additional methods based on the delegation mapping. + +By default, Moose stores attributes in the object instance, which is a +hashref, I<but this is invisible to the author of a Moose-based +class>! It is best to think of Moose attributes as "properties" of +the I<opaque> B<object instance>. These properties are accessed +through well-defined accessor methods. + +An attribute is something that the class's members have. For example, +People have first and last names. Users have passwords and last login +datetimes. + + has 'first_name' => ( + is => 'rw', + isa => 'Str', + ); + +=head2 Method + +A B<method> is very straightforward. Any subroutine you define in your +class is a method. + +B<Methods> correspond to verbs, and are what your objects can do. For +example, a User can login. + + sub login { ... } + +=head2 Role + +A role is something that a class I<does>. We also say that classes +I<consume> roles. For example, a Machine class might do the Breakable +role, and so could a Bone class. A role is used to define some concept +that cuts across multiple unrelated classes, like "breakability", or +"has a color". + +A role I<has> zero or more B<attributes>. + +A role I<has> zero or more B<methods>. + +A role I<has> zero or more B<method modifiers>. + +A role I<has> zero or more B<required methods>. + +A required method is not implemented by the role. Required methods are a way +for the role to declare "to use this role you must implement this method". + +A role I<has> zero or more B<excluded roles>. + +An excluded role is a role that the role doing the excluding says it +cannot be combined with. + +Roles are I<composed> into classes (or other roles). When a role is +composed into a class, its attributes and methods are "flattened" into +the class. Roles I<do not> show up in the inheritance hierarchy. When +a role is composed, its attributes and methods appear as if they were +defined I<in the consuming class>. + +Role are somewhat like mixins or interfaces in other OO languages. + + package Breakable; + + use Moose::Role; + + requires 'break'; + + has 'is_broken' => ( + is => 'rw', + isa => 'Bool', + ); + + after 'break' => sub { + my $self = shift; + + $self->is_broken(1); + }; + +=head2 Method modifiers + +A B<method modifier> is a hook that is called when a named method is +called. For example, you could say "before calling C<login()>, call +this modifier first". Modifiers come in different flavors like +"before", "after", "around", and "augment", and you can apply more +than one modifier to a single method. + +Method modifiers are often used as an alternative to overriding a +method in a parent class. They are also used in roles as a way of +modifying methods in the consuming class. + +Under the hood, a method modifier is just a plain old Perl subroutine +that gets called before or after (or around, etc.) some named method. + + before 'login' => sub { + my $self = shift; + my $pw = shift; + + warn "Called login() with $pw\n"; + }; + +=head2 Type + +Moose also comes with a (miniature) type system. This allows you to define +types for attributes. Moose has a set of built-in types based on the types +Perl provides in its core, such as C<Str>, C<Num>, C<Bool>, C<HashRef>, etc. + +In addition, every class name in your application can also be used as +a type name. + +Finally, you can define your own types with their own constraints. For +example, you could define a C<PosInt> type, a subtype of C<Int> which only +allows positive numbers. + +=head2 Delegation + +Moose attributes provide declarative syntax for defining delegations. A +delegation is a method which in turn calls some method on an attribute to do +its real work. + +=head2 Constructor + +A constructor creates an B<object instance> for the class. In old +school Perl, this was usually done by defining a method called +C<new()> which in turn called C<bless> on a reference. + +With Moose, this C<new()> method is created for you, and it simply +does the right thing. You should never need to define your own +constructor! + +Sometimes you want to do something whenever an object is created. In +those cases, you can provide a C<BUILD()> method in your class. Moose +will call this for you after creating a new object. + +=head2 Destructor + +This is a special method called when an object instance goes out of +scope. You can specialize what your class does in this method if you +need to, but you usually don't. + +With old school Perl 5, this is the C<DESTROY()> method, but with +Moose it is the C<DEMOLISH()> method. + +=head2 Object instance + +An object instance is a specific noun in the class's "category". For +example, one specific Person or User. An instance is created by the +class's B<constructor>. + +An instance has values for its attributes. For example, a specific +person has a first and last name. + +In old school Perl 5, this is often a blessed hash reference. With +Moose, you should never need to know what your object instance +actually is. (Okay, it's usually a blessed hashref with Moose, too.) + +=head2 Moose vs old school summary + +=over 4 + +=item * Class + +A package with no introspection other than mucking about in the symbol +table. + +With Moose, you get well-defined declaration and introspection. + +=item * Attributes + +Hand-written accessor methods, symbol table hackery, or a helper +module like C<Class::Accessor>. + +With Moose, these are declaratively defined, and distinct from +methods. + +=item * Method + +These are pretty much the same in Moose as in old school Perl. + +=item * Roles + +C<Class::Trait> or C<Class::Role>, or maybe C<mixin.pm>. + +With Moose, they're part of the core feature set, and are +introspectable like everything else. + +=item * Method Modifiers + +Could only be done through serious symbol table wizardry, and you +probably never saw this before (at least in Perl 5). + +=item * Type + +Hand-written parameter checking in your C<new()> method and accessors. + +With Moose, you define types declaratively, and then use them by name +with your attributes. + +=item * Delegation + +C<Class::Delegation> or C<Class::Delegator>, but probably even more +hand-written code. + +With Moose, this is also declarative. + +=item * Constructor + +A C<new()> method which calls C<bless> on a reference. + +Comes for free when you define a class with Moose. + +=item * Destructor + +A C<DESTROY()> method. + +With Moose, this is called C<DEMOLISH()>. + +=item * Object Instance + +A blessed reference, usually a hash reference. + +With Moose, this is an opaque thing which has a bunch of attributes +and methods, as defined by its class. + +=item * Immutabilization + +Moose comes with a feature called "immutabilization". When you make +your class immutable, it means you're done adding methods, attributes, +roles, etc. This lets Moose optimize your class with a bunch of +extremely dirty in-place code generation tricks that speed up things +like object construction and so on. + +=back + +=head1 META WHAT? + +A metaclass is a class that describes classes. With Moose, every class you +define gets a C<meta()> method. The C<meta()> method returns a +L<Moose::Meta::Class> object, which has an introspection API that can tell you +about the class it represents. + + my $meta = User->meta(); + + for my $attribute ( $meta->get_all_attributes ) { + print $attribute->name(), "\n"; + + if ( $attribute->has_type_constraint ) { + print " type: ", $attribute->type_constraint->name, "\n"; + } + } + + for my $method ( $meta->get_all_methods ) { + print $method->name, "\n"; + } + +Almost every concept we defined earlier has a meta class, so we have +L<Moose::Meta::Class>, L<Moose::Meta::Attribute>, +L<Moose::Meta::Method>, L<Moose::Meta::Role>, +L<Moose::Meta::TypeConstraint>, L<Moose::Meta::Instance>, and so on. + +=head1 BUT I NEED TO DO IT MY WAY! + +One of the great things about Moose is that if you dig down and find +that it does something the "wrong way", you can change it by extending +a metaclass. For example, you can have arrayref based objects, you can +make your constructors strict (no unknown parameters allowed!), you can +define a naming scheme for attribute accessors, you can make a class a +Singleton, and much, much more. + +Many of these extensions require surprisingly small amounts of code, +and once you've done it once, you'll never have to hand-code "your way +of doing things" again. Instead you'll just load your favorite +extensions. + + package MyWay::User; + + use Moose; + use MooseX::StrictConstructor; + use MooseX::MyWay; + + has ...; + +=head1 WHAT NEXT? + +So you're sold on Moose. Time to learn how to really use it. + +If you want to see how Moose would translate directly into old school +Perl 5 OO code, check out L<Moose::Manual::Unsweetened>. This might be +helpful for quickly wrapping your brain around some aspects of "the +Moose way". + +Or you can skip that and jump straight to L<Moose::Manual::Classes> +and the rest of the L<Moose::Manual>. + +After that we recommend that you start with the L<Moose::Cookbook>. If +you work your way through all the recipes under the basics section, +you should have a pretty good sense of how Moose works, and all of its +basic OO features. + +After that, check out the Role recipes. If you're really curious, go +on and read the Meta and Extending recipes, but those are mostly there +for people who want to be Moose wizards and extend Moose itself. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Construction.pod b/lib/Moose/Manual/Construction.pod new file mode 100644 index 0000000..1e6c53f --- /dev/null +++ b/lib/Moose/Manual/Construction.pod @@ -0,0 +1,225 @@ +# PODNAME: Moose::Manual::Construction +# ABSTRACT: Object construction (and destruction) with Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Construction - Object construction (and destruction) with Moose + +=head1 VERSION + +version 2.1405 + +=head1 WHERE'S THE CONSTRUCTOR? + +B<Do not define a C<new()> method for your classes!> + +When you C<use Moose> in your class, your class becomes a subclass of +L<Moose::Object>. The L<Moose::Object> provides a C<new()> method for your +class. If you follow our recommendations in L<Moose::Manual::BestPractices> +and make your class immutable, then you actually get a class-specific C<new()> +method "inlined" in your class. + +=head1 OBJECT CONSTRUCTION AND ATTRIBUTES + +The Moose-provided constructor accepts a hash or hash reference of +named parameters matching your attributes (actually, matching their +C<init_arg>s). This is just another way in which Moose keeps you from +worrying I<how> classes are implemented. Simply define a class and +you're ready to start creating objects! + +=head1 OBJECT CONSTRUCTION HOOKS + +Moose lets you hook into object construction. You can validate an +object's state, do logging, customize construction from parameters which +do not match your attributes, or maybe allow non-hash(ref) constructor +arguments. You can do this by creating C<BUILD> and/or C<BUILDARGS> +methods. + +If these methods exist in your class, Moose will arrange for them to +be called as part of the object construction process. + +=head2 BUILDARGS + +The C<BUILDARGS> method is called as a class method I<before> an +object is created. It will receive all of the arguments that were +passed to C<new()> I<as-is>, and is expected to return a hash +reference. This hash reference will be used to construct the object, +so it should contain keys matching your attributes' names (well, +C<init_arg>s). + +One common use for C<BUILDARGS> is to accommodate a non-hash(ref) +calling style. For example, we might want to allow our Person class to +be called with a single argument of a social security number, C<< +Person->new($ssn) >>. + +Without a C<BUILDARGS> method, Moose will complain, because it expects +a hash or hash reference. We can use the C<BUILDARGS> method to +accommodate this calling style: + + around BUILDARGS => sub { + my $orig = shift; + my $class = shift; + + if ( @_ == 1 && !ref $_[0] ) { + return $class->$orig( ssn => $_[0] ); + } + else { + return $class->$orig(@_); + } + }; + +Note the call to C<< $class->$orig >>. This will call the default C<BUILDARGS> +in L<Moose::Object>. This method takes care of distinguishing between a hash +reference and a plain hash for you. + +=head2 BUILD + +The C<BUILD> method is called I<after> an object is created. There are +several reasons to use a C<BUILD> method. One of the most common is to +check that the object state is valid. While we can validate individual +attributes through the use of types, we can't validate the state of a +whole object that way. + + sub BUILD { + my $self = shift; + + if ( $self->country_of_residence eq 'USA' ) { + die 'All US residents must have an SSN' + unless $self->has_ssn; + } + } + +Another use of a C<BUILD> method could be for logging or tracking +object creation. + + sub BUILD { + my $self = shift; + + debug( 'Made a new person - SSN = ', $self->ssn, ); + } + +The C<BUILD> method is called with the hash reference of the parameters passed +to the constructor (after munging by C<BUILDARGS>). This gives you a chance to +do something with parameters that do not represent object attributes. + + sub BUILD { + my $self = shift; + my $args = shift; + + $self->add_friend( + My::User->new( + user_id => $args->{user_id}, + ) + ); + } + +=head3 BUILD and parent classes + +The interaction between multiple C<BUILD> methods in an inheritance hierarchy +is different from normal Perl methods. B<You should never call C<< +$self->SUPER::BUILD >>>, nor should you ever apply a method modifier to +C<BUILD>. + +Moose arranges to have all of the C<BUILD> methods in a hierarchy +called when an object is constructed, I<from parents to +children>. This might be surprising at first, because it reverses the +normal order of method inheritance. + +The theory behind this is that C<BUILD> methods can only be used for +increasing specialization of a class's constraints, so it makes sense +to call the least specific C<BUILD> method first. Also, this is how +Perl 6 does it. + +=head1 OBJECT DESTRUCTION + +Moose provides a hook for object destruction with the C<DEMOLISH> +method. As with C<BUILD>, you should never explicitly call C<< +$self->SUPER::DEMOLISH >>. Moose will arrange for all of the +C<DEMOLISH> methods in your hierarchy to be called, from most to least +specific. + +Each C<DEMOLISH> method is called with a single argument. This is a boolean +value indicating whether or not this method was called as part of the global +destruction process (when the Perl interpreter exits). + +In most cases, Perl's built-in garbage collection is sufficient, and +you won't need to provide a C<DEMOLISH> method. + +=head2 Error Handling During Destruction + +The interaction of object destruction and Perl's global C<$@> and C<$?> +variables can be very confusing. + +Moose always localizes C<$?> when an object is being destroyed. This means +that if you explicitly call C<exit>, that exit code will be preserved even if +an object's destructor makes a system call. + +Moose also preserves C<$@> against any C<eval> calls that may happen during +object destruction. However, if an object's C<DEMOLISH> method actually dies, +Moose explicitly rethrows that error. + +If you do not like this behavior, you will have to provide your own C<DESTROY> +method and use that instead of the one provided by L<Moose::Object>. You can +do this to preserve C<$@> I<and> capture any errors from object destruction by +creating an error stack. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Contributing.pod b/lib/Moose/Manual/Contributing.pod new file mode 100644 index 0000000..2c3b239 --- /dev/null +++ b/lib/Moose/Manual/Contributing.pod @@ -0,0 +1,546 @@ +# PODNAME: Moose::Manual::Contributing +# ABSTRACT: How to get involved in Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Contributing - How to get involved in Moose + +=head1 VERSION + +version 2.1405 + +=head1 GETTING INVOLVED + +Moose is an open project, and we are always willing to accept bug fixes, +more tests, and documentation patches. Commit bits are given out freely and +it's easy to get started! + +=head2 Get the Code + +If you just want to get your feet wet and check out the code, you can do so +from the comfort of your web browser by going to the official repository on +GitHub: L<https://github.com/moose/Moose>. + +However, if you know how to use git and would rather have a local copy +(because, why wouldn't you?!), then you can clone it: + + git clone git@github.com:moose/Moose.git + +If, at some point, you think you'd like to contribute a patch, please see +L</Getting Started>. + +I<B<NOTE:> Your contribution is very important to us. If, for some reason, +you would prefer not to use Git/GitHub, come talk to us at #moose on +irc.perl.org and we can work something out.> + +=head2 People + +As Moose has matured, some structure has emerged in the process. + +=over + +=item Cabal - people who can release moose + +These people are the ones who have co-maint on Moose itself and can create a +release. They're listed under L<Moose/CABAL> in the Moose documentation. They +are responsible for reviewing branches, and are the only people who are +allowed to push to stable branches. + +Cabal members are listed in L<Moose> and can often be found on irc in the +L<irc://irc.perl.org/#moose-dev> channel. + +=item Contributors - people creating a topic or branch + +You! + +=back + +=head2 New Features + +Moose already has a fairly large feature set, and we are currently +B<not> looking to add any major new features to it. If you have an +idea for a new feature in Moose, you are encouraged to create a +MooseX module first. + +At this stage, no new features will even be considered for addition +into the core without first being vetted as a MooseX module, unless +it is absolutely 100% impossible to implement the feature outside the +core. + +If you think it is 100% impossible, please come discuss it with us on IRC or +via e-mail. Your feature may need a small hook in the core, or a +refactoring of some core modules, and we are definitely open to that. + +Moose was built from the ground up with the idea of being highly extensible, +and quite often the feature requests we see can be implemented through small +extensions. Try it, it's much easier than you might think. + +=head2 Branch Layout + +The repository is divided into several branches to make maintenance easier for +everyone involved. The branches below are ordered by level of stability. + +=over + +=item stable/* + +The branch from which releases are cut. When making a new major release, the +release manager makes a new C<stable/X.YY> branch at the current position of +C<master>. The version used in the stable branch should not include the last +two digits of the version number. + +For minor releases, patches will be committed to C<master>, and +backported (cherry-picked) to the appropriate stable branch as needed. A +stable branch is only updated by someone from the Cabal during a release. + +=item master + +The main development branch. All new code should be written against this +branch. This branch contains code that has been reviewed, and will be included +in the next major release. Commits which are judged to not break backwards +compatibility may be backported into C<stable> to be included in the next minor +release. + +=item topic/* + +Small personal branches that are still in progress. They can be freely rebased. +They contain targeted features that may span a handful of commits. Any change +or bugfix should be created in a topic branch. + +=item rfc/* + +Topic branches that are completed and waiting on review. A Cabal member will +look over branches in this namespace, and either merge them to C<master> if +they are acceptable, or move them back to a different namespace otherwise. +This namespace is being phased out now that we are using GitHub's pull +requests in our L</Development Workflow>. + +=item attic/* + +Branches which have been reviewed, and rejected. They remain in the repository +in case we later change our mind, or in case parts of them are still useful. + +=item abandoned/* + +Topic branches which have had no activity for a long period of time will be +moved here, to keep the main areas clean. + +=back + +Larger, longer term branches can also be created in the root namespace (i.e. +at the same level as master and stable). This may be appropriate if multiple +people are intending to work on the branch. These branches should not be +rebased without checking with other developers first. + +=head1 WORKFLOWS + +=head2 Getting Started + +So, you've cloned the main Moose repository to your local machine (see +L</Get the Code>) and you're ready to do some hacking. We couldn't be +happier to welcome you to our community! + +Of course, to ensure that your first experience is as productive and +satisfying as possible, you should probably take some time to read over this +entire POD document. Doing so will give you a full understanding of how Moose +developers and maintainers work together and what they expect from one +another. Done? Great! + +Next, assuming you have a GitHub account, go to +L<http://github.com/moose/Moose> and B<fork the repository> (see +L<https://help.github.com/articles/fork-a-repo>). This will put an exact +replica of the Moose repository into your GitHub account, which will serve as +a place to publish your patches for the Moose maintainers to review and +incorporate. + +Once your fork has been created, switch to your local working repository directory +and update your C<origin> remote's push URL. This allows you to use a single +remote (C<origin>) to both pull in the latest code from GitHub and also push +your work to your own fork: + + # Replace YOUR_USERNAME below with your GitHub username + git remote set-url --push origin git@github.com:YOUR_USERNAME/moose.git + +You can verify your work: + + $ git remote -v + origin git@github.com:moose/Moose.git (fetch) + origin git@github.com:YOUR_USERNAME/moose.git (push) + +Now, you're ready for action! From now on, you just follow the L</Development +Workflow> to publish your work and B<submit pull requests> to the Moose Cabal. + +=head2 Development Workflow + +The general gist of the B<STANDARD WORKFLOW> is: + +=over 4 + +=item 1. Update your local repository with the latest commits from the official repository + +=item 2. Create a new topic branch, based on the master branch + +=item 3. Hack away + +=item 4. Commit and push the topic branch to your forked repository + +=item 5. Submit a pull request through GitHub for that branch + +=back + +What follows is a more detailed rundown of that workflow. Please make sure to +review and follow the steps in the previous section, L</Getting Started>, if +you have not done so already. + +=head3 Update Your Repository + +Update your local copy of the master branch from the remote: + + git checkout master + git pull --rebase + +=head3 Create Your Topic Branch + +Now, create a new topic branch based on your master branch. It's useful to +use concise, descriptive branch names such as: pod-syntax-contrib, +feat-autodelegation, patch-23-role-comp, etc. However, we'll just call ours +C<my-feature> for demonstration purposes: + + git checkout -b topic/my-feature + +=head3 Hack. Commit. Repeat. + +While you're hacking, the most important thing to remember is that your topic +branch is yours to do with as you like. Nothing you do there will affect +anyone else at this point. Commit as often as little or as often as you need +to and don't let perfection get in the way of progress. However, don't try to +do too much as the easiest changes to integrate are small and focused. + +If it's been a while since you created your topic branch, it's often a good +idea to periodically rebase your branch off of the upstream master to reduce +your work later on: + + git fetch # or, git remote update + git rebase origin/master # or, git pull --rebase origin master + +You should also feel free to publish (using C<push --force> if necessary) your +branch to your GitHub fork if you simply need feedback from others. (Note: +actual collaboration takes a bit more finesse and a lot less C<--force> +however). + +=head3 Clean Up Your Branch + +Finally, when your development is done, it's time to prepare your branch for +review. Even the smallest branches can often use a little bit of tidying up +before they are unleashed on a reviewer. Clarifying/cleaning up commit +messages, reordering commits, splitting large commits or those which contain +different types of changes, squashing related or straggler commits are all +B<highly> worthwhile activities to undertake on your topic branch. + +B<Remember:> Your topic branch is yours. Don't worry about rewriting its +history or breaking fast-forward. Some useful commands are listed below but +please make sure that you understand what they do as they can rewrite history: + + - git commit --amend + - git rebase --interactive + - git cherry-pick + +Ultimately, your goal in cleaning up your branch is to craft a set of commits +whose content and messages are as focused and understandable as possible. +Doing so will greatly increase the chances of a speedy review and acceptance +into the mainline development. + +=head3 Rebase on the Latest + +Before your final push and issuing a pull request, you need to ensure that +your changes can be easily merged into the master branch of the upstream +repository. This is done by once again rebasing your branch on the latest +C<origin/master>. + + git fetch # or, git remote update + git rebase origin/master # or, git pull --rebase origin master + +=head3 Publish and Pull Request + +Now it's time to make your final push of the branch to your fork. The +C<--force> flag is only necessary if you've pushed before and subsequently +rewriting your history: + + git push --force + +After your branch is published, you can issue a pull request to the Moose +Cabal. See <https://help.github.com/articles/using-pull-requests> for details. + +Congratulations! You're now a contributor! + +=head2 Approval Workflow + +Moose is an open project but it is also an increasingly important one. Many +modules depend on Moose being stable. Therefore, we have a basic set of +criteria for reviewing and merging branches. What follows is a set of rough +guidelines that ensures all new code is properly vetted before it is merged to +the master branch. + +It should be noted that if you want your specific branch to be approved, it is +B<your> responsibility to follow this process and advocate for your branch. + +=over 4 + +=item Small bug fixes, doc patches and additional passing tests. + +These items don't really require approval beyond one of the core contributors +just doing a simple review. For especially simple patches (doc patches +especially), committing directly to master is fine. + +=item Larger bug fixes, doc additions and TODO or failing tests. + +Larger bug fixes should be reviewed by at least one cabal member and should be +tested using the F<xt/author/test-my-dependents.t> test. + +New documentation is always welcome, but should also be reviewed by a cabal +member for accuracy. + +TODO tests are basically feature requests, see our L</New Features> section +for more information on that. If your feature needs core support, create a +C<topic/> branch using the L</Development Workflow> and start hacking away. + +Failing tests are basically bug reports. You should find a core contributor +and/or cabal member to see if it is a real bug, then submit the bug and your +test to the RT queue. Source control is not a bug reporting tool. + +=item New user-facing features. + +Anything that creates a new user-visible feature needs to be approved by +B<more than one> cabal member. + +Make sure you have reviewed L</New Features> to be sure that you are following +the guidelines. Do not be surprised if a new feature is rejected for the core. + +=item New internals features. + +New features for Moose internals are less restrictive than user facing +features, but still require approval by B<at least one> cabal member. + +Ideally you will have run the F<test-my-dependents.t> script to be sure you +are not breaking any MooseX module or causing any other unforeseen havoc. If +you do this (rather than make us do it), it will only help to hasten your +branch's approval. + +=item Backwards incompatible changes. + +Anything that breaks backwards compatibility must be discussed by the +cabal. Backwards incompatible changes should not be merged to master if there +are strong objections from any cabal members. + +We have a policy for what we see as sane L</BACKWARDS COMPATIBILITY> for +Moose. If your changes break back-compat, you must be ready to discuss and +defend your change. + +=back + +=head2 Release Workflow + + # major releases (including trial releases) + git checkout master + + # minor releases + git checkout stable/X.YY + + # do final changelogging, etc + vim dist.ini # increment version number + git commit + dzil release # or dzil release --trial for trial releases + git commit # to add the actual release date + git branch stable/X.YY # only for non-trial major releases + +=head3 Release How-To + +Moose uses L<Dist::Zilla> to manage releases. Although the git repository comes +with a C<Makefile.PL>, it is a very basic one just to allow the basic +C<perl Makefile.PL && make && make test> cycle to work. In particular, it +doesn't include any release metadata, such as dependencies. In order to get +started with Dist::Zilla, first install it: C<cpanm Dist::Zilla>, and then +install the plugins necessary for reading the C<dist.ini>: +C<dzil authordeps | cpanm>. + +Moose releases fall into two categories, each with their own level of release +preparation. A minor release is one which does not include any API changes, +deprecations, and so on. In that case, it is sufficient to simply test the +release candidate against a few different Perls. Testing should be done against +at least two recent major versions of Perl (5.8.8 and 5.10.1, for example). If +you have more versions available, you are encouraged to test them all. However, +we do not put a lot of effort into supporting older 5.8.x releases. + +For major releases which include an API change or deprecation, you should run +the F<xt/author/test-my-dependents.t> test. This tests a long list of MooseX +and other Moose-using modules from CPAN. In order to run this script, you must +arrange to have the new version of Moose in Perl's include path. You can use +C<prove -b> and C<prove -I>, install the module, or fiddle with the C<PERL5LIB> +environment variable, whatever makes you happy. + +This test downloads each module from CPAN, runs its tests, and logs failures +and warnings to a set of files named F<test-mydeps-$$-*.log>. If there are +failures or warnings, please work with the authors of the modules in question +to fix them. If the module author simply isn't available or does not want to +fix the bug, it is okay to make a release. + +Regardless of whether or not a new module is available, any breakages should +be noted in the conflicts list in the distribution's F<dist.ini>. + +=head2 Emergency Bug Workflow (for immediate release) + +The stable branch exists for easily making bug fix releases. + + git remote update + git checkout -b topic/my-emergency-fix origin/master + # hack + git commit + +Then a cabal member merges into C<master>, and backports the change into +C<stable/X.YY>: + + git checkout master + git merge topic/my-emergency-fix + git push + git checkout stable/X.YY + git cherry-pick -x master + git push + # release + +=head2 Project Workflow + +For longer lasting branches, we use a subversion style branch layout, where +master is routinely merged into the branch. Rebasing is allowed as long as all +the branch contributors are using C<git pull --rebase> properly. + +C<commit --amend>, C<rebase --interactive>, etc. are not allowed, and should +only be done in topic branches. Committing to master is still done with the +same review process as a topic branch, and the branch must merge as a fast +forward. + +This is pretty much the way we're doing branches for large-ish things right +now. + +Obviously there is no technical limitation on the number of branches. You can +freely create topic branches off of project branches, or sub projects inside +larger projects freely. Such branches should incorporate the name of the branch +they were made off so that people don't accidentally assume they should be +merged into master: + + git checkout -b my-project--topic/foo my-project + +(unfortunately Git will not allow C<my-project/foo> as a branch name if +C<my-project> is a valid ref). + +=head1 BRANCH ARCHIVAL + +Merged branches should be deleted. + +Failed branches may be kept, but should be moved to C<attic/> to differentiate +them from in-progress topic branches. + +Branches that have not been worked on for a long time will be moved to +C<abandoned/> periodically, but feel free to move the branch back to C<topic/> +if you want to start working on it again. + +=head1 TESTS, TESTS, TESTS + +If you write I<any> code for Moose, you B<must> add tests for that code. If you +do not write tests then we cannot guarantee your change will not be removed or +altered at a later date, as there is nothing to confirm this is desired +behavior. + +If your code change/addition is deep within the bowels of Moose and your test +exercises this feature in a non-obvious way, please add some comments either +near the code in question or in the test so that others know. + +We also greatly appreciate documentation to go with your changes, and an entry +in the Changes file. Make sure to give yourself credit! Major changes or new +user-facing features should also be documented in L<Moose::Manual::Delta>. + +=head1 DOCS, DOCS, DOCS + +Any user-facing changes must be accompanied by documentation. If you're not +comfortable writing docs yourself, you might be able to convince another Moose +dev to help you. + +Our goal is to make sure that all features are documented. Undocumented +features are not considered part of the API when it comes to determining +whether a change is backwards compatible. + +=head1 BACKWARDS COMPATIBILITY + +Change is inevitable, and Moose is not immune to this. We do our best +to maintain backwards compatibility, but we do not want the code base +to become overburdened by this. This is not to say that we will be +frivolous with our changes, quite the opposite, just that we are not +afraid of change and will do our best to keep it as painless as +possible for the end user. + +Our policy for handling backwards compatibility is documented in more detail in +L<Moose::Manual::Support>. + +All backwards incompatible changes B<must> be documented in +L<Moose::Manual::Delta>. Make sure to document any useful tips or workarounds +for the change in that document. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Delegation.pod b/lib/Moose/Manual/Delegation.pod new file mode 100644 index 0000000..0d6210d --- /dev/null +++ b/lib/Moose/Manual/Delegation.pod @@ -0,0 +1,313 @@ +# PODNAME: Moose::Manual::Delegation +# ABSTRACT: Attribute delegation + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Delegation - Attribute delegation + +=head1 VERSION + +version 2.1405 + +=head1 WHAT IS DELEGATION? + +Delegation is a feature that lets you create "proxy" methods that do nothing +more than call some other method on an attribute. This lets you simplify a +complex set of "has-a" relationships and present a single unified API from one +class. + +With delegation, consumers of a class don't need to know about all the +objects it contains, reducing the amount of API they need to learn. + +Delegations are defined as a mapping between one or more methods +provided by the "real" class (the delegatee), and a set of +corresponding methods in the delegating class. The delegating class +can re-use the method names provided by the delegatee or provide its +own names. + +Delegation is also a great way to wrap an existing class, especially a +non-Moose class or one that is somehow hard (or impossible) to +subclass. + +=head1 DEFINING A MAPPING + +Moose offers a number of options for defining a delegation's mapping, +ranging from simple to complex. + +The simplest form is to simply specify a list of methods: + + package Website; + + use Moose; + + has 'uri' => ( + is => 'ro', + isa => 'URI', + handles => [qw( host path )], + ); + +Using an arrayref tells Moose to create methods in your class that match the +method names in the delegated class. + +With this definition, we can call C<< $website->host >> and it "just +works". Under the hood, Moose will call C<< $website->uri->host >> for +you. Note that C<$website> is I<not> automatically passed to the C<host> +method; the invocant is C<< $website->uri >>. + +We can also define a mapping as a hash reference. This allows you to +rename methods as part of the mapping: + + package Website; + + use Moose; + + has 'uri' => ( + is => 'ro', + isa => 'URI', + handles => { + hostname => 'host', + path => 'path', + }, + ); + +Using a hash tells Moose to create method names (specified on the left) which +invoke the delegated class methods (specified on the right). + +In this example, we've created a C<< $website->hostname >> method, +rather than simply using C<URI.pm>'s name, C<host> in the Website +class. + +These two mapping forms are the ones you will use most often. The +remaining methods are a bit more complex. + + has 'uri' => ( + is => 'ro', + isa => 'URI', + handles => qr/^(?:host|path|query.*)/, + ); + +This is similar to the array version, except it uses the regex to +match against all the methods provided by the delegatee. In order for +this to work, you must provide an C<isa> parameter for the attribute, +and it must be a class. Moose uses this to introspect the delegatee +class and determine what methods it provides. + +You can use a role name as the value of C<handles>: + + has 'uri' => ( + is => 'ro', + isa => 'URI', + handles => 'HasURI', + ); + +Moose will introspect the role to determine what methods it provides +and create a name-for-name mapping for each of those methods. + +Finally, you can provide a sub reference to I<generate> a mapping that behaves +like the hash example above. You probably won't need this version often (if +ever). See the L<Moose> docs for more details on exactly how this works. + +=head1 NATIVE DELEGATION + +Native delegations allow you to delegate to standard Perl data structures as +if they were objects. + + has 'queue' => ( + traits => ['Array'], + isa => 'ArrayRef[Item]', + default => sub { [ ] }, + handles => { + add_item => 'push', + next_item => 'shift', + }, + ) + +The C<Array> trait in the C<traits> parameter tells Moose that you would like +to use the set of Array helpers. Moose will then create C<add_item> and +C<next_item> methods that "just work". Behind the scenes C<add_item> is +something like + + sub add_item { + my ($self, @items) = @_; + + for my $item (@items) { + $Item_TC->validate($item); + } + + push @{ $self->queue }, @items; + } + +For example, you might use Array helpers to add C<add_task> and +C<add_appointment> methods to a Calendar class: + + has 'tasks' => ( + traits => ['Array'], + isa => 'ArrayRef[Task]', + default => sub { [ ] }, + handles => { + add_task => 'push', + next_task => 'shift', + }, + ); + + has 'appointments' => ( + traits => ['Array'], + isa => 'ArrayRef[Appointment]', + default => sub { [ ] }, + handles => { + add_appointment => 'push', + next_appointment => 'shift', + }, + ); + +Which you would call as: + + $calendar->add_task( $task_obj ); + $calendar->add_appointment( $appointment_obj ); + +As mentioned above, each trait provides a number of methods which are +summarized below. For more information about each of these provided methods +see the documentation for that specific trait. + +Moose includes the following traits for native delegation. + +=over 4 + +=item * L<Array|Moose::Meta::Attribute::Native::Trait::Array> + +The following methods are provided by the native Array trait: + +count, is_empty, elements, get, pop, push, shift, unshift, splice, first, +first_index, grep, map, reduce, sort, sort_in_place, shuffle, uniq, join, set, +delete, insert, clear, accessor, natatime, shallow_clone + +=item * L<Bool|Moose::Meta::Attribute::Native::Trait::Bool> + +The following methods are provided by the native Bool trait: + +set, unset, toggle, not + +=item * L<Code|Moose::Meta::Attribute::Native::Trait::Code> + +The following methods are provided by the native Code trait: + +execute, execute_method + +=item * L<Counter|Moose::Meta::Attribute::Native::Trait::Counter> + +The following methods are provided by the native Counter trait: + +set, inc, dec, reset + +=item * L<Hash|Moose::Meta::Attribute::Native::Trait::Hash> + +The following methods are provided by the native Hash trait: + +get, set, delete, keys, exists, defined, values, kv, elements, clear, count, +is_empty, accessor, shallow_clone + +=item * L<Number|Moose::Meta::Attribute::Native::Trait::Number> + +The following methods are provided by the native Number trait: + +add, sub, mul, div, mod, abs + +=item * L<String|Moose::Meta::Attribute::Native::Trait::String> + +The following methods are provided by the native String trait: + +inc, append, prepend, replace, match, chop, chomp, clear, length, substr + +=back + +=head1 CURRYING + +Currying allows you to create a method with some pre-set parameters. You can +create a curried delegation method: + + package Spider; + use Moose; + + has request => ( + is => 'ro' + isa => 'HTTP::Request', + handles => { + set_user_agent => [ header => 'UserAgent' ], + }, + ) + +With this definition, calling C<< $spider->set_user_agent('MyClient') >> will +call C<< $spider->request->header('UserAgent', 'MyClient') >> behind the +scenes. + +Note that with currying, the currying always starts with the first parameter to +a method (C<$_[0]>). Any arguments you pass to the delegation come after the +curried arguments. + +=head1 MISSING ATTRIBUTES + +It is perfectly valid to delegate methods to an attribute which is not +required or can be undefined. When a delegated method is called, Moose +will throw a runtime error if the attribute does not contain an +object. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Delta.pod b/lib/Moose/Manual/Delta.pod new file mode 100644 index 0000000..34edf17 --- /dev/null +++ b/lib/Moose/Manual/Delta.pod @@ -0,0 +1,1275 @@ +# PODNAME: Moose::Manual::Delta +# ABSTRACT: Important Changes in Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Delta - Important Changes in Moose + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This documents any important or noteworthy changes in Moose, with a +focus on things that affect backwards compatibility. This does duplicate data +from the F<Changes> file, but aims to provide more details and when possible +workarounds. + +Besides helping keep up with changes, you can also use this document +for finding the lowest version of Moose that supported a given +feature. If you encounter a problem and have a solution but don't see +it documented here, or think we missed an important feature, please +send us a patch. + +=head1 2.1400 + +=over 4 + +=item Overloading implementation has changed + +Overloading meta information used to be implemented by a +C<Class::MOP::Method::Overload> class. This class has been removed, and +overloading is now implemented by L<Class::MOP::Overload>. Overloading is not +really equivalent to a method, so the former implementation didn't work +properly for various cases. + +All of the overloading-related methods for classes and roles have the same +names, but those methods now return L<Class::MOP::Overload> objects. + +=item Core support for overloading in roles + +Roles which use overloading now pass that overloading onto other classes (and +roles) which consume that role. + +This works much like L<MooseX::Role::WithOverloading>, except that we properly +detect overloading conflicts during role summation and when applying one role +to another. L<MooseX::Role::WithOverloading> did not do any conflict +detection. + +If you want to write code that uses overloading and works with previous +versions of Moose and this one, upgrade to L<MooseX::Role::WithOverloading> +version 0.15 or greater. That version will detect when Moose itself handles +overloading and get out of the way. + +=back + +=head1 2.1200 + +=over 4 + +=item Classes created by Moose are now registered in C<%INC> + +This means that this will no longer die (and will also no longer try to load +C<Foo.pm>): + + { + package Foo; + use Moose; + } + + # ... + + use Foo; + +If you're using the MOP, this behavior will occur when the C<create> (or +C<create_anon_class>) method is used, but not when the C<initialize> method +is used. + +=item Moose now uses L<Module::Runtime> instead of L<Class::Load> to load classes + +Class::Load has always had some weird issues with the ways that it tries to +figure out if a class is loaded. For instance, extending an empty package was +previously impossible, because Class::Load would think that the class failed to +load, even though that is a perfectly valid thing to do. It was also difficult +to deal with modules like L<IO::Handle>, which partially populate several other +packages when they are loaded (so calling C<load_class> on C<'IO::Handle'> +followed by C<'IO::File'> could end up with a broken C<IO::File>, in some +cases). + +Now, Moose uses the same mechanisms as perl itself to figure out if a class is +loaded. A class is considered to be loaded if its entry in C<%INC> is set. Perl +sets the C<%INC> entry for you automatically whenever a file is loaded via +C<use> or C<require>. Also, as mentioned above, Moose also now sets the C<%INC> +entry for any classes defined with it, even if they aren't loaded from a +separate file. This does however mean that if you are trying to use Moose with +non-Moose classes defined in the same file, then you will need to set C<%INC> +manually now, where it may have worked in the past. For instance: + + { + package My::NonMoose; + + sub new { bless {}, shift } + + $INC{'My/NonMoose.pm'} = __FILE__; + # alternatively: + # use Module::Runtime 'module_notional_filename'; + # $INC{module_notional_filename(__PACKAGE__)} = __FILE__; + } + + { + package My::Moose; + use Moose; + + extends 'My::NonMoose'; + } + +If you don't do this, you will get an error message about not being able to +locate C<My::NonMoose> in C<@INC>. We hope that this case will be fairly rare. + +=item The Class::Load wrapper functions in Class::MOP have been deprecated + +C<Class::MOP::load_class>, C<Class::MOP::is_class_loaded>, and +C<Class::MOP::load_first_existing_class> have been deprecated. They have been +undocumented and discouraged since version 2.0200. You should replace their use +with the corresponding functions in L<Class::Load>, or just use +L<Module::Runtime> directly. + +=item The non-arrayref forms of C<enum> and C<duck_type> have been deprecated + +Originally, C<enum> could be called like this: + + enum('MyType' => qw(foo bar baz)) + +This was confusing, however (since it was different from the syntax for +anonymous enum types), and it makes error checking more difficult (since you +can't tell just by looking whether C<enum('Foo', 'Bar', 'Baz')> was intended to +be a type named C<Foo> with elements of C<Bar> and C<Baz>, or if this was +actually a mistake where someone got the syntax for an anonymous enum type +wrong). This all also applies to C<duck_type>. + +Calling C<enum> and C<duck_type> with a list of arguments as described above +has been undocumented since version 0.93, and is now deprecated. You should +replace + + enum MyType => qw(foo bar baz); + +in your code with + + enum MyType => [qw(foo bar baz)]; + +=item Moose string exceptions have been replaced by Moose exception objects + +Previously, Moose threw string exceptions on error conditions, which were not +so verbose. All those string exceptions have now been converted to exception +objects, which provide very detailed information about the exceptions. These +exception objects provide a string overload that matches the previous exception +message, so in most cases you should not have to change your code. + +For learning about the usage of Moose exception objects, read +L<Moose::Manual::Exceptions>. Individual exceptions are documented in +L<Moose::Manual::Exceptions::Manifest>. + +This work was funded as part of the GNOME Outreach Program for Women. + +=back + +=head1 2.1000 + +=over 4 + +=item The Num type is now stricter + +The C<Num> type used to accept anything that fits Perl's notion of a number, +which included Inf, NaN, and strings like C<" 1234 \n">. We believe that the +type constraint should indicate "this is a number", not "this coerces to a +number". Therefore, Num now only accepts integers, floating point numbers +(both in decimal notation and exponential notation), 0, .0, 0.0, etc. + +If you want the old behavior you can use the C<LaxNum> type in +L<MooseX::Types::LaxNum>. + +=item You can use L<Specio> instead of core Moose types + +The L<Specio> distribution is an experimental new type system intended to +eventually replace the core Moose types, but yet also work with things like +L<Moo> and L<Mouse> and anything else. Right now this is all speculative, but +at least you can use Specio with Moose. + +=back + +=head1 2.0600 + +=over 4 + +=item C<< ->init_meta >> is even less reliable at loading extensions + +Previously, calling C<< MooseX::Foo->init_meta(@_) >> (and nothing else) from +within your own C<init_meta> had a decent chance of doing something useful. +This was never supported behavior, and didn't always work anyway. Due to some +implementation adjustments, this now has a smaller chance of doing something +useful, which could break code that was expecting it to continue doing useful +things. Code that does this should instead just call +C<< MooseX::Foo->import({ into => $into }) >>. + +=item All the Cookbook recipes have been renamed + +We've given them all descriptive names, rather than numbers. This makes it +easier to talk about them, and eliminates the need to renumber recipes in +order to reorder them or delete one. + +=back + +=head1 2.0400 + +=over 4 + +=item The parent of a union type is its components' nearest common ancestor + +Previously, union types considered all of their component types their parent +types. This was incorrect because parent types are defined as types that must +be satisfied in order for the child type to be satisfied, but in a union, +validating as any parent type will validate against the entire union. This has +been changed to find the nearest common ancestor for all of its components. For +example, a union of "Int|ArrayRef[Int]" now has a parent of "Defined". + +=item Union types consider all members in the C<is_subtype_of> and C<is_a_type_of> methods + +Previously, a union type would report itself as being of a subtype of a type if +I<any> of its member types were subtypes of that type. This was incorrect +because any value that passes a subtype constraint must also pass a parent +constraint. This has changed so that I<all> of its member types must be a +subtype of the specified type. + +=item Enum types now work with just one value + +Previously, an C<enum> type needed to have two or more values. Nobody knew +why, so we fixed it. + +=item Methods defined in UNIVERSAL now appear in the MOP + +Any method introspection methods that look at methods from parent classes now +find methods defined in UNIVERSAL. This includes methods like C<< +$class->get_all_methods >> and C<< $class->find_method_by_name >>. + +This also means that you can now apply method modifiers to these methods. + +=item Hand-optimized type constraint code causes a deprecation warning + +If you provide an optimized sub ref for a type constraint, this now causes a +deprecation warning. Typically, this comes from passing an C<optimize_as> +parameter to C<subtype>, but it could also happen if you create a +L<Moose::Meta::TypeConstraint> object directly. + +Use the inlining feature (C<inline_as>) added in 2.0100 instead. + +=item C<Class::Load::load_class> and C<is_class_loaded> have been removed + +The C<Class::MOP::load_class> and C<Class::MOP::is_class_loaded> subroutines +are no longer documented, and will cause a deprecation warning in the +future. Moose now uses L<Class::Load> to provide this functionality, and you +should do so as well. + +=back + +=head1 2.0205 + +=over 4 + +=item Array and Hash native traits provide a C<shallow_clone> method + +The Array and Hash native traits now provide a "shallow_clone" method, which +will return a reference to a new container with the same contents as the +attribute's reference. + +=back + +=head1 2.0200 + +=over 4 + +=item Hand-optimized type constraint code is deprecated in favor of inlining + +Moose allows you to provide a hand-optimized version of a type constraint's +subroutine reference. This version allows type constraints to generate inline +code, and you should use this inlining instead of providing a hand-optimized +subroutine reference. + +This affects the C<optimize_as> sub exported by +L<Moose::Util::TypeConstraints>. Use C<inline_as> instead. + +This will start warning in the 2.0300 release. + +=back + +=head1 2.0002 + +=over 4 + +=item More useful type constraint error messages + +If you have L<Devel::PartialDump> version 0.14 or higher installed, Moose's +type constraint error messages will use it to display the invalid value, rather +than just displaying it directly. This will generally be much more useful. For +instance, instead of this: + + Attribute (foo) does not pass the type constraint because: Validation failed for 'ArrayRef[Int]' with value ARRAY(0x275eed8) + +the error message will instead look like + + Attribute (foo) does not pass the type constraint because: Validation failed for 'ArrayRef[Int]' with value [ "a" ] + +Note that L<Devel::PartialDump> can't be made a direct dependency at the +moment, because it uses Moose itself, but we're considering options to make +this easier. + +=back + +=head1 2.0000 + +=over 4 + +=item Roles have their own default attribute metaclass + +Previously, when a role was applied to a class, it would use the attribute +metaclass defined in the class when copying over the attributes in the role. +This was wrong, because for instance, using L<MooseX::FollowPBP> in the class +would end up renaming all of the accessors generated by the role, some of which +may be being called in the role, causing it to break. Roles now keep track of +their own attribute metaclass to use by default when being applied to a class +(defaulting to Moose::Meta::Attribute). This is modifiable using +L<Moose::Util::MetaRole> by passing the C<applied_attribute> key to the +C<role_metaroles> option, as in: + + Moose::Util::MetaRole::apply_metaroles( + for => __PACKAGE__, + class_metaroles => { + attribute => ['My::Meta::Role::Attribute'], + }, + role_metaroles => { + applied_attribute => ['My::Meta::Role::Attribute'], + }, + ); + +=item Class::MOP has been folded into the Moose dist + +Moose and Class::MOP are tightly related enough that they have always had to be +kept pretty closely in step in terms of versions. Making them into a single +dist should simplify the upgrade process for users, as it should no longer be +possible to upgrade one without the other and potentially cause issues. No +functionality has changed, and this should be entirely transparent. + +=item Moose's conflict checking is more robust and useful + +There are two parts to this. The most useful one right now is that Moose will +ship with a C<moose-outdated> script, which can be run at any point to list the +modules which are installed that conflict with the installed version of Moose. +After upgrading Moose, running C<moose-outdated | cpanm> should be sufficient +to ensure that all of the Moose extensions you use will continue to work. + +The other part is that Moose's C<META.json> file will also specify the +conflicts under the C<x_conflicts> (now C<x_breaks>) key. We are working with the Perl tool chain +developers to try to get conflicts support added to CPAN clients, and if/when +that happens, the metadata already exists, and so the conflict checking will +become automatic. + +=item The lazy_build attribute feature is discouraged + +While not deprecated, we strongly discourage you from using this feature. + +=item Most deprecated APIs/features are slated for removal in Moose 2.0200 + +Most of the deprecated APIs and features in Moose will start throwing an error +in Moose 2.0200. Some of the features will go away entirely, and some will +simply throw an error. + +The things on the chopping block are: + +=over 8 + +=item * Old public methods in Class::MOP and Moose + +This includes things like C<< Class::MOP::Class->get_attribute_map >>, C<< +Class::MOP::Class->construct_instance >>, and many others. These were +deprecated in L<Class::MOP> 0.80_01, released on April 5, 2009. + +These methods will be removed entirely in Moose 2.0200. + +=item * Old public functions in Class::MOP + +This include C<Class::MOP::subname>, C<Class::MOP::in_global_destruction>, and +the C<Class::MOP::HAS_ISAREV> constant. The first two were deprecated in 0.84, +and the last in 0.80. Class::MOP 0.84 was released on May 12, 2009. + +These functions will be removed entirely in Moose 2.0200. + +=item * The C<alias> and C<excludes> option for role composition + +These were renamed to C<-alias> and C<-excludes> in Moose 0.89, released on +August 13, 2009. + +Passing these will throw an error in Moose 2.0200. + +=item * The old L<Moose::Util::MetaRole> API + +This include the C<apply_metaclass_roles()> function, as well as passing the +C<for_class> or any key ending in C<_roles> to C<apply_metaroles()>. This was +deprecated in Moose 0.93_01, released on January 4, 2010. + +These will all throw an error in Moose 2.0200. + +=item * Passing plain lists to C<type()> or C<subtype()> + +The old API for these functions allowed you to pass a plain list of parameter, +rather than a list of hash references (which is what C<as()>, C<where>, +etc. return). This was deprecated in Moose 0.71_01, released on February 22, +2009. + +This will throw an error in Moose 2.0200. + +=item * The Role subtype + +This subtype was deprecated in Moose 0.84, released on June 26, 2009. + +This will be removed entirely in Moose 2.0200. + +=back + +=back + +=head1 1.21 + +=over 4 + +=item * New release policy + +As of the 2.0 release, Moose now has an official release and support policy, +documented in L<Moose::Manual::Support>. All API changes will now go through a +deprecation cycle of at least one year, after which the deprecated API can be +removed. Deprecations and removals will only happen in major releases. + +In between major releases, we will still make minor releases to add new +features, fix bugs, update documentation, etc. + +=back + +=head1 1.16 + +=over 4 + +=item Configurable stacktraces + +Classes which use the L<Moose::Error::Default> error class can now have +stacktraces disabled by setting the C<MOOSE_ERROR_STYLE> env var to C<croak>. +This is experimental, fairly incomplete, and won't work in all cases (because +Moose's error system in general is all of these things), but this should allow +for reducing at least some of the verbosity in most cases. + +=back + +=head1 1.15 + +=over 4 + +=item Native Delegations + +In previous versions of Moose, the Native delegations were created as +closures. The generated code was often quite slow compared to doing the same +thing by hand. For example, the Array's push delegation ended up doing +something like this: + + push @{ $self->$reader() }, @_; + +If the attribute was created without a reader, the C<$reader> sub reference +followed a very slow code path. Even with a reader, this is still slower than +it needs to be. + +Native delegations are now generated as inline code, just like other +accessors, so we can access the slot directly. + +In addition, native traits now do proper constraint checking in all cases. In +particular, constraint checking has been improved for array and hash +references. Previously, only the I<contained> type (the C<Str> in +C<HashRef[Str]>) would be checked when a new value was added to the +collection. However, if there was a constraint that applied to the whole +value, this was never checked. + +In addition, coercions are now called on the whole value. + +The delegation methods now do more argument checking. All of the methods check +that a valid number of arguments were passed to the method. In addition, the +delegation methods check that the arguments are sane (array indexes, hash +keys, numbers, etc.) when applicable. We have tried to emulate the behavior of +Perl builtins as much as possible. + +Finally, triggers are called whenever the value of the attribute is changed by +a Native delegation. + +These changes are only likely to break code in a few cases. + +The inlining code may or may not preserve the original reference when changes +are made. In some cases, methods which change the value may replace it +entirely. This will break tied values. + +If you have a typed arrayref or hashref attribute where the type enforces a +constraint on the whole collection, this constraint will now be checked. It's +possible that code which previously ran without errors will now cause the +constraint to fail. However, presumably this is a good thing ;) + +If you are passing invalid arguments to a delegation which were previously +being ignored, these calls will now fail. + +If your code relied on the trigger only being called for a regular writer, +that may cause problems. + +As always, you are encouraged to test before deploying the latest version of +Moose to production. + +=item Defaults is and default for String, Counter, and Bool + +A few native traits (String, Counter, Bool) provide default values of "is" and +"default" when you created an attribute. Allowing them to provide these values +is now deprecated. Supply the value yourself when creating the attribute. + +=item The C<meta> method + +Moose and Class::MOP have been cleaned up internally enough to make the +C<meta> method that you get by default optional. C<use Moose> and +C<use Moose::Role> now can take an additional C<-meta_name> option, which +tells Moose what name to use when installing the C<meta> method. Passing +C<undef> to this option suppresses generation of the C<meta> method +entirely. This should be useful for users of modules which also use a C<meta> +method or function, such as L<Curses> or L<Rose::DB::Object>. + +=back + +=head1 1.09 + +=over 4 + +=item All deprecated features now warn + +Previously, deprecation mostly consisted of simply saying "X is deprecated" in +the Changes file. We were not very consistent about actually warning. Now, all +deprecated features still present in Moose actually give a warning. The +warning is issued once per calling package. See L<Moose::Deprecated> for more +details. + +=item You cannot pass C<< coerce => 1 >> unless the attribute's type constraint has a coercion + +Previously, this was accepted, and it sort of worked, except that if you +attempted to set the attribute after the object was created, you would get a +runtime error. + +Now you will get a warning when you attempt to define the attribute. + +=item C<no Moose>, C<no Moose::Role>, and C<no Moose::Exporter> no longer unimport strict and warnings + +This change was made in 1.05, and has now been reverted. We don't know if the +user has explicitly loaded strict or warnings on their own, and unimporting +them is just broken in that case. + +=item Reversed logic when defining which options can be changed + +L<Moose::Meta::Attribute> now allows all options to be changed in an +overridden attribute. The previous behaviour required each option to be +whitelisted using the C<legal_options_for_inheritance> method. This method has +been removed, and there is a new method, C<illegal_options_for_inheritance>, +which can now be used to prevent certain options from being changeable. + +In addition, we only throw an error if the illegal option is actually +changed. If the superclass didn't specify this option at all when defining the +attribute, the subclass version can still add it as an option. + +Example of overriding this in an attribute trait: + + package Bar::Meta::Attribute; + use Moose::Role; + + has 'my_illegal_option' => ( + isa => 'CodeRef', + is => 'rw', + ); + + around illegal_options_for_inheritance => sub { + return ( shift->(@_), qw/my_illegal_option/ ); + }; + +=back + +=head1 1.05 + +=over 4 + +=item L<Moose::Object/BUILD> methods are now called when calling C<new_object> + +Previously, C<BUILD> methods would only be called from C<Moose::Object::new>, +but now they are also called when constructing an object via +C<Moose::Meta::Class::new_object>. C<BUILD> methods are an inherent part of the +object construction process, and this should make C<< $meta->new_object >> +actually usable without forcing people to use C<< $meta->name->new >>. + +=item C<no Moose>, C<no Moose::Role>, and C<no Moose::Exporter> now unimport strict and warnings + +In the interest of having C<no Moose> clean up everything that C<use Moose> +does in the calling scope, C<no Moose> (as well as all other +L<Moose::Exporter>-using modules) now unimports strict and warnings. + +=item Metaclass compatibility checking and fixing should be much more robust + +The L<metaclass compatibility|Moose/METACLASS COMPATIBILITY AND MOOSE> checking +and fixing algorithms have been completely rewritten, in both Class::MOP and +Moose. This should resolve many confusing errors when dealing with non-Moose +inheritance and with custom metaclasses for things like attributes, +constructors, etc. For correct code, the only thing that should require a +change is that custom error metaclasses must now inherit from +L<Moose::Error::Default>. + +=back + +=head1 1.02 + +=over 4 + +=item Moose::Meta::TypeConstraint::Class is_subtype_of behavior + +Earlier versions of L<is_subtype_of|Moose::Meta::TypeConstraint::Class/is_subtype_of> +would incorrectly return true when called with itself, its own TC name or +its class name as an argument. (i.e. $foo_tc->is_subtype_of('Foo') == 1) This +behavior was a caused by C<isa> being checked before the class name. The old +behavior can be accessed with L<is_type_of|Moose::Meta::TypeConstraint::Class/is_type_of> + +=back + +=head1 1.00 + +=over 4 + +=item Moose::Meta::Attribute::Native::Trait::Code no longer creates reader methods by default + +Earlier versions of L<Moose::Meta::Attribute::Native::Trait::Code> created +read-only accessors for the attributes it's been applied to, even if you didn't +ask for it with C<< is => 'ro' >>. This incorrect behaviour has now been fixed. + +=back + +=head1 0.95 + +=over 4 + +=item Moose::Util add_method_modifier behavior + +add_method_modifier (and subsequently the sugar functions Moose::before, +Moose::after, and Moose::around) can now accept arrayrefs, with the same +behavior as lists. Types other than arrayref and regexp result in an error. + +=back + +=head1 0.93_01 and 0.94 + +=over 4 + +=item Moose::Util::MetaRole API has changed + +The C<apply_metaclass_roles> function is now called C<apply_metaroles>. The +way arguments are supplied has been changed to force you to distinguish +between metaroles applied to L<Moose::Meta::Class> (and helpers) versus +L<Moose::Meta::Role>. + +The old API still works, but will warn in a future release, and eventually be +removed. + +=item Moose::Meta::Role has real attributes + +The attributes returned by L<Moose::Meta::Role> are now instances of the +L<Moose::Meta::Role::Attribute> class, instead of bare hash references. + +=item "no Moose" now removes C<blessed> and C<confess> + +Moose is now smart enough to know exactly what it exported, even when it +re-exports functions from other packages. When you unimport Moose, it will +remove these functions from your namespace unless you I<also> imported them +directly from their respective packages. + +If you have a C<no Moose> in your code I<before> you call C<blessed> or +C<confess>, your code will break. You can either move the C<no Moose> call +later in your code, or explicitly import the relevant functions from the +packages that provide them. + +=item L<Moose::Exporter> is smarter about unimporting re-exports + +The change above comes from a general improvement to L<Moose::Exporter>. It +will now unimport any function it exports, even if that function is a +re-export from another package. + +=item Attributes in roles can no longer override class attributes with "+foo" + +Previously, this worked more or less accidentally, because role attributes +weren't objects. This was never documented, but a few MooseX modules took +advantage of this. + +=item The composition_class_roles attribute in L<Moose::Meta::Role> is now a method + +This was done to make it possible for roles to alter the list of composition +class roles by applying a method modifiers. Previously, this was an attribute +and MooseX modules override it. Since that no longer works, this was made a +method. + +This I<should> be an attribute, so this may switch back to being an attribute +in the future if we can figure out how to make this work. + +=back + +=head1 0.93 + +=over 4 + +=item Calling $object->new() is no longer deprecated + +We decided to undeprecate this. Now it just works. + +=item Both C<get_method_map> and C<get_attribute_map> is deprecated + +These metaclass methods were never meant to be public, and they are both now +deprecated. The work around if you still need the functionality they provided +is to iterate over the list of names manually. + + my %fields = map { $_ => $meta->get_attribute($_) } $meta->get_attribute_list; + +This was actually a change in L<Class::MOP>, but this version of Moose +requires a version of L<Class::MOP> that includes said change. + +=back + +=head1 0.90 + +=over 4 + +=item Added Native delegation for Code refs + +See L<Moose::Meta::Attribute::Native::Trait::Code> for details. + +=item Calling $object->new() is deprecated + +Moose has long supported this, but it's never really been documented, and we +don't think this is a good practice. If you want to construct an object from +an existing object, you should provide some sort of alternate constructor like +C<< $object->clone >>. + +Calling C<< $object->new >> now issues a warning, and will be an error in a +future release. + +=item Moose no longer warns if you call C<make_immutable> for a class with mutable ancestors + +While in theory this is a good thing to warn about, we found so many +exceptions to this that doing this properly became quite problematic. + +=back + +=head1 0.89_02 + +=over 4 + +=item New Native delegation methods from L<List::Util> and L<List::MoreUtils> + +In particular, we now have C<reduce>, C<shuffle>, C<uniq>, and C<natatime>. + +=item The Moose::Exporter with_caller feature is now deprecated + +Use C<with_meta> instead. The C<with_caller> option will start warning in a +future release. + +=item Moose now warns if you call C<make_immutable> for a class with mutable ancestors + +This is dangerous because modifying a class after a subclass has been +immutabilized will lead to incorrect results in the subclass, due to inlining, +caching, etc. This occasionally happens accidentally, when a class loads one +of its subclasses in the middle of its class definition, so pointing out that +this may cause issues should be helpful. Metaclasses (classes that inherit +from L<Class::MOP::Object>) are currently exempt from this check, since at the +moment we aren't very consistent about which metaclasses we immutabilize. + +=item C<enum> and C<duck_type> now take arrayrefs for all forms + +Previously, calling these functions with a list would take the first element of +the list as the type constraint name, and use the remainder as the enum values +or method names. This makes the interface inconsistent with the anon-type forms +of these functions (which must take an arrayref), and a free-form list where +the first value is sometimes special is hard to validate (and harder to give +reasonable error messages for). These functions have been changed to take +arrayrefs in all their forms - so, C<< enum 'My::Type' => [qw(foo bar)] >> is +now the preferred way to create an enum type constraint. The old syntax still +works for now, but it will hopefully be deprecated and removed in a future +release. + +=back + +=head1 0.89_01 + +L<Moose::Meta::Attribute::Native> has been moved into the Moose core from +L<MooseX::AttributeHelpers>. Major changes include: + +=over 4 + +=item C<traits>, not C<metaclass> + +Method providers are only available via traits. + +=item C<handles>, not C<provides> or C<curries> + +The C<provides> syntax was like core Moose C<< handles => HASHREF >> +syntax, but with the keys and values reversed. This was confusing, +and AttributeHelpers now uses C<< handles => HASHREF >> in a way that +should be intuitive to anyone already familiar with how it is used for +other attributes. + +The C<curries> functionality provided by AttributeHelpers has been +generalized to apply to all cases of C<< handles => HASHREF >>, though +not every piece of functionality has been ported (currying with a +CODEREF is not supported). + +=item C<empty> is now C<is_empty>, and means empty, not non-empty + +Previously, the C<empty> method provided by Arrays and Hashes returned true if +the attribute was B<not> empty (no elements). Now it returns true if the +attribute B<is> empty. It was also renamed to C<is_empty>, to reflect this. + +=item C<find> was renamed to C<first>, and C<first> and C<last> were removed + +L<List::Util> refers to the functionality that we used to provide under C<find> +as L<first|List::Util/first>, so that will likely be more familiar (and will +fit in better if we decide to add more List::Util functions). C<first> and +C<last> were removed, since their functionality is easily duplicated with +curries of C<get>. + +=item Helpers that take a coderef of one argument now use C<$_> + +Subroutines passed as the first argument to C<first>, C<map>, and C<grep> now +receive their argument in C<$_> rather than as a parameter to the subroutine. +Helpers that take a coderef of two or more arguments remain using the argument +list (there are technical limitations to using C<$a> and C<$b> like C<sort> +does). + +See L<Moose::Meta::Attribute::Native> for the new documentation. + +=back + +The C<alias> and C<excludes> role parameters have been renamed to C<-alias> +and C<-excludes>. The old names still work, but new code should use the new +names, and eventually the old ones will be deprecated and removed. + +=head1 0.89 + +C<< use Moose -metaclass => 'Foo' >> now does alias resolution, just like +C<-traits> (and the C<metaclass> and C<traits> options to C<has>). + +Added two functions C<meta_class_alias> and C<meta_attribute_alias> to +L<Moose::Util>, to simplify aliasing metaclasses and metatraits. This is +a wrapper around the old + + package Moose::Meta::Class::Custom::Trait::FooTrait; + sub register_implementation { 'My::Meta::Trait' } + +way of doing this. + +=head1 0.84 + +When an attribute generates I<no> accessors, we now warn. This is to help +users who forget the C<is> option. If you really do not want any accessors, +you can use C<< is => 'bare' >>. You can maintain back compat with older +versions of Moose by using something like: + + ($Moose::VERSION >= 0.84 ? is => 'bare' : ()) + +When an accessor overwrites an existing method, we now warn. To work around +this warning (if you really must have this behavior), you can explicitly +remove the method before creating it as an accessor: + + sub foo {} + + __PACKAGE__->meta->remove_method('foo'); + + has foo => ( + is => 'ro', + ); + +When an unknown option is passed to C<has>, we now warn. You can silence +the warning by fixing your code. :) + +The C<Role> type has been deprecated. On its own, it was useless, +since it just checked C<< $object->can('does') >>. If you were using +it as a parent type, just call C<role_type('Role::Name')> to create an +appropriate type instead. + +=head1 0.78 + +C<use Moose::Exporter;> now imports C<strict> and C<warnings> into packages +that use it. + +=head1 0.77 + +C<DEMOLISHALL> and C<DEMOLISH> now receive an argument indicating whether or +not we are in global destruction. + +=head1 0.76 + +Type constraints no longer run coercions for a value that already matches the +constraint. This may affect some (arguably buggy) edge case coercions that +rely on side effects in the C<via> clause. + +=head1 0.75 + +L<Moose::Exporter> now accepts the C<-metaclass> option for easily +overriding the metaclass (without L<metaclass>). This works for classes +and roles. + +=head1 0.74 + +Added a C<duck_type> sugar function to L<Moose::Util::TypeConstraints> +to make integration with non-Moose classes easier. It simply checks if +C<< $obj->can() >> a list of methods. + +A number of methods (mostly inherited from L<Class::MOP>) have been +renamed with a leading underscore to indicate their internal-ness. The +old method names will still work for a while, but will warn that the +method has been renamed. In a few cases, the method will be removed +entirely in the future. This may affect MooseX authors who were using +these methods. + +=head1 0.73 + +Calling C<subtype> with a name as the only argument now throws an +exception. If you want an anonymous subtype do: + + my $subtype = subtype as 'Foo'; + +This is related to the changes in version 0.71_01. + +The C<is_needed> method in L<Moose::Meta::Method::Destructor> is now +only usable as a class method. Previously, it worked as a class or +object method, with a different internal implementation for each +version. + +The internals of making a class immutable changed a lot in Class::MOP +0.78_02, and Moose's internals have changed along with it. The +external C<< $metaclass->make_immutable >> method still works the same +way. + +=head1 0.72 + +A mutable class accepted C<< Foo->new(undef) >> without complaint, +while an immutable class would blow up with an unhelpful error. Now, +in both cases we throw a helpful error instead. + +This "feature" was originally added to allow for cases such as this: + + my $args; + + if ( something() ) { + $args = {...}; + } + + return My::Class->new($args); + +But we decided this is a bad idea and a little too magical, because it +can easily mask real errors. + +=head1 0.71_01 + +Calling C<type> or C<subtype> without the sugar helpers (C<as>, +C<where>, C<message>) is now deprecated. + +As a side effect, this meant we ended up using Perl prototypes on +C<as>, and code like this will no longer work: + + use Moose::Util::TypeConstraints; + use Declare::Constraints::Simple -All; + + subtype 'ArrayOfInts' + => as 'ArrayRef' + => IsArrayRef(IsInt); + +Instead it must be changed to this: + + subtype( + 'ArrayOfInts' => { + as => 'ArrayRef', + where => IsArrayRef(IsInt) + } + ); + +If you want to maintain backwards compat with older versions of Moose, +you must explicitly test Moose's C<VERSION>: + + if ( Moose->VERSION < 0.71_01 ) { + subtype 'ArrayOfInts' + => as 'ArrayRef' + => IsArrayRef(IsInt); + } + else { + subtype( + 'ArrayOfInts' => { + as => 'ArrayRef', + where => IsArrayRef(IsInt) + } + ); + } + +=head1 0.70 + +We no longer pass the meta-attribute object as a final argument to +triggers. This actually changed for inlined code a while back, but the +non-inlined version and the docs were still out of date. + +If by some chance you actually used this feature, the workaround is +simple. You fetch the attribute object from out of the C<$self> +that is passed as the first argument to trigger, like so: + + has 'foo' => ( + is => 'ro', + isa => 'Any', + trigger => sub { + my ( $self, $value ) = @_; + my $attr = $self->meta->find_attribute_by_name('foo'); + + # ... + } + ); + +=head1 0.66 + +If you created a subtype and passed a parent that Moose didn't know +about, it simply ignored the parent. Now it automatically creates the +parent as a class type. This may not be what you want, but is less +broken than before. + +You could declare a name with subtype such as "Foo!Bar". Moose would +accept this allowed, but if you used it in a parameterized type such +as "ArrayRef[Foo!Bar]" it wouldn't work. We now do some vetting on +names created via the sugar functions, so that they can only contain +alphanumerics, ":", and ".". + +=head1 0.65 + +Methods created via an attribute can now fulfill a C<requires> +declaration for a role. Honestly we don't know why Stevan didn't make +this work originally, he was just insane or something. + +Stack traces from inlined code will now report the line and file as +being in your class, as opposed to in Moose guts. + +=head1 0.62_02 + +When a class does not provide all of a role's required methods, the +error thrown now mentions all of the missing methods, as opposed to +just the first missing method. + +Moose will no longer inline a constructor for your class unless it +inherits its constructor from Moose::Object, and will warn when it +doesn't inline. If you want to force inlining anyway, pass +C<< replace_constructor => 1 >> to C<make_immutable>. + +If you want to get rid of the warning, pass C<< inline_constructor => +0 >>. + +=head1 0.62 + +Removed the (deprecated) C<make_immutable> keyword. + +Removing an attribute from a class now also removes delegation +(C<handles>) methods installed for that attribute. This is correct +behavior, but if you were wrongly relying on it you might get bit. + +=head1 0.58 + +Roles now add methods by calling C<add_method>, not +C<alias_method>. They make sure to always provide a method object, +which will be cloned internally. This means that it is now possible to +track the source of a method provided by a role, and even follow its +history through intermediate roles. This means that methods added by +a role now show up when looking at a class's method list/map. + +Parameter and Union args are now sorted, this makes Int|Str the same +constraint as Str|Int. Also, incoming type constraint strings are +normalized to remove all whitespace differences. This is mostly for +internals and should not affect outside code. + +L<Moose::Exporter> will no longer remove a subroutine that the +exporting package re-exports. Moose re-exports the Carp::confess +function, among others. The reasoning is that we cannot know whether +you have also explicitly imported those functions for your own use, so +we err on the safe side and always keep them. + +=head1 0.56 + +C<Moose::init_meta> should now be called as a method. + +New modules for extension writers, L<Moose::Exporter> and +L<Moose::Util::MetaRole>. + +=head1 0.55_01 + +Implemented metaclass traits (and wrote a recipe for it): + + use Moose -traits => 'Foo' + +This should make writing small Moose extensions a little +easier. + +=head1 0.55 + +Fixed C<coerce> to accept anon types just like C<subtype> can. +So that you can do: + + coerce $some_anon_type => from 'Str' => via { ... }; + +=head1 0.51 + +Added C<BUILDARGS>, a new step in C<< Moose::Object->new() >>. + +=head1 0.49 + +Fixed how the C<< is => (ro|rw) >> works with custom defined +C<reader>, C<writer> and C<accessor> options. See the below table for +details: + + is => ro, writer => _foo # turns into (reader => foo, writer => _foo) + is => rw, writer => _foo # turns into (reader => foo, writer => _foo) + is => rw, accessor => _foo # turns into (accessor => _foo) + is => ro, accessor => _foo # error, accesor is rw + +=head1 0.45 + +The C<before/around/after> method modifiers now support regexp +matching of method names. NOTE: this only works for classes, it is +currently not supported in roles, but, ... patches welcome. + +The C<has> keyword for roles now accepts the same array ref form that +L<Moose>.pm does for classes. + +A trigger on a read-only attribute is no longer an error, as it's +useful to trigger off of the constructor. + +Subtypes of parameterizable types now are parameterizable types +themselves. + +=head1 0.44 + +Fixed issue where C<DEMOLISHALL> was eating the value in C<$@>, and so +not working correctly. It still kind of eats them, but so does vanilla +perl. + +=head1 0.41 + +Inherited attributes may now be extended without restriction on the +type ('isa', 'does'). + +The entire set of Moose::Meta::TypeConstraint::* classes were +refactored in this release. If you were relying on their internals you +should test your code carefully. + +=head1 0.40 + +Documenting the use of '+name' with attributes that come from recently +composed roles. It makes sense, people are using it, and so why not +just officially support it. + +The C<< Moose::Meta::Class->create >> method now supports roles. + +It is now possible to make anonymous enum types by passing C<enum> an +array reference instead of the C<< enum $name => @values >>. + +=head1 0.37 + +Added the C<make_immutable> keyword as a shortcut to calling +C<make_immutable> on the meta object. This eventually got removed! + +Made C<< init_arg => undef >> work in Moose. This means "do not accept +a constructor parameter for this attribute". + +Type errors now use the provided message. Prior to this release they +didn't. + +=head1 0.34 + +Moose is now a postmodern object system :) + +The Role system was completely refactored. It is 100% backwards +compat, but the internals were totally changed. If you relied on the +internals then you are advised to test carefully. + +Added method exclusion and aliasing for Roles in this release. + +Added the L<Moose::Util::TypeConstraints::OptimizedConstraints> +module. + +Passing a list of values to an accessor (which is only expecting one +value) used to be silently ignored, now it throws an error. + +=head1 0.26 + +Added parameterized types and did a pretty heavy refactoring of the +type constraint system. + +Better framework extensibility and better support for "making your own +Moose". + +=head1 0.25 or before + +Honestly, you shouldn't be using versions of Moose that are this old, +so many bug fixes and speed improvements have been made you would be +crazy to not upgrade. + +Also, I am tired of going through the Changelog so I am stopping here, +if anyone would like to continue this please feel free. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Exceptions.pod b/lib/Moose/Manual/Exceptions.pod new file mode 100644 index 0000000..61435a2 --- /dev/null +++ b/lib/Moose/Manual/Exceptions.pod @@ -0,0 +1,239 @@ +# PODNAME: Moose::Manual::Exceptions +# ABSTRACT: Moose's exceptions + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Exceptions - Moose's exceptions + +=head1 VERSION + +version 2.1405 + +=head1 EXCEPTIONS IN MOOSE + +Moose will throw an exception for all error conditions. This applies both to +code in the Moose core I<as well> as to all code generated when a class is +made immutable. All exceptions are subclasses of the C<Moose::Exception> +class. + +Each type of error has its own unique subclass, and many subclasses have +additional attributes to provide more information about the error's context, +such as what classes or roles were involved. + +=head1 EXCEPTION STRINGIFICATION + +By default, Moose exceptions remove Moose internals from the stack trace. If +you set the C<MOOSE_FULL_EXCEPTION> environment variable to a true value, then +the Moose internals will be included in the trace. + +=head1 HANDLING MOOSE EXCEPTIONS + +Because Moose's exceptions use the standard C<die> mechanism, you are free to +catch and handle errors however you like. You could use an C<eval> block to +catch Moose exceptions. However, the Moose team strongly recommends using +L<Try::Tiny> instead. Please refer to L<Try::Tiny>'s documentation for a +discussion of how C<eval> is dangerous. + +The following example demonstrates how to catch and inspect a +L<Moose::Exception>. For the sake of simplicity, we will cause a very simple +error. The C<extends> keywords expects a list of superclass names. If we pass +no superclass names, Moose will throw an instance of +L<Moose::Exception::ExtendsMissingArgs>. + +=head2 Catching with Try::Tiny + + use warnings; + use strict; + use Try::Tiny; + + try { + package Example::Exception; + use Moose; + extends; # <-- error! + } + catch { + # $_ contains the instance of the exception thrown by the above try + # block, but $_ may get clobbered, so we should copy its value to + # another variable. + my $e = $_; + + # Exception objects are not ubiquitous in Perl, so we must check + # whether $e is blessed. We also need to ensure that $e is actually + # the kind of exception we were expecting. + if ( blessed $e + && $e->isa('Moose::Exception::ExtendsMissingArgs') ) { + + my $class_name = $e->class_name; + warn "You forgot to specify a superclass for $class_name, silly!"; + } + + # It's either another type of an object or not an object at all. + else { + warn "$e\n"; + } + } + +=head2 Example of catching ValidationFailedForTypeConstraint + + use warnings; + use strict; + + use Try::Tiny; + + { + package Person; + use Moose; + use Moose::Util::TypeConstraints; + + subtype 'NameStr', + as 'Str', + where { $_ =~ /^[a-zA-Z]+$/; }; + + has age => ( + is => 'ro', + isa => 'Int', + required => 1 + ); + + has name => ( + is => 'ro', + isa => 'NameStr', + required => 1 + ); + } + + my $person; + while ( !$person ) { + try { + print 'Enter your age : '; + my $age = <STDIN>; + chomp $age; + print 'Enter your name : '; + my $name = <STDIN>; + chomp $name; + $person = Person->new( + age => $age, + name => $name + ); + my $person_name = $person->name; + my $person_age = $person->age; + print "$person_name is $person_age years old\n"; + } + catch { + my $e = $_; + + if ( + blessed $e + && $e->isa( + 'Moose::Exception::ValidationFailedForTypeConstraint') + ) { + + my $attribute_name = $e->attribute->name; + my $type_name = $e->type->name; + my $value = $e->value; + + warn + "You entered $value for $attribute_name, which is not a $type_name!"; + } + else { + warn "$e\n"; + } + } + } + +=head2 Example of catching AttributeIsRequired + + use warnings; + use strict; + use Try::Tiny; + + { + package Example::RequiredAttribute; + use Moose; + + has required_attribute => ( + is => 'ro', + isa => 'Int', + required => 1 + ); + } + + try { + # we're not passing required_attribute, so it'll throw an exception + my $object = Example::RequiredAttribute->new(); + } + catch { + my $e = $_; + if ( blessed $e && $e->isa('Moose::Exception::AttributeIsRequired') ) + { + warn $e->message, "\n"; + } + else { + warn "$e\n"; + } + }; + +=head1 MOOSE EXCEPTION CLASSES + +All the exception classes are listed in L<Moose::Manual::Exceptions::Manifest>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Exceptions/Manifest.pod b/lib/Moose/Manual/Exceptions/Manifest.pod new file mode 100644 index 0000000..3fd0e68 --- /dev/null +++ b/lib/Moose/Manual/Exceptions/Manifest.pod @@ -0,0 +1,8343 @@ +# PODNAME: Moose::Manual::Exceptions::Manifest +# ABSTRACT: Moose's Exception Types + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Exceptions::Manifest - Moose's Exception Types + +=head1 VERSION + +version 2.1405 + +=head1 Moose::Exception::AccessorMustReadWrite + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot define an accessor name on a read-only attribute, accessors are read/ +write + +=head1 Moose::Exception::AddParameterizableTypeTakesParameterizableType + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + Type must be a Moose::Meta::TypeConstraint::Parameterizable not Foo + +=head1 Moose::Exception::AddRoleTakesAMooseMetaRoleInstance + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_to_be_added >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles must be instances of Moose::Meta::Role + +=head1 Moose::Exception::AddRoleToARoleTakesAMooseMetaRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->role_to_be_added >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles must be instances of Moose::Meta::Role + +=head1 Moose::Exception::ApplyTakesABlessedInstance + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->param >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass in an blessed instance + +=head1 Moose::Exception::AttachToClassNeedsAClassMOPClassInstanceOrASubclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->class >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a Class::MOP::Class instance (or a subclass) + +=head1 Moose::Exception::AttributeConflictInRoles + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->second_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Role 'Foo4' has encountered an attribute conflict while being composed into +'Bar4'. This is a fatal error and cannot be disambiguated. The conflicting +attribute is named 'foo'. + +=head1 Moose::Exception::AttributeConflictInSummation + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::AttributeName>, L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->second_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + We have encountered an attribute conflict with 'foo' during role composition +. This attribute is defined in both Foo2 and Bar2. This is a fatal error and +cannot be disambiguated. + +=head1 Moose::Exception::AttributeExtensionIsNotSupportedInRoles + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + has '+attr' is not supported in roles + +=head1 Moose::Exception::AttributeIsRequired + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute can be used for fetching attribute instance: + my $class = Moose::Util::find_meta( $exception->class_name ); + my $attribute = $class->get_attribute( $exception->attribute_name ); + + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef, has a predicate C<has_params> and is +optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Attribute (baz) is required + Attribute (bar) is required + Attribute (foo_required) is required + Attribute (baz) is required + +=head1 Moose::Exception::AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Your attribute must be an instance of Class::MOP::Mixin::AttributeCore (or a + subclass) + +=head1 Moose::Exception::AttributeNamesDoNotMatch + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute> and is required. + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + attribute_name (foo) does not match attribute->name (bar) + +=head1 Moose::Exception::AttributeValueIsNotAnObject + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute>, L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->given_value >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method::Delegation> and is +required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot delegate get_count to count because the value of foo is not an object + (got 'ARRAY(0x223f578)') + +=head1 Moose::Exception::AttributeValueIsNotDefined + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute>, L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method::Delegation> and is +required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot delegate get_count to count because the value of foo is not defined + +=head1 Moose::Exception::AutoDeRefNeedsArrayRefOrHashRef + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot auto-dereference anything other than a ArrayRef or HashRef on +attribute (bar) + +=head1 Moose::Exception::BadOptionFormat + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->option_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->option_value >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + bad accessor/reader/writer/predicate/clearer format, must be a HASH ref + +=head1 Moose::Exception::BothBuilderAndDefaultAreNotAllowed + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Setting both default and builder is not allowed. + +=head1 Moose::Exception::BuilderDoesNotExist + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute> and L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Foo does not support builder method '_build_baz' for attribute 'baz' + +=head1 Moose::Exception::BuilderMethodNotSupportedForAttribute + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute> and L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Class::MOP::Attribute does not support builder method 'foo' for attribute +'bar' + +=head1 Moose::Exception::BuilderMethodNotSupportedForInlineAttribute + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->builder >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Test::LazyBuild::Attribute does not support builder method '_build_fool' for + attribute 'fool' + +=head1 Moose::Exception::BuilderMustBeAMethodName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + builder must be a defined scalar value which is a method name + +=head1 Moose::Exception::CallingMethodOnAnImmutableInstance + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The 'add_method' method cannot be called on an immutable instance + +=head1 Moose::Exception::CallingReadOnlyMethodOnAnImmutableInstance + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The 'superclasses' method is read-only when called on an immutable instance + +=head1 Moose::Exception::CanExtendOnlyClasses + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot inherit from a Moose Role (Bar) + +=head1 Moose::Exception::CanOnlyConsumeRole + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You can only consume roles, Module::Runtime is not a Moose role + +=head1 Moose::Exception::CanOnlyWrapBlessedCode + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->code >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Can only wrap blessed CODE + +=head1 Moose::Exception::CanReblessOnlyIntoASubclass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Instance>, +L<Moose::Exception::Role::InstanceClass>, L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->instance_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You may rebless only into a subclass of (Foo2), of which (Foo) isn't. + +=head1 Moose::Exception::CanReblessOnlyIntoASuperclass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Instance> and +L<Moose::Exception::Role::InstanceClass>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->instance_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You may rebless only into a superclass of (Foo), of which (Foo2) isn't. + +=head1 Moose::Exception::CannotAddAdditionalTypeCoercionsToUnion + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_coercion_union_object >> + +This attribute is read-only, isa L<Moose::Meta::TypeCoercion::Union> and is +required. + +=back + +=head4 Sample Error Message: + + Cannot add additional type coercions to Union types + +=head1 Moose::Exception::CannotAddAsAnAttributeToARole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot add a Moose::Meta::Class as an attribute to a role + +=head1 Moose::Exception::CannotApplyBaseClassRolesToRole + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You can only apply base class roles to a Moose class, not a role. + +=head1 Moose::Exception::CannotAssignValueToReadOnlyAccessor + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and +L<Moose::Exception::Role::EitherAttributeOrAttributeName>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<has_attribute> and is optional. + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str, has a predicate C<has_attribute_name> and +is optional. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef, has a predicate C<has_params> and is +optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->value >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Message: + + Cannot assign a value to a read-only accessor + +=head1 Moose::Exception::CannotAugmentIfLocalMethodPresent + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::Method>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method> and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot add an augment method if a local method is already present + +=head1 Moose::Exception::CannotAugmentNoSuperMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot augment 'foo' because it has no super method + +=head1 Moose::Exception::CannotAutoDerefWithoutIsa + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot auto-dereference without specifying a type constraint on +attribute (bar) + +=head1 Moose::Exception::CannotAutoDereferenceTypeConstraint + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute>, L<Moose::Exception::Role::Instance> and +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Can not auto de-reference the type constraint 'Int' + +=head1 Moose::Exception::CannotCalculateNativeType + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot calculate native type for Moose::Meta::Class::__ANON__::SERIAL:: + +=head1 Moose::Exception::CannotCallAnAbstractBaseMethod + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Class::MOP::Method::Generated is an abstract base class, you must provide a +constructor. + +=head1 Moose::Exception::CannotCallAnAbstractMethod + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Abstract method + +=head1 Moose::Exception::CannotCoerceAWeakRef + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot have a weak reference to a coerced value on attribute (bar) + +=head1 Moose::Exception::CannotCoerceAttributeWhichHasNoCoercion + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions>, +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + You cannot coerce an attribute (foo) unless its type (Str) has a coercion + +=head1 Moose::Exception::CannotCreateHigherOrderTypeWithoutATypeParameter + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + You cannot create a Higher Order type without a type parameter + +=head1 Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresent + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Method>, L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->aliased_method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method> and is required. + +=item B<< $exception->role_being_applied_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot create a method alias if a local method of the same name exists + +=head1 Moose::Exception::CannotCreateMethodAliasLocalMethodIsPresentInClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Method>, +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->aliased_method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method> and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot create a method alias if a local method of the same name exists + +=head1 Moose::Exception::CannotDelegateLocalMethodIsPresent + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Attribute> and L<Moose::Exception::Role::Method>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method> and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot overwrite a locally defined method (full) with a delegation + +=head1 Moose::Exception::CannotDelegateWithoutIsa + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot delegate methods based on a Regexp without a type constraint (isa) + +=head1 Moose::Exception::CannotFindDelegateMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot find delegate metaclass for attribute bar + +=head1 Moose::Exception::CannotFindType + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + Cannot find type 'Foo', perhaps you forgot to load it + +=head1 Moose::Exception::CannotFindTypeGivenToMatchOnType + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->action >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->to_match >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Message: + + Cannot find or parse the type 'doesNotExist' + +=head1 Moose::Exception::CannotFixMetaclassCompatibility + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass_type >> + +This attribute is read-only, isa Str and is optional. + +=item B<< $exception->superclass >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Can't fix metaclass incompatibility for Foo9 because it is not pristine. + Can't fix metaclass incompatibility for Foo::Unsafe::Sub because it is not +pristine. + +=head1 Moose::Exception::CannotGenerateInlineConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->parameterizable_type_object_name >> + +This attribute can be used for fetching parameterizable type +constraint(Moose::Meta::TypeConstraint::Parameterizable): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + + +=item B<< $exception->value >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + Can't generate an inline constraint for Int, since none was defined + +=head1 Moose::Exception::CannotInitializeMooseMetaRoleComposite + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->args >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->old_meta >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->role_composite >> + +This attribute is read-only, isa L<Moose::Meta::Role::Composite> and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Moose::Meta::Role::Composite instances can only be reinitialized from an +existing metaclass instance + +=head1 Moose::Exception::CannotInlineTypeConstraintCheck + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Cannot inline a type constraint check for NotInlinable + +=head1 Moose::Exception::CannotLocatePackageInINC + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->INC >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->possible_packages >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + Can't locate Moose::Meta::Attribute::Custom::Trait::Xyz or Xyz in \@INC \(\@ +INC contains: + +=head1 Moose::Exception::CannotMakeMetaclassCompatible + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->superclass_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::CannotOverrideALocalMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot add an override of method 'bar' because there is a local version of +'bar' + +=head1 Moose::Exception::CannotOverrideBodyOfMetaMethods + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Overriding the body of meta methods is not allowed + +=head1 Moose::Exception::CannotOverrideLocalMethodIsPresent + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::Method>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method >> + +This attribute is read-only, isa L<Moose::Meta::Method> and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot add an override method if a local method is already present + +=head1 Moose::Exception::CannotOverrideNoSuperMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot override 'foo' because it has no super method + +=head1 Moose::Exception::CannotRegisterUnnamedTypeConstraint + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + can't register an unnamed type constraint + +=head1 Moose::Exception::CannotUseLazyBuildAndDefaultSimultaneously + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You can not use lazy_build and default for the same attribute (bar) + +=head1 Moose::Exception::CircularReferenceInAlso + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->also_parameter >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->stack >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Circular reference in 'also' parameter to Moose::Exporter between +MooseX::CircularAlso and MooseX::CircularAlso + +=head1 Moose::Exception::ClassDoesNotHaveInitMeta + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->traits >> + +This attribute is read-only, isa ArrayRef and is required. + +=back + +=head4 Sample Error Message: + + Cannot provide traits when Moose::Util::TypeConstraints does not have an +init_meta() method + +=head1 Moose::Exception::ClassDoesTheExcludedRole + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->excluded_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The class FooClass2 does the excluded role 'ExcludedRole2' + +=head1 Moose::Exception::ClassNamesDoNotMatch + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa L<Class::MOP::Class> and is required. + +=item B<< $exception->class_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::CloneObjectExpectsAnInstanceOfMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an instance of the metaclass (Foo), not (foo) + +=head1 Moose::Exception::CodeBlockMustBeACodeRef + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Instance>, L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Your code block must be a CODE reference + +=head1 Moose::Exception::CoercingWithoutCoercions + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Cannot coerce without a type coercion + +=head1 Moose::Exception::CoercionAlreadyExists + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->constraint_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + A coercion action already exists for 'Int' + +=head1 Moose::Exception::CoercionNeedsTypeConstraint + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot have coercion without specifying a type constraint on attribute +(bar) + +=head1 Moose::Exception::ConflictDetectedInCheckRoleExclusions + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->excluded_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Conflict detected: Foo excludes role 'Bar' + +=head1 Moose::Exception::ConflictDetectedInCheckRoleExclusionsInToClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Conflict detected: FooClass excludes role 'BarRole' + +=head1 Moose::Exception::ConstructClassInstanceTakesPackageName + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a package name + +=head1 Moose::Exception::CouldNotCreateMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->error >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->option_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->option_value >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not create the 'predicate' method for bar because : Can't call method +"name" on an undefined value + +=head1 Moose::Exception::CouldNotCreateWriter + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::EitherAttributeOrAttributeName> and +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<has_attribute> and is optional. + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str, has a predicate C<has_attribute_name> and +is optional. + +=item B<< $exception->error >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef, has a predicate C<has_params> and is +optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not generate inline writer because : Could not create writer for 'bar' + because Can't locate object method "_eval_environment" via package +"Class::MOP::Attribute" + +=head1 Moose::Exception::CouldNotEvalConstructor + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->constructor_method >> + +This attribute is read-only, isa L<Class::MOP::Method::Constructor> and is +required. + +=item B<< $exception->error >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->source >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not eval the constructor : + +=head1 Moose::Exception::CouldNotEvalDestructor + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->error >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_destructor_object >> + +This attribute is read-only, isa L<Moose::Meta::Method::Destructor> and is +required. + +=item B<< $exception->source >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not eval the destructor + +=head1 Moose::Exception::CouldNotFindTypeConstraintToCoerceFrom + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->constraint_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not find the type constraint (xyz) to coerce from + +=head1 Moose::Exception::CouldNotGenerateInlineAttributeMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->error >> + +This attribute is read-only, isa L<Moose::Exception|Str> and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->option >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Could not generate inline accessor because : Can't call method +"get_meta_instance" on an undefined value + Could not generate inline reader because : Can't call method +"get_meta_instance" on an undefined value + Could not generate inline writer because : Can't call method +"get_meta_instance" on an undefined value + Could not generate inline predicate because : Can't call method +"get_meta_instance" on an undefined value + Could not generate inline clearer because : Can't call method +"get_meta_instance" on an undefined value + +=head1 Moose::Exception::CouldNotLocateTypeConstraintForUnion + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Could not locate type constraint (foo) for the union + +=head1 Moose::Exception::CouldNotParseType + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->position >> + +This attribute is read-only, isa Int and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + 'Str | Undef |' didn't parse (parse-pos=11 and str-length=13) + +=head1 Moose::Exception::CreateMOPClassTakesArrayRefOfAttributes + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreateMOPClass>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an ARRAY ref of attributes + +=head1 Moose::Exception::CreateMOPClassTakesArrayRefOfSuperclasses + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreateMOPClass>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an ARRAY ref of superclasses + +=head1 Moose::Exception::CreateMOPClassTakesHashRefOfMethods + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreateMOPClass>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an HASH ref of methods + +=head1 Moose::Exception::CreateTakesArrayRefOfRoles + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreate>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an ARRAY ref of roles + +=head1 Moose::Exception::CreateTakesHashRefOfAttributes + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreate>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a HASH ref of attributes + +=head1 Moose::Exception::CreateTakesHashRefOfMethods + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::ParamsHash> and +L<Moose::Exception::Role::RoleForCreate>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a HASH ref of methods + +=head1 Moose::Exception::DefaultToMatchOnTypeMustBeCodeRef + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->cases_to_be_matched >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->default_action >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->to_match >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Default case must be a CODE ref, not ARRAY(0x14f6fc8) + +=head1 Moose::Exception::DelegationToAClassWhichIsNotLoaded + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->class_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The bar attribute is trying to delegate to a class which has not been loaded + - Not::Loaded + +=head1 Moose::Exception::DelegationToARoleWhichIsNotLoaded + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The bar attribute is trying to delegate to a role which has not been loaded +- Role + +=head1 Moose::Exception::DelegationToATypeWhichIsNotAClass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + The bar attribute is trying to delegate to a type (Int) that is not backed +by a class + The bar attribute is trying to delegate to a type (PositiveInt) that is not +backed by a class + +=head1 Moose::Exception::DoesRequiresRoleName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a role name to does() + +=head1 Moose::Exception::EnumCalledWithAnArrayRefAndAdditionalArgs + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->args >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->array >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + enum called with an array reference and additional arguments. Did you mean +to parenthesize the enum call's parameters? + +=head1 Moose::Exception::EnumValuesMustBeString + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->value >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Messages: + + Enum values must be strings, not undef + Enum values must be strings, not 'ARRAY(0x191d1b8)' + +=head1 Moose::Exception::ExtendsMissingArgs + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Must derive at least one class + +=head1 Moose::Exception::HandlesMustBeAHashRef + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->given_handles >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The 'handles' option must be a HASH reference, not bar + +=head1 Moose::Exception::IllegalInheritedOptions + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->illegal_options >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Illegal inherited options => (clearer) + +=head1 Moose::Exception::IllegalMethodTypeToAddMethodModifier + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_or_object >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->modifier_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->params >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Methods passed to before must be provided as a list, arrayref or regex, not +HASH + +=head1 Moose::Exception::IncompatibleMetaclassOfSuperclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_meta_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->superclass_meta_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->superclass_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The metaclass of My::Class (Class::MOP::Class) is not compatible with the +metaclass of its superclass, My::Role (Moose::Meta::Role) + +=head1 Moose::Exception::InitMetaRequiresClass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot call init_meta without specifying a for_class + +=head1 Moose::Exception::InitializeTakesUnBlessedPackageName + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package_name >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a package name and it cannot be blessed + +=head1 Moose::Exception::InstanceBlessedIntoWrongClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::Instance>, +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Objects passed as the __INSTANCE__ parameter must already be blessed into +the correct class, but Bar=HASH(0x2d77528) is not a Foo + +=head1 Moose::Exception::InstanceMustBeABlessedReference + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The __INSTANCE__ parameter must be a blessed reference, not ARRAY(0x1d75d40) + +=head1 Moose::Exception::InvalidArgPassedToMooseUtilMetaRole + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->argument >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + When using Moose::Util::MetaRole, you must pass a Moose class name, role +name, metaclass object, or metarole object. You passed Foo=HASH(0x16adb58), and +we resolved this to a Foo object. + When using Moose::Util::MetaRole, you must pass a Moose class name, role +name, metaclass object, or metarole object. You passed ARRAY(0x21eb868), and +this did not resolve to a metaclass or metarole. Maybe you need to call Moose->i +nit_meta to initialize the metaclass first? + When using Moose::Util::MetaRole, you must pass a Moose class name, role +name, metaclass object, or metarole object. You passed undef, and this did not +resolve to a metaclass or metarole. Maybe you need to call Moose->init_meta to +initialize the metaclass first? + +=head1 Moose::Exception::InvalidArgumentToMethod + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->argument >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->argument_noun >> + +This attribute is read-only, isa Str, has a default value "argument" and is +optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->ordinal >> + +This attribute is read-only, isa Str, has a predicate C<is_ordinal_set> and is +optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->type_of_argument >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Messages: + + The index passed to get must be an integer + The argument passed to first must be a code reference + The argument passed to first_index must be a code reference + The argument passed to grep must be a code reference + The argument passed to join must be a string + The argument passed to map must be a code reference + The n value passed to natatime must be an integer + The second argument passed to natatime must be a code reference + The argument passed to reduce must be a code reference + The argument passed to sort must be a code reference + The argument passed to sort_in_place must be a code reference + The length argument passed to splice must be an integer + The argument passed to grep must be a code reference + The key passed to exists must be a defined value + The argument passed to match must be a string or regexp reference + The first argument passed to replace must be a string or regexp reference + The second argument passed to replace must be a string or code reference + The first argument passed to substr must be an integer + The second argument passed to substr must be an integer + The third argument passed to substr must be a string + +=head1 Moose::Exception::InvalidArgumentsToTraitAliases + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->alias >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + HASH references are not valid arguments to the 'trait_aliases' option + +=head1 Moose::Exception::InvalidBaseTypeGivenToCreateParameterizedTypeConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Could not locate the base type (Foo) + +=head1 Moose::Exception::InvalidHandleValue + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->handle_value >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + All values passed to handles must be strings or ARRAY references, not (?^:ba +r) + +=head1 Moose::Exception::InvalidHasProvidedInARole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Usage: has 'name' => ( key => value, ... ) + +=head1 Moose::Exception::InvalidNameForType + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + contains invalid characters + +=head1 Moose::Exception::InvalidOverloadOperator + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->operator >> + +This attribute is read-only, isa Defined and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::InvalidRoleApplication + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->application >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Role applications must be instances of +Moose::Meta::Role::Application::ToClass + +=head1 Moose::Exception::InvalidTypeConstraint + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->registry_object >> + +This attribute is read-only, isa L<Moose::Meta::TypeConstraint::Registry> and is + required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Message: + + No type supplied / type is not a valid type constraint + +=head1 Moose::Exception::InvalidTypeGivenToCreateParameterizedTypeConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Could not parse type name (Foo) correctly + +=head1 Moose::Exception::InvalidValueForIs + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + I do not understand this option (is => bar) on attribute (foo) + +=head1 Moose::Exception::IsaDoesNotDoTheRole + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot have an isa option and a does option if the isa does not do the does +on attribute (bar) + +=head1 Moose::Exception::IsaLacksDoesMethod + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot have an isa option which cannot ->does() on attribute (bar) + +=head1 Moose::Exception::LazyAttributeNeedsADefault + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::EitherAttributeOrAttributeName>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<has_attribute> and is optional. + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str, has a predicate C<has_attribute_name> and +is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef, has a predicate C<has_params> and is +optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot have a lazy attribute (bar) without specifying a default value +for it + +=head1 Moose::Exception::Legacy + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Hello, I am an exception object + An inline error + +=head1 Moose::Exception::MOPAttributeNewNeedsAttributeName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must provide a name for the attribute + +=head1 Moose::Exception::MatchActionMustBeACodeRef + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->action >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->to_match >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Match action must be a CODE ref, not ARRAY(0x27a0748) + +=head1 Moose::Exception::MessageParameterMustBeCodeRef + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The 'message' parameter must be a coderef + +=head1 Moose::Exception::MetaclassIsAClassNotASubclassOfGivenMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Foo3 already has a metaclass, but it does not inherit Moose::Meta::Role +(Moose::Meta::Class=HASH(0x2d5d160)). You cannot make the same thing a role and +a class. Remove either Moose or Moose::Role. + +=head1 Moose::Exception::MetaclassIsARoleNotASubclassOfGivenMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Foo3 already has a metaclass, but it does not inherit Moose::Meta::Class +(Moose::Meta::Role=HASH(0x29d3c78)). You cannot make the same thing a role and a + class. Remove either Moose or Moose::Role. + +=head1 Moose::Exception::MetaclassIsNotASubclassOfGivenMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Foo4 already has a metaclass, but it does not inherit Moose::Meta::Role +(Class::MOP::Class=HASH(0x2c385a8)). + Foo4 already has a metaclass, but it does not inherit Moose::Meta::Class +(Class::MOP::Class=HASH(0x278a4a0)). + +=head1 Moose::Exception::MetaclassMustBeASubclassOfMooseMetaClass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The Metaclass Foo3 must be a subclass of Moose::Meta::Class. + +=head1 Moose::Exception::MetaclassMustBeASubclassOfMooseMetaRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The Metaclass Foo3 must be a subclass of Moose::Meta::Role. + +=head1 Moose::Exception::MetaclassMustBeDerivedFromClassMOPClass + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The metaclass (Foo) must be derived from Class::MOP::Class + +=head1 Moose::Exception::MetaclassNotLoaded + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The Metaclass Foo2 must be loaded. (Perhaps you forgot to 'use Foo2'?) + +=head1 Moose::Exception::MetaclassTypeIncompatible + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->superclass_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The attribute_metaclass metaclass for Foo::All::Sub::Attribute +(Bar::Meta::Attribute) is not compatible with the attribute metaclass of its +superclass, Foo::All (Foo::Meta::Attribute) + +=head1 Moose::Exception::MethodExpectedAMetaclassObject + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->metaclass >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The is_needed method expected a metaclass object as its arugment + +=head1 Moose::Exception::MethodExpectsFewerArgs + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->maximum_args >> + +This attribute is read-only, isa Int and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot call substr with more than 3 arguments + +=head1 Moose::Exception::MethodExpectsMoreArgs + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->minimum_args >> + +This attribute is read-only, isa Int and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Cannot call substr without at least 1 argument + +=head1 Moose::Exception::MethodModifierNeedsMethodName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass in a method name + +=head1 Moose::Exception::MethodNameConflictInRoles + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->conflict >> + +This attribute is read-only, isa +ArrayRef[Moose::Meta::Role::Method::Conflicting] and is required. + +This attribute has handles as follows: + conflict_methods_count => count + get_all_methods => elements + get_method_at => get + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Due to a method name conflict in roles 'Bar::Role' and 'Foo::Role', the +method 'foo' must be implemented or excluded by 'My::Foo::Class::Broken' + Due to method name conflicts in roles 'Bar2::Role' and 'Foo2::Role', the +methods 'bar' and 'foo' must be implemented or excluded by +'My::Foo::Class::Broken2' + +=head1 Moose::Exception::MethodNameNotFoundInInheritanceHierarchy + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The method 'foo' was not found in the inheritance hierarchy for Foo + +=head1 Moose::Exception::MethodNameNotGiven + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must define a method name to find + +=head1 Moose::Exception::MustDefineAMethodName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must define a method name + +=head1 Moose::Exception::MustDefineAnAttributeName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must define an attribute name + +=head1 Moose::Exception::MustDefineAnOverloadOperator + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Instance>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->instance >> + +This attribute is read-only, isa Object and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::MustHaveAtLeastOneValueToEnumerate + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must have at least one value to enumerate through + +=head1 Moose::Exception::MustPassAHashOfOptions + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a hash of options + +=head1 Moose::Exception::MustPassAMooseMetaRoleInstanceOrSubclass + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a Moose::Meta::Role instance (or a subclass) + +=head1 Moose::Exception::MustPassAPackageNameOrAnExistingClassMOPPackageInstance + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a package name or an existing Class::MOP::Package instance + +=head1 Moose::Exception::MustPassEvenNumberOfArguments + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->args >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an even number of arguments to set + +=head1 Moose::Exception::MustPassEvenNumberOfAttributeOptions + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->options >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an even number of attribute options + +=head1 Moose::Exception::MustProvideANameForTheAttribute + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must provide a name for the attribute + +=head1 Moose::Exception::MustSpecifyAtleastOneMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Must specify at least one method + +=head1 Moose::Exception::MustSpecifyAtleastOneRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Must specify at least one role + +=head1 Moose::Exception::MustSpecifyAtleastOneRoleToApplicant + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->applicant >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Must specify at least one role to apply to TestClass=HASH(0x2bee290) + Must specify at least one role to apply to Moose::Meta::Class=HASH(0x1a1f818) + Must specify at least one role to apply to Moose::Meta::Role=HASH(0x1f22d40) + +=head1 Moose::Exception::MustSupplyAClassMOPAttributeInstance + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply an attribute which is a 'Class::MOP::Attribute' instance + +=head1 Moose::Exception::MustSupplyADelegateToMethod + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a delegate_to_method which is a method name or a CODE +reference + +=head1 Moose::Exception::MustSupplyAMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass a metaclass instance if you want to inline + +=head1 Moose::Exception::MustSupplyAMooseMetaAttributeInstance + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply an attribute which is a 'Moose::Meta::Attribute' instance + +=head1 Moose::Exception::MustSupplyAnAccessorTypeToConstructWith + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply an accessor_type to construct with + +=head1 Moose::Exception::MustSupplyAnAttributeToConstructWith + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply an attribute to construct with + +=head1 Moose::Exception::MustSupplyArrayRefAsCurriedArguments + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a curried_arguments which is an ARRAY reference + +=head1 Moose::Exception::MustSupplyPackageNameAndName + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply the package_name and name parameters + +=head1 Moose::Exception::NeedsTypeConstraintUnionForTypeCoercionUnion + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_coercion_union_object >> + +This attribute is read-only, isa L<Moose::Meta::TypeCoercion::Union> and is +required. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + You can only create a Moose::Meta::TypeCoercion::Union for a +Moose::Meta::TypeConstraint::Union, not a Str + +=head1 Moose::Exception::NeitherAttributeNorAttributeNameIsGiven + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You need to give attribute or attribute_name or both + +=head1 Moose::Exception::NeitherClassNorClassNameIsGiven + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::NeitherRoleNorRoleNameIsGiven + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::NeitherTypeNorTypeNameIsGiven + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::NoAttributeFoundInSuperClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class>, +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Could not find an attribute by the name of 'bar' to inherit from in Test2 + +=head1 Moose::Exception::NoBodyToInitializeInAnAbstractBaseClass + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + No body to initialize, Class::MOP::Method::Generated is an abstract base +class + +=head1 Moose::Exception::NoCasesMatched + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->cases_to_be_matched >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->to_match >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + No cases matched for 123 + +=head1 Moose::Exception::NoConstraintCheckForTypeConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + Could not compile type constraint 'FooTypeConstraint' because no constraint +check + +=head1 Moose::Exception::NoDestructorClassSpecified + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The 'inline_destructor' option is present, but no destructor class was +specified + +=head1 Moose::Exception::NoImmutableTraitSpecifiedForClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + no immutable trait specified for Moose::Meta::Class=HASH(0x19a2280) + +=head1 Moose::Exception::NoParentGivenToSubtype + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + A subtype cannot consist solely of a name, it must have a parent + +=head1 Moose::Exception::OnlyInstancesCanBeCloned + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->instance >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You can only clone instances, (ARRAY(0x2162350)) is not a blessed instance + +=head1 Moose::Exception::OperatorIsRequired + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadConflictInSummation + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->overloaded_op >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_application >> + +This attribute is read-only, isa +L<Moose::Meta::Role::Application::RoleSummation> and is required. + +=item B<< $exception->role_names >> + +This attribute is an ArrayRef containing role names, if you want metaobjects +associated with these role names, then call method roles on the exception object. + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresAMetaClass + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresAMetaMethod + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresAMetaOverload + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresAMethodNameOrCoderef + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresAnOperator + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverloadRequiresNamesForCoderef + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::OverrideConflictInComposition + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_being_applied_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->two_overrides_found >> + +This attribute is read-only, isa Bool, has a default value 0 and is required. + +=back + +=head4 Sample Error Messages: + + Role 'Foo6' has encountered an 'override' method conflict during composition + (A local method of the same name as been found). This is a fatal error. + Role 'Foo7' has encountered an 'override' method conflict during composition + (Two 'override' methods of the same name encountered). This is a fatal error. + +=head1 Moose::Exception::OverrideConflictInSummation + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_application >> + +This attribute is read-only, isa +L<Moose::Meta::Role::Application::RoleSummation> and is required. + +=item B<< $exception->role_names >> + +This attribute is an ArrayRef containing role names, if you want metaobjects +associated with these role names, then call method roles on the exception object. + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->two_overrides_found >> + +This attribute is read-only, isa Bool, has a default value 0 and is required. + +=back + +=head4 Sample Error Messages: + + Role 'Foo3|Bar3' has encountered an 'override' method conflict during +composition (A local method of the same name has been found). This is a fatal +error. + We have encountered an 'override' method conflict during composition (Two +'override' methods of the same name encountered). This is a fatal error. + +=head1 Moose::Exception::PackageDoesNotUseMooseExporter + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->is_loaded >> + +This attribute is read-only, isa Bool and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Package in also (NoSuchThing) does not seem to use Moose::Exporter (is it +loaded?) + +=head1 Moose::Exception::PackageNameAndNameParamsNotGivenToWrap + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->code >> + +This attribute is read-only, isa CodeRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply the package_name and name parameters + +=head1 Moose::Exception::PackagesAndModulesAreNotCachable + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->is_module >> + +This attribute is read-only, isa Bool and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Modules are not cacheable + Packages are not cacheable + +=head1 Moose::Exception::ParameterIsNotSubtypeOfParent + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + + +=item B<< $exception->type_parameter >> + +This attribute is read-only, isa Str and is required. + +=back + +=head4 Sample Error Message: + + Int is not a subtype of Float + +=head1 Moose::Exception::ReferencesAreNotAllowedAsDefault + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + References are not allowed as default values, you must wrap the default of +'foo' in a CODE reference (ex: sub { [] } and not []) + +=head1 Moose::Exception::RequiredAttributeLacksInitialization + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + A required attribute must have either 'init_arg', 'builder', or 'default' + +=head1 Moose::Exception::RequiredAttributeNeedsADefault + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You cannot have a required attribute (bar) without a default, builder, or an + init_arg + +=head1 Moose::Exception::RequiredMethodsImportedByClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->imported_method >> + +This attribute is read-only, isa L<Moose::Meta::Role::Method::Required> and is +required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->missing_methods >> + +This attribute is read-only, isa ArrayRef[Moose::Meta::Role::Method::Required] +and is required. + +This attribute has handles as follows: + get_all_methods => elements + get_method_at => get + method_count => count + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + +=head1 Moose::Exception::RequiredMethodsNotImplementedByClass + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::Class> and L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->missing_methods >> + +This attribute is read-only, isa ArrayRef[Moose::Meta::Role::Method::Required] +and is required. + +This attribute has handles as follows: + get_all_methods => elements + get_method_at => get + method_count => count + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + 'Foo3::Role|Bar3::Role|Baz3::Role' requires the method 'foo' to be +implemented by 'My::Foo::Class::Broken3' + +=head1 Moose::Exception::RoleDoesTheExcludedRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->excluded_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->second_role_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The role Bar2 does the excluded role 'Bar3' + +=head1 Moose::Exception::RoleExclusionConflict + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->roles >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Messages: + + Conflict detected: Role Foo1 excludes role 'Bar1' + Conflict detected: Roles Foo1, Baz1 exclude role 'Bar1' + +=head1 Moose::Exception::RoleNameRequired + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a role name to look for + +=head1 Moose::Exception::RoleNameRequiredForMooseMetaRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a role name to look for + +=head1 Moose::Exception::RolesDoNotSupportAugment + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles cannot support 'augment' + +=head1 Moose::Exception::RolesDoNotSupportExtends + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles do not support 'extends' (you can use 'with' to specialize a role) + +=head1 Moose::Exception::RolesDoNotSupportInner + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles cannot support 'inner' + +=head1 Moose::Exception::RolesDoNotSupportRegexReferencesForMethodModifiers + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Role>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->modifier_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->role_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->role_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Roles do not currently support regex references for before method modifiers + +=head1 Moose::Exception::RolesInCreateTakesAnArrayRef + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass an ARRAY ref of roles + +=head1 Moose::Exception::RolesListMustBeInstancesOfMooseMetaRole + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->role >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The list of roles must be instances of Moose::Meta::Role, not foo + +=head1 Moose::Exception::SingleParamsToNewMustBeHashRef + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Single parameters to new() must be a HASH ref + +=head1 Moose::Exception::TriggerMustBeACodeRef + +This class is a subclass of L<Moose::Exception> and consume roles +L<Moose::Exception::Role::InvalidAttributeOptions> and +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Trigger must be a CODE ref on attribute (bar) + +=head1 Moose::Exception::TypeConstraintCannotBeUsedForAParameterizableType + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->parent_type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->parent_type_name ); + + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + The Int[Xyz] constraint cannot be used, because Int doesn't subtype or +coerce from a parameterizable type. + +=head1 Moose::Exception::TypeConstraintIsAlreadyCreated + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->package_defined_in >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Messages: + + The type constraint 'Foo1' has already been created in Moose::Role and +cannot be created again in main + The type constraint 'Foo2' has already been created in Moose and cannot be +created again in main + The type constraint 'Foo3' has already been created in Moose and cannot be +created again in main + +=head1 Moose::Exception::TypeParameterMustBeMooseMetaType + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::TypeConstraint>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_name >> + +This attribute can be used for fetching type +constraint(Moose::Meta::TypeConstraint): + my $type_constraint = Moose::Util::TypeConstraints::find_type_constraint( +$exception->type_name ); + +=back + +=head4 Sample Error Message: + + The type parameter must be a Moose meta type + +=head1 Moose::Exception::UnableToCanonicalizeHandles + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->handles >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Unable to canonicalize the 'handles' option with GLOB(0x109d0b0) + +=head1 Moose::Exception::UnableToCanonicalizeNonRolePackage + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->handles >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Unable to canonicalize the 'handles' option with Foo1 because its metaclass +is not a Moose::Meta::Role + +=head1 Moose::Exception::UnableToRecognizeDelegateMetaclass + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->delegate_metaclass >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Unable to recognize the delegate metaclass 'Class::MOP::Package + +=head1 Moose::Exception::UndefinedHashKeysPassedToMethod + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->hash_keys >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->method_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + Hash keys passed to set must be defined + +=head1 Moose::Exception::UnionCalledWithAnArrayRefAndAdditionalArgs + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->args >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->array >> + +This attribute is read-only, isa ArrayRef and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + union called with an array reference and additional arguments + +=head1 Moose::Exception::UnionTakesAtleastTwoTypeNames + +This class is a subclass of L<Moose::Exception>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must pass in at least 2 type names to make a union + +=head1 Moose::Exception::ValidationFailedForInlineTypeConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Class>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->class_name >> + +This attribute can be used for fetching metaclass instance: + my $metaclass_instance = Moose::Util::find_meta( $exception->class_name ); + + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->new_member >> + +This attribute is read-only, isa Bool, has a predicate C<is_a_new_member>, has a + default value 0 and is optional. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type_constraint_message >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->value >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Messages: + + Attribute (foo) does not pass the type constraint because: Validation failed + for 'Int' with value 10.5 + Attribute (a4) does not pass the type constraint because: Validation failed +for 'ArrayRef' with value "invalid" + Attribute (a4) does not pass the type constraint because: Validation failed +for 'ArrayRef' with value "invalid" + Attribute (a4) does not pass the type constraint because: Validation failed +for 'ArrayRef' with value "invalid" + Attribute (a4) does not pass the type constraint because: Validation failed +for 'ArrayRef' with value "invalid" + Attribute (from_parameterizable) does not pass the type constraint because: +Validation failed for 'ParameterizableArrayRef[Int]'\E with value "?Hello"? + A new member value for foo does not pass its type constraint because: +Validation failed for 'Int' with value 1.2 + +=head1 Moose::Exception::ValidationFailedForTypeConstraint + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::Attribute>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute >> + +This attribute is read-only, isa L<Class::MOP::Attribute>, has a predicate +C<is_attribute_set> and is optional. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=item B<< $exception->type >> + +This attribute is read-only, isa L<Moose::Util::TypeConstraints> and is required. + +=item B<< $exception->value >> + +This attribute is read-only, isa Any and is required. + +=back + +=head4 Sample Error Messages: + + Attribute (bar) does not pass the type constraint because: Validation failed + for 'Int' with value "test" + Validation failed for 'OnlyPositiveInts' with value -123 + +=head1 Moose::Exception::WrapTakesACodeRefToBless + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->class >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->code >> + +This attribute is read-only, isa Any and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + You must supply a CODE reference to bless, not (foo) + +=head1 Moose::Exception::WrongTypeConstraintGiven + +This class is a subclass of L<Moose::Exception> and consumes role +L<Moose::Exception::Role::ParamsHash>. + +=over 4 + +=back + +=head2 ATTRIBUTES + +=over 4 + +=item B<< $exception->attribute_name >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->given_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->message >> + +This attribute is read-only and isa Str. It is lazy and has a default value +'Error'. + +=item B<< $exception->params >> + +This attribute is read-only, isa HashRef and is required. + +=item B<< $exception->required_type >> + +This attribute is read-only, isa Str and is required. + +=item B<< $exception->trace >> + +This attribute is read-only and isa L<Devel::StackTrace>. It is lazy & dependent + on $exception->message. + +=back + +=head4 Sample Error Message: + + The type constraint for foo must be a subtype of ArrayRef but it's a Int + + + +=for comment insert generated content here + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut
\ No newline at end of file diff --git a/lib/Moose/Manual/FAQ.pod b/lib/Moose/Manual/FAQ.pod new file mode 100644 index 0000000..2d6a782 --- /dev/null +++ b/lib/Moose/Manual/FAQ.pod @@ -0,0 +1,470 @@ +# PODNAME: Moose::Manual::FAQ +# ABSTRACT: Frequently asked questions about Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::FAQ - Frequently asked questions about Moose + +=head1 VERSION + +version 2.1405 + +=head1 FREQUENTLY ASKED QUESTIONS + +=head2 Module Stability + +=head3 Is Moose "production ready"? + +Yes! Many sites with household names are using Moose to build +high-traffic services. Countless others are using Moose in production. +See L<http://moose.iinteractive.com/about.html#organizations> for +a partial list. + +As of this writing, Moose is a dependency of several hundred CPAN +modules. L<https://metacpan.org/requires/module/Moose> + +=head3 Is Moose's API stable? + +Yes. The sugary API, the one 95% of users will interact with, is +B<very stable>. Any changes will be B<100% backwards compatible>. + +The meta API is less set in stone. We reserve the right to tweak +parts of it to improve efficiency or consistency. This will not be +done lightly. We do perform deprecation cycles. We I<really> +do not like making ourselves look bad by breaking your code. +Submitting test cases is the best way to ensure that your code is not +inadvertently broken by refactoring. + +=head3 I heard Moose is slow, is this true? + +Again, this one is tricky, so Yes I<and> No. + +Firstly, I<nothing> in life is free, and some Moose features do cost +more than others. It is also the policy of Moose to B<only charge you +for the features you use>, and to do our absolute best to not place +any extra burdens on the execution of your code for features you are +not using. Of course using Moose itself does involve some overhead, +but it is mostly compile time. At this point we do have some options +available for getting the speed you need. + +Currently we provide the option of making your classes immutable as a +means of boosting speed. This will mean a slightly larger compile time +cost, but the runtime speed increase (especially in object +construction) is pretty significant. This can be done with the +following code: + + MyClass->meta->make_immutable(); + +=head2 Constructors + +=head3 How do I write custom constructors with Moose? + +Ideally, you should never write your own C<new> method, and should use +Moose's other features to handle your specific object construction +needs. Here are a few scenarios, and the Moose way to solve them; + +If you need to call initialization code post instance construction, +then use the C<BUILD> method. This feature is taken directly from Perl +6. Every C<BUILD> method in your inheritance chain is called (in the +correct order) immediately after the instance is constructed. This +allows you to ensure that all your superclasses are initialized +properly as well. This is the best approach to take (when possible) +because it makes subclassing your class much easier. + +If you need to affect the constructor's parameters prior to the +instance actually being constructed, you have a number of options. + +To change the parameter processing as a whole, you can use the +C<BUILDARGS> method. The default implementation accepts key/value +pairs or a hash reference. You can override it to take positional +args, or any other format + +To change the handling of individual parameters, there are I<coercions> (See +the L<Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion> for a complete +example and explanation of coercions). With coercions it is possible to morph +argument values into the correct expected types. This approach is the most +flexible and robust, but does have a slightly higher learning curve. + +=head3 How do I make non-Moose constructors work with Moose? + +Usually the correct approach to subclassing a non-Moose class is +delegation. Moose makes this easy using the C<handles> keyword, +coercions, and C<lazy_build>, so subclassing is often not the ideal +route. + +That said, if you really need to inherit from a non-Moose class, see +L<Moose::Cookbook::Basics::DateTime_ExtendingNonMooseParent> for an example of how to do it, +or take a look at L<Moose::Manual::MooseX/"MooseX::NonMoose">. + +=head2 Accessors + +=head3 How do I tell Moose to use get/set accessors? + +The easiest way to accomplish this is to use the C<reader> and +C<writer> attribute options: + + has 'bar' => ( + isa => 'Baz', + reader => 'get_bar', + writer => 'set_bar', + ); + +Moose will still take advantage of type constraints, triggers, etc. +when creating these methods. + +If you do not like this much typing, and wish it to be a default for +your classes, please see L<MooseX::FollowPBP>. This extension will +allow you to write: + + has 'bar' => ( + isa => 'Baz', + is => 'rw', + ); + +Moose will create separate C<get_bar> and C<set_bar> methods instead +of a single C<bar> method. + +If you like C<bar> and C<set_bar>, see +L<MooseX::SemiAffordanceAccessor>. + +NOTE: This B<cannot> be set globally in Moose, as that would break +other classes which are built with Moose. You can still save on typing +by defining a new C<MyApp::Moose> that exports Moose's sugar and then +turns on L<MooseX::FollowPBP>. See +L<Moose::Cookbook::Extending::Mooseish_MooseSugar>. + +=head3 How can I inflate/deflate values in accessors? + +Well, the first question to ask is if you actually need both inflate +and deflate. + +If you only need to inflate, then we suggest using coercions. Here is +some basic sample code for inflating a L<DateTime> object: + + class_type 'DateTime'; + + coerce 'DateTime' + => from 'Str' + => via { DateTime::Format::MySQL->parse_datetime($_) }; + + has 'timestamp' => (is => 'rw', isa => 'DateTime', coerce => 1); + +This creates a custom type for L<DateTime> objects, then attaches +a coercion to that type. The C<timestamp> attribute is then told +to expect a C<DateTime> type, and to try to coerce it. When a C<Str> +type is given to the C<timestamp> accessor, it will attempt to +coerce the value into a C<DateTime> object using the code in found +in the C<via> block. + +For a more comprehensive example of using coercions, see the +L<Moose::Cookbook::Basics::HTTP_SubtypesAndCoercion>. + +If you need to deflate your attribute's value, the current best +practice is to add an C<around> modifier to your accessor: + + # a timestamp which stores as + # seconds from the epoch + has 'timestamp' => (is => 'rw', isa => 'Int'); + + around 'timestamp' => sub { + my $next = shift; + my $self = shift; + + return $self->$next unless @_; + + # assume we get a DateTime object ... + my $timestamp = shift; + return $self->$next( $timestamp->epoch ); + }; + +It is also possible to do deflation using coercion, but this tends to +get quite complex and require many subtypes. An example of this is +outside the scope of this document, ask on #moose or send a mail to +the list. + +Still another option is to write a custom attribute metaclass, which +is also outside the scope of this document, but we would be happy to +explain it on #moose or the mailing list. + +=head2 Method Modifiers + +=head3 How can I affect the values in C<@_> using C<before>? + +You can't, actually: C<before> only runs before the main method, and +it cannot easily affect the method's execution. + +You similarly can't use C<after> to affect the return value of a +method. + +We limit C<before> and C<after> because this lets you write more +concise code. You do not have to worry about passing C<@_> to the +original method, or forwarding its return value (being careful to +preserve context). + +The C<around> method modifier has neither of these limitations, but is +a little more verbose. + +Alternatively, the L<MooseX::Mangle> extension provides the +C<mangle_args> function, which does allow you to affect C<@_>. + +=head3 Can I use C<before> to stop execution of a method? + +Yes, but only if you throw an exception. If this is too drastic a +measure then we suggest using C<around> instead. The C<around> method +modifier is the only modifier which can gracefully prevent execution +of the main method. Here is an example: + + around 'baz' => sub { + my $next = shift; + my ($self, %options) = @_; + unless ($options->{bar} eq 'foo') { + return 'bar'; + } + $self->$next(%options); + }; + +By choosing not to call the C<$next> method, you can stop the +execution of the main method. + +Alternatively, the L<MooseX::Mangle> extension provides the +C<guard> function, which will conditionally prevent execution +of the original method. + +=head3 Why can't I see return values in an C<after> modifier? + +As with the C<before> modifier, the C<after> modifier is simply called +I<after> the main method. It is passed the original contents of C<@_> +and B<not> the return values of the main method. + +Again, the arguments are too lengthy as to why this has to be. And as +with C<before> I recommend using an C<around> modifier instead. Here +is some sample code: + + around 'foo' => sub { + my $next = shift; + my ($self, @args) = @_; + my @rv = $next->($self, @args); + # do something silly with the return values + return reverse @rv; + }; + +Alternatively, the L<MooseX::Mangle> extension provides the +C<mangle_return> function, which allows modifying the return values +of the original method. + +=head2 Type Constraints + +=head3 How can I provide a custom error message for a type constraint? + +Use the C<message> option when building the subtype: + + subtype 'NaturalLessThanTen' + => as 'Natural' + => where { $_ < 10 } + => message { "This number ($_) is not less than ten!" }; + +This C<message> block will be called when a value fails to pass the +C<NaturalLessThanTen> constraint check. + +=head3 Can I turn off type constraint checking? + +There's no support for it in the core of Moose yet. This option may +come in a future release. + +Meanwhile there's a L<MooseX +extension|MooseX::Attribute::TypeConstraint::CustomizeFatal> that +allows you to do this on a per-attribute basis, and if it doesn't do +what you it's easy to write one that fits your use case. + +=head3 My coercions stopped working with recent Moose, why did you break it? + +Moose 0.76 fixed a case where coercions were being applied even if the original +constraint passed. This has caused some edge cases to fail where people were +doing something like + + subtype 'Address', as 'Str'; + coerce 'Address', from 'Str', via { get_address($_) }; + +This is not what they intended, because the type constraint C<Address> is too +loose in this case. It is saying that all strings are Addresses, which is +obviously not the case. The solution is to provide a C<where> clause that +properly restricts the type constraint: + + subtype 'Address', as 'Str', where { looks_like_address($_) }; + +This will allow the coercion to apply only to strings that fail to look like an +Address. + +=head2 Roles + +=head3 Why is BUILD not called for my composed roles? + +C<BUILD> is never called in composed roles. The primary reason is that +roles are B<not> order sensitive. Roles are composed in such a way +that the order of composition does not matter (for information on the +deeper theory of this read the original traits papers here +L<http://www.iam.unibe.ch/~scg/Research/Traits/>). + +Because roles are essentially unordered, it would be impossible to +determine the order in which to execute the C<BUILD> methods. + +As for alternate solutions, there are a couple. + +=over 4 + +=item * + +Using a combination of lazy and default in your attributes to defer +initialization (see the Binary Tree example in the cookbook for a good example +of lazy/default usage +L<Moose::Cookbook::Basics::BinaryTree_AttributeFeatures>) + +=item * + +Use attribute triggers, which fire after an attribute is set, to +facilitate initialization. These are described in the L<Moose> docs, +and examples can be found in the test suite. + +=back + +In general, roles should not I<require> initialization; they should +either provide sane defaults or should be documented as needing +specific initialization. One such way to "document" this is to have a +separate attribute initializer which is required for the role. Here is +an example of how to do this: + + package My::Role; + use Moose::Role; + + has 'height' => ( + is => 'rw', + isa => 'Int', + lazy => 1, + default => sub { + my $self = shift; + $self->init_height; + } + ); + + requires 'init_height'; + +In this example, the role will not compose successfully unless the +class provides a C<init_height> method. + +If none of those solutions work, then it is possible that a role is +not the best tool for the job, and you really should be using +classes. Or, at the very least, you should reduce the amount of +functionality in your role so that it does not require initialization. + +=head3 What are traits, and how are they different from roles? + +In Moose, a trait is almost exactly the same thing as a role, except +that traits typically register themselves, which allows you to refer +to them by a short name ("Big" vs "MyApp::Role::Big"). + +In Moose-speak, a I<Role> is usually composed into a I<class> at +compile time, whereas a I<Trait> is usually composed into an instance +of a class at runtime to add or modify the behavior of B<just that +instance>. + +Outside the context of Moose, traits and roles generally mean exactly +the same thing. The original paper called them traits, but Perl 6 +will call them roles. + +=head3 Can an attribute-generated method (e.g. an accessor) satisfy requires? + +Yes, just be sure to consume the role I<after> declaring your +attribute. L<Moose::Manual::Roles/Required Attributes> provides +an example: + + package Breakable; + use Moose::Role; + requires 'stress'; + + package Car; + use Moose; + has 'stress' => ( is => 'rw', isa => 'Int' ); + with 'Breakable'; + +If you mistakenly consume the C<Breakable> role before declaring your +C<stress> attribute, you would see an error like this: + + 'Breakable' requires the method 'stress' to be implemented by 'Car' at... + +=head2 Moose and Subroutine Attributes + +=head3 Why don't subroutine attributes I inherited from a superclass work? + +Currently when subclassing a module is done at runtime with the +C<extends> keyword, but attributes are checked at compile time by +Perl. To make attributes work, you must place C<extends> in a C<BEGIN> +block so that the attribute handlers will be available at compile time, +like this: + + BEGIN { extends qw/Foo/ } + +Note that we're talking about Perl's subroutine attributes here, not +Moose attributes: + + sub foo : Bar(27) { ... } + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/MOP.pod b/lib/Moose/Manual/MOP.pod new file mode 100644 index 0000000..9f5ce63 --- /dev/null +++ b/lib/Moose/Manual/MOP.pod @@ -0,0 +1,214 @@ +# PODNAME: Moose::Manual::MOP +# ABSTRACT: The Moose (and Class::MOP) meta API + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::MOP - The Moose (and Class::MOP) meta API + +=head1 VERSION + +version 2.1405 + +=head1 INTRODUCTION + +Moose provides a powerful introspection API built on top of +C<Class::MOP>. "MOP" stands for Meta-Object Protocol. In plainer +English, a MOP is an API for performing introspection on classes, +attributes, methods, and so on. + +In fact, it is C<Class::MOP> that provides many of Moose's core +features, including attributes, before/after/around method modifiers, +and immutability. In most cases, Moose takes an existing C<Class::MOP> +class and subclasses it to add additional features. Moose also adds +some entirely new features of its own, such as roles, the augment +modifier, and types. + +If you're interested in the MOP, it's important to know about +C<Class::MOP> so you know what docs to read. Often, the introspection +method that you're looking for is defined in a C<Class::MOP> class, +rather than Moose itself. + +The MOP provides more than just I<read-only> introspection. It also +lets you add attributes and methods, apply roles, and much more. In +fact, all of the declarative Moose sugar is simply a thin layer on top +of the MOP API. + +If you want to write Moose extensions, you'll need to learn some of +the MOP API. The introspection methods are also handy if you want to +generate docs or inheritance graphs, or do some other runtime +reflection. + +This document is not a complete reference for the meta API. We're just +going to cover some of the highlights, and give you a sense of how it +all works. To really understand it, you'll have to read a lot of other +docs, and possibly even dig into the Moose guts a bit. + +=head1 GETTING STARTED + +The usual entry point to the meta API is through a class's metaclass +object, which is a L<Moose::Meta::Class>. This is available by calling +the C<meta> method on a class or object: + + package User; + + use Moose; + + my $meta = __PACKAGE__->meta; + +The C<meta> method is added to a class when it uses Moose. + +You can also use C<< Class::MOP::Class->initialize($name) >> to get a +metaclass object for any class. This is safer than calling C<< +$class->meta >> when you're not sure that the class has a meta method. + +The C<< Class::MOP::Class->initialize >> constructor will return an +existing metaclass if one has already been created (via Moose or some +other means). If it hasn't, it will return a new C<Class::MOP::Class> +object. This will work for classes that use Moose, meta API classes, +and classes which don't use Moose at all. + +=head1 USING THE METACLASS OBJECT + +The metaclass object can tell you about a class's attributes, methods, +roles, parents, and more. For example, to look at all of the class's +attributes: + + for my $attr ( $meta->get_all_attributes ) { + print $attr->name, "\n"; + } + +The C<get_all_attributes> method is documented in +C<Class::MOP::Class>. For Moose-using classes, it returns a list of +L<Moose::Meta::Attribute> objects for attributes defined in the class +and its parents. + +You can also get a list of methods: + + for my $method ( $meta->get_all_methods ) { + print $method->fully_qualified_name, "\n"; + } + +Now we're looping over a list of L<Moose::Meta::Method> objects. Note +that some of these objects may actually be a subclass of +L<Moose::Meta::Method>, as Moose uses different classes to represent +wrapped methods, delegation methods, constructors, etc. + +We can look at a class's parent classes and subclasses: + + for my $class ( $meta->linearized_isa ) { + print "$class\n"; + } + + for my $subclass ( $meta->subclasses ) { + print "$subclass\n"; + } + +Note that both these methods return class I<names>, not metaclass +objects. + +=head1 ALTERING CLASSES WITH THE MOP + +The metaclass object can change the class directly, by adding +attributes, methods, etc. + +As an example, we can add a method to a class: + + $meta->add_method( 'say' => sub { print @_, "\n" } ); + +Or an attribute: + + $meta->add_attribute( 'size' => ( is => 'rw', isa => 'Int' ) ); + +Obviously, this is much more cumbersome than using Perl syntax or +Moose sugar for defining methods and attributes, but this API allows +for very powerful extensions. + +You might remember that we've talked about making classes immutable +elsewhere in the manual. This is a good practice. However, once a +class is immutable, calling any of these update methods will throw an +exception. + +You can make a class mutable again simply by calling C<< +$meta->make_mutable >>. Once you're done changing it, you can +restore immutability by calling C<< $meta->make_immutable >>. + +However, the most common use for this part of the meta API is as +part of Moose extensions. These extensions should assume that they are +being run before you make a class immutable. + +=head1 GOING FURTHER + +If you're interested in extending Moose, we recommend reading all of +the "Meta" and "Extending" recipes in the L<Moose::Cookbook>. Those +recipes show various practical applications of the MOP. + +If you'd like to write your own extensions, one of the best ways to +learn more about this is to look at other similar extensions to see +how they work. You'll probably also need to read various API docs, +including the docs for the various C<Moose::Meta::*> and +C<Class::MOP::*> classes. + +Finally, we welcome questions on the Moose mailing list and +IRC. Information on the mailing list, IRC, and more references can be +found in the L<Moose.pm docs|Moose/GETTING HELP>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/MethodModifiers.pod b/lib/Moose/Manual/MethodModifiers.pod new file mode 100644 index 0000000..671a250 --- /dev/null +++ b/lib/Moose/Manual/MethodModifiers.pod @@ -0,0 +1,432 @@ +# PODNAME: Moose::Manual::MethodModifiers +# ABSTRACT: Moose's method modifiers + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::MethodModifiers - Moose's method modifiers + +=head1 VERSION + +version 2.1405 + +=head1 WHAT IS A METHOD MODIFIER? + +Moose provides a feature called "method modifiers". You can also think +of these as "hooks" or "advice". + +It's probably easiest to understand this feature with a few examples: + + package Example; + + use Moose; + + sub foo { + print " foo\n"; + } + + before 'foo' => sub { print "about to call foo\n"; }; + after 'foo' => sub { print "just called foo\n"; }; + + around 'foo' => sub { + my $orig = shift; + my $self = shift; + + print " I'm around foo\n"; + + $self->$orig(@_); + + print " I'm still around foo\n"; + }; + +Now if I call C<< Example->new->foo >> I'll get the following output: + + about to call foo + I'm around foo + foo + I'm still around foo + just called foo + +You probably could have figured that out from the names "before", +"after", and "around". + +Also, as you can see, the before modifiers come before around +modifiers, and after modifiers come last. + +When there are multiple modifiers of the same type, the before and +around modifiers run from the last added to the first, and after +modifiers run from first added to last: + + before 2 + before 1 + around 2 + around 1 + primary + around 1 + around 2 + after 1 + after 2 + +=head1 WHY USE THEM? + +Method modifiers have many uses. They are often used in roles to alter the +behavior of methods in the classes that consume the role. See +L<Moose::Manual::Roles> for more information about roles. + +Since modifiers are mostly useful in roles, some of the examples below +are a bit artificial. They're intended to give you an idea of how +modifiers work, but may not be the most natural usage. + +=head1 BEFORE, AFTER, AND AROUND + +Method modifiers can be used to add behavior to methods without modifying the definition of those methods. + +=head2 Before and after Modifiers + +Method modifiers can be used to add behavior to a method that Moose +generates for you, such as an attribute accessor: + + has 'size' => ( is => 'rw' ); + + before 'size' => sub { + my $self = shift; + + if (@_) { + Carp::cluck('Someone is setting size'); + } + }; + +Another use for the before modifier would be to do some sort of +prechecking on a method call. For example: + + before 'size' => sub { + my $self = shift; + + die 'Cannot set size while the person is growing' + if @_ && $self->is_growing; + }; + +This lets us implement logical checks that don't make sense as type +constraints. In particular, they're useful for defining logical rules +about an object's state changes. + +Similarly, an after modifier could be used for logging an action that +was taken. + +Note that the return values of both before and after modifiers are +ignored. + +=head2 Around modifiers + +An around modifier is more powerful than either a before or +after modifier. It can modify the arguments being passed to the +original method, and you can even decide to simply not call the +original method at all. You can also modify the return value with an +around modifier. + +An around modifier receives the original method as its first argument, +I<then> the object, and finally any arguments passed to the method. + + around 'size' => sub { + my $orig = shift; + my $self = shift; + + return $self->$orig() + unless @_; + + my $size = shift; + $size = $size / 2 + if $self->likes_small_things(); + + return $self->$orig($size); + }; + +=head2 Wrapping multiple methods at once + +C<before>, C<after>, and C<around> can also modify multiple methods +at once. The simplest example of this is passing them as a list: + + before [qw(foo bar baz)] => sub { + warn "something is being called!"; + }; + +This will add a C<before> modifier to each of the C<foo>, C<bar>, +and C<baz> methods in the current class, just as though a separate +call to C<before> was made for each of them. The list can be passed +either as a bare list, or as an arrayref. Note that the name of the +function being modified isn't passed in in any way; this syntax is +only intended for cases where the function being modified doesn't +actually matter. If the function name does matter, use something like this: + + for my $func (qw(foo bar baz)) { + before $func => sub { + warn "$func was called!"; + }; + } + +=head2 Using regular expressions to select methods to wrap + +In addition, you can specify a regular expression to indicate the +methods to wrap, like so: + + after qr/^command_/ => sub { + warn "got a command"; + }; + +This will match the regular expression against each method name +returned by L<Class::MOP::Class/get_method_list>, and add a modifier +to each one that matches. The same caveats apply as above. + +Using regular expressions to determine methods to wrap is quite a bit more +powerful than the previous alternatives, but it's also quite a bit more +dangerous. Bear in mind that if your regular expression matches certain Perl +and Moose reserved method names with a special meaning to Moose or Perl, such +as C<meta>, C<new>, C<BUILD>, C<DESTROY>, C<AUTOLOAD>, etc, this could cause +unintended (and hard to debug) problems and is best avoided. + +=head2 Execution order of method modifiers and inheritance + +When both a superclass and an inheriting class have the same method modifiers, +the method modifiers of the inheriting class are wrapped around the method +modifiers of the superclass, as the following example illustrates: + +Here is the parent class: + + package Parent; + use Moose; + sub rant { printf " RANTING!\n" } + before 'rant' => sub { printf " In %s before\n", __PACKAGE__ }; + after 'rant' => sub { printf " In %s after\n", __PACKAGE__ }; + around 'rant' => sub { + my $orig = shift; + my $self = shift; + printf " In %s around before calling original\n", __PACKAGE__; + $self->$orig; + printf " In %s around after calling original\n", __PACKAGE__; + }; + 1; + +And the child class: + + package Child; + use Moose; + extends 'Parent'; + before 'rant' => sub { printf "In %s before\n", __PACKAGE__ }; + after 'rant' => sub { printf "In %s after\n", __PACKAGE__ }; + around 'rant' => sub { + my $orig = shift; + my $self = shift; + printf " In %s around before calling original\n", __PACKAGE__; + $self->$orig; + printf " In %s around after calling original\n", __PACKAGE__; + }; + 1; + +And here's the output when we call the wrapped method (C<< Child->rant >>): + + % perl -MChild -e 'Child->new->rant' + + In Child before + In Child around before calling original + In Parent before + In Parent around before calling original + RANTING! + In Parent around after calling original + In Parent after + In Child around after calling original + In Child after + +=head1 INNER AND AUGMENT + +Augment and inner are two halves of the same feature. The augment +modifier provides a sort of inverted subclassing. You provide part of +the implementation in a superclass, and then document that subclasses +are expected to provide the rest. + +The superclass calls C<inner()>, which then calls the C<augment> +modifier in the subclass: + + package Document; + + use Moose; + + sub as_xml { + my $self = shift; + + my $xml = "<document>\n"; + $xml .= inner(); + $xml .= "</document>\n"; + + return $xml; + } + +Using C<inner()> in this method makes it possible for one or more +subclasses to then augment this method with their own specific +implementation: + + package Report; + + use Moose; + + extends 'Document'; + + augment 'as_xml' => sub { + my $self = shift; + + my $xml = " <report>\n"; + $xml .= inner(); + $xml .= " </report>\n"; + + return $xml; + }; + +When we call C<as_xml> on a Report object, we get something like this: + + <document> + <report> + </report> + </document> + +But we also called C<inner()> in C<Report>, so we can continue +subclassing and adding more content inside the document: + + package Report::IncomeAndExpenses; + + use Moose; + + extends 'Report'; + + augment 'as_xml' => sub { + my $self = shift; + + my $xml = ' <income>' . $self->income . '</income>'; + $xml .= "\n"; + $xml .= ' <expenses>' . $self->expenses . '</expenses>'; + $xml .= "\n"; + + $xml .= inner() || q{}; + + return $xml; + }; + +Now our report has some content: + + <document> + <report> + <income>$10</income> + <expenses>$8</expenses> + </report> + </document> + +What makes this combination of C<augment> and C<inner()> special is +that it allows us to have methods which are called from parent (least +specific) to child (most specific). This inverts the normal +inheritance pattern. + +Note that in C<Report::IncomeAndExpenses> we call C<inner()> again. If the +object is an instance of C<Report::IncomeAndExpenses> then this call is a +no-op, and just returns false. It's a good idea to always call C<inner()> to +allow for future subclassing. + +=head1 OVERRIDE AND SUPER + +Finally, Moose provides some simple sugar for Perl's built-in method +overriding scheme. If you want to override a method from a parent +class, you can do this with C<override>: + + package Employee; + + use Moose; + + extends 'Person'; + + has 'job_title' => ( is => 'rw' ); + + override 'display_name' => sub { + my $self = shift; + + return super() . q{, } . $self->title(); + }; + +The call to C<super()> is almost the same as calling C<< +$self->SUPER::display_name >>. The difference is that the arguments +passed to the superclass's method will always be the same as the ones +passed to the method modifier, and cannot be changed. + +All arguments passed to C<super()> are ignored, as are any changes +made to C<@_> before C<super()> is called. + +=head1 SEMI-COLONS + +Because all of these method modifiers are implemented as Perl +functions, you must always end the modifier declaration with a +semi-colon: + + after 'foo' => sub { }; + +=head1 CAVEATS + +These method modification features do not work well with multiple inheritance, +due to how method resolution is performed in Perl. Experiment with a test +program to ensure your class hierarchy works as expected, or more preferably, +don't use multiple inheritance (roles can help with this)! + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/MooseX.pod b/lib/Moose/Manual/MooseX.pod new file mode 100644 index 0000000..8748267 --- /dev/null +++ b/lib/Moose/Manual/MooseX.pod @@ -0,0 +1,326 @@ +# PODNAME: Moose::Manual::MooseX +# ABSTRACT: Recommended Moose extensions + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::MooseX - Recommended Moose extensions + +=head1 VERSION + +version 2.1405 + +=head1 MooseX? + +It's easy to extend and change Moose, and this is part of what makes +Moose so powerful. You can use the MOP API to do things your own way, +add new features, and generally customize your Moose. + +Writing your own extensions does require a good understanding of the +meta-model. You can start learning about this with the +L<Moose::Manual::MOP> docs. There are also several extension recipes +in the L<Moose::Cookbook>. + +Explaining how to write extensions is beyond the scope of this +manual. Fortunately, lots of people have already written extensions +and put them on CPAN for you. + +This document covers a few of the ones we like best. + +=head1 L<MooseX::AttributeHelpers> + +The functionality of this MooseX module has been moved into Moose core. +See L<Moose::Meta::Attribute::Native>. + +=head1 L<Moose::Autobox> + +MooseX::AttributeHelpers, but turned inside out, Moose::Autobox provides +methods on both arrays/hashes/etc. but also references to them, using +Moose roles, allowing you do to things like: + + use Moose::Autobox; + + $somebody_elses_object->orders->push($order); + +Lexically scoped and not to everybody's taste, but very handy for sugaring +up other people's APIs and your own code. + +=head1 L<MooseX::StrictConstructor> + +By default, Moose lets you pass any old junk into a class's +constructor. If you load L<MooseX::StrictConstructor>, your class will +throw an error if it sees something it doesn't recognize; + + package User; + + use Moose; + use MooseX::StrictConstructor; + + has 'name'; + has 'email'; + + User->new( name => 'Bob', emali => 'bob@example.com' ); + +With L<MooseX::StrictConstructor>, that typo ("emali") will cause a +runtime error. With plain old Moose, the "emali" attribute would be +silently ignored. + +=head1 L<MooseX::Params::Validate> + +We have high hopes for the future of L<MooseX::Method::Signatures> and +L<Moops>. However, these modules, while used regularly in +production by some of the more insane members of the community, are +still marked alpha just in case backwards incompatible changes need to +be made. + +If you don't want to risk that, for now we recommend the decidedly more +clunky (but also faster and simpler) L<MooseX::Params::Validate>. This +module lets you apply Moose types and coercions to any method +arguments. + + package User; + + use Moose; + use MooseX::Params::Validate; + + sub login { + my $self = shift; + my ($password) + = validated_list( \@_, password => { isa => 'Str', required => 1 } ); + + ... + } + +=head1 L<MooseX::Getopt> + +This is a role which adds a C<new_with_options> method to your +class. This is a constructor that takes the command line options and +uses them to populate attributes. + +This makes writing a command-line application as a module trivially +simple: + + package App::Foo; + + use Moose; + with 'MooseX::Getopt'; + + has 'input' => ( + is => 'ro', + isa => 'Str', + required => 1 + ); + + has 'output' => ( + is => 'ro', + isa => 'Str', + required => 1 + ); + + sub run { ... } + +Then in the script that gets run we have: + + use App::Foo; + + App::Foo->new_with_options->run; + +From the command line, someone can execute the script: + + foo@example> foo --input /path/to/input --output /path/to/output + +=head1 L<MooseX::Singleton> + +To be honest, using a singleton is just a way to have a magic global +variable in languages that don't actually have global variables. + +In perl, you can just as easily use a global. However, if your +colleagues are Java-infected, they might prefer a singleton. Also, if +you have an existing class that I<isn't> a singleton but should be, +using L<MooseX::Singleton> is the easiest way to convert it. + + package Config; + + use MooseX::Singleton; # instead of Moose + + has 'cache_dir' => ( ... ); + +It's that simple. + +=head1 EXTENSIONS TO CONSIDER + +There are literally dozens of other extensions on CPAN. This is a list +of extensions that you might find useful, but we're not quite ready to +endorse just yet. + +=head2 L<MooseX::Declare> + +MooseX::Declare is based on L<Devel::Declare>, a giant bag of crack +originally implemented by mst with the goal of upsetting the perl core +developers so much by its very existence that they implemented proper +keyword handling in the core. + +As of perl5 version 14, this goal has been achieved, and modules such +as L<Devel::CallParser>, L<Function::Parameters>, and L<Keyword::Simple> provide +mechanisms to mangle perl syntax that don't require hallucinogenic +drugs to interpret the error messages they produce. + +If you want to use declarative syntax in new code, please for the love +of kittens get yourself a recent perl and look at L<Moops> instead. + +=head2 L<MooseX::Types> + +This extension helps you build a type library for your application. It +also lets you predeclare type names and use them as barewords. + + use MooseX::Types -declare => ['PositiveInt']; + use MooseX::Types::Moose 'Int'; + + subtype PositiveInt, + as Int, + where { $_ > 0 }, + message { "Int is not larger than 0" }; + +One nice feature is that those bareword names are actually namespaced +in Moose's type registry, so multiple applications can use the same +bareword names, even if the type definitions differ. + +=head2 L<MooseX::Types::Structured> + +This extension builds on top of L<MooseX::Types> to let you declare +complex data structure types. + + use MooseX::Types -declare => [ qw( Name Color ) ]; + use MooseX::Types::Moose qw(Str Int); + use MooseX::Types::Structured qw(Dict Tuple Optional); + + subtype Name + => as Dict[ first => Str, middle => Optional[Str], last => Str ]; + + subtype Color + => as Tuple[ Int, Int, Int, Optional[Int] ]; + +Of course, you could always use objects to represent these sorts of +things too. + +=head2 L<MooseX::ClassAttribute> + +This extension provides class attributes for Moose classes. The +declared class attributes are introspectable just like regular Moose +attributes. + + package User; + + use Moose; + use MooseX::ClassAttribute; + + has 'name' => ( ... ); + + class_has 'Cache' => ( ... ); + +Note however that this class attribute does I<not> inherit like a +L<Class::Data::Inheritable> or similar attribute - calling + + $subclass->Cache($cache); + +will set it for the superclass as well. Additionally, class data is usually +The Wrong Thing To Do in a strongly OO program since it makes testing a +lot harder - consider carefully whether you'd be better off with an object +that's passed around instead. + +=head2 L<MooseX::Daemonize> + +This is a role that provides a number of methods useful for creating a +daemon, including methods for starting and stopping, managing a PID +file, and signal handling. + +=head2 L<MooseX::Role::Parameterized> + +If you find yourself wanting a role that customizes itself for each +consumer, this is the tool for you. With this module, you can create a +role that accepts parameters and generates attributes, methods, etc. on +a customized basis for each consumer. + +=head2 L<MooseX::POE> + +This is a small wrapper that ties together a Moose class with +C<POE::Session>, and gives you an C<event> sugar function to declare +event handlers. + +=head2 L<MooseX::FollowPBP> + +Automatically names all accessors I<Perl Best Practices>-style, +"get_size" and "set_size". + +=head2 L<MooseX::SemiAffordanceAccessor> + +Automatically names all accessors with an explicit set and implicit +get, "size" and "set_size". + +=head2 L<MooseX::NonMoose> + +MooseX::NonMoose allows for easily subclassing non-Moose classes with Moose, +taking care of the annoying details connected with doing this, such as +setting up proper inheritance from Moose::Object and installing +(and inlining, at make_immutable time) a constructor that makes sure things +like BUILD methods are called. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Resources.pod b/lib/Moose/Manual/Resources.pod new file mode 100644 index 0000000..e122455 --- /dev/null +++ b/lib/Moose/Manual/Resources.pod @@ -0,0 +1,515 @@ +# PODNAME: Moose::Manual::Resources +# ABSTRACT: Links to various tutorials, videos, blogs, presentations, interviews, etc... + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Resources - Links to various tutorials, videos, blogs, presentations, interviews, etc... + +=head1 VERSION + +version 2.1405 + +=head1 Resources + +This section is an attempt to collect and list some of the many Moose resources that can be found online. Additional information can be found at http://moose.perl.org/ + +=head2 Videos + +=over 4 + +=item + +A new object system for the Perl 5 core, Stevan Little +L<https://www.youtube.com/watch?v=Gf0O6Ct7V1s> + +=item + +Stevan Little interviewed by Gabor Szabo for PerlMaven.com +L<https://www.youtube.com/watch?v=shu-bVimOpM> + +=item + +Perl 6 OO vs. Moose, Herbert Breunung +L<https://www.youtube.com/watch?v=Boh3109HVLo> + +=item + +Introduction To Moose, Mike Whitaker +L<https://www.youtube.com/watch?v=YVtqa6zWXqY> + +=item + +"Dr. Strange... Moose or: How I Learned to Stop Worrying and Love Perl" +L<https://www.youtube.com/watch?v=PNFiIU8S-7g> + +=item + +Evolving Software with Moose, Dave Cross +L<https://www.youtube.com/watch?v=BIMREkoPYKA> + +=item + +Testing with Test::Class::Moose, Curtis Poe +L<https://www.youtube.com/watch?v=kUHI1iRrfF4> + +=item + +"Moose is Perl" tutorial, OSCON 2014, Ricardo Signes +L<https://www.youtube.com/watch?v=LKXvG6VKew4> + +=back + +=head2 Articles + +=over 4 + +=item + +Perl.org Moose Whitepaper +L<https://www.perl.org/about/whitepapers/perl-object-oriented.html> + +=item + +PerlMaven.com +L<http://perlmaven.com/moose> + +=item + +Getting Started with Moose, brian d foy +http://www.theperlreview.com/articles/moose.html + +=item + +Wikipedia.org +L<http://en.wikipedia.org/wiki/Moose_(Perl)> + +=item + +Moose: A postmodern object system for Perl 5 +L<http://perltraining.com.au/tips/2010-01-27.html> + +=item + +Roles and Delegates and Refactoring +L<http://blog.woobling.org/2009/10/roles-and-delegates-and-refactoring.html> + +=back + +=head1 Older Resources + +=head2 Articles + +=head3 2011 + +=over 4 + +=item + +Dave Rolsky reviews Perl Best Practices, Chapter 15, Objects 7 years later +L<http://blog.urth.org/2011/03/reviewing-perl-best-practices-chapter-15-objects.html> + +=item + +Mark A. Stratman discusses subclassing non-Moose classes +L<http://blogs.perl.org/users/mark_a_stratman/2011/03/subclassing-tricky-non-moose-classes-constructor-problems.html> + +=item + +Mark A. Stratman shows how to use delegation to work with non-Moose classes +L<http://blogs.perl.org/users/mark_a_stratman/2011/03/subclassing-tricky-non-moose-classes-dont-do-it.html> + +=item + +The WebGUI folks talk about version 8.0 (which uses Moose) +L<http://blogs.perl.org/users/preaction/2011/01/whats-new-in-webgui-80-1---psgiplack.html> + +=item + +chromatic discusses Parameterized roles with Moose +L<http://www.modernperlbooks.com/mt/2011/01/the-parametric-role-of-my-mvc-plugin-system.html> + +=back + +=head3 2010 + +=over 4 + +=item + +Chris Prather discusses Moose and the Modern Perl movement +L<http://chris.prather.org/been-there-done-that.md.html> + +=item + +Devin Austin talks about MooseX::App::Cmd +L<http://www.catalyzed.org/2010/04/moosexappcmd-and-your-command-line-apps.html> + +=item + +JT Smith declares The Second Age of Perl +L<http://blogs.perl.org/users/jt_smith/2010/04/the-second-age-of-perl.html> + +=item + +JT Smith talks about Lacuna Expanse (which uses Moose) +L<http://blogs.perl.org/users/jt_smith/2010/10/why-the-lacuna-expanse-is-good-for-perl.html> + +=item + +Moose 1.00 is Released +L<http://stevan-little.blogspot.com/2010/03/moose-100-is-released.html> + +=item + +Moritz Lenz asks What is "Modern Perl"? +L<http://perlgeek.de/blog-en/perl-tips/what-is-modern-perl.html> + +=item + +Yuval Kogman declares "Moose has won". +L<http://blog.woobling.org/2010/09/moose-has-won.html> + +=item + +chromatic discusses how Moose helps you write more correct code +L<http://www.modernperlbooks.com/mt/2010/01/subtle-encouragement-toward-correctness.html> + +=item + +chromatic discusses the Moose deprecation policy +L<http://www.modernperlbooks.com/mt/2010/09/the-right-approach-to-deprecation.html> + +=item + +chromatic talks about Class::MOP in relation to his Modern Perl book +L<http://www.modernperlbooks.com/mt/2010/03/ill-get-the-mop.html> + +=item + +chromatic talks about Encapsulation and Moose +L<http://www.modernperlbooks.com/mt/2010/09/what-you-can-and-cannot-teach-about-encapsulation.html> + +=back + +=head3 2009 + +=over 4 + +=item + +Bruno Vecchi praises Moose for making his protein analysis code easier +L<http://zerothorder.blogspot.com/2009/04/chopping-proteins-with-moose.html> + +=item + +Chris Prather compares MooseX::Declare to Simula 67 +L<http://chris.prather.org/a-little-bit-of-history.md.html> + +=item + +Chris Prather rationalizes Moose's "post modern" label +L<http://chris.prather.org/why-moose-is-post-modern.html> + +=item + +Dave Rolsky's post-mortem on his Moose documentation grant +L<http://blog.urth.org/2009/04/moose-docs-grant-wrap-up.html> + +=item + +David McLaughlin experiments with extending Moose for MooseX::ChainedAccessors +L<http://www.dmclaughlin.com/2009/05/15/chained-accessors-in-moose/> + +=item + +Sam Crawley summarizes his experience with roles +L<http://samcrawley.wordpress.com/2009/05/03/getting-the-hang-of-moose-roles/> + +=item + +Shawn M Moore discusses Perl::Critic for Moose and linting with the MOP +L<http://blog.sartak.org/2009/05/perl-critic-dynamic-moose.html> + +=item + +Shlomi Fish discovers a better way to Moose +L<http://community.livejournal.com/shlomif_tech/38407.html> + +=item + +Stevan Little explains why you should make your Moose classes immutable +L<http://stevan-little.blogspot.com/2009/06/why-makeimmutable-is-recommended-for_13.html> + +=item + +Tomas Doran interview about the new Moose-based Catalyst +L<http://www.catalyzed.org/2009/04/catalyst-58-released.html> + +=item + +chromatic contrasts roles and duck-typing +L<http://www.modernperlbooks.com/mt/2009/05/perl-roles-versus-duck-typing.html> + +=item + +chromatic contrasts roles and inheritance +L<http://www.modernperlbooks.com/mt/2009/05/perl-roles-versus-inheritance.html> + +=item + +chromatic on The Why of Perl Roles +L<http://www.modernperlbooks.com/mt/2009/04/the-why-of-perl-roles.html> + +=back + +=head3 2008 + +=over 4 + +=item + +Barry Walsh does an excellent comparison of Moose and Ruby (specifically the Doodle module) +L<http://draegtun.wordpress.com/2008/03/12/doodling-with-moose-part-1/> + +=item + +Tim Bunce's excellent Perl Myths talk gives a shout out to Moose +L<http://www.slideshare.net/Tim.Bunce/perl-myths-200802-with-notes/> + +=item + +chromatic suggests Moose and Mouse in his Beginners Introduction to Object-Oriented Programming with Perl article +L<http://broadcast.oreilly.com/2008/11/beginners-introduction-to-obje.html> + +=back + +=head3 2007 + +=over 4 + +=item + +Larry mentioned Moose in 2007's State of the Onion speech +L<http://www.perl.com/pub/a/2007/12/06/soto-11.html?page=3> + +=item + +Max Kanat-Alexander (of Bugzilla fame) has some nice things to say about Moose +L<http://avatraxiom.livejournal.com/70947.html> + +=back + +=head3 2006 + +=over 4 + +=item + +Class::MOP Review (OnLAMP) +L<http://www.oreillynet.com/onlamp/blog/2006/06/cpan_module_review_classmop.html> + +=back + +=head2 Presentations + +=head3 Perl Mongers Groups + +=over 4 + +=item + +Doug Treder's Moose talk at Seattle Perl Users Group +L<http://www.slideshare.net/dtreder/moose-527243> + +=item + +Hans Dieter Pearcey's Meta-Moose at PDX.pm +L<http://www.weftsoar.net/~hdp/talk/meta-moose/slides/start.html> + +=item + +Piers Cawley's MooseX::Declare talk at London.pm (video) +L<http://www.bofh.org.uk/2009/05/13/london-pm-presentation> + +=item + +Robert Boone's Moose talk at Houston.pm +L<http://houston.pm.org/talks/2007talks/0704Talk/slides/start.html> + +=item + +hakobe's Moose presentation at Kansai.pm +L<http://www.slideshare.net/hakobe/moose> + +=back + +=head3 2011 + +=over 4 + +=item + +SawyerX's FOSDEM 2011 Moose talk +L<http://www.slideshare.net/xSawyer/moose-talk-at-fosdem-2011-perl-devroom> + +=back + +=head3 2010 + +=over 4 + +=item + +Drew Stephens gives a lighting talk on Moose at SHDH 36 +L<http://www.slideshare.net/dinomite/learning-moose-lightning> + +=item + +Jesse Luehrs's "Extending Moose" talk at YAPC::NA 2010 +L<http://tozt.net/talks/extending_moose_yapc_na_2010/> + +=item + +Shawn Moore's "Non-hierarchical osdc.tw +L<http://sartak.org/talks/osdc.tw-2010/nonhierarchical-oop/nonhierarchical-oop.pdf> + +=item + +Ynon Perek's Perl Object Oriented Programming slides +L<http://prezi.com/fgdoyw0smyqo/perl-object-oriented-programming/> + +=back + +=head3 2009 + +=over 4 + +=item + +Dave Rolsky's Introduction to Moose master class at YAPC::NA 2009 (delivered by Shawn Moore and Jonathan Rockway) +L<http://yapc10.org/yn2009/talk/2047> + +=item + +Devin Austin's Intro to Moose at YAPC::NA 2009 +L<http://yapc10.org/yn2009/talk/1967> + +=item + +Hans Dieter Pearcey's Code Reuse with Moose at YAPC::NA 2009 +L<http://yapc10.org/yn2009/talk/1984> + +=item + +Mike Whitaker's Intro to Moose at Italian Perl Workshop +L<http://www.slideshare.net/Penfold/introduction-to-moose-2437037> + +=item + +Mike Whitaker's Introduction to Moose at the Italian Perl Workshop +L<http://conferences.yapceurope.org/ipw2009/talk/2371> + +=item + +Shawn M Moore's Intro to Moose at Frozen Perl +L<http://sartak.org/talks/frozen-perl-2009/moose/> + +=item + +Shawn Moore's Extending Moose for Applications at YAPC::NA 2009 +L<http://sartak.org/talks/yapc-na-2009/extending-moose/extending-moose.pdf> + +=item + +Shawn Moore's Moose master class at YAPC::Asia 2009 +L<http://conferences.yapcasia.org/ya2009/talk/2192> + +=item + +Yuval Kogman's Why Moose at the Nordic Perl Workshop +L<http://www.perlworkshop.no/npw2009/talk/1901> + +=back + +=head3 2008 + +=over 4 + +=item + +Mike Whitaker's Intro to Moose at the London Perl Workshop +L<http://yapc.tv/2008/lpw/mike-whitaker-intro-moose/> + +=back + +=head3 2006 + +=over 4 + +=item + +Sam Vilain gives the very first Moose talk at YAPC::EU +L<http://www.yapceurope.org/2006/talk/item/63.html> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Roles.pod b/lib/Moose/Manual/Roles.pod new file mode 100644 index 0000000..3000e39 --- /dev/null +++ b/lib/Moose/Manual/Roles.pod @@ -0,0 +1,422 @@ +# PODNAME: Moose::Manual::Roles +# ABSTRACT: Roles, an alternative to deep hierarchies and base classes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Roles - Roles, an alternative to deep hierarchies and base classes + +=head1 VERSION + +version 2.1405 + +=head1 WHAT IS A ROLE? + +A role encapsulates some piece of behavior or state that can be shared between +classes. It is something that classes I<do>. It is important to understand that +I<roles are not classes>. You cannot inherit from a role, and a role cannot be +instantiated. We sometimes say that roles are I<consumed>, either by classes +or other roles. + +Instead, a role is I<composed> into a class. In practical terms, this +means that all of the methods, method modifiers, and attributes defined in a role are +added directly to (we sometimes say "flattened into") the class that +consumes the role. These attributes and methods then appear as if they +were defined in the class itself. A subclass of the consuming class +will inherit all of these methods and attributes. + +Moose roles are similar to mixins or interfaces in other languages. + +Besides defining their own methods and attributes, roles can also +require that the consuming class define certain methods of its +own. You could have a role that consisted only of a list of required +methods, in which case the role would be very much like a Java +interface. + +Note that attribute accessors also count as methods for the +purposes of satisfying the requirements of a role. + +=head1 A SIMPLE ROLE + +Creating a role looks a lot like creating a Moose class: + + package Breakable; + + use Moose::Role; + + has 'is_broken' => ( + is => 'rw', + isa => 'Bool', + ); + + sub break { + my $self = shift; + + print "I broke\n"; + + $self->is_broken(1); + } + +Except for our use of L<Moose::Role>, this looks just like a class +definition with Moose. However, this is not a class, and it cannot be +instantiated. + +Instead, its attributes and methods will be composed into classes +which use the role: + + package Car; + + use Moose; + + with 'Breakable'; + + has 'engine' => ( + is => 'ro', + isa => 'Engine', + ); + +The C<with> function composes roles into a class. Once that is done, +the C<Car> class has an C<is_broken> attribute and a C<break> +method. The C<Car> class also C<does('Breakable')>: + + my $car = Car->new( engine => Engine->new ); + + print $car->is_broken ? 'Busted' : 'Still working'; + $car->break; + print $car->is_broken ? 'Busted' : 'Still working'; + + $car->does('Breakable'); # true + +This prints: + + Still working + I broke + Busted + +We could use this same role in a C<Bone> class: + + package Bone; + + use Moose; + + with 'Breakable'; + + has 'marrow' => ( + is => 'ro', + isa => 'Marrow', + ); + +See also L<Moose::Cookbook::Roles::Comparable_CodeReuse> for an example. + +It's possible to compose existing roles into new roles. For example, we can +have a C<HandleWithCare> class which applies both the C<Breakable> and +C<Package> roles to any class which consumes it: + + package HandleWithCare; + + use Moose::Role; + + with 'Breakable', 'Package'; + +=head1 REQUIRED METHODS + +As mentioned previously, a role can require that consuming classes +provide one or more methods. Using our C<Breakable> example, let's +make it require that consuming classes implement their own C<break> +methods: + + package Breakable; + + use Moose::Role; + + requires 'break'; + + has 'is_broken' => ( + is => 'rw', + isa => 'Bool', + ); + + after 'break' => sub { + my $self = shift; + + $self->is_broken(1); + }; + +If we try to consume this role in a class that does not have a +C<break> method, we will get an exception. + +You can see that we added a method modifier on C<break>. We want +classes that consume this role to implement their own logic for +breaking, but we make sure that the C<is_broken> attribute is always +set to true when C<break> is called. + + package Car + + use Moose; + + with 'Breakable'; + + has 'engine' => ( + is => 'ro', + isa => 'Engine', + ); + + sub break { + my $self = shift; + + if ( $self->is_moving ) { + $self->stop; + } + } + +=head2 Roles Versus Abstract Base Classes + +If you are familiar with the concept of abstract base classes in other +languages, you may be tempted to use roles in the same way. + +You I<can> define an "interface-only" role, one that contains I<just> +a list of required methods. + +However, any class which consumes this role must implement all of the +required methods, either directly or through inheritance from a +parent. You cannot delay the method requirement check so that they can +be implemented by future subclasses. + +Because the role defines the required methods directly, adding a base +class to the mix would not achieve anything. We recommend that you +simply consume the interface role in each class which implements that +interface. + +=head2 Required Attributes + +As mentioned before, a role's required method may also be satisfied by an +attribute accessor. However, the call to C<has> which defines an attribute +happens at runtime. This means that you must define the attribute I<before> +consuming the role, or else the role will not see the generated accessor. + + package Breakable; + + use Moose::Role; + + requires 'stress'; + + package Car; + + use Moose; + + has 'stress' => ( + is => 'rw', + isa => 'Int', + ); + + with 'Breakable'; + +=head1 USING METHOD MODIFIERS + +Method modifiers and roles are a very powerful combination. Often, a +role will combine method modifiers and required methods. We already +saw one example with our C<Breakable> example. + +Method modifiers increase the complexity of roles, because they make +the role application order relevant. If a class uses multiple roles, +each of which modify the same method, those modifiers will be applied +in the same order as the roles are used: + + package MovieCar; + + use Moose; + + extends 'Car'; + + with 'Breakable', 'ExplodesOnBreakage'; + +Assuming that the new C<ExplodesOnBreakage> role I<also> has an +C<after> modifier on C<break>, the C<after> modifiers will run one +after the other. The modifier from C<Breakable> will run first, then +the one from C<ExplodesOnBreakage>. + +=head1 METHOD CONFLICTS + +If a class composes multiple roles, and those roles have methods of +the same name, we will have a conflict. In that case, the composing +class is required to provide its I<own> method of the same name. + + package Breakdancer; + + use Moose::Role; + + sub break { + + } + +If we compose both C<Breakable> and C<Breakdancer> in a class, we must +provide our own C<break> method: + + package FragileDancer; + + use Moose; + + with 'Breakable', 'Breakdancer'; + + sub break { ... } + +A role can be a collection of other roles: + + package Break::Bundle; + + use Moose::Role; + + with ('Breakable', 'Breakdancer'); + +When a role consumes another a role, the I<consuming> role's methods silently +win in any conflict, and the consumed role's methods are simply ignored. + +=head1 METHOD EXCLUSION AND ALIASING + +If we want our C<FragileDancer> class to be able to call the methods +from both its roles, we can alias the methods: + + package FragileDancer; + + use Moose; + + with 'Breakable' => { -alias => { break => 'break_bone' } }, + 'Breakdancer' => { -alias => { break => 'break_dance' } }; + +However, aliasing a method simply makes a I<copy> of the method with +the new name. We also need to exclude the original name: + + with 'Breakable' => { + -alias => { break => 'break_bone' }, + -excludes => 'break', + }, + 'Breakdancer' => { + -alias => { break => 'break_dance' }, + -excludes => 'break', + }; + +The excludes parameter prevents the C<break> method from being composed +into the C<FragileDancer> class, so we don't have a conflict. This +means that C<FragileDancer> does not need to implement its own +C<break> method. + +This is useful, but it's worth noting that this breaks the contract +implicit in consuming a role. Our C<FragileDancer> class does both the +C<Breakable> and C<BreakDancer>, but does not provide a C<break> +method. If some API expects an object that does one of those roles, it +probably expects it to implement that method. + +In some use cases we might alias and exclude methods from roles, but +then provide a method of the same name in the class itself. + +Also see L<Moose::Cookbook::Roles::Restartable_AdvancedComposition> for an example. + +=head1 OVERLOADING + +When a Moose role uses overloading, that overloading is composed into any +classes that consume the role. This includes the setting of the C<fallback> +value for that role's overloading. Just as with methods and attributes, when a +role consumes another role, that other role's overloading settings are applied +to the role. + +Just as with methods, there can be conflicts with overloading implementations +between multiple roles when they are all consumed by a class. If two roles +both provide different overloading implementations for a given operator, that +is a conflict. If two roles both implement overloading and have different +C<fallback> values, that is also considered a conflict. These conflicts are +detected when multiple roles are being composed into a class together. + +When a role consumes another role, the consuming role's overloading fallback +and operator implementations silently "win" the conflict. + +=head1 ROLE EXCLUSION + +A role can say that it cannot be combined with some other role. This +should be used with great caution, since it limits the re-usability of +the role. + + package Breakable; + + use Moose::Role; + + excludes 'BreakDancer'; + +=head1 ADDING A ROLE TO AN OBJECT INSTANCE + +You may want to add a role to an object instance, rather than to a class. For +example, you may want to add debug tracing to one instance of an object while +debugging a particular bug. Another use case might be to dynamically change +objects based on a user's configuration, as a plugin system. + +The best way to do this is to use the C<apply_all_roles()> function from +L<Moose::Util>: + + use Moose::Util qw( apply_all_roles ); + + my $car = Car->new; + apply_all_roles( $car, 'Breakable' ); + +This function can apply more than one role at a time, and will do so using the +normal Moose role combination system. We recommend using this function to +apply roles to an object. This is what Moose uses internally when you call +C<with>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Support.pod b/lib/Moose/Manual/Support.pod new file mode 100644 index 0000000..d4d48a6 --- /dev/null +++ b/lib/Moose/Manual/Support.pod @@ -0,0 +1,204 @@ +# PODNAME: Moose::Manual::Support +# ABSTRACT: Policies regarding support, releases, and compatibility. + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Support - Policies regarding support, releases, and compatibility. + +=head1 VERSION + +version 2.1405 + +=head1 SUPPORT POLICY + +There are two principles to Moose's policy of supported behavior. + +=over 4 + +=item 1. + +Moose favors correctness over everything. + +=item 2. + +Moose supports documented and tested behavior, not accidental behavior or side +effects. + +=back + +If a behavior has never been documented or tested, the behavior is +I<officially> undefined. Relying upon undocumented and untested behavior is +done at your own risk. + +If a behavior is documented or tested but found to be incorrect later, the +behavior will go through a deprecation period. During the deprecation period, +use of that feature will cause a warning. Eventually, the deprecated feature +will be removed. + +In some cases, it is not possible to deprecate a behavior. In this case, the +behavior will simply be changed in a major release. + +=head1 RELEASE SCHEDULE + +Moose is on a system of quarterly major releases, with minor releases as +needed between major releases. A minor release is defined as one that makes +every attempt to preserve backwards compatibility. Currently this means that we +did not introduce any new dependency conflicts, and that we did not make any +changes to documented or tested behavior (this typically means that minor +releases will not change any existing tests in the test suite, although they +can add new ones). A minor release can include new features and bug fixes. + +Major releases may be backwards incompatible. Moose prioritizes +correctness over backwards compatibility or performance; see the L<DEPRECATION +POLICY> to understand how backwards incompatible changes are announced. + +Major releases are scheduled to happen during fixed release windows. If the +window is missed, then there will not be a major release until the next +release window. The release windows are one month long, and occur during the +months of January, April, July, and October. + +Before a major release, a series of development releases will be made so that +users can test the upcoming major release before it is distributed to CPAN. It +is in the best interests of everyone involved if these releases are tested as +widely as possible. + +=head1 DEPRECATION POLICY + +Moose has always prioritized correctness over performance and backwards +compatibility. + +Major deprecations or API changes are documented in the Changes file as well +as in L<Moose::Manual::Delta>. The Moose developers will also make an effort +to warn users of upcoming deprecations and breakage through the Moose blog +(http://blog.moose.perl.org). + +Deprecated APIs will be preserved for at least one year I<after the major +release which deprecates that API>. Deprecated APIs will only be removed in a +major release. + +Moose will also warn during installation if the version of Moose being +installed will break an installed dependency. Unfortunately, due to the nature +of the Perl install process these warnings may be easy to miss. + +=head1 BACKWARDS COMPATIBILITY + +We try to ensure compatibility by having a extensive test suite (last count +over 18000 tests), as well as testing a number of packages (currently just +under 100 packages) that depend on Moose before any release. + +The current list of downstream dependencies that are tested is in +C<xt/author/test-my-dependents.t>. + +=head1 VERSION NUMBERS + +Moose version numbers consist of three parts, in the form X.YYZZ. The X is the +"special magic number" that only gets changed for really big changes. Think of +this as being like the "5" in Perl 5.12.1. + +The YY portion is the major version number. Moose uses even numbers for stable +releases, and odd numbers for trial releases. The ZZ is the minor version, and +it simply increases monotonically. It starts at "00" each time a new major +version is released. + +Semantically, this means that any two releases which share a major version +should be API-compatible with each other. In other words, 2.0200, 2.0201, and +2.0274 are all API-compatible. + +Prior to version 2.0, Moose version numbers were monotonically incrementing +two decimal values (0.01, 0.02, ... 1.11, 1.12, etc.). + +Moose was declared production ready at version 0.18 (via L<< +http://www.perlmonks.org/?node_id=608144 >>). + +=head1 PERL VERSION COMPATIBILITY + +As of version 2.16, Moose will officially support being run on perl 5.10.1+. Our +current policy is to support the earliest version of Perl shipped in the latest +stable release of any major operating system (this tends to mean CentOS). We +will provide at least six months notice (two major releases) when we decide to +increase the officially supported Perl version. + +"Officially supported" does not mean that these are the only versions of Perl +that Moose will work with. Our declared perl dependency will remain at 5.8.3 +as long as our test suite continues to pass on 5.8.3. What this does mean is +that the core Moose dev team will not be spending any time fixing bugs on +versions that aren't officially supported, and new contributions will not be +rejected due to being incompatible with older versions of perl except in the +most trivial of cases. We will, however, still welcome patches to make Moose +compatible with earlier versions, if other people are still interested in +maintaining compatibility. As such, the current minimum required version of +5.8.3 will remain for as long as downstream users are happy to assist with +maintenance. + +Note that although performance regressions are acceptable in order to maintain +backwards compatibility (as long as they only affect the older versions), +functionality changes and buggy behavior will not be. If it becomes impossible +to provide identical functionality between modern Perl versions and +unsupported Perl versions, we will increase our declared perl dependency +instead. + +=head1 CONTRIBUTING + +Moose has an open contribution policy. Anybody is welcome to submit a +patch. Please see L<Moose::Manual::Contributing> for more details. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Types.pod b/lib/Moose/Manual/Types.pod new file mode 100644 index 0000000..9ff7532 --- /dev/null +++ b/lib/Moose/Manual/Types.pod @@ -0,0 +1,491 @@ +# PODNAME: Moose::Manual::Types +# ABSTRACT: Moose's type system + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Types - Moose's type system + +=head1 VERSION + +version 2.1405 + +=head1 TYPES IN PERL? + +Moose provides its own type system for attributes. You can also use +these types to validate method parameters with the help of a MooseX +module. + +Moose's type system is based on a combination of Perl 5's own +I<implicit> types and some Perl 6 concepts. You can create your +own subtypes with custom constraints, making it easy to express any +sort of validation. + +Types have names, and you can re-use them by name, making it easy to +share types throughout a large application. + +However, this is not a "real" type system. Moose does not magically make Perl +start associating types with variables. This is just an advanced parameter +checking system which allows you to associate a name with a constraint. + +That said, it's still pretty damn useful, and we think it's one of the +things that makes Moose both fun and powerful. Taking advantage of the +type system makes it much easier to ensure that you are getting valid +data, and it also contributes greatly to code maintainability. + +=head1 THE TYPES + +The basic Moose type hierarchy looks like this + + Any + Item + Bool + Maybe[`a] + Undef + Defined + Value + Str + Num + Int + ClassName + RoleName + Ref + ScalarRef[`a] + ArrayRef[`a] + HashRef[`a] + CodeRef + RegexpRef + GlobRef + FileHandle + Object + +In practice, the only difference between C<Any> and C<Item> is +conceptual. C<Item> is used as the top-level type in the hierarchy. + +The rest of these types correspond to existing Perl concepts. +In particular: + +=over 4 + +=item + +C<Bool> accepts C<1> for true, and undef, 0, or the empty string as false. + +=item + +C<Maybe[`a]> accepts either C<`a> or C<undef>. + +=item + +C<Num> accepts integers, floating point numbers (both in decimal notation & +exponential notation), 0, .0, 0.0 etc. It doesn't accept numbers with +whitespace, Inf, Infinity, "0 but true", NaN & other such strings. + +=item + +C<ClassName> and C<RoleName> accept strings that are either the name of a class or the name of a role. The class/role must already be loaded when the constraint is checked. + +=item + +C<FileHandle> accepts either an L<IO::Handle> object or a builtin perl filehandle (see L<Scalar::Util/openhandle>). + +=item + +C<Object> accepts any blessed reference. + +=back + +The types followed by "[`a]" can be parameterized. So instead of just +plain C<ArrayRef> we can say that we want C<ArrayRef[Int]> instead. We +can even do something like C<HashRef[ArrayRef[Str]]>. + +The C<Maybe[`a]> type deserves a special mention. Used by itself, it +doesn't really mean anything (and is equivalent to C<Item>). When it +is parameterized, it means that the value is either C<undef> or the +parameterized type. So C<Maybe[Int]> means an integer or C<undef>. + +For more details on the type hierarchy, see +L<Moose::Util::TypeConstraints>. + +=head1 WHAT IS A TYPE? + +It's important to realize that types are not classes (or +packages). Types are just objects (L<Moose::Meta::TypeConstraint> +objects, to be exact) with a name and a constraint. Moose maintains a +global type registry that lets it convert names like C<Num> into the +appropriate object. + +However, class names I<can be> type names. When you define a new class +using Moose, it defines an associated type name behind the scenes: + + package MyApp::User; + + use Moose; + +Now you can use C<'MyApp::User'> as a type name: + + has creator => ( + is => 'ro', + isa => 'MyApp::User', + ); + +However, for non-Moose classes there's no magic. You may have to +explicitly declare the class type. This is a bit muddled because Moose +assumes that any unknown type name passed as the C<isa> value for an +attribute is a class. So this works: + + has 'birth_date' => ( + is => 'ro', + isa => 'DateTime', + ); + +In general, when Moose is presented with an unknown name, it assumes +that the name is a class: + + subtype 'ModernDateTime' + => as 'DateTime' + => where { $_->year() >= 1980 } + => message { 'The date you provided is not modern enough' }; + + has 'valid_dates' => ( + is => 'ro', + isa => 'ArrayRef[DateTime]', + ); + +Moose will assume that C<DateTime> is a class name in both of these +instances. + +=head1 SUBTYPES + +Moose uses subtypes in its built-in hierarchy. For example, C<Int> is +a child of C<Num>. + +A subtype is defined in terms of a parent type and a constraint. Any +constraints defined by the parent(s) will be checked first, followed by +constraints defined by the subtype. A value must pass I<all> of these +checks to be valid for the subtype. + +Typically, a subtype takes the parent's constraint and makes it more +specific. + +A subtype can also define its own constraint failure message. This +lets you do things like have an error "The value you provided (20), +was not a valid rating, which must be a number from 1-10." This is +much friendlier than the default error, which just says that the value +failed a validation check for the type. The default error can, however, +be made more friendly by installing L<Devel::PartialDump> (version 0.14 or +higher), which Moose will use if possible to display the invalid value. + +Here's a simple (and useful) subtype example: + + subtype 'PositiveInt', + as 'Int', + where { $_ > 0 }, + message { "The number you provided, $_, was not a positive number" }; + +Note that the sugar functions for working with types are all exported +by L<Moose::Util::TypeConstraints>. + +=head1 TYPE NAMES + +Type names are global throughout the current Perl +interpreter. Internally, Moose maps names to type objects via a +L<registry|Moose::Meta::TypeConstraint::Registry>. + +If you have multiple apps or libraries all using Moose in the same +process, you could have problems with collisions. We recommend that +you prefix names with some sort of namespace indicator to prevent +these sorts of collisions. + +For example, instead of calling a type "PositiveInt", call it +"MyApp::Type::PositiveInt" or "MyApp::Types::PositiveInt". We +recommend that you centralize all of these definitions in a single +package, C<MyApp::Types>, which can be loaded by other classes in your +application. + +However, before you do this, you should look at the L<MooseX::Types> +module. This module makes it easy to create a "type library" module, which can +export your types as perl constants. + + has 'counter' => (is => 'rw', isa => PositiveInt); + +This lets you use a short name rather than needing to fully qualify the name +everywhere. It also allows you to easily create parameterized types: + + has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]); + +This module will check your names at compile time, and is generally more +robust than the string type parsing for complex cases. + +=head1 COERCION + +A coercion lets you tell Moose to automatically convert one type to another. + + subtype 'ArrayRefOfInts', + as 'ArrayRef[Int]'; + + coerce 'ArrayRefOfInts', + from 'Int', + via { [ $_ ] }; + +You'll note that we created a subtype rather than coercing C<ArrayRef[Int]> +directly. It's a bad idea to add coercions to the raw built in +types. + +Coercions are global, just like type names, so a coercion applied to a built +in type is seen by all modules using Moose types. This is I<another> reason +why it is good to namespace your types. + +Moose will I<never> try to coerce a value unless you explicitly ask for +it. This is done by setting the C<coerce> attribute option to a true value: + + package Foo; + + has 'sizes' => ( + is => 'ro', + isa => 'ArrayRefOfInts', + coerce => 1, + ); + + Foo->new( sizes => 42 ); + +This code example will do the right thing, and the newly created +object will have C<[ 42 ]> as its C<sizes> attribute. + +=head2 Deep coercion + +Deep coercion is the coercion of type parameters for parameterized +types. Let's take these types as an example: + + subtype 'HexNum', + as 'Str', + where { /[a-f0-9]/i }; + + coerce 'Int', + from 'HexNum', + via { hex $_ }; + + has 'sizes' => ( + is => 'ro', + isa => 'ArrayRef[Int]', + coerce => 1, + ); + +If we try passing an array reference of hex numbers for the C<sizes> +attribute, Moose will not do any coercion. + +However, you can define a set of subtypes to enable coercion between +two parameterized types. + + subtype 'ArrayRefOfHexNums', + as 'ArrayRef[HexNum]'; + + subtype 'ArrayRefOfInts', + as 'ArrayRef[Int]'; + + coerce 'ArrayRefOfInts', + from 'ArrayRefOfHexNums', + via { [ map { hex } @{$_} ] }; + + Foo->new( sizes => [ 'a1', 'ff', '22' ] ); + +Now Moose will coerce the hex numbers to integers. + +Moose does not attempt to chain coercions, so it will not +coerce a single hex number. To do that, we need to define a separate +coercion: + + coerce 'ArrayRefOfInts', + from 'HexNum', + via { [ hex $_ ] }; + +Yes, this can all get verbose, but coercion is tricky magic, and we +think it's best to make it explicit. + +=head1 TYPE UNIONS + +Moose allows you to say that an attribute can be of two or more +disparate types. For example, we might allow an C<Object> or +C<FileHandle>: + + has 'output' => ( + is => 'rw', + isa => 'Object | FileHandle', + ); + +Moose actually parses that string and recognizes that you are creating +a type union. The C<output> attribute will accept any sort of object, +as well as an unblessed file handle. It is up to you to do the right +thing for each of them in your code. + +Whenever you use a type union, you should consider whether or not +coercion might be a better answer. + +For our example above, we might want to be more specific, and insist +that output be an object with a C<print> method: + + duck_type 'CanPrint', [qw(print)]; + +We can coerce file handles to an object that satisfies this condition +with a simple wrapper class: + + package FHWrapper; + + use Moose; + + has 'handle' => ( + is => 'rw', + isa => 'FileHandle', + ); + + sub print { + my $self = shift; + my $fh = $self->handle(); + + print {$fh} @_; + } + +Now we can define a coercion from C<FileHandle> to our wrapper class: + + coerce 'CanPrint' + => from 'FileHandle' + => via { FHWrapper->new( handle => $_ ) }; + + has 'output' => ( + is => 'rw', + isa => 'CanPrint', + coerce => 1, + ); + +This pattern of using a coercion instead of a type union will help +make your class internals simpler. + +=head1 TYPE CREATION HELPERS + +The L<Moose::Util::TypeConstraints> module exports a number of helper +functions for creating specific kinds of types. These include +C<class_type>, C<role_type>, C<maybe_type>, and C<duck_type>. See the +docs for details. + +One helper worth noting is C<enum>, which allows you to create a +subtype of C<Str> that only allows the specified values: + + enum 'RGB', [qw( red green blue )]; + +This creates a type named C<RGB>. + +=head1 ANONYMOUS TYPES + +All of the type creation functions return a type object. This type +object can be used wherever you would use a type name, as a parent +type, or as the value for an attribute's C<isa> option: + + has 'size' => ( + is => 'ro', + isa => subtype( 'Int' => where { $_ > 0 } ), + ); + +This is handy when you want to create a one-off type and don't want to +"pollute" the global namespace registry. + +=head1 VALIDATING METHOD PARAMETERS + +Moose does not provide any means of validating method +parameters. However, there are several MooseX extensions on CPAN which +let you do this. + +The simplest and least sugary is L<MooseX::Params::Validate>. This +lets you validate a set of named parameters using Moose types: + + use Moose; + use MooseX::Params::Validate; + + sub foo { + my $self = shift; + my %params = validated_hash( + \@_, + bar => { isa => 'Str', default => 'Moose' }, + ); + ... + } + +L<MooseX::Params::Validate> also supports coercions. + +There are several more powerful extensions that support method +parameter validation using Moose types, including +L<MooseX::Method::Signatures>, which gives you a full-blown C<method> +keyword. + + method morning ( Str $name ) { + $self->say("Good morning ${name}!"); + } + +=head1 LOAD ORDER ISSUES + +Because Moose types are defined at runtime, you may run into load +order problems. In particular, you may want to use a class's type +constraint before that type has been defined. + +In order to ameliorate this problem, we recommend defining I<all> of your +custom types in one module, C<MyApp::Types>, and then loading this module in +all of your other modules. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Manual/Unsweetened.pod b/lib/Moose/Manual/Unsweetened.pod new file mode 100644 index 0000000..bd36927 --- /dev/null +++ b/lib/Moose/Manual/Unsweetened.pod @@ -0,0 +1,386 @@ +# PODNAME: Moose::Manual::Unsweetened +# ABSTRACT: Moose idioms in plain old Perl 5 without the sugar + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Unsweetened - Moose idioms in plain old Perl 5 without the sugar + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +If you're trying to figure out just what the heck Moose does, and how +it saves you time, you might find it helpful to see what Moose is +I<really> doing for you. This document shows you the translation from +Moose sugar back to plain old Perl 5. + +=head1 CLASSES AND ATTRIBUTES + +First, we define two very small classes the Moose way. + + package Person; + + use DateTime; + use DateTime::Format::Natural; + use Moose; + use Moose::Util::TypeConstraints; + + has name => ( + is => 'rw', + isa => 'Str', + required => 1, + ); + + # Moose doesn't know about non-Moose-based classes. + class_type 'DateTime'; + + my $en_parser = DateTime::Format::Natural->new( + lang => 'en', + time_zone => 'UTC', + ); + + coerce 'DateTime' + => from 'Str' + => via { $en_parser->parse_datetime($_) }; + + has birth_date => ( + is => 'rw', + isa => 'DateTime', + coerce => 1, + handles => { birth_year => 'year' }, + ); + + enum 'ShirtSize' => [qw( s m l xl xxl )]; + + has shirt_size => ( + is => 'rw', + isa => 'ShirtSize', + default => 'l', + ); + +This is a fairly simple class with three attributes. We also define an enum +type to validate t-shirt sizes because we don't want to end up with something +like "blue" for the shirt size! + + package User; + + use Email::Valid; + use Moose; + use Moose::Util::TypeConstraints; + + extends 'Person'; + + subtype 'Email' + => as 'Str' + => where { Email::Valid->address($_) } + => message { "$_ is not a valid email address" }; + + has email_address => ( + is => 'rw', + isa => 'Email', + required => 1, + ); + +This class subclasses Person to add a single attribute, email address. + +Now we will show what these classes would look like in plain old Perl +5. For the sake of argument, we won't use any base classes or any +helpers like C<Class::Accessor>. + + package Person; + + use strict; + use warnings; + + use Carp qw( confess ); + use DateTime; + use DateTime::Format::Natural; + + sub new { + my $class = shift; + my %p = ref $_[0] ? %{ $_[0] } : @_; + + exists $p{name} + or confess 'name is a required attribute'; + $class->_validate_name( $p{name} ); + + exists $p{birth_date} + or confess 'birth_date is a required attribute'; + + $p{birth_date} = $class->_coerce_birth_date( $p{birth_date} ); + $class->_validate_birth_date( $p{birth_date} ); + + $p{shirt_size} = 'l' + unless exists $p{shirt_size}: + + $class->_validate_shirt_size( $p{shirt_size} ); + + return bless \%p, $class; + } + + sub _validate_name { + shift; + my $name = shift; + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + + defined $name + or confess 'name must be a string'; + } + + { + my $en_parser = DateTime::Format::Natural->new( + lang => 'en', + time_zone => 'UTC', + ); + + sub _coerce_birth_date { + shift; + my $date = shift; + + return $date unless defined $date && ! ref $date; + + my $dt = $en_parser->parse_datetime($date); + + return $dt ? $dt : undef; + } + } + + sub _validate_birth_date { + shift; + my $birth_date = shift; + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + + $birth_date->isa('DateTime') + or confess 'birth_date must be a DateTime object'; + } + + sub _validate_shirt_size { + shift; + my $shirt_size = shift; + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + + defined $shirt_size + or confess 'shirt_size cannot be undef'; + + my %sizes = map { $_ => 1 } qw( s m l xl xxl ); + + $sizes{$shirt_size} + or confess "$shirt_size is not a valid shirt size (s, m, l, xl, xxl)"; + } + + sub name { + my $self = shift; + + if (@_) { + $self->_validate_name( $_[0] ); + $self->{name} = $_[0]; + } + + return $self->{name}; + } + + sub birth_date { + my $self = shift; + + if (@_) { + my $date = $self->_coerce_birth_date( $_[0] ); + $self->_validate_birth_date( $date ); + + $self->{birth_date} = $date; + } + + return $self->{birth_date}; + } + + sub birth_year { + my $self = shift; + + return $self->birth_date->year; + } + + sub shirt_size { + my $self = shift; + + if (@_) { + $self->_validate_shirt_size( $_[0] ); + $self->{shirt_size} = $_[0]; + } + + return $self->{shirt_size}; + } + +Wow, that was a mouthful! One thing to note is just how much space the +data validation code consumes. As a result, it's pretty common for +Perl 5 programmers to just not bother. Unfortunately, not validating +arguments leads to surprises down the line ("why is birth_date an +email address?"). + +Also, did you spot the (intentional) bug? + +It's in the C<_validate_birth_date()> method. We should check that +the value in C<$birth_date> is actually defined and an object before +we go and call C<isa()> on it! Leaving out those checks means our data +validation code could actually cause our program to die. Oops. + +Note that if we add a superclass to Person we'll have to change the +constructor to account for that. + +(As an aside, getting all the little details of what Moose does for +you just right in this example was really not easy, which emphasizes +the point of the example. Moose saves you a lot of work!) + +Now let's see User: + + package User; + + use strict; + use warnings; + + use Carp qw( confess ); + use Email::Valid; + use Scalar::Util qw( blessed ); + + use parent 'Person'; + + sub new { + my $class = shift; + my %p = ref $_[0] ? %{ $_[0] } : @_; + + exists $p{email_address} + or confess 'email_address is a required attribute'; + $class->_validate_email_address( $p{email_address} ); + + my $self = $class->SUPER::new(%p); + + $self->{email_address} = $p{email_address}; + + return $self; + } + + sub _validate_email_address { + shift; + my $email_address = shift; + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + + defined $email_address + or confess 'email_address must be a string'; + + Email::Valid->address($email_address) + or confess "$email_address is not a valid email address"; + } + + sub email_address { + my $self = shift; + + if (@_) { + $self->_validate_email_address( $_[0] ); + $self->{email_address} = $_[0]; + } + + return $self->{email_address}; + } + +That one was shorter, but it only has one attribute. + +Between the two classes, we have a whole lot of code that doesn't do +much. We could probably simplify this by defining some sort of +"attribute and validation" hash, like this: + + package Person; + + my %Attr = ( + name => { + required => 1, + validate => sub { defined $_ }, + }, + birth_date => { + required => 1, + validate => sub { blessed $_ && $_->isa('DateTime') }, + }, + shirt_size => { + required => 1, + validate => sub { defined $_ && $_ =~ /^(?:s|m|l|xl|xxl)$/i }, + } + ); + +Then we could define a base class that would accept such a definition +and do the right thing. Keep that sort of thing up and we're well on +our way to writing a half-assed version of Moose! + +Of course, there are CPAN modules that do some of what Moose does, +like C<Class::Accessor>, C<Class::Meta>, and so on. But none of them +put together all of Moose's features along with a layer of declarative +sugar, nor are these other modules designed for extensibility in the +same way as Moose. With Moose, it's easy to write a MooseX module to +replace or extend a piece of built-in functionality. + +Moose is a complete OO package in and of itself, and is part of a rich +ecosystem of extensions. It also has an enthusiastic community of +users and is being actively maintained and developed. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute.pm b/lib/Moose/Meta/Attribute.pm new file mode 100644 index 0000000..0c91693 --- /dev/null +++ b/lib/Moose/Meta/Attribute.pm @@ -0,0 +1,1734 @@ +use strict; +use warnings; +package Moose::Meta::Attribute; +our $VERSION = '2.1405'; + +use B (); +use Scalar::Util 'blessed'; +use List::Util 1.33 'any'; +use Try::Tiny; +use overload (); + +use Moose::Deprecated; +use Moose::Meta::Method::Accessor; +use Moose::Meta::Method::Delegation; +use Moose::Util 'throw_exception'; +use Moose::Util::TypeConstraints (); +use Class::MOP::MiniTrait; + +use parent 'Class::MOP::Attribute', 'Moose::Meta::Mixin::AttributeCore'; + +use Carp 'confess'; + +Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait'); + +__PACKAGE__->meta->add_attribute('traits' => ( + reader => 'applied_traits', + predicate => 'has_applied_traits', + Class::MOP::_definition_context(), +)); + +# we need to have a ->does method in here to +# more easily support traits, and the introspection +# of those traits. We extend the does check to look +# for metatrait aliases. +sub does { + my ($self, $role_name) = @_; + my $name = try { + Moose::Util::resolve_metatrait_alias(Attribute => $role_name) + }; + return 0 if !defined($name); # failed to load class + return $self->Moose::Object::does($name); +} + +sub _inline_throw_exception { + my ( $self, $exception_type, $throw_args ) = @_; + return 'die Module::Runtime::use_module("Moose::Exception::' . $exception_type . '")->new(' . ($throw_args || '') . ')'; +} + +sub new { + my ($class, $name, %options) = @_; + $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS + + delete $options{__hack_no_process_options}; + + my %attrs = + ( map { $_ => 1 } + grep { defined } + map { $_->init_arg() } + $class->meta()->get_all_attributes() + ); + + my @bad = sort grep { ! $attrs{$_} } keys %options; + + if (@bad) + { + my $s = @bad > 1 ? 's' : ''; + my $list = join "', '", @bad; + + my $package = $options{definition_context}{package}; + my $context = $options{definition_context}{context} + || 'attribute constructor'; + my $type = $options{definition_context}{type} || 'class'; + + my $location = ''; + if (defined($package)) { + $location = " in "; + $location .= "$type " if $type; + $location .= $package; + } + + Carp::cluck "Found unknown argument$s '$list' in the $context for '$name'$location"; + } + + return $class->SUPER::new($name, %options); +} + +sub interpolate_class_and_new { + my $class = shift; + my $name = shift; + + throw_exception( MustPassEvenNumberOfAttributeOptions => attribute_name => $name, + options => \@_ + ) + if @_ % 2 == 1; + + my %args = @_; + + my ( $new_class, @traits ) = $class->interpolate_class(\%args); + $new_class->new($name, %args, ( scalar(@traits) ? ( traits => \@traits ) : () ) ); +} + +sub interpolate_class { + my ($class, $options) = @_; + + $class = ref($class) || $class; + + if ( my $metaclass_name = delete $options->{metaclass} ) { + my $new_class = Moose::Util::resolve_metaclass_alias( Attribute => $metaclass_name ); + + if ( $class ne $new_class ) { + if ( $new_class->can("interpolate_class") ) { + return $new_class->interpolate_class($options); + } else { + $class = $new_class; + } + } + } + + my @traits; + + if (my $traits = $options->{traits}) { + my $i = 0; + my $has_foreign_options = 0; + + while ($i < @$traits) { + my $trait = $traits->[$i++]; + next if ref($trait); # options to a trait we discarded + + $trait = Moose::Util::resolve_metatrait_alias(Attribute => $trait) + || $trait; + + next if $class->does($trait); + + push @traits, $trait; + + # are there options? + if ($traits->[$i] && ref($traits->[$i])) { + $has_foreign_options = 1 + if any { $_ ne '-alias' && $_ ne '-excludes' } keys %{ $traits->[$i] }; + + push @traits, $traits->[$i++]; + } + } + + if (@traits) { + my %options = ( + superclasses => [ $class ], + roles => [ @traits ], + ); + + if ($has_foreign_options) { + $options{weaken} = 0; + } + else { + $options{cache} = 1; + } + + my $anon_class = Moose::Meta::Class->create_anon_class(%options); + $class = $anon_class->name; + } + } + + return ( wantarray ? ( $class, @traits ) : $class ); +} + +# ... + +# method-generating options shouldn't be overridden +sub illegal_options_for_inheritance { + qw(reader writer accessor clearer predicate) +} + +# NOTE/TODO +# This method *must* be able to handle +# Class::MOP::Attribute instances as +# well. Yes, I know that is wrong, but +# apparently we didn't realize it was +# doing that and now we have some code +# which is dependent on it. The real +# solution of course is to push this +# feature back up into Class::MOP::Attribute +# but I not right now, I am too lazy. +# However if you are reading this and +# looking for something to do,.. please +# be my guest. +# - stevan +sub clone_and_inherit_options { + my ($self, %options) = @_; + + # NOTE: + # we may want to extends a Class::MOP::Attribute + # in which case we need to be able to use the + # core set of legal options that have always + # been here. But we allows Moose::Meta::Attribute + # instances to changes them. + # - SL + my @illegal_options = $self->can('illegal_options_for_inheritance') + ? $self->illegal_options_for_inheritance + : (); + + my @found_illegal_options = grep { exists $options{$_} && exists $self->{$_} ? $_ : undef } @illegal_options; + (scalar @found_illegal_options == 0) + || throw_exception( IllegalInheritedOptions => illegal_options => \@found_illegal_options, + params => \%options + ); + + $self->_process_isa_option( $self->name, \%options ); + $self->_process_does_option( $self->name, \%options ); + + # NOTE: + # this doesn't apply to Class::MOP::Attributes, + # so we can ignore it for them. + # - SL + if ($self->can('interpolate_class')) { + ( $options{metaclass}, my @traits ) = $self->interpolate_class(\%options); + + my %seen; + my @all_traits = grep { $seen{$_}++ } @{ $self->applied_traits || [] }, @traits; + $options{traits} = \@all_traits if @all_traits; + } + + # This method can be called on a CMOP::Attribute object, so we need to + # make sure we can call this method. + $self->_process_lazy_build_option( $self->name, \%options ) + if $self->can('_process_lazy_build_option'); + + $self->clone(%options); +} + +sub clone { + my ( $self, %params ) = @_; + + my $class = delete $params{metaclass} || ref $self; + + my ( @init, @non_init ); + + foreach my $attr ( grep { $_->has_value($self) } Class::MOP::class_of($self)->get_all_attributes ) { + push @{ $attr->has_init_arg ? \@init : \@non_init }, $attr; + } + + my %new_params = ( ( map { $_->init_arg => $_->get_value($self) } @init ), %params ); + + my $name = delete $new_params{name}; + + my $clone = $class->new($name, %new_params, __hack_no_process_options => 1 ); + + foreach my $attr ( @non_init ) { + $attr->set_value($clone, $attr->get_value($self)); + } + + return $clone; +} + +sub _process_options { + my ( $class, $name, $options ) = @_; + + $class->_process_is_option( $name, $options ); + $class->_process_isa_option( $name, $options ); + $class->_process_does_option( $name, $options ); + $class->_process_coerce_option( $name, $options ); + $class->_process_trigger_option( $name, $options ); + $class->_process_auto_deref_option( $name, $options ); + $class->_process_lazy_build_option( $name, $options ); + $class->_process_lazy_option( $name, $options ); + $class->_process_required_option( $name, $options ); +} + +sub _process_is_option { + my ( $class, $name, $options ) = @_; + + return unless $options->{is}; + + ### ------------------------- + ## is => ro, writer => _foo # turns into (reader => foo, writer => _foo) as before + ## is => rw, writer => _foo # turns into (reader => foo, writer => _foo) + ## is => rw, accessor => _foo # turns into (accessor => _foo) + ## is => ro, accessor => _foo # error, accesor is rw + ### ------------------------- + + if ( $options->{is} eq 'ro' ) { + throw_exception("AccessorMustReadWrite" => attribute_name => $name, + params => $options, + ) + if exists $options->{accessor}; + $options->{reader} ||= $name; + } + elsif ( $options->{is} eq 'rw' ) { + if ( $options->{writer} ) { + $options->{reader} ||= $name; + } + else { + $options->{accessor} ||= $name; + } + } + elsif ( $options->{is} eq 'bare' ) { + return; + # do nothing, but don't complain (later) about missing methods + } + else { + throw_exception( InvalidValueForIs => attribute_name => $name, + params => $options, + ); + } +} + +sub _process_isa_option { + my ( $class, $name, $options ) = @_; + + return unless exists $options->{isa}; + + if ( exists $options->{does} ) { + if ( try { $options->{isa}->can('does') } ) { + ( $options->{isa}->does( $options->{does} ) ) + || throw_exception( IsaDoesNotDoTheRole => attribute_name => $name, + params => $options, + ); + } + else { + throw_exception( IsaLacksDoesMethod => attribute_name => $name, + params => $options, + ); + } + } + + # allow for anon-subtypes here ... + # + # Checking for Specio explicitly is completely revolting. At some point + # this needs to be refactored so that Moose core defines a standard type + # API that all types must implement. Unfortunately, the current core API + # is _not_ the right API, so we probably need to A) come up with the new + # API (Specio is a good start); B) refactor the core types to implement + # that API; C) do duck type checking on type objects. + if ( blessed( $options->{isa} ) + && $options->{isa}->isa('Moose::Meta::TypeConstraint') ) { + $options->{type_constraint} = $options->{isa}; + } + elsif ( + blessed( $options->{isa} ) + && $options->{isa}->can('does') + && $options->{isa}->does('Specio::Constraint::Role::Interface') + ) { + $options->{type_constraint} = $options->{isa}; + } + else { + $options->{type_constraint} + = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint( + $options->{isa}, + { package_defined_in => $options->{definition_context}->{package} } + ); + } +} + +sub _process_does_option { + my ( $class, $name, $options ) = @_; + + return unless exists $options->{does} && ! exists $options->{isa}; + + # allow for anon-subtypes here ... + if ( blessed( $options->{does} ) + && $options->{does}->isa('Moose::Meta::TypeConstraint') ) { + $options->{type_constraint} = $options->{does}; + } + else { + $options->{type_constraint} + = Moose::Util::TypeConstraints::find_or_create_does_type_constraint( + $options->{does}, + { package_defined_in => $options->{definition_context}->{package} } + ); + } +} + +sub _process_coerce_option { + my ( $class, $name, $options ) = @_; + + return unless $options->{coerce}; + + ( exists $options->{type_constraint} ) + || throw_exception( CoercionNeedsTypeConstraint => attribute_name => $name, + params => $options, + ); + + throw_exception( CannotCoerceAWeakRef => attribute_name => $name, + params => $options, + ) + if $options->{weak_ref}; + + unless ( $options->{type_constraint}->has_coercion ) { + my $type = $options->{type_constraint}->name; + + throw_exception( CannotCoerceAttributeWhichHasNoCoercion => attribute_name => $name, + type_name => $type, + params => $options + ); + } +} + +sub _process_trigger_option { + my ( $class, $name, $options ) = @_; + + return unless exists $options->{trigger}; + + ( 'CODE' eq ref $options->{trigger} ) + || throw_exception( TriggerMustBeACodeRef => attribute_name => $name, + params => $options, + ); +} + +sub _process_auto_deref_option { + my ( $class, $name, $options ) = @_; + + return unless $options->{auto_deref}; + + ( exists $options->{type_constraint} ) + || throw_exception( CannotAutoDerefWithoutIsa => attribute_name => $name, + params => $options, + ); + + ( $options->{type_constraint}->is_a_type_of('ArrayRef') + || $options->{type_constraint}->is_a_type_of('HashRef') ) + || throw_exception( AutoDeRefNeedsArrayRefOrHashRef => attribute_name => $name, + params => $options, + ); +} + +sub _process_lazy_build_option { + my ( $class, $name, $options ) = @_; + + return unless $options->{lazy_build}; + + throw_exception( CannotUseLazyBuildAndDefaultSimultaneously => attribute_name => $name, + params => $options, + ) + if exists $options->{default}; + + $options->{lazy} = 1; + $options->{builder} ||= "_build_${name}"; + + if ( $name =~ /^_/ ) { + $options->{clearer} ||= "_clear${name}"; + $options->{predicate} ||= "_has${name}"; + } + else { + $options->{clearer} ||= "clear_${name}"; + $options->{predicate} ||= "has_${name}"; + } +} + +sub _process_lazy_option { + my ( $class, $name, $options ) = @_; + + return unless $options->{lazy}; + + ( exists $options->{default} || defined $options->{builder} ) + || throw_exception( LazyAttributeNeedsADefault => params => $options, + attribute_name => $name, + ); +} + +sub _process_required_option { + my ( $class, $name, $options ) = @_; + + if ( + $options->{required} + && !( + ( !exists $options->{init_arg} || defined $options->{init_arg} ) + || exists $options->{default} + || defined $options->{builder} + ) + ) { + throw_exception( RequiredAttributeNeedsADefault => params => $options, + attribute_name => $name, + ); + } +} + +sub initialize_instance_slot { + my ($self, $meta_instance, $instance, $params) = @_; + my $init_arg = $self->init_arg(); + # try to fetch the init arg from the %params ... + + my $val; + my $value_is_set; + if ( defined($init_arg) and exists $params->{$init_arg}) { + $val = $params->{$init_arg}; + $value_is_set = 1; + } + else { + # skip it if it's lazy + return if $self->is_lazy; + # and die if it's required and doesn't have a default value + my $class_name = blessed( $instance ); + throw_exception(AttributeIsRequired => attribute_name => $self->name, + class_name => $class_name, + params => $params, + ) + if $self->is_required && !$self->has_default && !$self->has_builder; + + # if nothing was in the %params, we can use the + # attribute's default value (if it has one) + if ($self->has_default) { + $val = $self->default($instance); + $value_is_set = 1; + } + elsif ($self->has_builder) { + $val = $self->_call_builder($instance); + $value_is_set = 1; + } + } + + return unless $value_is_set; + + $val = $self->_coerce_and_verify( $val, $instance ); + + $self->set_initial_value($instance, $val); + + if ( ref $val && $self->is_weak_ref ) { + $self->_weaken_value($instance); + } +} + +sub _call_builder { + my ( $self, $instance ) = @_; + + my $builder = $self->builder(); + + return $instance->$builder() + if $instance->can( $self->builder ); + + throw_exception( BuilderDoesNotExist => instance => $instance, + attribute => $self, + ); +} + +## Slot management + +sub _make_initializer_writer_callback { + my $self = shift; + my ($meta_instance, $instance, $slot_name) = @_; + my $old_callback = $self->SUPER::_make_initializer_writer_callback(@_); + return sub { + $old_callback->($self->_coerce_and_verify($_[0], $instance)); + }; +} + +sub set_value { + my ($self, $instance, @args) = @_; + my $value = $args[0]; + + my $attr_name = quotemeta($self->name); + + my $class_name = blessed( $instance ); + if ($self->is_required and not @args) { + throw_exception( AttributeIsRequired => attribute_name => $self->name, + class_name => $class_name, + ); + } + + $value = $self->_coerce_and_verify( $value, $instance ); + + my @old; + if ( $self->has_trigger && $self->has_value($instance) ) { + @old = $self->get_value($instance, 'for trigger'); + } + + $self->SUPER::set_value($instance, $value); + + if ( ref $value && $self->is_weak_ref ) { + $self->_weaken_value($instance); + } + + if ($self->has_trigger) { + $self->trigger->($instance, $value, @old); + } +} + +sub _inline_set_value { + my $self = shift; + my ($instance, $value, $tc, $coercion, $message, $for_constructor) = @_; + + my $old = '@old'; + my $copy = '$val'; + $tc ||= '$type_constraint'; + $coercion ||= '$type_coercion'; + $message ||= '$type_message'; + + my @code; + if ($self->_writer_value_needs_copy) { + push @code, $self->_inline_copy_value($value, $copy); + $value = $copy; + } + + # constructors already handle required checks + push @code, $self->_inline_check_required + unless $for_constructor; + + push @code, $self->_inline_tc_code($value, $tc, $coercion, $message); + + # constructors do triggers all at once at the end + push @code, $self->_inline_get_old_value_for_trigger($instance, $old) + unless $for_constructor; + + push @code, ( + $self->SUPER::_inline_set_value($instance, $value), + $self->_inline_weaken_value($instance, $value), + ); + + # constructors do triggers all at once at the end + push @code, $self->_inline_trigger($instance, $value, $old) + unless $for_constructor; + + return @code; +} + +sub _writer_value_needs_copy { + my $self = shift; + return $self->should_coerce; +} + +sub _inline_copy_value { + my $self = shift; + my ($value, $copy) = @_; + + return 'my ' . $copy . ' = ' . $value . ';' +} + +sub _inline_check_required { + my $self = shift; + + return unless $self->is_required; + + my $attr_name = quotemeta($self->name); + + return ( + 'if (@_ < 2) {', + $self->_inline_throw_exception( AttributeIsRequired => + 'attribute_name => "'.$attr_name.'",'. + 'class_name => $class_name' + ) . ';', + '}', + ); +} + +sub _inline_tc_code { + my $self = shift; + my ($value, $tc, $coercion, $message, $is_lazy) = @_; + return ( + $self->_inline_check_coercion( + $value, $tc, $coercion, $is_lazy, + ), + $self->_inline_check_constraint( + $value, $tc, $message, $is_lazy, + ), + ); +} + +sub _inline_check_coercion { + my $self = shift; + my ($value, $tc, $coercion) = @_; + + return unless $self->should_coerce && $self->type_constraint->has_coercion; + + if ( $self->type_constraint->can_be_inlined ) { + return ( + 'if (! (' . $self->type_constraint->_inline_check($value) . ')) {', + $value . ' = ' . $coercion . '->(' . $value . ');', + '}', + ); + } + else { + return ( + 'if (!' . $tc . '->(' . $value . ')) {', + $value . ' = ' . $coercion . '->(' . $value . ');', + '}', + ); + } +} + +sub _inline_check_constraint { + my $self = shift; + my ($value, $tc, $message) = @_; + + return unless $self->has_type_constraint; + + my $attr_name = quotemeta($self->name); + + if ( $self->type_constraint->can_be_inlined ) { + return ( + 'if (! (' . $self->type_constraint->_inline_check($value) . ')) {', + 'my $msg = do { local $_ = ' . $value . '; ' + . $message . '->(' . $value . ');' + . '};'. + $self->_inline_throw_exception( ValidationFailedForInlineTypeConstraint => + 'type_constraint_message => $msg , '. + 'class_name => $class_name, '. + 'attribute_name => "'.$attr_name.'",'. + 'value => '.$value + ).';', + '}', + ); + } + else { + return ( + 'if (!' . $tc . '->(' . $value . ')) {', + 'my $msg = do { local $_ = ' . $value . '; ' + . $message . '->(' . $value . ');' + . '};'. + $self->_inline_throw_exception( ValidationFailedForInlineTypeConstraint => + 'type_constraint_message => $msg , '. + 'class_name => $class_name, '. + 'attribute_name => "'.$attr_name.'",'. + 'value => '.$value + ).';', + '}', + ); + } +} + +sub _inline_get_old_value_for_trigger { + my $self = shift; + my ($instance, $old) = @_; + + return unless $self->has_trigger; + + return ( + 'my ' . $old . ' = ' . $self->_inline_instance_has($instance), + '? ' . $self->_inline_instance_get($instance), + ': ();', + ); +} + +sub _inline_weaken_value { + my $self = shift; + my ($instance, $value) = @_; + + return unless $self->is_weak_ref; + + my $mi = $self->associated_class->get_meta_instance; + return ( + $mi->inline_weaken_slot_value($instance, $self->name), + 'if ref ' . $value . ';', + ); +} + +sub _inline_trigger { + my $self = shift; + my ($instance, $value, $old) = @_; + + return unless $self->has_trigger; + + return '$trigger->(' . $instance . ', ' . $value . ', ' . $old . ');'; +} + +sub _eval_environment { + my $self = shift; + + my $env = { }; + + $env->{'$trigger'} = \($self->trigger) + if $self->has_trigger; + $env->{'$attr_default'} = \($self->default) + if $self->has_default; + + if ($self->has_type_constraint) { + my $tc_obj = $self->type_constraint; + + $env->{'$type_constraint'} = \( + $tc_obj->_compiled_type_constraint + ) unless $tc_obj->can_be_inlined; + # these two could probably get inlined versions too + $env->{'$type_coercion'} = \( + $tc_obj->coercion->_compiled_type_coercion + ) if $tc_obj->has_coercion; + $env->{'$type_message'} = \( + $tc_obj->has_message ? $tc_obj->message : $tc_obj->_default_message + ); + + $env = { %$env, %{ $tc_obj->inline_environment } }; + } + + $env->{'$class_name'} = \($self->associated_class->name); + + # XXX ugh, fix these + $env->{'$attr'} = \$self + if $self->has_initializer && $self->is_lazy; + # pretty sure this is only going to be closed over if you use a custom + # error class at this point, but we should still get rid of this + # at some point + $env->{'$meta'} = \($self->associated_class); + + return $env; +} + +sub _weaken_value { + my ( $self, $instance ) = @_; + + my $meta_instance = Class::MOP::Class->initialize( blessed($instance) ) + ->get_meta_instance; + + $meta_instance->weaken_slot_value( $instance, $self->name ); +} + +sub get_value { + my ($self, $instance, $for_trigger) = @_; + + if ($self->is_lazy) { + unless ($self->has_value($instance)) { + my $value; + if ($self->has_default) { + $value = $self->default($instance); + } elsif ( $self->has_builder ) { + $value = $self->_call_builder($instance); + } + + $value = $self->_coerce_and_verify( $value, $instance ); + + $self->set_initial_value($instance, $value); + + if ( ref $value && $self->is_weak_ref ) { + $self->_weaken_value($instance); + } + } + } + + if ( $self->should_auto_deref && ! $for_trigger ) { + + my $type_constraint = $self->type_constraint; + + if ($type_constraint->is_a_type_of('ArrayRef')) { + my $rv = $self->SUPER::get_value($instance); + return unless defined $rv; + return wantarray ? @{ $rv } : $rv; + } + elsif ($type_constraint->is_a_type_of('HashRef')) { + my $rv = $self->SUPER::get_value($instance); + return unless defined $rv; + return wantarray ? %{ $rv } : $rv; + } + else { + throw_exception( CannotAutoDereferenceTypeConstraint => type_name => $type_constraint->name, + instance => $instance, + attribute => $self + ); + } + + } + else { + + return $self->SUPER::get_value($instance); + } +} + +sub _inline_get_value { + my $self = shift; + my ($instance, $tc, $coercion, $message) = @_; + + my $slot_access = $self->_inline_instance_get($instance); + $tc ||= '$type_constraint'; + $coercion ||= '$type_coercion'; + $message ||= '$type_message'; + + return ( + $self->_inline_check_lazy($instance, $tc, $coercion, $message), + $self->_inline_return_auto_deref($slot_access), + ); +} + +sub _inline_check_lazy { + my $self = shift; + my ($instance, $tc, $coercion, $message) = @_; + + return unless $self->is_lazy; + + my $slot_exists = $self->_inline_instance_has($instance); + + return ( + 'if (!' . $slot_exists . ') {', + $self->_inline_init_from_default($instance, '$default', $tc, $coercion, $message, 'lazy'), + '}', + ); +} + +sub _inline_init_from_default { + my $self = shift; + my ($instance, $default, $tc, $coercion, $message, $for_lazy) = @_; + + if (!($self->has_default || $self->has_builder)) { + throw_exception( LazyAttributeNeedsADefault => attribute => $self ); + } + + return ( + $self->_inline_generate_default($instance, $default), + # intentionally not using _inline_tc_code, since that can be overridden + # to do things like possibly only do member tc checks, which isn't + # appropriate for checking the result of a default + $self->has_type_constraint + ? ($self->_inline_check_coercion($default, $tc, $coercion, $for_lazy), + $self->_inline_check_constraint($default, $tc, $message, $for_lazy)) + : (), + $self->_inline_init_slot($instance, $default), + $self->_inline_weaken_value($instance, $default), + ); +} + +sub _inline_generate_default { + my $self = shift; + my ($instance, $default) = @_; + + if ($self->has_default) { + my $source = 'my ' . $default . ' = $attr_default'; + $source .= '->(' . $instance . ')' + if $self->is_default_a_coderef; + return $source . ';'; + } + elsif ($self->has_builder) { + my $builder = B::perlstring($self->builder); + my $builder_str = quotemeta($self->builder); + my $attr_name_str = quotemeta($self->name); + return ( + 'my ' . $default . ';', + 'if (my $builder = ' . $instance . '->can(' . $builder . ')) {', + $default . ' = ' . $instance . '->$builder;', + '}', + 'else {', + 'my $class = ref(' . $instance . ') || ' . $instance . ';', + $self->_inline_throw_exception( + BuilderMethodNotSupportedForInlineAttribute => + 'class_name => $class,'. + 'attribute_name => "'.$attr_name_str.'",'. + 'instance => '.$instance.','. + 'builder => "'.$builder_str.'"' + ) . ';', + '}', + ); + } + else { + confess( + "Can't generate a default for " . $self->name + . " since no default or builder was specified" + ); + } +} + +sub _inline_init_slot { + my $self = shift; + my ($inv, $value) = @_; + + if ($self->has_initializer) { + return '$attr->set_initial_value(' . $inv . ', ' . $value . ');'; + } + else { + return $self->_inline_instance_set($inv, $value) . ';'; + } +} + +sub _inline_return_auto_deref { + my $self = shift; + + return 'return ' . $self->_auto_deref(@_) . ';'; +} + +sub _auto_deref { + my $self = shift; + my ($ref_value) = @_; + + return $ref_value unless $self->should_auto_deref; + + my $type_constraint = $self->type_constraint; + + my $sigil; + if ($type_constraint->is_a_type_of('ArrayRef')) { + $sigil = '@'; + } + elsif ($type_constraint->is_a_type_of('HashRef')) { + $sigil = '%'; + } + else { + confess( + 'Can not auto de-reference the type constraint \'' + . $type_constraint->name + . '\'' + ); + } + + return 'wantarray ' + . '? ' . $sigil . '{ (' . $ref_value . ') || return } ' + . ': (' . $ref_value . ')'; +} + +## installing accessors + +sub accessor_metaclass { 'Moose::Meta::Method::Accessor' } + +sub install_accessors { + my $self = shift; + $self->SUPER::install_accessors(@_); + $self->install_delegation if $self->has_handles; + return; +} + +sub _check_associated_methods { + my $self = shift; + unless ( + @{ $self->associated_methods } + || ($self->_is_metadata || '') eq 'bare' + ) { + Carp::cluck( + 'Attribute (' . $self->name . ') of class ' + . $self->associated_class->name + . ' has no associated methods' + . ' (did you mean to provide an "is" argument?)' + . "\n" + ) + } +} + +sub _process_accessors { + my $self = shift; + my ($type, $accessor, $generate_as_inline_methods) = @_; + + $accessor = ( keys %$accessor )[0] if ( ref($accessor) || '' ) eq 'HASH'; + my $method = $self->associated_class->get_method($accessor); + + if ( $method + && $method->isa('Class::MOP::Method::Accessor') + && $method->associated_attribute->name ne $self->name ) { + + my $other_attr_name = $method->associated_attribute->name; + my $name = $self->name; + + Carp::cluck( + "You are overwriting an accessor ($accessor) for the $other_attr_name attribute" + . " with a new accessor method for the $name attribute" ); + } + + if ( + $method + && !$method->is_stub + && !$method->isa('Class::MOP::Method::Accessor') + && ( !$self->definition_context + || $method->package_name eq $self->definition_context->{package} ) + ) { + + Carp::cluck( + "You are overwriting a locally defined method ($accessor) with " + . "an accessor" ); + } + + if ( !$self->associated_class->has_method($accessor) + && $self->associated_class->has_package_symbol( '&' . $accessor ) ) { + + Carp::cluck( + "You are overwriting a locally defined function ($accessor) with " + . "an accessor" ); + } + + $self->SUPER::_process_accessors(@_); +} + +sub remove_accessors { + my $self = shift; + $self->SUPER::remove_accessors(@_); + $self->remove_delegation if $self->has_handles; + return; +} + +sub install_delegation { + my $self = shift; + + # NOTE: + # Here we canonicalize the 'handles' option + # this will sort out any details and always + # return an hash of methods which we want + # to delagate to, see that method for details + my %handles = $self->_canonicalize_handles; + + # install the delegation ... + my $associated_class = $self->associated_class; + my $class_name = $associated_class->name; + + foreach my $handle ( sort keys %handles ) { + my $method_to_call = $handles{$handle}; + my $name = "${class_name}::${handle}"; + + if ( my $method = $associated_class->get_method($handle) ) { + throw_exception( + CannotDelegateLocalMethodIsPresent => attribute => $self, + method => $method, + ) unless $method->is_stub; + } + + # NOTE: + # handles is not allowed to delegate + # any of these methods, as they will + # override the ones in your class, which + # is almost certainly not what you want. + + # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something + #cluck("Not delegating method '$handle' because it is a core method") and + next + if $class_name->isa("Moose::Object") + and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle); + + my $method = $self->_make_delegation_method($handle, $method_to_call); + + $self->associated_class->add_method($method->name, $method); + $self->associate_method($method); + } +} + +sub remove_delegation { + my $self = shift; + my %handles = $self->_canonicalize_handles; + my $associated_class = $self->associated_class; + foreach my $handle (keys %handles) { + next unless any { $handle eq $_ } + map { $_->name } + @{ $self->associated_methods }; + $self->associated_class->remove_method($handle); + } +} + +# private methods to help delegation ... + +sub _canonicalize_handles { + my $self = shift; + my $handles = $self->handles; + if (my $handle_type = ref($handles)) { + if ($handle_type eq 'HASH') { + return %{$handles}; + } + elsif ($handle_type eq 'ARRAY') { + return map { $_ => $_ } @{$handles}; + } + elsif ($handle_type eq 'Regexp') { + ($self->has_type_constraint) + || throw_exception( CannotDelegateWithoutIsa => attribute => $self ); + return map { ($_ => $_) } + grep { /$handles/ } $self->_get_delegate_method_list; + } + elsif ($handle_type eq 'CODE') { + return $handles->($self, $self->_find_delegate_metaclass); + } + elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::DuckType')) { + return map { $_ => $_ } @{ $handles->methods }; + } + elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::Role')) { + $handles = $handles->role; + } + else { + throw_exception( UnableToCanonicalizeHandles => attribute => $self, + handles => $handles + ); + } + } + + Moose::Util::_load_user_class($handles); + my $role_meta = Class::MOP::class_of($handles); + + (blessed $role_meta && $role_meta->isa('Moose::Meta::Role')) + || throw_exception( UnableToCanonicalizeNonRolePackage => attribute => $self, + handles => $handles + ); + + return map { $_ => $_ } + map { $_->name } + grep { !$_->isa('Class::MOP::Method::Meta') } ( + $role_meta->_get_local_methods, + $role_meta->get_required_method_list, + ); +} + +sub _get_delegate_method_list { + my $self = shift; + my $meta = $self->_find_delegate_metaclass; + if ($meta->isa('Class::MOP::Class')) { + return map { $_->name } # NOTE: !never! delegate &meta + grep { $_->package_name ne 'Moose::Object' && !$_->isa('Class::MOP::Method::Meta') } + $meta->get_all_methods; + } + elsif ($meta->isa('Moose::Meta::Role')) { + return $meta->get_method_list; + } + else { + throw_exception( UnableToRecognizeDelegateMetaclass => attribute => $self, + delegate_metaclass => $meta + ); + } +} + +sub _find_delegate_metaclass { + my $self = shift; + my $class = $self->_isa_metadata; + my $role = $self->_does_metadata; + + if ( $class ) { + # make sure isa is actually a class + unless ( $self->type_constraint->isa("Moose::Meta::TypeConstraint::Class") ) { + throw_exception( DelegationToATypeWhichIsNotAClass => attribute => $self ); + } + + # make sure the class is loaded + unless ( Moose::Util::_is_package_loaded($class) ) { + throw_exception( DelegationToAClassWhichIsNotLoaded => attribute => $self, + class_name => $class + ); + } + # we might be dealing with a non-Moose class, + # and need to make our own metaclass. if there's + # already a metaclass, it will be returned + return Class::MOP::Class->initialize($class); + } + elsif ( $role ) { + unless ( Moose::Util::_is_package_loaded($role) ) { + throw_exception( DelegationToARoleWhichIsNotLoaded => attribute => $self, + role_name => $role + ); + } + + return Class::MOP::class_of($role); + } + else { + throw_exception( CannotFindDelegateMetaclass => attribute => $self ); + } +} + +sub delegation_metaclass { 'Moose::Meta::Method::Delegation' } + +sub _make_delegation_method { + my ( $self, $handle_name, $method_to_call ) = @_; + + my @curried_arguments; + + ($method_to_call, @curried_arguments) = @$method_to_call + if 'ARRAY' eq ref($method_to_call); + + return $self->delegation_metaclass->new( + name => $handle_name, + package_name => $self->associated_class->name, + attribute => $self, + delegate_to_method => $method_to_call, + curried_arguments => \@curried_arguments, + ); +} + +sub _coerce_and_verify { + my $self = shift; + my $val = shift; + my $instance = shift; + + return $val unless $self->has_type_constraint; + + $val = $self->type_constraint->coerce($val) + if $self->should_coerce && $self->type_constraint->has_coercion; + + $self->verify_against_type_constraint($val, instance => $instance); + + return $val; +} + +sub verify_against_type_constraint { + my $self = shift; + my $val = shift; + + return 1 if !$self->has_type_constraint; + + my $type_constraint = $self->type_constraint; + + $type_constraint->check($val) + || throw_exception( ValidationFailedForTypeConstraint => type => $type_constraint, + value => $val, + attribute => $self, + ); +} + +package Moose::Meta::Attribute::Custom::Moose; +our $VERSION = '2.1403'; + +sub register_implementation { 'Moose::Meta::Attribute' } +1; + +# ABSTRACT: The Moose attribute metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute - The Moose attribute metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Attribute> that provides +additional Moose-specific functionality. + +To really understand this class, you will need to start with the +L<Class::MOP::Attribute> documentation. This class can be understood +as a set of additional features on top of the basic feature provided +by that parent class. + +=head1 INHERITANCE + +C<Moose::Meta::Attribute> is a subclass of L<Class::MOP::Attribute>. + +=head1 METHODS + +Many of the documented below override methods in +L<Class::MOP::Attribute> and add Moose specific features. + +=head2 Creation + +=over 4 + +=item B<< Moose::Meta::Attribute->new($name, %options) >> + +This method overrides the L<Class::MOP::Attribute> constructor. + +Many of the options below are described in more detail in the +L<Moose::Manual::Attributes> document. + +It adds the following options to the constructor: + +=over 8 + +=item * is => 'ro', 'rw', 'bare' + +This provides a shorthand for specifying the C<reader>, C<writer>, or +C<accessor> names. If the attribute is read-only ('ro') then it will +have a C<reader> method with the same attribute as the name. + +If it is read-write ('rw') then it will have an C<accessor> method +with the same name. If you provide an explicit C<writer> for a +read-write attribute, then you will have a C<reader> with the same +name as the attribute, and a C<writer> with the name you provided. + +Use 'bare' when you are deliberately not installing any methods +(accessor, reader, etc.) associated with this attribute; otherwise, +Moose will issue a warning when this attribute is added to a +metaclass. + +=item * isa => $type + +This option accepts a type. The type can be a string, which should be +a type name. If the type name is unknown, it is assumed to be a class +name. + +This option can also accept a L<Moose::Meta::TypeConstraint> object. + +If you I<also> provide a C<does> option, then your C<isa> option must +be a class name, and that class must do the role specified with +C<does>. + +=item * does => $role + +This is short-hand for saying that the attribute's type must be an +object which does the named role. + +=item * coerce => $bool + +This option is only valid for objects with a type constraint +(C<isa>) that defined a coercion. If this is true, then coercions will be applied whenever +this attribute is set. + +You cannot make both this and the C<weak_ref> option true. + +=item * trigger => $sub + +This option accepts a subroutine reference, which will be called after +the attribute is set. + +=item * required => $bool + +An attribute which is required must be provided to the constructor. An +attribute which is required can also have a C<default> or C<builder>, +which will satisfy its required-ness. + +A required attribute must have a C<default>, C<builder> or a +non-C<undef> C<init_arg> + +=item * lazy => $bool + +A lazy attribute must have a C<default> or C<builder>. When an +attribute is lazy, the default value will not be calculated until the +attribute is read. + +=item * weak_ref => $bool + +If this is true, the attribute's value will be stored as a weak +reference. + +=item * documentation + +An arbitrary string that can be retrieved later by calling C<< +$attr->documentation >>. + +=item * auto_deref => $bool + +B<Note that in cases where you want this feature you are often better served +by using a L<Moose::Meta::Attribute::Native> trait instead>. + +If this is true, then the reader will dereference the value when it is +called. The attribute must have a type constraint which defines the +attribute as an array or hash reference. + +=item * lazy_build => $bool + +B<Note that use of this feature is strongly discouraged.> Some documentation +used to encourage use of this feature as a best practice, but we have changed +our minds. + +Setting this to true makes the attribute lazy and provides a number of +default methods. + + has 'size' => ( + is => 'ro', + lazy_build => 1, + ); + +is equivalent to this: + + has 'size' => ( + is => 'ro', + lazy => 1, + builder => '_build_size', + clearer => 'clear_size', + predicate => 'has_size', + ); + +If your attribute name starts with an underscore (C<_>), then the clearer +and predicate will as well: + + has '_size' => ( + is => 'ro', + lazy_build => 1, + ); + +becomes: + + has '_size' => ( + is => 'ro', + lazy => 1, + builder => '_build__size', + clearer => '_clear_size', + predicate => '_has_size', + ); + +Note the doubled underscore in the builder name. Internally, Moose +simply prepends the attribute name with "_build_" to come up with the +builder name. + +=back + +=item B<< $attr->clone(%options) >> + +This creates a new attribute based on attribute being cloned. You must +supply a C<name> option to provide a new name for the attribute. + +The C<%options> can only specify options handled by +L<Class::MOP::Attribute>. + +=back + +=head2 Value management + +=over 4 + +=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >> + +This method is used internally to initialize the attribute's slot in +the object C<$instance>. + +This overrides the L<Class::MOP::Attribute> method to handle lazy +attributes, weak references, and type constraints. + +=item B<get_value> + +=item B<set_value> + + eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') }; + if($@) { + print "Oops: $@\n"; + } + +I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'> + +Before setting the value, a check is made on the type constraint of +the attribute, if it has one, to see if the value passes it. If the +value fails to pass, the set operation dies. + +Any coercion to convert values is done before checking the type constraint. + +To check a value against a type constraint before setting it, fetch the +attribute instance using L<Class::MOP::Class/find_attribute_by_name>, +fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint> +and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Company_Subtypes> +for an example. + +=back + +=head2 Attribute Accessor generation + +=over 4 + +=item B<< $attr->install_accessors >> + +This method overrides the parent to also install delegation methods. + +If, after installing all methods, the attribute object has no associated +methods, it throws an error unless C<< is => 'bare' >> was passed to the +attribute constructor. (Trying to add an attribute that has no associated +methods is almost always an error.) + +=item B<< $attr->remove_accessors >> + +This method overrides the parent to also remove delegation methods. + +=item B<< $attr->inline_set($instance_var, $value_var) >> + +This method return a code snippet suitable for inlining the relevant +operation. It expect strings containing variable names to be used in the +inlining, like C<'$self'> or C<'$_[1]'>. + +=item B<< $attr->install_delegation >> + +This method adds its delegation methods to the attribute's associated +class, if it has any to add. + +=item B<< $attr->remove_delegation >> + +This method remove its delegation methods from the attribute's +associated class. + +=item B<< $attr->accessor_metaclass >> + +Returns the accessor metaclass name, which defaults to +L<Moose::Meta::Method::Accessor>. + +=item B<< $attr->delegation_metaclass >> + +Returns the delegation metaclass name, which defaults to +L<Moose::Meta::Method::Delegation>. + +=back + +=head2 Additional Moose features + +These methods are not found in the superclass. They support features +provided by Moose. + +=over 4 + +=item B<< $attr->does($role) >> + +This indicates whether the I<attribute itself> does the given +role. The role can be given as a full class name, or as a resolvable +trait name. + +Note that this checks the attribute itself, not its type constraint, +so it is checking the attribute's metaclass and any traits applied to +the attribute. + +=item B<< Moose::Meta::Class->interpolate_class_and_new($name, %options) >> + +This is an alternate constructor that handles the C<metaclass> and +C<traits> options. + +Effectively, this method is a factory that finds or creates the +appropriate class for the given C<metaclass> and/or C<traits>. + +Once it has the appropriate class, it will call C<< $class->new($name, +%options) >> on that class. + +=item B<< $attr->clone_and_inherit_options(%options) >> + +This method supports the C<has '+foo'> feature. It does various bits +of processing on the supplied C<%options> before ultimately calling +the C<clone> method. + +One of its main tasks is to make sure that the C<%options> provided +does not include the options returned by the +C<illegal_options_for_inheritance> method. + +=item B<< $attr->illegal_options_for_inheritance >> + +This returns a blacklist of options that can not be overridden in a +subclass's attribute definition. + +This exists to allow a custom metaclass to change or add to the list +of options which can not be changed. + +=item B<< $attr->type_constraint >> + +Returns the L<Moose::Meta::TypeConstraint> object for this attribute, +if it has one. + +=item B<< $attr->has_type_constraint >> + +Returns true if this attribute has a type constraint. + +=item B<< $attr->verify_against_type_constraint($value) >> + +Given a value, this method returns true if the value is valid for the +attribute's type constraint. If the value is not valid, it throws an +error. + +=item B<< $attr->handles >> + +This returns the value of the C<handles> option passed to the +constructor. + +=item B<< $attr->has_handles >> + +Returns true if this attribute performs delegation. + +=item B<< $attr->is_weak_ref >> + +Returns true if this attribute stores its value as a weak reference. + +=item B<< $attr->is_required >> + +Returns true if this attribute is required to have a value. + +=item B<< $attr->is_lazy >> + +Returns true if this attribute is lazy. + +=item B<< $attr->is_lazy_build >> + +Returns true if the C<lazy_build> option was true when passed to the +constructor. + +=item B<< $attr->should_coerce >> + +Returns true if the C<coerce> option passed to the constructor was +true. + +=item B<< $attr->should_auto_deref >> + +Returns true if the C<auto_deref> option passed to the constructor was +true. + +=item B<< $attr->trigger >> + +This is the subroutine reference that was in the C<trigger> option +passed to the constructor, if any. + +=item B<< $attr->has_trigger >> + +Returns true if this attribute has a trigger set. + +=item B<< $attr->documentation >> + +Returns the value that was in the C<documentation> option passed to +the constructor, if any. + +=item B<< $attr->has_documentation >> + +Returns true if this attribute has any documentation. + +=item B<< $attr->applied_traits >> + +This returns an array reference of all the traits which were applied +to this attribute. If none were applied, this returns C<undef>. + +=item B<< $attr->has_applied_traits >> + +Returns true if this attribute has any traits applied. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native.pm b/lib/Moose/Meta/Attribute/Native.pm new file mode 100644 index 0000000..8307129 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native.pm @@ -0,0 +1,299 @@ +use strict; +use warnings; +package Moose::Meta::Attribute::Native; +our $VERSION = '2.1405'; + +use Module::Runtime 'require_module'; + +my @trait_names = qw(Bool Counter Number String Array Hash Code); + +for my $trait_name (@trait_names) { + my $trait_class = "Moose::Meta::Attribute::Native::Trait::$trait_name"; + my $meta = Class::MOP::Class->initialize( + "Moose::Meta::Attribute::Custom::Trait::$trait_name" + ); + + if ($meta->find_method_by_name('register_implementation')) { + my $class = $meta->name->register_implementation; + die "An implementation for $trait_name already exists " . + "(found '$class' when trying to register '$trait_class')" + } + $meta->add_method(register_implementation => sub { + # resolve_metatrait_alias will load classes anyway, but throws away + # their error message; we WANT to die if there's a problem + require_module($trait_class); + return $trait_class; + }); +} + +1; + +# ABSTRACT: Delegate to native Perl types + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native - Delegate to native Perl types + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyClass; + use Moose; + + has 'mapping' => ( + traits => ['Hash'], + is => 'rw', + isa => 'HashRef[Str]', + default => sub { {} }, + handles => { + exists_in_mapping => 'exists', + ids_in_mapping => 'keys', + get_mapping => 'get', + set_mapping => 'set', + set_quantity => [ set => 'quantity' ], + }, + ); + + my $obj = MyClass->new; + $obj->set_quantity(10); # quantity => 10 + $obj->set_mapping('foo', 4); # foo => 4 + $obj->set_mapping('bar', 5); # bar => 5 + $obj->set_mapping('baz', 6); # baz => 6 + + # prints 5 + print $obj->get_mapping('bar') if $obj->exists_in_mapping('bar'); + + # prints 'quantity, foo, bar, baz' + print join ', ', $obj->ids_in_mapping; + +=head1 DESCRIPTION + +Native delegations allow you to delegate to native Perl data +structures as if they were objects. For example, in the L</SYNOPSIS> you can +see a hash reference being treated as if it has methods named C<exists()>, +C<keys()>, C<get()>, and C<set()>. + +The delegation methods (mostly) map to Perl builtins and operators. The return +values of these delegations should be the same as the corresponding Perl +operation. Any deviations will be explicitly documented. + +=head1 API + +Native delegations are enabled by passing certain options to C<has> when +creating an attribute. + +=head2 traits + +To enable this feature, pass the appropriate name in the C<traits> array +reference for the attribute. For example, to enable this feature for hash +reference, we include C<'Hash'> in the list of traits. + +=head2 isa + +You will need to make sure that the attribute has an appropriate type. For +example, to use this with a Hash you must specify that your attribute is some +sort of C<HashRef>. + +=head2 handles + +This is just like any other delegation, but only a hash reference is allowed +when defining native delegations. The keys are the methods to be created in +the class which contains the attribute. The values are the methods provided by +the associated trait. Currying works the same way as it does with any other +delegation. + +See the docs for each native trait for details on what methods are available. + +=head1 TRAITS FOR NATIVE DELEGATIONS + +Below are some simple examples of each native trait. More features are +available than what is shown here; this is just a quick synopsis. + +=over + +=item Array (L<Moose::Meta::Attribute::Native::Trait::Array>) + + has 'queue' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Str]', + default => sub { [] }, + handles => { + add_item => 'push', + next_item => 'shift', + # ... + } + ); + +=item Bool (L<Moose::Meta::Attribute::Native::Trait::Bool>) + + has 'is_lit' => ( + traits => ['Bool'], + is => 'ro', + isa => 'Bool', + default => 0, + handles => { + illuminate => 'set', + darken => 'unset', + flip_switch => 'toggle', + is_dark => 'not', + # ... + } + ); + +=item Code (L<Moose::Meta::Attribute::Native::Trait::Code>) + + has 'callback' => ( + traits => ['Code'], + is => 'ro', + isa => 'CodeRef', + default => sub { + sub {'called'} + }, + handles => { + call => 'execute', + # ... + } + ); + +=item Counter (L<Moose::Meta::Attribute::Native::Trait::Counter>) + + has 'counter' => ( + traits => ['Counter'], + is => 'ro', + isa => 'Num', + default => 0, + handles => { + inc_counter => 'inc', + dec_counter => 'dec', + reset_counter => 'reset', + # ... + } + ); + +=item Hash (L<Moose::Meta::Attribute::Native::Trait::Hash>) + + has 'options' => ( + traits => ['Hash'], + is => 'ro', + isa => 'HashRef[Str]', + default => sub { {} }, + handles => { + set_option => 'set', + get_option => 'get', + has_option => 'exists', + # ... + } + ); + +=item Number (L<Moose::Meta::Attribute::Native::Trait::Number>) + + has 'integer' => ( + traits => ['Number'], + is => 'ro', + isa => 'Int', + default => 5, + handles => { + set => 'set', + add => 'add', + sub => 'sub', + mul => 'mul', + div => 'div', + mod => 'mod', + abs => 'abs', + # ... + } + ); + +=item String (L<Moose::Meta::Attribute::Native::Trait::String>) + + has 'text' => ( + traits => ['String'], + is => 'ro', + isa => 'Str', + default => q{}, + handles => { + add_text => 'append', + replace_text => 'replace', + # ... + } + ); + +=back + +=head1 COMPATIBILITY WITH MooseX::AttributeHelpers + +This feature used to be a separated CPAN distribution called +L<MooseX::AttributeHelpers>. + +When the feature was incorporated into the Moose core, some of the API details +were changed. The underlying capabilities are the same, but some details of +the API were changed. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait.pm b/lib/Moose/Meta/Attribute/Native/Trait.pm new file mode 100644 index 0000000..d61ce06 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait.pm @@ -0,0 +1,244 @@ +package Moose::Meta::Attribute::Native::Trait; +our $VERSION = '2.1405'; + +use Moose::Role; +use Module::Runtime 'require_module'; +use Moose::Deprecated; +use Moose::Util 'throw_exception'; +use Moose::Util::TypeConstraints; + +requires '_helper_type'; + +before '_process_options' => sub { + my ( $self, $name, $options ) = @_; + + $self->_check_helper_type( $options, $name ); +}; + +sub _check_helper_type { + my ( $self, $options, $name ) = @_; + + my $type = $self->_helper_type; + + $options->{isa} = $type + unless exists $options->{isa}; + + my $isa; + my $isa_name; + + if ( blessed( $options->{isa} ) + && $options->{isa}->can('does') + && $options->{isa}->does('Specio::Constraint::Role::Interface') ) { + + $isa = $options->{isa}; + require Specio::Library::Builtins; + return if $isa->is_a_type_of( Specio::Library::Builtins::t($type) ); + $isa_name = $isa->name() || $isa->description(); + } + else { + $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint( + $options->{isa} ); + return if $isa->is_a_type_of($type); + $isa_name = $isa->name(); + } + + throw_exception( WrongTypeConstraintGiven => required_type => $type, + given_type => $isa_name, + attribute_name => $name, + params => $options + ); +} + +before 'install_accessors' => sub { (shift)->_check_handles_values }; + +sub _check_handles_values { + my $self = shift; + + my %handles = $self->_canonicalize_handles; + + for my $original_method ( values %handles ) { + my $name = $original_method->[0]; + + my $accessor_class = $self->_native_accessor_class_for($name); + + ( $accessor_class && $accessor_class->can('new') ) + || confess + "$name is an unsupported method type - $accessor_class"; + } +} + +around '_canonicalize_handles' => sub { + shift; + my $self = shift; + my $handles = $self->handles; + + return unless $handles; + + unless ( 'HASH' eq ref $handles ) { + throw_exception( HandlesMustBeAHashRef => instance => $self, + given_handles => $handles + ); + } + + return + map { $_ => $self->_canonicalize_handles_value( $handles->{$_} ) } + keys %$handles; +}; + +sub _canonicalize_handles_value { + my $self = shift; + my $value = shift; + + if ( ref $value && 'ARRAY' ne ref $value ) { + throw_exception( InvalidHandleValue => instance => $self, + handle_value => $value + ); + } + + return ref $value ? $value : [$value]; +} + +around '_make_delegation_method' => sub { + my $next = shift; + my ( $self, $handle_name, $method_to_call ) = @_; + + my ( $name, @curried_args ) = @$method_to_call; + + my $accessor_class = $self->_native_accessor_class_for($name); + + die "Cannot find an accessor class for $name" + unless $accessor_class && $accessor_class->can('new'); + + return $accessor_class->new( + name => $handle_name, + package_name => $self->associated_class->name, + delegate_to_method => $name, + attribute => $self, + is_inline => 1, + curried_arguments => \@curried_args, + root_types => [ $self->_root_types ], + ); +}; + +sub _root_types { + return $_[0]->_helper_type; +} + +sub _native_accessor_class_for { + my ( $self, $suffix ) = @_; + + my $role + = 'Moose::Meta::Method::Accessor::Native::' + . $self->_native_type . '::' + . $suffix; + + require_module($role); + return Moose::Meta::Class->create_anon_class( + superclasses => + [ $self->accessor_metaclass, $self->delegation_metaclass ], + roles => [$role], + cache => 1, + )->name; +} + +sub _build_native_type { + my $self = shift; + + for my $role_name ( map { $_->name } $self->meta->calculate_all_roles ) { + return $1 if $role_name =~ /::Native::Trait::(\w+)$/; + } + + throw_exception( CannotCalculateNativeType => instance => $self ); +} + +has '_native_type' => ( + is => 'ro', + isa => 'Str', + lazy => 1, + builder => '_build_native_type', +); + +no Moose::Role; +no Moose::Util::TypeConstraints; + +1; + +# ABSTRACT: Shared role for native delegation traits + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait - Shared role for native delegation traits + +=head1 VERSION + +version 2.1405 + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 SEE ALSO + +Documentation for Moose native traits can be found in +L<Moose::Meta::Attribute::Native>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Array.pm b/lib/Moose/Meta/Attribute/Native/Trait/Array.pm new file mode 100644 index 0000000..3d33b08 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Array.pm @@ -0,0 +1,384 @@ +package Moose::Meta::Attribute::Native::Trait::Array; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'ArrayRef' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for ArrayRef attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Array - Helper trait for ArrayRef attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Stuff; + use Moose; + + has 'options' => ( + traits => ['Array'], + is => 'ro', + isa => 'ArrayRef[Str]', + default => sub { [] }, + handles => { + all_options => 'elements', + add_option => 'push', + map_options => 'map', + filter_options => 'grep', + find_option => 'first', + get_option => 'get', + join_options => 'join', + count_options => 'count', + has_options => 'count', + has_no_options => 'is_empty', + sorted_options => 'sort', + }, + ); + + no Moose; + 1; + +=head1 DESCRIPTION + +This trait provides native delegation methods for array references. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<ArrayRef>. + +=head1 PROVIDED METHODS + +=over 4 + +=item * B<count> + +Returns the number of elements in the array. + + $stuff = Stuff->new; + $stuff->options( [ "foo", "bar", "baz", "boo" ] ); + + print $stuff->count_options; # prints 4 + +This method does not accept any arguments. + +=item * B<is_empty> + +Returns a boolean value that is true when the array has no elements. + + $stuff->has_no_options ? die "No options!\n" : print "Good boy.\n"; + +This method does not accept any arguments. + +=item * B<elements> + +Returns all of the elements of the array as an array (not an array reference). + + my @option = $stuff->all_options; + print "@options\n"; # prints "foo bar baz boo" + +This method does not accept any arguments. + +=item * B<get($index)> + +Returns an element of the array by its index. You can also use negative index +numbers, just as with Perl's core array handling. + + my $option = $stuff->get_option(1); + print "$option\n"; # prints "bar" + +If the specified element does not exist, this will return C<undef>. + +This method accepts just one argument. + +=item * B<pop> + +Just like Perl's builtin C<pop>. + +This method does not accept any arguments. + +=item * B<push($value1, $value2, value3 ...)> + +Just like Perl's builtin C<push>. Returns the number of elements in the new +array. + +This method accepts any number of arguments. + +=item * B<shift> + +Just like Perl's builtin C<shift>. + +This method does not accept any arguments. + +=item * B<unshift($value1, $value2, value3 ...)> + +Just like Perl's builtin C<unshift>. Returns the number of elements in the new +array. + +This method accepts any number of arguments. + +=item * B<splice($offset, $length, @values)> + +Just like Perl's builtin C<splice>. In scalar context, this returns the last +element removed, or C<undef> if no elements were removed. In list context, +this returns all the elements removed from the array. + +This method requires at least one argument. + +=item * B<first( sub { ... } )> + +This method returns the first matching item in the array, just like +L<List::Util>'s C<first> function. The matching is done with a subroutine +reference you pass to this method. The subroutine will be called against each +element in the array until one matches or all elements have been checked. +Each list element will be available to the sub in C<$_>. + + my $found = $stuff->find_option( sub {/^b/} ); + print "$found\n"; # prints "bar" + +This method requires a single argument. + +=item * B<first_index( sub { ... } )> + +This method returns the index of the first matching item in the array, just +like L<List::MoreUtils>'s C<first_index> function. The matching is done with a +subroutine reference you pass to this method. The subroutine will be called +against each element in the array until one matches or all elements have been +checked. Each list element will be available to the sub in C<$_>. + +This method requires a single argument. + +=item * B<grep( sub { ... } )> + +This method returns every element matching a given criteria, just like Perl's +core C<grep> function. This method requires a subroutine which implements the +matching logic; each list element will be available to the sub in C<$_>. + + my @found = $stuff->filter_options( sub {/^b/} ); + print "@found\n"; # prints "bar baz boo" + +This method requires a single argument. + +=item * B<map( sub { ... } )> + +This method transforms every element in the array and returns a new array, +just like Perl's core C<map> function. This method requires a subroutine which +implements the transformation; each list element will be available to the sub +in C<$_>. + + my @mod_options = $stuff->map_options( sub { $_ . "-tag" } ); + print "@mod_options\n"; # prints "foo-tag bar-tag baz-tag boo-tag" + +This method requires a single argument. + +=item * B<reduce( sub { ... } )> + +This method turns an array into a single value, by passing a function the +value so far and the next value in the array, just like L<List::Util>'s +C<reduce> function. The reducing is done with a subroutine reference you pass +to this method; each list element will be available to the sub in C<$_>. + + my $found = $stuff->reduce_options( sub { $_[0] . $_[1] } ); + print "$found\n"; # prints "foobarbazboo" + +This method requires a single argument. + +=item * B<sort> + +=item * B<sort( sub { ... } )> + +Returns the elements of the array (not an array reference) in sorted order, +or, like C<elements>, returns the number of elements in the array in scalar context. + +You can provide an optional subroutine reference to sort with (as you can with +Perl's core C<sort> function). However, instead of using C<$a> and C<$b> in +this subroutine, you will need to use C<$_[0]> and C<$_[1]>. + + # ascending ASCIIbetical + my @sorted = $stuff->sort_options(); + + # Descending alphabetical order + my @sorted_options = $stuff->sort_options( sub { lc $_[1] cmp lc $_[0] } ); + print "@sorted_options\n"; # prints "foo boo baz bar" + +This method accepts a single argument. + +=item * B<sort_in_place> + +=item * B<sort_in_place( sub { ... } )> + +Sorts the array I<in place>, modifying the value of the attribute. + +You can provide an optional subroutine reference to sort with (as you can with +Perl's core C<sort> function). However, instead of using C<$a> and C<$b>, you +will need to use C<$_[0]> and C<$_[1]> instead. + +This method does not define a return value. + +This method accepts a single argument. + +=item * B<shuffle> + +Returns the elements of the array in random order, like C<shuffle> from +L<List::Util>. + +This method does not accept any arguments. + +=item * B<uniq> + +Returns the array with all duplicate elements removed, like C<uniq> from +L<List::MoreUtils>. + +This method does not accept any arguments. + +=item * B<join($str)> + +Joins every element of the array using the separator given as argument, just +like Perl's core C<join> function. + + my $joined = $stuff->join_options(':'); + print "$joined\n"; # prints "foo:bar:baz:boo" + +This method requires a single argument. + +=item * B<set($index, $value)> + +Given an index and a value, sets the specified array element's value. + +This method returns the value at C<$index> after the set. + +This method requires two arguments. + +=item * B<delete($index)> + +Removes the element at the given index from the array. + +This method returns the deleted value. Note that if no value exists, it will +return C<undef>. + +This method requires one argument. + +=item * B<insert($index, $value)> + +Inserts a new element into the array at the given index. + +This method returns the new value at C<$index>. + +This method requires two arguments. + +=item * B<clear> + +Empties the entire array, like C<@array = ()>. + +This method does not define a return value. + +This method does not accept any arguments. + +=item * B<accessor($index)> + +=item * B<accessor($index, $value)> + +This method provides a get/set accessor for the array, based on array indexes. +If passed one argument, it returns the value at the specified index. If +passed two arguments, it sets the value of the specified index. + +When called as a setter, this method returns the new value at C<$index>. + +This method accepts one or two arguments. + +=item * B<natatime($n)> + +=item * B<natatime($n, $code)> + +This method returns an iterator which, on each call, returns C<$n> more items +from the array, in order, like C<natatime> from L<List::MoreUtils>. + +If you pass a coderef as the second argument, then this code ref will be +called on each group of C<$n> elements in the array until the array is +exhausted. + +This method accepts one or two arguments. + +=item * B<shallow_clone> + +This method returns a shallow clone of the array reference. The return value +is a reference to a new array with the same elements. It is I<shallow> +because any elements that were references in the original will be the I<same> +references in the clone. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Bool.pm b/lib/Moose/Meta/Attribute/Native/Trait/Bool.pm new file mode 100644 index 0000000..d228d0b --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Bool.pm @@ -0,0 +1,146 @@ +package Moose::Meta::Attribute::Native::Trait::Bool; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'Bool' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for Bool attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Bool - Helper trait for Bool attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Room; + use Moose; + + has 'is_lit' => ( + traits => ['Bool'], + is => 'rw', + isa => 'Bool', + default => 0, + handles => { + illuminate => 'set', + darken => 'unset', + flip_switch => 'toggle', + is_dark => 'not', + }, + ); + + my $room = Room->new(); + $room->illuminate; # same as $room->is_lit(1); + $room->darken; # same as $room->is_lit(0); + $room->flip_switch; # same as $room->is_lit(not $room->is_lit); + return $room->is_dark; # same as !$room->is_lit + +=head1 DESCRIPTION + +This trait provides native delegation methods for boolean values. A boolean is +a scalar which can be C<1>, C<0>, C<"">, or C<undef>. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<Bool>. + +=head1 PROVIDED METHODS + +None of these methods accept arguments. + +=over 4 + +=item * B<set> + +Sets the value to C<1> and returns C<1>. + +=item * B<unset> + +Set the value to C<0> and returns C<0>. + +=item * B<toggle> + +Toggles the value. If it's true, set to false, and vice versa. + +Returns the new value. + +=item * B<not> + +Equivalent of 'not C<$value>'. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Code.pm b/lib/Moose/Meta/Attribute/Native/Trait/Code.pm new file mode 100644 index 0000000..a0b90b3 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Code.pm @@ -0,0 +1,129 @@ +package Moose::Meta::Attribute::Native::Trait::Code; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'CodeRef' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for CodeRef attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Code - Helper trait for CodeRef attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Foo; + use Moose; + + has 'callback' => ( + traits => ['Code'], + is => 'ro', + isa => 'CodeRef', + default => sub { + sub { print "called" } + }, + handles => { + call => 'execute', + }, + ); + + my $foo = Foo->new; + $foo->call; # prints "called" + +=head1 DESCRIPTION + +This trait provides native delegation methods for code references. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<CodeRef>. + +=head1 PROVIDED METHODS + +=over 4 + +=item * B<execute(@args)> + +Calls the coderef with the given args. + +=item * B<execute_method(@args)> + +Calls the coderef with the instance as invocant and given args. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Counter.pm b/lib/Moose/Meta/Attribute/Native/Trait/Counter.pm new file mode 100644 index 0000000..2677f88 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Counter.pm @@ -0,0 +1,157 @@ +package Moose::Meta::Attribute::Native::Trait::Counter; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'Num' } +sub _root_types { 'Num', 'Int' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for Int attributes which represent counters + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Counter - Helper trait for Int attributes which represent counters + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyHomePage; + use Moose; + + has 'counter' => ( + traits => ['Counter'], + is => 'ro', + isa => 'Num', + default => 0, + handles => { + inc_counter => 'inc', + dec_counter => 'dec', + reset_counter => 'reset', + }, + ); + + my $page = MyHomePage->new(); + $page->inc_counter; # same as $page->counter( $page->counter + 1 ); + $page->dec_counter; # same as $page->counter( $page->counter - 1 ); + + my $count_by_twos = 2; + $page->inc_counter($count_by_twos); + +=head1 DESCRIPTION + +This trait provides native delegation methods for counters. A counter can be +any sort of number (integer or not). The delegation methods allow you to +increment, decrement, or reset the value. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<Num>. + +=head1 PROVIDED METHODS + +=over 4 + +=item * B<set($value)> + +Sets the counter to the specified value and returns the new value. + +This method requires a single argument. + +=item * B<inc> + +=item * B<inc($arg)> + +Increases the attribute value by the amount of the argument, or by 1 if no +argument is given. This method returns the new value. + +This method accepts a single argument. + +=item * B<dec> + +=item * B<dec($arg)> + +Decreases the attribute value by the amount of the argument, or by 1 if no +argument is given. This method returns the new value. + +This method accepts a single argument. + +=item * B<reset> + +Resets the value stored in this slot to its default value, and returns the new +value. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Hash.pm b/lib/Moose/Meta/Attribute/Native/Trait/Hash.pm new file mode 100644 index 0000000..25fbc6b --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Hash.pm @@ -0,0 +1,226 @@ +package Moose::Meta::Attribute::Native::Trait::Hash; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'HashRef' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for HashRef attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Hash - Helper trait for HashRef attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Stuff; + use Moose; + + has 'options' => ( + traits => ['Hash'], + is => 'ro', + isa => 'HashRef[Str]', + default => sub { {} }, + handles => { + set_option => 'set', + get_option => 'get', + has_no_options => 'is_empty', + num_options => 'count', + delete_option => 'delete', + option_pairs => 'kv', + }, + ); + +=head1 DESCRIPTION + +This trait provides native delegation methods for hash references. + +=head1 PROVIDED METHODS + +=over 4 + +=item B<get($key, $key2, $key3...)> + +Returns values from the hash. + +In list context it returns a list of values in the hash for the given keys. In +scalar context it returns the value for the last key specified. + +This method requires at least one argument. + +=item B<set($key =E<gt> $value, $key2 =E<gt> $value2...)> + +Sets the elements in the hash to the given values. It returns the new values +set for each key, in the same order as the keys passed to the method. + +This method requires at least two arguments, and expects an even number of +arguments. + +=item B<delete($key, $key2, $key3...)> + +Removes the elements with the given keys. + +In list context it returns a list of values in the hash for the deleted +keys. In scalar context it returns the value for the last key specified. + +=item B<keys> + +Returns the list of keys in the hash. + +This method does not accept any arguments. + +=item B<exists($key)> + +Returns true if the given key is present in the hash. + +This method requires a single argument. + +=item B<defined($key)> + +Returns true if the value of a given key is defined. + +This method requires a single argument. + +=item B<values> + +Returns the list of values in the hash. + +This method does not accept any arguments. + +=item B<kv> + +Returns the key/value pairs in the hash as an array of array references. + + for my $pair ( $object->option_pairs ) { + print "$pair->[0] = $pair->[1]\n"; + } + +This method does not accept any arguments. + +=item B<elements> + +Returns the key/value pairs in the hash as a flattened list.. + +This method does not accept any arguments. + +=item B<clear> + +Resets the hash to an empty value, like C<%hash = ()>. + +This method does not accept any arguments. + +=item B<count> + +Returns the number of elements in the hash. Also useful to check for a nonempty hash, because C<count> returns a true (nonzero) value if there is something in the hash: +C<< has_options => 'count' >>. + +This method does not accept any arguments. + +=item B<is_empty> + +If the hash is populated, returns false. Otherwise, returns true. + +This method does not accept any arguments. + +=item B<accessor($key)> + +=item B<accessor($key, $value)> + +If passed one argument, returns the value of the specified key. If passed two +arguments, sets the value of the specified key. + +When called as a setter, this method returns the value that was set. + +=item B<shallow_clone> + +This method returns a shallow clone of the hash reference. The return value +is a reference to a new hash with the same keys and values. It is I<shallow> +because any values that were references in the original will be the I<same> +references in the clone. + +=back + +Note that C<each> is deliberately omitted, due to its stateful interaction +with the hash iterator. C<keys> or C<kv> are much safer. + +=head1 METHODS + +=over 4 + +=item B<meta> + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/Number.pm b/lib/Moose/Meta/Attribute/Native/Trait/Number.pm new file mode 100644 index 0000000..4851246 --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/Number.pm @@ -0,0 +1,155 @@ +package Moose::Meta::Attribute::Native::Trait::Number; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'Num' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for Num attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::Number - Helper trait for Num attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Real; + use Moose; + + has 'integer' => ( + traits => ['Number'], + is => 'ro', + isa => 'Num', + default => 5, + handles => { + set => 'set', + add => 'add', + sub => 'sub', + mul => 'mul', + div => 'div', + mod => 'mod', + abs => 'abs', + }, + ); + + my $real = Real->new(); + $real->add(5); # same as $real->integer($real->integer + 5); + $real->sub(2); # same as $real->integer($real->integer - 2); + +=head1 DESCRIPTION + +This trait provides native delegation methods for numbers. All of the +operations correspond to arithmetic operations like addition or +multiplication. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<Num>. + +=head1 PROVIDED METHODS + +All of these methods modify the attribute's value in place. All methods return +the new value. + +=over 4 + +=item * B<add($value)> + +Adds the current value of the attribute to C<$value>. + +=item * B<sub($value)> + +Subtracts C<$value> from the current value of the attribute. + +=item * B<mul($value)> + +Multiplies the current value of the attribute by C<$value>. + +=item * B<div($value)> + +Divides the current value of the attribute by C<$value>. + +=item * B<mod($value)> + +Returns the current value of the attribute modulo C<$value>. + +=item * B<abs> + +Sets the current value of the attribute to its absolute value. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Attribute/Native/Trait/String.pm b/lib/Moose/Meta/Attribute/Native/Trait/String.pm new file mode 100644 index 0000000..c919f3a --- /dev/null +++ b/lib/Moose/Meta/Attribute/Native/Trait/String.pm @@ -0,0 +1,187 @@ +package Moose::Meta::Attribute::Native::Trait::String; +our $VERSION = '2.1405'; + +use Moose::Role; +with 'Moose::Meta::Attribute::Native::Trait'; + +sub _helper_type { 'Str' } + +no Moose::Role; + +1; + +# ABSTRACT: Helper trait for Str attributes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Attribute::Native::Trait::String - Helper trait for Str attributes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyHomePage; + use Moose; + + has 'text' => ( + traits => ['String'], + is => 'rw', + isa => 'Str', + default => q{}, + handles => { + add_text => 'append', + replace_text => 'replace', + }, + ); + + my $page = MyHomePage->new(); + $page->add_text("foo"); # same as $page->text($page->text . "foo"); + +=head1 DESCRIPTION + +This trait provides native delegation methods for strings. + +=head1 DEFAULT TYPE + +If you don't provide an C<isa> value for your attribute, it will default to +C<Str>. + +=head1 PROVIDED METHODS + +=over 4 + +=item * B<inc> + +Increments the value stored in this slot using the magical string autoincrement +operator. Note that Perl doesn't provide analogous behavior in C<-->, so +C<dec> is not available. This method returns the new value. + +This method does not accept any arguments. + +=item * B<append($string)> + +Appends to the string, like C<.=>, and returns the new value. + +This method requires a single argument. + +=item * B<prepend($string)> + +Prepends to the string and returns the new value. + +This method requires a single argument. + +=item * B<replace($pattern, $replacement)> + +Performs a regexp substitution (L<perlop/s>). There is no way to provide the +C<g> flag, but code references will be accepted for the replacement, causing +the regex to be modified with a single C<e>. C</smxi> can be applied using the +C<qr> operator. This method returns the new value. + +This method requires two arguments. + +=item * B<match($pattern)> + +Runs the regex against the string and returns the matching value(s). + +This method requires a single argument. + +=item * B<chop> + +Just like L<perlfunc/chop>. This method returns the chopped character. + +This method does not accept any arguments. + +=item * B<chomp> + +Just like L<perlfunc/chomp>. This method returns the number of characters +removed. + +This method does not accept any arguments. + +=item * B<clear> + +Sets the string to the empty string (not the value passed to C<default>). + +This method does not have a defined return value. + +This method does not accept any arguments. + +=item * B<length> + +Just like L<perlfunc/length>, returns the length of the string. + +=item * B<substr> + +This acts just like L<perlfunc/substr>. When called as a writer, it returns +the substring that was replaced, just like the Perl builtin. + +This method requires at least one argument, and accepts no more than three. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Class.pm b/lib/Moose/Meta/Class.pm new file mode 100644 index 0000000..fafd2c5 --- /dev/null +++ b/lib/Moose/Meta/Class.pm @@ -0,0 +1,1002 @@ +package Moose::Meta::Class; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP; +use Data::OptList; +use List::Util 1.33 qw( any first ); +use List::MoreUtils qw( uniq first_index ); +use Scalar::Util 'blessed'; + +use Moose::Meta::Method::Overridden; +use Moose::Meta::Method::Augmented; +use Moose::Meta::Class::Immutable::Trait; +use Moose::Meta::Method::Constructor; +use Moose::Meta::Method::Destructor; +use Moose::Meta::Method::Meta; +use Moose::Util 'throw_exception'; +use Class::MOP::MiniTrait; + +use parent 'Class::MOP::Class'; + +Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait'); + +__PACKAGE__->meta->add_attribute('roles' => ( + reader => 'roles', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('role_applications' => ( + reader => '_get_role_applications', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute( + Class::MOP::Attribute->new('immutable_trait' => ( + accessor => "immutable_trait", + default => 'Moose::Meta::Class::Immutable::Trait', + Class::MOP::_definition_context(), + )) +); + +__PACKAGE__->meta->add_attribute('constructor_class' => ( + accessor => 'constructor_class', + default => 'Moose::Meta::Method::Constructor', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('destructor_class' => ( + accessor => 'destructor_class', + default => 'Moose::Meta::Method::Destructor', + Class::MOP::_definition_context(), +)); + +sub initialize { + my $class = shift; + my @args = @_; + unshift @args, 'package' if @args % 2; + my %opts = @args; + my $package = delete $opts{package}; + return Class::MOP::get_metaclass_by_name($package) + || $class->SUPER::initialize($package, + 'attribute_metaclass' => 'Moose::Meta::Attribute', + 'method_metaclass' => 'Moose::Meta::Method', + 'instance_metaclass' => 'Moose::Meta::Instance', + %opts, + ); +} + +sub create { + my $class = shift; + my @args = @_; + + unshift @args, 'package' if @args % 2 == 1; + my %options = @args; + + (ref $options{roles} eq 'ARRAY') + || throw_exception( RolesInCreateTakesAnArrayRef => params => \%options ) + if exists $options{roles}; + + my $package = delete $options{package}; + my $roles = delete $options{roles}; + + my $new_meta = $class->SUPER::create($package, %options); + + if ($roles) { + Moose::Util::apply_all_roles( $new_meta, @$roles ); + } + + return $new_meta; +} + +sub _meta_method_class { 'Moose::Meta::Method::Meta' } + +sub _anon_package_prefix { 'Moose::Meta::Class::__ANON__::SERIAL::' } + +sub _anon_cache_key { + my $class = shift; + my %options = @_; + + my $superclass_key = join('|', + map { $_->[0] } @{ Data::OptList::mkopt($options{superclasses} || []) } + ); + + my $roles = Data::OptList::mkopt(($options{roles} || []), { + moniker => 'role', + val_test => sub { ref($_[0]) eq 'HASH' }, + }); + + my @role_keys; + for my $role_spec (@$roles) { + my ($role, $params) = @$role_spec; + $params = { %$params } if $params; + + my $key = blessed($role) ? $role->name : $role; + + if ($params && %$params) { + my $alias = delete $params->{'-alias'} + || delete $params->{'alias'} + || {}; + my $excludes = delete $params->{'-excludes'} + || delete $params->{'excludes'} + || []; + $excludes = [$excludes] unless ref($excludes) eq 'ARRAY'; + + if (%$params) { + warn "Roles with parameters cannot be cached. Consider " + . "applying the parameters before calling " + . "create_anon_class, or using 'weaken => 0' instead"; + return; + } + + my $alias_key = join('%', + map { $_ => $alias->{$_} } sort keys %$alias + ); + my $excludes_key = join('%', + sort @$excludes + ); + $key .= '<' . join('+', 'a', $alias_key, 'e', $excludes_key) . '>'; + } + + push @role_keys, $key; + } + + my $role_key = join('|', sort @role_keys); + + # Makes something like Super::Class|Super::Class::2=Role|Role::1 + return join('=', $superclass_key, $role_key); +} + +sub reinitialize { + my $self = shift; + my $pkg = shift; + + my $meta = blessed $pkg ? $pkg : Class::MOP::class_of($pkg); + + my %existing_classes; + if ($meta) { + %existing_classes = map { $_ => $meta->$_() } qw( + attribute_metaclass + method_metaclass + wrapped_method_metaclass + instance_metaclass + constructor_class + destructor_class + ); + } + + return $self->SUPER::reinitialize( + $pkg, + %existing_classes, + @_, + ); +} + +sub add_role { + my ($self, $role) = @_; + (blessed($role) && $role->isa('Moose::Meta::Role')) + || throw_exception( AddRoleTakesAMooseMetaRoleInstance => role_to_be_added => $role, + class_name => $self->name, + ); + push @{$self->roles} => $role; +} + +sub role_applications { + my ($self) = @_; + + return @{$self->_get_role_applications}; +} + +sub add_role_application { + my ($self, $application) = @_; + + (blessed($application) && $application->isa('Moose::Meta::Role::Application::ToClass')) + || throw_exception( InvalidRoleApplication => class_name => $self->name, + application => $application, + ); + + push @{$self->_get_role_applications} => $application; +} + +sub calculate_all_roles { + my $self = shift; + my %seen; + grep { !$seen{$_->name}++ } map { $_->calculate_all_roles } @{ $self->roles }; +} + +sub _roles_with_inheritance { + my $self = shift; + my %seen; + grep { !$seen{$_->name}++ } + map { Class::MOP::class_of($_)->can('roles') + ? @{ Class::MOP::class_of($_)->roles } + : () } + $self->linearized_isa; +} + +sub calculate_all_roles_with_inheritance { + my $self = shift; + my %seen; + grep { !$seen{$_->name}++ } + map { Class::MOP::class_of($_)->can('calculate_all_roles') + ? Class::MOP::class_of($_)->calculate_all_roles + : () } + $self->linearized_isa; +} + +sub does_role { + my ($self, $role_name) = @_; + + (defined $role_name) + || throw_exception( RoleNameRequired => class_name => $self->name ); + + foreach my $class ($self->class_precedence_list) { + my $meta = Class::MOP::class_of($class); + # when a Moose metaclass is itself extended with a role, + # this check needs to be done since some items in the + # class_precedence_list might in fact be Class::MOP + # based still. + next unless $meta && $meta->can('roles'); + foreach my $role (@{$meta->roles}) { + return 1 if $role->does_role($role_name); + } + } + return 0; +} + +sub excludes_role { + my ($self, $role_name) = @_; + + (defined $role_name) + || throw_exception( RoleNameRequired => class_name => $self->name ); + + foreach my $class ($self->class_precedence_list) { + my $meta = Class::MOP::class_of($class); + # when a Moose metaclass is itself extended with a role, + # this check needs to be done since some items in the + # class_precedence_list might in fact be Class::MOP + # based still. + next unless $meta && $meta->can('roles'); + foreach my $role (@{$meta->roles}) { + return 1 if $role->excludes_role($role_name); + } + } + return 0; +} + +sub new_object { + my $self = shift; + my $params = @_ == 1 ? $_[0] : {@_}; + my $object = $self->SUPER::new_object($params); + + $self->_call_all_triggers($object, $params); + + $object->BUILDALL($params) if $object->can('BUILDALL'); + + return $object; +} + +sub _call_all_triggers { + my ($self, $object, $params) = @_; + + foreach my $attr ( $self->get_all_attributes() ) { + + next unless $attr->can('has_trigger') && $attr->has_trigger; + + my $init_arg = $attr->init_arg; + next unless defined $init_arg; + next unless exists $params->{$init_arg}; + + $attr->trigger->( + $object, + ( + $attr->should_coerce + ? $attr->get_read_method_ref->($object) + : $params->{$init_arg} + ), + ); + } +} + +sub _generate_fallback_constructor { + my $self = shift; + my ($class) = @_; + return $class . '->Moose::Object::new(@_)' +} + +sub _inline_params { + my $self = shift; + my ($params, $class) = @_; + return ( + 'my ' . $params . ' = ', + $self->_inline_BUILDARGS($class, '@_'), + ';', + ); +} + +sub _inline_BUILDARGS { + my $self = shift; + my ($class, $args) = @_; + + my $buildargs = $self->find_method_by_name("BUILDARGS"); + + if ($args eq '@_' + && (!$buildargs or $buildargs->body == \&Moose::Object::BUILDARGS)) { + return ( + 'do {', + 'my $params;', + 'if (scalar @_ == 1) {', + 'if (!defined($_[0]) || ref($_[0]) ne \'HASH\') {', + $self->_inline_throw_exception( + 'SingleParamsToNewMustBeHashRef' + ) . ';', + '}', + '$params = { %{ $_[0] } };', + '}', + 'elsif (@_ % 2) {', + 'Carp::carp(', + '"The new() method for ' . $class . ' expects a ' + . 'hash reference or a key/value list. You passed an ' + . 'odd number of arguments"', + ');', + '$params = {@_, undef};', + '}', + 'else {', + '$params = {@_};', + '}', + '$params;', + '}', + ); + } + else { + return $class . '->BUILDARGS(' . $args . ')'; + } +} + +sub _inline_slot_initializer { + my $self = shift; + my ($attr, $idx) = @_; + + return ( + '## ' . $attr->name, + $self->_inline_check_required_attr($attr), + $self->SUPER::_inline_slot_initializer(@_), + ); +} + +sub _inline_check_required_attr { + my $self = shift; + my ($attr) = @_; + + return unless defined $attr->init_arg; + return unless $attr->can('is_required') && $attr->is_required; + return if $attr->has_default || $attr->has_builder; + + return ( + 'if (!exists $params->{\'' . $attr->init_arg . '\'}) {', + $self->_inline_throw_exception( + AttributeIsRequired => + 'params => $params, '. + 'class_name => $class_name, '. + 'attribute_name => "'.quotemeta($attr->name).'"' + ).';', + '}', + ); +} + +# XXX: these two are duplicated from cmop, because we have to pass the tc stuff +# through to _inline_set_value - this should probably be fixed, but i'm not +# quite sure how. -doy +sub _inline_init_attr_from_constructor { + my $self = shift; + my ($attr, $idx) = @_; + + my @initial_value = $attr->_inline_set_value( + '$instance', + '$params->{\'' . $attr->init_arg . '\'}', + '$type_constraint_bodies[' . $idx . ']', + '$type_coercions[' . $idx . ']', + '$type_constraint_messages[' . $idx . ']', + 'for constructor', + ); + + push @initial_value, ( + '$attrs->[' . $idx . ']->set_initial_value(', + '$instance,', + $attr->_inline_instance_get('$instance'), + ');', + ) if $attr->has_initializer; + + return @initial_value; +} + +sub _inline_init_attr_from_default { + my $self = shift; + my ($attr, $idx) = @_; + + return if $attr->can('is_lazy') && $attr->is_lazy; + my $default = $self->_inline_default_value($attr, $idx); + return unless $default; + + my @initial_value = ( + 'my $default = ' . $default . ';', + $attr->_inline_set_value( + '$instance', + '$default', + '$type_constraint_bodies[' . $idx . ']', + '$type_coercions[' . $idx . ']', + '$type_constraint_messages[' . $idx . ']', + 'for constructor', + ), + ); + + push @initial_value, ( + '$attrs->[' . $idx . ']->set_initial_value(', + '$instance,', + $attr->_inline_instance_get('$instance'), + ');', + ) if $attr->has_initializer; + + return @initial_value; +} + +sub _inline_extra_init { + my $self = shift; + return ( + $self->_inline_triggers, + $self->_inline_BUILDALL, + ); +} + +sub _inline_triggers { + my $self = shift; + my @trigger_calls; + + my @attrs = sort { $a->name cmp $b->name } $self->get_all_attributes; + for my $i (0 .. $#attrs) { + my $attr = $attrs[$i]; + + next unless $attr->can('has_trigger') && $attr->has_trigger; + + my $init_arg = $attr->init_arg; + next unless defined $init_arg; + + push @trigger_calls, + 'if (exists $params->{\'' . $init_arg . '\'}) {', + '$triggers->[' . $i . ']->(', + '$instance,', + $attr->_inline_instance_get('$instance') . ',', + ');', + '}'; + } + + return @trigger_calls; +} + +sub _inline_BUILDALL { + my $self = shift; + + my @methods = reverse $self->find_all_methods_by_name('BUILD'); + my @BUILD_calls; + + foreach my $method (@methods) { + push @BUILD_calls, + '$instance->' . $method->{class} . '::BUILD($params);'; + } + + return @BUILD_calls; +} + +sub _eval_environment { + my $self = shift; + + my @attrs = sort { $a->name cmp $b->name } $self->get_all_attributes; + + my $triggers = [ + map { $_->can('has_trigger') && $_->has_trigger ? $_->trigger : undef } + @attrs + ]; + + # We need to check if the attribute ->can('type_constraint') + # since we may be trying to immutabilize a Moose meta class, + # which in turn has attributes which are Class::MOP::Attribute + # objects, rather than Moose::Meta::Attribute. And + # Class::MOP::Attribute attributes have no type constraints. + # However we need to make sure we leave an undef value there + # because the inlined code is using the index of the attributes + # to determine where to find the type constraint + + my @type_constraints = map { + $_->can('type_constraint') ? $_->type_constraint : undef + } @attrs; + + my @type_constraint_bodies = map { + defined $_ ? $_->_compiled_type_constraint : undef; + } @type_constraints; + + my @type_coercions = map { + defined $_ && $_->has_coercion + ? $_->coercion->_compiled_type_coercion + : undef + } @type_constraints; + + my @type_constraint_messages = map { + defined $_ + ? ($_->has_message ? $_->message : $_->_default_message) + : undef + } @type_constraints; + + return { + %{ $self->SUPER::_eval_environment }, + ((any { defined && $_->has_initializer } @attrs) + ? ('$attrs' => \[@attrs]) + : ()), + '$triggers' => \$triggers, + '@type_coercions' => \@type_coercions, + '@type_constraint_bodies' => \@type_constraint_bodies, + '@type_constraint_messages' => \@type_constraint_messages, + ( map { defined($_) ? %{ $_->inline_environment } : () } + @type_constraints ), + # pretty sure this is only going to be closed over if you use a custom + # error class at this point, but we should still get rid of this + # at some point + '$meta' => \$self, + '$class_name' => \($self->name), + }; +} + +sub superclasses { + my $self = shift; + my $supers = Data::OptList::mkopt(\@_); + foreach my $super (@{ $supers }) { + my ($name, $opts) = @{ $super }; + Moose::Util::_load_user_class($name, $opts); + my $meta = Class::MOP::class_of($name); + throw_exception( CanExtendOnlyClasses => role_name => $meta->name ) + if $meta && $meta->isa('Moose::Meta::Role') + } + return $self->SUPER::superclasses(map { $_->[0] } @{ $supers }); +} + +### --------------------------------------------- + +sub add_attribute { + my $self = shift; + my $attr = + (blessed $_[0] && $_[0]->isa('Class::MOP::Attribute') + ? $_[0] + : $self->_process_attribute(@_)); + $self->SUPER::add_attribute($attr); + # it may be a Class::MOP::Attribute, theoretically, which doesn't have + # 'bare' and doesn't implement this method + if ($attr->can('_check_associated_methods')) { + $attr->_check_associated_methods; + } + return $attr; +} + +sub add_override_method_modifier { + my ($self, $name, $method, $_super_package) = @_; + + my $existing_method = $self->get_method($name); + (!$existing_method) + || throw_exception( CannotOverrideLocalMethodIsPresent => class_name => $self->name, + method => $existing_method, + ); + $self->add_method($name => Moose::Meta::Method::Overridden->new( + method => $method, + class => $self, + package => $_super_package, # need this for roles + name => $name, + )); +} + +sub add_augment_method_modifier { + my ($self, $name, $method) = @_; + my $existing_method = $self->get_method($name); + throw_exception( CannotAugmentIfLocalMethodPresent => class_name => $self->name, + method => $existing_method, + ) + if( $existing_method ); + + $self->add_method($name => Moose::Meta::Method::Augmented->new( + method => $method, + class => $self, + name => $name, + )); +} + +## Private Utility methods ... + +sub _find_next_method_by_name_which_is_not_overridden { + my ($self, $name) = @_; + foreach my $method ($self->find_all_methods_by_name($name)) { + return $method->{code} + if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overridden'); + } + return undef; +} + +## Metaclass compatibility + +sub _base_metaclasses { + my $self = shift; + my %metaclasses = $self->SUPER::_base_metaclasses; + for my $class (keys %metaclasses) { + $metaclasses{$class} =~ s/^Class::MOP/Moose::Meta/; + } + return ( + %metaclasses, + ); +} + +sub _fix_class_metaclass_incompatibility { + my $self = shift; + my ($super_meta) = @_; + + $self->SUPER::_fix_class_metaclass_incompatibility(@_); + + if ($self->_class_metaclass_can_be_made_compatible($super_meta)) { + ($self->is_pristine) + || throw_exception( CannotFixMetaclassCompatibility => class => $self, + superclass => $super_meta + ); + my $super_meta_name = $super_meta->_real_ref_name; + my $class_meta_subclass_meta_name = Moose::Util::_reconcile_roles_for_metaclass(blessed($self), $super_meta_name); + my $new_self = $class_meta_subclass_meta_name->reinitialize( + $self->name, + ); + + $self->_replace_self( $new_self, $class_meta_subclass_meta_name ); + } +} + +sub _fix_single_metaclass_incompatibility { + my $self = shift; + my ($metaclass_type, $super_meta) = @_; + + $self->SUPER::_fix_single_metaclass_incompatibility(@_); + + if ($self->_single_metaclass_can_be_made_compatible($super_meta, $metaclass_type)) { + ($self->is_pristine) + || throw_exception( CannotFixMetaclassCompatibility => class => $self, + superclass => $super_meta, + metaclass_type => $metaclass_type + ); + my $super_meta_name = $super_meta->_real_ref_name; + my $class_specific_meta_subclass_meta_name = Moose::Util::_reconcile_roles_for_metaclass($self->$metaclass_type, $super_meta->$metaclass_type); + my $new_self = $super_meta->reinitialize( + $self->name, + $metaclass_type => $class_specific_meta_subclass_meta_name, + ); + + $self->_replace_self( $new_self, $super_meta_name ); + } +} + +sub _replace_self { + my $self = shift; + my ( $new_self, $new_class) = @_; + + %$self = %$new_self; + bless $self, $new_class; + + # We need to replace the cached metaclass instance or else when it goes + # out of scope Class::MOP::Class destroy's the namespace for the + # metaclass's class, causing much havoc. + my $weaken = Class::MOP::metaclass_is_weak( $self->name ); + Class::MOP::store_metaclass_by_name( $self->name, $self ); + Class::MOP::weaken_metaclass( $self->name ) if $weaken; +} + +sub _process_attribute { + my ( $self, $name, @args ) = @_; + + @args = %{$args[0]} if scalar @args == 1 && ref($args[0]) eq 'HASH'; + + if (($name || '') =~ /^\+(.*)/) { + return $self->_process_inherited_attribute($1, @args); + } + else { + return $self->_process_new_attribute($name, @args); + } +} + +sub _process_new_attribute { + my ( $self, $name, @args ) = @_; + + $self->attribute_metaclass->interpolate_class_and_new($name, @args); +} + +sub _process_inherited_attribute { + my ($self, $attr_name, %options) = @_; + + my $inherited_attr = $self->find_attribute_by_name($attr_name); + (defined $inherited_attr) + || throw_exception( NoAttributeFoundInSuperClass => class_name => $self->name, + attribute_name => $attr_name, + params => \%options + ); + if ($inherited_attr->isa('Moose::Meta::Attribute')) { + return $inherited_attr->clone_and_inherit_options(%options); + } + else { + # NOTE: + # kind of a kludge to handle Class::MOP::Attributes + return $inherited_attr->Moose::Meta::Attribute::clone_and_inherit_options(%options); + } +} + +# reinitialization support + +sub _restore_metaobjects_from { + my $self = shift; + my ($old_meta) = @_; + + $self->SUPER::_restore_metaobjects_from($old_meta); + + for my $role ( @{ $old_meta->roles } ) { + $self->add_role($role); + } + + for my $application ( @{ $old_meta->_get_role_applications } ) { + $application->class($self); + $self->add_role_application ($application); + } +} + +## Immutability + +sub _immutable_options { + my ( $self, @args ) = @_; + + $self->SUPER::_immutable_options( + inline_destructor => 1, + + # Moose always does this when an attribute is created + inline_accessors => 0, + + @args, + ); +} + +sub _fixup_attributes_after_rebless { + my $self = shift; + my ($instance, $rebless_from, %params) = @_; + + $self->SUPER::_fixup_attributes_after_rebless( + $instance, + $rebless_from, + %params + ); + + $self->_call_all_triggers( $instance, \%params ); +} + +## ------------------------------------------------- + +our $error_level; + +sub _inline_throw_exception { + my ( $self, $exception_type, $throw_args ) = @_; + return 'die Module::Runtime::use_module("Moose::Exception::' . $exception_type . '")->new(' . ($throw_args || '') . ')'; +} + +1; + +# ABSTRACT: The Moose metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Class - The Moose metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Class> that provides +additional Moose-specific functionality. + +To really understand this class, you will need to start with the +L<Class::MOP::Class> documentation. This class can be understood as a +set of additional features on top of the basic feature provided by +that parent class. + +=head1 INHERITANCE + +C<Moose::Meta::Class> is a subclass of L<Class::MOP::Class>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Class->initialize($package_name, %options) >> + +This overrides the parent's method in order to provide its own +defaults for the C<attribute_metaclass>, C<instance_metaclass>, and +C<method_metaclass> options. + +These all default to the appropriate Moose class. + +=item B<< Moose::Meta::Class->create($package_name, %options) >> + +This overrides the parent's method in order to accept a C<roles> +option. This should be an array reference containing roles +that the class does, each optionally followed by a hashref of options +(C<-excludes> and C<-alias>). + + my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] ); + +=item B<< Moose::Meta::Class->create_anon_class >> + +This overrides the parent's method to accept a C<roles> option, just +as C<create> does. + +It also accepts a C<cache> option. If this is C<true>, then the anonymous +class will be cached based on its superclasses and roles. If an +existing anonymous class in the cache has the same superclasses and +roles, it will be reused. + + my $metaclass = Moose::Meta::Class->create_anon_class( + superclasses => ['Foo'], + roles => [qw/Some Roles Go Here/], + cache => 1, + ); + +Each entry in both the C<superclasses> and the C<roles> option can be +followed by a hash reference with arguments. The C<superclasses> +option can be supplied with a L<-version|Class::MOP/Class Loading +Options> option that ensures the loaded superclass satisfies the +required version. The C<role> option also takes the C<-version> as an +argument, but the option hash reference can also contain any other +role relevant values like exclusions or parameterized role arguments. + +=item B<< $metaclass->new_object(%params) >> + +This overrides the parent's method in order to add support for +attribute triggers. + +=item B<< $metaclass->superclasses(@superclasses) >> + +This is the accessor allowing you to read or change the parents of +the class. + +Each superclass can be followed by a hash reference containing a +L<-version|Class::MOP/Class Loading Options> value. If the version +requirement is not satisfied an error will be thrown. + +When you pass classes to this method, we will attempt to load them if they are +not already loaded. + +=item B<< $metaclass->add_override_method_modifier($name, $sub) >> + +This adds an C<override> method modifier to the package. + +=item B<< $metaclass->add_augment_method_modifier($name, $sub) >> + +This adds an C<augment> method modifier to the package. + +=item B<< $metaclass->calculate_all_roles >> + +This will return a unique array of L<Moose::Meta::Role> instances +which are attached to this class. + +=item B<< $metaclass->calculate_all_roles_with_inheritance >> + +This will return a unique array of L<Moose::Meta::Role> instances +which are attached to this class, and each of this class's ancestors. + +=item B<< $metaclass->add_role($role) >> + +This takes a L<Moose::Meta::Role> object, and adds it to the class's +list of roles. This I<does not> actually apply the role to the class. + +=item B<< $metaclass->role_applications >> + +Returns a list of L<Moose::Meta::Role::Application::ToClass> +objects, which contain the arguments to role application. + +=item B<< $metaclass->add_role_application($application) >> + +This takes a L<Moose::Meta::Role::Application::ToClass> object, and +adds it to the class's list of role applications. This I<does not> +actually apply any role to the class; it is only for tracking role +applications. + +=item B<< $metaclass->does_role($role) >> + +This returns a boolean indicating whether or not the class does the specified +role. The role provided can be either a role name or a L<Moose::Meta::Role> +object. This tests both the class and its parents. + +=item B<< $metaclass->excludes_role($role_name) >> + +A class excludes a role if it has already composed a role which +excludes the named role. This tests both the class and its parents. + +=item B<< $metaclass->add_attribute($attr_name, %params|$params) >> + +This overrides the parent's method in order to allow the parameters to +be provided as a hash reference. + +=item B<< $metaclass->constructor_class($class_name) >> + +=item B<< $metaclass->destructor_class($class_name) >> + +These are the names of classes used when making a class immutable. These +default to L<Moose::Meta::Method::Constructor> and +L<Moose::Meta::Method::Destructor> respectively. These accessors are +read-write, so you can use them to change the class name. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Class/Immutable/Trait.pm b/lib/Moose/Meta/Class/Immutable/Trait.pm new file mode 100644 index 0000000..8dba57a --- /dev/null +++ b/lib/Moose/Meta/Class/Immutable/Trait.pm @@ -0,0 +1,123 @@ +package Moose::Meta::Class::Immutable::Trait; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP; +use Scalar::Util qw( blessed ); + +use parent 'Class::MOP::Class::Immutable::Trait'; + +use Moose::Util 'throw_exception'; + +sub add_role { $_[1]->_immutable_cannot_call } + +sub calculate_all_roles { + my $orig = shift; + my $self = shift; + @{ $self->{__immutable}{calculate_all_roles} ||= [ $self->$orig ] }; +} + +sub calculate_all_roles_with_inheritance { + my $orig = shift; + my $self = shift; + @{ $self->{__immutable}{calculate_all_roles_with_inheritance} ||= [ $self->$orig ] }; +} + +sub does_role { + shift; + my $self = shift; + my $role = shift; + + (defined $role) + || throw_exception( RoleNameRequired => class_name => $self->name ); + + $self->{__immutable}{does_role} ||= { map { $_->name => 1 } $self->calculate_all_roles_with_inheritance }; + + my $name = blessed $role ? $role->name : $role; + + return $self->{__immutable}{does_role}{$name}; +} + +1; + +# ABSTRACT: Implements immutability for metaclass objects + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Class::Immutable::Trait - Implements immutability for metaclass objects + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class makes some Moose-specific metaclass methods immutable. This +is deep guts. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Instance.pm b/lib/Moose/Meta/Instance.pm new file mode 100644 index 0000000..ee412b4 --- /dev/null +++ b/lib/Moose/Meta/Instance.pm @@ -0,0 +1,109 @@ +package Moose::Meta::Instance; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP::MiniTrait; + +use parent 'Class::MOP::Instance'; + +Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait'); + +1; + +# ABSTRACT: The Moose Instance metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Instance - The Moose Instance metaclass + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + # nothing to see here + +=head1 DESCRIPTION + +This class provides the low level data storage abstractions for +attributes. + +Using this API directly in your own code violates encapsulation, and +we recommend that you use the appropriate APIs in +L<Moose::Meta::Class> and L<Moose::Meta::Attribute> instead. Those +APIs in turn call the methods in this class as appropriate. + +At present, this is an empty subclass of L<Class::MOP::Instance>, so +you should see that class for all API details. + +=head1 INHERITANCE + +C<Moose::Meta::Instance> is a subclass of L<Class::MOP::Instance>. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method.pm b/lib/Moose/Meta/Method.pm new file mode 100644 index 0000000..e0bc667 --- /dev/null +++ b/lib/Moose/Meta/Method.pm @@ -0,0 +1,100 @@ +package Moose::Meta::Method; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP::MiniTrait; + +use parent 'Class::MOP::Method'; + +Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait'); + +1; + +# ABSTRACT: A Moose Method metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method - A Moose Method metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Method> that provides +additional Moose-specific functionality, all of which is private. + +To understand this class, you should read the the L<Class::MOP::Method> +documentation. + +=head1 INHERITANCE + +C<Moose::Meta::Method> is a subclass of L<Class::MOP::Method>. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Accessor.pm b/lib/Moose/Meta/Method/Accessor.pm new file mode 100644 index 0000000..3b30b2d --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor.pm @@ -0,0 +1,208 @@ +package Moose::Meta::Method::Accessor; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Try::Tiny; + +use parent 'Moose::Meta::Method', + 'Class::MOP::Method::Accessor'; + +use Moose::Util 'throw_exception'; + +# multiple inheritance is terrible +sub new { + goto &Class::MOP::Method::Accessor::new; +} + +sub _new { + goto &Class::MOP::Method::Accessor::_new; +} + +sub _error_thrower { + my $self = shift; + return $self->associated_attribute + if ref($self) && defined($self->associated_attribute); + return $self->SUPER::_error_thrower; +} + +sub _compile_code { + my $self = shift; + my @args = @_; + try { + $self->SUPER::_compile_code(@args); + } + catch { + throw_exception( CouldNotCreateWriter => attribute => $self->associated_attribute, + error => $_, + instance => $self + ); + }; +} + +sub _eval_environment { + my $self = shift; + return $self->associated_attribute->_eval_environment; +} + +sub _instance_is_inlinable { + my $self = shift; + return $self->associated_attribute->associated_class->instance_metaclass->is_inlinable; +} + +sub _generate_reader_method { + my $self = shift; + $self->_instance_is_inlinable ? $self->_generate_reader_method_inline(@_) + : $self->SUPER::_generate_reader_method(@_); +} + +sub _generate_writer_method { + my $self = shift; + $self->_instance_is_inlinable ? $self->_generate_writer_method_inline(@_) + : $self->SUPER::_generate_writer_method(@_); +} + +sub _generate_accessor_method { + my $self = shift; + $self->_instance_is_inlinable ? $self->_generate_accessor_method_inline(@_) + : $self->SUPER::_generate_accessor_method(@_); +} + +sub _generate_predicate_method { + my $self = shift; + $self->_instance_is_inlinable ? $self->_generate_predicate_method_inline(@_) + : $self->SUPER::_generate_predicate_method(@_); +} + +sub _generate_clearer_method { + my $self = shift; + $self->_instance_is_inlinable ? $self->_generate_clearer_method_inline(@_) + : $self->SUPER::_generate_clearer_method(@_); +} + +sub _writer_value_needs_copy { + shift->associated_attribute->_writer_value_needs_copy(@_); +} + +sub _inline_tc_code { + shift->associated_attribute->_inline_tc_code(@_); +} + +sub _inline_check_coercion { + shift->associated_attribute->_inline_check_coercion(@_); +} + +sub _inline_check_constraint { + shift->associated_attribute->_inline_check_constraint(@_); +} + +sub _inline_check_lazy { + shift->associated_attribute->_inline_check_lazy(@_); +} + +sub _inline_store_value { + shift->associated_attribute->_inline_instance_set(@_) . ';'; +} + +sub _inline_get_old_value_for_trigger { + shift->associated_attribute->_inline_get_old_value_for_trigger(@_); +} + +sub _inline_trigger { + shift->associated_attribute->_inline_trigger(@_); +} + +sub _get_value { + shift->associated_attribute->_inline_instance_get(@_); +} + +sub _has_value { + shift->associated_attribute->_inline_instance_has(@_); +} + +1; + +# ABSTRACT: A Moose Method metaclass for accessors + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Accessor - A Moose Method metaclass for accessors + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Method::Accessor> that +provides additional Moose-specific functionality, all of which is +private. + +To understand this class, you should read the the +L<Class::MOP::Method::Accessor> documentation. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Accessor/Native.pm b/lib/Moose/Meta/Method/Accessor/Native.pm new file mode 100644 index 0000000..01a3fee --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native.pm @@ -0,0 +1,157 @@ +package Moose::Meta::Method::Accessor::Native; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Carp qw( confess ); +use Scalar::Util qw( blessed ); + +use Moose::Role; + +use Moose::Util 'throw_exception'; + +around new => sub { + my $orig = shift; + my $class = shift; + my %options = @_; + + $options{curried_arguments} = [] + unless exists $options{curried_arguments}; + + throw_exception( MustSupplyArrayRefAsCurriedArguments => params => \%options, + class_name => $class + ) + unless $options{curried_arguments} + && ref($options{curried_arguments}) eq 'ARRAY'; + + my $attr_context = $options{attribute}->definition_context; + my $desc = 'native delegation method '; + $desc .= $options{attribute}->associated_class->name; + $desc .= '::' . $options{name}; + $desc .= " ($options{delegate_to_method})"; + $desc .= " of attribute " . $options{attribute}->name; + $options{definition_context} = { + %{ $attr_context || {} }, + description => $desc, + }; + + $options{accessor_type} = 'native'; + + return $class->$orig(%options); +}; + +sub _new { + my $class = shift; + my $options = @_ == 1 ? $_[0] : {@_}; + + return bless $options, $class; +} + +sub root_types { (shift)->{'root_types'} } + +sub _initialize_body { + my $self = shift; + + $self->{'body'} = $self->_compile_code( [$self->_generate_method] ); + + return; +} + +sub _inline_curried_arguments { + my $self = shift; + + return unless @{ $self->curried_arguments }; + + return 'unshift @_, @curried;'; +} + +sub _inline_check_argument_count { + my $self = shift; + + my @code; + + if (my $min = $self->_minimum_arguments) { + push @code, ( + 'if (@_ < ' . $min . ') {', + $self->_inline_throw_exception( MethodExpectsMoreArgs => + 'method_name => "'.$self->delegate_to_method.'",'. + "minimum_args => ".$min, + ) . ';', + '}', + ); + } + + if (defined(my $max = $self->_maximum_arguments)) { + push @code, ( + 'if (@_ > ' . $max . ') {', + $self->_inline_throw_exception( MethodExpectsFewerArgs => + 'method_name => "'.$self->delegate_to_method.'",'. + 'maximum_args => '.$max, + ) . ';', + '}', + ); + } + + return @code; +} + +sub _inline_return_value { + my $self = shift; + my ($slot_access, $for_writer) = @_; + + return 'return ' . $self->_return_value($slot_access, $for_writer) . ';'; +} + +sub _minimum_arguments { 0 } +sub _maximum_arguments { undef } + +override _get_value => sub { + my $self = shift; + my ($instance) = @_; + + return $self->_slot_access_can_be_inlined + ? super() + : $instance . '->$reader'; +}; + +override _inline_store_value => sub { + my $self = shift; + my ($instance, $value) = @_; + + return $self->_slot_access_can_be_inlined + ? super() + : $instance . '->$writer(' . $value . ');'; +}; + +override _eval_environment => sub { + my $self = shift; + + my $env = super(); + + $env->{'@curried'} = $self->curried_arguments; + + return $env if $self->_slot_access_can_be_inlined; + + my $reader = $self->associated_attribute->get_read_method_ref; + $reader = $reader->body if blessed $reader; + + $env->{'$reader'} = \$reader; + + my $writer = $self->associated_attribute->get_write_method_ref; + $writer = $writer->body if blessed $writer; + + $env->{'$writer'} = \$writer; + + return $env; +}; + +sub _slot_access_can_be_inlined { + my $self = shift; + + return $self->is_inline && $self->_instance_is_inlinable; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array.pm b/lib/Moose/Meta/Method/Accessor/Native/Array.pm new file mode 100644 index 0000000..d585648 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array.pm @@ -0,0 +1,28 @@ +package Moose::Meta::Method::Accessor::Native::Array; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +sub _inline_check_var_is_valid_index { + my $self = shift; + my ($var) = @_; + + return ( + 'if (!defined(' . $var . ') || ' . $var . ' !~ /^-?\d+$/) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => '.$var.','. + 'method_name => "'.$self->delegate_to_method.'",'. + 'type_of_argument => "integer",'. + 'type => "Int",'. + 'argument_noun => "index"', + ) . ';', + '}', + ); +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/Writer.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/Writer.pm new file mode 100644 index 0000000..e47d940 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/Writer.pm @@ -0,0 +1,27 @@ +package Moose::Meta::Method::Accessor::Native::Array::Writer; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer', + 'Moose::Meta::Method::Accessor::Native::Array', + 'Moose::Meta::Method::Accessor::Native::Collection'; + +sub _inline_coerce_new_values { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Collection::_inline_coerce_new_values(@_); +} + +sub _new_members { '@_' } + +sub _copy_old_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @{(' . $slot_access . ')} ]'; +} + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/accessor.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/accessor.pm new file mode 100644 index 0000000..62af0a5 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/accessor.pm @@ -0,0 +1,56 @@ +package Moose::Meta::Method::Accessor::Native::Array::accessor; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::set', + 'Moose::Meta::Method::Accessor::Native::Array::get'; + +sub _inline_process_arguments { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Array::get::_inline_process_arguments(@_); +} + +sub _inline_check_arguments { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Array::get::_inline_check_arguments(@_); +} + +sub _return_value { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Array::get::_return_value(@_); +} + +sub _generate_method { + my $self = shift; + + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); + + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'), + # get + 'if (@_ == 1) {', + $self->_inline_check_var_is_valid_index('$_[0]'), + $self->Moose::Meta::Method::Accessor::Native::Array::get::_inline_return_value($slot_access), + '}', + # set + 'else {', + $self->_inline_writer_core($inv, $slot_access), + '}', + '}', + ); +} + +sub _minimum_arguments { 1 } +sub _maximum_arguments { 2 } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/clear.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/clear.pm new file mode 100644 index 0000000..39913ff --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/clear.pm @@ -0,0 +1,28 @@ +package Moose::Meta::Method::Accessor::Native::Array::clear; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _maximum_arguments { 0 } + +sub _adds_members { 0 } + +sub _potential_value { '[]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = [];'; +} + +sub _return_value { '' } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/count.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/count.pm new file mode 100644 index 0000000..724db7a --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/count.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Array::count; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'scalar @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/delete.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/delete.pm new file mode 100644 index 0000000..bf47e09 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/delete.pm @@ -0,0 +1,50 @@ +package Moose::Meta::Method::Accessor::Native::Array::delete; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return $self->_inline_check_var_is_valid_index('$_[0]'); +} + +sub _adds_members { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my @potential = @{ (' . $slot_access . ') }; ' + . '@return = splice @potential, $_[0], 1; ' + . '\@potential; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@return = splice @{ (' . $slot_access . ') }, $_[0], 1;'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '$return[0]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/elements.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/elements.pm new file mode 100644 index 0000000..59dcc14 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/elements.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Array::elements; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '@{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/first.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/first.pm new file mode 100644 index 0000000..32059f8 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/first.pm @@ -0,0 +1,42 @@ +package Moose::Meta::Method::Accessor::Native::Array::first; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::Util (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "first",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '&List::Util::first($_[0], @{ (' . $slot_access . ') })'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/first_index.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/first_index.pm new file mode 100644 index 0000000..da22266 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/first_index.pm @@ -0,0 +1,42 @@ +package Moose::Meta::Method::Accessor::Native::Array::first_index; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::MoreUtils (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "first_index",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '&List::MoreUtils::first_index($_[0], @{ (' . $slot_access . ') })'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/get.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/get.pm new file mode 100644 index 0000000..3e88930 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/get.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Array::get; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP::MiniTrait; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader', + 'Moose::Meta::Method::Accessor::Native::Array'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return $self->_inline_check_var_is_valid_index('$_[0]'); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . '->[ $_[0] ]'; +} + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/grep.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/grep.pm new file mode 100644 index 0000000..c750e5b --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/grep.pm @@ -0,0 +1,41 @@ +package Moose::Meta::Method::Accessor::Native::Array::grep; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "grep",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'grep { $_[0]->() } @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/insert.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/insert.pm new file mode 100644 index 0000000..c085223 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/insert.pm @@ -0,0 +1,58 @@ +package Moose::Meta::Method::Accessor::Native::Array::insert; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _minimum_arguments { 2 } + +sub _maximum_arguments { 2 } + +sub _adds_members { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my @potential = @{ (' . $slot_access . ') }; ' + . 'splice @potential, $_[0], 0, $_[1]; ' + . '\@potential; ' + . '})'; +} + +# We need to override this because while @_ can be written to, we cannot write +# directly to $_[1]. +sub _inline_coerce_new_values { + my $self = shift; + + return unless $self->associated_attribute->should_coerce; + + return unless $self->_tc_member_type_can_coerce; + + return '@_ = ($_[0], $member_coercion->($_[1]));'; +}; + +sub _new_members { '$_[1]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return 'splice @{ (' . $slot_access . ') }, $_[0], 0, $_[1];'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . '->[ $_[0] ]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/is_empty.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/is_empty.pm new file mode 100644 index 0000000..c57c448 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/is_empty.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Array::is_empty; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '@{ (' . $slot_access . ') } ? 0 : 1'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/join.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/join.pm new file mode 100644 index 0000000..b06ae3b --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/join.pm @@ -0,0 +1,41 @@ +package Moose::Meta::Method::Accessor::Native::Array::join; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Moose::Util::_STRINGLIKE0($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "join",'. + 'type_of_argument => "string",'. + 'type => "Str",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'join $_[0], @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/map.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/map.pm new file mode 100644 index 0000000..59c6225 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/map.pm @@ -0,0 +1,41 @@ +package Moose::Meta::Method::Accessor::Native::Array::map; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "map",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'map { $_[0]->() } @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/natatime.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/natatime.pm new file mode 100644 index 0000000..e72815e --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/natatime.pm @@ -0,0 +1,65 @@ +package Moose::Meta::Method::Accessor::Native::Array::natatime; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::MoreUtils (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 2 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!defined($_[0]) || $_[0] !~ /^\d+$/) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "natatime",'. + 'type_of_argument => "integer",'. + 'type => "Int",'. + 'argument_noun => "n value"', + ) . ';', + '}', + 'if (@_ == 2 && !Params::Util::_CODELIKE($_[1])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[1],'. + 'method_name => "natatime",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",'. + 'ordinal => "second"', + ) . ';', + '}', + ); +} + +sub _inline_return_value { + my $self = shift; + my ($slot_access) = @_; + + return ( + 'my $iter = List::MoreUtils::natatime($_[0], @{ (' . $slot_access . ') });', + 'if ($_[1]) {', + 'while (my @vals = $iter->()) {', + '$_[1]->(@vals);', + '}', + '}', + 'else {', + 'return $iter;', + '}', + ); +} + +# Not called, but needed to satisfy the Reader role +sub _return_value { } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/pop.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/pop.pm new file mode 100644 index 0000000..a9df36f --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/pop.pm @@ -0,0 +1,47 @@ +package Moose::Meta::Method::Accessor::Native::Array::pop; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _maximum_arguments { 0 } + +sub _adds_members { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @{ (' . $slot_access . ') } > 1 ' + . '? @{ (' . $slot_access . ') }[0..$#{ (' . $slot_access . ') } - 1] ' + . ': () ]'; +} + +sub _inline_capture_return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'my $old = ' . $slot_access . '->[-1];'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return 'pop @{ (' . $slot_access . ') };'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '$old'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/push.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/push.pm new file mode 100644 index 0000000..eec4344 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/push.pm @@ -0,0 +1,36 @@ +package Moose::Meta::Method::Accessor::Native::Array::push; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _adds_members { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @{ (' . $slot_access . ') }, @_ ]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return 'push @{ (' . $slot_access . ') }, @_;'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'scalar @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/reduce.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/reduce.pm new file mode 100644 index 0000000..12fd9c4 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/reduce.pm @@ -0,0 +1,42 @@ +package Moose::Meta::Method::Accessor::Native::Array::reduce; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::Util (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "reduce",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'List::Util::reduce { $_[0]->($a, $b) } @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/set.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/set.pm new file mode 100644 index 0000000..b487303 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/set.pm @@ -0,0 +1,64 @@ +package Moose::Meta::Method::Accessor::Native::Array::set; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _minimum_arguments { 2 } + +sub _maximum_arguments { 2 } + +sub _inline_check_arguments { + my $self = shift; + + return $self->_inline_check_var_is_valid_index('$_[0]'); +} + +sub _adds_members { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my @potential = @{ (' . $slot_access . ') }; ' + . '$potential[$_[0]] = $_[1]; ' + . '\@potential; ' + . '})'; +} + +# We need to override this because while @_ can be written to, we cannot write +# directly to $_[1]. +sub _inline_coerce_new_values { + my $self = shift; + + return unless $self->associated_attribute->should_coerce; + + return unless $self->_tc_member_type_can_coerce; + + return '@_ = ($_[0], $member_coercion->($_[1]));'; +}; + +sub _new_members { '$_[1]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . '->[$_[0]] = $_[1];'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . '->[$_[0]]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/shallow_clone.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/shallow_clone.pm new file mode 100644 index 0000000..f4dd6b4 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/shallow_clone.pm @@ -0,0 +1,26 @@ +package Moose::Meta::Method::Accessor::Native::Array::shallow_clone; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 0 } + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @{ (' . $slot_access . ') } ]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/shift.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/shift.pm new file mode 100644 index 0000000..f0c3057 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/shift.pm @@ -0,0 +1,47 @@ +package Moose::Meta::Method::Accessor::Native::Array::shift; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _maximum_arguments { 0 } + +sub _adds_members { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @{ (' . $slot_access . ') } > 1 ' + . '? @{ (' . $slot_access . ') }[1..$#{ (' . $slot_access . ') }] ' + . ': () ]'; +} + +sub _inline_capture_return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'my $old = ' . $slot_access . '->[0];'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return 'shift @{ (' . $slot_access . ') };'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '$old'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/shuffle.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/shuffle.pm new file mode 100644 index 0000000..9e7a93e --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/shuffle.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::Array::shuffle; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'List::Util::shuffle @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/sort.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/sort.pm new file mode 100644 index 0000000..a1b15a1 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/sort.pm @@ -0,0 +1,44 @@ +package Moose::Meta::Method::Accessor::Native::Array::sort; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (@_ && !Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "sort",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return + 'wantarray ? ( ' . + '$_[0] ' + . '? sort { $_[0]->($a, $b) } @{ (' . $slot_access . ') } ' + . ': sort @{ (' . $slot_access . ') }' + . ' ) : @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/sort_in_place.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/sort_in_place.pm new file mode 100644 index 0000000..cfdb2c1 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/sort_in_place.pm @@ -0,0 +1,45 @@ +package Moose::Meta::Method::Accessor::Native::Array::sort_in_place; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (@_ && !Params::Util::_CODELIKE($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "sort_in_place",'. + 'type_of_argument => "code reference",'. + 'type => "CodeRef",', + ) . ';', + '}', + ); +} + +sub _adds_members { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ $_[0] ' + . '? sort { $_[0]->($a, $b) } @{ (' . $slot_access . ') } ' + . ': sort @{ (' . $slot_access . ') } ]'; +} + +sub _return_value { '' } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/splice.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/splice.pm new file mode 100644 index 0000000..8bbc6df --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/splice.pm @@ -0,0 +1,72 @@ +package Moose::Meta::Method::Accessor::Native::Array::splice; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _minimum_arguments { 1 } + +sub _adds_members { 1 } + +sub _inline_process_arguments { + return ( + 'my $idx = shift;', + 'my $len = @_ ? shift : undef;', + ); +} + +sub _inline_check_arguments { + my $self = shift; + + return ( + $self->_inline_check_var_is_valid_index('$idx'), + 'if (defined($len) && $len !~ /^-?\d+$/) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $len,'. + 'method_name => "splice",'. + 'type_of_argument => "integer",'. + 'type => "Int",'. + 'argument_noun => "length argument"', + ) . ';', + '}', + ); +} + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my @potential = @{ (' . $slot_access . ') }; ' + . '@return = defined $len ' + . '? (splice @potential, $idx, $len, @_) ' + . ': (splice @potential, $idx); ' + . '\@potential;' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return ( + '@return = defined $len', + '? (splice @{ (' . $slot_access . ') }, $idx, $len, @_)', + ': (splice @{ (' . $slot_access . ') }, $idx);', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'wantarray ? @return : $return[-1]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/uniq.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/uniq.pm new file mode 100644 index 0000000..535b802 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/uniq.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::Array::uniq; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::MoreUtils (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'List::MoreUtils::uniq @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Array/unshift.pm b/lib/Moose/Meta/Method/Accessor/Native/Array/unshift.pm new file mode 100644 index 0000000..4111671 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Array/unshift.pm @@ -0,0 +1,36 @@ +package Moose::Meta::Method::Accessor::Native::Array::unshift; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Array::Writer'; + +sub _adds_members { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '[ @_, @{ (' . $slot_access . ') } ]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return 'unshift @{ (' . $slot_access . ') }, @_;'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'scalar @{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Bool/not.pm b/lib/Moose/Meta/Method/Accessor/Native/Bool/not.pm new file mode 100644 index 0000000..60eb646 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Bool/not.pm @@ -0,0 +1,20 @@ +package Moose::Meta::Method::Accessor::Native::Bool::not; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '!' . $slot_access; +} + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Bool/set.pm b/lib/Moose/Meta/Method/Accessor/Native/Bool/set.pm new file mode 100644 index 0000000..725da20 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Bool/set.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::Bool::set; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { 1 } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = 1;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Bool/toggle.pm b/lib/Moose/Meta/Method/Accessor/Native/Bool/toggle.pm new file mode 100644 index 0000000..663b1a2 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Bool/toggle.pm @@ -0,0 +1,29 @@ +package Moose::Meta::Method::Accessor::Native::Bool::toggle; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' ? 0 : 1'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = ' . $slot_access . ' ? 0 : 1;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Bool/unset.pm b/lib/Moose/Meta/Method/Accessor/Native/Bool/unset.pm new file mode 100644 index 0000000..6c5c62b --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Bool/unset.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::Bool::unset; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { 0 } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = 0;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Code/execute.pm b/lib/Moose/Meta/Method/Accessor/Native/Code/execute.pm new file mode 100644 index 0000000..c74604f --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Code/execute.pm @@ -0,0 +1,20 @@ +package Moose::Meta::Method::Accessor::Native::Code::execute; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . '->(@_)'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Code/execute_method.pm b/lib/Moose/Meta/Method/Accessor/Native/Code/execute_method.pm new file mode 100644 index 0000000..b3d40b9 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Code/execute_method.pm @@ -0,0 +1,20 @@ +package Moose::Meta::Method::Accessor::Native::Code::execute_method; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . '->($self, @_)'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Collection.pm b/lib/Moose/Meta/Method/Accessor/Native/Collection.pm new file mode 100644 index 0000000..67331d5 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Collection.pm @@ -0,0 +1,167 @@ +package Moose::Meta::Method::Accessor::Native::Collection; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +requires qw( _adds_members ); + +sub _inline_coerce_new_values { + my $self = shift; + + return unless $self->associated_attribute->should_coerce; + + return unless $self->_tc_member_type_can_coerce; + + return ( + '(' . $self->_new_members . ') = map { $member_coercion->($_) }', + $self->_new_members . ';', + ); +} + +sub _tc_member_type_can_coerce { + my $self = shift; + + my $member_tc = $self->_tc_member_type; + + return $member_tc && $member_tc->has_coercion; +} + +sub _tc_member_type { + my $self = shift; + + my $tc = $self->associated_attribute->type_constraint; + while ($tc) { + return $tc->type_parameter + if $tc->can('type_parameter'); + $tc = $tc->parent; + } + + return; +} + +sub _writer_value_needs_copy { + my $self = shift; + + return $self->_constraint_must_be_checked + && !$self->_check_new_members_only; +} + +sub _inline_tc_code { + my $self = shift; + my ($value, $tc, $coercion, $message, $is_lazy) = @_; + + return unless $self->_constraint_must_be_checked; + + if ($self->_check_new_members_only) { + return unless $self->_adds_members; + + return $self->_inline_check_member_constraint($self->_new_members); + } + else { + return ( + $self->_inline_check_coercion($value, $tc, $coercion, $is_lazy), + $self->_inline_check_constraint($value, $tc, $message, $is_lazy), + ); + } +} + +sub _check_new_members_only { + my $self = shift; + + my $attr = $self->associated_attribute; + + my $tc = $attr->type_constraint; + + # If we have a coercion, we could come up with an entirely new value after + # coercing, so we need to check everything, + return 0 if $attr->should_coerce && $tc->has_coercion; + + # If the parent is our root type (ArrayRef, HashRef, etc), that means we + # can just check the new members of the collection, because we know that + # we will always be generating an appropriate collection type. + # + # However, if this type has its own constraint (it's Parameteriz_able_, + # not Paramet_erized_), we don't know what is being checked by the + # constraint, so we need to check the whole value, not just the members. + return 1 + if $self->_is_root_type( $tc->parent ) + && ( $tc->isa('Moose::Meta::TypeConstraint::Parameterized') + || $tc->isa('Specio::Constraint::Parameterized') ); + + return 0; +} + +sub _inline_check_member_constraint { + my $self = shift; + my ($new_value) = @_; + + my $attr_name = $self->associated_attribute->name; + + my $check + = $self->_tc_member_type->can_be_inlined + ? '! (' . $self->_tc_member_type->_inline_check('$new_val') . ')' + : ' !$member_tc->($new_val) '; + + return ( + 'for my $new_val (' . $new_value . ') {', + "if ($check) {", + 'my $msg = do { local $_ = $new_val; $member_message->($new_val) };'. + $self->_inline_throw_exception( ValidationFailedForInlineTypeConstraint => + "attribute_name => '".$attr_name."',". + 'type_constraint_message => $msg,'. + 'class_name => $class_name,'. + 'value => $new_val,'. + 'new_member => 1', + ) . ';', + '}', + '}', + ); +} + +sub _inline_get_old_value_for_trigger { + my $self = shift; + my ($instance, $old) = @_; + + my $attr = $self->associated_attribute; + return unless $attr->has_trigger; + + return ( + 'my ' . $old . ' = ' . $self->_has_value($instance), + '? ' . $self->_copy_old_value($self->_get_value($instance)), + ': ();', + ); +} + +around _eval_environment => sub { + my $orig = shift; + my $self = shift; + + my $env = $self->$orig(@_); + + my $member_tc = $self->_tc_member_type; + + return $env unless $member_tc; + + $env->{'$member_tc'} = \( $member_tc->_compiled_type_constraint ); + $env->{'$member_coercion'} = \( + $member_tc->coercion->_compiled_type_coercion + ) if $member_tc->has_coercion; + $env->{'$member_message'} = \( + $member_tc->has_message + ? $member_tc->message + : $member_tc->_default_message + ); + + my $tc_env = $member_tc->inline_environment(); + + $env = { %{$env}, %{$tc_env} }; + + return $env; +}; + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Counter/Writer.pm b/lib/Moose/Meta/Method/Accessor/Native/Counter/Writer.pm new file mode 100644 index 0000000..55ab4a7 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Counter/Writer.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::Counter::Writer; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _constraint_must_be_checked { + my $self = shift; + + my $attr = $self->associated_attribute; + + return $attr->has_type_constraint + && ($attr->type_constraint->name =~ /^(?:Num|Int)$/ + || ($attr->should_coerce && $attr->type_constraint->has_coercion) + ); +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Counter/dec.pm b/lib/Moose/Meta/Method/Accessor/Native/Counter/dec.pm new file mode 100644 index 0000000..3e61d59 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Counter/dec.pm @@ -0,0 +1,30 @@ +package Moose::Meta::Method::Accessor::Native::Counter::dec; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 0 } +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' - (defined $_[0] ? $_[0] : 1)'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' -= defined $_[0] ? $_[0] : 1;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Counter/inc.pm b/lib/Moose/Meta/Method/Accessor/Native/Counter/inc.pm new file mode 100644 index 0000000..1efeab8 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Counter/inc.pm @@ -0,0 +1,30 @@ +package Moose::Meta::Method::Accessor::Native::Counter::inc; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 0 } +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' + (defined $_[0] ? $_[0] : 1)'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' += defined $_[0] ? $_[0] : 1;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Counter/reset.pm b/lib/Moose/Meta/Method/Accessor/Native/Counter/reset.pm new file mode 100644 index 0000000..b62ac7b --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Counter/reset.pm @@ -0,0 +1,36 @@ +package Moose::Meta::Method::Accessor::Native::Counter::reset; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + my $attr = $self->associated_attribute; + + return '(do { ' + . join(' ', $attr->_inline_generate_default( + '$self', '$default_for_reset' + )) . ' ' + . '$default_for_reset; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = ' . $self->_potential_value . ';'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Counter/set.pm b/lib/Moose/Meta/Method/Accessor/Native/Counter/set.pm new file mode 100644 index 0000000..671984c --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Counter/set.pm @@ -0,0 +1,25 @@ +package Moose::Meta::Method::Accessor::Native::Counter::set; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } +sub _maximum_arguments { 1 } + +sub _potential_value { '$_[0]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash.pm new file mode 100644 index 0000000..721c5f5 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash.pm @@ -0,0 +1,28 @@ +package Moose::Meta::Method::Accessor::Native::Hash; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +sub _inline_check_var_is_valid_key { + my $self = shift; + my ($var) = @_; + + return ( + 'if (!defined(' . $var . ')) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => '.$var.','. + 'method_name => "'.$self->delegate_to_method.'",'. + 'type_of_argument => "defined value",'. + 'type => "Defined",'. + 'argument_noun => "key"', + ) . ';', + '}', + ); +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/Writer.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/Writer.pm new file mode 100644 index 0000000..ccc3e1f --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/Writer.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Hash::Writer; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::MOP::MiniTrait; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer', + 'Moose::Meta::Method::Accessor::Native::Hash', + 'Moose::Meta::Method::Accessor::Native::Collection'; + +sub _inline_coerce_new_values { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Collection::_inline_coerce_new_values(@_); +} + +sub _new_values { '@values' } + +sub _copy_old_value { + my $self = shift; + my ($slot_access) = @_; + + return '{ %{ (' . $slot_access . ') } }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/accessor.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/accessor.pm new file mode 100644 index 0000000..f4f978e --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/accessor.pm @@ -0,0 +1,61 @@ +package Moose::Meta::Method::Accessor::Native::Hash::accessor; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Hash::set', + 'Moose::Meta::Method::Accessor::Native::Hash::get'; + +sub _inline_process_arguments { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Hash::set::_inline_process_arguments(@_); +} + +sub _inline_check_argument_count { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Hash::set::_inline_check_argument_count(@_); +} + +sub _inline_check_arguments { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Hash::set::_inline_check_arguments(@_); +} + +sub _return_value { + my $self = shift; + $self->Moose::Meta::Method::Accessor::Native::Hash::set::_return_value(@_); +} + +sub _generate_method { + my $self = shift; + + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); + + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'), + # get + 'if (@_ == 1) {', + $self->_inline_check_var_is_valid_key('$_[0]'), + $slot_access . '->{$_[0]}', + '}', + # set + 'else {', + $self->_inline_writer_core($inv, $slot_access), + '}', + '}', + ); +} + +sub _minimum_arguments { 1 } +sub _maximum_arguments { 2 } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/clear.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/clear.pm new file mode 100644 index 0000000..751a443 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/clear.pm @@ -0,0 +1,28 @@ +package Moose::Meta::Method::Accessor::Native::Hash::clear; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Hash::Writer'; + +sub _maximum_arguments { 0 } + +sub _adds_members { 0 } + +sub _potential_value { '{}' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = {};'; +} + +sub _return_value { '' } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/count.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/count.pm new file mode 100644 index 0000000..aca9116 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/count.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Hash::count; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'scalar keys %{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/defined.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/defined.pm new file mode 100644 index 0000000..0062918 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/defined.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Hash::defined; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader', + 'Moose::Meta::Method::Accessor::Native::Hash'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return $self->_inline_check_var_is_valid_key('$_[0]'); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'defined ' . $slot_access . '->{ $_[0] }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/delete.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/delete.pm new file mode 100644 index 0000000..1a6d706 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/delete.pm @@ -0,0 +1,40 @@ +package Moose::Meta::Method::Accessor::Native::Hash::delete; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Hash::Writer'; + +sub _adds_members { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my %potential = %{ (' . $slot_access . ') }; ' + . '@return = delete @potential{@_}; ' + . '\%potential; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@return = delete @{ (' . $slot_access . ') }{@_};'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'wantarray ? @return : $return[-1]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/elements.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/elements.pm new file mode 100644 index 0000000..d1ba09d --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/elements.pm @@ -0,0 +1,23 @@ +package Moose::Meta::Method::Accessor::Native::Hash::elements; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'map { $_, ' . $slot_access . '->{$_} } ' + . 'keys %{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/exists.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/exists.pm new file mode 100644 index 0000000..7ab09cc --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/exists.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Hash::exists; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader', + 'Moose::Meta::Method::Accessor::Native::Hash'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return $self->_inline_check_var_is_valid_key('$_[0]'); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = shift; + + return 'exists ' . $slot_access . '->{ $_[0] }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/get.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/get.pm new file mode 100644 index 0000000..a91c8f8 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/get.pm @@ -0,0 +1,35 @@ +package Moose::Meta::Method::Accessor::Native::Hash::get; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader', + 'Moose::Meta::Method::Accessor::Native::Hash'; + +sub _minimum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'for (@_) {', + $self->_inline_check_var_is_valid_key('$_'), + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '@_ > 1 ' + . '? @{ (' . $slot_access . ') }{@_} ' + . ': ' . $slot_access . '->{$_[0]}'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/is_empty.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/is_empty.pm new file mode 100644 index 0000000..7948927 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/is_empty.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Hash::is_empty; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'scalar keys %{ (' . $slot_access . ') } ? 0 : 1'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/keys.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/keys.pm new file mode 100644 index 0000000..439be94 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/keys.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Hash::keys; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'keys %{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/kv.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/kv.pm new file mode 100644 index 0000000..4bbb325 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/kv.pm @@ -0,0 +1,23 @@ +package Moose::Meta::Method::Accessor::Native::Hash::kv; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'map { [ $_, ' . $slot_access . '->{$_} ] } ' + . 'keys %{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/set.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/set.pm new file mode 100644 index 0000000..7d7a1fa --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/set.pm @@ -0,0 +1,103 @@ +package Moose::Meta::Method::Accessor::Native::Hash::set; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::MoreUtils (); +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Hash::Writer'; + +sub _minimum_arguments { 2 } + +sub _maximum_arguments { undef } + +around _inline_check_argument_count => sub { + my $orig = shift; + my $self = shift; + + return ( + $self->$orig(@_), + 'if (@_ % 2) {', + $self->_inline_throw_exception( MustPassEvenNumberOfArguments => + "method_name => '".$self->delegate_to_method."',". + 'args => \@_', + ) . ';', + '}', + ); +}; + +sub _inline_process_arguments { + my $self = shift; + + return ( + 'my @keys_idx = grep { ! ($_ % 2) } 0..$#_;', + 'my @values_idx = grep { $_ % 2 } 0..$#_;', + ); +} + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'for (@keys_idx) {', + 'if (!defined($_[$_])) {', + $self->_inline_throw_exception( UndefinedHashKeysPassedToMethod => + 'hash_keys => \@keys_idx,'. + "method_name => '".$self->delegate_to_method."'", + ) . ';', + '}', + '}', + ); +} + +sub _adds_members { 1 } + +# We need to override this because while @_ can be written to, we cannot write +# directly to $_[1]. +sub _inline_coerce_new_values { + my $self = shift; + + return unless $self->associated_attribute->should_coerce; + + return unless $self->_tc_member_type_can_coerce; + + # Is there a simpler way to do this? + return ( + 'my $iter = List::MoreUtils::natatime(2, @_);', + '@_ = ();', + 'while (my ($key, $val) = $iter->()) {', + 'push @_, $key, $member_coercion->($val);', + '}', + ); +}; + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '{ %{ (' . $slot_access . ') }, @_ }'; +} + +sub _new_members { '@_[ @values_idx ]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@{ (' . $slot_access . ') }{ @_[@keys_idx] } = @_[@values_idx];'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'wantarray ' + . '? @{ (' . $slot_access . ') }{ @_[@keys_idx] } ' + . ': ' . $slot_access . '->{ $_[$keys_idx[0]] }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/shallow_clone.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/shallow_clone.pm new file mode 100644 index 0000000..62b09cb --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/shallow_clone.pm @@ -0,0 +1,26 @@ +package Moose::Meta::Method::Accessor::Native::Hash::shallow_clone; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 0 } + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '{ %{ (' . $slot_access . ') } }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Hash/values.pm b/lib/Moose/Meta/Method/Accessor/Native/Hash/values.pm new file mode 100644 index 0000000..750ce76 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Hash/values.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::Hash::values; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'values %{ (' . $slot_access . ') }'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/abs.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/abs.pm new file mode 100644 index 0000000..987a89f --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/abs.pm @@ -0,0 +1,29 @@ +package Moose::Meta::Method::Accessor::Native::Number::abs; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return 'abs(' . $slot_access . ')'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = abs(' . $slot_access . ');'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/add.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/add.pm new file mode 100644 index 0000000..a7bd95c --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/add.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Number::add; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' + $_[0]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' += $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/div.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/div.pm new file mode 100644 index 0000000..e2037a2 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/div.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Number::div; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' / $_[0]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' /= $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/mod.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/mod.pm new file mode 100644 index 0000000..80a3c2a --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/mod.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Number::mod; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' % $_[0]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' %= $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/mul.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/mul.pm new file mode 100644 index 0000000..6b019a6 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/mul.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Number::mul; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' * $_[0]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' *= $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/set.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/set.pm new file mode 100644 index 0000000..2aa9c40 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/set.pm @@ -0,0 +1,25 @@ +package Moose::Meta::Method::Accessor::Native::Number::set; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } +sub _maximum_arguments { 1 } + +sub _potential_value { '$_[0]' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Number/sub.pm b/lib/Moose/Meta/Method/Accessor/Native/Number/sub.pm new file mode 100644 index 0000000..c2fa157 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Number/sub.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::Number::sub; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' - $_[0]'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' -= $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Reader.pm b/lib/Moose/Meta/Method/Accessor/Native/Reader.pm new file mode 100644 index 0000000..df885e5 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Reader.pm @@ -0,0 +1,47 @@ +package Moose::Meta::Method::Accessor::Native::Reader; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native'; + +requires '_return_value'; + +sub _generate_method { + my $self = shift; + + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); + + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + $self->_inline_reader_core($inv, $slot_access, @_), + '}', + ); +} + +sub _inline_reader_core { + my $self = shift; + my ($inv, $slot_access, @extra) = @_; + + return ( + $self->_inline_check_argument_count, + $self->_inline_process_arguments($inv, $slot_access), + $self->_inline_check_arguments, + $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'), + $self->_inline_return_value($slot_access), + ); +} + +sub _inline_process_arguments { return } + +sub _inline_check_arguments { return } + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/append.pm b/lib/Moose/Meta/Method/Accessor/Native/String/append.pm new file mode 100644 index 0000000..e941e5a --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/append.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::String::append; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '( ' . $slot_access . ' . $_[0] )'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' .= $_[0];'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/chomp.pm b/lib/Moose/Meta/Method/Accessor/Native/String/chomp.pm new file mode 100644 index 0000000..49e2215 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/chomp.pm @@ -0,0 +1,40 @@ +package Moose::Meta::Method::Accessor::Native::String::chomp; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my $val = ' . $slot_access . '; ' + . '@return = chomp $val; ' + . '$val ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@return = chomp ' . $slot_access . ';'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '$return[0]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/chop.pm b/lib/Moose/Meta/Method/Accessor/Native/String/chop.pm new file mode 100644 index 0000000..c15fd0f --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/chop.pm @@ -0,0 +1,40 @@ +package Moose::Meta::Method::Accessor::Native::String::chop; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my $val = ' . $slot_access . '; ' + . '@return = chop $val; ' + . '$val; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@return = chop ' . $slot_access . ';'; +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return '$return[0]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/clear.pm b/lib/Moose/Meta/Method/Accessor/Native/String/clear.pm new file mode 100644 index 0000000..7aec2c5 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/clear.pm @@ -0,0 +1,24 @@ +package Moose::Meta::Method::Accessor::Native::String::clear; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { '""' } + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = "";'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/inc.pm b/lib/Moose/Meta/Method/Accessor/Native/String/inc.pm new file mode 100644 index 0000000..3ee5605 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/inc.pm @@ -0,0 +1,33 @@ +package Moose::Meta::Method::Accessor::Native::String::inc; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _maximum_arguments { 0 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my $val = ' . $slot_access . '; ' + . '$val++; ' + . '$val; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . '++;'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/length.pm b/lib/Moose/Meta/Method/Accessor/Native/String/length.pm new file mode 100644 index 0000000..bf40b40 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/length.pm @@ -0,0 +1,22 @@ +package Moose::Meta::Method::Accessor::Native::String::length; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _maximum_arguments { 0 } + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return 'length ' . $slot_access; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/match.pm b/lib/Moose/Meta/Method/Accessor/Native/String/match.pm new file mode 100644 index 0000000..ae85a96 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/match.pm @@ -0,0 +1,42 @@ +package Moose::Meta::Method::Accessor::Native::String::match; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Util (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Moose::Util::_STRINGLIKE0($_[0]) && !Params::Util::_REGEX($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'type => "Str|RegexpRef",'. + 'type_of_argument => "string or regexp reference",'. + 'method_name => "match"', + ) . ';', + '}', + ); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access . ' =~ $_[0]'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/prepend.pm b/lib/Moose/Meta/Method/Accessor/Native/String/prepend.pm new file mode 100644 index 0000000..87a0695 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/prepend.pm @@ -0,0 +1,31 @@ +package Moose::Meta::Method::Accessor::Native::String::prepend; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 1 } + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '$_[0] . ' . $slot_access; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return $slot_access . ' = $_[0] . ' . $slot_access . ';'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/replace.pm b/lib/Moose/Meta/Method/Accessor/Native/String/replace.pm new file mode 100644 index 0000000..6e33609 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/replace.pm @@ -0,0 +1,69 @@ +package Moose::Meta::Method::Accessor::Native::String::replace; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Util (); +use Params::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _minimum_arguments { 1 } + +sub _maximum_arguments { 2 } + +sub _inline_check_arguments { + my $self = shift; + + return ( + 'if (!Moose::Util::_STRINGLIKE0($_[0]) && !Params::Util::_REGEX($_[0])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[0],'. + 'method_name => "replace",'. + 'ordinal => "first",'. + 'type_of_argument => "string or regexp reference",'. + 'type => "Str|RegexpRef"', + ) . ';', + '}', + 'if (!Moose::Util::_STRINGLIKE0($_[1]) && !Params::Util::_CODELIKE($_[1])) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $_[1],'. + 'method_name => "replace",'. + 'ordinal => "second",'. + 'type_of_argument => "string or code reference",'. + 'type => "Str|CodeRef"', + ) . ';', + '}', + ); +} + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my $val = ' . $slot_access . '; ' + . 'ref $_[1] ' + . '? $val =~ s/$_[0]/$_[1]->()/e ' + . ': $val =~ s/$_[0]/$_[1]/; ' + . '$val; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return ( + 'ref $_[1]', + '? ' . $slot_access . ' =~ s/$_[0]/$_[1]->()/e', + ': ' . $slot_access . ' =~ s/$_[0]/$_[1]/;', + ); +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/String/substr.pm b/lib/Moose/Meta/Method/Accessor/Native/String/substr.pm new file mode 100644 index 0000000..df82e23 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/String/substr.pm @@ -0,0 +1,123 @@ +package Moose::Meta::Method::Accessor::Native::String::substr; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Util (); + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native::Reader', + 'Moose::Meta::Method::Accessor::Native::Writer'; + +sub _generate_method { + my $self = shift; + + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); + + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + 'if (@_ == 1 || @_ == 2) {', + $self->_inline_reader_core($inv, $slot_access), + '}', + 'elsif (@_ == 3) {', + $self->_inline_writer_core($inv, $slot_access), + '}', + 'else {', + $self->_inline_check_argument_count, + '}', + '}', + ); +} + +sub _minimum_arguments { 1 } +sub _maximum_arguments { 3 } + +sub _inline_process_arguments { + my $self = shift; + my ($inv, $slot_access) = @_; + + return ( + 'my $offset = shift;', + 'my $length = @_ ? shift : length ' . $slot_access . ';', + 'my $replacement = shift;', + ); +} + +sub _inline_check_arguments { + my $self = shift; + my ($for_writer) = @_; + + my @code = ( + 'if ($offset !~ /^-?\d+$/) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $offset,'. + 'ordinal => "first",'. + 'type_of_argument => "integer",'. + 'method_name => "substr",'. + 'type => "Int"', + ) . ';', + '}', + 'if ($length !~ /^-?\d+$/) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $length,'. + 'ordinal => "second",'. + 'type_of_argument => "integer",'. + 'method_name => "substr",'. + 'type => "Int"', + ) . ';', + '}', + ); + + if ($for_writer) { + push @code, ( + 'if (!Moose::Util::_STRINGLIKE0($replacement)) {', + $self->_inline_throw_exception( InvalidArgumentToMethod => + 'argument => $replacement,'. + 'ordinal => "third",'. + 'type_of_argument => "string",'. + 'method_name => "substr",'. + 'type => "Str"', + ) . ';', + '}', + ); + } + + return @code; +} + +sub _potential_value { + my $self = shift; + my ($slot_access) = @_; + + return '(do { ' + . 'my $potential = ' . $slot_access . '; ' + . '@return = substr $potential, $offset, $length, $replacement; ' + . '$potential; ' + . '})'; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + my ($inv, $new, $slot_access) = @_; + + return '@return = substr ' . $slot_access . ', ' + . '$offset, $length, $replacement;'; +} + +sub _return_value { + my $self = shift; + my ($slot_access, $for_writer) = @_; + + return '$return[0]' if $for_writer; + + return 'substr ' . $slot_access . ', $offset, $length'; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Accessor/Native/Writer.pm b/lib/Moose/Meta/Method/Accessor/Native/Writer.pm new file mode 100644 index 0000000..b25e063 --- /dev/null +++ b/lib/Moose/Meta/Method/Accessor/Native/Writer.pm @@ -0,0 +1,174 @@ +package Moose::Meta::Method::Accessor::Native::Writer; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::Util 1.33 qw( any ); +use Moose::Util; + +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native'; + +requires '_potential_value'; + +sub _generate_method { + my $self = shift; + + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); + + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + $self->_inline_writer_core($inv, $slot_access), + '}', + ); +} + +sub _inline_writer_core { + my $self = shift; + my ($inv, $slot_access) = @_; + + my $potential = $self->_potential_value($slot_access); + my $old = '@old'; + + my @code; + push @code, ( + $self->_inline_check_argument_count, + $self->_inline_process_arguments($inv, $slot_access), + $self->_inline_check_arguments('for writer'), + $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'), + ); + + if ($self->_return_value($slot_access)) { + # some writers will save the return value in this variable when they + # generate the potential value. + push @code, 'my @return;' + } + + push @code, ( + $self->_inline_coerce_new_values, + $self->_inline_copy_native_value(\$potential), + $self->_inline_tc_code($potential, '$type_constraint', '$type_coercion', '$type_message'), + $self->_inline_get_old_value_for_trigger($inv, $old), + $self->_inline_capture_return_value($slot_access), + $self->_inline_set_new_value($inv, $potential, $slot_access), + $self->_inline_trigger($inv, $slot_access, $old), + $self->_inline_return_value($slot_access, 'for writer'), + ); + + return @code; +} + +sub _inline_process_arguments { return } + +sub _inline_check_arguments { return } + +sub _inline_coerce_new_values { return } + +sub _writer_value_needs_copy { + my $self = shift; + + return $self->_constraint_must_be_checked; +} + +sub _constraint_must_be_checked { + my $self = shift; + + my $attr = $self->associated_attribute; + + return $attr->has_type_constraint + && ( !$self->_is_root_type( $attr->type_constraint ) + || ( $attr->should_coerce && $attr->type_constraint->has_coercion ) ); +} + +sub _is_root_type { + my $self = shift; + my $type = shift; + + if ( blessed($type) + && $type->can('does') + && $type->does('Specio::Constraint::Role::Interface') ) + { + require Specio::Library::Builtins; + return + any { $type->is_same_type_as( Specio::Library::Builtins::t($_) ) } + @{ $self->root_types }; + } + else { + my $name = $type->name; + return any { $name eq $_ } @{ $self->root_types }; + } +} + +sub _inline_copy_native_value { + my $self = shift; + my ($potential_ref) = @_; + + return unless $self->_writer_value_needs_copy; + + my $code = 'my $potential = ' . ${$potential_ref} . ';'; + + ${$potential_ref} = '$potential'; + + return $code; +} + +around _inline_tc_code => sub { + my $orig = shift; + my $self = shift; + my ($value, $tc, $coercion, $message, $for_lazy) = @_; + + return unless $for_lazy || $self->_constraint_must_be_checked; + + return $self->$orig(@_); +}; + +around _inline_check_constraint => sub { + my $orig = shift; + my $self = shift; + my ($value, $tc, $message, $for_lazy) = @_; + + return unless $for_lazy || $self->_constraint_must_be_checked; + + return $self->$orig(@_); +}; + +sub _inline_capture_return_value { return } + +sub _inline_set_new_value { + my $self = shift; + + return $self->_inline_store_value(@_) + if $self->_writer_value_needs_copy + || !$self->_slot_access_can_be_inlined + || !$self->_get_is_lvalue; + + return $self->_inline_optimized_set_new_value(@_); +} + +sub _get_is_lvalue { + my $self = shift; + + return $self->associated_attribute->associated_class->instance_metaclass->inline_get_is_lvalue; +} + +sub _inline_optimized_set_new_value { + my $self = shift; + + return $self->_inline_store_value(@_); +} + +sub _return_value { + my $self = shift; + my ($slot_access) = @_; + + return $slot_access; +} + +no Moose::Role; + +1; diff --git a/lib/Moose/Meta/Method/Augmented.pm b/lib/Moose/Meta/Method/Augmented.pm new file mode 100644 index 0000000..56a07d1 --- /dev/null +++ b/lib/Moose/Meta/Method/Augmented.pm @@ -0,0 +1,175 @@ +package Moose::Meta::Method::Augmented; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use parent 'Moose::Meta::Method'; + +use Moose::Util 'throw_exception'; + +sub new { + my ( $class, %args ) = @_; + + # the package can be overridden by roles + # it is really more like body's compilation stash + # this is where we need to override the definition of super() so that the + # body of the code can call the right overridden version + my $name = $args{name}; + my $meta = $args{class}; + + my $super = $meta->find_next_method_by_name($name); + + (defined $super) + || throw_exception( CannotAugmentNoSuperMethod => params => \%args, + class => $class, + method_name => $name + ); + + my $_super_package = $super->package_name; + # BUT!,... if this is an overridden method .... + if ($super->isa('Moose::Meta::Method::Overridden')) { + # we need to be sure that we actually + # find the next method, which is not + # an 'override' method, the reason is + # that an 'override' method will not + # be the one calling inner() + my $real_super = $meta->_find_next_method_by_name_which_is_not_overridden($name); + $_super_package = $real_super->package_name; + } + + my $super_body = $super->body; + + my $method = $args{method}; + + my $body = sub { + local $Moose::INNER_ARGS{$_super_package} = [ @_ ]; + local $Moose::INNER_BODY{$_super_package} = $method; + $super_body->(@_); + }; + + # FIXME store additional attrs + $class->wrap( + $body, + package_name => $meta->name, + name => $name + ); +} + +1; + +# ABSTRACT: A Moose Method metaclass for augmented methods + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Augmented - A Moose Method metaclass for augmented methods + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class implements method augmentation logic for the L<Moose> +C<augment> keyword. + +The augmentation subroutine reference will be invoked explicitly using +the C<inner> keyword from the parent class's method definition. + +=head1 INHERITANCE + +C<Moose::Meta::Method::Augmented> is a subclass of L<Moose::Meta::Method>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Method::Augmented->new(%options) >> + +This constructs a new object. It accepts the following options: + +=over 8 + +=item * class + +The metaclass object for the class in which the augmentation is being +declared. This option is required. + +=item * name + +The name of the method which we are augmenting. This method must exist +in one of the class's superclasses. This option is required. + +=item * method + +The subroutine reference which implements the augmentation. This +option is required. + +=back + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Constructor.pm b/lib/Moose/Meta/Method/Constructor.pm new file mode 100644 index 0000000..c6aaebb --- /dev/null +++ b/lib/Moose/Meta/Method/Constructor.pm @@ -0,0 +1,145 @@ +package Moose::Meta::Method::Constructor; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Scalar::Util 'weaken'; + +use parent 'Moose::Meta::Method', + 'Class::MOP::Method::Constructor'; + +use Moose::Util 'throw_exception'; + +sub new { + my $class = shift; + my %options = @_; + + my $meta = $options{metaclass}; + + (ref $options{options} eq 'HASH') + || throw_exception( MustPassAHashOfOptions => params => \%options, + class => $class + ); + + ($options{package_name} && $options{name}) + || throw_exception( MustSupplyPackageNameAndName => params => \%options, + class => $class + ); + + my $self = bless { + 'body' => undef, + 'package_name' => $options{package_name}, + 'name' => $options{name}, + 'options' => $options{options}, + 'associated_metaclass' => $meta, + 'definition_context' => $options{definition_context}, + '_expected_method_class' => $options{_expected_method_class} || 'Moose::Object', + } => $class; + + # we don't want this creating + # a cycle in the code, if not + # needed + weaken($self->{'associated_metaclass'}); + + $self->_initialize_body; + + return $self; +} + +## method + +sub _initialize_body { + my $self = shift; + $self->{'body'} = $self->_generate_constructor_method_inline; +} + +1; + +# ABSTRACT: Method Meta Object for constructors + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Constructor - Method Meta Object for constructors + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Method::Constructor> that +provides additional Moose-specific functionality + +To understand this class, you should read the the +L<Class::MOP::Method::Constructor> documentation as well. + +=head1 INHERITANCE + +C<Moose::Meta::Method::Constructor> is a subclass of +L<Moose::Meta::Method> I<and> L<Class::MOP::Method::Constructor>. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Delegation.pm b/lib/Moose/Meta/Method/Delegation.pm new file mode 100644 index 0000000..752bd27 --- /dev/null +++ b/lib/Moose/Meta/Method/Delegation.pm @@ -0,0 +1,258 @@ +package Moose::Meta::Method::Delegation; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Scalar::Util 'blessed', 'weaken'; + +use parent 'Moose::Meta::Method', + 'Class::MOP::Method::Generated'; + +use Moose::Util 'throw_exception'; + +sub new { + my $class = shift; + my %options = @_; + + ( exists $options{attribute} ) + || throw_exception( MustSupplyAnAttributeToConstructWith => params => \%options, + class => $class + ); + + ( blessed( $options{attribute} ) + && $options{attribute}->isa('Moose::Meta::Attribute') ) + || throw_exception( MustSupplyAMooseMetaAttributeInstance => params => \%options, + class => $class + ); + + ( $options{package_name} && $options{name} ) + || throw_exception( MustSupplyPackageNameAndName => params => \%options, + class => $class + ); + + ( $options{delegate_to_method} && ( !ref $options{delegate_to_method} ) + || ( 'CODE' eq ref $options{delegate_to_method} ) ) + || throw_exception( MustSupplyADelegateToMethod => params => \%options, + class => $class + ); + + exists $options{curried_arguments} + || ( $options{curried_arguments} = [] ); + + ( $options{curried_arguments} && + ( 'ARRAY' eq ref $options{curried_arguments} ) ) + || throw_exception( MustSupplyArrayRefAsCurriedArguments => params => \%options, + class_name => $class + ); + + my $self = $class->_new( \%options ); + + weaken( $self->{'attribute'} ); + + $self->_initialize_body; + + return $self; +} + +sub _new { + my $class = shift; + my $options = @_ == 1 ? $_[0] : {@_}; + + return bless $options, $class; +} + +sub curried_arguments { (shift)->{'curried_arguments'} } + +sub associated_attribute { (shift)->{'attribute'} } + +sub delegate_to_method { (shift)->{'delegate_to_method'} } + +sub _initialize_body { + my $self = shift; + + my $method_to_call = $self->delegate_to_method; + return $self->{body} = $method_to_call + if ref $method_to_call; + + my $accessor = $self->_get_delegate_accessor; + + my $handle_name = $self->name; + + # NOTE: we used to do a goto here, but the goto didn't handle + # failure correctly (it just returned nothing), so I took that + # out. However, the more I thought about it, the less I liked it + # doing the goto, and I preferred the act of delegation being + # actually represented in the stack trace. - SL + # not inlining this, since it won't really speed things up at + # all... the only thing that would end up different would be + # interpolating in $method_to_call, and a bunch of things in the + # error handling that mostly never gets called - doy + $self->{body} = sub { + my $instance = shift; + my $proxy = $instance->$accessor(); + + if( !defined $proxy ) { + throw_exception( AttributeValueIsNotDefined => method => $self, + instance => $instance, + attribute => $self->associated_attribute, + ); + } + elsif( ref($proxy) && !blessed($proxy) ) { + throw_exception( AttributeValueIsNotAnObject => method => $self, + instance => $instance, + attribute => $self->associated_attribute, + given_value => $proxy + ); + } + + unshift @_, @{ $self->curried_arguments }; + $proxy->$method_to_call(@_); + }; +} + +sub _get_delegate_accessor { + my $self = shift; + my $attr = $self->associated_attribute; + + # NOTE: + # always use a named method when + # possible, if you use the method + # ref and there are modifiers on + # the accessors then it will not + # pick up the modifiers too. Only + # the named method will assure that + # we also have any modifiers run. + # - SL + my $accessor = $attr->has_read_method + ? $attr->get_read_method + : $attr->get_read_method_ref; + + $accessor = $accessor->body if Scalar::Util::blessed $accessor; + + return $accessor; +} + +1; + +# ABSTRACT: A Moose Method metaclass for delegation methods + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Delegation - A Moose Method metaclass for delegation methods + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This is a subclass of L<Moose::Meta::Method> for delegation +methods. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Method::Delegation->new(%options) >> + +This creates the delegation methods based on the provided C<%options>. + +=over 4 + +=item I<attribute> + +This must be an instance of C<Moose::Meta::Attribute> which this +accessor is being generated for. This options is B<required>. + +=item I<delegate_to_method> + +The method in the associated attribute's value to which we +delegate. This can be either a method name or a code reference. + +=item I<curried_arguments> + +An array reference of arguments that will be prepended to the argument list for +any call to the delegating method. + +=back + +=item B<< $metamethod->associated_attribute >> + +Returns the attribute associated with this method. + +=item B<< $metamethod->curried_arguments >> + +Return any curried arguments that will be passed to the delegated method. + +=item B<< $metamethod->delegate_to_method >> + +Returns the method to which this method delegates, as passed to the +constructor. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Destructor.pm b/lib/Moose/Meta/Method/Destructor.pm new file mode 100644 index 0000000..cd37245 --- /dev/null +++ b/lib/Moose/Meta/Method/Destructor.pm @@ -0,0 +1,255 @@ +package Moose::Meta::Method::Destructor; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Devel::GlobalDestruction (); +use Scalar::Util 'blessed', 'weaken'; +use Try::Tiny; + +use parent 'Moose::Meta::Method', + 'Class::MOP::Method::Inlined'; + +use Moose::Util 'throw_exception'; + +sub new { + my $class = shift; + my %options = @_; + + (ref $options{options} eq 'HASH') + || throw_exception( MustPassAHashOfOptions => params => \%options, + class => $class + ); + + ($options{package_name} && $options{name}) + || throw_exception( MustSupplyPackageNameAndName => params => \%options, + class => $class + ); + + my $self = bless { + # from our superclass + 'body' => undef, + 'package_name' => $options{package_name}, + 'name' => $options{name}, + # ... + 'options' => $options{options}, + 'definition_context' => $options{definition_context}, + 'associated_metaclass' => $options{metaclass}, + } => $class; + + # we don't want this creating + # a cycle in the code, if not + # needed + weaken($self->{'associated_metaclass'}); + + $self->_initialize_body; + + return $self; +} + +## accessors + +sub options { (shift)->{'options'} } + +## method + +sub is_needed { + my $self = shift; + my $metaclass = shift; + + ( blessed $metaclass && $metaclass->isa('Class::MOP::Class') ) + || throw_exception( MethodExpectedAMetaclassObject => metaclass => $metaclass, + class => $self + ); + + return $metaclass->find_method_by_name("DEMOLISHALL"); +} + +sub _initialize_body { + my $self = shift; + # TODO: + # the %options should also include a both + # a call 'initializer' and call 'SUPER::' + # options, which should cover approx 90% + # of the possible use cases (even if it + # requires some adaption on the part of + # the author, after all, nothing is free) + + my $class = $self->associated_metaclass->name; + my @source = ( + 'sub {', + 'my $self = shift;', + 'return ' . $self->_generate_fallback_destructor('$self'), + 'if Scalar::Util::blessed($self) ne \'' . $class . '\';', + $self->_generate_DEMOLISHALL('$self'), + 'return;', + '}', + ); + warn join("\n", @source) if $self->options->{debug}; + + my $code = try { + $self->_compile_code(source => \@source); + } + catch { + my $source = join("\n", @source); + throw_exception( CouldNotEvalDestructor => method_destructor_object => $self, + source => $source, + error => $_ + ); + }; + + $self->{'body'} = $code; +} + +sub _generate_fallback_destructor { + my $self = shift; + my ($inv) = @_; + + return $inv . '->Moose::Object::DESTROY(@_)'; +} + +sub _generate_DEMOLISHALL { + my $self = shift; + my ($inv) = @_; + + my @methods = $self->associated_metaclass->find_all_methods_by_name('DEMOLISH'); + return unless @methods; + + return ( + 'local $?;', + 'my $igd = Devel::GlobalDestruction::in_global_destruction;', + 'Try::Tiny::try {', + (map { $inv . '->' . $_->{class} . '::DEMOLISH($igd);' } @methods), + '}', + 'Try::Tiny::catch {', + 'die $_;', + '};', + ); +} + + +1; + +# ABSTRACT: Method Meta Object for destructors + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Destructor - Method Meta Object for destructors + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Method::Inlined> that +provides Moose-specific functionality for inlining destructors. + +To understand this class, you should read the +L<Class::MOP::Method::Inlined> documentation as well. + +=head1 INHERITANCE + +C<Moose::Meta::Method::Destructor> is a subclass of +L<Moose::Meta::Method> I<and> L<Class::MOP::Method::Inlined>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Method::Destructor->new(%options) >> + +This constructs a new object. It accepts the following options: + +=over 8 + +=item * package_name + +The package for the class in which the destructor is being +inlined. This option is required. + +=item * name + +The name of the destructor method. This option is required. + +=item * metaclass + +The metaclass for the class this destructor belongs to. This is +optional, as it can be set later by calling C<< +$metamethod->attach_to_class >>. + +=back + +=item B<< Moose::Meta;:Method::Destructor->is_needed($metaclass) >> + +Given a L<Moose::Meta::Class> object, this method returns a boolean +indicating whether the class needs a destructor. If the class or any +of its parents defines a C<DEMOLISH> method, it needs a destructor. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Meta.pm b/lib/Moose/Meta/Method/Meta.pm new file mode 100644 index 0000000..7796683 --- /dev/null +++ b/lib/Moose/Meta/Method/Meta.pm @@ -0,0 +1,112 @@ +package Moose::Meta::Method::Meta; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use parent 'Moose::Meta::Method', + 'Class::MOP::Method::Meta'; + +sub _is_caller_mop_internal { + my $self = shift; + my ($caller) = @_; + return 1 if $caller =~ /^Moose(?:::|$)/; + return $self->SUPER::_is_caller_mop_internal($caller); +} + +# XXX: ugh multiple inheritance +sub wrap { + my $class = shift; + return $class->Class::MOP::Method::Meta::wrap(@_); +} + +sub _make_compatible_with { + my $self = shift; + return $self->Class::MOP::Method::Meta::_make_compatible_with(@_); +} + +1; + +# ABSTRACT: A Moose Method metaclass for C<meta> methods + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Meta - A Moose Method metaclass for C<meta> methods + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Method::Meta> that +provides additional Moose-specific functionality, all of which is +private. + +To understand this class, you should read the the +L<Class::MOP::Method::Meta> documentation. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Method/Overridden.pm b/lib/Moose/Meta/Method/Overridden.pm new file mode 100644 index 0000000..4c9aee7 --- /dev/null +++ b/lib/Moose/Meta/Method/Overridden.pm @@ -0,0 +1,164 @@ +package Moose::Meta::Method::Overridden; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use parent 'Moose::Meta::Method'; + +use Moose::Util 'throw_exception'; + +sub new { + my ( $class, %args ) = @_; + + # the package can be overridden by roles + # it is really more like body's compilation stash + # this is where we need to override the definition of super() so that the + # body of the code can call the right overridden version + my $super_package = $args{package} || $args{class}->name; + + my $name = $args{name}; + + my $super = $args{class}->find_next_method_by_name($name); + + (defined $super) + || throw_exception( CannotOverrideNoSuperMethod => class => $class, + params => \%args, + method_name => $name + ); + + my $super_body = $super->body; + + my $method = $args{method}; + + my $body = sub { + local $Moose::SUPER_PACKAGE = $super_package; + local @Moose::SUPER_ARGS = @_; + local $Moose::SUPER_BODY = $super_body; + return $method->(@_); + }; + + # FIXME do we need this make sure this works for next::method? + # subname "${super_package}::${name}", $method; + + # FIXME store additional attrs + $class->wrap( + $body, + package_name => $args{class}->name, + name => $name + ); +} + +1; + +# ABSTRACT: A Moose Method metaclass for overridden methods + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Method::Overridden - A Moose Method metaclass for overridden methods + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class implements method overriding logic for the L<Moose> +C<override> keyword. + +The overriding subroutine's parent will be invoked explicitly using +the C<super> keyword from the parent class's method definition. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Method::Overridden->new(%options) >> + +This constructs a new object. It accepts the following options: + +=over 8 + +=item * class + +The metaclass object for the class in which the override is being +declared. This option is required. + +=item * name + +The name of the method which we are overriding. This method must exist +in one of the class's superclasses. This option is required. + +=item * method + +The subroutine reference which implements the overriding. This option +is required. + +=back + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Mixin/AttributeCore.pm b/lib/Moose/Meta/Mixin/AttributeCore.pm new file mode 100644 index 0000000..8503d8f --- /dev/null +++ b/lib/Moose/Meta/Mixin/AttributeCore.pm @@ -0,0 +1,184 @@ +package Moose::Meta::Mixin::AttributeCore; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use parent 'Class::MOP::Mixin::AttributeCore'; + +__PACKAGE__->meta->add_attribute( + 'isa' => ( + reader => '_isa_metadata', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'does' => ( + reader => '_does_metadata', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'is' => ( + reader => '_is_metadata', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'required' => ( + reader => 'is_required', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'lazy' => ( + reader => 'is_lazy', Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'lazy_build' => ( + reader => 'is_lazy_build', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'coerce' => ( + reader => 'should_coerce', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'weak_ref' => ( + reader => 'is_weak_ref', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'auto_deref' => ( + reader => 'should_auto_deref', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'type_constraint' => ( + reader => 'type_constraint', + predicate => 'has_type_constraint', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'trigger' => ( + reader => 'trigger', + predicate => 'has_trigger', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'handles' => ( + reader => 'handles', + writer => '_set_handles', + predicate => 'has_handles', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'documentation' => ( + reader => 'documentation', + predicate => 'has_documentation', + Class::MOP::_definition_context(), + ) +); + +1; + +# ABSTRACT: Core attributes shared by attribute metaclasses + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Mixin::AttributeCore - Core attributes shared by attribute metaclasses + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class implements the core attributes (aka properties) shared by all Moose +attributes. See the L<Moose::Meta::Attribute> documentation for API details. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Object/Trait.pm b/lib/Moose/Meta/Object/Trait.pm new file mode 100644 index 0000000..ed23f22 --- /dev/null +++ b/lib/Moose/Meta/Object/Trait.pm @@ -0,0 +1,107 @@ +package Moose::Meta::Object::Trait; +our $VERSION = '2.1405'; + +use Scalar::Util qw(blessed); + +sub _get_compatible_metaclass { + my $orig = shift; + my $self = shift; + return $self->$orig(@_) + || $self->_get_compatible_metaclass_by_role_reconciliation(@_); +} + +sub _get_compatible_metaclass_by_role_reconciliation { + my $self = shift; + my ($other_name) = @_; + my $meta_name = blessed($self) ? $self->_real_ref_name : $self; + + return unless Moose::Util::_classes_differ_by_roles_only( + $meta_name, $other_name + ); + + return Moose::Util::_reconcile_roles_for_metaclass( + $meta_name, $other_name + ); +} + +1; + +# ABSTRACT: Some overrides for L<Class::MOP::Object> functionality + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Object::Trait - Some overrides for L<Class::MOP::Object> functionality + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This module is entirely private, you shouldn't ever need to interact with +it directly. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role.pm b/lib/Moose/Meta/Role.pm new file mode 100644 index 0000000..fbd8c1e --- /dev/null +++ b/lib/Moose/Meta/Role.pm @@ -0,0 +1,1095 @@ +package Moose::Meta::Role; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; + +use Moose::Meta::Class; +use Moose::Meta::Role::Attribute; +use Moose::Meta::Role::Method; +use Moose::Meta::Role::Method::Required; +use Moose::Meta::Role::Method::Conflicting; +use Moose::Meta::Method::Meta; +use Moose::Util qw/throw_exception/; +use Class::MOP::MiniTrait; + +use parent 'Class::MOP::Module', + 'Class::MOP::Mixin::HasAttributes', + 'Class::MOP::Mixin::HasMethods', + 'Class::MOP::Mixin::HasOverloads'; + +Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait'); + +## ------------------------------------------------------------------ +## NOTE: +## I normally don't do this, but I am doing +## a whole bunch of meta-programmin' in this +## module, so it just makes sense. For a clearer +## picture of what is going on in the next +## several lines of code, look at the really +## big comment at the end of this file (right +## before the POD). +## - SL +## ------------------------------------------------------------------ + +my $META = __PACKAGE__->meta; + +## ------------------------------------------------------------------ +## attributes ... + +# NOTE: +# since roles are lazy, we hold all the attributes +# of the individual role in 'stasis' until which +# time when it is applied to a class. This means +# keeping a lot of things in hash maps, so we are +# using a little of that meta-programmin' magic +# here and saving lots of extra typin'. And since +# many of these attributes above require similar +# functionality to support them, so we again use +# the wonders of meta-programmin' to deliver a +# very compact solution to this normally verbose +# problem. +# - SL + +foreach my $action ( + { + name => 'excluded_roles_map', + attr_reader => 'get_excluded_roles_map' , + methods => { + add => 'add_excluded_roles', + get_keys => 'get_excluded_roles_list', + existence => 'excludes_role', + } + }, + { + name => 'required_methods', + attr_reader => 'get_required_methods_map', + methods => { + remove => 'remove_required_methods', + get_values => 'get_required_method_list', + existence => 'requires_method', + } + }, +) { + + my $attr_reader = $action->{attr_reader}; + my $methods = $action->{methods}; + + # create the attribute + $META->add_attribute($action->{name} => ( + reader => $attr_reader, + default => sub { {} }, + Class::MOP::_definition_context(), + )); + + # create some helper methods + $META->add_method($methods->{add} => sub { + my ($self, @values) = @_; + $self->$attr_reader->{$_} = undef foreach @values; + }) if exists $methods->{add}; + + $META->add_method($methods->{get_keys} => sub { + my ($self) = @_; + keys %{$self->$attr_reader}; + }) if exists $methods->{get_keys}; + + $META->add_method($methods->{get_values} => sub { + my ($self) = @_; + values %{$self->$attr_reader}; + }) if exists $methods->{get_values}; + + $META->add_method($methods->{get} => sub { + my ($self, $name) = @_; + $self->$attr_reader->{$name} + }) if exists $methods->{get}; + + $META->add_method($methods->{existence} => sub { + my ($self, $name) = @_; + exists $self->$attr_reader->{$name} ? 1 : 0; + }) if exists $methods->{existence}; + + $META->add_method($methods->{remove} => sub { + my ($self, @values) = @_; + delete $self->$attr_reader->{$_} foreach @values; + }) if exists $methods->{remove}; +} + +$META->add_attribute( + 'method_metaclass', + reader => 'method_metaclass', + default => 'Moose::Meta::Role::Method', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'required_method_metaclass', + reader => 'required_method_metaclass', + default => 'Moose::Meta::Role::Method::Required', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'conflicting_method_metaclass', + reader => 'conflicting_method_metaclass', + default => 'Moose::Meta::Role::Method::Conflicting', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'application_to_class_class', + reader => 'application_to_class_class', + default => 'Moose::Meta::Role::Application::ToClass', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'application_to_role_class', + reader => 'application_to_role_class', + default => 'Moose::Meta::Role::Application::ToRole', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'application_to_instance_class', + reader => 'application_to_instance_class', + default => 'Moose::Meta::Role::Application::ToInstance', + Class::MOP::_definition_context(), +); + +$META->add_attribute( + 'applied_attribute_metaclass', + reader => 'applied_attribute_metaclass', + default => 'Moose::Meta::Attribute', + Class::MOP::_definition_context(), +); + +# More or less copied from Moose::Meta::Class +sub initialize { + my $class = shift; + my @args = @_; + unshift @args, 'package' if @args % 2; + my %opts = @args; + my $package = delete $opts{package}; + return Class::MOP::get_metaclass_by_name($package) + || $class->SUPER::initialize($package, + 'attribute_metaclass' => 'Moose::Meta::Role::Attribute', + %opts, + ); +} + +sub reinitialize { + my $self = shift; + my $pkg = shift; + + my $meta = blessed $pkg ? $pkg : Class::MOP::class_of($pkg); + + my %existing_classes; + if ($meta) { + %existing_classes = map { $_ => $meta->$_() } qw( + attribute_metaclass + method_metaclass + wrapped_method_metaclass + required_method_metaclass + conflicting_method_metaclass + application_to_class_class + application_to_role_class + application_to_instance_class + applied_attribute_metaclass + ); + } + + my %options = @_; + $options{weaken} = Class::MOP::metaclass_is_weak($meta->name) + if !exists $options{weaken} + && blessed($meta) + && $meta->isa('Moose::Meta::Role'); + + # don't need to remove generated metaobjects here yet, since we don't + # yet generate anything in roles. this may change in the future though... + # keep an eye on that + my $new_meta = $self->SUPER::reinitialize( + $pkg, + %existing_classes, + %options, + ); + $new_meta->_restore_metaobjects_from($meta) + if $meta && $meta->isa('Moose::Meta::Role'); + return $new_meta; +} + +sub _restore_metaobjects_from { + my $self = shift; + my ($old_meta) = @_; + + $self->_restore_metamethods_from($old_meta); + $self->_restore_metaattributes_from($old_meta); + + for my $role ( @{ $old_meta->get_roles } ) { + $self->add_role($role); + } +} + +sub add_attribute { + my $self = shift; + + if (blessed $_[0] && ! $_[0]->isa('Moose::Meta::Role::Attribute') ) { + my $class = ref $_[0]; + throw_exception( CannotAddAsAnAttributeToARole => role_name => $self->name, + attribute_class => $class, + ); + } + elsif (!blessed($_[0]) && defined($_[0]) && $_[0] =~ /^\+(.*)/) { + throw_exception( AttributeExtensionIsNotSupportedInRoles => attribute_name => $_[0], + role_name => $self->name, + ); + } + + return $self->SUPER::add_attribute(@_); +} + +sub _attach_attribute { + my ( $self, $attribute ) = @_; + + $attribute->attach_to_role($self); +} + +sub add_required_methods { + my $self = shift; + + for (@_) { + my $method = $_; + if (!blessed($method)) { + $method = $self->required_method_metaclass->new( + name => $method, + ); + } + $self->get_required_methods_map->{$method->name} = $method; + } +} + +sub add_conflicting_method { + my $self = shift; + + my $method; + if (@_ == 1 && blessed($_[0])) { + $method = shift; + } + else { + $method = $self->conflicting_method_metaclass->new(@_); + } + + $self->add_required_methods($method); +} + +## ------------------------------------------------------------------ +## method modifiers + +# NOTE: +# the before/around/after method modifiers are +# stored by name, but there can be many methods +# then associated with that name. So again we have +# lots of similar functionality, so we can do some +# meta-programmin' and save some time. +# - SL + +foreach my $modifier_type (qw[ before around after ]) { + + my $attr_reader = "get_${modifier_type}_method_modifiers_map"; + + # create the attribute ... + $META->add_attribute("${modifier_type}_method_modifiers" => ( + reader => $attr_reader, + default => sub { {} }, + Class::MOP::_definition_context(), + )); + + # and some helper methods ... + $META->add_method("get_${modifier_type}_method_modifiers" => sub { + my ($self, $method_name) = @_; + #return () unless exists $self->$attr_reader->{$method_name}; + my $mm = $self->$attr_reader->{$method_name}; + $mm ? @$mm : (); + }); + + $META->add_method("has_${modifier_type}_method_modifiers" => sub { + my ($self, $method_name) = @_; + # NOTE: + # for now we assume that if it exists,.. + # it has at least one modifier in it + (exists $self->$attr_reader->{$method_name}) ? 1 : 0; + }); + + $META->add_method("add_${modifier_type}_method_modifier" => sub { + my ($self, $method_name, $method) = @_; + + $self->$attr_reader->{$method_name} = [] + unless exists $self->$attr_reader->{$method_name}; + + my $modifiers = $self->$attr_reader->{$method_name}; + + # NOTE: + # check to see that we aren't adding the + # same code twice. We err in favor of the + # first on here, this may not be as expected + foreach my $modifier (@{$modifiers}) { + return if $modifier == $method; + } + + push @{$modifiers} => $method; + }); + +} + +## ------------------------------------------------------------------ +## override method modifiers + +$META->add_attribute('override_method_modifiers' => ( + reader => 'get_override_method_modifiers_map', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +# NOTE: +# these are a little different because there +# can only be one per name, whereas the other +# method modifiers can have multiples. +# - SL + +sub add_override_method_modifier { + my ($self, $method_name, $method) = @_; + (!$self->has_method($method_name)) + || throw_exception( CannotOverrideALocalMethod => method_name => $method_name, + role_name => $self->name, + ); + $self->get_override_method_modifiers_map->{$method_name} = $method; +} + +sub has_override_method_modifier { + my ($self, $method_name) = @_; + # NOTE: + # for now we assume that if it exists,.. + # it has at least one modifier in it + (exists $self->get_override_method_modifiers_map->{$method_name}) ? 1 : 0; +} + +sub get_override_method_modifier { + my ($self, $method_name) = @_; + $self->get_override_method_modifiers_map->{$method_name}; +} + +## general list accessor ... + +sub get_method_modifier_list { + my ($self, $modifier_type) = @_; + my $accessor = "get_${modifier_type}_method_modifiers_map"; + keys %{$self->$accessor}; +} + +sub _meta_method_class { 'Moose::Meta::Method::Meta' } + +## ------------------------------------------------------------------ +## subroles + +$META->add_attribute('roles' => ( + reader => 'get_roles', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +sub add_role { + my ($self, $role) = @_; + (blessed($role) && $role->isa('Moose::Meta::Role')) + || throw_exception( AddRoleToARoleTakesAMooseMetaRole => role_to_be_added => $role, + role_name => $self->name, + ); + push @{$self->get_roles} => $role; + $self->reset_package_cache_flag; +} + +sub calculate_all_roles { + my $self = shift; + my %seen; + grep { + !$seen{$_->name}++ + } ($self, map { + $_->calculate_all_roles + } @{ $self->get_roles }); +} + +sub does_role { + my ($self, $role) = @_; + (defined $role) + || throw_exception( RoleNameRequiredForMooseMetaRole => role_name => $self->name ); + my $role_name = blessed $role ? $role->name : $role; + # if we are it,.. then return true + return 1 if $role_name eq $self->name; + # otherwise.. check our children + foreach my $role (@{$self->get_roles}) { + return 1 if $role->does_role($role_name); + } + return 0; +} + +sub find_method_by_name { (shift)->get_method(@_) } + +## ------------------------------------------------------------------ +## role construction +## ------------------------------------------------------------------ + +sub apply { + my ($self, $other, %args) = @_; + + (blessed($other)) + || throw_exception( ApplyTakesABlessedInstance => param => $other, + role_name => $self->name, + ); + + my $application_class; + if ($other->isa('Moose::Meta::Role')) { + $application_class = $self->application_to_role_class; + } + elsif ($other->isa('Moose::Meta::Class')) { + $application_class = $self->application_to_class_class; + } + else { + $application_class = $self->application_to_instance_class; + } + + Moose::Util::_load_user_class($application_class); + + if ( exists $args{'-excludes'} ) { + # I wish we had coercion here :) + $args{'-excludes'} = ( + ref $args{'-excludes'} eq 'ARRAY' + ? $args{'-excludes'} + : [ $args{'-excludes'} ] + ); + } + + return $application_class->new(%args)->apply($self, $other, \%args); +} + +sub composition_class_roles { } + +sub combine { + my ($class, @role_specs) = @_; + + require Moose::Meta::Role::Composite; + + my (@roles, %role_params); + while (@role_specs) { + my ($role, $params) = @{ splice @role_specs, 0, 1 }; + my $requested_role + = blessed $role + ? $role + : Class::MOP::class_of($role); + + my $actual_role = $requested_role->_role_for_combination($params); + push @roles => $actual_role; + + next unless defined $params; + $role_params{$actual_role->name} = $params; + } + + my $c = Moose::Meta::Role::Composite->new(roles => \@roles); + return $c->apply_params(\%role_params); +} + +sub _role_for_combination { + my ($self, $params) = @_; + return $self; +} + +sub create { + my $class = shift; + my @args = @_; + + unshift @args, 'package' if @args % 2 == 1; + my %options = @args; + + (ref $options{attributes} eq 'HASH') + || throw_exception( CreateTakesHashRefOfAttributes => params => \%options, + attribute_class => $class + ) + if exists $options{attributes}; + + (ref $options{methods} eq 'HASH') + || throw_exception( CreateTakesHashRefOfMethods => params => \%options, + attribute_class => $class + ) + if exists $options{methods}; + + (ref $options{roles} eq 'ARRAY') + || throw_exception( CreateTakesArrayRefOfRoles => params => \%options, + attribute_class => $class + ) + if exists $options{roles}; + + my $package = delete $options{package}; + my $roles = delete $options{roles}; + my $attributes = delete $options{attributes}; + my $methods = delete $options{methods}; + my $meta_name = exists $options{meta_name} + ? delete $options{meta_name} + : 'meta'; + + my $meta = $class->SUPER::create($package => %options); + + $meta->_add_meta_method($meta_name) + if defined $meta_name; + + if (defined $attributes) { + foreach my $attribute_name (keys %{$attributes}) { + my $attr = $attributes->{$attribute_name}; + $meta->add_attribute( + $attribute_name => blessed $attr ? $attr : %{$attr} ); + } + } + + if (defined $methods) { + foreach my $method_name (keys %{$methods}) { + $meta->add_method($method_name, $methods->{$method_name}); + } + } + + if ($roles) { + Moose::Util::apply_all_roles($meta, @$roles); + } + + return $meta; +} + +sub consumers { + my $self = shift; + my @consumers; + for my $meta (Class::MOP::get_all_metaclass_instances) { + next if $meta->name eq $self->name; + next unless $meta->isa('Moose::Meta::Class') + || $meta->isa('Moose::Meta::Role'); + push @consumers, $meta->name + if $meta->does_role($self->name); + } + return @consumers; +} + +# XXX: something more intelligent here? +sub _anon_package_prefix { 'Moose::Meta::Role::__ANON__::SERIAL::' } + +sub create_anon_role { shift->create_anon(@_) } +sub is_anon_role { shift->is_anon(@_) } + +sub _anon_cache_key { + my $class = shift; + my %options = @_; + + # XXX fix this duplication (see MMC::_anon_cache_key + my $roles = Data::OptList::mkopt(($options{roles} || []), { + moniker => 'role', + val_test => sub { ref($_[0]) eq 'HASH' }, + }); + + my @role_keys; + for my $role_spec (@$roles) { + my ($role, $params) = @$role_spec; + $params = { %$params }; + + my $key = blessed($role) ? $role->name : $role; + + if ($params && %$params) { + my $alias = delete $params->{'-alias'} + || delete $params->{'alias'} + || {}; + my $excludes = delete $params->{'-excludes'} + || delete $params->{'excludes'} + || []; + $excludes = [$excludes] unless ref($excludes) eq 'ARRAY'; + + if (%$params) { + warn "Roles with parameters cannot be cached. Consider " + . "applying the parameters before calling " + . "create_anon_class, or using 'weaken => 0' instead"; + return; + } + + my $alias_key = join('%', + map { $_ => $alias->{$_} } sort keys %$alias + ); + my $excludes_key = join('%', + sort @$excludes + ); + $key .= '<' . join('+', 'a', $alias_key, 'e', $excludes_key) . '>'; + } + + push @role_keys, $key; + } + + # Makes something like Role|Role::1 + return join('|', sort @role_keys); +} + +##################################################################### +## NOTE: +## This is Moose::Meta::Role as defined by Moose (plus the use of +## MooseX::AttributeHelpers module). It is here as a reference to +## make it easier to see what is happening above with all the meta +## programming. - SL +##################################################################### +# +# has 'roles' => ( +# metaclass => 'Array', +# reader => 'get_roles', +# isa => 'ArrayRef[Moose::Meta::Role]', +# default => sub { [] }, +# provides => { +# 'push' => 'add_role', +# } +# ); +# +# has 'excluded_roles_map' => ( +# metaclass => 'Hash', +# reader => 'get_excluded_roles_map', +# isa => 'HashRef[Str]', +# provides => { +# # Not exactly set, cause it sets multiple +# 'set' => 'add_excluded_roles', +# 'keys' => 'get_excluded_roles_list', +# 'exists' => 'excludes_role', +# } +# ); +# +# has 'required_methods' => ( +# metaclass => 'Hash', +# reader => 'get_required_methods_map', +# isa => 'HashRef[Moose::Meta::Role::Method::Required]', +# provides => { +# # not exactly set, or delete since it works for multiple +# 'set' => 'add_required_methods', +# 'delete' => 'remove_required_methods', +# 'keys' => 'get_required_method_list', +# 'exists' => 'requires_method', +# } +# ); +# +# # the before, around and after modifiers are +# # HASH keyed by method-name, with ARRAY of +# # CODE refs to apply in that order +# +# has 'before_method_modifiers' => ( +# metaclass => 'Hash', +# reader => 'get_before_method_modifiers_map', +# isa => 'HashRef[ArrayRef[CodeRef]]', +# provides => { +# 'keys' => 'get_before_method_modifiers', +# 'exists' => 'has_before_method_modifiers', +# # This actually makes sure there is an +# # ARRAY at the given key, and pushed onto +# # it. It also checks for duplicates as well +# # 'add' => 'add_before_method_modifier' +# } +# ); +# +# has 'after_method_modifiers' => ( +# metaclass => 'Hash', +# reader =>'get_after_method_modifiers_map', +# isa => 'HashRef[ArrayRef[CodeRef]]', +# provides => { +# 'keys' => 'get_after_method_modifiers', +# 'exists' => 'has_after_method_modifiers', +# # This actually makes sure there is an +# # ARRAY at the given key, and pushed onto +# # it. It also checks for duplicates as well +# # 'add' => 'add_after_method_modifier' +# } +# ); +# +# has 'around_method_modifiers' => ( +# metaclass => 'Hash', +# reader =>'get_around_method_modifiers_map', +# isa => 'HashRef[ArrayRef[CodeRef]]', +# provides => { +# 'keys' => 'get_around_method_modifiers', +# 'exists' => 'has_around_method_modifiers', +# # This actually makes sure there is an +# # ARRAY at the given key, and pushed onto +# # it. It also checks for duplicates as well +# # 'add' => 'add_around_method_modifier' +# } +# ); +# +# # override is similar to the other modifiers +# # except that it is not an ARRAY of code refs +# # but instead just a single name->code mapping +# +# has 'override_method_modifiers' => ( +# metaclass => 'Hash', +# reader =>'get_override_method_modifiers_map', +# isa => 'HashRef[CodeRef]', +# provides => { +# 'keys' => 'get_override_method_modifier', +# 'exists' => 'has_override_method_modifier', +# 'add' => 'add_override_method_modifier', # checks for local method .. +# } +# ); +# +##################################################################### + + +1; + +# ABSTRACT: The Moose Role metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role - The Moose Role metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a subclass of L<Class::MOP::Module> that provides +additional Moose-specific functionality. + +Its API looks a lot like L<Moose::Meta::Class>, but internally it +implements many things differently. This may change in the future. + +=head1 INHERITANCE + +C<Moose::Meta::Role> is a subclass of L<Class::MOP::Module>. + +=head1 METHODS + +=head2 Construction + +=over 4 + +=item B<< Moose::Meta::Role->initialize($role_name) >> + +This method creates a new role object with the provided name. + +=item B<< Moose::Meta::Role->combine( [ $role => { ... } ], [ $role ], ... ) >> + +This method accepts a list of array references. Each array reference +should contain a role name or L<Moose::Meta::Role> object as its first element. The second element is +an optional hash reference. The hash reference can contain C<-excludes> +and C<-alias> keys to control how methods are composed from the role. + +The return value is a new L<Moose::Meta::Role::Composite> that +represents the combined roles. + +=item B<< $metarole->composition_class_roles >> + +When combining multiple roles using C<combine>, this method is used to obtain a +list of role names to be applied to the L<Moose::Meta::Role::Composite> +instance returned by C<combine>. The default implementation returns an empty +list. Extensions that need to hook into role combination may wrap this method +to return additional role names. + +=item B<< Moose::Meta::Role->create($name, %options) >> + +This method is identical to the L<Moose::Meta::Class> C<create> +method. + +=item B<< Moose::Meta::Role->create_anon_role >> + +This method is identical to the L<Moose::Meta::Class> +C<create_anon_class> method. + +=item B<< $metarole->is_anon_role >> + +Returns true if the role is an anonymous role. + +=item B<< $metarole->consumers >> + +Returns a list of names of classes and roles which consume this role. + +=back + +=head2 Role application + +=over 4 + +=item B<< $metarole->apply( $thing, @options ) >> + +This method applies a role to the given C<$thing>. That can be another +L<Moose::Meta::Role>, object, a L<Moose::Meta::Class> object, or a +(non-meta) object instance. + +The options are passed directly to the constructor for the appropriate +L<Moose::Meta::Role::Application> subclass. + +Note that this will apply the role even if the C<$thing> in question already +C<does> this role. L<Moose::Util/does_role> is a convenient wrapper for +finding out if role application is necessary. + +=back + +=head2 Roles and other roles + +=over 4 + +=item B<< $metarole->get_roles >> + +This returns an array reference of roles which this role does. This +list may include duplicates. + +=item B<< $metarole->calculate_all_roles >> + +This returns a I<unique> list of all roles that this role does, and +all the roles that its roles do. + +=item B<< $metarole->does_role($role) >> + +Given a role I<name> or L<Moose::Meta::Role> object, returns true if this role +does the given role. + +=item B<< $metarole->add_role($role) >> + +Given a L<Moose::Meta::Role> object, this adds the role to the list of +roles that the role does. + +=item B<< $metarole->get_excluded_roles_list >> + +Returns a list of role names which this role excludes. + +=item B<< $metarole->excludes_role($role_name) >> + +Given a role I<name>, returns true if this role excludes the named +role. + +=item B<< $metarole->add_excluded_roles(@role_names) >> + +Given one or more role names, adds those roles to the list of excluded +roles. + +=back + +=head2 Methods + +The methods for dealing with a role's methods are all identical in API +and behavior to the same methods in L<Class::MOP::Class>. + +=over 4 + +=item B<< $metarole->method_metaclass >> + +Returns the method metaclass name for the role. This defaults to +L<Moose::Meta::Role::Method>. + +=item B<< $metarole->get_method($name) >> + +=item B<< $metarole->has_method($name) >> + +=item B<< $metarole->add_method( $name, $body ) >> + +=item B<< $metarole->get_method_list >> + +=item B<< $metarole->find_method_by_name($name) >> + +These methods are all identical to the methods of the same name in +L<Class::MOP::Package> + +=back + +=head2 Attributes + +As with methods, the methods for dealing with a role's attribute are +all identical in API and behavior to the same methods in +L<Class::MOP::Class>. + +However, attributes stored in this class are I<not> stored as +objects. Rather, the attribute definition is stored as a hash +reference. When a role is composed into a class, this hash reference +is passed directly to the metaclass's C<add_attribute> method. + +This is quite likely to change in the future. + +=over 4 + +=item B<< $metarole->get_attribute($attribute_name) >> + +=item B<< $metarole->has_attribute($attribute_name) >> + +=item B<< $metarole->get_attribute_list >> + +=item B<< $metarole->add_attribute($name, %options) >> + +=item B<< $metarole->remove_attribute($attribute_name) >> + +=back + +=head2 Overload introspection and creation + +The methods for dealing with a role's overloads are all identical in API and +behavior to the same methods in L<Class::MOP::Class>. + +=over 4 + +=item B<< $metarole->is_overloaded >> + +=item B<< $metarole->get_overloaded_operator($op) >> + +=item B<< $metarole->has_overloaded_operator($op) >> + +=item B<< $metarole->get_overload_list >> + +=item B<< $metarole->get_all_overloaded_operators >> + +=item B<< $metarole->add_overloaded_operator($op, $impl) >> + +=item B<< $metarole->remove_overloaded_operator($op) >> + +=back + +=head2 Required methods + +=over 4 + +=item B<< $metarole->get_required_method_list >> + +Returns the list of methods required by the role. + +=item B<< $metarole->requires_method($name) >> + +Returns true if the role requires the named method. + +=item B<< $metarole->add_required_methods(@names) >> + +Adds the named methods to the role's list of required methods. + +=item B<< $metarole->remove_required_methods(@names) >> + +Removes the named methods from the role's list of required methods. + +=item B<< $metarole->add_conflicting_method(%params) >> + +Instantiate the parameters as a L<Moose::Meta::Role::Method::Conflicting> +object, then add it to the required method list. + +=back + +=head2 Method modifiers + +These methods act like their counterparts in L<Class::MOP::Class> and +L<Moose::Meta::Class>. + +However, method modifiers are simply stored internally, and are not +applied until the role itself is applied to a class. + +=over 4 + +=item B<< $metarole->add_after_method_modifier($method_name, $method) >> + +=item B<< $metarole->add_around_method_modifier($method_name, $method) >> + +=item B<< $metarole->add_before_method_modifier($method_name, $method) >> + +=item B<< $metarole->add_override_method_modifier($method_name, $method) >> + +These methods all add an appropriate modifier to the internal list of +modifiers. + +=item B<< $metarole->has_after_method_modifiers >> + +=item B<< $metarole->has_around_method_modifiers >> + +=item B<< $metarole->has_before_method_modifiers >> + +=item B<< $metarole->has_override_method_modifier >> + +Return true if the role has any modifiers of the given type. + +=item B<< $metarole->get_after_method_modifiers($method_name) >> + +=item B<< $metarole->get_around_method_modifiers($method_name) >> + +=item B<< $metarole->get_before_method_modifiers($method_name) >> + +Given a method name, returns a list of the appropriate modifiers for +that method. + +=item B<< $metarole->get_override_method_modifier($method_name) >> + +Given a method name, returns the override method modifier for that +method, if it has one. + +=back + +=head2 Introspection + +=over 4 + +=item B<< Moose::Meta::Role->meta >> + +This will return a L<Class::MOP::Class> instance for this class. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Application.pm b/lib/Moose/Meta/Role/Application.pm new file mode 100644 index 0000000..58a123e --- /dev/null +++ b/lib/Moose/Meta/Role/Application.pm @@ -0,0 +1,225 @@ +package Moose::Meta::Role::Application; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; +use overload (); + +use List::Util 1.33 qw( all ); + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('method_exclusions' => ( + init_arg => '-excludes', + reader => 'get_method_exclusions', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('method_aliases' => ( + init_arg => '-alias', + reader => 'get_method_aliases', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +sub new { + my ($class, %params) = @_; + $class->_new(\%params); +} + +sub is_method_excluded { + my ($self, $method_name) = @_; + foreach (@{$self->get_method_exclusions}) { + return 1 if $_ eq $method_name; + } + return 0; +} + +sub is_method_aliased { + my ($self, $method_name) = @_; + exists $self->get_method_aliases->{$method_name} ? 1 : 0 +} + +sub is_aliased_method { + my ($self, $method_name) = @_; + my %aliased_names = reverse %{$self->get_method_aliases}; + exists $aliased_names{$method_name} ? 1 : 0; +} + +sub apply { + my $self = shift; + + $self->check_role_exclusions(@_); + $self->check_required_methods(@_); + $self->check_required_attributes(@_); + + $self->apply_overloading(@_); + $self->apply_attributes(@_); + $self->apply_methods(@_); + + $self->apply_override_method_modifiers(@_); + + $self->apply_before_method_modifiers(@_); + $self->apply_around_method_modifiers(@_); + $self->apply_after_method_modifiers(@_); +} + +sub check_role_exclusions { throw_exception( "CannotCallAnAbstractMethod" ); } +sub check_required_methods { throw_exception( "CannotCallAnAbstractMethod" ); } +sub check_required_attributes { throw_exception( "CannotCallAnAbstractMethod" ); } + +sub apply_attributes { throw_exception( "CannotCallAnAbstractMethod" ); } +sub apply_methods { throw_exception( "CannotCallAnAbstractMethod" ); } +sub apply_override_method_modifiers { throw_exception( "CannotCallAnAbstractMethod" ); } +sub apply_method_modifiers { throw_exception( "CannotCallAnAbstractMethod" ); } + +sub apply_before_method_modifiers { (shift)->apply_method_modifiers('before' => @_) } +sub apply_around_method_modifiers { (shift)->apply_method_modifiers('around' => @_) } +sub apply_after_method_modifiers { (shift)->apply_method_modifiers('after' => @_) } + +sub apply_overloading { + my ( $self, $role, $other ) = @_; + + return unless $role->is_overloaded; + + unless ( $other->is_overloaded ) { + $other->set_overload_fallback_value( + $role->get_overload_fallback_value ); + } + + for my $overload ( $role->get_all_overloaded_operators ) { + next if $other->has_overloaded_operator( $overload->operator ); + $other->add_overloaded_operator( + $overload->operator => $overload->clone ); + } +} + +1; + +# ABSTRACT: A base class for role application + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Application - A base class for role application + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This is the abstract base class for role applications. + +The API for this class and its subclasses still needs some +consideration, and is intentionally not yet documented. + +=head2 METHODS + +=over 4 + +=item B<new> + +=item B<meta> + +=item B<get_method_exclusions> + +=item B<is_method_excluded> + +=item B<get_method_aliases> + +=item B<is_aliased_method> + +=item B<is_method_aliased> + +=item B<apply> + +=item B<check_role_exclusions> + +=item B<check_required_methods> + +=item B<check_required_attributes> + +=item B<apply_attributes> + +=item B<apply_methods> + +=item B<apply_overloading> + +=item B<apply_method_modifiers> + +=item B<apply_before_method_modifiers> + +=item B<apply_after_method_modifiers> + +=item B<apply_around_method_modifiers> + +=item B<apply_override_method_modifiers> + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Application/RoleSummation.pm b/lib/Moose/Meta/Role/Application/RoleSummation.pm new file mode 100644 index 0000000..1276b66 --- /dev/null +++ b/lib/Moose/Meta/Role/Application/RoleSummation.pm @@ -0,0 +1,440 @@ +package Moose::Meta::Role::Application::RoleSummation; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use List::Util 1.33 qw( all ); +use Scalar::Util 'blessed'; + +use Moose::Meta::Role::Composite; + +use parent 'Moose::Meta::Role::Application'; + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('role_params' => ( + reader => 'role_params', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +sub get_exclusions_for_role { + my ($self, $role) = @_; + $role = $role->name if blessed $role; + my $excludes_key = exists $self->role_params->{$role}->{'-excludes'} ? + '-excludes' : 'excludes'; + if ($self->role_params->{$role} && defined $self->role_params->{$role}->{$excludes_key}) { + if (ref $self->role_params->{$role}->{$excludes_key} eq 'ARRAY') { + return $self->role_params->{$role}->{$excludes_key}; + } + return [ $self->role_params->{$role}->{$excludes_key} ]; + } + return []; +} + +sub get_method_aliases_for_role { + my ($self, $role) = @_; + $role = $role->name if blessed $role; + my $alias_key = exists $self->role_params->{$role}->{'-alias'} ? + '-alias' : 'alias'; + if ($self->role_params->{$role} && defined $self->role_params->{$role}->{$alias_key}) { + return $self->role_params->{$role}->{$alias_key}; + } + return {}; +} + +sub is_method_excluded { + my ($self, $role, $method_name) = @_; + foreach ($self->get_exclusions_for_role($role->name)) { + return 1 if $_ eq $method_name; + } + return 0; +} + +sub is_method_aliased { + my ($self, $role, $method_name) = @_; + exists $self->get_method_aliases_for_role($role->name)->{$method_name} ? 1 : 0 +} + +sub is_aliased_method { + my ($self, $role, $method_name) = @_; + my %aliased_names = reverse %{$self->get_method_aliases_for_role($role->name)}; + exists $aliased_names{$method_name} ? 1 : 0; +} + +sub check_role_exclusions { + my ($self, $c) = @_; + + my %excluded_roles; + for my $role (@{ $c->get_roles }) { + my $name = $role->name; + + for my $excluded ($role->get_excluded_roles_list) { + push @{ $excluded_roles{$excluded} }, $name; + } + } + + foreach my $role (@{$c->get_roles}) { + foreach my $excluded (keys %excluded_roles) { + next unless $role->does_role($excluded); + + my @excluding = @{ $excluded_roles{$excluded} }; + + throw_exception( RoleExclusionConflict => roles => \@excluding, + role_name => $excluded + ); + } + } + + $c->add_excluded_roles(keys %excluded_roles); +} + +sub check_required_methods { + my ($self, $c) = @_; + + my %all_required_methods = + map { $_->name => $_ } + map { $_->get_required_method_list } + @{$c->get_roles}; + + foreach my $role (@{$c->get_roles}) { + foreach my $required (keys %all_required_methods) { + + delete $all_required_methods{$required} + if $role->has_method($required) + || $self->is_aliased_method($role, $required); + } + } + + $c->add_required_methods(values %all_required_methods); +} + +sub check_required_attributes { + +} + +sub apply_attributes { + my ($self, $c) = @_; + + my @all_attributes; + + for my $role ( @{ $c->get_roles } ) { + push @all_attributes, + map { $role->get_attribute($_) } $role->get_attribute_list; + } + + my %seen; + foreach my $attr (@all_attributes) { + my $name = $attr->name; + + if ( exists $seen{$name} ) { + next if $seen{$name}->is_same_as($attr); + + my $role1 = $seen{$name}->associated_role->name; + my $role2 = $attr->associated_role->name; + + throw_exception( AttributeConflictInSummation => attribute_name => $name, + role_name => $role1, + second_role_name => $role2, + ); + } + + $seen{$name} = $attr; + } + + foreach my $attr (@all_attributes) { + $c->add_attribute( $attr->clone ); + } +} + +sub apply_methods { + my ($self, $c) = @_; + + my @all_methods = map { + my $role = $_; + my $aliases = $self->get_method_aliases_for_role($role); + my %excludes = map { $_ => undef } @{ $self->get_exclusions_for_role($role) }; + ( + (map { + exists $excludes{$_} ? () : + +{ + role => $role, + name => $_, + method => $role->get_method($_), + } + } map { $_->name } + grep { !$_->isa('Class::MOP::Method::Meta') } + $role->_get_local_methods), + (map { + +{ + role => $role, + name => $aliases->{$_}, + method => $role->get_method($_), + } + } keys %$aliases) + ); + } @{$c->get_roles}; + + my (%seen, %conflicts, %method_map); + foreach my $method (@all_methods) { + next if $conflicts{$method->{name}}; + my $seen = $seen{$method->{name}}; + + if ($seen) { + if ($seen->{method}->body != $method->{method}->body) { + $c->add_conflicting_method( + name => $method->{name}, + roles => [$method->{role}->name, $seen->{role}->name], + ); + + delete $method_map{$method->{name}}; + $conflicts{$method->{name}} = 1; + next; + } + } + + $seen{$method->{name}} = $method; + $method_map{$method->{name}} = $method->{method}; + } + + $c->add_method($_ => $method_map{$_}) for keys %method_map; +} + +sub apply_override_method_modifiers { + my ($self, $c) = @_; + + my @all_overrides = map { + my $role = $_; + map { + +{ + name => $_, + method => $role->get_override_method_modifier($_), + } + } $role->get_method_modifier_list('override'); + } @{$c->get_roles}; + + my %seen; + foreach my $override (@all_overrides) { + my @role_names = map { $_->name } @{$c->get_roles}; + if ( $c->has_method($override->{name}) ){ + throw_exception( OverrideConflictInSummation => role_names => \@role_names, + role_application => $self, + method_name => $override->{name} + ); + } + if (exists $seen{$override->{name}}) { + if ( $seen{$override->{name}} != $override->{method} ) { + throw_exception( OverrideConflictInSummation => role_names => \@role_names, + role_application => $self, + method_name => $override->{name}, + two_overrides_found => 1 + ); + } + } + $seen{$override->{name}} = $override->{method}; + } + + $c->add_override_method_modifier( + $_->{name}, $_->{method} + ) for @all_overrides; + +} + +sub apply_method_modifiers { + my ($self, $modifier_type, $c) = @_; + my $add = "add_${modifier_type}_method_modifier"; + my $get = "get_${modifier_type}_method_modifiers"; + foreach my $role (@{$c->get_roles}) { + foreach my $method_name ($role->get_method_modifier_list($modifier_type)) { + $c->$add( + $method_name, + $_ + ) foreach $role->$get($method_name); + } + } +} + +sub apply_overloading { + my ( $self, $c ) = @_; + + my @overloaded_roles = grep { $_->is_overloaded } @{ $c->get_roles }; + return unless @overloaded_roles; + + my %fallback; + for my $role (@overloaded_roles) { + $fallback{ $role->name } = $role->get_overload_fallback_value; + } + + for my $role_name ( keys %fallback ) { + for my $other_role_name ( grep { $_ ne $role_name } keys %fallback ) { + my @fb_values = @fallback{ $role_name, $other_role_name }; + if ( all {defined} @fb_values ) { + next if $fallback{$role_name} eq $fallback{$other_role_name}; + throw_exception( + 'OverloadConflictInSummation', + role_names => [ $role_name, $other_role_name ], + role_application => $self, + overloaded_op => 'fallback', + ); + } + + next if all { !defined } @fb_values; + throw_exception( + 'OverloadConflictInSummation', + role_names => [ $role_name, $other_role_name ], + role_application => $self, + overloaded_op => 'fallback', + ); + } + } + + if ( keys %fallback ) { + $c->set_overload_fallback_value( ( values %fallback )[0] ); + } + + my %overload_map; + for my $role (@overloaded_roles) { + for my $overload ( $role->get_all_overloaded_operators ) { + $overload_map{ $overload->operator }{ $role->name } = $overload; + } + } + + for my $op_name ( keys %overload_map ) { + my @roles = keys %{ $overload_map{$op_name} }; + my $overload = $overload_map{$op_name}{ $roles[0] }; + + if ( @roles > 1 && !all { $overload->_is_equal_to($_) } + values %{ $overload_map{$op_name} } ) { + + throw_exception( + 'OverloadConflictInSummation', + role_names => [ @roles[ 0, 1 ] ], + role_application => $self, + overloaded_op => $op_name, + ); + } + + $c->add_overloaded_operator( + $op_name => $overload_map{$op_name}{ $roles[0] } ); + } +} + +1; + +# ABSTRACT: Combine two or more roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Application::RoleSummation - Combine two or more roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +Summation composes two traits, forming the union of non-conflicting +bindings and 'disabling' the conflicting bindings + +=head2 METHODS + +=over 4 + +=item B<new> + +=item B<meta> + +=item B<role_params> + +=item B<get_exclusions_for_role> + +=item B<get_method_aliases_for_role> + +=item B<is_aliased_method> + +=item B<is_method_aliased> + +=item B<is_method_excluded> + +=item B<apply> + +=item B<check_role_exclusions> + +=item B<check_required_methods> + +=item B<check_required_attributes> + +=item B<apply_attributes> + +=item B<apply_methods> + +=item B<apply_overloading> + +=item B<apply_method_modifiers> + +=item B<apply_override_method_modifiers> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Application/ToClass.pm b/lib/Moose/Meta/Role/Application/ToClass.pm new file mode 100644 index 0000000..03eeedd --- /dev/null +++ b/lib/Moose/Meta/Role/Application/ToClass.pm @@ -0,0 +1,314 @@ +package Moose::Meta::Role::Application::ToClass; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use List::Util 'first'; +use Moose::Util 'throw_exception'; +use Scalar::Util 'weaken'; + +use parent 'Moose::Meta::Role::Application'; + +__PACKAGE__->meta->add_attribute('role' => ( + reader => 'role', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('class' => ( + accessor => 'class', + Class::MOP::_definition_context(), +)); + +sub apply { + my ($self, $role, $class) = @_; + + # We need weak_ref in CMOP :( + weaken($self->{role} = $role); + weaken($self->{class} = $class); + + $self->SUPER::apply($role, $class); + + $class->add_role($role); + $class->add_role_application($self); +} + +sub check_role_exclusions { + my ($self, $role, $class) = @_; + if ($class->excludes_role($role->name)) { + throw_exception( ConflictDetectedInCheckRoleExclusionsInToClass => class_name => $class->name, + role_name => $role->name, + ); + } + foreach my $excluded_role_name ($role->get_excluded_roles_list) { + if ($class->does_role($excluded_role_name)) { + throw_exception( ClassDoesTheExcludedRole => role_name => $role->name, + excluded_role_name => $excluded_role_name, + class_name => $class->name, + ); + } + } +} + +sub check_required_methods { + my ($self, $role, $class) = @_; + + my @missing; + my @is_attr; + + # NOTE: + # we might need to move this down below the + # the attributes so that we can require any + # attribute accessors. However I am thinking + # that maybe those are somehow exempt from + # the require methods stuff. + foreach my $required_method ($role->get_required_method_list) { + my $required_method_name = $required_method->name; + + if (!$class->find_method_by_name($required_method_name)) { + + next if $self->is_aliased_method($required_method_name); + + push @missing, $required_method; + } + } + + return unless @missing; + + my $error = ''; + + @missing = sort { $a->name cmp $b->name } @missing; + my @conflicts = grep { $_->isa('Moose::Meta::Role::Method::Conflicting') } @missing; + + if (@conflicts) { + my $conflict = $conflicts[0]; + my $roles = $conflict->roles_as_english_list; + + my @same_role_conflicts = grep { $_->roles_as_english_list eq $roles } @conflicts; + + throw_exception( MethodNameConflictInRoles => conflict => \@same_role_conflicts, + class_name => $class->name + ); + } + elsif (@missing) { + if (my $meth = first { $class->name->can($_) } @missing) { + throw_exception( RequiredMethodsImportedByClass => class_name => $class->name, + role_name => $role->name, + missing_methods => \@missing, + imported_method => $meth + ); + } + else { + throw_exception( RequiredMethodsNotImplementedByClass => class_name => $class->name, + role_name => $role->name, + missing_methods => \@missing, + ); + } + } +} + +sub check_required_attributes { + +} + +sub apply_attributes { + my ($self, $role, $class) = @_; + + foreach my $attribute_name ($role->get_attribute_list) { + # it if it has one already + if ($class->has_attribute($attribute_name) && + # make sure we haven't seen this one already too + $class->get_attribute($attribute_name) != $role->get_attribute($attribute_name)) { + next; + } + else { + $class->add_attribute( + $role->get_attribute($attribute_name)->attribute_for_class + ); + } + } +} + +sub apply_methods { + my ( $self, $role, $class ) = @_; + + foreach my $method ( $role->_get_local_methods ) { + my $method_name = $method->name; + + next if $method->isa('Class::MOP::Method::Meta'); + + unless ( $self->is_method_excluded($method_name) ) { + + my $class_method = $class->get_method($method_name); + + next if $class_method && $class_method->body != $method->body; + + $class->add_method( + $method_name, + $method, + ); + } + + next unless $self->is_method_aliased($method_name); + + my $aliased_method_name = $self->get_method_aliases->{$method_name}; + + my $class_method = $class->get_method($aliased_method_name); + + if ( $class_method && $class_method->body != $method->body ) { + throw_exception( CannotCreateMethodAliasLocalMethodIsPresentInClass => aliased_method_name => $aliased_method_name, + method => $method, + role_name => $role->name, + class_name => $class->name, + ); + } + + $class->add_method( + $aliased_method_name, + $method, + ); + } + + # we must reset the cache here since + # we are just aliasing methods, otherwise + # the modifiers go wonky. + $class->reset_package_cache_flag; +} + +sub apply_override_method_modifiers { + my ($self, $role, $class) = @_; + foreach my $method_name ($role->get_method_modifier_list('override')) { + # it if it has one already then ... + if ($class->has_method($method_name)) { + next; + } + else { + # if this is not a role, then we need to + # find the original package of the method + # so that we can tell the class were to + # find the right super() method + my $method = $role->get_override_method_modifier($method_name); + my ($package) = Class::MOP::get_code_info($method); + # if it is a class, we just add it + $class->add_override_method_modifier($method_name, $method, $package); + } + } +} + +sub apply_method_modifiers { + my ($self, $modifier_type, $role, $class) = @_; + my $add = "add_${modifier_type}_method_modifier"; + my $get = "get_${modifier_type}_method_modifiers"; + foreach my $method_name ($role->get_method_modifier_list($modifier_type)) { + $class->$add( + $method_name, + $_ + ) foreach $role->$get($method_name); + } +} + +1; + +# ABSTRACT: Compose a role into a class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Application::ToClass - Compose a role into a class + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +=head2 METHODS + +=over 4 + +=item B<new> + +=item B<meta> + +=item B<apply> + +=item B<check_role_exclusions> + +=item B<check_required_methods> + +=item B<check_required_attributes> + +=item B<apply_attributes> + +=item B<apply_methods> + +=item B<apply_method_modifiers> + +=item B<apply_override_method_modifiers> + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Application/ToInstance.pm b/lib/Moose/Meta/Role/Application/ToInstance.pm new file mode 100644 index 0000000..5e82c45 --- /dev/null +++ b/lib/Moose/Meta/Role/Application/ToInstance.pm @@ -0,0 +1,141 @@ +package Moose::Meta::Role::Application::ToInstance; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; +use List::Util 1.33 'all'; + +use parent 'Moose::Meta::Role::Application'; + +__PACKAGE__->meta->add_attribute('rebless_params' => ( + reader => 'rebless_params', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +use constant _NEED_OVERLOAD_HACK_FOR_OBJECTS => $] < 5.008009; + +sub apply { + my ( $self, $role, $object, $args ) = @_; + + my $obj_meta = Class::MOP::class_of($object) || 'Moose::Meta::Class'; + + # This is a special case to handle the case where the object's metaclass + # is a Class::MOP::Class, but _not_ a Moose::Meta::Class (for example, + # when applying a role to a Moose::Meta::Attribute object). + $obj_meta = 'Moose::Meta::Class' + unless $obj_meta->isa('Moose::Meta::Class'); + + my $class = $obj_meta->create_anon_class( + superclasses => [ blessed($object) ], + roles => [ $role, keys(%$args) ? ($args) : () ], + cache => (all { $_ eq '-alias' || $_ eq '-excludes' } keys %$args), + ); + + $class->rebless_instance( $object, %{ $self->rebless_params } ); + + if ( _NEED_OVERLOAD_HACK_FOR_OBJECTS + && overload::Overloaded( ref $object ) ) { + + # need to use $_[2] here to apply to the object in the caller + _reset_amagic($_[2]); + } + + return $object; +} + +1; + +# ABSTRACT: Compose a role into an instance + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Application::ToInstance - Compose a role into an instance + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +=head2 METHODS + +=over 4 + +=item B<new> + +=item B<meta> + +=item B<apply> + +=item B<rebless_params> + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Application/ToRole.pm b/lib/Moose/Meta/Role/Application/ToRole.pm new file mode 100644 index 0000000..0d8af91 --- /dev/null +++ b/lib/Moose/Meta/Role/Application/ToRole.pm @@ -0,0 +1,283 @@ +package Moose::Meta::Role::Application::ToRole; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use parent 'Moose::Meta::Role::Application'; + +use Moose::Util 'throw_exception'; + +sub apply { + my ($self, $role1, $role2) = @_; + $self->SUPER::apply($role1, $role2); + $role2->add_role($role1); +} + +sub check_role_exclusions { + my ($self, $role1, $role2) = @_; + if ( $role2->excludes_role($role1->name) ) { + throw_exception( ConflictDetectedInCheckRoleExclusions => role_name => $role2->name, + excluded_role_name => $role1->name, + ); + } + foreach my $excluded_role_name ($role1->get_excluded_roles_list) { + if ( $role2->does_role($excluded_role_name) ) { + throw_exception( RoleDoesTheExcludedRole => role_name => $role2->name, + excluded_role_name => $excluded_role_name, + second_role_name => $role1->name, + ); + } + $role2->add_excluded_roles($excluded_role_name); + } +} + +sub check_required_methods { + my ($self, $role1, $role2) = @_; + foreach my $required_method ($role1->get_required_method_list) { + my $required_method_name = $required_method->name; + + next if $self->is_aliased_method($required_method_name); + + $role2->add_required_methods($required_method) + unless $role2->find_method_by_name($required_method_name); + } +} + +sub check_required_attributes { + +} + +sub apply_attributes { + my ($self, $role1, $role2) = @_; + foreach my $attribute_name ($role1->get_attribute_list) { + # it if it has one already + if ($role2->has_attribute($attribute_name) && + # make sure we haven't seen this one already too + $role2->get_attribute($attribute_name) != $role1->get_attribute($attribute_name)) { + + my $role2_name = $role2->name; + + throw_exception( AttributeConflictInRoles => role_name => $role1->name, + second_role_name => $role2->name, + attribute_name => $attribute_name + ); + } + else { + $role2->add_attribute( + $role1->get_attribute($attribute_name)->clone + ); + } + } +} + +sub apply_methods { + my ( $self, $role1, $role2 ) = @_; + foreach my $method ( $role1->_get_local_methods ) { + + my $method_name = $method->name; + + next if $method->isa('Class::MOP::Method::Meta'); + + unless ( $self->is_method_excluded($method_name) ) { + + my $role2_method = $role2->get_method($method_name); + if ( $role2_method + && $role2_method->body != $method->body ) { + + # method conflicts between roles used to result in the method + # becoming a requirement but now are permitted just like + # for classes, hence no code in this branch anymore. + } + else { + $role2->add_method( + $method_name, + $method, + ); + } + } + + next unless $self->is_method_aliased($method_name); + + my $aliased_method_name = $self->get_method_aliases->{$method_name}; + + my $role2_method = $role2->get_method($aliased_method_name); + + if ( $role2_method + && $role2_method->body != $method->body ) { + + throw_exception( CannotCreateMethodAliasLocalMethodIsPresent => aliased_method_name => $aliased_method_name, + method => $method, + role_name => $role2->name, + role_being_applied_name => $role1->name, + ); + } + + $role2->add_method( + $aliased_method_name, + $role1->get_method($method_name) + ); + + if ( !$role2->has_method($method_name) ) { + $role2->add_required_methods($method_name) + unless $self->is_method_excluded($method_name); + } + } +} + +sub apply_override_method_modifiers { + my ($self, $role1, $role2) = @_; + foreach my $method_name ($role1->get_method_modifier_list('override')) { + # it if it has one already then ... + if ($role2->has_method($method_name)) { + # if it is being composed into another role + # we have a conflict here, because you cannot + # combine an overridden method with a locally + # defined one + throw_exception( OverrideConflictInComposition => role_name => $role2->name, + role_being_applied_name => $role1->name, + method_name => $method_name + ); + } + else { + # if we are a role, we need to make sure + # we don't have a conflict with the role + # we are composing into + if ($role2->has_override_method_modifier($method_name) && + $role1->get_override_method_modifier($method_name) != $role2->get_override_method_modifier($method_name)) { + + throw_exception( OverrideConflictInComposition => role_name => $role2->name, + role_being_applied_name => $role1->name, + method_name => $method_name, + two_overrides_found => 1 + ); + } + else { + # if there is no conflict, + # just add it to the role + $role2->add_override_method_modifier( + $method_name, + $role1->get_override_method_modifier($method_name) + ); + } + } + } +} + +sub apply_method_modifiers { + my ($self, $modifier_type, $role1, $role2) = @_; + my $add = "add_${modifier_type}_method_modifier"; + my $get = "get_${modifier_type}_method_modifiers"; + foreach my $method_name ($role1->get_method_modifier_list($modifier_type)) { + $role2->$add( + $method_name, + $_ + ) foreach $role1->$get($method_name); + } +} + +1; + +# ABSTRACT: Compose a role into another role + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Application::ToRole - Compose a role into another role + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +=head2 METHODS + +=over 4 + +=item B<new> + +=item B<meta> + +=item B<apply> + +=item B<check_role_exclusions> + +=item B<check_required_methods> + +=item B<check_required_attributes> + +=item B<apply_attributes> + +=item B<apply_methods> + +=item B<apply_method_modifiers> + +=item B<apply_override_method_modifiers> + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Attribute.pm b/lib/Moose/Meta/Role/Attribute.pm new file mode 100644 index 0000000..0c09550 --- /dev/null +++ b/lib/Moose/Meta/Role/Attribute.pm @@ -0,0 +1,263 @@ +package Moose::Meta::Role::Attribute; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use List::Util 1.33 'all'; +use Scalar::Util 'blessed', 'weaken'; + +use parent 'Moose::Meta::Mixin::AttributeCore', 'Class::MOP::Object'; + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute( + 'metaclass' => ( + reader => 'metaclass', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'associated_role' => ( + reader => 'associated_role', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + '_original_role' => ( + reader => '_original_role', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'is' => ( + reader => 'is', + Class::MOP::_definition_context(), + ) +); + +__PACKAGE__->meta->add_attribute( + 'original_options' => ( + reader => 'original_options', + Class::MOP::_definition_context(), + ) +); + +sub new { + my ( $class, $name, %options ) = @_; + + (defined $name) + || throw_exception( MustProvideANameForTheAttribute => params => \%options, + class => $class + ); + + my $role = delete $options{_original_role}; + + return bless { + name => $name, + original_options => \%options, + _original_role => $role, + %options, + }, $class; +} + +sub attach_to_role { + my ( $self, $role ) = @_; + + ( blessed($role) && $role->isa('Moose::Meta::Role') ) + || throw_exception( MustPassAMooseMetaRoleInstanceOrSubclass => class => $self, + role => $role + ); + + weaken( $self->{'associated_role'} = $role ); +} + +sub original_role { + my $self = shift; + + return $self->_original_role || $self->associated_role; +} + +sub attribute_for_class { + my $self = shift; + + my $metaclass = $self->original_role->applied_attribute_metaclass; + + return $metaclass->interpolate_class_and_new( + $self->name => %{ $self->original_options } ); +} + +sub clone { + my $self = shift; + + my $role = $self->original_role; + + return ( ref $self )->new( + $self->name, + %{ $self->original_options }, + _original_role => $role, + ); +} + +sub is_same_as { + my $self = shift; + my $attr = shift; + + my $self_options = $self->original_options; + my $other_options = $attr->original_options; + + return 0 + unless ( join q{|}, sort keys %{$self_options} ) eq ( join q{|}, sort keys %{$other_options} ); + + for my $key ( keys %{$self_options} ) { + return 0 if defined $self_options->{$key} && ! defined $other_options->{$key}; + return 0 if ! defined $self_options->{$key} && defined $other_options->{$key}; + + next if all { ! defined } $self_options->{$key}, $other_options->{$key}; + + return 0 unless $self_options->{$key} eq $other_options->{$key}; + } + + return 1; +} + +1; + +# ABSTRACT: The Moose attribute metaclass for Roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Attribute - The Moose attribute metaclass for Roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class implements the API for attributes in roles. Attributes in roles are +more like attribute prototypes than full blown attributes. While they are +introspectable, they have very little behavior. + +=head1 METHODS + +This class provides the following methods: + +=over 4 + +=item B<< Moose::Meta::Role::Attribute->new(...) >> + +This method accepts all the options that would be passed to the constructor +for L<Moose::Meta::Attribute>. + +=item B<< $attr->metaclass >> + +=item B<< $attr->is >> + +Returns the option as passed to the constructor. + +=item B<< $attr->associated_role >> + +Returns the L<Moose::Meta::Role> to which this attribute belongs, if any. + +=item B<< $attr->original_role >> + +Returns the L<Moose::Meta::Role> in which this attribute was first +defined. This may not be the same as the value of C<associated_role()> for +attributes in a composite role, or when one role consumes other roles. + +=item B<< $attr->original_options >> + +Returns a hash reference of options passed to the constructor. This is used +when creating a L<Moose::Meta::Attribute> object from this object. + +=item B<< $attr->attach_to_role($role) >> + +Attaches the attribute to the given L<Moose::Meta::Role>. + +=item B<< $attr->attribute_for_class($metaclass) >> + +Given an attribute metaclass name, this method calls C<< +$metaclass->interpolate_class_and_new >> to construct an attribute object +which can be added to a L<Moose::Meta::Class>. + +=item B<< $attr->clone >> + +Creates a new object identical to the object on which the method is called. + +=item B<< $attr->is_same_as($other_attr) >> + +Compares two role attributes and returns true if they are identical. + +=back + +In addition, this class implements all informational predicates implements by +L<Moose::Meta::Attribute> (and L<Class::MOP::Attribute>). + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Composite.pm b/lib/Moose/Meta/Role/Composite.pm new file mode 100644 index 0000000..40e0dad --- /dev/null +++ b/lib/Moose/Meta/Role/Composite.pm @@ -0,0 +1,324 @@ +package Moose::Meta::Role::Composite; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; +use Moose::Util 'throw_exception'; +use parent 'Moose::Meta::Role'; + +# NOTE: +# we need to override the ->name +# method from Class::MOP::Package +# since we don't have an actual +# package for this. +# - SL +__PACKAGE__->meta->add_attribute('name' => ( + reader => 'name', + Class::MOP::_definition_context(), +)); + +# NOTE: +# Again, since we don't have a real +# package to store our methods in, +# we use a HASH ref instead. +# - SL +__PACKAGE__->meta->add_attribute('_methods' => ( + reader => '_method_map', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('_overloads' => ( + reader => '_overload_map', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('_overload_fallback' => ( + accessor => '_overload_fallback', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute( + 'application_role_summation_class', + reader => 'application_role_summation_class', + default => 'Moose::Meta::Role::Application::RoleSummation', + Class::MOP::_definition_context(), +); + +sub new { + my ($class, %params) = @_; + + # the roles param is required ... + foreach ( @{$params{roles}} ) { + unless ( $_->isa('Moose::Meta::Role') ) { + throw_exception( RolesListMustBeInstancesOfMooseMetaRole => params => \%params, + role => $_, + class => $class + ); + } + } + + my @composition_roles = map { + $_->composition_class_roles + } @{ $params{roles} }; + + if (@composition_roles) { + my $meta = Moose::Meta::Class->create_anon_class( + superclasses => [ $class ], + roles => [ @composition_roles ], + cache => 1, + ); + $class = $meta->name; + } + + # and the name is created from the + # roles if one has not been provided + $params{name} ||= (join "|" => map { $_->name } @{$params{roles}}); + $class->_new(\%params); +} + +# There's no such thing as an anonymous composite role since composites are an +# artifact of Moose's internals. However, a composite role that contains an +# anon role may _look_ like an anon role since $self->name =~ /$anon_key/ can +# return true if the first role in the composite is anonymous itself. +sub is_anon { 0 } + +# This is largely a copy of what's in Moose::Meta::Role (itself +# largely a copy of Class::MOP::Class). However, we can't actually +# call add_package_symbol, because there's no package into which to +# add the symbol. +sub add_method { + my ($self, $method_name, $method) = @_; + + unless ( defined $method_name && $method_name ) { + throw_exception( MustDefineAMethodName => instance => $self ); + } + + my $body; + if (blessed($method)) { + $body = $method->body; + if ($method->package_name ne $self->name) { + $method = $method->clone( + package_name => $self->name, + name => $method_name + ) if $method->can('clone'); + } + } + else { + $body = $method; + $method = $self->wrap_method_body( body => $body, name => $method_name ); + } + + $self->_method_map->{$method_name} = $method; +} + +sub get_method_list { + my $self = shift; + return keys %{ $self->_method_map }; +} + +sub _get_local_methods { + my $self = shift; + return values %{ $self->_method_map }; +} + +sub has_method { + my ($self, $method_name) = @_; + + return exists $self->_method_map->{$method_name}; +} + +sub get_method { + my ($self, $method_name) = @_; + + return $self->_method_map->{$method_name}; +} + +sub is_overloaded { + my ($self) = @_; + return keys %{ $self->_overload_map }; +} + +sub add_overloaded_operator { + my ( $self, $op_name, $overload ) = @_; + + unless ( defined $op_name && $op_name ) { + throw_exception( + 'MustDefineAnOverloadOperator', + instance => $self, + ); + } + + $self->_overload_map->{$op_name} = $overload; +} + +sub get_overload_fallback_value { + my ($self) = @_; + return $self->_overload_fallback; +} + +sub set_overload_fallback_value { + my $self = shift; + $self->_overload_fallback(shift); +} + +sub get_all_overloaded_operators { + my ( $self, $method_name ) = @_; + return values %{ $self->_overload_map }; +} + +sub apply_params { + my ($self, $role_params) = @_; + Moose::Util::_load_user_class($self->application_role_summation_class); + + $self->application_role_summation_class->new( + role_params => $role_params, + )->apply($self); + + return $self; +} + +sub reinitialize { + my ( $class, $old_meta, @args ) = @_; + + throw_exception( CannotInitializeMooseMetaRoleComposite => old_meta => $old_meta, + args => \@args, + role_composite => $class + ) + if !blessed $old_meta + || !$old_meta->isa('Moose::Meta::Role::Composite'); + + my %existing_classes = map { $_ => $old_meta->$_() } qw( + application_role_summation_class + ); + + return $old_meta->meta->clone_object( $old_meta, %existing_classes, @args ); +} + +1; + +# ABSTRACT: An object to represent the set of roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Composite - An object to represent the set of roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +A composite is a role that consists of a set of two or more roles. + +The API of a composite role is almost identical to that of a regular +role. + +=head1 INHERITANCE + +C<Moose::Meta::Role::Composite> is a subclass of L<Moose::Meta::Role>. + +=head2 METHODS + +=over 4 + +=item B<< Moose::Meta::Role::Composite->new(%options) >> + +This returns a new composite role object. It accepts the same +options as its parent class, with a few changes: + +=over 8 + +=item * roles + +This option is an array reference containing a list of +L<Moose::Meta::Role> object. This is a required option. + +=item * name + +If a name is not given, one is generated from the roles provided. + +=item * apply_params(\%role_params) + +Creates a new RoleSummation role application with C<%role_params> and applies +the composite role to it. The RoleSummation role application class used is +determined by the composite role's C<application_role_summation_class> +attribute. + +=item * reinitialize($metaclass) + +Like C<< Class::MOP::Package->reinitialize >>, but doesn't allow passing a +string with the package name, as there is no real package for composite roles. + +=back + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Method.pm b/lib/Moose/Meta/Role/Method.pm new file mode 100644 index 0000000..5dff6f4 --- /dev/null +++ b/lib/Moose/Meta/Role/Method.pm @@ -0,0 +1,101 @@ +package Moose::Meta::Role::Method; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use parent 'Moose::Meta::Method'; + +sub _make_compatible_with { + my $self = shift; + my ($other) = @_; + + # XXX: this is pretty gross. the issue here is blah blah blah + # see the comments in CMOP::Method::Meta and CMOP::Method::Wrapped + return $self unless $other->_is_compatible_with($self->_real_ref_name); + + return $self->SUPER::_make_compatible_with(@_); +} + +1; + +# ABSTRACT: A Moose Method metaclass for Roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Method - A Moose Method metaclass for Roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This is primarily used to mark methods coming from a role +as being different. Right now it is nothing but a subclass +of L<Moose::Meta::Method>. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Method/Conflicting.pm b/lib/Moose/Meta/Role/Method/Conflicting.pm new file mode 100644 index 0000000..9d810fc --- /dev/null +++ b/lib/Moose/Meta/Role/Method/Conflicting.pm @@ -0,0 +1,139 @@ +package Moose::Meta::Role::Method::Conflicting; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Moose::Util; + +use parent 'Moose::Meta::Role::Method::Required'; + +__PACKAGE__->meta->add_attribute('roles' => ( + reader => 'roles', + required => 1, + Class::MOP::_definition_context(), +)); + +sub roles_as_english_list { + my $self = shift; + Moose::Util::english_list( map { q{'} . $_ . q{'} } @{ $self->roles } ); +} + +1; + +# ABSTRACT: A Moose metaclass for conflicting methods in Roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Method::Conflicting - A Moose metaclass for conflicting methods in Roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +=head1 INHERITANCE + +C<Moose::Meta::Role::Method::Conflicting> is a subclass of +L<Moose::Meta::Role::Method::Required>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Role::Method::Conflicting->new(%options) >> + +This creates a new type constraint based on the provided C<%options>: + +=over 8 + +=item * name + +The method name. This is required. + +=item * roles + +The list of role names that generated the conflict. This is required. + +=back + +=item B<< $method->name >> + +Returns the conflicting method's name, as provided to the constructor. + +=item B<< $method->roles >> + +Returns the roles that generated this conflicting method, as provided to the +constructor. + +=item B<< $method->roles_as_english_list >> + +Returns the roles that generated this conflicting method as an English list. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/Role/Method/Required.pm b/lib/Moose/Meta/Role/Method/Required.pm new file mode 100644 index 0000000..ebdd366 --- /dev/null +++ b/lib/Moose/Meta/Role/Method/Required.pm @@ -0,0 +1,129 @@ +package Moose::Meta::Role::Method::Required; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use overload '""' => sub { shift->name }, # stringify to method name + fallback => 1; + +use parent 'Class::MOP::Object'; + +# This is not a Moose::Meta::Role::Method because it has no implementation, it +# is just a name + +__PACKAGE__->meta->add_attribute('name' => ( + reader => 'name', + required => 1, + Class::MOP::_definition_context(), +)); + +sub new { shift->_new(@_) } + +1; + +# ABSTRACT: A Moose metaclass for required methods in Roles + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::Role::Method::Required - A Moose metaclass for required methods in Roles + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +=head1 INHERITANCE + +C<Moose::Meta::Role::Method::Required> is a subclass of L<Class::MOP::Object>. +It is B<not> a subclass of C<Moose::Meta::Role::Method> since it does not +provide an implementation of the method. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::Role::Method::Required->new(%options) >> + +This creates a new type constraint based on the provided C<%options>: + +=over 8 + +=item * name + +The method name. This is required. + +=back + +=item B<< $method->name >> + +Returns the required method's name, as provided to the constructor. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeCoercion.pm b/lib/Moose/Meta/TypeCoercion.pm new file mode 100644 index 0000000..58317bc --- /dev/null +++ b/lib/Moose/Meta/TypeCoercion.pm @@ -0,0 +1,243 @@ +package Moose::Meta::TypeCoercion; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Moose::Meta::Attribute; +use Moose::Util::TypeConstraints (); + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('type_coercion_map' => ( + reader => 'type_coercion_map', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute( + Moose::Meta::Attribute->new('type_constraint' => ( + reader => 'type_constraint', + weak_ref => 1, + Class::MOP::_definition_context(), + )) +); + +# private accessor +__PACKAGE__->meta->add_attribute('compiled_type_coercion' => ( + accessor => '_compiled_type_coercion', + Class::MOP::_definition_context(), +)); + +sub new { + my $class = shift; + my $self = Class::MOP::class_of($class)->new_object(@_); + $self->compile_type_coercion; + return $self; +} + +sub compile_type_coercion { + my $self = shift; + my @coercion_map = @{$self->type_coercion_map}; + my @coercions; + while (@coercion_map) { + my ($constraint_name, $action) = splice(@coercion_map, 0, 2); + my $type_constraint = ref $constraint_name ? $constraint_name : Moose::Util::TypeConstraints::find_or_parse_type_constraint($constraint_name); + + unless ( defined $type_constraint ) { + throw_exception( CouldNotFindTypeConstraintToCoerceFrom => constraint_name => $constraint_name, + instance => $self + ); + } + + push @coercions => [ + $type_constraint->_compiled_type_constraint, + $action + ]; + } + $self->_compiled_type_coercion(sub { + my $thing = shift; + foreach my $coercion (@coercions) { + my ($constraint, $converter) = @$coercion; + if ($constraint->($thing)) { + local $_ = $thing; + return $converter->($thing); + } + } + return $thing; + }); +} + +sub has_coercion_for_type { + my ($self, $type_name) = @_; + my %coercion_map = @{$self->type_coercion_map}; + exists $coercion_map{$type_name} ? 1 : 0; +} + +sub add_type_coercions { + my ($self, @new_coercion_map) = @_; + + my $coercion_map = $self->type_coercion_map; + my %has_coercion = @$coercion_map; + + while (@new_coercion_map) { + my ($constraint_name, $action) = splice(@new_coercion_map, 0, 2); + + if ( exists $has_coercion{$constraint_name} ) { + throw_exception( CoercionAlreadyExists => constraint_name => $constraint_name, + instance => $self + ); + } + + push @{$coercion_map} => ($constraint_name, $action); + } + + # and re-compile ... + $self->compile_type_coercion; +} + +sub coerce { $_[0]->_compiled_type_coercion->($_[1]) } + + +1; + +# ABSTRACT: The Moose Type Coercion metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeCoercion - The Moose Type Coercion metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +A type coercion object is basically a mapping of one or more type +constraints and the associated coercions subroutines. + +It's unlikely that you will need to instantiate an object of this +class directly, as it's part of the deep internals of Moose. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeCoercion->new(%options) >> + +Creates a new type coercion object, based on the options provided. + +=over 8 + +=item * type_constraint + +This is the L<Moose::Meta::TypeConstraint> object for the type that is +being coerced I<to>. + +=back + +=item B<< $coercion->type_coercion_map >> + +This returns the map of type constraints to coercions as an array +reference. The values of the array alternate between type names and +subroutine references which implement the coercion. + +The value is an array reference because coercions are tried in the +order they are added. + +=item B<< $coercion->type_constraint >> + +This returns the L<Moose::Meta::TypeConstraint> that was passed to the +constructor. + +=item B<< $coercion->has_coercion_for_type($type_name) >> + +Returns true if the coercion can coerce the named type. + +=item B<< $coercion->add_type_coercions( $type_name => $sub, ... ) >> + +This method takes a list of type names and subroutine references. If +the coercion already has a mapping for a given type, it throws an +exception. + +Coercions are actually + +=item B<< $coercion->coerce($value) >> + +This method takes a value and applies the first valid coercion it +finds. + +This means that if the value could belong to more than type in the +coercion object, the first coercion added is used. + +=item B<< Moose::Meta::TypeCoercion->meta >> + +This will return a L<Class::MOP::Class> instance for this class. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeCoercion/Union.pm b/lib/Moose/Meta/TypeCoercion/Union.pm new file mode 100644 index 0000000..5ef179d --- /dev/null +++ b/lib/Moose/Meta/TypeCoercion/Union.pm @@ -0,0 +1,145 @@ +package Moose::Meta::TypeCoercion::Union; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; + +use parent 'Moose::Meta::TypeCoercion'; + +use Moose::Util 'throw_exception'; + +sub compile_type_coercion { + my $self = shift; + my $type_constraint = $self->type_constraint; + + (blessed $type_constraint && $type_constraint->isa('Moose::Meta::TypeConstraint::Union')) + || throw_exception( NeedsTypeConstraintUnionForTypeCoercionUnion => type_coercion_union_object => $self, + type_name => $type_constraint->name + ); + + $self->_compiled_type_coercion( + sub { + my $value = shift; + + foreach my $type ( grep { $_->has_coercion } + @{ $type_constraint->type_constraints } ) { + my $temp = $type->coerce($value); + return $temp if $type_constraint->check($temp); + } + + return $value; + } + ); +} + +sub has_coercion_for_type { 0 } + +sub add_type_coercions { + my $self = shift; + throw_exception( CannotAddAdditionalTypeCoercionsToUnion => type_coercion_union_object => $self ); +} + +1; + +# ABSTRACT: The Moose Type Coercion metaclass for Unions + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeCoercion::Union - The Moose Type Coercion metaclass for Unions + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This is a subclass of L<Moose::Meta::TypeCoercion> that is used for +L<Moose::Meta::TypeConstraint::Union> objects. + +=head1 METHODS + +=over 4 + +=item B<< $coercion->has_coercion_for_type >> + +This method always returns false. + +=item B<< $coercion->add_type_coercions >> + +This method always throws an error. You cannot add coercions to a +union type coercion. + +=item B<< $coercion->coerce($value) >> + +This method will coerce by trying the coercions for each type in the +union. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint.pm b/lib/Moose/Meta/TypeConstraint.pm new file mode 100644 index 0000000..e943eec --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint.pm @@ -0,0 +1,604 @@ +package Moose::Meta::TypeConstraint; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use overload '0+' => sub { refaddr(shift) }, # id an object + '""' => sub { shift->name }, # stringify to tc name + bool => sub { 1 }, + fallback => 1; + +use Eval::Closure; +use Scalar::Util qw(refaddr); +use Sub::Name qw(subname); +use Try::Tiny; + +use base 'Class::MOP::Object'; + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('name' => ( + reader => 'name', + Class::MOP::_definition_context(), +)); +__PACKAGE__->meta->add_attribute('parent' => ( + reader => 'parent', + predicate => 'has_parent', + Class::MOP::_definition_context(), +)); + +my $null_constraint = sub { 1 }; +__PACKAGE__->meta->add_attribute('constraint' => ( + reader => 'constraint', + writer => '_set_constraint', + default => sub { $null_constraint }, + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('message' => ( + accessor => 'message', + predicate => 'has_message', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('_default_message' => ( + accessor => '_default_message', + Class::MOP::_definition_context(), +)); + +# can't make this a default because it has to close over the type name, and +# cmop attributes don't have lazy +my $_default_message_generator = sub { + my $name = shift; + sub { + my $value = shift; + # have to load it late like this, since it uses Moose itself + my $can_partialdump = try { + # versions prior to 0.14 had a potential infinite loop bug + require Devel::PartialDump; + Devel::PartialDump->VERSION(0.14); + 1; + }; + if ($can_partialdump) { + $value = Devel::PartialDump->new->dump($value); + } + else { + $value = (defined $value ? overload::StrVal($value) : 'undef'); + } + return "Validation failed for '" . $name . "' with value $value"; + } +}; +__PACKAGE__->meta->add_attribute('coercion' => ( + accessor => 'coercion', + predicate => 'has_coercion', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('inlined' => ( + init_arg => 'inlined', + accessor => 'inlined', + predicate => '_has_inlined_type_constraint', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('inline_environment' => ( + init_arg => 'inline_environment', + accessor => '_inline_environment', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +sub parents { + my $self = shift; + $self->parent; +} + +# private accessors + +__PACKAGE__->meta->add_attribute('compiled_type_constraint' => ( + accessor => '_compiled_type_constraint', + predicate => '_has_compiled_type_constraint', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('package_defined_in' => ( + accessor => '_package_defined_in', + Class::MOP::_definition_context(), +)); + +sub new { + my $class = shift; + my ($first, @rest) = @_; + my %args = ref $first ? %$first : $first ? ($first, @rest) : (); + $args{name} = $args{name} ? "$args{name}" : "__ANON__"; + + if ( exists $args{message} + && (!ref($args{message}) || ref($args{message}) ne 'CODE') ) { + throw_exception( MessageParameterMustBeCodeRef => params => \%args, + class => $class + ); + } + + my $self = $class->_new(%args); + $self->compile_type_constraint() + unless $self->_has_compiled_type_constraint; + $self->_default_message($_default_message_generator->($self->name)) + unless $self->has_message; + return $self; +} + + + +sub coerce { + my $self = shift; + + my $coercion = $self->coercion; + + unless ($coercion) { + throw_exception( CoercingWithoutCoercions => type_name => $self->name ); + } + + return $_[0] if $self->check($_[0]); + + return $coercion->coerce(@_); +} + +sub assert_coerce { + my $self = shift; + + my $result = $self->coerce(@_); + + $self->assert_valid($result); + + return $result; +} + +sub check { + my ($self, @args) = @_; + my $constraint_subref = $self->_compiled_type_constraint; + return $constraint_subref->(@args) ? 1 : undef; +} + +sub validate { + my ($self, $value) = @_; + if ($self->_compiled_type_constraint->($value)) { + return undef; + } + else { + $self->get_message($value); + } +} + +sub can_be_inlined { + my $self = shift; + + if ( $self->has_parent && $self->constraint == $null_constraint ) { + return $self->parent->can_be_inlined; + } + + return $self->_has_inlined_type_constraint; +} + +sub _inline_check { + my $self = shift; + + unless ( $self->can_be_inlined ) { + throw_exception( CannotInlineTypeConstraintCheck => type_name => $self->name ); + } + + if ( $self->has_parent && $self->constraint == $null_constraint ) { + return $self->parent->_inline_check(@_); + } + + return '( do { ' . $self->inlined->( $self, @_ ) . ' } )'; +} + +sub inline_environment { + my $self = shift; + + if ( $self->has_parent && $self->constraint == $null_constraint ) { + return $self->parent->inline_environment; + } + + return $self->_inline_environment; +} + +sub assert_valid { + my ( $self, $value ) = @_; + + return 1 if $self->check($value); + + throw_exception( + 'ValidationFailedForTypeConstraint', + type => $self, + value => $value + ); +} + +sub get_message { + my ($self, $value) = @_; + my $msg = $self->has_message + ? $self->message + : $self->_default_message; + local $_ = $value; + return $msg->($value); +} + +## type predicates ... + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return; + + return 1 if $self == $other; + + return unless $self->constraint == $other->constraint; + + if ( $self->has_parent ) { + return unless $other->has_parent; + return unless $self->parent->equals( $other->parent ); + } else { + return if $other->has_parent; + } + + return; +} + +sub is_a_type_of { + my ($self, $type_or_name) = @_; + + my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return; + + ($self->equals($type) || $self->is_subtype_of($type)); +} + +sub is_subtype_of { + my ($self, $type_or_name) = @_; + + my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return; + + my $current = $self; + + while (my $parent = $current->parent) { + return 1 if $parent->equals($type); + $current = $parent; + } + + return 0; +} + +## compiling the type constraint + +sub compile_type_constraint { + my $self = shift; + $self->_compiled_type_constraint($self->_actually_compile_type_constraint); +} + +## type compilers ... + +sub _actually_compile_type_constraint { + my $self = shift; + + if ( $self->can_be_inlined ) { + return eval_closure( + source => 'sub { ' . $self->_inline_check('$_[0]') . ' }', + environment => $self->inline_environment, + ); + } + + my $check = $self->constraint; + unless ( defined $check ) { + throw_exception( NoConstraintCheckForTypeConstraint => type_name => $self->name ); + } + + return $self->_compile_subtype($check) + if $self->has_parent; + + return $self->_compile_type($check); +} + +sub _compile_subtype { + my ($self, $check) = @_; + + # gather all the parent constraints in order + my @parents; + foreach my $parent ($self->_collect_all_parents) { + push @parents => $parent->constraint; + } + + @parents = grep { $_ != $null_constraint } reverse @parents; + + unless ( @parents ) { + return $self->_compile_type($check); + } else { + # general case, check all the constraints, from the first parent to ourselves + my @checks = @parents; + push @checks, $check if $check != $null_constraint; + return subname($self->name => sub { + my (@args) = @_; + local $_ = $args[0]; + foreach my $check (@checks) { + return undef unless $check->(@args); + } + return 1; + }); + } +} + +sub _compile_type { + my ($self, $check) = @_; + + return $check if $check == $null_constraint; # Item, Any + + return subname($self->name => sub { + my (@args) = @_; + local $_ = $args[0]; + $check->(@args); + }); +} + +## other utils ... + +sub _collect_all_parents { + my $self = shift; + my @parents; + my $current = $self->parent; + while (defined $current) { + push @parents => $current; + $current = $current->parent; + } + return @parents; +} + +sub create_child_type { + my ($self, %opts) = @_; + my $class = ref $self; + return $class->new(%opts, parent => $self); +} + +1; + +# ABSTRACT: The Moose Type Constraint metaclass + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents a single type constraint. Moose's built-in type +constraints, as well as constraints you define, are all stored in a +L<Moose::Meta::TypeConstraint::Registry> object as objects of this +class. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint->new(%options) >> + +This creates a new type constraint based on the provided C<%options>: + +=over 8 + +=item * name + +The constraint name. If a name is not provided, it will be set to +"__ANON__". + +=item * parent + +A C<Moose::Meta::TypeConstraint> object which is the parent type for +the type being created. This is optional. + +=item * constraint + +This is the subroutine reference that implements the actual constraint +check. This defaults to a subroutine which always returns true. + +=item * message + +A subroutine reference which is used to generate an error message when +the constraint fails. This is optional. + +=item * coercion + +A L<Moose::Meta::TypeCoercion> object representing the coercions to +the type. This is optional. + +=item * inlined + +A subroutine which returns a string suitable for inlining this type +constraint. It will be called as a method on the type constraint object, and +will receive a single additional parameter, a variable name to be tested +(usually C<"$_"> or C<"$_[0]">. + +This is optional. + +=item * inline_environment + +A hash reference of variables to close over. The keys are variables names, and +the values are I<references> to the variables. + +=back + +=item B<< $constraint->equals($type_name_or_object) >> + +Returns true if the supplied name or type object is the same as the +current type. + +=item B<< $constraint->is_subtype_of($type_name_or_object) >> + +Returns true if the supplied name or type object is a parent of the +current type. + +=item B<< $constraint->is_a_type_of($type_name_or_object) >> + +Returns true if the given type is the same as the current type, or is +a parent of the current type. This is a shortcut for checking +C<equals> and C<is_subtype_of>. + +=item B<< $constraint->coerce($value) >> + +This will attempt to coerce the value to the type. If the type does not +have any defined coercions this will throw an error. + +If no coercion can produce a value matching C<$constraint>, the original +value is returned. + +=item B<< $constraint->assert_coerce($value) >> + +This method behaves just like C<coerce>, but if the result is not valid +according to C<$constraint>, an error is thrown. + +=item B<< $constraint->check($value) >> + +Returns true if the given value passes the constraint for the type. + +=item B<< $constraint->validate($value) >> + +This is similar to C<check>. However, if the type I<is valid> then the +method returns an explicit C<undef>. If the type is not valid, we call +C<< $self->get_message($value) >> internally to generate an error +message. + +=item B<< $constraint->assert_valid($value) >> + +Like C<check> and C<validate>, this method checks whether C<$value> is +valid under the constraint. If it is, it will return true. If it is not, +an exception will be thrown with the results of +C<< $self->get_message($value) >>. + +=item B<< $constraint->name >> + +Returns the type's name, as provided to the constructor. + +=item B<< $constraint->parent >> + +Returns the type's parent, as provided to the constructor, if any. + +=item B<< $constraint->has_parent >> + +Returns true if the type has a parent type. + +=item B<< $constraint->parents >> + +Returns all of the types parents as an list of type constraint objects. + +=item B<< $constraint->constraint >> + +Returns the type's constraint, as provided to the constructor. + +=item B<< $constraint->get_message($value) >> + +This generates a method for the given value. If the type does not have +an explicit message, we generate a default message. + +=item B<< $constraint->has_message >> + +Returns true if the type has a message. + +=item B<< $constraint->message >> + +Returns the type's message as a subroutine reference. + +=item B<< $constraint->coercion >> + +Returns the type's L<Moose::Meta::TypeCoercion> object, if one +exists. + +=item B<< $constraint->has_coercion >> + +Returns true if the type has a coercion. + +=item B<< $constraint->can_be_inlined >> + +Returns true if this type constraint can be inlined. A type constraint which +subtypes an inlinable constraint and does not add an additional constraint +"inherits" its parent type's inlining. + +=item B<< $constraint->create_child_type(%options) >> + +This returns a new type constraint of the same class using the +provided C<%options>. The C<parent> option will be the current type. + +This method exists so that subclasses of this class can override this +behavior and change how child types are created. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Class.pm b/lib/Moose/Meta/TypeConstraint/Class.pm new file mode 100644 index 0000000..2f5e5c3 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Class.pm @@ -0,0 +1,265 @@ +package Moose::Meta::TypeConstraint::Class; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use B; +use Scalar::Util (); +use Moose::Util::TypeConstraints (); + +use parent 'Moose::Meta::TypeConstraint'; + +__PACKAGE__->meta->add_attribute('class' => ( + reader => 'class', + Class::MOP::_definition_context(), +)); + +my $inliner = sub { + my $self = shift; + my $val = shift; + + return 'Scalar::Util::blessed(' . $val . ')' + . ' && ' . $val . '->isa(' . B::perlstring($self->class) . ')'; +}; + +sub new { + my ( $class, %args ) = @_; + + $args{parent} + = Moose::Util::TypeConstraints::find_type_constraint('Object'); + + my $class_name = $args{class}; + $args{constraint} = sub { $_[0]->isa($class_name) }; + + $args{inlined} = $inliner; + + my $self = $class->SUPER::new( \%args ); + + $self->compile_type_constraint(); + + return $self; +} + +sub parents { + my $self = shift; + return ( + $self->parent, + map { + # FIXME find_type_constraint might find a TC named after the class but that isn't really it + # I did this anyway since it's a convention that preceded TypeConstraint::Class, and it should DWIM + # if anybody thinks this problematic please discuss on IRC. + # a possible fix is to add by attr indexing to the type registry to find types of a certain property + # regardless of their name + Moose::Util::TypeConstraints::find_type_constraint($_) + || + __PACKAGE__->new( class => $_, name => "__ANON__" ) + } Class::MOP::class_of($self->class)->superclasses, + ); +} + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + if (!defined($other)) { + if (!ref($type_or_name)) { + return $self->class eq $type_or_name; + } + return; + } + + return unless $other->isa(__PACKAGE__); + + return $self->class eq $other->class; +} + +sub is_a_type_of { + my ($self, $type_or_name) = @_; + + ($self->equals($type_or_name) || $self->is_subtype_of($type_or_name)); +} + +sub is_subtype_of { + my ($self, $type_or_name_or_class ) = @_; + + my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name_or_class); + + if ( not defined $type ) { + if ( not ref $type_or_name_or_class ) { + # it might be a class + my $class = $self->class; + return 1 if $class ne $type_or_name_or_class + && $class->isa( $type_or_name_or_class ); + } + return; + } + + if ( $type->isa(__PACKAGE__) && $type->class ne $self->class) { + # if $type_or_name_or_class isn't a class, it might be the TC name of another ::Class type + # or it could also just be a type object in this branch + return $self->class->isa( $type->class ); + } else { + # the only other thing we are a subtype of is Object + $self->SUPER::is_subtype_of($type); + } +} + +# This is a bit counter-intuitive, but a child type of a Class type +# constraint is not itself a Class type constraint (it has no class +# attribute). This whole create_child_type thing needs some changing +# though, probably making MMC->new a factory or something. +sub create_child_type { + my ($self, @args) = @_; + return Moose::Meta::TypeConstraint->new(@args, parent => $self); +} + +sub get_message { + my $self = shift; + my ($value) = @_; + + if ($self->has_message) { + return $self->SUPER::get_message(@_); + } + + $value = (defined $value ? overload::StrVal($value) : 'undef'); + return "Validation failed for '" . $self->name . "' with value $value (not isa " . $self->class . ")"; +} + +1; + +# ABSTRACT: Class/TypeConstraint parallel hierarchy + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Class - Class/TypeConstraint parallel hierarchy + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents type constraints for a class. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Class> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::Class->new(%options) >> + +This creates a new class type constraint based on the given +C<%options>. + +It takes the same options as its parent, with two exceptions. First, +it requires an additional option, C<class>, which is name of the +constraint's class. Second, it automatically sets the parent to the +C<Object> type. + +The constructor also overrides the hand optimized type constraint with +one it creates internally. + +=item B<< $constraint->class >> + +Returns the class name associated with the constraint. + +=item B<< $constraint->parents >> + +Returns all the type's parent types, corresponding to its parent +classes. + +=item B<< $constraint->is_subtype_of($type_name_or_object) >> + +If the given type is also a class type, then this checks that the +type's class is a subclass of the other type's class. + +Otherwise it falls back to the implementation in +L<Moose::Meta::TypeConstraint>. + +=item B<< $constraint->create_child_type(%options) >> + +This returns a new L<Moose::Meta::TypeConstraint> object with the type +as its parent. + +Note that it does I<not> return a +C<Moose::Meta::TypeConstraint::Class> object! + +=item B<< $constraint->get_message($value) >> + +This is the same as L<Moose::Meta::TypeConstraint/get_message> except +that it explicitly says C<isa> was checked. This is to help users deal +with accidentally autovivified type constraints. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/DuckType.pm b/lib/Moose/Meta/TypeConstraint/DuckType.pm new file mode 100644 index 0000000..7304f35 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/DuckType.pm @@ -0,0 +1,221 @@ +package Moose::Meta::TypeConstraint::DuckType; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use B; +use Scalar::Util 'blessed'; +use List::Util 1.33 qw(all); +use Moose::Util 'english_list'; + +use Moose::Util::TypeConstraints (); + +use parent 'Moose::Meta::TypeConstraint'; + +__PACKAGE__->meta->add_attribute('methods' => ( + accessor => 'methods', + Class::MOP::_definition_context(), +)); + +my $inliner = sub { + my $self = shift; + my $val = shift; + + return $self->parent->_inline_check($val) + . ' && do {' . "\n" + . 'my $val = ' . $val . ';' . "\n" + . '&List::Util::all(' . "\n" + . 'sub { $val->can($_) },' . "\n" + . join(', ', map { B::perlstring($_) } @{ $self->methods }) + . ');' . "\n" + . '}'; +}; + +sub new { + my ( $class, %args ) = @_; + + $args{parent} + = Moose::Util::TypeConstraints::find_type_constraint('Object'); + + my @methods = @{ $args{methods} }; + $args{constraint} = sub { + my $val = $_[0]; + return all { $val->can($_) } @methods; + }; + + $args{inlined} = $inliner; + + my $self = $class->SUPER::new(\%args); + + $self->compile_type_constraint() + unless $self->_has_compiled_type_constraint; + + return $self; +} + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + return unless $other->isa(__PACKAGE__); + + my @self_methods = sort @{ $self->methods }; + my @other_methods = sort @{ $other->methods }; + + return unless @self_methods == @other_methods; + + while ( @self_methods ) { + my $method = shift @self_methods; + my $other_method = shift @other_methods; + + return unless $method eq $other_method; + } + + return 1; +} + +sub create_child_type { + my ($self, @args) = @_; + return Moose::Meta::TypeConstraint->new(@args, parent => $self); +} + +sub get_message { + my $self = shift; + my ($value) = @_; + + if ($self->has_message) { + return $self->SUPER::get_message(@_); + } + + return $self->SUPER::get_message($value) unless blessed($value); + + my @methods = grep { !$value->can($_) } @{ $self->methods }; + my $class = blessed $value; + $class ||= $value; + + return $class + . " is missing methods " + . english_list(map { "'$_'" } @methods); +} + +1; + +# ABSTRACT: Type constraint for duck typing + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::DuckType - Type constraint for duck typing + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents type constraints based on an enumerated list of +required methods. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::DuckType> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::DuckType->new(%options) >> + +This creates a new duck type constraint based on the given +C<%options>. + +It takes the same options as its parent, with several +exceptions. First, it requires an additional option, C<methods>. This +should be an array reference containing a list of required method +names. Second, it automatically sets the parent to the C<Object> type. + +Finally, it ignores any provided C<constraint> option. The constraint +is generated automatically based on the provided C<methods>. + +=item B<< $constraint->methods >> + +Returns the array reference of required methods provided to the +constructor. + +=item B<< $constraint->create_child_type >> + +This returns a new L<Moose::Meta::TypeConstraint> object with the type +as its parent. + +Note that it does I<not> return a C<Moose::Meta::TypeConstraint::DuckType> +object! + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Enum.pm b/lib/Moose/Meta/TypeConstraint/Enum.pm new file mode 100644 index 0000000..9e1204d --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Enum.pm @@ -0,0 +1,230 @@ +package Moose::Meta::TypeConstraint::Enum; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use B; +use Moose::Util::TypeConstraints (); + +use parent 'Moose::Meta::TypeConstraint'; + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('values' => ( + accessor => 'values', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('_inline_var_name' => ( + accessor => '_inline_var_name', + Class::MOP::_definition_context(), +)); + +my $inliner = sub { + my $self = shift; + my $val = shift; + + return 'defined(' . $val . ') ' + . '&& !ref(' . $val . ') ' + . '&& $' . $self->_inline_var_name . '{' . $val . '}'; +}; + +my $var_suffix = 0; + +sub new { + my ( $class, %args ) = @_; + + $args{parent} = Moose::Util::TypeConstraints::find_type_constraint('Str'); + $args{inlined} = $inliner; + + if ( scalar @{ $args{values} } < 1 ) { + throw_exception( MustHaveAtLeastOneValueToEnumerate => params => \%args, + class => $class + ); + } + + for (@{ $args{values} }) { + if (!defined($_)) { + throw_exception( EnumValuesMustBeString => params => \%args, + class => $class, + value => $_ + ); + } + elsif (ref($_)) { + throw_exception( EnumValuesMustBeString => params => \%args, + class => $class, + value => $_ + ); + } + } + + my %values = map { $_ => 1 } @{ $args{values} }; + $args{constraint} = sub { $values{ $_[0] } }; + + my $var_name = 'enums' . $var_suffix++;; + $args{_inline_var_name} = $var_name; + $args{inline_environment} = { '%' . $var_name => \%values }; + + my $self = $class->SUPER::new(\%args); + + $self->compile_type_constraint() + unless $self->_has_compiled_type_constraint; + + return $self; +} + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + return unless $other->isa(__PACKAGE__); + + my @self_values = sort @{ $self->values }; + my @other_values = sort @{ $other->values }; + + return unless @self_values == @other_values; + + while ( @self_values ) { + my $value = shift @self_values; + my $other_value = shift @other_values; + + return unless $value eq $other_value; + } + + return 1; +} + +sub constraint { + my $self = shift; + + my %values = map { $_ => undef } @{ $self->values }; + + return sub { exists $values{$_[0]} }; +} + +sub create_child_type { + my ($self, @args) = @_; + return Moose::Meta::TypeConstraint->new(@args, parent => $self); +} + +1; + +# ABSTRACT: Type constraint for enumerated values. + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Enum - Type constraint for enumerated values. + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents type constraints based on an enumerated list of +acceptable values. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Enum> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::Enum->new(%options) >> + +This creates a new enum type constraint based on the given +C<%options>. + +It takes the same options as its parent, with several +exceptions. First, it requires an additional option, C<values>. This +should be an array reference containing a list of valid string +values. Second, it automatically sets the parent to the C<Str> type. + +Finally, it ignores any provided C<constraint> option. The constraint +is generated automatically based on the provided C<values>. + +=item B<< $constraint->values >> + +Returns the array reference of acceptable values provided to the +constructor. + +=item B<< $constraint->create_child_type >> + +This returns a new L<Moose::Meta::TypeConstraint> object with the type +as its parent. + +Note that it does I<not> return a C<Moose::Meta::TypeConstraint::Enum> +object! + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Parameterizable.pm b/lib/Moose/Meta/TypeConstraint/Parameterizable.pm new file mode 100644 index 0000000..250e4e6 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Parameterizable.pm @@ -0,0 +1,200 @@ +package Moose::Meta::TypeConstraint::Parameterizable; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use parent 'Moose::Meta::TypeConstraint'; +use Moose::Meta::TypeConstraint::Parameterized; +use Moose::Util::TypeConstraints (); + +use Moose::Util 'throw_exception'; + +use Carp 'confess'; + +__PACKAGE__->meta->add_attribute('constraint_generator' => ( + accessor => 'constraint_generator', + predicate => 'has_constraint_generator', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('inline_generator' => ( + accessor => 'inline_generator', + predicate => 'has_inline_generator', + Class::MOP::_definition_context(), +)); + +sub generate_constraint_for { + my ($self, $type) = @_; + + return unless $self->has_constraint_generator; + + return $self->constraint_generator->($type->type_parameter) + if $type->is_subtype_of($self->name); + + return $self->_can_coerce_constraint_from($type) + if $self->has_coercion + && $self->coercion->has_coercion_for_type($type->parent->name); + + return; +} + +sub _can_coerce_constraint_from { + my ($self, $type) = @_; + my $coercion = $self->coercion; + my $constraint = $self->constraint_generator->($type->type_parameter); + return sub { + local $_ = $coercion->coerce($_); + $constraint->(@_); + }; +} + +sub generate_inline_for { + my ($self, $type, $val) = @_; + + throw_exception( CannotGenerateInlineConstraint => parameterizable_type_object_name => $self->name, + type_name => $type->name, + value => $val, + ) + unless $self->has_inline_generator; + + return '( do { ' . $self->inline_generator->( $self, $type, $val ) . ' } )'; +} + +sub _parse_type_parameter { + my ($self, $type_parameter) = @_; + return Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($type_parameter); +} + +sub parameterize { + my ($self, $type_parameter) = @_; + + my $contained_tc = $self->_parse_type_parameter($type_parameter); + + ## The type parameter should be a subtype of the parent's type parameter + ## if there is one. + + if(my $parent = $self->parent) { + if($parent->can('type_parameter')) { + unless ( $contained_tc->is_a_type_of($parent->type_parameter) ) { + throw_exception( ParameterIsNotSubtypeOfParent => type_parameter => $type_parameter, + type_name => $self->name, + ); + } + } + } + + if ( $contained_tc->isa('Moose::Meta::TypeConstraint') ) { + my $tc_name = $self->name . '[' . $contained_tc->name . ']'; + return Moose::Meta::TypeConstraint::Parameterized->new( + name => $tc_name, + parent => $self, + type_parameter => $contained_tc, + parameterized_from => $self, + ); + } + else { + confess("The type parameter must be a Moose meta type"); + } +} + + +1; + +# ABSTRACT: Type constraints which can take a parameter (ArrayRef) + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Parameterizable - Type constraints which can take a parameter (ArrayRef) + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents a parameterizable type constraint. This is a +type constraint like C<ArrayRef> or C<HashRef>, that can be +parameterized and made more specific by specifying a contained +type. For example, instead of just an C<ArrayRef> of anything, you can +specify that is an C<ArrayRef[Int]>. + +A parameterizable constraint should not be used as an attribute type +constraint. Instead, when parameterized it creates a +L<Moose::Meta::TypeConstraint::Parameterized> which should be used. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Parameterizable> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 METHODS + +This class is intentionally not documented because the API is +confusing and needs some work. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Parameterized.pm b/lib/Moose/Meta/TypeConstraint/Parameterized.pm new file mode 100644 index 0000000..8db9c88 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Parameterized.pm @@ -0,0 +1,188 @@ +package Moose::Meta::TypeConstraint::Parameterized; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; +use Moose::Util::TypeConstraints; +use Moose::Meta::TypeConstraint::Parameterizable; +use Moose::Util 'throw_exception'; + +use parent 'Moose::Meta::TypeConstraint'; + +__PACKAGE__->meta->add_attribute('type_parameter' => ( + accessor => 'type_parameter', + predicate => 'has_type_parameter', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('parameterized_from' => ( + accessor => 'parameterized_from', + predicate => 'has_parameterized_from', + Class::MOP::_definition_context(), +)); + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + return unless $other->isa(__PACKAGE__); + + return ( + $self->type_parameter->equals( $other->type_parameter ) + and + $self->parent->equals( $other->parent ) + ); +} + +sub compile_type_constraint { + my $self = shift; + + unless ( $self->has_type_parameter ) { + throw_exception( CannotCreateHigherOrderTypeWithoutATypeParameter => type_name => $self->name ); + } + + my $type_parameter = $self->type_parameter; + + unless ( blessed $type_parameter && $type_parameter->isa('Moose::Meta::TypeConstraint') ) { + throw_exception( TypeParameterMustBeMooseMetaType => type_name => $self->name ); + } + + foreach my $type (Moose::Util::TypeConstraints::get_all_parameterizable_types()) { + if (my $constraint = $type->generate_constraint_for($self)) { + $self->_set_constraint($constraint); + return $self->SUPER::compile_type_constraint; + } + } + + # if we get here, then we couldn't + # find a way to parameterize this type + throw_exception( TypeConstraintCannotBeUsedForAParameterizableType => type_name => $self->name, + parent_type_name => $self->parent->name, + ); +} + +sub can_be_inlined { + my $self = shift; + + return + $self->has_parameterized_from + && $self->parameterized_from->has_inline_generator + && $self->type_parameter->can_be_inlined; +} + +sub inline_environment { + my $self = shift; + + return { + ($self->has_parameterized_from + ? (%{ $self->parameterized_from->inline_environment }) + : ()), + ($self->has_type_parameter + ? (%{ $self->type_parameter->inline_environment }) + : ()), + }; +} + +sub _inline_check { + my $self = shift; + + return unless $self->can_be_inlined; + + return $self->parameterized_from->generate_inline_for( $self->type_parameter, @_ ); +} + +sub create_child_type { + my ($self, %opts) = @_; + return Moose::Meta::TypeConstraint::Parameterizable->new(%opts, parent=>$self); +} + +1; + +# ABSTRACT: Type constraints with a bound parameter (ArrayRef[Int]) + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Parameterized - Type constraints with a bound parameter (ArrayRef[Int]) + +=head1 VERSION + +version 2.1405 + +=head1 METHODS + +This class is intentionally not documented because the API is +confusing and needs some work. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Parameterized> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Registry.pm b/lib/Moose/Meta/TypeConstraint/Registry.pm new file mode 100644 index 0000000..7c534a7 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Registry.pm @@ -0,0 +1,210 @@ +package Moose::Meta::TypeConstraint::Registry; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Scalar::Util 'blessed'; + +use parent 'Class::MOP::Object'; + +use Moose::Util 'throw_exception'; + +__PACKAGE__->meta->add_attribute('parent_registry' => ( + reader => 'get_parent_registry', + writer => 'set_parent_registry', + predicate => 'has_parent_registry', + Class::MOP::_definition_context(), +)); + +__PACKAGE__->meta->add_attribute('type_constraints' => ( + reader => 'type_constraints', + default => sub { {} }, + Class::MOP::_definition_context(), +)); + +sub new { + my $class = shift; + my $self = $class->_new(@_); + return $self; +} + +sub has_type_constraint { + my ($self, $type_name) = @_; + ($type_name and exists $self->type_constraints->{$type_name}) ? 1 : 0 +} + +sub get_type_constraint { + my ($self, $type_name) = @_; + return unless defined $type_name; + $self->type_constraints->{$type_name} +} + +sub add_type_constraint { + my ($self, $type) = @_; + + unless ( $type && blessed $type && $type->isa('Moose::Meta::TypeConstraint') ) { + throw_exception( InvalidTypeConstraint => registry_object => $self, + type => $type + ); + } + + $self->type_constraints->{$type->name} = $type; +} + +sub find_type_constraint { + my ($self, $type_name) = @_; + return $self->get_type_constraint($type_name) + if $self->has_type_constraint($type_name); + return $self->get_parent_registry->find_type_constraint($type_name) + if $self->has_parent_registry; + return; +} + +1; + +# ABSTRACT: registry for type constraints + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Registry - registry for type constraints + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is a registry that maps type constraint names to +L<Moose::Meta::TypeConstraint> objects. + +Currently, it is only used internally by +L<Moose::Util::TypeConstraints>, which creates a single global +registry. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Registry> is a subclass of +L<Class::MOP::Object>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::Registry->new(%options) >> + +This creates a new registry object based on the provided C<%options>: + +=over 8 + +=item * parent_registry + +This is an optional L<Moose::Meta::TypeConstraint::Registry> +object. + +=item * type_constraints + +This is hash reference of type names to type objects. This is +optional. Constraints can be added to the registry after it is +created. + +=back + +=item B<< $registry->get_parent_registry >> + +Returns the registry's parent registry, if it has one. + +=item B<< $registry->has_parent_registry >> + +Returns true if the registry has a parent. + +=item B<< $registry->set_parent_registry($registry) >> + +Sets the parent registry. + +=item B<< $registry->get_type_constraint($type_name) >> + +This returns the L<Moose::Meta::TypeConstraint> object from the +registry for the given name, if one exists. + +=item B<< $registry->has_type_constraint($type_name) >> + +Returns true if the registry has a type of the given name. + +=item B<< $registry->add_type_constraint($type) >> + +Adds a new L<Moose::Meta::TypeConstraint> object to the registry. + +=item B<< $registry->find_type_constraint($type_name) >> + +This method looks in the current registry for the named type. If the +type is not found, then this method will look in the registry's +parent, if it has one. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Role.pm b/lib/Moose/Meta/TypeConstraint/Role.pm new file mode 100644 index 0000000..db609d9 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Role.pm @@ -0,0 +1,239 @@ +package Moose::Meta::TypeConstraint::Role; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use B; +use Moose::Util::TypeConstraints (); +use Moose::Util (); + +use parent 'Moose::Meta::TypeConstraint'; + +__PACKAGE__->meta->add_attribute('role' => ( + reader => 'role', + Class::MOP::_definition_context(), +)); + +my $inliner = sub { + my $self = shift; + my $val = shift; + + return 'Moose::Util::does_role(' + . $val . ', ' + . B::perlstring($self->role) + . ')'; +}; + +sub new { + my ( $class, %args ) = @_; + + $args{parent} = Moose::Util::TypeConstraints::find_type_constraint('Object'); + + my $role_name = $args{role}; + $args{constraint} = sub { Moose::Util::does_role( $_[0], $role_name ) }; + + $args{inlined} = $inliner; + + my $self = $class->SUPER::new( \%args ); + + $self->compile_type_constraint(); + + return $self; +} + +sub parents { + my $self = shift; + return ( + $self->parent, + map { + # FIXME find_type_constraint might find a TC named after the role but that isn't really it + # I did this anyway since it's a convention that preceded TypeConstraint::Role, and it should DWIM + # if anybody thinks this problematic please discuss on IRC. + # a possible fix is to add by attr indexing to the type registry to find types of a certain property + # regardless of their name + Moose::Util::TypeConstraints::find_type_constraint($_) + || + __PACKAGE__->new( role => $_, name => "__ANON__" ) + } @{ Class::MOP::class_of($self->role)->get_roles }, + ); +} + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + return unless defined $other; + return unless $other->isa(__PACKAGE__); + + return $self->role eq $other->role; +} + +sub is_a_type_of { + my ($self, $type_or_name) = @_; + + my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + ($self->equals($type) || $self->is_subtype_of($type_or_name)); +} + +sub is_subtype_of { + my ($self, $type_or_name_or_role ) = @_; + + if ( not ref $type_or_name_or_role ) { + # it might be a role + my $class = Class::MOP::class_of($self->role); + return 1 if defined($class) && $class->does_role( $type_or_name_or_role ); + } + + my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name_or_role); + + return unless defined $type; + + if ( $type->isa(__PACKAGE__) ) { + # if $type_or_name_or_role isn't a role, it might be the TC name of another ::Role type + # or it could also just be a type object in this branch + my $class = Class::MOP::class_of($self->role); + return defined($class) && $class->does_role( $type->role ); + } else { + # the only other thing we are a subtype of is Object + $self->SUPER::is_subtype_of($type); + } +} + +sub create_child_type { + my ($self, @args) = @_; + return Moose::Meta::TypeConstraint->new(@args, parent => $self); +} + +1; + +# ABSTRACT: Role/TypeConstraint parallel hierarchy + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Role - Role/TypeConstraint parallel hierarchy + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class represents type constraints for a role. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Role> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::Role->new(%options) >> + +This creates a new role type constraint based on the given +C<%options>. + +It takes the same options as its parent, with two exceptions. First, +it requires an additional option, C<role>, which is name of the +constraint's role. Second, it automatically sets the parent to the +C<Object> type. + +The constructor also overrides the hand optimized type constraint with +one it creates internally. + +=item B<< $constraint->role >> + +Returns the role name associated with the constraint. + +=item B<< $constraint->parents >> + +Returns all the type's parent types, corresponding to the roles that +its role does. + +=item B<< $constraint->is_subtype_of($type_name_or_object) >> + +If the given type is also a role type, then this checks that the +type's role does the other type's role. + +Otherwise it falls back to the implementation in +L<Moose::Meta::TypeConstraint>. + +=item B<< $constraint->create_child_type(%options) >> + +This returns a new L<Moose::Meta::TypeConstraint> object with the type +as its parent. + +Note that it does I<not> return a C<Moose::Meta::TypeConstraint::Role> +object! + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Meta/TypeConstraint/Union.pm b/lib/Moose/Meta/TypeConstraint/Union.pm new file mode 100644 index 0000000..da85f86 --- /dev/null +++ b/lib/Moose/Meta/TypeConstraint/Union.pm @@ -0,0 +1,348 @@ +package Moose::Meta::TypeConstraint::Union; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use metaclass; + +use Moose::Meta::TypeCoercion::Union; + +use List::Util 1.33 qw(first all); + +use parent 'Moose::Meta::TypeConstraint'; + +__PACKAGE__->meta->add_attribute('type_constraints' => ( + accessor => 'type_constraints', + default => sub { [] }, + Class::MOP::_definition_context(), +)); + +sub new { + my ($class, %options) = @_; + + my $name = join '|' => sort { $a cmp $b } + map { $_->name } @{ $options{type_constraints} }; + + my $self = $class->SUPER::new( + name => $name, + %options, + ); + + $self->_set_constraint( $self->_compiled_type_constraint ); + + return $self; +} + +# XXX - this is a rather gross implementation of laziness for the benefit of +# MX::Types. If we try to call ->has_coercion on the objects during object +# construction, this does not work when defining a recursive constraint with +# MX::Types. +sub coercion { + my $self = shift; + + return $self->{coercion} if exists $self->{coercion}; + + # Using any instead of grep here causes a weird error with some corner + # cases when MX::Types is in use. See RT #61001. + if ( grep { $_->has_coercion } @{ $self->type_constraints } ) { + return $self->{coercion} = Moose::Meta::TypeCoercion::Union->new( + type_constraint => $self ); + } + else { + return $self->{coercion} = undef; + } +} + +sub has_coercion { + return defined $_[0]->coercion; +} + +sub _actually_compile_type_constraint { + my $self = shift; + + my @constraints = @{ $self->type_constraints }; + + return sub { + my $value = shift; + foreach my $type (@constraints) { + return 1 if $type->check($value); + } + return undef; + }; +} + +sub can_be_inlined { + my $self = shift; + + # This was originally done with all() from List::MoreUtils, but that + # caused some sort of bizarro parsing failure under 5.10. + for my $tc ( @{ $self->type_constraints } ) { + return 0 unless $tc->can_be_inlined; + } + + return 1; +} + +sub _inline_check { + my $self = shift; + my $val = shift; + + return '(' + . ( + join ' || ', map { '(' . $_->_inline_check($val) . ')' } + @{ $self->type_constraints } + ) + . ')'; +} + +sub inline_environment { + my $self = shift; + + return { map { %{ $_->inline_environment } } + @{ $self->type_constraints } }; +} + +sub equals { + my ( $self, $type_or_name ) = @_; + + my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name); + + return unless $other->isa(__PACKAGE__); + + my @self_constraints = @{ $self->type_constraints }; + my @other_constraints = @{ $other->type_constraints }; + + return unless @self_constraints == @other_constraints; + + # FIXME presort type constraints for efficiency? + constraint: foreach my $constraint ( @self_constraints ) { + for ( my $i = 0; $i < @other_constraints; $i++ ) { + if ( $constraint->equals($other_constraints[$i]) ) { + splice @other_constraints, $i, 1; + next constraint; + } + } + } + + return @other_constraints == 0; +} + +sub parent { + my $self = shift; + + my ($first, @rest) = @{ $self->type_constraints }; + + for my $parent ( $first->_collect_all_parents ) { + return $parent if all { $_->is_a_type_of($parent) } @rest; + } + + return; +} + +sub validate { + my ($self, $value) = @_; + my $message; + foreach my $type (@{$self->type_constraints}) { + my $err = $type->validate($value); + return unless defined $err; + $message .= ($message ? ' and ' : '') . $err + if defined $err; + } + return ($message . ' in (' . $self->name . ')') ; +} + +sub find_type_for { + my ($self, $value) = @_; + + return first { $_->check($value) } @{ $self->type_constraints }; +} + +sub is_a_type_of { + my ($self, $type_name) = @_; + + return all { $_->is_a_type_of($type_name) } @{ $self->type_constraints }; +} + +sub is_subtype_of { + my ($self, $type_name) = @_; + + return all { $_->is_subtype_of($type_name) } @{ $self->type_constraints }; +} + +sub create_child_type { + my ( $self, %opts ) = @_; + + my $constraint + = Moose::Meta::TypeConstraint->new( %opts, parent => $self ); + + # if we have a type constraint union, and no + # type check, this means we are just aliasing + # the union constraint, which means we need to + # handle this differently. + # - SL + if ( not( defined $opts{constraint} ) + && $self->has_coercion ) { + $constraint->coercion( + Moose::Meta::TypeCoercion::Union->new( + type_constraint => $self, + ) + ); + } + + return $constraint; +} + +1; + +# ABSTRACT: A union of Moose type constraints + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Meta::TypeConstraint::Union - A union of Moose type constraints + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This metaclass represents a union of type constraints. A union takes +multiple type constraints, and is true if any one of its member +constraints is true. + +=head1 INHERITANCE + +C<Moose::Meta::TypeConstraint::Union> is a subclass of +L<Moose::Meta::TypeConstraint>. + +=over 4 + +=item B<< Moose::Meta::TypeConstraint::Union->new(%options) >> + +This creates a new class type constraint based on the given +C<%options>. + +It takes the same options as its parent. It also requires an +additional option, C<type_constraints>. This is an array reference +containing the L<Moose::Meta::TypeConstraint> objects that are the +members of the union type. The C<name> option defaults to the names +all of these member types sorted and then joined by a pipe (|). + +The constructor sets the implementation of the constraint so that is +simply calls C<check> on the newly created object. + +Finally, the constructor also makes sure that the object's C<coercion> +attribute is a L<Moose::Meta::TypeCoercion::Union> object. + +=item B<< $constraint->type_constraints >> + +This returns the array reference of C<type_constraints> provided to +the constructor. + +=item B<< $constraint->parent >> + +This returns the nearest common ancestor of all the components of the union. + +=item B<< $constraint->check($value) >> + +=item B<< $constraint->validate($value) >> + +These two methods simply call the relevant method on each of the +member type constraints in the union. If any type accepts the value, +the value is valid. + +With C<validate> the error message returned includes all of the error +messages returned by the member type constraints. + +=item B<< $constraint->equals($type_name_or_object) >> + +A type is considered equal if it is also a union type, and the two +unions have the same member types. + +=item B<< $constraint->find_type_for($value) >> + +This returns the first member type constraint for which C<check($value)> is +true, allowing you to determine which of the Union's member type constraints +a given value matches. + +=item B<< $constraint->is_a_type_of($type_name_or_object) >> + +This returns true if all of the member type constraints return true +for the C<is_a_type_of> method. + +=item B<< $constraint->is_subtype_of >> + +This returns true if all of the member type constraints return true +for the C<is_a_subtype_of> method. + +=item B<< $constraint->create_child_type(%options) >> + +This returns a new L<Moose::Meta::TypeConstraint> object with the type +as its parent. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Object.pm b/lib/Moose/Object.pm new file mode 100644 index 0000000..63b5c56 --- /dev/null +++ b/lib/Moose/Object.pm @@ -0,0 +1,272 @@ +package Moose::Object; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Carp (); +use Devel::GlobalDestruction (); +use MRO::Compat (); +use Scalar::Util (); +use Try::Tiny (); + +use Moose::Util (); + +use if ( not our $__mx_is_compiled ), 'Moose::Meta::Class'; +use if ( not our $__mx_is_compiled ), metaclass => 'Moose::Meta::Class'; + +sub new { + my $class = shift; + my $real_class = Scalar::Util::blessed($class) || $class; + + my $params = $real_class->BUILDARGS(@_); + + return Class::MOP::Class->initialize($real_class)->new_object($params); +} + +sub BUILDARGS { + my $class = shift; + if ( scalar @_ == 1 ) { + unless ( defined $_[0] && ref $_[0] eq 'HASH' ) { + Moose::Util::throw_exception( "SingleParamsToNewMustBeHashRef" ); + } + return { %{ $_[0] } }; + } + elsif ( @_ % 2 ) { + Carp::carp( + "The new() method for $class expects a hash reference or a key/value list." + . " You passed an odd number of arguments" ); + return { @_, undef }; + } + else { + return {@_}; + } +} + +sub BUILDALL { + # NOTE: we ask Perl if we even + # need to do this first, to avoid + # extra meta level calls + return unless $_[0]->can('BUILD'); + my ($self, $params) = @_; + foreach my $method (reverse Class::MOP::class_of($self)->find_all_methods_by_name('BUILD')) { + $method->{code}->execute($self, $params); + } +} + +sub DEMOLISHALL { + my $self = shift; + my ($in_global_destruction) = @_; + + # NOTE: we ask Perl if we even + # need to do this first, to avoid + # extra meta level calls + return unless $self->can('DEMOLISH'); + + my @isa; + if ( my $meta = Class::MOP::class_of($self ) ) { + @isa = $meta->linearized_isa; + } else { + # We cannot count on being able to retrieve a previously made + # metaclass, _or_ being able to make a new one during global + # destruction. However, we should still be able to use mro at + # that time (at least tests suggest so ;) + my $class_name = ref $self; + @isa = @{ mro::get_linear_isa($class_name) } + } + + foreach my $class (@isa) { + no strict 'refs'; + my $demolish = *{"${class}::DEMOLISH"}{CODE}; + $self->$demolish($in_global_destruction) + if defined $demolish; + } +} + +sub DESTROY { + my $self = shift; + + local $?; + + # < doy> if the destructor is being called because an exception is thrown, then $@ will be set + # < doy> but if DEMOLISH does an eval which succeeds, that will clear $@ + # < doy> which is broken + # < doy> try::tiny implicitly localizes $@ in the try block, which fixes that + Try::Tiny::try { + $self->DEMOLISHALL(Devel::GlobalDestruction::in_global_destruction); + } + Try::Tiny::catch { + die $_; + }; + + return; +} + +# support for UNIVERSAL::DOES ... +BEGIN { + my $does = UNIVERSAL->can("DOES") ? "SUPER::DOES" : "isa"; + eval 'sub DOES { + my ( $self, $class_or_role_name ) = @_; + return $self->'.$does.'($class_or_role_name) + || $self->does($class_or_role_name); + }'; +} + +# new does() methods will be created +# as appropriate see Moose::Meta::Role +sub does { + my ($self, $role_name) = @_; + my $class = Scalar::Util::blessed($self) || $self; + my $meta = Class::MOP::Class->initialize($class); + (defined $role_name) + || Moose::Util::throw_exception( DoesRequiresRoleName => class_name => $meta->name ); + return 1 if $meta->can('does_role') && $meta->does_role($role_name); + return 0; +} + +sub dump { + my $self = shift; + require Data::Dumper; + local $Data::Dumper::Maxdepth = shift if @_; + Data::Dumper::Dumper $self; +} + +1; + +# ABSTRACT: The base object for Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Object - The base object for Moose + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This class is the default base class for all Moose-using classes. When +you C<use Moose> in this class, your class will inherit from this +class. + +It provides a default constructor and destructor, which run all of the +C<BUILD> and C<DEMOLISH> methods in the inheritance hierarchy, +respectively. + +You don't actually I<need> to inherit from this in order to use Moose, +but it makes it easier to take advantage of all of Moose's features. + +=head1 METHODS + +=over 4 + +=item B<< Moose::Object->new(%params|$params) >> + +This method calls C<< $class->BUILDARGS(@_) >>, and then creates a new +instance of the appropriate class. Once the instance is created, it +calls C<< $instance->BUILD($params) >> for each C<BUILD> method in the +inheritance hierarchy. + +=item B<< Moose::Object->BUILDARGS(%params|$params) >> + +The default implementation of this method accepts a hash or hash +reference of named parameters. If it receives a single argument that +I<isn't> a hash reference it throws an error. + +You can override this method in your class to handle other types of +options passed to the constructor. + +This method should always return a hash reference of named options. + +=item B<< $object->does($role_name) >> + +This returns true if the object does the given role. + +=item B<< $object->DOES($class_or_role_name) >> + +This is a Moose role-aware implementation of L<UNIVERSAL/DOES>. + +This is effectively the same as writing: + + $object->does($name) || $object->isa($name) + +This method will work with Perl 5.8, which did not implement +C<UNIVERSAL::DOES>. + +=item B<< $object->dump($maxdepth) >> + +This is a handy utility for C<Data::Dumper>ing an object. By default, +the maximum depth is 1, to avoid making a mess. + +=item B<< $object->DESTROY >> + +A default destructor is provided, which calls +C<< $instance->DEMOLISH($in_global_destruction) >> for each C<DEMOLISH> +method in the inheritance hierarchy. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Role.pm b/lib/Moose/Role.pm new file mode 100644 index 0000000..72c9bd6 --- /dev/null +++ b/lib/Moose/Role.pm @@ -0,0 +1,381 @@ +use strict; +use warnings; +package Moose::Role; +our $VERSION = '2.1405'; + +use Scalar::Util (); +use Carp (); +use Class::Load 'is_class_loaded'; +use Module::Runtime 'module_notional_filename'; + +use Sub::Exporter; + +use Moose (); +use Moose::Util 'throw_exception'; + +use Moose::Exporter; +use Moose::Meta::Role; +use Moose::Util::TypeConstraints; + +sub extends { + throw_exception("RolesDoNotSupportExtends"); +} + +sub with { + Moose::Util::apply_all_roles( shift, @_ ); +} + +sub requires { + my $meta = shift; + throw_exception( MustSpecifyAtleastOneMethod => role_name => $meta->name ) unless @_; + $meta->add_required_methods(@_); +} + +sub excludes { + my $meta = shift; + throw_exception( MustSpecifyAtleastOneRole => role_name => $meta->name ) unless @_; + $meta->add_excluded_roles(@_); +} + +sub has { + my $meta = shift; + my $name = shift; + throw_exception( InvalidHasProvidedInARole => role_name => $meta->name, + attribute_name => $name, + ) + if @_ == 1; + my %context = Moose::Util::_caller_info; + $context{context} = 'has declaration'; + $context{type} = 'role'; + my %options = ( definition_context => \%context, @_ ); + my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ]; + $meta->add_attribute( $_, %options ) for @$attrs; +} + +sub _add_method_modifier { + my $type = shift; + my $meta = shift; + + if ( ref($_[0]) eq 'Regexp' ) { + throw_exception( RolesDoNotSupportRegexReferencesForMethodModifiers => modifier_type => $type, + role_name => $meta->name, + ); + } + + Moose::Util::add_method_modifier($meta, $type, \@_); +} + +sub before { _add_method_modifier('before', @_) } + +sub after { _add_method_modifier('after', @_) } + +sub around { _add_method_modifier('around', @_) } + +# see Moose.pm for discussion +sub super { + return unless $Moose::SUPER_BODY; + $Moose::SUPER_BODY->(@Moose::SUPER_ARGS); +} + +sub override { + my $meta = shift; + my ( $name, $code ) = @_; + $meta->add_override_method_modifier( $name, $code ); +} + +sub inner { + throw_exception("RolesDoNotSupportInner"); +} + +sub augment { + throw_exception("RolesDoNotSupportAugment"); +} + +Moose::Exporter->setup_import_methods( + with_meta => [ + qw( with requires excludes has before after around override ) + ], + as_is => [ + qw( extends super inner augment ), + 'Carp::confess', + 'Scalar::Util::blessed', + ], +); + +sub init_meta { + shift; + my %args = @_; + + my $role = $args{for_class}; + + unless ($role) { + require Moose; + throw_exception( InitMetaRequiresClass => params => \%args ); + } + + my $metaclass = $args{metaclass} || "Moose::Meta::Role"; + my $meta_name = exists $args{meta_name} ? $args{meta_name} : 'meta'; + + throw_exception( MetaclassNotLoaded => class_name => $metaclass ) + unless is_class_loaded($metaclass); + + throw_exception( MetaclassMustBeASubclassOfMooseMetaRole => role_name => $metaclass ) + unless $metaclass->isa('Moose::Meta::Role'); + + # make a subtype for each Moose role + role_type $role unless find_type_constraint($role); + + my $meta; + if ( $meta = Class::MOP::get_metaclass_by_name($role) ) { + unless ( $meta->isa("Moose::Meta::Role") ) { + if ( $meta->isa('Moose::Meta::Class') ) { + throw_exception( MetaclassIsAClassNotASubclassOfGivenMetaclass => class_name => $role, + metaclass => $metaclass, + ); + } else { + throw_exception( MetaclassIsNotASubclassOfGivenMetaclass => class_name => $role, + metaclass => $metaclass, + ); + } + } + } + else { + $meta = $metaclass->initialize($role); + my $filename = module_notional_filename($meta->name); + $INC{$filename} = '(set by Moose)' + unless exists $INC{$filename}; + } + + if (defined $meta_name) { + # also check for inherited non moose 'meta' method? + my $existing = $meta->get_method($meta_name); + if ($existing && !$existing->isa('Class::MOP::Method::Meta')) { + Carp::cluck "Moose::Role is overwriting an existing method named " + . "$meta_name in role $role with a method " + . "which returns the class's metaclass. If this is " + . "actually what you want, you should remove the " + . "existing method, otherwise, you should rename or " + . "disable this generated method using the " + . "'-meta_name' option to 'use Moose::Role'."; + } + $meta->_add_meta_method($meta_name); + } + + return $meta; +} + +1; + +# ABSTRACT: The Moose Role + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Role - The Moose Role + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package Eq; + use Moose::Role; # automatically turns on strict and warnings + + requires 'equal'; + + sub no_equal { + my ($self, $other) = @_; + !$self->equal($other); + } + + # ... then in your classes + + package Currency; + use Moose; # automatically turns on strict and warnings + + with 'Eq'; + + sub equal { + my ($self, $other) = @_; + $self->as_float == $other->as_float; + } + + # ... and also + + package Comparator; + use Moose; + + has compare_to => ( + is => 'ro', + does => 'Eq', + handles => 'Eq', + ); + + # ... which allows + + my $currency1 = Currency->new(...); + my $currency2 = Currency->new(...); + Comparator->new(compare_to => $currency1)->equal($currency2); + +=head1 DESCRIPTION + +The concept of roles is documented in L<Moose::Manual::Roles>. This document +serves as API documentation. + +=head1 EXPORTED FUNCTIONS + +Moose::Role currently supports all of the functions that L<Moose> exports, but +differs slightly in how some items are handled (see L</CAVEATS> below for +details). + +Moose::Role also offers two role-specific keyword exports: + +=over 4 + +=item B<requires (@method_names)> + +Roles can require that certain methods are implemented by any class which +C<does> the role. + +Note that attribute accessors also count as methods for the purposes +of satisfying the requirements of a role. + +=item B<excludes (@role_names)> + +Roles can C<exclude> other roles, in effect saying "I can never be combined +with these C<@role_names>". This is a feature which should not be used +lightly. + +=back + +=head2 B<unimport> + +Moose::Role offers a way to remove the keywords it exports, through the +C<unimport> method. You simply have to say C<no Moose::Role> at the bottom of +your code for this to work. + +=head1 METACLASS + +When you use Moose::Role, you can specify traits which will be applied to your +role metaclass: + + use Moose::Role -traits => 'My::Trait'; + +This is very similar to the attribute traits feature. When you do +this, your class's C<meta> object will have the specified traits +applied to it. See L<Moose/Metaclass and Trait Name Resolution> for more +details. + +All role metaclasses (note, not the role itself) extend L<Moose::Meta::Role>. +You can test if a package is a role or not using L<Moose::Util/is_role>. + +=head1 APPLYING ROLES + +In addition to being applied to a class using the 'with' syntax (see +L<Moose::Manual::Roles>) and using the L<Moose::Util> 'apply_all_roles' +method, roles may also be applied to an instance of a class using +L<Moose::Util> 'apply_all_roles' or the role's metaclass: + + MyApp::Test::SomeRole->meta->apply( $instance ); + +Doing this creates a new, mutable, anonymous subclass, applies the role to that, +and reblesses. In a debugger, for example, you will see class names of the +form C< Moose::Meta::Class::__ANON__::SERIAL::6 >, which means that doing a +'ref' on your instance may not return what you expect. See L<Moose::Object> for +'DOES'. + +Additional params may be added to the new instance by providing +'rebless_params'. See L<Moose::Meta::Role::Application::ToInstance>. + +=head1 CAVEATS + +Role support has only a few caveats: + +=over 4 + +=item * + +Roles cannot use the C<extends> keyword; it will throw an exception for now. +The same is true of the C<augment> and C<inner> keywords (not sure those +really make sense for roles). All other Moose keywords will be I<deferred> +so that they can be applied to the consuming class. + +=item * + +Role composition does its best to B<not> be order-sensitive when it comes to +conflict resolution and requirements detection. However, it is order-sensitive +when it comes to method modifiers. All before/around/after modifiers are +included whenever a role is composed into a class, and then applied in the order +in which the roles are used. This also means that there is no conflict for +before/around/after modifiers. + +In most cases, this will be a non-issue; however, it is something to keep in +mind when using method modifiers in a role. You should never assume any +ordering. + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Spec/Role.pod b/lib/Moose/Spec/Role.pod new file mode 100644 index 0000000..f7b288d --- /dev/null +++ b/lib/Moose/Spec/Role.pod @@ -0,0 +1,397 @@ +# PODNAME: Moose::Spec::Role +# ABSTRACT: Formal spec for Role behavior + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Spec::Role - Formal spec for Role behavior + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +B<NOTE:> This document is currently incomplete. + +=head2 Components of a Role + +=over 4 + +=item Excluded Roles + +A role can have a list of excluded roles, these are basically +roles that they shouldn't be composed with. This is not just +direct composition either, but also "inherited" composition. + +This feature was taken from the Fortress language and is really +of most use when building a large set of role "building blocks" +some of which should never be used together. + +=item Attributes + +A roles attributes are similar to those of a class, except that +they are not actually applied. This means that methods that are +generated by an attributes accessor will not be generated in the +role, but only created once the role is applied to a class. + +=item Methods + +These are the methods defined within the role. Simple as that. + +=item Required Methods + +A role can require a consuming class (or role) to provide a +given method. Failure to do so for classes is a fatal error, +while for roles it simply passes on the method requirement to +the consuming role. + +=item Required Attributes + +Just as a role can require methods, it can also require attributes. +The requirement fulfilling attribute must implement at least as much +as is required. That means, for instance, that if the role requires +that the attribute be read-only, then it must at least have a reader +and can also have a writer. It means that if the role requires that +the attribute be an ArrayRef, then it must either be an ArrayRef or +a subtype of an ArrayRef. + +=item Overridden Methods + +The C<override> and C<super> keywords are allowed in roles, but +their behavior is different from that of its class counterparts. +The C<super> in a class refers directly to that class's superclass, +while the C<super> in a role is deferred and only has meaning once +the role is composed into a class. Once that composition occurs, +C<super> then refers to that class's superclass. + +It is key to remember that roles do not have hierarchy, so they +can never have a I<super> role. + +=item Method Modifiers + +These are the C<before>, C<around> and C<after> modifiers provided +in Moose classes. The difference here is that the modifiers are not +actually applied until the role is composed into a class (this is +just like attributes and the C<override> keyword). + +=back + +=head2 Role Composition + +=head3 Composing into a Class + +=over 4 + +=item Excluded Roles + +=item Required Methods + +=item Required Attributes + +=item Attributes + +=item Methods + +=item Overridden methods + +=item Method Modifiers (before, around, after) + +=back + +=head3 Composing into a Instance + +=head3 Composing into a Role + +=over 4 + +=item Excluded Roles + +=item Required Methods + +=item Required Attributes + +=item Attributes + +=item Methods + +=item Overridden methods + +=item Method Modifiers (before, around, after) + +=back + +=head3 Role Summation + +When multiple roles are added to another role (using the +C<with @roles> keyword) the roles are composed symmetrically. +The product of the composition is a composite role +(L<Moose::Meta::Role::Composite>). + +=over 4 + +=item Excluded Roles + +=item Required Methods + +=item Required Attributes + +=item Attributes + +Attributes with the same name will conflict and are considered +a unrecoverable error. No other aspect of the attribute is +examined, it is enough that just the attribute names conflict. + +The reason for such early and harsh conflicts with attributes +is because there is so much room for variance between two +attributes that the problem quickly explodes and rules get +very complex. It is my opinion that this complexity is not +worth the trouble. + +=item Methods + +Methods with the same name will conflict, but no error is +thrown, instead the method name is added to the list of +I<required> methods for the new composite role. + +To look at this in terms of set theory, each role can be +said to have a set of methods. The symmetric difference of +these two sets is the new set of methods for the composite +role, while the intersection of these two sets are the +conflicts. This can be illustrated like so: + + Role A has method set { a, b, c } + Role B has method set { c, d, e } + + The composite role (A,B) has + method set { a, b, d, e } + conflict set { c } + +=item Overridden methods + +An overridden method can conflict in one of two ways. + +The first way is with another overridden method of the same +name, and this is considered an unrecoverable error. This +is an obvious error since you cannot override a method twice +in the same class. + +The second way for conflict is for an overridden method and a +regular method to have the same name. This is also an unrecoverable +error since there is no way to combine these two, nor is it +okay for both items to be composed into a single class at some +point. + +The use of override in roles can be tricky, but if used +carefully they can be a very powerful tool. + +=item Method Modifiers (before, around, after) + +Method modifiers are the only place where the ordering of +role composition matters. This is due to the nature of +method modifiers themselves. + +Since a method can have multiple method modifiers, these +are just collected in order to be later applied to the +class in that same order. + +In general, great care should be taken in using method +modifiers in roles. The order sensitivity can possibly +lead to subtle and difficult to find bugs if they are +overused. As with all good things in life, moderation +is the key. + +=back + +=head3 Composition Edge Cases + +This is a just a set of complex edge cases which can easily get +confused. This attempts to clarify those cases and provide an +explanation of what is going on in them. + +=over 4 + +=item Role Method Overriding + +Many people want to "override" methods in roles they are consuming. +This works fine for classes, since the local class method is favored +over the role method. However in roles it is trickier, this is because +conflicts result in neither method being chosen and the method being +"required" instead. + +Here is an example of this (incorrect) type of overriding. + + package Role::Foo; + use Moose::Role; + + sub foo { ... } + + package Role::FooBar; + use Moose::Role; + + with 'Role::Foo'; + + sub foo { ... } + sub bar { ... } + +Here the C<foo> methods conflict and the Role::FooBar now requires a +class or role consuming it to implement C<foo>. This is very often not +what the user wants. + +Now here is an example of the (correct) type of overriding, only it is +not overriding at all, as is explained in the text below. + + package Role::Foo; + use Moose::Role; + + sub foo { ... } + + package Role::Bar; + use Moose::Role; + + sub foo { ... } + sub bar { ... } + + package Role::FooBar; + use Moose::Role; + + with 'Role::Foo', 'Role::Bar'; + + sub foo { ... } + +This works because the combination of Role::Foo and Role::Bar produce +a conflict with the C<foo> method. This conflict results in the +composite role (that was created by the combination of Role::Foo +and Role::Bar using the I<with> keyword) having a method requirement +of C<foo>. The Role::FooBar then fulfills this requirement. + +It is important to note that Role::FooBar is simply fulfilling the +required C<foo> method, and **NOT** overriding C<foo>. This is an +important distinction to make. + +Now here is another example of a (correct) type of overriding, this +time using the I<excludes> option. + + package Role::Foo; + use Moose::Role; + + sub foo { ... } + + package Role::FooBar; + use Moose::Role; + + with 'Role::Foo' => { -excludes => 'foo' }; + + sub foo { ... } + sub bar { ... } + +By specifically excluding the C<foo> method during composition, +we allow B<Role::FooBar> to define its own version of C<foo>. + +=back + +=head1 SEE ALSO + +=over 4 + +=item Traits + +Roles are based on Traits, which originated in the Smalltalk +community. + +=over 4 + +=item L<http://www.iam.unibe.ch/~scg/Research/Traits/> + +This is the main site for the original Traits papers. + +=item L<Class::Trait> + +I created this implementation of traits several years ago, +after reading the papers linked above. (This module is now +maintained by Ovid and I am no longer involved with it). + +=back + +=item Roles + +Since they are relatively new, and the Moose implementation +is probably the most mature out there, roles don't have much +to link to. However, here is some bits worth looking at (mostly +related to Perl 6) + +=over 4 + +=item L<http://www.oreillynet.com/onlamp/blog/2006/08/roles_composable_units_of_obje.html> + +This is chromatic's take on roles, which is worth reading since +he was/is one of the big proponents of them. + +=item L<http://svn.perl.org/perl6/doc/trunk/design/syn/S12.pod> + +This is Synopsis 12, which is all about the Perl 6 Object System. +Which, of course, includes roles. + +=back + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Unsweetened.pod b/lib/Moose/Unsweetened.pod new file mode 100644 index 0000000..11d2e43 --- /dev/null +++ b/lib/Moose/Unsweetened.pod @@ -0,0 +1,77 @@ +# PODNAME: Moose::Unsweetened +# ABSTRACT: Moved to Moose::Manual::Unsweetened, so go read that + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Unsweetened - Moved to Moose::Manual::Unsweetened, so go read that + +=head1 VERSION + +version 2.1405 + +=head1 DESCRIPTION + +This document has been moved to L<Moose::Manual::Unsweetened>. This +POD document still exists for the benefit of anyone out there who +might've linked to it in the past. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Util.pm b/lib/Moose/Util.pm new file mode 100644 index 0000000..18eb8e1 --- /dev/null +++ b/lib/Moose/Util.pm @@ -0,0 +1,734 @@ +package Moose::Util; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Module::Runtime 0.014 'use_package_optimistically', 'use_module', 'module_notional_filename'; +use Data::OptList; +use Params::Util qw( _STRING ); +use Sub::Exporter; +use Scalar::Util 'blessed'; +use List::Util 1.33 qw(first any all); +use overload (); +use Try::Tiny; + + +my @exports = qw[ + find_meta + is_role + does_role + search_class_by_role + ensure_all_roles + apply_all_roles + with_traits + get_all_init_args + get_all_attribute_values + resolve_metatrait_alias + resolve_metaclass_alias + add_method_modifier + english_list + meta_attribute_alias + meta_class_alias + throw_exception +]; + +Sub::Exporter::setup_exporter({ + exports => \@exports, + groups => { all => \@exports } +}); + +# Things that need to ->import from Moose::Util +# should be loaded after Moose::Util defines ->import +require Class::MOP; + +sub throw_exception { + my ($class_name, @args_to_exception) = @_; + my $class = "Moose::Exception::$class_name"; + _load_user_class( $class ); + die $class->new( @args_to_exception ); +} + +## some utils for the utils ... + +sub find_meta { Class::MOP::class_of(@_) } + +## the functions ... + +sub is_role { + my $package_or_obj = shift; + + my $meta = find_meta($package_or_obj); + return if not $meta; + return $meta->isa('Moose::Meta::Role'); +} + +sub does_role { + my ($class_or_obj, $role) = @_; + + if (try { $class_or_obj->isa('Moose::Object') }) { + return $class_or_obj->does($role); + } + + my $meta = find_meta($class_or_obj); + + return unless defined $meta; + return unless $meta->can('does_role'); + return 1 if $meta->does_role($role); + return; +} + +sub search_class_by_role { + my ($class_or_obj, $role) = @_; + + my $meta = find_meta($class_or_obj); + + return unless defined $meta; + + my $role_name = blessed $role ? $role->name : $role; + + foreach my $class ($meta->class_precedence_list) { + + my $_meta = find_meta($class); + + next unless defined $_meta; + + foreach my $role (@{ $_meta->roles || [] }) { + return $class if $role->name eq $role_name; + } + } + + return; +} + +# this can possibly behave in unexpected ways because the roles being composed +# before being applied could differ from call to call; I'm not sure if or how +# to document this possible quirk. +sub ensure_all_roles { + my $applicant = shift; + _apply_all_roles($applicant, sub { !does_role($applicant, $_) }, @_); +} + +sub apply_all_roles { + my $applicant = shift; + _apply_all_roles($applicant, undef, @_); +} + +sub _apply_all_roles { + my $applicant = shift; + my $role_filter = shift; + + unless (@_) { + require Moose; + throw_exception( MustSpecifyAtleastOneRoleToApplicant => applicant => $applicant ); + } + + # If @_ contains role meta objects, mkopt will think that they're values, + # because they're references. In other words (roleobj1, roleobj2, + # roleobj3) will become [ [ roleobj1, roleobj2 ], [ roleobj3, undef ] ] + # -- this is no good. We'll preprocess @_ first to eliminate the potential + # bug. + # -- rjbs, 2011-04-08 + my $roles = Data::OptList::mkopt( [@_], { + moniker => 'role', + name_test => sub { + ! ref $_[0] or blessed($_[0]) && $_[0]->isa('Moose::Meta::Role') + } + }); + + my @role_metas; + foreach my $role (@$roles) { + my $meta; + + if ( blessed $role->[0] ) { + $meta = $role->[0]; + } + else { + &use_module($role->[0], $role->[1] && $role->[1]{-version} ? $role->[1]{-version} : ()); + $meta = find_meta( $role->[0] ); + } + + unless ($meta && $meta->isa('Moose::Meta::Role') ) { + throw_exception( CanOnlyConsumeRole => role_name => $role->[0] ); + } + + push @role_metas, [ $meta, $role->[1] ]; + } + + if ( defined $role_filter ) { + @role_metas = grep { local $_ = $_->[0]; $role_filter->() } @role_metas; + } + + return unless @role_metas; + + _load_user_class($applicant) + unless blessed($applicant) + || Class::MOP::class_of($applicant); + + my $meta = ( blessed $applicant ? $applicant : Moose::Meta::Class->initialize($applicant) ); + + if ( scalar @role_metas == 1 ) { + my ( $role, $params ) = @{ $role_metas[0] }; + $role->apply( $meta, ( defined $params ? %$params : () ) ); + } + else { + Moose::Meta::Role->combine(@role_metas)->apply($meta); + } +} + +sub with_traits { + my ($class, @roles) = @_; + return $class unless @roles; + return Moose::Meta::Class->create_anon_class( + superclasses => [$class], + roles => \@roles, + cache => 1, + )->name; +} + +# instance deconstruction ... + +sub get_all_attribute_values { + my ($class, $instance) = @_; + return +{ + map { $_->name => $_->get_value($instance) } + grep { $_->has_value($instance) } + $class->get_all_attributes + }; +} + +sub get_all_init_args { + my ($class, $instance) = @_; + return +{ + map { $_->init_arg => $_->get_value($instance) } + grep { $_->has_value($instance) } + grep { defined($_->init_arg) } + $class->get_all_attributes + }; +} + +sub resolve_metatrait_alias { + return resolve_metaclass_alias( @_, trait => 1 ); +} + +sub _build_alias_package_name { + my ($type, $name, $trait) = @_; + return 'Moose::Meta::' + . $type + . '::Custom::' + . ( $trait ? 'Trait::' : '' ) + . $name; +} + +{ + my %cache; + + sub resolve_metaclass_alias { + my ( $type, $metaclass_name, %options ) = @_; + + my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' ); + return $cache{$cache_key}{$metaclass_name} + if $cache{$cache_key}{$metaclass_name}; + + my $possible_full_name = _build_alias_package_name( + $type, $metaclass_name, $options{trait} + ); + + my @possible = ($possible_full_name, $metaclass_name); + for my $package (@possible) { + use_package_optimistically($package); + if ($package->can('register_implementation')) { + return $cache{$cache_key}{$metaclass_name} = + $package->register_implementation; + } + elsif (find_meta($package)) { + return $cache{$cache_key}{$metaclass_name} = $package; + } + } + + throw_exception( CannotLocatePackageInINC => possible_packages => _english_list_or(@possible), + INC => \@INC, + type => $type, + metaclass_name => $metaclass_name, + params => \%options + ); + } +} + +sub add_method_modifier { + my ( $class_or_obj, $modifier_name, $args ) = @_; + my $meta + = $class_or_obj->can('add_before_method_modifier') + ? $class_or_obj + : find_meta($class_or_obj); + my $code = pop @{$args}; + my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier'; + if ( my $method_modifier_type = ref( @{$args}[0] ) ) { + if ( $method_modifier_type eq 'Regexp' ) { + my @all_methods = $meta->get_all_methods; + my @matched_methods + = grep { $_->name =~ @{$args}[0] } @all_methods; + $meta->$add_modifier_method( $_->name, $code ) + for @matched_methods; + } + elsif ($method_modifier_type eq 'ARRAY') { + $meta->$add_modifier_method( $_, $code ) for @{$args->[0]}; + } + else { + throw_exception( IllegalMethodTypeToAddMethodModifier => class_or_object => $class_or_obj, + modifier_name => $modifier_name, + params => $args + ); + } + } + else { + $meta->$add_modifier_method( $_, $code ) for @{$args}; + } +} + +sub english_list { + _english_list_and(@_); +} + +sub _english_list_and { + _english_list('and', \@_); +} + +sub _english_list_or { + _english_list('or', \@_); +} + +sub _english_list { + my ($conjunction, $items) = @_; + + my @items = sort @$items; + + return $items[0] if @items == 1; + return "$items[0] $conjunction $items[1]" if @items == 2; + + my $tail = pop @items; + my $list = join ', ', @items; + $list .= ", $conjunction " . $tail; + + return $list; +} + +sub _caller_info { + my $level = @_ ? ($_[0] + 1) : 2; + my %info; + @info{qw(package file line)} = caller($level); + return %info; +} + +sub _create_alias { + my ($type, $name, $trait, $for) = @_; + my $package = _build_alias_package_name($type, $name, $trait); + Class::MOP::Class->initialize($package)->add_method( + register_implementation => sub { $for } + ); +} + +sub meta_attribute_alias { + my ($to, $from) = @_; + $from ||= caller; + my $meta = Class::MOP::class_of($from); + my $trait = $meta->isa('Moose::Meta::Role'); + _create_alias('Attribute', $to, $trait, $from); +} + +sub meta_class_alias { + my ($to, $from) = @_; + $from ||= caller; + my $meta = Class::MOP::class_of($from); + my $trait = $meta->isa('Moose::Meta::Role'); + _create_alias('Class', $to, $trait, $from); +} + +sub _load_user_class { + my ($class, $opts) = @_; + &use_package_optimistically( + $class, + $opts && $opts->{-version} ? $opts->{-version} : () + ); +} + +# XXX - this should be added to Params::Util +sub _STRINGLIKE0 ($) { + return 1 if _STRING( $_[0] ); + if ( blessed $_[0] ) { + return overload::Method( $_[0], q{""} ); + } + + return 1 if defined $_[0] && $_[0] eq q{}; + + return 0; +} + +sub _reconcile_roles_for_metaclass { + my ($class_meta_name, $super_meta_name) = @_; + + my @role_differences = _role_differences( + $class_meta_name, $super_meta_name, + ); + + # handle the case where we need to fix compatibility between a class and + # its parent, but all roles in the class are already also done by the + # parent + # see t/metaclasses/metaclass_compat_no_fixing_bug.t + return $super_meta_name + unless @role_differences; + + return Moose::Meta::Class->create_anon_class( + superclasses => [$super_meta_name], + roles => [map { $_->name } @role_differences], + cache => 1, + )->name; +} + +sub _role_differences { + my ($class_meta_name, $super_meta_name) = @_; + my @super_role_metas = map { + $_->isa('Moose::Meta::Role::Composite') + ? (@{ $_->get_roles }) + : ($_) + } $super_meta_name->meta->can('_roles_with_inheritance') + ? $super_meta_name->meta->_roles_with_inheritance + : $super_meta_name->meta->can('roles') + ? @{ $super_meta_name->meta->roles } + : (); + my @role_metas = map { + $_->isa('Moose::Meta::Role::Composite') + ? (@{ $_->get_roles }) + : ($_) + } $class_meta_name->meta->can('_roles_with_inheritance') + ? $class_meta_name->meta->_roles_with_inheritance + : $class_meta_name->meta->can('roles') + ? @{ $class_meta_name->meta->roles } + : (); + my @differences; + for my $role_meta (@role_metas) { + push @differences, $role_meta + unless any { $_->name eq $role_meta->name } @super_role_metas; + } + return @differences; +} + +sub _classes_differ_by_roles_only { + my ( $self_meta_name, $super_meta_name ) = @_; + + my $common_base_name + = _find_common_base( $self_meta_name, $super_meta_name ); + + return unless defined $common_base_name; + + my @super_meta_name_ancestor_names + = _get_ancestors_until( $super_meta_name, $common_base_name ); + my @class_meta_name_ancestor_names + = _get_ancestors_until( $self_meta_name, $common_base_name ); + + return + unless all { _is_role_only_subclass($_) } + @super_meta_name_ancestor_names, + @class_meta_name_ancestor_names; + + return 1; +} + +sub _find_common_base { + my ($meta1, $meta2) = map { Class::MOP::class_of($_) } @_; + return unless defined $meta1 && defined $meta2; + + # FIXME? This doesn't account for multiple inheritance (not sure + # if it needs to though). For example, if somewhere in $meta1's + # history it inherits from both ClassA and ClassB, and $meta2 + # inherits from ClassB & ClassA, does it matter? And what crazy + # fool would do that anyway? + + my %meta1_parents = map { $_ => 1 } $meta1->linearized_isa; + + return first { $meta1_parents{$_} } $meta2->linearized_isa; +} + +sub _get_ancestors_until { + my ($start_name, $until_name) = @_; + + my @ancestor_names; + for my $ancestor_name (Class::MOP::class_of($start_name)->linearized_isa) { + last if $ancestor_name eq $until_name; + push @ancestor_names, $ancestor_name; + } + return @ancestor_names; +} + +sub _is_role_only_subclass { + my ($meta_name) = @_; + my $meta = Class::MOP::Class->initialize($meta_name); + my @parent_names = $meta->superclasses; + + # XXX: don't feel like messing with multiple inheritance here... what would + # that even do? + return unless @parent_names == 1; + my ($parent_name) = @parent_names; + my $parent_meta = Class::MOP::Class->initialize($parent_name); + + # only get the roles attached to this particular class, don't look at + # superclasses + my @roles = $meta->can('calculate_all_roles') + ? $meta->calculate_all_roles + : (); + + # it's obviously not a role-only subclass if it doesn't do any roles + return unless @roles; + + # loop over all methods that are a part of the current class + # (not inherited) + for my $method ( $meta->_get_local_methods ) { + # always ignore meta + next if $method->isa('Class::MOP::Method::Meta'); + # we'll deal with attributes below + next if $method->can('associated_attribute'); + # if the method comes from a role we consumed, ignore it + next if $meta->can('does_role') + && $meta->does_role($method->original_package_name); + # FIXME - this really isn't right. Just because a modifier is + # defined in a role doesn't mean it isn't _also_ defined in the + # subclass. + next if $method->isa('Class::MOP::Method::Wrapped') + && ( + (!scalar($method->around_modifiers) + || any { $_->has_around_method_modifiers($method->name) } @roles) + && (!scalar($method->before_modifiers) + || any { $_->has_before_method_modifiers($method->name) } @roles) + && (!scalar($method->after_modifiers) + || any { $_->has_after_method_modifiers($method->name) } @roles) + ); + + return 0; + } + + # loop over all attributes that are a part of the current class + # (not inherited) + # FIXME - this really isn't right. Just because an attribute is + # defined in a role doesn't mean it isn't _also_ defined in the + # subclass. + for my $attr (map { $meta->get_attribute($_) } $meta->get_attribute_list) { + next if any { $_->has_attribute($attr->name) } @roles; + + return 0; + } + + return 1; +} + +sub _is_package_loaded { + my ($package) = @_; + defined $INC{module_notional_filename($package)}; +} + +1; + +# ABSTRACT: Utilities for working with Moose classes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Util - Utilities for working with Moose classes + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + use Moose::Util qw/find_meta does_role search_class_by_role/; + + my $meta = find_meta($object) || die "No metaclass found"; + + if (does_role($object, $role)) { + print "The object can do $role!\n"; + } + + my $class = search_class_by_role($object, 'FooRole'); + print "Nearest class with 'FooRole' is $class\n"; + +=head1 DESCRIPTION + +This module provides a set of utility functions. Many of these +functions are intended for use in Moose itself or MooseX modules, but +some of them may be useful for use in your own code. + +=head1 EXPORTED FUNCTIONS + +=over 4 + +=item B<find_meta($class_or_obj)> + +This method takes a class name or object and attempts to find a +metaclass for the class, if one exists. It will B<not> create one if it +does not yet exist. + +=item B<is_role($package_or_obj)> + +Returns true if the provided package name or object is a L<Moose::Role>. + +=item B<does_role($class_or_obj, $role_or_obj)> + +Returns true if C<$class_or_obj> does the given C<$role_or_obj>. The role can +be provided as a name or a L<Moose::Meta::Role> object. + +The class must already have a metaclass for this to work. If it doesn't, this +function simply returns false. + +=item B<search_class_by_role($class_or_obj, $role_or_obj)> + +Returns the first class in the class's precedence list that does +C<$role_or_obj>, if any. The role can be either a name or a +L<Moose::Meta::Role> object. + +The class must already have a metaclass for this to work. + +=item B<apply_all_roles($applicant, @roles)> + +This function applies one or more roles to the given C<$applicant>. The +applicant can be a role name, class name, or object. + +The C<$applicant> must already have a metaclass object. + +The list of C<@roles> should a list of names or L<Moose::Meta::Role> objects, +each of which can be followed by an optional hash reference of options +(C<-excludes> and C<-alias>). + +=item B<ensure_all_roles($applicant, @roles)> + +This function is similar to C<apply_all_roles>, but only applies roles that +C<$applicant> does not already consume. + +=item B<with_traits($class_name, @role_names)> + +This function creates a new class from C<$class_name> with each of +C<@role_names> applied. It returns the name of the new class. + +=item B<get_all_attribute_values($meta, $instance)> + +Returns a hash reference containing all of the C<$instance>'s +attributes. The keys are attribute names. + +=item B<get_all_init_args($meta, $instance)> + +Returns a hash reference containing all of the C<init_arg> values for +the instance's attributes. The values are the associated attribute +values. If an attribute does not have a defined C<init_arg>, it is +skipped. + +This could be useful in cloning an object. + +=item B<resolve_metaclass_alias($category, $name, %options)> + +=item B<resolve_metatrait_alias($category, $name, %options)> + +Resolves a short name to a full class name. Short names are often used +when specifying the C<metaclass> or C<traits> option for an attribute: + + has foo => ( + metaclass => "Bar", + ); + +The name resolution mechanism is covered in +L<Moose/Metaclass and Trait Name Resolution>. + +=item B<meta_class_alias($to[, $from])> + +=item B<meta_attribute_alias($to[, $from])> + +Create an alias from the class C<$from> (or the current package, if +C<$from> is unspecified), so that +L<Moose/Metaclass and Trait Name Resolution> works properly. + +=item B<english_list(@items)> + +Given a list of scalars, turns them into a proper list in English +("one and two", "one, two, three, and four"). This is used to help us +make nicer error messages. + +=item B<throw_exception( $class_name, %arguments_to_exception)> + +Calls die with an object of Moose::Exception::$class_name, with +%arguments_to_exception passed as arguments. + +=back + +=head1 TODO + +Here is a list of possible functions to write + +=over 4 + +=item discovering original method from modified method + +=item search for origin class of a method or attribute + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Util/MetaRole.pm b/lib/Moose/Util/MetaRole.pm new file mode 100644 index 0000000..c85bc3c --- /dev/null +++ b/lib/Moose/Util/MetaRole.pm @@ -0,0 +1,329 @@ +package Moose::Util::MetaRole; +our $VERSION = '2.1405'; + +use strict; +use warnings; +use Scalar::Util 'blessed'; + +use List::Util 1.33 qw( first all ); +use Moose::Deprecated; +use Moose::Util 'throw_exception'; + +sub apply_metaroles { + my %args = @_; + + my $for = _metathing_for( $args{for} ); + + if ( $for->isa('Moose::Meta::Role') ) { + return _make_new_metaclass( $for, $args{role_metaroles}, 'role' ); + } + else { + return _make_new_metaclass( $for, $args{class_metaroles}, 'class' ); + } +} + +sub _metathing_for { + my $passed = shift; + + my $found + = blessed $passed + ? $passed + : Class::MOP::class_of($passed); + + return $found + if defined $found + && blessed $found + && ( $found->isa('Moose::Meta::Role') + || $found->isa('Moose::Meta::Class') ); + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + + throw_exception( InvalidArgPassedToMooseUtilMetaRole => argument => $passed ); +} + +sub _make_new_metaclass { + my $for = shift; + my $roles = shift; + my $primary = shift; + + return $for unless keys %{$roles}; + + my $new_metaclass + = exists $roles->{$primary} + ? _make_new_class( ref $for, $roles->{$primary} ) + : blessed $for; + + my %classes; + + for my $key ( grep { $_ ne $primary } keys %{$roles} ) { + my $attr = first {$_} + map { $for->meta->find_attribute_by_name($_) } ( + $key . '_metaclass', + $key . '_class' + ); + + my $reader = $attr->get_read_method; + + $classes{ $attr->init_arg } + = _make_new_class( $for->$reader(), $roles->{$key} ); + } + + my $new_meta = $new_metaclass->reinitialize( $for, %classes ); + + return $new_meta; +} + +sub apply_base_class_roles { + my %args = @_; + + my $meta = _metathing_for( $args{for} || $args{for_class} ); + throw_exception( CannotApplyBaseClassRolesToRole => params => \%args, + role_name => $meta->name, + ) + if $meta->isa('Moose::Meta::Role'); + + my $new_base = _make_new_class( + $meta->name, + $args{roles}, + [ $meta->superclasses() ], + ); + + $meta->superclasses($new_base) + if $new_base ne $meta->name(); +} + +sub _make_new_class { + my $existing_class = shift; + my $roles = shift; + my $superclasses = shift || [$existing_class]; + + return $existing_class unless $roles; + + my $meta = Class::MOP::Class->initialize($existing_class); + + return $existing_class + if $meta->can('does_role') && all { $meta->does_role($_) } + grep { !ref $_ } @{$roles}; + + return Moose::Meta::Class->create_anon_class( + superclasses => $superclasses, + roles => $roles, + cache => 1, + )->name(); +} + +1; + +# ABSTRACT: Apply roles to any metaclass, as well as the object base class + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Util::MetaRole - Apply roles to any metaclass, as well as the object base class + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + package MyApp::Moose; + + use Moose (); + use Moose::Exporter; + use Moose::Util::MetaRole; + + use MyApp::Role::Meta::Class; + use MyApp::Role::Meta::Method::Constructor; + use MyApp::Role::Object; + + Moose::Exporter->setup_import_methods( also => 'Moose' ); + + sub init_meta { + shift; + my %args = @_; + + Moose->init_meta(%args); + + Moose::Util::MetaRole::apply_metaroles( + for => $args{for_class}, + class_metaroles => { + class => ['MyApp::Role::Meta::Class'], + constructor => ['MyApp::Role::Meta::Method::Constructor'], + }, + ); + + Moose::Util::MetaRole::apply_base_class_roles( + for => $args{for_class}, + roles => ['MyApp::Role::Object'], + ); + + return $args{for_class}->meta(); + } + +=head1 DESCRIPTION + +This utility module is designed to help authors of Moose extensions +write extensions that are able to cooperate with other Moose +extensions. To do this, you must write your extensions as roles, which +can then be dynamically applied to the caller's metaclasses. + +This module makes sure to preserve any existing superclasses and roles +already set for the meta objects, which means that any number of +extensions can apply roles in any order. + +=head1 USAGE + +The easiest way to use this module is through L<Moose::Exporter>, which can +generate the appropriate C<init_meta> method for you, and make sure it is +called when imported. + +=head1 FUNCTIONS + +This module provides two functions. + +=head2 apply_metaroles( ... ) + +This function will apply roles to one or more metaclasses for the specified +class. It will return a new metaclass object for the class or role passed in +the "for" parameter. + +It accepts the following parameters: + +=over 4 + +=item * for => $name + +This specifies the class or for which to alter the meta classes. This can be a +package name, or an appropriate meta-object (a L<Moose::Meta::Class> or +L<Moose::Meta::Role>). + +=item * class_metaroles => \%roles + +This is a hash reference specifying which metaroles will be applied to the +class metaclass and its contained metaclasses and helper classes. + +Each key should in turn point to an array reference of role names. + +It accepts the following keys: + +=over 8 + +=item class + +=item attribute + +=item method + +=item wrapped_method + +=item instance + +=item constructor + +=item destructor + +=item error + +=back + +=item * role_metaroles => \%roles + +This is a hash reference specifying which metaroles will be applied to the +role metaclass and its contained metaclasses and helper classes. + +It accepts the following keys: + +=over 8 + +=item role + +=item attribute + +=item method + +=item required_method + +=item conflicting_method + +=item application_to_class + +=item application_to_role + +=item application_to_instance + +=item application_role_summation + +=item applied_attribute + +=back + +=back + +=head2 apply_base_class_roles( for => $class, roles => \@roles ) + +This function will apply the specified roles to the object's base class. + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Util/TypeConstraints.pm b/lib/Moose/Util/TypeConstraints.pm new file mode 100644 index 0000000..e4b75e3 --- /dev/null +++ b/lib/Moose/Util/TypeConstraints.pm @@ -0,0 +1,1459 @@ +package Moose::Util::TypeConstraints; +our $VERSION = '2.1405'; + +use Carp (); +use Scalar::Util qw( blessed ); +use Moose::Exporter; +use Moose::Deprecated; + +## -------------------------------------------------------- +# Prototyped subs must be predeclared because we have a +# circular dependency with Moose::Meta::Attribute et. al. +# so in case of us being use'd first the predeclaration +# ensures the prototypes are in scope when consumers are +# compiled. + +# dah sugah! +sub where (&); +sub via (&); +sub message (&); +sub inline_as (&); + +## -------------------------------------------------------- + +use Moose::Meta::TypeConstraint; +use Moose::Meta::TypeConstraint::Union; +use Moose::Meta::TypeConstraint::Parameterized; +use Moose::Meta::TypeConstraint::Parameterizable; +use Moose::Meta::TypeConstraint::Class; +use Moose::Meta::TypeConstraint::Role; +use Moose::Meta::TypeConstraint::Enum; +use Moose::Meta::TypeConstraint::DuckType; +use Moose::Meta::TypeCoercion; +use Moose::Meta::TypeCoercion::Union; +use Moose::Meta::TypeConstraint::Registry; + +use Moose::Util 'throw_exception'; + +Moose::Exporter->setup_import_methods( + as_is => [ + qw( + type subtype class_type role_type maybe_type duck_type + as where message inline_as + coerce from via + enum union + find_type_constraint + register_type_constraint + match_on_type ) + ], +); + +## -------------------------------------------------------- +## type registry and some useful functions for it +## -------------------------------------------------------- + +my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new; + +sub get_type_constraint_registry {$REGISTRY} +sub list_all_type_constraints { keys %{ $REGISTRY->type_constraints } } + +sub export_type_constraints_as_functions { + my $pkg = caller(); + no strict 'refs'; + foreach my $constraint ( keys %{ $REGISTRY->type_constraints } ) { + my $tc = $REGISTRY->get_type_constraint($constraint) + ->_compiled_type_constraint; + *{"${pkg}::${constraint}"} + = sub { $tc->( $_[0] ) ? 1 : undef }; # the undef is for compat + } +} + +sub create_type_constraint_union { + _create_type_constraint_union(\@_); +} + +sub create_named_type_constraint_union { + my $name = shift; + _create_type_constraint_union($name, \@_); +} + +sub _create_type_constraint_union { + my $name; + $name = shift if @_ > 1; + my @tcs = @{ shift() }; + + my @type_constraint_names; + + if ( scalar @tcs == 1 && _detect_type_constraint_union( $tcs[0] ) ) { + @type_constraint_names = _parse_type_constraint_union( $tcs[0] ); + } + else { + @type_constraint_names = @tcs; + } + + ( scalar @type_constraint_names >= 2 ) + || throw_exception("UnionTakesAtleastTwoTypeNames"); + + my @type_constraints = map { + find_or_parse_type_constraint($_) + || throw_exception( CouldNotLocateTypeConstraintForUnion => type_name => $_ ); + } @type_constraint_names; + + my %options = ( + type_constraints => \@type_constraints + ); + $options{name} = $name if defined $name; + + return Moose::Meta::TypeConstraint::Union->new(%options); +} + + +sub create_parameterized_type_constraint { + my $type_constraint_name = shift; + my ( $base_type, $type_parameter ) + = _parse_parameterized_type_constraint($type_constraint_name); + + ( defined $base_type && defined $type_parameter ) + || throw_exception( InvalidTypeGivenToCreateParameterizedTypeConstraint => type_name => $type_constraint_name ); + + if ( $REGISTRY->has_type_constraint($base_type) ) { + my $base_type_tc = $REGISTRY->get_type_constraint($base_type); + return _create_parameterized_type_constraint( + $base_type_tc, + $type_parameter + ); + } + else { + throw_exception( InvalidBaseTypeGivenToCreateParameterizedTypeConstraint => type_name => $base_type ); + } +} + +sub _create_parameterized_type_constraint { + my ( $base_type_tc, $type_parameter ) = @_; + if ( $base_type_tc->can('parameterize') ) { + return $base_type_tc->parameterize($type_parameter); + } + else { + return Moose::Meta::TypeConstraint::Parameterized->new( + name => $base_type_tc->name . '[' . $type_parameter . ']', + parent => $base_type_tc, + type_parameter => + find_or_create_isa_type_constraint($type_parameter), + ); + } +} + +#should we also support optimized checks? +sub create_class_type_constraint { + my ( $class, $options ) = @_; + +# too early for this check +#find_type_constraint("ClassName")->check($class) +# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name"); + + my $pkg_defined_in = $options->{package_defined_in} || scalar( caller(1) ); + + if (my $type = $REGISTRY->get_type_constraint($class)) { + if (!($type->isa('Moose::Meta::TypeConstraint::Class') && $type->class eq $class)) { + throw_exception( TypeConstraintIsAlreadyCreated => package_defined_in => $pkg_defined_in, + type_name => $type->name, + ); + } + else { + return $type; + } + } + + my %options = ( + class => $class, + name => $class, + package_defined_in => $pkg_defined_in, + %{ $options || {} }, # overrides options from above + ); + + $options{name} ||= "__ANON__"; + + my $tc = Moose::Meta::TypeConstraint::Class->new(%options); + $REGISTRY->add_type_constraint($tc); + return $tc; +} + +sub create_role_type_constraint { + my ( $role, $options ) = @_; + +# too early for this check +#find_type_constraint("ClassName")->check($class) +# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name"); + + my $pkg_defined_in = $options->{package_defined_in} || scalar( caller(1) ); + + if (my $type = $REGISTRY->get_type_constraint($role)) { + if (!($type->isa('Moose::Meta::TypeConstraint::Role') && $type->role eq $role)) { + throw_exception( TypeConstraintIsAlreadyCreated => type_name => $type->name, + package_defined_in => $pkg_defined_in + ); + } + else { + return $type; + } + } + + my %options = ( + role => $role, + name => $role, + package_defined_in => $pkg_defined_in, + %{ $options || {} }, + ); + + $options{name} ||= "__ANON__"; + + my $tc = Moose::Meta::TypeConstraint::Role->new(%options); + $REGISTRY->add_type_constraint($tc); + return $tc; +} + +sub find_or_create_type_constraint { + my ( $type_constraint_name, $options_for_anon_type ) = @_; + + if ( my $constraint + = find_or_parse_type_constraint($type_constraint_name) ) { + return $constraint; + } + elsif ( defined $options_for_anon_type ) { + + # NOTE: + # if there is no $options_for_anon_type + # specified, then we assume they don't + # want to create one, and return nothing. + + # otherwise assume that we should create + # an ANON type with the $options_for_anon_type + # options which can be passed in. It should + # be noted that these don't get registered + # so we need to return it. + # - SL + return Moose::Meta::TypeConstraint->new( + name => '__ANON__', + %{$options_for_anon_type} + ); + } + + return; +} + +sub find_or_create_isa_type_constraint { + my ($type_constraint_name, $options) = @_; + find_or_parse_type_constraint($type_constraint_name) + || create_class_type_constraint($type_constraint_name, $options); +} + +sub find_or_create_does_type_constraint { + my ($type_constraint_name, $options) = @_; + find_or_parse_type_constraint($type_constraint_name) + || create_role_type_constraint($type_constraint_name, $options); +} + +sub find_or_parse_type_constraint { + my $type_constraint_name = normalize_type_constraint_name(shift); + my $constraint; + + if ( $constraint = find_type_constraint($type_constraint_name) ) { + return $constraint; + } + elsif ( _detect_type_constraint_union($type_constraint_name) ) { + $constraint = create_type_constraint_union($type_constraint_name); + } + elsif ( _detect_parameterized_type_constraint($type_constraint_name) ) { + $constraint + = create_parameterized_type_constraint($type_constraint_name); + } + else { + return; + } + + $REGISTRY->add_type_constraint($constraint); + return $constraint; +} + +sub normalize_type_constraint_name { + my $type_constraint_name = shift; + $type_constraint_name =~ s/\s//g; + return $type_constraint_name; +} + +sub _confess { + my $error = shift; + + local $Carp::CarpLevel = $Carp::CarpLevel + 1; + Carp::confess($error); +} + +## -------------------------------------------------------- +## exported functions ... +## -------------------------------------------------------- + +sub find_type_constraint { + my $type = shift; + + if ( blessed $type and $type->isa("Moose::Meta::TypeConstraint") ) { + return $type; + } + else { + return unless $REGISTRY->has_type_constraint($type); + return $REGISTRY->get_type_constraint($type); + } +} + +sub register_type_constraint { + my $constraint = shift; + throw_exception( CannotRegisterUnnamedTypeConstraint => type => $constraint ) + unless defined $constraint->name; + $REGISTRY->add_type_constraint($constraint); + return $constraint; +} + +# type constructors + +sub type { + my $name = shift; + + my %p = map { %{$_} } @_; + + return _create_type_constraint( + $name, undef, $p{where}, $p{message}, + $p{inline_as}, + ); +} + +sub subtype { + if ( @_ == 1 && !ref $_[0] ) { + throw_exception( NoParentGivenToSubtype => name => $_[0] ); + } + + # The blessed check is mostly to accommodate MooseX::Types, which + # uses an object which overloads stringification as a type name. + my $name = ref $_[0] && !blessed $_[0] ? undef : shift; + + my %p = map { %{$_} } @_; + + # subtype Str => where { ... }; + if ( !exists $p{as} ) { + $p{as} = $name; + $name = undef; + } + + return _create_type_constraint( + $name, $p{as}, $p{where}, $p{message}, + $p{inline_as}, + ); +} + +sub class_type { + create_class_type_constraint(@_); +} + +sub role_type ($;$) { + create_role_type_constraint(@_); +} + +sub maybe_type { + my ($type_parameter) = @_; + + register_type_constraint( + $REGISTRY->get_type_constraint('Maybe')->parameterize($type_parameter) + ); +} + +sub duck_type { + my ( $type_name, @methods ) = @_; + if ( ref $type_name eq 'ARRAY' && !@methods ) { + @methods = ($type_name); + $type_name = undef; + } + if ( @methods == 1 && ref $methods[0] eq 'ARRAY' ) { + @methods = @{ $methods[0] }; + } + else { + Moose::Deprecated::deprecated( + feature => 'non-arrayref form of duck_type', + message => "Passing a list of values to duck_type is deprecated. " + . "The method names should be wrapped in an arrayref.", + ); + } + + register_type_constraint( + create_duck_type_constraint( + $type_name, + \@methods, + ) + ); +} + +sub coerce { + my ( $type_name, @coercion_map ) = @_; + _install_type_coercions( $type_name, \@coercion_map ); +} + +# The trick of returning @_ lets us avoid having to specify a +# prototype. Perl will parse this: +# +# subtype 'Foo' +# => as 'Str' +# => where { ... } +# +# as this: +# +# subtype( 'Foo', as( 'Str', where { ... } ) ); +# +# If as() returns all its extra arguments, this just works, and +# preserves backwards compatibility. +sub as { { as => shift }, @_ } +sub where (&) { { where => $_[0] } } +sub message (&) { { message => $_[0] } } +sub inline_as (&) { { inline_as => $_[0] } } + +sub from {@_} +sub via (&) { $_[0] } + +sub enum { + my ( $type_name, @values ) = @_; + + # NOTE: + # if only an array-ref is passed then + # you get an anon-enum + # - SL + if ( ref $type_name eq 'ARRAY' ) { + @values == 0 + || throw_exception( EnumCalledWithAnArrayRefAndAdditionalArgs => array => $type_name, + args => \@values + ); + @values = ($type_name); + $type_name = undef; + } + if ( @values == 1 && ref $values[0] eq 'ARRAY' ) { + @values = @{ $values[0] }; + } + else { + Moose::Deprecated::deprecated( + feature => 'non-arrayref form of enum', + message => "Passing a list of values to enum is deprecated. " + . "Enum values should be wrapped in an arrayref.", + ); + } + + register_type_constraint( + create_enum_type_constraint( + $type_name, + \@values, + ) + ); +} + +sub union { + my ( $type_name, @constraints ) = @_; + if ( ref $type_name eq 'ARRAY' ) { + @constraints == 0 + || throw_exception( UnionCalledWithAnArrayRefAndAdditionalArgs => array => $type_name, + args => \@constraints + ); + @constraints = @$type_name; + $type_name = undef; + } + if ( @constraints == 1 && ref $constraints[0] eq 'ARRAY' ) { + @constraints = @{ $constraints[0] }; + } + if ( defined $type_name ) { + return register_type_constraint( + create_named_type_constraint_union( $type_name, @constraints ) + ); + } + return create_type_constraint_union( @constraints ); +} + +sub create_enum_type_constraint { + my ( $type_name, $values ) = @_; + + Moose::Meta::TypeConstraint::Enum->new( + name => $type_name || '__ANON__', + values => $values, + ); +} + +sub create_duck_type_constraint { + my ( $type_name, $methods ) = @_; + + Moose::Meta::TypeConstraint::DuckType->new( + name => $type_name || '__ANON__', + methods => $methods, + ); +} + +sub match_on_type { + my ($to_match, @cases) = @_; + my $default; + if (@cases % 2 != 0) { + $default = pop @cases; + (ref $default eq 'CODE') + || throw_exception( DefaultToMatchOnTypeMustBeCodeRef => to_match => $to_match, + default_action => $default, + cases_to_be_matched => \@cases + ); + } + while (@cases) { + my ($type, $action) = splice @cases, 0, 2; + + unless (blessed $type && $type->isa('Moose::Meta::TypeConstraint')) { + $type = find_or_parse_type_constraint($type) + || throw_exception( CannotFindTypeGivenToMatchOnType => type => $type, + to_match => $to_match, + action => $action + ); + } + + (ref $action eq 'CODE') + || throw_exception( MatchActionMustBeACodeRef => type_name => $type->name, + action => $action, + to_match => $to_match + ); + + if ($type->check($to_match)) { + local $_ = $to_match; + return $action->($to_match); + } + } + (defined $default) + || throw_exception( NoCasesMatched => to_match => $to_match, + cases_to_be_matched => \@cases + ); + { + local $_ = $to_match; + return $default->($to_match); + } +} + + +## -------------------------------------------------------- +## desugaring functions ... +## -------------------------------------------------------- + +sub _create_type_constraint ($$$;$) { + my $name = shift; + my $parent = shift; + my $check = shift; + my $message = shift; + my $inlined = shift; + + my $pkg_defined_in = scalar( caller(1) ); + + if ( defined $name ) { + my $type = $REGISTRY->get_type_constraint($name); + + ( $type->_package_defined_in eq $pkg_defined_in ) + || throw_exception( TypeConstraintIsAlreadyCreated => package_defined_in => $pkg_defined_in, + type_name => $type->name, + ) + if defined $type; + + if( $name !~ /^[\w:\.]+$/ ) { + throw_exception( InvalidNameForType => name => $name ); + } + } + + my %opts = ( + name => $name, + package_defined_in => $pkg_defined_in, + + ( $check ? ( constraint => $check ) : () ), + ( $message ? ( message => $message ) : () ), + ( $inlined ? ( inlined => $inlined ) : () ), + ); + + my $constraint; + if ( + defined $parent + and $parent + = blessed $parent + ? $parent + : find_or_create_isa_type_constraint($parent) + ) { + $constraint = $parent->create_child_type(%opts); + } + else { + $constraint = Moose::Meta::TypeConstraint->new(%opts); + } + + $REGISTRY->add_type_constraint($constraint) + if defined $name; + + return $constraint; +} + +sub _install_type_coercions ($$) { + my ( $type_name, $coercion_map ) = @_; + my $type = find_type_constraint($type_name); + ( defined $type ) + || throw_exception( CannotFindType => type_name => $type_name ); + + if ( $type->has_coercion ) { + $type->coercion->add_type_coercions(@$coercion_map); + } + else { + my $type_coercion = Moose::Meta::TypeCoercion->new( + type_coercion_map => $coercion_map, + type_constraint => $type + ); + $type->coercion($type_coercion); + } +} + +## -------------------------------------------------------- +## type notation parsing ... +## -------------------------------------------------------- + +{ + + # All I have to say is mugwump++ cause I know + # do not even have enough regexp-fu to be able + # to have written this (I can only barely + # understand it as it is) + # - SL + + use re "eval"; + + my $valid_chars = qr{[\w:\.]}; + my $type_atom = qr{ (?>$valid_chars+) }x; + my $ws = qr{ (?>\s*) }x; + my $op_union = qr{ $ws \| $ws }x; + + my ($type, $type_capture_parts, $type_with_parameter, $union, $any); + if (Class::MOP::IS_RUNNING_ON_5_10) { + my $type_pattern + = q{ (?&type_atom) (?: \[ (?&ws) (?&any) (?&ws) \] )? }; + my $type_capture_parts_pattern + = q{ ((?&type_atom)) (?: \[ (?&ws) ((?&any)) (?&ws) \] )? }; + my $type_with_parameter_pattern + = q{ (?&type_atom) \[ (?&ws) (?&any) (?&ws) \] }; + my $union_pattern + = q{ (?&type) (?> (?: (?&op_union) (?&type) )+ ) }; + my $any_pattern + = q{ (?&type) | (?&union) }; + + my $defines = qr{(?(DEFINE) + (?<valid_chars> $valid_chars) + (?<type_atom> $type_atom) + (?<ws> $ws) + (?<op_union> $op_union) + (?<type> $type_pattern) + (?<type_capture_parts> $type_capture_parts_pattern) + (?<type_with_parameter> $type_with_parameter_pattern) + (?<union> $union_pattern) + (?<any> $any_pattern) + )}x; + + $type = qr{ $type_pattern $defines }x; + $type_capture_parts = qr{ $type_capture_parts_pattern $defines }x; + $type_with_parameter = qr{ $type_with_parameter_pattern $defines }x; + $union = qr{ $union_pattern $defines }x; + $any = qr{ $any_pattern $defines }x; + } + else { + $type + = qr{ $type_atom (?: \[ $ws (??{$any}) $ws \] )? }x; + $type_capture_parts + = qr{ ($type_atom) (?: \[ $ws ((??{$any})) $ws \] )? }x; + $type_with_parameter + = qr{ $type_atom \[ $ws (??{$any}) $ws \] }x; + $union + = qr{ $type (?> (?: $op_union $type )+ ) }x; + $any + = qr{ $type | $union }x; + } + + + sub _parse_parameterized_type_constraint { + { no warnings 'void'; $any; } # force capture of interpolated lexical + $_[0] =~ m{ $type_capture_parts }x; + return ( $1, $2 ); + } + + sub _detect_parameterized_type_constraint { + { no warnings 'void'; $any; } # force capture of interpolated lexical + $_[0] =~ m{ ^ $type_with_parameter $ }x; + } + + sub _parse_type_constraint_union { + { no warnings 'void'; $any; } # force capture of interpolated lexical + my $given = shift; + my @rv; + while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) { + push @rv => $1; + } + ( pos($given) eq length($given) ) + || throw_exception( CouldNotParseType => type => $given, + position => pos($given) + ); + @rv; + } + + sub _detect_type_constraint_union { + { no warnings 'void'; $any; } # force capture of interpolated lexical + $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x; + } +} + +## -------------------------------------------------------- +# define some basic built-in types +## -------------------------------------------------------- + +# By making these classes immutable before creating all the types in +# Moose::Util::TypeConstraints::Builtin , we avoid repeatedly calling the slow +# MOP-based accessors. +$_->make_immutable( + inline_constructor => 1, + constructor_name => "_new", + + # these are Class::MOP accessors, so they need inlining + inline_accessors => 1 + ) for grep { $_->is_mutable } + map { Class::MOP::class_of($_) } + qw( + Moose::Meta::TypeConstraint + Moose::Meta::TypeConstraint::Union + Moose::Meta::TypeConstraint::Parameterized + Moose::Meta::TypeConstraint::Parameterizable + Moose::Meta::TypeConstraint::Class + Moose::Meta::TypeConstraint::Role + Moose::Meta::TypeConstraint::Enum + Moose::Meta::TypeConstraint::DuckType + Moose::Meta::TypeConstraint::Registry +); + +require Moose::Util::TypeConstraints::Builtins; +Moose::Util::TypeConstraints::Builtins::define_builtins($REGISTRY); + +my @PARAMETERIZABLE_TYPES + = map { $REGISTRY->get_type_constraint($_) } qw[ScalarRef ArrayRef HashRef Maybe]; + +sub get_all_parameterizable_types {@PARAMETERIZABLE_TYPES} + +sub add_parameterizable_type { + my $type = shift; + ( blessed $type + && $type->isa('Moose::Meta::TypeConstraint::Parameterizable') ) + || throw_exception( AddParameterizableTypeTakesParameterizableType => type_name => $type ); + + push @PARAMETERIZABLE_TYPES => $type; +} + +## -------------------------------------------------------- +# end of built-in types ... +## -------------------------------------------------------- + +{ + my @BUILTINS = list_all_type_constraints(); + sub list_all_builtin_type_constraints {@BUILTINS} +} + +1; + +# ABSTRACT: Type constraint system for Moose + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Util::TypeConstraints - Type constraint system for Moose + +=head1 VERSION + +version 2.1405 + +=head1 SYNOPSIS + + use Moose::Util::TypeConstraints; + + subtype 'Natural', + as 'Int', + where { $_ > 0 }; + + subtype 'NaturalLessThanTen', + as 'Natural', + where { $_ < 10 }, + message { "This number ($_) is not less than ten!" }; + + coerce 'Num', + from 'Str', + via { 0+$_ }; + + class_type 'DateTimeClass', { class => 'DateTime' }; + + role_type 'Barks', { role => 'Some::Library::Role::Barks' }; + + enum 'RGBColors', [qw(red green blue)]; + + union 'StringOrArray', [qw( String ArrayRef )]; + + no Moose::Util::TypeConstraints; + +=head1 DESCRIPTION + +This module provides Moose with the ability to create custom type +constraints to be used in attribute definition. + +=head2 Important Caveat + +This is B<NOT> a type system for Perl 5. These are type constraints, +and they are not used by Moose unless you tell it to. No type +inference is performed, expressions are not typed, etc. etc. etc. + +A type constraint is at heart a small "check if a value is valid" +function. A constraint can be associated with an attribute. This +simplifies parameter validation, and makes your code clearer to read, +because you can refer to constraints by name. + +=head2 Slightly Less Important Caveat + +It is B<always> a good idea to quote your type names. + +This prevents Perl from trying to execute the call as an indirect +object call. This can be an issue when you have a subtype with the +same name as a valid class. + +For instance: + + subtype DateTime => as Object => where { $_->isa('DateTime') }; + +will I<just work>, while this: + + use DateTime; + subtype DateTime => as Object => where { $_->isa('DateTime') }; + +will fail silently and cause many headaches. The simple way to solve +this, as well as future proof your subtypes from classes which have +yet to have been created, is to quote the type name: + + use DateTime; + subtype 'DateTime', as 'Object', where { $_->isa('DateTime') }; + +=head2 Default Type Constraints + +This module also provides a simple hierarchy for Perl 5 types, here is +that hierarchy represented visually. + + Any + Item + Bool + Maybe[`a] + Undef + Defined + Value + Str + Num + Int + ClassName + RoleName + Ref + ScalarRef[`a] + ArrayRef[`a] + HashRef[`a] + CodeRef + RegexpRef + GlobRef + FileHandle + Object + +B<NOTE:> Any type followed by a type parameter C<[`a]> can be +parameterized, this means you can say: + + ArrayRef[Int] # an array of integers + HashRef[CodeRef] # a hash of str to CODE ref mappings + ScalarRef[Int] # a reference to an integer + Maybe[Str] # value may be a string, may be undefined + +If Moose finds a name in brackets that it does not recognize as an +existing type, it assumes that this is a class name, for example +C<ArrayRef[DateTime]>. + +B<NOTE:> Unless you parameterize a type, then it is invalid to include +the square brackets. I.e. C<ArrayRef[]> will be treated as a new type +name, I<not> as a parameterization of C<ArrayRef>. + +B<NOTE:> The C<Undef> type constraint for the most part works +correctly now, but edge cases may still exist, please use it +sparingly. + +B<NOTE:> The C<ClassName> type constraint does a complex package +existence check. This means that your class B<must> be loaded for this +type constraint to pass. + +B<NOTE:> The C<RoleName> constraint checks a string is a I<package +name> which is a role, like C<'MyApp::Role::Comparable'>. + +=head2 Type Constraint Naming + +Type name declared via this module can only contain alphanumeric +characters, colons (:), and periods (.). + +Since the types created by this module are global, it is suggested +that you namespace your types just as you would namespace your +modules. So instead of creating a I<Color> type for your +B<My::Graphics> module, you would call the type +I<My::Graphics::Types::Color> instead. + +=head2 Use with Other Constraint Modules + +This module can play nicely with other constraint modules with some +slight tweaking. The C<where> clause in types is expected to be a +C<CODE> reference which checks its first argument and returns a +boolean. Since most constraint modules work in a similar way, it +should be simple to adapt them to work with Moose. + +For instance, this is how you could use it with +L<Declare::Constraints::Simple> to declare a completely new type. + + type 'HashOfArrayOfObjects', + where { + IsHashRef( + -keys => HasLength, + -values => IsArrayRef(IsObject) + )->(@_); + }; + +For more examples see the F<t/examples/example_w_DCS.t> test +file. + +Here is an example of using L<Test::Deep> and its non-test +related C<eq_deeply> function. + + type 'ArrayOfHashOfBarsAndRandomNumbers', + where { + eq_deeply($_, + array_each(subhashof({ + bar => isa('Bar'), + random_number => ignore() + }))) + }; + +For a complete example see the +F<t/examples/example_w_TestDeep.t> test file. + +=head2 Error messages + +Type constraints can also specify custom error messages, for when they fail to +validate. This is provided as just another coderef, which receives the invalid +value in C<$_>, as in: + + subtype 'PositiveInt', + as 'Int', + where { $_ > 0 }, + message { "$_ is not a positive integer!" }; + +If no message is specified, a default message will be used, which indicates +which type constraint was being used and what value failed. If +L<Devel::PartialDump> (version 0.14 or higher) is installed, it will be used to +display the invalid value, otherwise it will just be printed as is. + +=head1 FUNCTIONS + +=head2 Type Constraint Constructors + +The following functions are used to create type constraints. They +will also register the type constraints your create in a global +registry that is used to look types up by name. + +See the L</SYNOPSIS> for an example of how to use these. + +=over 4 + +=item B<< subtype 'Name', as 'Parent', where { } ... >> + +This creates a named subtype. + +If you provide a parent that Moose does not recognize, it will +automatically create a new class type constraint for this name. + +When creating a named type, the C<subtype> function should either be +called with the sugar helpers (C<where>, C<message>, etc), or with a +name and a hashref of parameters: + + subtype( 'Foo', { where => ..., message => ... } ); + +The valid hashref keys are C<as> (the parent), C<where>, C<message>, +and C<inline_as>. + +=item B<< subtype as 'Parent', where { } ... >> + +This creates an unnamed subtype and will return the type +constraint meta-object, which will be an instance of +L<Moose::Meta::TypeConstraint>. + +When creating an anonymous type, the C<subtype> function should either +be called with the sugar helpers (C<where>, C<message>, etc), or with +just a hashref of parameters: + + subtype( { where => ..., message => ... } ); + +=item B<class_type ($class, ?$options)> + +Creates a new subtype of C<Object> with the name C<$class> and the +metaclass L<Moose::Meta::TypeConstraint::Class>. + + # Create a type called 'Box' which tests for objects which ->isa('Box') + class_type 'Box'; + +By default, the name of the type and the name of the class are the same, but +you can specify both separately. + + # Create a type called 'Box' which tests for objects which ->isa('ObjectLibrary::Box'); + class_type 'Box', { class => 'ObjectLibrary::Box' }; + +=item B<role_type ($role, ?$options)> + +Creates a C<Role> type constraint with the name C<$role> and the +metaclass L<Moose::Meta::TypeConstraint::Role>. + + # Create a type called 'Walks' which tests for objects which ->does('Walks') + role_type 'Walks'; + +By default, the name of the type and the name of the role are the same, but +you can specify both separately. + + # Create a type called 'Walks' which tests for objects which ->does('MooseX::Role::Walks'); + role_type 'Walks', { role => 'MooseX::Role::Walks' }; + +=item B<maybe_type ($type)> + +Creates a type constraint for either C<undef> or something of the +given type. + +=item B<duck_type ($name, \@methods)> + +This will create a subtype of Object and test to make sure the value +C<can()> do the methods in C<\@methods>. + +This is intended as an easy way to accept non-Moose objects that +provide a certain interface. If you're using Moose classes, we +recommend that you use a C<requires>-only Role instead. + +=item B<duck_type (\@methods)> + +If passed an ARRAY reference as the only parameter instead of the +C<$name>, C<\@methods> pair, this will create an unnamed duck type. +This can be used in an attribute definition like so: + + has 'cache' => ( + is => 'ro', + isa => duck_type( [qw( get_set )] ), + ); + +=item B<enum ($name, \@values)> + +This will create a basic subtype for a given set of strings. +The resulting constraint will be a subtype of C<Str> and +will match any of the items in C<\@values>. It is case sensitive. +See the L</SYNOPSIS> for a simple example. + +B<NOTE:> This is not a true proper enum type, it is simply +a convenient constraint builder. + +=item B<enum (\@values)> + +If passed an ARRAY reference as the only parameter instead of the +C<$name>, C<\@values> pair, this will create an unnamed enum. This +can then be used in an attribute definition like so: + + has 'sort_order' => ( + is => 'ro', + isa => enum([qw[ ascending descending ]]), + ); + +=item B<union ($name, \@constraints)> + +This will create a basic subtype where any of the provided constraints +may match in order to satisfy this constraint. + +=item B<union (\@constraints)> + +If passed an ARRAY reference as the only parameter instead of the +C<$name>, C<\@constraints> pair, this will create an unnamed union. +This can then be used in an attribute definition like so: + + has 'items' => ( + is => 'ro', + isa => union([qw[ Str ArrayRef ]]), + ); + +This is similar to the existing string union: + + isa => 'Str|ArrayRef' + +except that it supports anonymous elements as child constraints: + + has 'color' => ( + isa => 'ro', + isa => union([ 'Int', enum([qw[ red green blue ]]) ]), + ); + +=item B<as 'Parent'> + +This is just sugar for the type constraint construction syntax. + +It takes a single argument, which is the name of a parent type. + +=item B<where { ... }> + +This is just sugar for the type constraint construction syntax. + +It takes a subroutine reference as an argument. When the type +constraint is tested, the reference is run with the value to be tested +in C<$_>. This reference should return true or false to indicate +whether or not the constraint check passed. + +=item B<message { ... }> + +This is just sugar for the type constraint construction syntax. + +It takes a subroutine reference as an argument. When the type +constraint fails, then the code block is run with the value provided +in C<$_>. This reference should return a string, which will be used in +the text of the exception thrown. + +=item B<inline_as { ... }> + +This can be used to define a "hand optimized" inlinable version of your type +constraint. + +You provide a subroutine which will be called I<as a method> on a +L<Moose::Meta::TypeConstraint> object. It will receive a single parameter, the +name of the variable to check, typically something like C<"$_"> or C<"$_[0]">. + +The subroutine should return a code string suitable for inlining. You can +assume that the check will be wrapped in parentheses when it is inlined. + +The inlined code should include any checks that your type's parent types +do. If your parent type constraint defines its own inlining, you can simply use +that to avoid repeating code. For example, here is the inlining code for the +C<Value> type, which is a subtype of C<Defined>: + + sub { + $_[0]->parent()->_inline_check($_[1]) + . ' && !ref(' . $_[1] . ')' + } + +=item B<< type 'Name', where { } ... >> + +This creates a base type, which has no parent. + +The C<type> function should either be called with the sugar helpers +(C<where>, C<message>, etc), or with a name and a hashref of +parameters: + + type( 'Foo', { where => ..., message => ... } ); + +The valid hashref keys are C<where>, C<message>, and C<inlined_as>. + +=back + +=head2 Type Constraint Utilities + +=over 4 + +=item B<< match_on_type $value => ( $type => \&action, ... ?\&default ) >> + +This is a utility function for doing simple type based dispatching similar to +match/case in OCaml and case/of in Haskell. It is not as featureful as those +languages, nor does not it support any kind of automatic destructuring +bind. Here is a simple Perl pretty printer dispatching over the core Moose +types. + + sub ppprint { + my $x = shift; + match_on_type $x => ( + HashRef => sub { + my $hash = shift; + '{ ' + . ( + join ", " => map { $_ . ' => ' . ppprint( $hash->{$_} ) } + sort keys %$hash + ) . ' }'; + }, + ArrayRef => sub { + my $array = shift; + '[ ' . ( join ", " => map { ppprint($_) } @$array ) . ' ]'; + }, + CodeRef => sub {'sub { ... }'}, + RegexpRef => sub { 'qr/' . $_ . '/' }, + GlobRef => sub { '*' . B::svref_2object($_)->NAME }, + Object => sub { $_->can('to_string') ? $_->to_string : $_ }, + ScalarRef => sub { '\\' . ppprint( ${$_} ) }, + Num => sub {$_}, + Str => sub { '"' . $_ . '"' }, + Undef => sub {'undef'}, + => sub { die "I don't know what $_ is" } + ); + } + +Or a simple JSON serializer: + + sub to_json { + my $x = shift; + match_on_type $x => ( + HashRef => sub { + my $hash = shift; + '{ ' + . ( + join ", " => + map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) } + sort keys %$hash + ) . ' }'; + }, + ArrayRef => sub { + my $array = shift; + '[ ' . ( join ", " => map { to_json($_) } @$array ) . ' ]'; + }, + Num => sub {$_}, + Str => sub { '"' . $_ . '"' }, + Undef => sub {'null'}, + => sub { die "$_ is not acceptable json type" } + ); + } + +The matcher is done by mapping a C<$type> to an C<\&action>. The C<$type> can +be either a string type or a L<Moose::Meta::TypeConstraint> object, and +C<\&action> is a subroutine reference. This function will dispatch on the +first match for C<$value>. It is possible to have a catch-all by providing an +additional subroutine reference as the final argument to C<match_on_type>. + +=back + +=head2 Type Coercion Constructors + +You can define coercions for type constraints, which allow you to +automatically transform values to something valid for the type +constraint. If you ask your accessor to coerce, then Moose will run +the type-coercion code first, followed by the type constraint +check. This feature should be used carefully as it is very powerful +and could easily take off a limb if you are not careful. + +See the L</SYNOPSIS> for an example of how to use these. + +=over 4 + +=item B<< coerce 'Name', from 'OtherName', via { ... } >> + +This defines a coercion from one type to another. The C<Name> argument +is the type you are coercing I<to>. + +To define multiple coercions, supply more sets of from/via pairs: + + coerce 'Name', + from 'OtherName', via { ... }, + from 'ThirdName', via { ... }; + +=item B<from 'OtherName'> + +This is just sugar for the type coercion construction syntax. + +It takes a single type name (or type object), which is the type being +coerced I<from>. + +=item B<via { ... }> + +This is just sugar for the type coercion construction syntax. + +It takes a subroutine reference. This reference will be called with +the value to be coerced in C<$_>. It is expected to return a new value +of the proper type for the coercion. + +=back + +=head2 Creating and Finding Type Constraints + +These are additional functions for creating and finding type +constraints. Most of these functions are not available for +importing. The ones that are importable as specified. + +=over 4 + +=item B<find_type_constraint($type_name)> + +This function can be used to locate the L<Moose::Meta::TypeConstraint> +object for a named type. + +This function is importable. + +=item B<register_type_constraint($type_object)> + +This function will register a L<Moose::Meta::TypeConstraint> with the +global type registry. + +This function is importable. + +=item B<normalize_type_constraint_name($type_constraint_name)> + +This method takes a type constraint name and returns the normalized +form. This removes any whitespace in the string. + +=item B<create_type_constraint_union($pipe_separated_types | @type_constraint_names)> + +=item B<create_named_type_constraint_union($name, $pipe_separated_types | @type_constraint_names)> + +This can take a union type specification like C<'Int|ArrayRef[Int]'>, +or a list of names. It returns a new +L<Moose::Meta::TypeConstraint::Union> object. + +=item B<create_parameterized_type_constraint($type_name)> + +Given a C<$type_name> in the form of C<'BaseType[ContainerType]'>, +this will create a new L<Moose::Meta::TypeConstraint::Parameterized> +object. The C<BaseType> must already exist as a parameterizable +type. + +=item B<create_class_type_constraint($class, $options)> + +Given a class name this function will create a new +L<Moose::Meta::TypeConstraint::Class> object for that class name. + +The C<$options> is a hash reference that will be passed to the +L<Moose::Meta::TypeConstraint::Class> constructor (as a hash). + +=item B<create_role_type_constraint($role, $options)> + +Given a role name this function will create a new +L<Moose::Meta::TypeConstraint::Role> object for that role name. + +The C<$options> is a hash reference that will be passed to the +L<Moose::Meta::TypeConstraint::Role> constructor (as a hash). + +=item B<create_enum_type_constraint($name, $values)> + +Given a enum name this function will create a new +L<Moose::Meta::TypeConstraint::Enum> object for that enum name. + +=item B<create_duck_type_constraint($name, $methods)> + +Given a duck type name this function will create a new +L<Moose::Meta::TypeConstraint::DuckType> object for that enum name. + +=item B<find_or_parse_type_constraint($type_name)> + +Given a type name, this first attempts to find a matching constraint +in the global registry. + +If the type name is a union or parameterized type, it will create a +new object of the appropriate, but if given a "regular" type that does +not yet exist, it simply returns false. + +When given a union or parameterized type, the member or base type must +already exist. + +If it creates a new union or parameterized type, it will add it to the +global registry. + +=item B<find_or_create_isa_type_constraint($type_name)> + +=item B<find_or_create_does_type_constraint($type_name)> + +These functions will first call C<find_or_parse_type_constraint>. If +that function does not return a type, a new type object will +be created. + +The C<isa> variant will use C<create_class_type_constraint> and the +C<does> variant will use C<create_role_type_constraint>. + +=item B<get_type_constraint_registry> + +Returns the L<Moose::Meta::TypeConstraint::Registry> object which +keeps track of all type constraints. + +=item B<list_all_type_constraints> + +This will return a list of type constraint names in the global +registry. You can then fetch the actual type object using +C<find_type_constraint($type_name)>. + +=item B<list_all_builtin_type_constraints> + +This will return a list of builtin type constraints, meaning those +which are defined in this module. See the L<Default Type Constraints> +section for a complete list. + +=item B<export_type_constraints_as_functions> + +This will export all the current type constraints as functions into +the caller's namespace (C<Int()>, C<Str()>, etc). Right now, this is +mostly used for testing, but it might prove useful to others. + +=item B<get_all_parameterizable_types> + +This returns all the parameterizable types that have been registered, +as a list of type objects. + +=item B<add_parameterizable_type($type)> + +Adds C<$type> to the list of parameterizable types + +=back + +=head1 BUGS + +See L<Moose/BUGS> for details on reporting bugs. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2006 by Infinity Interactive, Inc.. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/Moose/Util/TypeConstraints/Builtins.pm b/lib/Moose/Util/TypeConstraints/Builtins.pm new file mode 100644 index 0000000..400afe6 --- /dev/null +++ b/lib/Moose/Util/TypeConstraints/Builtins.pm @@ -0,0 +1,305 @@ +package Moose::Util::TypeConstraints::Builtins; +our $VERSION = '2.1405'; + +use strict; +use warnings; + +use Class::Load qw( is_class_loaded ); +use List::Util 1.33 (); +use Scalar::Util qw( blessed ); + +sub type { goto &Moose::Util::TypeConstraints::type } +sub subtype { goto &Moose::Util::TypeConstraints::subtype } +sub as { goto &Moose::Util::TypeConstraints::as } +sub where (&) { goto &Moose::Util::TypeConstraints::where } +sub inline_as (&) { goto &Moose::Util::TypeConstraints::inline_as } + +sub define_builtins { + my $registry = shift; + + type 'Any' # meta-type including all + => where {1} + => inline_as { '1' }; + + subtype 'Item' # base type + => as 'Any' + => inline_as { '1' }; + + subtype 'Undef' + => as 'Item' + => where { !defined($_) } + => inline_as { + '!defined(' . $_[1] . ')' + }; + + subtype 'Defined' + => as 'Item' + => where { defined($_) } + => inline_as { + 'defined(' . $_[1] . ')' + }; + + subtype 'Bool' + => as 'Item' + => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' } + => inline_as { + '(' + . '!defined(' . $_[1] . ') ' + . '|| ' . $_[1] . ' eq "" ' + . '|| (' . $_[1] . '."") eq "1" ' + . '|| (' . $_[1] . '."") eq "0"' + . ')' + }; + + subtype 'Value' + => as 'Defined' + => where { !ref($_) } + => inline_as { + $_[0]->parent()->_inline_check($_[1]) + . ' && !ref(' . $_[1] . ')' + }; + + subtype 'Ref' + => as 'Defined' + => where { ref($_) } + # no need to call parent - ref also checks for definedness + => inline_as { 'ref(' . $_[1] . ')' }; + + subtype 'Str' + => as 'Value' + => where { ref(\$_) eq 'SCALAR' || ref(\(my $val = $_)) eq 'SCALAR' } + => inline_as { + $_[0]->parent()->_inline_check($_[1]) + . ' && (' + . 'ref(\\' . $_[1] . ') eq "SCALAR"' + . ' || ref(\\(my $val = ' . $_[1] . ')) eq "SCALAR"' + . ')' + }; + + my $value_type = Moose::Util::TypeConstraints::find_type_constraint('Value'); + subtype 'Num' + => as 'Str' + => where { + my $val = $_; + ($val =~ /\A[+-]?[0-9]+\z/) || + ( $val =~ /\A(?:[+-]?) #matches optional +- in the beginning + (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3 + [0-9]* #matches 0-9 zero or more times + (?:\.[0-9]+)? #matches optional .89 or nothing + (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc + \z/x ); + } + => inline_as { + # the long Str tests are redundant here + #storing $_[1] in a temporary value, + #so that $_[1] won't get converted to a string for regex match + #see t/attributes/numeric_defaults.t for more details + 'my $val = '.$_[1].';'. + $value_type->_inline_check('$val') + .' && ( $val =~ /\A[+-]?[0-9]+\z/ || ' + . '$val =~ /\A(?:[+-]?) #matches optional +- in the beginning + (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3 + [0-9]* #matches 0-9 zero or more times + (?:\.[0-9]+)? #matches optional .89 or nothing + (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc + \z/x ); ' + }; + + subtype 'Int' + => as 'Num' + => where { (my $val = $_) =~ /\A-?[0-9]+\z/ } + => inline_as { + $value_type->_inline_check($_[1]) + . ' && (my $val = ' . $_[1] . ') =~ /\A-?[0-9]+\z/' + }; + + subtype 'CodeRef' + => as 'Ref' + => where { ref($_) eq 'CODE' } + => inline_as { 'ref(' . $_[1] . ') eq "CODE"' }; + + subtype 'RegexpRef' + => as 'Ref' + => where( \&_RegexpRef ) + => inline_as { + 'Moose::Util::TypeConstraints::Builtins::_RegexpRef(' . $_[1] . ')' + }; + + subtype 'GlobRef' + => as 'Ref' + => where { ref($_) eq 'GLOB' } + => inline_as { 'ref(' . $_[1] . ') eq "GLOB"' }; + + # NOTE: scalar filehandles are GLOB refs, but a GLOB ref is not always a + # filehandle + subtype 'FileHandle' + => as 'Ref' + => where { + (ref($_) eq "GLOB" && Scalar::Util::openhandle($_)) + || (blessed($_) && $_->isa("IO::Handle")); + } + => inline_as { + '(ref(' . $_[1] . ') eq "GLOB" ' + . '&& Scalar::Util::openhandle(' . $_[1] . ')) ' + . '|| (Scalar::Util::blessed(' . $_[1] . ') ' + . '&& ' . $_[1] . '->isa("IO::Handle"))' + }; + + subtype 'Object' + => as 'Ref' + => where { blessed($_) } + => inline_as { 'Scalar::Util::blessed(' . $_[1] . ')' }; + + subtype 'ClassName' + => as 'Str' + => where { is_class_loaded($_) } + # the long Str tests are redundant here + => inline_as { 'Class::Load::is_class_loaded(' . $_[1] . ')' }; + + subtype 'RoleName' + => as 'ClassName' + => where { + (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role'); + } + => inline_as { + $_[0]->parent()->_inline_check($_[1]) + . ' && do {' + . 'my $meta = Class::MOP::class_of(' . $_[1] . ');' + . '$meta && $meta->isa("Moose::Meta::Role");' + . '}' + }; + + $registry->add_type_constraint( + Moose::Meta::TypeConstraint::Parameterizable->new( + name => 'ScalarRef', + package_defined_in => __PACKAGE__, + parent => + Moose::Util::TypeConstraints::find_type_constraint('Ref'), + constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' }, + constraint_generator => sub { + my $type_parameter = shift; + my $check = $type_parameter->_compiled_type_constraint; + return sub { + return $check->( ${$_} ); + }; + }, + inlined => sub { + 'ref(' . $_[1] . ') eq "SCALAR" ' + . '|| ref(' . $_[1] . ') eq "REF"' + }, + inline_generator => sub { + my $self = shift; + my $type_parameter = shift; + my $val = shift; + '(ref(' . $val . ') eq "SCALAR" || ref(' . $val . ') eq "REF") ' + . '&& ' . $type_parameter->_inline_check('${(' . $val . ')}') + }, + ) + ); + + $registry->add_type_constraint( + Moose::Meta::TypeConstraint::Parameterizable->new( + name => 'ArrayRef', + package_defined_in => __PACKAGE__, + parent => + Moose::Util::TypeConstraints::find_type_constraint('Ref'), + constraint => sub { ref($_) eq 'ARRAY' }, + constraint_generator => sub { + my $type_parameter = shift; + my $check = $type_parameter->_compiled_type_constraint; + return sub { + foreach my $x (@$_) { + ( $check->($x) ) || return; + } + 1; + } + }, + inlined => sub { 'ref(' . $_[1] . ') eq "ARRAY"' }, + inline_generator => sub { + my $self = shift; + my $type_parameter = shift; + my $val = shift; + + 'do {' + . 'my $check = ' . $val . ';' + . 'ref($check) eq "ARRAY" ' + . '&& &List::Util::all(' + . 'sub { ' . $type_parameter->_inline_check('$_') . ' }, ' + . '@{$check}' + . ')' + . '}'; + }, + ) + ); + + $registry->add_type_constraint( + Moose::Meta::TypeConstraint::Parameterizable->new( + name => 'HashRef', + package_defined_in => __PACKAGE__, + parent => + Moose::Util::TypeConstraints::find_type_constraint('Ref'), + constraint => sub { ref($_) eq 'HASH' }, + constraint_generator => sub { + my $type_parameter = shift; + my $check = $type_parameter->_compiled_type_constraint; + return sub { + foreach my $x ( values %$_ ) { + ( $check->($x) ) || return; + } + 1; + } + }, + inlined => sub { 'ref(' . $_[1] . ') eq "HASH"' }, + inline_generator => sub { + my $self = shift; + my $type_parameter = shift; + my $val = shift; + + 'do {' + . 'my $check = ' . $val . ';' + . 'ref($check) eq "HASH" ' + . '&& &List::Util::all(' + . 'sub { ' . $type_parameter->_inline_check('$_') . ' }, ' + . 'values %{$check}' + . ')' + . '}'; + }, + ) + ); + + $registry->add_type_constraint( + Moose::Meta::TypeConstraint::Parameterizable->new( + name => 'Maybe', + package_defined_in => __PACKAGE__, + parent => + Moose::Util::TypeConstraints::find_type_constraint('Item'), + constraint => sub {1}, + constraint_generator => sub { + my $type_parameter = shift; + my $check = $type_parameter->_compiled_type_constraint; + return sub { + return 1 if not( defined($_) ) || $check->($_); + return; + } + }, + inlined => sub {'1'}, + inline_generator => sub { + my $self = shift; + my $type_parameter = shift; + my $val = shift; + '!defined(' . $val . ') ' + . '|| (' . $type_parameter->_inline_check($val) . ')' + }, + ) + ); +} + +1; + +__END__ + +=pod + +=for pod_coverage_needs_some_pod + +=cut |