User Control Panel
Advertisements

HELP US, HELP YOU!

Create Subroutine Source from Scalar?

 
Post new topic   Reply to topic    Bot Depot Forum Index -> Perl
View unanswered posts
Author Message
Cer
Upgraded Agent
Upgraded Agent


Joined: 03 Feb 2004
Posts: 3776
Location: Michigan
Reputation: 146.9
votes: 4

PostPosted: Wed Jan 04, 2006 9:17 pm    Post subject: Create Subroutine Source from Scalar? Reply with quote

What I'm trying to do is create an anonymous subroutine (coderef) using a scalar that contains the code for the subroutine to contain.

The purpose for doing this is for RiveScript to be able to define its objects directly within its own files, such as:

Code:
> object fortune
   my ($method,$msg) = @_;

   my @fortunes = (
      'You will be rich and famous',
      'You will become a movie star',
      'You will go to the moon',
   );

   return $fortunes [ int(rand(scalar(@fortunes))) ];
< object

+ give me a fortune cookie
- Your fortune cookie: &fortune()


And that would, of course, be the equivalent to the now-system of having a Perl subroutine and calling a method to the module to associate an object with that routine.

However I can't seem to figure out how to take a scalar that contains Perl code as its value, and make a subroutine with its data as its code.

Here was a simplified test I was doing:

Code:
#!/usr/bin/perl -w

use strict;
use warnings;

my $subroutine = '
   my ($method,$data) = @_;

   return "Method = $method; Data = $data";
';

print "My Subroutine's Source Code:\n"
   . $subroutine . "\n\n"
   . "===========================\n\n";

print "Creating a coderef...\n";
my $refs = {};
$refs->{code} = sub {
   $subroutine
};

print "Coderef Value: $refs->{code}\n\n";

print "Calling subroutine...\n\n";

my $out = &{$refs->{code}} ("myMethod", "someData");

print "Done. Out = $out\n";


And its output was this:
Quote:
D:\Perl\tests\Optional Regexp>perl subs.pl
My Subroutine's Source Code:

my ($method,$data) = @_;

return "Method = $method; Data = $data";


===========================

Creating a coderef...
Coderef Value: CODE(0x234fe0)

Calling subroutine...

Done. Out =
my ($method,$data) = @_;

return "Method = $method; Data = $data";


The coderef value test worked and gave me a coderef but what the subroutine should have returned was the values of $method and $data, rather than the entire subroutine's code.

Does anybody know how to do this?

edit
One thing that worked as a solution to my very simply test,
Code:
$refs->{code} = sub {
   return eval $subroutine;
};

Did not work in RiveScript. I might be on the right track though. I've tried do and return do also, which both failed.

edit(2)
I also tried evaling the entire thing (setting the coderef and all)...
Code:
my $val = eval "
  $self->{macros}->{'$objName'} = sub {
    $objCode
  };
  $self->{macros}->{'rive'} = sub {
    return 'Rive macro success';
  };
  1;
";
print "Eval: $val\n";

The eval returns undef like it should when it's successful but neither the code-defined object or the 'rive' object were defined at all.

_________________
Current Site (2008) http://www.cuvou.com/
Back to top
Mojave
Almost An Agent
Almost An Agent


Joined: 01 Nov 2003
Posts: 1434

Reputation: 66.4

PostPosted: Thu Jan 05, 2006 12:46 am    Post subject: Reply with quote

If you can name your sub, then this might help you:

Code:
my $eval_string = 'sub hello { print "hello\n"; }';

eval $eval_string;

&hello;


If you have to use a coderef, then this might help (although I couldn't make $sub a my value):

Code:
my $eval_string = '$sub = sub { print "hello\n"; }';

eval $eval_string;

&$sub;


I left out the part where you take your sub contents from a text file and add them to $eval_string, since I figured you know all about that. If not, I could rework this to be more complete.

Hope that's what you're looking for.
Back to top
Cer
Upgraded Agent
Upgraded Agent


Joined: 03 Feb 2004
Posts: 3776
Location: Michigan
Reputation: 146.9
votes: 4

PostPosted: Thu Jan 05, 2006 4:20 am    Post subject: Reply with quote

Thanks. One solution I figured out that *kinda* works was to use eval to create a new subroutine with its contents, then call the $self->setSubroutine method to associate the subroutine with its object. So basically it took the Perl code from the reply file and did with it the exact same thing you'd do before I got the bright idea to do this.

The only problem was that some objects wouldn't work. Like my weather, Google, and botmaster command objects wouldn't be created this way. It might be something to do with the variables they used but I'm not sure.

_________________
Current Site (2008) http://www.cuvou.com/
Back to top
mattaustin
Sentinel
Sentinel


Joined: 19 Jul 2004
Posts: 556
Location: Los Angeles, CA
Reputation: 50.7
votes: 1

PostPosted: Thu Jan 05, 2006 7:33 am    Post subject: Reply with quote

what about something like this (or am i not understanding what your looking for):

Code:
$var = 'print "test";';
$refs->{code} = sub{eval $var};
&{$refs->{code}};
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Bot Depot Forum Index -> Perl All times are GMT
Page 1 of 1

 



Protected by phpBB Security phpBB-TweakS
phpBB Security Has Blocked 9 Exploit Attempts.
Antispam Captcha Mod by phpbb-security.com
Powered by phpBB © 2001, 2005 phpBB Group