Kubernetes-REST

 view release on metacpan or  search on metacpan

.claude/skills/perl-moo/SKILL.md  view on Meta::CPAN

# Sequential with → first wins:
with 'RoleA';   # foo() from RoleA is now in the class
with 'RoleB';   # foo() already exists → RoleA wins silently
```

"Class wins": if the class defines `foo()` itself, neither role's version is used. For complex conflict strategies: refactor roles to avoid the overlap.

---

## Pattern 12 – Parameterized Roles

```perl
package Counter;
use Moo::Role;
use MooX::Role::Parameterized;
parameter name => (is => 'ro', required => 1);
role {
    my ($p, $mop) = @_;
    my $n = $p->name;
    $mop->has($n => (is => 'rw', default => sub { 0 }));
    $mop->method("inc_$n" => sub { $_[0]->$n($_[0]->$n + 1) });
};

package Thing;
use Moo;
use MooX::Role::Parameterized::With;
with Counter => { name => 'hits' };

Thing->new->inc_hits;   # generates: hits attribute + inc_hits method
```

Module is marked **experimental**. `role { }` block runs at composition time; `$mop` proxies `has/around/before/after/requires`.

---

## Pattern 13 – Moose Interop

When Moose is loaded before Moo classes are compiled, Moo auto-inflates its metaclasses. This means:

- Moose class can `extends` a Moo class
- Moo class can `with` a Moose role

```perl
BEGIN { require Moose }
package MyMooseClass;
use Moose;
extends 'MyMooClass';   # works if Moose was loaded first
```

For Moose-style syntax in Moo (`isa => 'Str'`, `lazy_build`), use `MooX::late`. Avoid `Any::Moose` – deprecated, points to Moo.

---

## Type Constraints

Moo has no built-in type system. `isa` takes a coderef:

```perl
use Types::Standard qw(Str Int ArrayRef);
has name => (is => 'ro', isa => Str);
has tags => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });
```

`Type::Tiny` / `Types::Standard` is the official recommendation in Moo docs (replaces `MooseX::Types`).

---

## Decision Guide

| Situation | Use |
|---|---|
| Shared attributes/methods, stable "is-a" | `extends` |
| Optional/horizontal feature | `Moo::Role` + `with` |
| Same pattern, different config | `MooX::Role::Parameterized` |
| Delegate method set to sub-object | `handles` |
| Array/Hash operations on attribute | `Sub::HandlesVia` |
| Logging/validation/caching wrapper | `before`/`around`/`after` |
| Catch constructor typos | `MooX::StrictConstructor` |
| Cross-project boilerplate | `Import::Into` house-style module |
| Named types | `Type::Tiny` / `Types::Standard` |
| Multiple roles define same method | Sequential `with` or refactor |
| Legacy non-Moo parent | `FOREIGNBUILDARGS` |
| Multiple inheritance | Last resort; use `mro 'c3'` |

---

## Common Pitfalls

- `default => []` → **shared state bug**. Always `default => sub { [] }`.
- `extends 'A'; extends 'B'` → replaces, does NOT add B to A. Use `extends 'A', 'B'`.
- Imports after `use Moo::Role` are **composed into consumers** as methods.
- `namespace::autoclean` < 0.16 inflates Moo classes to Moose unexpectedly.
- `trigger` does NOT receive old value (unlike Moose).
- `Sub::HandlesVia` must be loaded *after* `use Moo`.
- `BUILD` chain is automatic; calling `SUPER::BUILD` manually breaks it.
- Never override `DESTROY`; use `DEMOLISH`.



( run in 2.650 seconds using v1.01-cache-2.11-cpan-99c4e6809bf )