| Inline-Wrapper documentation | Contained in the Inline-Wrapper distribution. |
Inline::Wrapper - Convenient module wrapper/loader routines for Inline.pm
sample.pl:
use Inline::Wrapper;
my $inline = Inline::Wrapper->new(
language => 'C',
base_dir => '.',
);
my @symbols = $inline->load( 'answer' );
my @retvals = $inline->run( 'answer', 'the_answer', 3, 56 );
print "The answer is: ", $retvals[0], "\n";
exit(0);
answer.c:
int the_answer( int arg1, int arg2 ) {
return ( arg1 * arg2 ) >> 2;
}
Inline::Wrapper provides wrapper routines around Inline to make embedding functions from another language into a Perl application much more convenient.
Instead of having to include the external code in a Perl source file after the __END__ directive, Inline::Wrapper allows you to have separate, individually-configurable module repositories to more easily manage all of your external application code.
Inline::Wrapper provides the following features:
my $wrapper = Inline::Wrapper->new(
language => 'C',
base_dir => 'src/code/C',
auto_reload => 1,
);
Create a new Inline::Wrapper object, with the appropriate attributes (if specified).
ARGUMENTS:
All arguments are of the hash form Var => Value. new() will complain and croak if they do not follow this form.
The arguments to new() become the defaults used by load(). You can individually configure loaded modules using load(), as well.
Optional. Set to the default language for which you wish to load modules, if not explicitly specified via load().
NOTE: It defaults to Lua because that is what I wrote this module for. Just pass in the argument if you don't like that.
ALSO NOTE: Currently only a couple of "known" languages are hard-coded into this module. If you wish to use others, don't pass this argument, and use the add_language() method after the object has been instantiated.
Optional. Set to a TRUE value to default to automatically checking if modules have been changed since the last load(), and reload them if necessary.
Optional. Set to the default base directory from which you wish to load all modules.
RETURNS: blessed $object, or undef on failure.
$obj->initialize();
Initialize arguments. If you are subclassing, overload this, not new().
Generally only called from within new().
my @functions = $obj->load( $modname, %arguments );
The workhorse. Loads the actual module referred to by $modname, imports its symbols into a private namespace, and makes them available to call via run().
ARGUMENTS:
$modname is REQUIRED. It corresponds to the base filename, without extension, loaded from the base_dir. See the Details of steps taken by load() section, Step 3, for clarification of how pathname resolution is done. $modname is also how you will refer to this particular module from your program, so keep track of it.
This method accepts all of the same arguments as new(). Thus, you can set the defaults via new(), yet still individually configure module components differently from the defaults, if desired.
Returns a list of @functions made available by loading $modname, or warns and returns an empty list if unsuccessful.
Since this is the real guts of this module, here are the exact steps taken when loading the module, doing pathname resolution, etc.
join( $PATH_SEP, $base_dir , $modname . $lang_ext );
$obj->unload( $modname );
Completely unload the module identified by $modname, and render its functions uncallable.
This will actually go destroy the Inline::Wrapper::Module object, as well as the code module's corresponding private namespace.
Returns $modname (TRUE) upon success, carps and returns undef on failure.
my @retvals = $obj->run( $modname, $function, @arguments );
Run the named $function that you loaded from $modname, with the specified @arguments (if any).
NOTE: If the auto_reload option is TRUE, run() will also attempt to reload the source script from disk before running the function, if the ctime of the file has changed since the last run.
Assuming a successful compilation (you are checking for errors, right?), this will execute the function provided by the loaded module. Call syntax and everything is up to the function provided. This simply executes the sub that Inline loaded as-is, but in its own private namespace to keep your app clean.
Returns @retvals, consisting of the actual return values provided by the module function itself. Whatever the function returns, that's what you get.
my @modules = $obj->modules();
Returns a list of loaded module names, or the empty list if no modules have been (successfully) loaded.
my @functions = $obj->functions( $modname );
Returns a list of loaded @functions, which were made available by loading $modname.
Various accessors that allow you to inspect or change the default settings after creating the object.
my $base_dir = $obj->base_dir();
Returns the default base_dir attribute from the object.
$obj->set_base_dir( '/some/path' );
Sets the default base_dir attribute of the object, and returns whatever it ended up being set to.
NOTE: Only affects modules loaded after this setting was made.
my $bool = $obj->auto_reload();
Returns a $boolean as to whether or not the default auto_reload setting is enabled for new modules.
$obj->set_auto_reload( 1 );
Sets the default auto_reload attribute of the object, and returns whatever it ended up being set to.
NOTE: Only affects modules loaded after this setting was made.
my $lang = $obj->language();
Returns the default language attribute of the object.
$obj->set_language( 'C' );
Sets the default language attribute of the object, and returns whatever it ended up being set to.
NOTE: Only affects modules loaded after this setting was made.
ALSO NOTE: This checks for "valid" languages via a pretty naive method. Currently only a couple are hard-coded. However, you can add your own languages via the add_language() method.
$obj->add_language( 'Lojban' => '.xkcd' );
Adds a language to the "known languages" table, allowing you to later use set_language().
This can also be used to set a new file extension for an existing language.
REQUIRES a $language name (e.g. 'Python') and a filename $extension (e.g. '.py'), which will be used in pathname resolution, as described under load().
Returns TRUE if successful, carps and returns FALSE otherwise.
The Inline documentation.
The Inline-FAQ list.
The examples/ directory of this module's distribution.
Thank you, kennethk and ikegami for your assistance on perlmonks.
Please kindly read through this documentation and the examples/ thoroughly, before emailing me with questions. Your answer is likely in here.
Also, please make sure that your issue is actually with Inline::Wrapper and not with Inline itself.
Jason McManus (INFIDEL) -- infidel AT cpan.org
Copyright (c) Jason McManus
This module may be used, modified, and distributed under the same terms as Perl itself. Please see the license that came with your Perl distribution for details.
| Inline-Wrapper documentation | Contained in the Inline-Wrapper distribution. |
package Inline::Wrapper; # # Inline::* module dynamic loader and useful wrapper routines # # $Id: Wrapper.pm 14 2010-03-10 09:08:18Z infidel $ # # POD documentation after __END__ # use strict; use warnings; use Carp qw( carp croak ); use Data::Dumper; use vars qw( $TRUE $FALSE $VERSION ); BEGIN { $INC{'Inline::Wrapper.pm'} ||= __FILE__ }; # recursive use check use Inline::Wrapper::Module; # individual code modules ### ### VARS ### $VERSION = '0.05'; *TRUE = \1; *FALSE = \0; my $DEFAULTS = { base_dir => '.', # default search directory auto_reload => $FALSE, # automatically reload module? language => 'Lua', # default language }; my $LANGS = { Foo => '.foo', # built in to Inline's distro C => '.c', Lua => '.lua', # 'C++' => '.cpp', # Java => '.java', # Python => '.py', # Tcl => '.tcl', # Ruby => '.rb', }; my $PARAMS = { base_dir => sub { $_[0] }, auto_reload => sub { $_[0] ? $TRUE : $FALSE }, language => sub { defined( $_[0] ) and exists( $LANGS->{$_[0]} ) ? $_[0] : ( carp sprintf( "Invalid language: %s; using %s", $_[0], $DEFAULTS->{language} ) and $DEFAULTS->{language} ) }, }; ### ### CONSTRUCTOR ### sub new { my( $class, @args ) = @_; # Check parameters @args = %{ $args[0] } if( ref( $args[0] ) eq 'HASH' ); croak "$class: \%args must be a hash; read the docs" if( @args & 1 ); # Set up object my $self = { %$DEFAULTS, # modules => {}, }; bless( $self, $class ); # Initialize object instance @args = $self->_process_args( @args ); $self->initialize( @args ); return( $self ); } sub initialize { my( $self ) = @_; $self->{modules} = {}; return; } ### ### PUBLIC METHODS ### # Load a code module named $modname from $base_dir with $lang_extension sub load { my( $self, $modname, @args ) = @_; # Check arguments croak "load() \$modname is a required param; read the docs" unless( $modname ); @args = %{ $args[0] } if( ref( $args[0] ) eq 'HASH' ); croak "load(): \%args must be a hash; read the docs" if( @args & 1 ); my %args = @args; # Check for duplicate modules, return @function list if found # XXX: Possible bug; should probably issue reload if auto_reload # ends up being set to true. if( my $temp_module = $self->_module( $modname ) ) { my $temp_lang = $args{language} || $self->language(); my $temp_base_dir = $args{base_dir} || $self->base_dir(); if( $temp_lang eq $temp_module->language() && $temp_base_dir eq $temp_module->base_dir() ) { $temp_module->set_auto_reload( $args{auto_reload} ) if( $args{auto_reload} ); print "HONK!\n"; return( $temp_module->_function_list() ); # RETURN } } # Create a new module object my $module = Inline::Wrapper::Module->new( module_name => $modname, lang_ext => $self->_lang_ext(), $self->_settings(), %args, ); $self->_add_module( $modname, $module ); # Actually attempt to load the inline module my @functions = $module->_load(); return( @functions ); } # Completely unload a loaded $modname, rendering its functions uncallable sub unload { my( $self, $modname ) = @_; carp "$modname not loaded" and return unless( ref( $self->_module( $modname ) ) ); return( $self->_del_module( $modname ) && $modname ); } # Run a $modname::$funcname function, passing it @args sub run { my( $self, $modname, $funcname, @args ) = @_; my $module = $self->_module( $modname ); my @retvals = $module->_run( $funcname, @args ); return( @retvals ); } # Return the list of already-loaded modules sub modules { my( $self ) = @_; return( $self->_module_names() ); } # Return the list of functions loaded from $modname sub functions { my( $self, $modname ) = @_; my $module = $self->_module( $modname ); carp "Module '$modname' not loaded" and return() unless( ref( $module ) ); return( $module->_function_list() ); } ### ### PRIVATE METHODS ### sub _process_args { my( $self, @args ) = @_; croak "_process_args() requires an even number of params" if( @args & 1 ); my %args = @args; for( keys %args ) { next unless( exists( $PARAMS->{lc $_} ) ); # not for us, pass on $self->{lc $_} = $PARAMS->{lc $_}->( $args{$_} ); delete( $args{$_} ); } return( %args ); } sub _module_names { my( $self ) = @_; return( keys( %{ $self->{modules} } ) ); } sub _settings { my( $self ) = @_; my %defaults = map { $_ => $self->{$_} } keys( %$DEFAULTS ); return( %defaults ); } ### ### ACCESSORS ### sub base_dir { my( $self ) = @_; return( $self->{base_dir} ); } sub set_base_dir { my( $self, $base_dir ) = @_; # Validate $base_dir = $PARAMS->{base_dir}->( $base_dir ); return( defined( $base_dir ) ? $self->{base_dir} = $base_dir : $self->{base_dir} ); } sub language { my( $self ) = @_; return( $self->{language} ); } sub set_language { my( $self, $language ) = @_; # Validate $language = $PARAMS->{language}->( $language ); return( defined( $language ) ? $self->{language} = $language : $self->{language} ); } sub add_language { my( $self, $language, $lang_ext ) = @_; carp "add_language(): Language not set; read the docs" and return unless( $language ); carp "add_language(): Language extension not set; read the docs" and return unless( $lang_ext ); return( ( $LANGS->{$language} = $lang_ext ) ? $language : undef ); } sub auto_reload { my( $self ) = @_; return( $self->{auto_reload} ); } sub set_auto_reload { my( $self, $auto_reload ) = @_; # Validate $auto_reload = $PARAMS->{auto_reload}->( $auto_reload ); return( defined( $auto_reload ) ? $self->{auto_reload} = $auto_reload : $self->{auto_reload} ); } ### PRIVATE ACCESSORS sub _module { my( $self, $modname ) = @_; return( $self->{modules}->{$modname} ); } sub _add_module { my( $self, $modname, $module ) = @_; return( $self->{modules}->{$modname} = $module ); } sub _del_module { my( $self, $modname ) = @_; # Namespace is deleted by $module->DESTROY() return( delete( $self->{modules}->{$modname} ) ); } ### ### PRIVATE UTILITY ROUTINES ### sub _lang_ext { my( $self, $language ) = @_; $language ||= $self->{language}; return( $LANGS->{$language} ); } 1; __END__
### Thank you, drive through. ###