Relisp

Synopsis

Emacs is great. So is Ruby. This purpose of this library 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?”

Install

[sudo] gem install relisp

Then the library is installed, and you can call elisp from ruby. But if you want to call ruby from emacs (and you do, right?) you need to go into the src directory and copy relisp.el and/or relisp.elc to your elisp folder (probably ~/.elisp or ~/.emacs.d/site-lisp). Then you might want to add the lines

(autoload 'relisp-start-slave "relisp" nil t)
(autoload 'ruby-eval "relisp" nil t)

to your emacs initialization file (~/.emacs' or ~/.emacs.d/init.el).

If you don’t know where to find the files for this gem, run the command gem env gemdir. Or you can download the tarball for this gem and get the files there.

Usage

The stuff below and a lot more is all in the examples directory if you want to try running it.

Emacs calling Ruby

With a generic slave

Start up a ruby process:

(relisp-start-slave)

Then make calls to ruby with ruby_eval:

(ruby-eval "1 + 2 + 3") 
    => 6
(ruby-eval "'ruby string'.reverse")
    => "gnirts ybur"
(type-of (ruby-eval "{:name => 'john'}"))	
    => hash-table

If you need to use the value of an elisp variable, method_missing will give it to you:

(setq list '(3 5 2 6 4 1))
(ruby-eval "list = symbol_value(:list)")

(setq elisp-vector [1 2 3 4 5 6])
(ruby-eval "vect = symbol_value(:\"elisp-vector\")")
(ruby-eval "vect = self.elisp_vector")
; or even
(ruby-eval "vect = elisp_vector")

Note that the data types/classes are correct in both languages. The results are converted–it’s not just strings getting passed back and forth.

Elisp can ask Ruby to evaluate code which in turn will call elisp:

(ruby-eval "elisp_eval('(+ 1 2)')")
(ruby-eval "elisp_eval('(ruby-eval \"1 + 2\")')")

The state of the slave persists from one call to the next:

(ruby-eval "a = 5")
(ruby-eval "a + 1")
   => 6

Specifying a slave file

The ruby slave file should look something like this:

require 'relisp'

slave = Relisp::RubySlave.new

def sample_ruby_method
  Relisp::Buffer.new("ruby-created-buffer")
end

slave.start

The call to slave.start should probably be the last line of the file since it starts an infinite loop. The elisp code just needs to specify the path to the ruby slave when calling relisp-start-slave:

(relisp-start-slave "ruby_slave")
(ruby-eval "sample_ruby_method")

For debugging and curiousity, all of the messages between emacs and ruby are recorded in the buffer *Relisp*.

Ruby calling Emacs

The Emacs process is managed by Relisp::ElispSlave.

require 'relisp'
emacs = Relisp::ElispSlave.new

Calls are made calling elisp_eval and elisp_exec on the ElispSlave object.

emacs.elisp_eval "(+ 1 2)"
   => 3
emacs.elisp_eval '(concat "two " "words")'
   => "two words"
emacs.elisp_eval( "(setq new-var 23)")
emacs.elisp_eval( "(+ 1 new-var)")
   => 24

The usual method_missing magic provides access to elisp functions:

emacs.concat("two", " words")        # (concat "two" "words")
emacs.*(5,2)                         # (* 5 2)
emacs.create_file_buffer("blah.txt") # (create-file-buffer "blah.txt")

Emacs editing types have proxy classes with extensive functionality:

buffer =  Relisp::Buffer.new("ruby-created-buffer")
   => #<Relisp::Buffer:0xb7c4784c>
buffer.name
   => "ruby-created-buffer"

To print debug information showing messages between ruby and emacs, use the ElispSlave#debugging method:

emacs.debugging do
  emacs.elisp_eval "(+ 1 2)"    
end

Author

Don March <[email protected]>

Copyright © 2009, 2010 Don March.

Licensed under the GNU General Public License.

Relisp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Relisp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <www.gnu.org/licenses/>.