NAME
Sub::Mage::Spellbook - Recipes for Sub::Mage
IMPORTS
We'll start with import attributes seems that they are created at the beginning when we use Sub::Mage
. Generally they will be in the form of an array, as such:
use Sub::Mage qw/:5.010 :Debug :Moose/;
The first option :5.010
imports the 5.010 feature (so you can use "say" and "given"), the second :Debug
turns on debugging, and the last one we used :Moose
lets Sub::Mage know that you're using Moose, so don't import overide
, after
and before
as Moose already has these features. And Moose is great. Another handy import attribute is :Class
. Please read below about Controlling a Class remotely to see how it works.
Controlling a Class remotely
Sub::Mage makes this easy with its array of methods.
First, let's create a blank package and turn it into our class. When using :Class
it removes the need to add sub new { ... }
and also imports some other handy methods, like augment
and accessor
.
package Spells;
use Sub::Mage qw/:Class/;
1;
That's our whole class.. now, let's control it from merlin.pl
use Spells;
my $spells = Spells->new;
# create a method called 'fireball' in Spells
Spells->conjur( fireball => sub {
my $self = shift;
$self->{damage} = 5;
});
# create an accessor method called 'damage_of_fireball'
Spells->conjur( damage_of_fireball => sub {
return shift->{damage};
});
$spells->fireball;
print $spells->damage_of_fireball; # returns 5
Notice how we didn't even need to load Sub::Mage
in merlin.pl
? This is because we used everything from the Spells
class. We've created the subroutine fireball
but we want to let people create their own damage modifier and make it verbose..
Spells->override( fireball => sub {
my ($self, $val) = @_;
$self->{damage} = $val;
});
Oh, we forgot to make it verbose. Let's just tag it on the end...
Spells->after( fireball => sub {
my ($self, $val) = @_;
print "Damage set to $val\n";
});
So now we call..
$spells->fireball(10);
And see Damage set to 10
. And that's how you can control a blank class remotely. Useless, but interesting.
TIPS
Not just for subroutines
While Sub::Mage was created to manage subroutines, it has had some extra functionality added to it. You can use it as a very small OOP framework.. very small. This is not to replace Moo, Mo, Mouse, Moose, etc, etc.. However, if you're using Sub::Mage anyway and need something lightweight, it may just do what you're looking for.
Let's take a look at what you get when you import :Class
accessor
Accessor can be used to create, you guessed it, accessors. These accessors are readable and writable methods which means you can alter the value of it down the track if you wish.
augment
An awful name, to which I regret. Augment is similar to use base
. You can also add multiple modules into your augmentation.
augment qw/
My::Cool::Module
I::Need::This::One
And::This::One
/;
chainable
Simply adds a return bless $self, 'Into::Package'
to the end of the given subroutine. You can now bless a different $self
key now, too. ie: $self-
{_key}
The above methods can help writing a class fairly easy, and neat. chainable
may seem like more typing, but you get the bonus of having all of your chains at the top of your code as reference. This may not be handy for everyone, but I sure like it.
Writing a class
Let's create a simple module.
package MyModule;
use Sub::Mage qw/:Class/;
accessor 'x' => 7;
1;
If you weren't to use Sub::Mage you would need to add new
and create subroutine called x
that could return a value, but also take an argument that would change that default value to return next time. Now let's use the module. Sub::Mage modules can be used the same as any other, but let's inherit it.
package MyApp;
use Sub::Mage qw/:Class/;
augment 'MyModule';
my $foo = MyModule->new;
print $foo->x; # prints 7
__PACKAGE__->x(5); # augmenting it allows us to call it from __PACKAGE__ or $self
print __PACKAGE__->x; # prints 5
# now throw in some classic Sub::Mage
MyModule->after(sub {
my $self = shift;
print "X is done!\n";
});
__PACKAGE__->x; # prints X is done!
Sub::Mage will try to allow you to do pretty much anything you can think of. So as you can see, altering subroutines is just the surface to what it offers.