Re: Can I add methods to an existing object?
by ikegami (Patriarch) on Apr 02, 2009 at 20:10 UTC
|
| [reply] |
Re: Can I add methods to an existing object?
by Fletch (Bishop) on Apr 02, 2009 at 20:44 UTC
|
use strict;
package Foo;
sub new { my( $c, $v ) = @_; return bless { val => $v }, $c; }
sub wubble { print "Wubble: ", shift()->{'val'}, "\n"; };
package main;
my $f = Foo->new( "abc" );
$f->wubble;
eval { $f->flop; };
if( $@ ) {
print "Problem: $@\n";
}
eval q{sub Foo::flop { print "Flop: ", scalar reverse( shift()->{'val'
+} ), "\n"; }};
eval { $f->flop; };
if( $@ ) {
print "Problem: $@\n";
}
exit 0;
__END__
Wubble: abc
Problem: Can't locate object method "flop" via package "Foo" at /tmp/s
+quonk line 15.
Flop: cba
(Of course if you're serious then Moose and Class::MOP would be less hacky ways to do it.)
The cake is a lie.
The cake is a lie.
The cake is a lie.
| [reply] [d/l] |
Re: Can I add methods to an existing object?
by morgon (Priest) on Apr 02, 2009 at 21:04 UTC
|
If you can accept that the method is added to the class (and not just to this one instance in the way you can have singleton-methods e.g. in Ruby) this is very simple as methods are just symbol-table entries just like any other sub.
Here an example that adds a new "bubba" method to a "Hubba"-class after an instance already has been created:
use strict;
package Hubba;
sub new {
my($pck)=@_;
bless {}, $pck;
}
# no bubba-method defined here
package main;
# create new instance
my $h = new Hubba;
# add entry to symbol-table
*Hubba::bubba = sub { print "bubba" };
# call new method via old instance
$h->bubba;
| [reply] |
|
You can also declare that as:
sub Hubba::bubba { print "bubba" }
which looks more intuitive to me. BTW, is the "Bubba" capitalized in the name of the bubble gum brand?
| [reply] [d/l] |
|
This is not quite the same thing.
Your approach declares the bubba-method at compile-time, my example at run-time.
You could not use your approach e.g. in a context where the name of the method to be added in not known at compile-time (e.g. is entered by the user).
And "hubba" and "bubba" are my just my personal preference for generic names that I use where others may use "foo" and "bar" that others prefer - I can't remember where I got that from initially but it has nothing to do with bubble gum :-)
| [reply] |
|
Re: Can I add methods to an existing object?
by roubi (Hermit) on Apr 02, 2009 at 20:33 UTC
|
What type of restrictions are you dealing with here? There are various ways to accomplish this, but your post seems to imply that the simplest one (adding the methods to the file describing your object's class) is off-limit. A little more background would help narrow down the amount of hackery required in your case. | [reply] |
|
Right, sorry..
I'm doing some Cat stuff and using Authen::Simple for authentication. My Cat instance has a Log::Dispatch logger which has methods like 'error','warning','debug' etc... Authen::Simple objects can take a logging object too, but it has to provide 'debug','info','warn' and 'error'. Log::Dispatch provides 'warning' but not 'warn'. To work around this, I made my own class which I called Log::Dispatch::Warn, which is a subclass of Log::Dispatch with a 'warn' sub which just calls 'warning'.
It seems kind of silly to create a whole module just to make an object call $self->warning(@_) if someone calls $object->warn($blah).
| [reply] [d/l] [select] |
|
First, I thought of something like this:
*Log::Dispatch::warn = *Log::Dispatch::warning;
But I thought, that it doesn't look nice ;) so I changed it to:
*Log::Dispatch::warn = \&Log::Dispatch::warning;
But both threw warnings that Log::Dispatch::warn is "used only once: possible typo..."; And then, based upon the answers from morgon and mr_mischief I thought of
sub Log::Dispatch::warn {
my $self = shift;
$self->warning(@_);
}
tested with:
#!/usr/bin/perl -l
use strict;
use warnings;
package foo;
sub new {
bless {}, shift();
}
sub foo {
my $self = shift;
print "hello @_";
}
package main;
sub foo::bar {
my ( $self ) = shift;
$self->foo(@_);
}
*foo::baz = \&foo::foo;
*foo::buzz = *foo::foo;
my $o = foo->new();
$o->bar('world');
$o->baz('world');
$o->buzz('world');
__END__
| [reply] [d/l] [select] |
|
|
|
|
It'd be interesting to hear from autarch himself why 'warn' wasn't added to the list of valid methods of Log::Dispatch when various other abbreviations like 'err' and 'crit' and 'emer' have been. Maybe he is just waiting to hear from someone like you? :)
| [reply] |