Ruby/Python is a Ruby extension library to embed Python interpreter in Ruby. With this library, you can use modules written for Python from your Ruby scripts.
Ruby/Python is designed to integrate the two languages as
transparently as possible. Thus you need neither bothersome coding nor
special consideration to use Python modules. It is much the same as
using library written for Ruby.
Simple Example
First of all, let's look at tiny Ruby scripts to access a FTP server with ftplib. The native versions of ftplib are bundled with both Ruby and Python. Though using ftplib via Ruby/Python has no practical meaning, it is a good example.
First, a script using ftplib written in Ruby for Ruby.
Very simple. Second, a script using ftplib written in Python for Python via Ruby/Python.require 'ftplib' ftp = FTP.open('ftp.netlab.co.jp') ftp.login ftp.chdir('pub/lang/ruby') puts ftp.dir ftp.quit
require 'python' require 'python/ftplib' ftp = Py::Ftplib::FTP.new('ftp.netlab.co.jp') ftp.login ftp.cwd('pub/lang/ruby') ftp.dir ftp.quit
Compare the two scripts. There are not so many differences between them. But the latter script uses a library written for Python!
The big difference is the require
expressions at the
beginning and the naming of class FTP
. And there are a few
different method names. If you are an experienced Ruby user, you may
roughly understand how to use Ruby/Python. As you see, Ruby/Python is a
extension library which enables Ruby users to utilize the modules
written for Python as if they were written for Ruby.
require 'python'
To use Ruby/Python, You need to load Ruby/Python library.
Ruby/Python library itself is a library named 'python'.
When Ruby/Python is loaded, a module named Py
is defined
(under Object
). The functionalities of Ruby/Python is
provided as modules, classes and module functions under Py
module.
eval
and exec
Py.eval(PythonExpression) Py.exec(PythonStatement)
The most simple way to use Python functionalities is to call module
functions eval
and exec
in Py
module. These module functions are equivalent of Python's
eval
builtin function and exec
statement. Py.eval
evaluates a Python expression and
returns the value of the expression. Py.exec
executes
Python statements.
Example:
list = Py.eval('[1, 2, 3]') # returns a Python list object Py.exec('print "hello world"') # print "hello world" to stdout
obj.method(...) obj.method?(...) # returns true or false
You can invoke methods of Python objects. If the method name is
suffixed by '?', the value Python method returned is tested as Boolean
value and returns true
or false
. This
notation is needed because there are no simple mapping between Python
boolean values and Ruby boolean values. If you expect boolean value,
you must append '?'. (Python provides no special objects representing
boolean value. In Python None
, 0
, empty list,
etc. represent false, and the other objects represent true. Usually
Python API uses 0
to represent false. But 0
is true in Ruby.)
Example:
dict = Py.eval('{"One": 1, "Two": 2}') # Python dictionary (hash) object dict.keys # ["One", "Two"] dict["Two"] # 2 dict.has_key("Three") # 0 (true in Ruby) dict.has_key?("Three") # false
obj.method([...,] Py::AS_KEYWORD, key1 => val1, key2 => val2, ...) obj.method([...,] Py::KW, key1 => val1, key2 => val2, ...)
Python methods can receive keyword arguments. But Ruby currently
doesn't support keyword arguments. So Ruby/Python do it in it's own
fashion as shown above. A special constant Py::AS_KEYWORD
is introduced. (Py::KW
is shorthand.) If
Py::AS_KEYWORD
is found in the argument list, the remaining
part of the arguments is interpreted as a hash including keyword
arguments. Each keyword name must be a string or a symbol id.
Example:
ftp = Py::Ftplib::FTP.new ftp.connect(Py::AS_KEYWORD, 'host' => 'ftp.netlab.co.jp', 'port' => 21) # string keyword ftp.login(Py::KW, :user => 'anonymous', :passwd => 'mail address') # id keyword
When a block is given to Python method invocation, aobj.method(...) {|arg| ...}
Proc
object is created and passed as the last argument. Proc
objects looks callable objects from Python. So the above
expression is equivalent to the following one:
obj.method(..., Proc.new{|arg| ...})
require 'python/module'
Ruby/Python replaces builtin function require
. The new
require
interprets library names prefixed with
'python/'
specially. When Library names prefixed with
'python/'
is passed, the specified Python module is
imported. This is the same as following Python statement.
import module
Imported Python modules look as if they are Ruby modules defined
under Py
module. When the name of a Python module begins
with lower case letters, corresponding Ruby module is defined with
capitalized name. Python modules are also refered by attribute
reference to the Py
module.
Example: Access to Python sys module.
require 'python' # Py module is defined require 'python/sys' # Py::Sys module is defined Py::Sys # Reference by constant. Py.sys # Attribute reference to Py module. Same as Py::Sys
Functions and attributes defined in Python modules are provided as modules functions.
Example:
require 'python/math' # Py::Math is defined Py::Math.sqrt(2) # 1.41421 Py::Math.pi # 3.14159
Python classes and types are mapped to Ruby classes. These classes
are defined as subclasses of Py::Object
. Thus all Python
objects are instance of Py::Object
.
Example:
list = Py.eval('[1, 2, 3]') # Python list type object list.type # Py::Types::ListType class list.is_a?(Py::Object) # true
Invocation of class method new
defined in each Ruby
class correspond to Python class creates a class instance. The
arguments passed to new
is used as arguments in Python
instance creation.
Example:
require 'python/ftplib' ftp = Py::Ftplib::FTP.new('ftp.netlab.co.jp') # Equivalent to following Python expression. # ftplib.FTP('ftp.netlab.co.jp')
Objects go across the boundary between Ruby and Python when they are passed as argument to method invocation. Such objects are automatically converted to the destination language's objects. And when objects are returned as a result of method invocation, opposite conversion is performed.
Following objects are converted to the destination language's native objects, that is to say, passed by value.
Ruby object | Python object | Note |
---|---|---|
nil | None |
|
true | 1 | (1) |
false | 0 | (1) |
String instance | string | |
Integer instance |
Plain Integer or Long Integer | |
Float instance |
Floating Point Number |
Integer
instance. If you want 0/1
to
false/true
conversion, suffix
method name with '?'.
Ruby Module
or Class
is defined for each
Python module, class and type. Thus these objects are converted to each
other.
Objects not mentioned above is passed by reference.
When a Python object is passed by reference to Ruby, the object is
converted to an instance of a Py::Object
's subclass. This
object holds the reference to the Python object, and behaves as a
proxy to the Python object. When a message is sent to the
proxy object, the message is forwarded to the Python object.
When a Ruby object is passed by reference to Python, the object looks as if it is a extension type object from Python. This object also holds the reference to the Ruby object, and forward messages.