App-Raider
view release on metacpan or search on metacpan
.claude/skills/perl-moose/SKILL.md view on Meta::CPAN
__PACKAGE__->meta->make_immutable;
```
**Rules:** Moose does NOT silently pick a winner â conflicts are fatal. Class-defined method always wins over roles.
---
## Pattern 4 â Roles in Roles (Bundles)
```perl
package Role::Bundle;
use Moose::Role;
with 'Role::Printable', 'Role::Serializable'; # bundle multiple roles
```
Composing `Role::Bundle` into a class pulls in both sub-roles. Good for grouping related capabilities.
---
## Pattern 5 â Dynamic Role Application
```perl
use Moose::Util 'apply_all_roles';
my $obj = MyClass->new;
apply_all_roles($obj, 'Role::Debug'); # reblesses into anon subclass
```
Use for plugin systems or per-instance decoration. Required role attributes must already be present.
---
## Pattern 6 â Parameterized Roles (MooseX::Role::Parameterized)
```perl
package Role::Counter;
use MooseX::Role::Parameterized;
parameter name => (isa => 'Str', required => 1);
role {
my $p = shift;
my $n = $p->name;
has $n => (is => 'rw', isa => 'Int', default => 0);
method "inc_$n" => sub { my $self = shift; $self->$n($self->$n + 1) };
};
package Game::Weapon;
use Moose;
use namespace::autoclean;
with 'Role::Counter' => { name => 'power' };
__PACKAGE__->meta->make_immutable;
# generates: power attribute + inc_power method
```
Use `method` (not `sub`) inside `role { }` block. Non-core â adds `MooseX::Role::Parameterized` dependency.
---
## Pattern 7 â Attribute Options Cheatsheet
```perl
has name => (is => 'ro', required => 1);
has tags => (is => 'ro', isa => 'ArrayRef[Str]', default => sub { [] }); # ALWAYS coderef for refs
has content => (is => 'lazy'); # built on first access
sub _build_content { "generated: " . $_[0]->name }
has status => (
is => 'rw',
isa => 'Str',
trigger => sub { # fires on new() and set
my ($self, $new, $old) = @_; # $old is undef on construction
die "bad status" unless $new =~ /\A(new|ok|done)\z/;
},
);
has _secret => (is => 'ro', init_arg => 'secret'); # constructor uses 'secret', stored as _secret
has size => (
is => 'ro',
isa => 'Int',
coerce => 1, # requires subtype with coercion defined
);
```
**Rules:**
- `default => []` â **shared state bug**. Always `default => sub { [] }`.
- Prefer `builder` over `default` for complex initialization â builders are inheritable and overridable.
- `trigger` receives `($self, $new_val, $old_val)` â unlike Moo, old value IS passed.
- `coerce` only on your own subtypes, never on built-in type names (global side effects).
- `is => 'lazy'` requires a `_build_name` method or explicit `builder`.
---
## Pattern 8 â Native Traits Delegation
```perl
package TaskList;
use Moose;
use namespace::autoclean;
has tasks => (
traits => ['Array'],
is => 'ro',
isa => 'ArrayRef[Task]',
default => sub { [] },
handles => {
add_task => 'push',
next_task => 'shift',
all_tasks => 'elements',
task_count => 'count',
find_task => 'first',
},
);
__PACKAGE__->meta->make_immutable;
```
Available native traits: `Array`, `Hash`, `Bool`, `String`, `Number`, `Counter`, `Code`. Each provides a set of generated methods. See `Moose::Meta::Attribute::Native::Trait::*` on CPAN.
---
## Pattern 9 â `handles` Delegation to Objects
```perl
package Website;
.claude/skills/perl-moose/SKILL.md view on Meta::CPAN
```perl
around BUILDARGS => sub {
my ($orig, $class, @args) = @_;
# normalize: allow single string arg
return $class->$orig(id => $args[0]) if @args == 1 && !ref $args[0];
$class->$orig(@args);
};
sub BUILD {
my ($self, $args) = @_; # called AFTER all attributes are set
die "SSN required for US" if $self->country eq 'USA' && !$self->ssn;
# don't call SUPER::BUILD â Moose handles the chain (parentâchild order)
}
```
**Rules:**
- Never define `sub new` â use `BUILDARGS`/`BUILD` instead.
- `BUILDARGS`: class method, runs before construction, returns hashref.
- `BUILD`: object method, runs after construction. Moose calls all `BUILD` in the hierarchy automatically.
- Never call `SUPER::BUILD` manually.
- For cleanup: use `DEMOLISH` (childâparent order), never override `DESTROY`.
---
## Pattern 13 â `make_immutable` + `namespace::autoclean`
```perl
package MyClass;
use Moose;
use namespace::autoclean; # remove imported keywords after compile
has name => (is => 'ro', required => 1);
__PACKAGE__->meta->make_immutable; # ALWAYS â massive perf gain on object creation
```
**Rules:**
- `namespace::autoclean` goes at the top (after `use Moose`), `make_immutable` at the bottom.
- After `make_immutable`: no more dynamic `add_attribute`, `add_role` etc.
- `namespace::autoclean` removes `has`, `with`, `extends` etc. from the symbol table â they won't accidentally become methods.
---
## Pattern 14 â Type Constraints
```perl
use Moose::Util::TypeConstraints;
subtype 'PositiveInt',
as 'Int',
where { $_ > 0 },
message { "$_ is not a positive integer" };
coerce 'PositiveInt',
from 'Str',
via { int($_) };
# Or use Type::Tiny (recommended â works with both Moo and Moose):
use Types::Standard qw(Str Int ArrayRef InstanceOf);
has name => (is => 'ro', isa => Str);
has items => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });
```
Prefer `Type::Tiny` / `Types::Standard` â portable between Moo and Moose, better error messages.
---
## Decision Guide
| Situation | Use |
|---|---|
| Shared attributes/methods, stable "is-a" | `extends` |
| Optional/horizontal feature | `Moose::Role` + `with` |
| Enforce interface contract | `requires` |
| Same role, different config | `MooseX::Role::Parameterized` |
| Delegate method set to sub-object | `handles` (list/hash/role form) |
| Array/Hash/Counter operations | `traits => ['Array']` + `handles` |
| Logging/validation/caching wrapper | `before`/`around`/`after` |
| Parent defines frame, child fills content | `augment`/`inner` |
| Normalize constructor args | `around BUILDARGS` |
| Post-construction validation/setup | `BUILD` |
| Catch constructor typos | `MooseX::StrictConstructor` |
| Named types with coercion | `Type::Tiny` / `Moose::Util::TypeConstraints` |
| Multiple roles define same method | Resolve in class or `-alias`/`-excludes` |
| Metaclass extensions | `traits` on attributes or class |
| Per-instance behavior change | `Moose::Util::apply_all_roles` |
---
## Common Pitfalls
- `default => []` â **shared state bug**. Always `default => sub { [] }`.
- `extends 'A'; extends 'B'` â replaces, does NOT add. Use `extends 'A', 'B'`.
- Separate `with 'RoleA'; with 'RoleB'` â skips conflict detection. Use one `with`.
- `with` before `has` â `requires` check may fail spuriously. Define `has` first.
- `coerce` on built-in type names â global side effects across the whole program.
- Never define `sub new` â breaks Moose constructor optimization.
- Never call `SUPER::BUILD` manually â Moose handles the chain.
- Never override `DESTROY` â use `DEMOLISH`.
- Forgetting `make_immutable` â significant performance penalty on every `new`.
- `around` without forwarding `@_` correctly â subtle argument loss.
---
## MooseX Extensions (Cheatsheet)
| Module | Purpose |
|---|---|
| `MooseX::StrictConstructor` | Dies on unknown constructor args |
| `MooseX::Role::Parameterized` | Parameterized roles |
| `MooseX::ClassAttribute` | Class-level (shared) attributes |
| `MooseX::Types` | Named type libraries |
| `MooseX::Singleton` | Singleton pattern (`->instance`) |
| `MooseX::Getopt` | Auto CLI options from attributes |
| `MooseX::Storage` | Serialization/deserialization |
( run in 0.417 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )