Okay, look. If you use Emacs extensively and have never wished you could use something to customize it besides Lisp…well, then, 100 hacker points for you. But not this project. This project is not for you.

This purpose of Relisp is to:

  • call Ruby from Emacs
  • call Elisp from Ruby
  • manipulate Emacs without using Elisp to some extent (Ruby wrappers around some Elisp functions and objects)
  • reduce the number of blog entries titled “Is Ruby an acceptable Lisp?” and flame wars under the title “ruby vs. lisp vs. scheme vs. haskell vs. …”

How about some examples?

Call Ruby from Emacs

(relisp-start-slave)
(ruby-eval "1 + 2 + 3")
;    => 6

(ruby-eval "'ruby string'.reverse")
;    => "gnirts ybur"

Emacs starts a ruby process and they both pass questions and answers back and forth. Simple enough. But it’s more than just handing each other strings:

(type-of (ruby-eval "{:first => 'john', :last => 'doe'}"))
;    => hash-table

(setq list '(3 5 2 6 4 1))
(ruby-eval (concat (relisp-to-ruby list) ".class"))
;    => Relisp::Cons

(ruby-eval (concat (relisp-to-ruby list) ".to_list.class"))
;    => Relisp::List [a subclass of Array]

(ruby-eval (concat (relisp-to-ruby list) ".to_list.sort"))
;    => (1 2 3 4 5 6)

(type-of (ruby-eval (concat (relisp-to-ruby list) ".to_list.sort")))
;    => cons

Whenever objects are passed from Elisp to Ruby or back again they’re translated to the appropriate analogous type/class in the other language. An Elisp integer becomes a Ruby Fixnum, a vector becomes an Array, things like that.

Call Elisp from Ruby

I admit that I initially added this functionality just so I could run Relisp’s unit tests from the Ruby side. But if you ever want to use some Lisp in your Ruby programs, you can do that now.

require 'relisp'

emacs = Relisp::ElispSlave.new
emacs.elisp_eval( "(+ 1 2)" )
#    => 3

emacs.elisp_eval( '(concat "two " "words")' )
#    => "two words"

Looks sort of like the Lisp version, right? Using the typical method_missing magic, unknown ElispSlave methods are translated into calls to Lisp functions:

emacs.*(5, 2)
#    => 10 [calls (* 5 2)]

emacs.create_file_buffer( "blah.txt" )
#    =>  #<Relisp::Buffer:0x7f3839cf8168 ...> [calls (create-file-buffer "blah.txt")]

The result to that last example sort of gives away the grand finale. Wouldn’t it be nice to have a Ruby interface to things like buffers, windows and frames? Yes. Yes it would:

new_buffer = Relisp::Buffer.new("name_of_new_buffer")
new_buffer.switch_to
Relisp::Frame.new({:width => 80, :height => 20, :name => "ruby frame"})

Installation

For all of the glorious details, see the documentation at http://relisp.rubyforge.org/. To get the gem, just pull up the terminal:

[sudo] gem install relisp