Acme-oop-ism Part Three: techniques

Acme-oop-ism is about writing code that works in Moose, Mouse and Moo. We've already looked at how Type::Tiny has achieved this. Now I'm going to introduce you to some Acme-oop-ist techniques.

use Moo

Want to write a reusable class or role to stick on CPAN? If you were planning on using Moose, how about considering Moo instead? Moo doesn't have all of Moose's features, but if your project doesn't need advanced metaprogramming, it may still have enough.

Moo is designed to interact nicely with Moose. Moose and Moo classes can extend each other. Moose classes can consume Moo roles, and vice versa. It won't much help you interact with Mouse, but two out of three ain't bad.

Role::Tiny is sometimes also an option.

Delegate

Rather than creating roles intended for consumption, or base classes intended for inheriting from, each of which would potentially lock people using your module into a particular OO framework, consider creating small classes that can be delegated to.

As an example, rather than creating a HorseDrawn role that can be applied to cart objects, create a Horse class that cart objects can delegate conveyance to.

Moo, Mouse and Moose each have handy shortcuts (handles) for delegated methods.

Use Moo or Class::Tiny, or even hand-written classes to keep dependencies down.

Use the surface syntax

The internals of Moo, Mouse and Moose are rather different to each other (particularly Moo). Their syntactic sugar is less so. Rather than calling $class->meta->add_attribute(), can you get away with calling has()?

MooX::HandlesVia and MooX::late are two CPAN modules that extend Moo by providing wrappers for has(). Each of these is Moo-specific, but it's easy to imagine applications of this idea that are not.

MooseX::MungeHas provides generic logic for munging has across OO frameworks.

MooX::PrivateAttributes and MooX::ProtectedAttributes manage to work for Moose by using a similar technique - calling the has and around sugar instead of metaclass tinkering.

Multiple code paths

As a last resort, you can add different code paths for handling Moose, Mouse and Moo. You can check to see what framework a class is using via $class->meta->isa(...) and handle it appropriately.

Tools of the trade include run-time loading via require or Module::Runtime, and judicious use of stringy eval.

Kavorka::MethodModifier's install_sub method is an example of this, providing different code paths for installing method modifiers into Moo, Mouse, Moose, and plain Perl classes.

Subclass::Of is another example.

That's all your Acme-oop for now. I'll write some more on the topic soon.

4 Comments

By the way, just to clear up a bit of confusion on my part: does Class::Tiny support multiple inheritance? Because it isn't stated anywhere in the documentation. I managed to subclass two other packages, but the code also works when I replace Class::Tiny with Object::Tiny which specifically states in the docs that MI won't work. Maybe I'm doing something wrong?

https://gist.github.com/ggl/7219790

I'm was just toying around with Perl OO builders trying to grasp some more advanced concepts and wondered if Class::Tiny supports MI. I know it can be extended to do roles and other Moose-isms via Class::Tiny::Antlers but saw nothing about MI in the documentation, the source, github. Your article turned out to be a proper opportunity to ask.

I've modified the gist after reading again through perlobj.

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.