Rupy: Python in your Ruby
Rupy is a bridge between the Ruby and Python interpreters. It embeds a running Python interpreter in the application's process using FFI and provides a means for wrapping and converting Python objects. Rupy is based on Zach Raines's amazing RubyPython project.
Rupy uses FFI to marshall the data between the Ruby and Python VMs and make Python calls. Recently, Rupy has added the ability to:
Inherit from Python classes;
Configure callbacks from Python;
Run Python generators (on Ruby 1.9.2 or later).
Rupy is currently managed from GitHub: [github.com/steeve/rupy].
require "rupy" Rupy.start # start the Python VM cPickle = Rupy.import("cPickle") p cPickle.dumps("Testing rupy").rubify Rupy.stop # stop the Python VM
Specific Python Version
require "rupy" Rupy.start(:python => "python2.7") # Can also be a full path cPickle = Rupy.import("cPickle") p cPickle.dumps("Testing rupy").rubify Rupy.stop # stop the Python VM
# Easy Rupy.start_from_virtualenv("/path/to/virtualenv") # Or verbose Rupy.start(:python => "/path/to/virtualenv/bin/python") Rupy.activate
# Python def readfile(): for line in open("/some/file"): yield line # Ruby readfile.to_enum.each do |line| puts line end
Python to Ruby callbacks
# Python def dosomething(callback): print callback(5) # Ruby dosomething(lambda do |value| value * 2 end) def mycallback(value) return value * 2 end dosomething(method(:mycallback))
# Python def test_generator(callback): for i in callback(): print "Got %d" % i # Ruby test_generator(Rupy.generator do (0..10).each do |i| Rupy.yield i end end)
Features / Problems
Can handle simple conversion of Python builtin types to Ruby builtin types and vice versa
Can import Python modules
Can execute arbitrary methods on imported modules and return the result
Python objects can be treated as Ruby objects!
Python's standard library available to you from within Ruby.
Pass Ruby methods and procs as callbacks and call them from within Python code.
Specify the python executable to be loaded, including virtualenv.
Builtin Python methods which require a top level frame object (eval, dir, …) do not work properly at present.
There is no support for passing complicated (non-basic) Ruby types to Python.
Rupy is known to work with the C-based Python interpreter, versions 2.4 through 2.7; no work has yet been done to enable Python 3.0 support or to work with alternative Python implementations.
Rupy is known to work with the C-based (MRI) Ruby interpreter on versions 1.8.7 and 1.9.2. However, it uses Ruby-FFI, so it may work with other implementations without modification.
There are features that are not currently supported in Rupy that may be considered for future releases, dependent on need, interest, and solutions.
It might be nice to have some nice import helpers provided by Rupy to make the interface more seamless and provide advanced import features:
# Python from mod2.mod1 import sym as mysym # Ruby py :from => "mod2.mod1", :import => "sym", :as => "mysym" py :from => "mod2.mod1", :import => :sym, :as => :mysym py :from => [ :mod2, :mod1 ], :import => :sym, :as => :mysym # Python import mod1 as mymod # Ruby py :import => "mod1", :as => "mymod" py :import => :mod1, :as => :mymod # Python from mod2.mod1 import * # Ruby py :from => "mod2.mod1", :import => :* pyrequire "mod2/mod1" # ruby style imports
Python named arguments
# Python def foo(arg1, arg2): pass # Ruby foo(:arg2 => "bar2", :arg1 => "bar1") # with Ruby 1.9 foo(arg2: "bar2", arg1: "bar1")
Catch Exceptions from Ruby
# Python class MyFirstException(Exception): pass class MySecondException(MyFirstException): pass def test(): raise MySecondException # Ruby begin test rescue MyFirstException => e # We may need to work out name collisions puts e.message end
Python >= 2.4, < 3.0
Ruby >= 1.8.6
You must be able to build the ffi gem under your environment.
Note: RubyPython and Rupy have been tested on Mac OS 10.5.x
gem install rupy
Steeve Morin: I'm in love with both languages and want to be able to take what's best from each. This is an idea that was in my head for quite some time, and seeing that Zach Raines only developed RubyPython sporadically, I decided to implement what was missing to address my use cases.
Austin Ziegler: I have a need to control some Python code through a Ruby application for a project I'm working on, so I found RubyPython.
I implemented and submitted a bug fix for Zach's implementation and he pointed me to Steeve's fork as something that would be developed more frequently. There's
This project owes a great debt to Zach Raines for RubyPython for the initial code. His original code (updated irregularly) can be found on [BitBucket](raineszm.bitbucket.org/rubypython/).
See License.rdoc for full details.
(The MIT License)
Copyright 2011 Steeve Morin, Austin Ziegler, and Zach Raines Portions copyright 2008–2011 Zach Raines
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.