Документация
HTML CSS PHP PERL другое

Section 9.3.  Inline:: Everything Else

 
Previous
Table of Contents
Next

9.3. Inline:: Everything Else

Originally, Inline was just for wrapping C code; however, pretty soon developers[Section 9.3.  Inline:: Everything Else] saw the potential to extend the concept to other languages. Brian rewrote the original Inline.pm to support a greater degree of pluggability, and now CPAN contains a whole host of Inline:: modules.

[Section 9.3.  Inline:: Everything Else] Particularly Neil Watkiss, at the time Brian's coworker at ActiveState.

To round off the chapter, we'll take a look at some other languages you can use in the Inline style.

9.3.1. Inline::Python

Perhaps the most advanced of the non-C Inline modules is Neil Watkiss's Inline::Python; together with his PyPerl, one can mix Python and Perl code in a near-seamless way.

The first and most obvious thing we can do with Inline::Python is the same sort of thing we've been doing with Inline::Cwrap Python routines and use them from Perl:

    use Inline Python => q{
    import os
    def orig_path(  ):
        return os.defpath.split(os.pathsep)
    };

    print "$_\n" for orig_path(  );

Python's os.defpath method returns a built-in search path for executables (unmodified by the value of the $PATH environment variable); we then split this on the separator character for paths (generally ":" on Unix systems) and return it as a Python array.

Inline::Python takes care of turning that Python array into an array that we can use in Perl.

Again, just like Inline::C, we can import library functions without specifying code for them:

    use Inline Python => q{
    from quopri import encodestring
    };

    print encodestring("quoted=printable"); # quoted=3Dprintable

However, we can also import entire classes, allowing access to Python classes and their methods. Let's use the RobotFileParser class contained in the Python robotparser library, used for reading and querying robots.txt files on remote web sites:

    use Inline Python => q{
    from robotparser import RobotFileParser
    };

    my $parser= RobotFileParser->new(  );
    $parser->set_url('http://www.musi-cal.com/robots.txt');
    $parser->read(  );
    # ...

Once we've imported a class, all of its methods are available from Perl as though we were using the class from Pythonall arguments to the methods and any return values come through the Inline::Python bridge, appearing to Perl like Perl values and appearing to Python like Python values. This allows for a pretty seamless integration of Python libraries into Perl.

But what if we want to mix the two languages even more? When Inline::Python starts up, it loads a special Python library called perl. We can use this to grab subroutines from the Perl environment.

    use Inline Python => q{

    def callperl(  ):
        print "This is Python speaking..."
        perl.hi_world(  )
    };

    sub hi_world { print "Hello! I'm in Perl!\n" }

    callperl(  );

Our Perl main package appears as the perl class inside the Python interpreter. Using the same magic that wraps Python methods into Perl subroutines, Inline::Python also turns Perl subroutines into Python methods. That's seamless integration.

Inline::Python also provides a few other functions that make for a smooth transition in and out of Python; perl.eval inside Python and py_eval inside Perl can evaluate strings in the appropriate foreign language, and there are facilities for controlling the binding of Perl and Python routines.

Inline::Python works well for applications where the mother tongue is Perl; Neil's PyPerl is a first-language Python equivalent. Neil has worked hard to produce an extremely robust framework for fluid movement between Perl and Python, and the Inline::Python module is a huge bonus for anyone who wants or needs to use Python classes in their Perl code.

9.3.2. Inline::Ruby

Ruby (http://www.ruby-lang.org) is an interesting, modern, object-oriented scripting language created by Yukihiro Matsumoto (Matz). As you might be able to guess, Inline::Ruby allows you to call Ruby methods and access Ruby classes from Perl. It works precisely the same way as Inline::Python, but doesn't support the same sort of two-way communication. However, you can define methods in Ruby and import Ruby libraries and have them callable from Perl.

An interesting, but slightly complex, feature of Inline::Ruby is the ability to pass Perl subroutines to iterators. Ruby distinguishes between two types of usage for what Perl calls anonymous subroutines: the first type is called a Proc object in Ruby, and it is what most uses of Perl anonymous subs turn into; with the second type, all Ruby methods can take an optional block as an argument following the ordinary formal parameters. This acts as a callback, and the Ruby method can yield control to the callback with the yield keyword.

When a method iteratively calls yield over the contents of a data structure, it's referred to as an iterator. Here's an example of iterating over an array:

    array = ["Hello", "there", "Ruby!"]
    array.each { |x| puts x }

The each iterator method is a little like Perl's for loop: it calls the attached code block on each element of the array in turn.

You might asssume that we could happily say something like this in Inline::Ruby:

    $object->each(sub { print $_[0] });

However, as we've mentioned, the code block isn't passed to the iterator as an ordinary argumentit's attached separately. To get the same effect in Inline::Ruby, we need to associate the code block like so:

    $object->iter(sub { print $_[0] })->each;

This first prepares the object for calling the iterator with the right code block, and then calls it with no ordinary arguments; this does what we mean.

If you haven't taken much of a look at Ruby thus far, I'd encourage you to do so; maybe start by looking at my rubyisms Perl module, which brings some of the more interesting features from Ruby into Perl.

9.3.3. Inline::CPR

We've seen how Inline::C can create Perl extensions to C libraries; the usual topic that goes along with extensions is embedding. This is the process of creating a C program that contains a Perl interpreter and can call Perl subroutines.

Unfortunately, embedding is trickypossibly trickier than XS. Ingy's solution is the curious Inline::CPR module. It works a little like this: you write a C program in the usual way that contains a main( ) function. Here's a simple one:

    void main(void) {
         printf("Hello, C!\n");
    }

Now you do something a bit funny with it; you add a shebang (#!) line to make the C program run under the CPR interpreter, like so:

    #!/usr/bin/cpr

    void main(void) {
         print("Hello, C!\n");
    }

At this point, we have a C program that is a CPR script.

The CPR interpreter is a little program that starts a Perl interpreter and passes your C program wholesale to Inline::C. This compiles your C functions and binds them to Perl subroutines. Once the Perl interpreter has finished doing the usual Inline::C thing, it calls the main subroutine. Conceptually, you've written a Perl program like this:

    #!/usr/bin/perl

    use Inline C => q{

    void main(void) {
         printf("Hello, C!\n");
    }

    };

    main(  )

Once this is done, your C program is up and running inside the context of a Perl interpreter.

The neat part is that because you have a C program running inside Perl, you can use all theInline::C TRicks you've learned about already in this chapter.

Inline::CPR is still in the development stages, and you can't really do anything too clever with it, but it's an interesting framework for solving the embedding problem.

9.3.4. Inline::Struct

You may be thinking that Inline::C is all very well for interfacing to relatively simple C libraries, but in the real world, libraries use more complicated variable types than just the strings, integers, and floating-point types we've seen so far. Most libraries define their own structures and expect us to pass and recieve these structures. How can we do this with Inline?

The answer is to use Neil Watkiss's Inline::Struct. This gives us an object-oriented approach to C structures. To enable this, we simply add the following to our Inline::C programs:

    use Inline C => Config => ENABLE => STRUCTS;

And then, theoretically, any structures defined in your C code will be wrapped into Perl classes.

9.3.5. Miscellaneous Other Inlines

There are now more Inline-style modules on the CPAN than it's sensible to describe, so we'll end this chapter by throwing out a few pointers to other modules worth looking at.

For many years, the only way to plug Java and Perl together was the O'Reilly JPL (Java Perl Lingo) project. This used the JNI (Java Native Interface) C library to embed a Java interpreter inside a Perl interpreter. It was slow, complex and not entirely well documented. Now we have Inline::Java, a Perl-Java bridge that can use either JNI or a socket connection to a standalone Java server process.

Inline::ASM is an obvious extension of the Inline::C concept which lets you write assembly code inline; this is turned into a little library that is wrapped with Inline::C in the usual way.

Inline::Basic is an interesting language extension because it doesn't actually call out to a separate interpreter; it uses a Basic interpreter written in Perl (the Language::Basic module) to interpret your Inline code. Finally, Inline::Files is not actually an Inline.pm module at all, but uses a similar technique to allow you to put multiple virtual files into a _ _DATA_ _ section of a Perl program, instead of just the one.

    Previous
    Table of Contents
    Next
    © 2000- NIV