NAME
Inline::Ruby - Write Perl subroutines and classes in Ruby.
SYNOPSIS
print "9 + 16 = ", add(9, 16), "\n";
print "9 - 16 = ", subtract(9, 16), "\n";
use Inline Ruby;
__END__
__Ruby__
def add(a, b)
a + b
end
def subtract(a, b)
a - b
end
DESCRIPTION
The Inline::Ruby
module allows you to put Ruby source code directly "inline" in a Perl script or module. It sets up an in-process Ruby interpreter, runs your code, and then examines Ruby's symbol table, looking for things to bind to Perl.
The process of interrogating the Ruby interpreter only occurs the first time you run your Ruby code. The namespace is cached, and subsequent calls use the cached version. Of course, your Ruby code must still be run every time your run the Perl script -- but Inline::Ruby already knows the results of running it.
Using the Inline::Ruby Module
Using Inline::Ruby will seem very similar to using any other Inline language, thanks to Inline's consistent look and feel.
This section will explain the different ways to use Inline::Ruby. For more details on Inline
, see 'perldoc Inline'.
Importing Functions
Using functions defined in Ruby is just like using Perl subs. You just supply the source code to Inline::Ruby, and then use them.
use Inline Ruby => <<'END';
def doit
...
end
END
doit();
Importing Classes
If you're written a library in Ruby, it's probably object-oriented. Binding Ruby classes to Perl is as easy as telling Ruby to import the class library.
use Inline Ruby;
my $obj = SomeClass->new;
__END__
__Ruby__
# Pretend SomeClass is defined in an external library
require 'SomeClass'
Ruby Configuration Options
For information on how to specify Inline configuration options, see Inline. This section describes each of the configuration options available for Ruby.
BIND_TYPE or BIND_TYPES
Normally, Inline::Ruby binds classes, modules, and functions into Perl. That can be really big namespace polluter, so you can tell Inline::Ruby to ignore functions, for example:
use Inline Ruby => DATA => BIND_TYPES => [undef, qw(classes modules)];
ITER
When Inline::Ruby binds a Ruby class, module, or function into a Perl package, it also binds a function named iter
to the package. iter
is used to set up an iterator block when calling Ruby methods.
It's conceivable that the word iter
will conflict with an actual function in the class -- if that happens, you can override the name of the iter
function using this configuration option.
use Inline Ruby => DATA => ITER => 'my_iter';
FILTERS
Like several other Inline languages, Inline::Ruby allows you to preprocess your Inline::Ruby code with a custom filter:
use Inline Ruby => DATA => FILTER => \&my_filter;
Inline::Ruby Features
There are several cool topics worth mentioning specially:
Perl Subs as Iterator Blocks
Perl Subs as Proc Objects
Exceptions
The following few sections describe each topic and give examples.
Perl Subs as Iterator Blocks
Ruby has very primitive looping support -- all the libraries and builtins use iterators, which provide the same functionality with more power.
Here's an example of iterating over the elements of an Array in Ruby:
array = [1, 2, 3]
array.each { |x|
print "array.each printing array element: #{x}\n"
}
Here's an example writing a function which calls an iterator:
def call_iter
yield "hello, iterator!"
end
Ruby's yield
keyword invokes the block passed the the function. There can only be one block passed to each function. A function can invoke the block several times, though. Like Perl's anonymous subroutines, Ruby's blocks are closures: they remember the context in which they were defined, so they have access to local variables defined at that point.
Inline::Ruby allows you to pass a Perl subroutine reference as an iterator block. That means whenever yield
is called, the Perl subroutine will be called with the arguments to yield
.
Here's an example:
use Inline Ruby;
sub block { print "Ruby says: @_\n" }
no_iter();
iter(\&block)->call_iter;
__END__
__Ruby__
def no_iter
print "no block\n"
end
def call_iter
yield "hello, block!"
end
As you can see, calling a global function with an iterator is slightly more complicated than just calling a regular function. Why not just pass the subroutine in the parameter list? Because that would actually pass it as a Proc object, which is also supported in Ruby (see "Perl Subs as Proc Objects").
That was functions. What about methods?
use Inline Ruby;
$obj = Iterator->new(1, "2", [3, 4], {5 => 6});
$obj->iter(\&my_iter)->each;
sub iter {
use Data::Dumper;
print Dumper \@_;
}
__END__
__Ruby__
class Iterator
def initialize(*elements)
@elements = elements
end
def each
for i in @elements
yield i
end
end
end
That example showed an instance method being called. Class methods are very similar -- you just call the method on the class, not an instance of it:
Iterator->iter(\&my_iter)->some_class_iterator(@args);
There are six combinations of iterators and function types, all supported by Inline::Ruby:
global_function();
iter(\&my_iter)->global_iterator();
Class->class_method();
Class->iter(\&my_iter)->class_iterator();
$obj->instance_method();
$obj->iter(\&my_iter)->instance_iterator();
Ruby also allows you to prototype a function definition to pass the block in as an argument:
def function(arg1, arg2, arg3, &b)
b.call(arg1, arg2, arg3)
end
function(1, 2, 3) { |x| print "hello #{x}\n" }
Passing a Perl Block to such a function is just like passing a Perl Block to any other function:
iter(\&my_block)->function($arg1, $arg2, $arg3);
Ruby also allows you to pass "real" compiled blocks around. The next section talks about that.
Perl Subs as Proc Objects
Like Perl, Ruby allows variables to contain subroutine references. They're called Proc
s in Ruby, and they're very similar to compiled blocks. You created them by calling Proc.new { }
, which returns an object with a call
method. A Proc is not allowed to call yield
.
Perl subroutines are very similar to Ruby's Proc: they can't call yield
(Perl doesn't have it) and they are closures (which makes them suitable for calling from Ruby).
If you pass a code ref as a parameter to a Ruby function or method, it will be converted to a Proc object, callable from Ruby:
use Inline Ruby;
ine(\&my_iter);
__END__
__Ruby__
def ine(beckand)
beckand.call("I'm at your")
end
Inline::Ruby ships with this sample script:
use Inline Ruby => 'require "tk"';
# Create a button widget that prints 'hello', and pack it.
TkButton->new(undef,{text=>'hello',command=>sub{print"hello\n"}})->pack;
# Create a button widget that exits the process, and pack it.
TkButton->new(undef,{text=>'quit',command=>'exit'})->pack;
# Run Tk's mainloop
Tk->mainloop;
This example pops up a windows with two buttons in it: "hello", and "quit". Clicking "hello" prints "hello\n" to your console, and "quit" does the expected.
Exceptions
Exceptions are an important part of Ruby. Any function can throw an exception at any time. If you don't catch an exception, Ruby will immediately exit the process (even if you're inside Inline::Ruby).
To avoid this rather unpleasant exit, Inline::Ruby always wraps every call to the Ruby interpreter with a rescue
block (Ruby's equivalent of Perl's block eval
). When an exception occurs, Inline::Ruby creates a wrapper exception object and generates a Perl exception.
use Inline Ruby;
print divby0(10);
__END__
__Ruby__
def divby0(n)
n/0
end
This throws a ZeroDivisionError in Ruby. Because it wasn't caught in Ruby, it gets caught by Inline::Ruby's internals, which generate a Perl exception. But Perl didn't trap the error either... so the process exits:
ttul:~/dev/cpan/Inline-Ruby$ perl -Mblib t.pl
Using /home/nwatkiss/dev/cpan/Inline-Ruby/blib
#<ZeroDivisionError: divided by 0>
ttul:~/dev/cpan/Inline-Ruby$
The exception is actually an object, so you can call these methods on it:
type
What type of Exception was it? Returns the class of the Ruby exception ("ZeroDivisionError" in this case).
message
Returns the error message thrown by the code ("divided by 0" in this case).
inspect
Returns this: sprintf("#<%s: %s>", $@->type, $@->message)
backtrace
Prints the backtrace as far as Ruby is concerned. This does not include any Perl calls that may exists between consecutive entries.
If you "stringify" the exception ("$@"), it returns $@->inspect plus a newline.
Perl Exceptions Inside Callbacks
What happens when a callback die
s? This generates a Perl exception which is caught by Inline::Ruby. It throws a new exception to Ruby: PerlException. The description is whatever is contained in "$@"
. The new Ruby exception might be caught inside the Ruby code, or it might percolate back to Inline::Ruby, where it will be wrapped back into $@
and thrown as a Perl Exception again.
use Inline Ruby;
sub callback { die "died!" }
iter(\&callback)->func;
__END__
__Ruby__
def func
yield [1, 2, 3]
end
This example prints the following:
ttul:~/dev/cpan/Inline-Ruby$ perl -Mblib t.pl
Using /home/nwatkiss/dev/cpan/Inline-Ruby/blib
#<PerlException: (in cleanup) died! at t.pl line 3.>
So the Perl exception was wrapped in a Ruby exception (PerlException), and then re-wrapped into an Inline::Ruby::Exception object, which was printed out when Perl exited.
This exception could have been caught in two places:
Catching Perl Exceptions in Ruby
Here's an example of catching a Perl exception from Ruby:
use Inline Ruby; sub callback { die "died!" } iter(\&callback)->func; __END__ __Ruby__ def func begin yield [1, 2, 3] rescue PerlException => e print "Got an exception: " + e + "\n" end end
Resulting in this output:
ttul:~/dev/cpan/Inline-Ruby$ perl -Mblib t.pl Using /home/nwatkiss/dev/cpan/Inline-Ruby/blib Got an exception: (in cleanup) died! at t.pl line 3.
Catching exceptions in Perl
Here's a familiar example of catching exceptions in Perl:
use Inline Ruby; sub callback { die "died!" } eval { iter(\&callback)->func; }; print "Got an exception: $@" if $@; __END__ __Ruby__ def func yield [1, 2, 3] end
Which prints:
ttul:~/dev/cpan/Inline-Ruby$ perl -Mblib t.pl Using /home/nwatkiss/dev/cpan/Inline-Ruby/blib Got an exception: #<PerlException: (in cleanup) died! at t.pl line 3.>
Supported Data Types
Inline::Ruby seamlessly converts between most types of Perl and Ruby data types.
Supported Perl Data Types
The following data types may be passed from Perl into Ruby. Any unrecognized type is replaced with undef
during translation.
Integer
Converted to Ruby "Fixnum" object.
Floating Point
Convert to Ruby "Float" object.
String
Converted to Ruby "String" object.
Array Reference
Converted to Ruby "Array" object (elements recursively converted).
Hash Reference
Converted to Ruby "Hash" object (elements recursively converted).
Code Reference
Converted to Ruby "Proc" object.
Undef (and all others)
Converted to Ruby NilClass object (known as nil).
Supported Ruby Data Types
The following Ruby types map be either returned from a Ruby method or function to Perl, or may be passed as arguments to a Perl callback. Unrecognized types are replaced with nil
and translated to undef
.
Object
Ruby objects are wrapped in instances of the
Inline::Ruby::Object
class. This allows Perl to call methods on the object as usual.Fixnum
Converted to a Perl integer scalar.
Float
Converted to a Perl floating point scalar.
String
Converted to a Perl string.
Array
Converted to a Perl array reference (elements recursively converted).
Hash
Converted to a Perl hash reference (elements recursively converted).
True
Converted to a scalar containing 1.
False, Nil, and anything else
Converted to
undef
.
Low-Level Inline::Ruby
Unlike most other Inline languages, you can use Inline::Ruby
independently of Inline:
use Inline::Ruby qw(rb_eval);
rb_eval('print "hello from Ruby!\n"');
By default, Inline::Ruby doesn't export anything. You can request any or all of the following functions:
rb_eval()
Takes one string argument, a Ruby expression, and returns the result of evaluating it. For example:
$sum = rb_eval("3 + 4");
rb_call_function()
Takes the following arguments:
$func
The name of the Ruby function to call.
@_
Optional arguments to the Ruby function.
For example:
rb_eval <<END; def func(a, b, c) p [a, b, c] end END rb_call_function("func", 1, "2", [3, 4])
rb_call_class_method()
Takes the following arguments:
$class
The class containing the class method.
$method
The name of the method to call.
@_
Optional arguments to the class method.
For example:
print Dumper rb_call_class_method("Class", "methods");
rb_new_object()
Takes the following arguments:
$class
A class into which to bless the Perl object.
$ruby_class
The ruby class to create an instance of.
@_
Optional arguments to the object's constructor.
For example:
rb_eval <<END; class Cls def initialize(a, b) print "Creating new Cls: #{a} #{b}\n" end end END my $o = rb_new_object("main::Cls", "Cls", 1, 2);
rb_call_instance_method()
Takes the following arguments:
$instance
An instance of Inline::Ruby::Object or a derived class.
$method
The name of the method to run on the object.
@_
Optional arguments to the method.
For example:
my $o = rb_new_object("Inline::Ruby::Object", "Object") my $ans = rb_call_instance_method($o, "methods");
rb_iter()
Sets up a Ruby method for calling in iterator context.
Takes the following arguments:
$obj
An object upon which the method will be called. This object is stored inside the returned object, so that when you call a method on it, it is retrieved at that point.
If you pass 'undef' as the
$obj
, the calling methods on the returned object will invoke the global Ruby function of the same name with the iterator block.$iterator
A reference to a Perl subroutine which will be passed as an iterator to the Ruby method.
For example:
my $obj = rb_new_obj("Something"); my $ready = rb_iter($obj, sub { ... }); # call Something#some_method with an iterator $ready->some_method; # call Something#some_method without an iterator $obj->some_method;
SUPPORTED PLATFORMS
Inline::Ruby has so far been tested on Linux only.
Perl versions tested: 5.005_03, 5.6.0, and 5.6.1. It will probably work with 5.7.x as well.
Ruby versions tested: 1.6.[3-6].
The next release will focus on increasing the number of supported platforms. I suspect that any platform where Perl and Ruby both compile will be easy to support.
SEE ALSO
For information about using Inline
, see Inline.
For information about other Inline languages, see Inline-Support.
Inline::Ruby's mailing list is inline@perl.org
To subscribe, send email to inline-subscribe@perl.org
BUGS AND DEFICIENCIES
None so far.
There are bound to be some bugs lurking about. Feel free to email bug reports to inline@perl.org.
They're mite evan bee spelyng mystaikz.
AUTHOR
Neil Watkiss <NEILW@cpan.org>
COPYRIGHT
Copyright (c) 2002, Neil Watkiss.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
See http://www.perl.com/perl/misc/Artistic.html.
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 440:
You forgot a '=back' before '=head1'
- Around line 557:
You forgot a '=back' before '=head1'