How to create a coderef from an object-method?

  • Thread starter Bruno Boettcher
  • Start date
B

Bruno Boettcher

Hello!

i am having trouble writing a script for xchat...

that thing has a method to add new commands or handlers, and that method
uses coderefs....

now i have created an object with several methods, and i have a table
with the commands to add to the client, and now i am trying to find the
syntax to do this....


here you can see the different tries i made so far:

foreach my $cmd (keys(%$commands))
{
#my $funcref = \&{$this->{"leve"}->($commands->{$cmd})};
#my $funcref = \&Leve::($commands->{$cmd});
#my $funcref = eval("\&{".$this->{"leve"}."->".$commands->{$cmd}."}");
#my $funcref = eval("\&{Leve::".$commands->{$cmd}."}");
my $funcref = eval("sub { ".$this->{"leve"}."->".$commands->{$cmd}."(@_);}");
Xchat::hook_command("l".$cmd, $funcref);
Xchat::print("added command handler l".$cmd." calling back on $funcref");
}#foreach my $cmd (keys(%$commands))

the version with the anon sub would be the most interesting, since that
would preserve the OO design, passing the reference of the object along
the call....

but this dooesn't seem to work... the $funcref is empty in this last
case, and none of them work....

problem is that all the cases depicted in the docu are very simple
structures.... nothing composite is ever used as an example... so i am
quite clueless here....

what would be the best way to achieve this?

thanks for any help
 
S

Samwyse

Bruno said:
Hello!

i am having trouble writing a script for xchat...

that thing has a method to add new commands or handlers, and that method
uses coderefs....

now i have created an object with several methods, and i have a table
with the commands to add to the client, and now i am trying to find the
syntax to do this....


here you can see the different tries i made so far:

foreach my $cmd (keys(%$commands))
{
#my $funcref = \&{$this->{"leve"}->($commands->{$cmd})};
#my $funcref = \&Leve::($commands->{$cmd});
#my $funcref = eval("\&{".$this->{"leve"}."->".$commands->{$cmd}."}");
#my $funcref = eval("\&{Leve::".$commands->{$cmd}."}");
my $funcref = eval("sub { ".$this->{"leve"}."->".$commands->{$cmd}."(@_);}");
Xchat::hook_command("l".$cmd, $funcref);
Xchat::print("added command handler l".$cmd." calling back on $funcref");
}#foreach my $cmd (keys(%$commands))

What's wrong with this:
my $funcref = $this->{"leve"}->($commands->{$cmd});

Have you tried using Data::Dumper to look at your structures?
Looking at your code, $this refers to a hash whose values are coderefs,
each of which takes a scalar and returns something, I presume a coderef.
print Dumper($this);
print Dumper($commands);
 
B

Bruno Boettcher

hi again

ok, seems i haven't given enough code...

to complete:

Leve.pm:
package Leve;
our(%commands);


sub new
{
my ($class) = @_;
my $this = {
"commands" => \%commands,
#lots of other class vars#
};

bless ($this, $class);
return $this;
}# sub new

sub print { ... ; }
$commands{"print"} = "print";
sub leve_list { ... ; }
$commands{"list"} = "leve_list";
sub leve_clear { ... ;}
$commands{"clear"} = "leve_clear";
etc...

then in xchat2Handler:
$this->{"leve"} = new Leve();
$commands = $this->{"leve"}->{"commands"};
foreach my $cmd (keys(%$commands))
{
my $funcref = eval("sub { ".$this->{"leve"}."->".$commands->{$cmd}."(@_);}");
#eg for list:
#my $funcref = eval("sub { ".$this->{"leve"}."->leve_list(@_);}");
#resulting in a reference to the method: Leve::leve_list($this,@_);
Xchat::hook_command("l".$cmd, $funcref);
Xchat::print("added command handler l".$cmd." calling back on $funcref");
}#foreach my $cmd (keys(%$commands))

so i don't think i can access the method coderefs as if they were hash
values....


thanks for your help!
 
S

Samwyse

Bruno said:
ok, seems i haven't given enough code...

to complete:

Leve.pm:
package Leve;
our(%commands);

sub new
{
my ($class) = @_;
my $this = {
"commands" => \%commands,
#lots of other class vars#
};

bless ($this, $class);
return $this;
}# sub new

sub print { ... ; }
$commands{"print"} = "print";

$commands{"print"} = \&print;
sub leve_list { ... ; }
$commands{"list"} = "leve_list";

$commands{"list"} = \&leve_list;
sub leve_clear { ... ;}
$commands{"clear"} = "leve_clear";

$commands{"clear"} = \&leve_clear;

Or you can do all the work at compile time via anonymous subroutines.
Note that => will magically quote the word in front of it, so you don't
need to type them all yourself.

package Leve;
use strict;
sub new {
my $class = shift;
my $this = {
commands => {
print => sub { ... ; },
leve_list => sub { ... ; },
leve_clear => sub { ... ; },
},
};
bless $this, $class;
return $this;
}

then in xchat2Handler:
$this->{"leve"} = new Leve();
$commands = $this->{"leve"}->{"commands"};

my $funcref = $this->{"leve"}->{"commands"}->{$cmd};
#eg for list:
#my $funcref = eval("sub { ".$this->{"leve"}."->leve_list(@_);}");
#resulting in a reference to the method: Leve::leve_list($this,@_);


so i don't think i can access the method coderefs as if they were hash
values....

Sure you can, if you do it right. Did you try using Data::Dumper, as I
suggested? It will go a long way towards helping debug complex data
structures.
 
B

Brian McCauley

Bruno said:
my $funcref = eval("sub { ".$this->{"leve"}."->".$commands->{$cmd}."(@_);}");
the $funcref is empty

By 'empty' I assume you really mean undef.

I suggest you print out the string you are about to eval() and also
the error you get when the eval() fails.

my $funcstr = "sub {
".$this->{"leve"}."->".$commands->{$cmd}."(@_);}";
print "$funcstr\n";
my $funcref = eval($funcstr);
print "$@\n";

Then slap yourself on the forehead, say "D'oh" and fix the quotes.
 
B

Bruno Boettcher

Bruno Boettcher wrote:
$commands{"print"} = \&print;
hmmm indeed...
Or you can do all the work at compile time via anonymous subroutines.
Note that => will magically quote the word in front of it, so you don't
need to type them all yourself.
yep but that would rendre the code not really readable, and would
confuse ctags...
Sure you can, if you do it right. Did you try using Data::Dumper, as I
suggested? It will go a long way towards helping debug complex data
structures.
i always use Data::Dumper :D
 
R

Robert Sedlacek

Bruno Boettcher said:
now i have created an object with several methods, and i have a table
with the commands to add to the client, and now i am trying to find the
syntax to do this....

Man, I *really* need to integrate perltidy into tin. Anyway, assuming
this:

my $leve = $this->{ leve }; # the object
my $cmd = $this->{ cmd }; # the method?
my @args = qw/ foo bar /; # arguments, I don't know where they are
# coming from in your code

How about this solution:

my $coderef = sub { $leve->$cmd( @args ) };

? That's untested code, tho, but how I would go for it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top