Happy Newton's Birthday, monks!
I have decided to give myself the winter solstice present of picking up Lua, with an intent to use it as a quick embedded scripting language (somewhat silly from Perl, I know, but I plan to also use the same Lua code elsewhere). In doing so, I have run into a situation with namespaces that I think may actually require string eval for the first time in >8 years of Perl, which causes my codesmell sensors to go haywire, and thus, I am seeking your sage advice.
Essentially, I want to write a wrapper module around Inline::Lua which will facilitate config information (paths, file loading, etc) and provide a simple OO interface of ->load( 'module' ) and ->run( 'module', 'sub', @args ) However, for future-proofing, it is desirable to load each Lua module's symbols into their own namespace (package), indexed by Lua module name, so that collisions between symbols don't take place when loading multiple Lua modules.
I have been unable to get a handle to it from the ->run() method. Thus, is there also a way to avoid this, and get rid of the second string eval?local *func = $main::{"Lua::${modname}::${funcname}"}
Replacing one or both with a block eval would be ideal. While the code below does "work" (I'll be adding further error checking, of course), it still causes me no small consternation in thinking that there is a better way to do it.
Thus, I throw myself upon the mercy of the monks during this fine Kwanzaa season. Thank you ever so much.
(NB: Inline::Lua may be difficult to install properly; but it should not be necessary to install to simply examine the code.)
----------- Lua.pm ---------------
package Lua; use strict; use warnings; use Carp qw( croak ); #use Inline; my $luadir = '.'; sub new { my( $class ) = @_; my $self = {}; return( bless( $self, $class ) ); } sub load { my( $self, $module ) = @_; my $src_file = $module . '.lua' unless( $module =~ m/.*\.lua$/ ); my $path = path_join( $luadir, $src_file ); open( my $fd, '<', $path ) or warn "$src_file is inaccessible" and return; my $luacode = do { local $/; <$fd> }; close( $fd ); ####################################################### my $code = sprintf( 'package Lua::%s;' . 'use Inline;' . 'Inline->bind( Lua => $luacode );' . 'return( grep { ! /^BEGIN$/ } keys %%Lua::%s:: + )', $module, $module ); my @symbols = eval $code; package Lua; chomp $@ if( $@ ); warn "Error compiling $path: '$@'" and return if( $@ ); ####################################################### return( @symbols ); } sub run { my( $self, $module, $funcname, @args ) = @_; ###################################################### my $sub = sprintf( 'Lua::%s::%s( @args );', $module, $funcname ); my @retval = eval $sub; chomp $@ if( $@ ); warn "Error executing $module::$funcname: $@" and return if( $@ ); ###################################################### return( @retval ); } sub path_join { my $pathchar = ( $^O eq 'MSWin32' ) ? "\\" : '/'; return( join( $pathchar, @_ ) ); } 1; __END__
-------- lua.pl --------
#!/usr/bin/perl use strict; use warnings; use lib '.'; use Lua; my $lua = Lua->new(); my @symbols = $lua->load( 'foo' ); $lua->run( 'foo', 'Greet', 'grandma', 'pie' ); __END__
----------- foo.lua -------------
function Greet( name, treat ) print( "Hello, " .. name .. ". Would you like some " .. treat .. +"?\n" ) end
In reply to Inline::* and string eval -- Have I found a place where it might actually be necessary? by Luftkissenboot
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |