summaryrefslogtreecommitdiff
path: root/lib/Class/MakeMethods/Composite/Universal.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Class/MakeMethods/Composite/Universal.pm')
-rw-r--r--lib/Class/MakeMethods/Composite/Universal.pm150
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/Class/MakeMethods/Composite/Universal.pm b/lib/Class/MakeMethods/Composite/Universal.pm
new file mode 100644
index 0000000..e53e76d
--- /dev/null
+++ b/lib/Class/MakeMethods/Composite/Universal.pm
@@ -0,0 +1,150 @@
+=head1 NAME
+
+Class::MakeMethods::Composite::Universal - Composite Method Tricks
+
+=head1 SYNOPSIS
+
+ Class::MakeMethods::Composite::Universal->make_patch(
+ -TargetClass => 'SomeClass::OverYonder',
+ name => 'foo',
+ pre_rules => [
+ sub {
+ my $method = pop;
+ warn "Arguments for foo:", @_
+ }
+ ]
+ post_rules => [
+ sub {
+ warn "Result of foo:", Class::MakeMethods::Composite->CurrentResults
+ }
+ ]
+ );
+
+=head1 DESCRIPTION
+
+The Composite::Universal suclass of MakeMethods provides some generally-applicable types of methods based on Class::MakeMethods::Composite.
+
+=cut
+
+package Class::MakeMethods::Composite::Universal;
+
+$VERSION = 1.000;
+use strict;
+use Class::MakeMethods::Composite '-isasubclass';
+use Carp;
+
+########################################################################
+
+=head1 METHOD GENERATOR TYPES
+
+=head2 patch
+
+The patch ruleset generates composites whose core behavior is based on an existing subroutine.
+
+Here's a sample usage:
+
+ sub foo {
+ my $count = shift;
+ return 'foo' x $count;
+ }
+
+ Class::MakeMethods::Composite::Universal->make(
+ -ForceInstall => 1,
+ patch => {
+ name => 'foo',
+ pre_rules => [
+ sub {
+ my $method = pop @_;
+ if ( ! scalar @_ ) {
+ @{ $method->{args} } = ( 2 );
+ }
+ },
+ sub {
+ my $method = pop @_;
+ my $count = shift;
+ if ( $count > 99 ) {
+ Carp::confess "Won't foo '$count' -- that's too many!"
+ }
+ },
+ ],
+ post_rules => [
+ sub {
+ my $method = pop @_;
+ if ( ref $method->{result} eq 'SCALAR' ) {
+ ${ $method->{result} } =~ s/oof/oozle-f/g;
+ } elsif ( ref $method->{result} eq 'ARRAY' ) {
+ map { s/oof/oozle-f/g } @{ $method->{result} };
+ }
+ }
+ ],
+ },
+ );
+
+=cut
+
+use vars qw( %PatchFragments );
+
+sub patch {
+ (shift)->_build_composite( \%PatchFragments, @_ );
+}
+
+%PatchFragments = (
+ '' => [
+ '+init' => sub {
+ my $method = pop @_;
+ my $origin = ( $Class::MethodMaker::CONTEXT{TargetClass} || '' ) .
+ '::' . $method->{name};
+ no strict 'refs';
+ $method->{patch_original} = *{ $origin }{CODE}
+ or croak "No subroutine $origin() to patch";
+ },
+ 'do' => sub {
+ my $method = pop @_;
+ my $sub = $method->{patch_original};
+ &$sub( @_ );
+ },
+ ],
+);
+
+=head2 make_patch
+
+A convenient wrapper for C<make()> and the C<patch> method generator.
+
+Provides the '-ForceInstall' flag, which is required to ensure that the patched subroutine replaces the original.
+
+For example, one could add logging to an existing method as follows:
+
+ Class::MakeMethods::Composite::Universal->make_patch(
+ -TargetClass => 'SomeClass::OverYonder',
+ name => 'foo',
+ pre_rules => [
+ sub {
+ my $method = pop;
+ warn "Arguments for foo:", @_
+ }
+ ]
+ post_rules => [
+ sub {
+ warn "Result of foo:", Class::MakeMethods::Composite->CurrentResults
+ }
+ ]
+ );
+
+=cut
+
+sub make_patch {
+ (shift)->make( -ForceInstall => 1, patch => { @_ } );
+}
+
+
+########################################################################
+
+=head1 SEE ALSO
+
+See L<Class::MakeMethods> for general information about this distribution.
+
+See L<Class::MakeMethods::Composite> for more about this family of subclasses.
+
+=cut
+
+1;