NAME Class::Monkey - Monkey Patch a class/instance with modifiers and other sweet stuff DESCRIPTION Say we have a module installed on the system. It does some handy things, but you find a bug or a strange feature. We can easily fix it without subclassing by the following... # StupidClass.pm package SupidClass; sub new { my $class = shift; return bless {}, $class; } sub name { my ($self, $name) = @_; print "Hello, ${name}\n"; } sub no_args { print "No arguments were specified!\n"; } 1; Above is our class. A stupid one at that. The "name" method doesn't validate the arguments.. it just tries to print them in a 'hello' string. We can use an "around" method to call the "name" method if arguments are passed, or to call "no_args" if not. We can happily do this from the program. # our_program.pl use Class::Monkey qw; # The patch around 'name' => sub { my $method = shift; my $self = shift; if (@_) { $self->$method(@_); } else { $self->no_args(); } }, qw; # /The Patch $s->name(); # actually executes no_args $s->name("World"): # runs name SYNOPSIS Simply import the classes you want to patch as an array when you "use Class::Monkey". Doing this means you won't even need to "use" the module you want to patch - Class::Monkey takes care of that for you. use Class::Monkey qw; method 'needThisMethod' => sub { ... }, qw; my $p = Some::Package->new; $p->needThisMethod; METHODS exports Have a subroutine in your file you want to explort to your patched class? Use "exports" to do so. package Foo; sub new { return bless {}, __PACKAGE__ } 1; # test.pl package MyPatcher; use Class::Monkey qw; sub foo { print "Hiya\n"; } exports 'foo', qw; my $foo = Foo->new; $foo->foo(); # prints Hiya exports 'foo', $foo; # works with instances too extends Sometimes you might not want to include the module you want to patch when you "use Class::Monkey". No problem. You can use "extends" to do it later on. use Class::Monkey; extends 'SomeClass'; extends qw; has Gives the wanted class an accessor. You can assign it a read-only or read-writable type (Similar to Moose). Because it works on remote packages you need to give it the full name of the method including the class. use Class::Monkey qw; has 'Foo::Class::greet' => ( is => 'ro', default => 'Hello' ); # read-only has 'Foo::Class::name' => ( is => 'rw', default => 'World' ); # read-writable my $foo = Foo::Class->new; say "Hello, " . $foo->name; $foo->name('Monkey); # updates the name accessor to return a new value If you leave out the "is" parameter when you define an accessor it will always default to read-writable. instance Note This method should be deprecated as all modifiers now support constants OR an instance. Class::Monkey will determine which method should be used, so calling "instance" is no longer required. Patch an instance method instead of an entire class # Pig.pm package Pig; sub new { return bless {}, shift; } sub says { print "Oink!\n"; } # test.pl package main; use Class::Monkey qw; my $pig = Pig->new; my $pig2 = Pig->new; instance 'says' => sub { print "Meow\n"; }, $pig2; # only $pig2 will have its says method overridden As of 0.002 you can now do it like this override 'says' => sub { print "Meow\n"; }, $pig2; before 'says' => sub { print "Going to speak\n"; }, $pig; etc.. original If you want to run the original version of a patched method, but not unpatch it right away you can use "original" to do so. It will run the old method before it was patched with any arguments you specify, but the actual method will still remain patched. after 'someMethod' => sub { print "Blah\n" }, qw; original('Foo', 'someMethod', qw); OR if you prefer, you can just call "Class::Monkey::PatchedClassName::method-"(@args)> Class::Monkey::Foo->someMethod('these', 'are', 'my', 'args); override Overrides an already existing method. If the target method doesn't exist then Class::Monkey will throw an error. override 'foo' => sub { return "foo bar"; }, qw; method Creates a brand new method in the target module. It will NOT allow you to override an existing one using this, and will throw an error. method 'active_customers' => sub { my $self = shift; return $self->search({ status => 'active' }); }, qw; before Simply adds code to the target method before the original code is ran # Foo.pm package Foo; sub new { return bless {}, __PACKAGE__; } sub hello { print "Hello, $self->{name}; } 1; # test.pl use Class::Monkey qw; my $foo = Foo->new; before 'hello' => { my $self = shift; $self->{name} = 'World'; }, qw; print $foo->hello . "\n"; after Basically the same as "before", but appends the code specified to the END of the original around Around gives the user a bit more control over the subroutine. When you create an around method the first argument will be the original method, the second is $self and the third is any arguments passed to the original subroutine. In a away this allows you to control the flow of the entire subroutine. package MyFoo; sub greet { my ($self, $name) = @_; print "Hello, $name!\n"; } 1; # test.pl use Class::Monkey qw; # only call greet if any arguments were passed to MyFoo->greet() around 'greet' => sub { my $method = shift; my $self = shift; $self->$method(@_) if @_; }, qw; unpatch Undoes any modifications made to patched methods, restoring it to its original state. override 'this' => sub { print "Blah\n"; }, qw; unpatch 'this', 'FooClass'; AUTHOR Brad Haywood LICENSE You may distribute this code under the same terms as Perl itself.