relisp 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/COPYING +674 -0
- data/Manifest +18 -0
- data/README +171 -0
- data/Rakefile +50 -0
- data/examples/elisp_master/elisp_master.el +54 -0
- data/examples/elisp_master/ruby_slave +19 -0
- data/examples/ruby_master/ruby_master_example +27 -0
- data/lib/relisp/editing_types.rb +86 -0
- data/lib/relisp/programming_types.rb +293 -0
- data/lib/relisp/slaves.rb +365 -0
- data/lib/relisp.rb +30 -0
- data/setup.rb +1599 -0
- data/src/relisp.el +264 -0
- data/src/relisp.elc +0 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/manifest.rake +48 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +279 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/test/test_editing_types.rb +43 -0
- data/test/test_programming_types.rb +275 -0
- data/test/test_slaves.rb +84 -0
- metadata +110 -0
data/Manifest
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
COPYING
|
3
|
+
Manifest
|
4
|
+
README
|
5
|
+
Rakefile
|
6
|
+
examples/elisp_master/elisp_master.el
|
7
|
+
examples/elisp_master/ruby_slave
|
8
|
+
examples/ruby_master/ruby_master_example
|
9
|
+
lib/relisp.rb
|
10
|
+
lib/relisp/editing_types.rb
|
11
|
+
lib/relisp/programming_types.rb
|
12
|
+
lib/relisp/slaves.rb
|
13
|
+
setup.rb
|
14
|
+
src/relisp.el
|
15
|
+
src/relisp.elc
|
16
|
+
test/test_editing_types.rb
|
17
|
+
test/test_programming_types.rb
|
18
|
+
test/test_slaves.rb
|
data/README
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
= Relisp
|
2
|
+
|
3
|
+
== Synopsis
|
4
|
+
|
5
|
+
Emacs is great. So is Ruby. This purpose of this library is to:
|
6
|
+
* call Ruby from Emacs
|
7
|
+
* call Elisp from Ruby
|
8
|
+
* manipulate Emacs without using Elisp to some extent (Ruby wrappers
|
9
|
+
around some Elisp functions and objects)
|
10
|
+
* reduce the number of blog entries titled "Is Ruby an acceptable
|
11
|
+
lisp?" and flame wars under the title "ruby vs. lisp vs. scheme
|
12
|
+
vs. haskell vs. ..."
|
13
|
+
|
14
|
+
== Install
|
15
|
+
|
16
|
+
[sudo] gem install sundae
|
17
|
+
|
18
|
+
Then the library is installed, and you can call elisp from ruby. But
|
19
|
+
if you want to call ruby from emacs (and you do, right?) you need to
|
20
|
+
go into the +src+ directory and copy <tt>relisp.el</tt> and/or
|
21
|
+
<tt>relisp.elc</tt> to your elisp folder (probably <tt>~/.elisp</tt>).
|
22
|
+
Then you might want to add the line <tt>(require 'relisp)</tt> to your
|
23
|
+
emacs initialization file (probably <tt>~/.emacs'</tt>).
|
24
|
+
|
25
|
+
If you don't know where to find the files for this gem, run the
|
26
|
+
command <tt>gem env gemdir</tt>. Or you can download the tarball for
|
27
|
+
this gem and get the files there.
|
28
|
+
|
29
|
+
== Usage
|
30
|
+
|
31
|
+
The stuff below is all in the +examples+ directory if you want to try
|
32
|
+
running it.
|
33
|
+
|
34
|
+
=== Emacs calling Ruby
|
35
|
+
|
36
|
+
==== With a generic slave
|
37
|
+
|
38
|
+
Start up a ruby process:
|
39
|
+
|
40
|
+
(relisp-start-slave)
|
41
|
+
|
42
|
+
Then make calls to ruby with <tt>ruby_eval</tt>:
|
43
|
+
|
44
|
+
(ruby-eval "1 + 2 + 3")
|
45
|
+
=> 6
|
46
|
+
(ruby-eval "'ruby string'.reverse")
|
47
|
+
=> "gnirts ybur"
|
48
|
+
(type-of (ruby-eval "{:name => 'john'}"))
|
49
|
+
=> hash-table
|
50
|
+
|
51
|
+
If you need to use an elisp variable or expression in the middle of
|
52
|
+
the command, <tt>relisp-to-ruby</tt> will provide a string that, when
|
53
|
+
evaluated by ruby, is equal to the original elisp object. For example:
|
54
|
+
|
55
|
+
(setq vect [1 2 3 4 5 6])
|
56
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".class"))
|
57
|
+
=> Relisp::Vector
|
58
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".kind_of?(Array)"))
|
59
|
+
=> t
|
60
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".reverse"))
|
61
|
+
=> [6 5 4 3 2 1]
|
62
|
+
(type-of (ruby-eval (concat (relisp-to-ruby vect) ".reverse")))
|
63
|
+
=> vector
|
64
|
+
|
65
|
+
Note that the data types/classes are correct in both languages. The
|
66
|
+
results are converted--it's not just strings getting passed back and
|
67
|
+
forth.
|
68
|
+
|
69
|
+
Elisp can ask Ruby to evaluate code which in turn will call elisp:
|
70
|
+
|
71
|
+
(ruby-eval "elisp_eval('(+ 1 2)')")
|
72
|
+
(ruby-eval "elisp_eval('(ruby-eval \"1 + 2\")')")
|
73
|
+
|
74
|
+
The state of the slave persists from one call to the next:
|
75
|
+
|
76
|
+
(ruby-eval "a = 5")
|
77
|
+
(ruby-eval "a + 1")
|
78
|
+
=> 6
|
79
|
+
|
80
|
+
==== Specifying a slave file
|
81
|
+
|
82
|
+
The ruby slave file should look something like this:
|
83
|
+
|
84
|
+
require 'relisp'
|
85
|
+
|
86
|
+
slave = Relisp::RubySlave.new
|
87
|
+
|
88
|
+
def sample_ruby_method
|
89
|
+
Relisp::Buffer.new("ruby-created-buffer")
|
90
|
+
end
|
91
|
+
|
92
|
+
slave.start
|
93
|
+
|
94
|
+
The call to <tt>slave.start</tt> should probably be the last line of
|
95
|
+
the file since it starts an infinite loop. The elisp code just
|
96
|
+
needs to specify the ruby slave file before calling
|
97
|
+
<tt>relisp-start-slave</tt>:
|
98
|
+
|
99
|
+
(setq relisp-ruby-slave-path "ruby_slave")
|
100
|
+
(relisp-start-slave)
|
101
|
+
(ruby-eval "sample_ruby_method")
|
102
|
+
|
103
|
+
For debugging and curiousity, all of the messages between emacs and
|
104
|
+
ruby are recorded in the buffer <tt>\*Relisp\*</tt>.
|
105
|
+
|
106
|
+
=== Ruby calling Emacs
|
107
|
+
|
108
|
+
The Emacs process is managed by <tt>Relisp::ElispSlave</tt>.
|
109
|
+
|
110
|
+
require 'relisp'
|
111
|
+
emacs = Relisp::ElispSlave.new
|
112
|
+
|
113
|
+
Calls are made calling <tt>elisp_eval</tt> and <tt>elisp_execute</tt>
|
114
|
+
on the ElispSlave object.
|
115
|
+
|
116
|
+
emacs.elisp_eval "(+ 1 2)"
|
117
|
+
=> 3
|
118
|
+
emacs.elisp_eval '(concat "two " "words")'
|
119
|
+
=> "two words"
|
120
|
+
emacs.elisp_eval( "(setq new-var 23)")
|
121
|
+
emacs.elisp_eval( "(+ 1 new-var)")
|
122
|
+
=> 24
|
123
|
+
|
124
|
+
The usual <tt>method_missing</tt> magic provides access to elisp
|
125
|
+
functions:
|
126
|
+
|
127
|
+
emacs.concat("two", " words") # (concat "two" "words")
|
128
|
+
emacs.*(5,2) # (* 5 2)
|
129
|
+
emacs.create_file_buffer("blah.txt") # (create-file-buffer "blah.txt")
|
130
|
+
|
131
|
+
Emacs editing types have (or will have) proxy classes:
|
132
|
+
|
133
|
+
buffer = Relisp::Buffer.new("ruby-created-buffer")
|
134
|
+
=> #<Relisp::Buffer:0xb7c4784c>
|
135
|
+
buffer.name
|
136
|
+
=> "ruby-created-buffer"
|
137
|
+
|
138
|
+
To print debug information showing messages between ruby and emacs,
|
139
|
+
use the <tt>ElispSlave#debugging</tt> method:
|
140
|
+
|
141
|
+
emacs.debugging do
|
142
|
+
emacs.elisp_eval "(+ 1 2)"
|
143
|
+
end
|
144
|
+
|
145
|
+
== To Do
|
146
|
+
|
147
|
+
* finish implementing emacs editting types (buffers, frames, etc.)
|
148
|
+
* fix Windows bug(s)
|
149
|
+
|
150
|
+
== Author
|
151
|
+
|
152
|
+
<don@ohspite.net>
|
153
|
+
|
154
|
+
== Copyright
|
155
|
+
|
156
|
+
Copyright (C) 2009 <don@ohspite.net>.
|
157
|
+
Licensed under the GNU General Public License.
|
158
|
+
|
159
|
+
Relisp is free software: you can redistribute it and/or modify it
|
160
|
+
under the terms of the GNU General Public License as published by
|
161
|
+
the Free Software Foundation, either version 3 of the License, or
|
162
|
+
(at your option) any later version.
|
163
|
+
|
164
|
+
Relisp is distributed in the hope that it will be useful, but
|
165
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
166
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
167
|
+
General Public License for more details.
|
168
|
+
|
169
|
+
You should have received a copy of the GNU General Public License
|
170
|
+
along with this program. If not, see
|
171
|
+
<http://www.gnu.org/licenses/>.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
begin
|
2
|
+
require 'bones'
|
3
|
+
Bones.setup
|
4
|
+
rescue LoadError
|
5
|
+
begin
|
6
|
+
load 'tasks/setup.rb'
|
7
|
+
rescue LoadError
|
8
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
ensure_in_path 'lib'
|
13
|
+
require 'relisp'
|
14
|
+
|
15
|
+
task :default => 'test'
|
16
|
+
|
17
|
+
PROJ.name = 'relisp'
|
18
|
+
PROJ.authors = 'Don'
|
19
|
+
PROJ.email = 'don@ohspite.net'
|
20
|
+
PROJ.url = 'relisp.rubyforge.org'
|
21
|
+
PROJ.summary = 'Call ruby from emacs and call elisp from ruby. If you never did you should. These things are fun and fun is good.'
|
22
|
+
PROJ.description = 'Call ruby from emacs and call elisp from ruby. If you never did you should. These things are fun and fun is good.'
|
23
|
+
PROJ.version = Relisp::VERSION
|
24
|
+
PROJ.rubyforge.name = 'relisp'
|
25
|
+
PROJ.history_file = 'CHANGELOG'
|
26
|
+
PROJ.manifest_file = 'Manifest'
|
27
|
+
PROJ.readme_file = 'README'
|
28
|
+
PROJ.rdoc.main = 'README'
|
29
|
+
PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.svn/ \.git/ \.bzr/ \.bzrignore ^pkg/)
|
30
|
+
PROJ.rdoc.include = %w(README ^lib/ ^bin/ ^ext/ \.txt$ \.rdoc$)
|
31
|
+
|
32
|
+
PROJ.gem.extras[:post_install_message] = <<-MSG
|
33
|
+
---------------------------
|
34
|
+
Wait! You're not finished!
|
35
|
+
|
36
|
+
The gem is installed, and you can now call elisp from ruby. But if
|
37
|
+
you want to call ruby from emacs (and you do, right?) you need to go
|
38
|
+
into the 'src' directory of this gem and copy 'relisp.el' and/or
|
39
|
+
'relisp.elc' to your elisp folder (probably '~/.elisp'). Then you
|
40
|
+
might want to add the line "(require 'relisp)" to your emacs
|
41
|
+
initialization file (probably '~/.emacs').
|
42
|
+
|
43
|
+
If you don't know where to find the files for this gem, run the
|
44
|
+
command "gem env gemdir". Or you can download the tarball for this
|
45
|
+
gem and get the files there.
|
46
|
+
---------------------------
|
47
|
+
MSG
|
48
|
+
|
49
|
+
PROJ.spec.opts << '--color'
|
50
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
;; How to specify a file when running the slave. The next few
|
2
|
+
;; `ruby-eval's call methods defined in the ruby slave file.
|
3
|
+
|
4
|
+
(progn
|
5
|
+
(relisp-stop-slave)
|
6
|
+
(setq relisp-ruby-slave-path "ruby_slave")
|
7
|
+
(relisp-start-slave))
|
8
|
+
|
9
|
+
(ruby-eval "sample_ruby_method1")
|
10
|
+
(ruby-eval "sample_ruby_method2")
|
11
|
+
|
12
|
+
(member "ruby-created-buffer" (mapcar (lambda (a) (buffer-name a)) (buffer-list)))
|
13
|
+
(ruby-eval "sample_ruby_method3")
|
14
|
+
(member "ruby-created-buffer" (mapcar (lambda (a) (buffer-name a)) (buffer-list)))
|
15
|
+
|
16
|
+
;; How to start the ruby slave without a file. The rest of the
|
17
|
+
;; commands will work fine with a slave started either way.
|
18
|
+
|
19
|
+
(progn
|
20
|
+
(relisp-stop-slave)
|
21
|
+
(makunbound 'relisp-ruby-slave-path)
|
22
|
+
(relisp-start-slave))
|
23
|
+
|
24
|
+
;; Basic functionality--note that return values are not strings but
|
25
|
+
;; actual elisp data types:
|
26
|
+
(ruby-eval "1 + 2 + 3")
|
27
|
+
(ruby-eval "'ruby string'.reverse")
|
28
|
+
|
29
|
+
(setq vect [1 2 3 4 5 6])
|
30
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".class"))
|
31
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".kind_of?(Array)"))
|
32
|
+
(ruby-eval (concat (relisp-to-ruby vect) ".reverse"))
|
33
|
+
(type-of (ruby-eval (concat (relisp-to-ruby vect) ".reverse")))
|
34
|
+
|
35
|
+
(setq list '(3 5 2 6 4 1))
|
36
|
+
(ruby-eval (concat (relisp-to-ruby list) ".sort"))
|
37
|
+
(type-of (ruby-eval (concat (relisp-to-ruby list) ".sort")))
|
38
|
+
|
39
|
+
(setq str "a couple of words")
|
40
|
+
(ruby-eval (concat (relisp-to-ruby str) ".split"))
|
41
|
+
|
42
|
+
(type-of (ruby-eval "{:name => 'john'}"))
|
43
|
+
|
44
|
+
;; Recursive calls:
|
45
|
+
(ruby-eval "elisp_eval('(+ 1 2)')")
|
46
|
+
(ruby-eval "elisp_eval('(ruby-eval \"1 + 2\")')")
|
47
|
+
|
48
|
+
;; Variable persistence between calls:
|
49
|
+
(ruby-eval "a = 5")
|
50
|
+
(ruby-eval "a + 1")
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "../../lib")
|
2
|
+
|
3
|
+
require 'relisp'
|
4
|
+
|
5
|
+
slave = Relisp::RubySlave.new
|
6
|
+
|
7
|
+
def sample_ruby_method1
|
8
|
+
elisp_eval("(+ 1 5)")
|
9
|
+
end
|
10
|
+
|
11
|
+
def sample_ruby_method2
|
12
|
+
elisp_eval('(ruby-eval "(1 + 5)")')
|
13
|
+
end
|
14
|
+
|
15
|
+
def sample_ruby_method3
|
16
|
+
Relisp::Buffer.new("ruby-created-buffer")
|
17
|
+
end
|
18
|
+
|
19
|
+
slave.start
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "../../lib")
|
4
|
+
|
5
|
+
require 'relisp'
|
6
|
+
|
7
|
+
emacs = Relisp::ElispSlave.new
|
8
|
+
|
9
|
+
# basic functionality
|
10
|
+
puts emacs.elisp_eval("(+ 1 2)")
|
11
|
+
puts (emacs.elisp_eval '(concat "two " "words")')
|
12
|
+
puts emacs.concat("two", " words")
|
13
|
+
puts emacs.*(5,2)
|
14
|
+
puts emacs.create_file_buffer("blah.txt")
|
15
|
+
|
16
|
+
# variable persistence between calls
|
17
|
+
emacs.elisp_eval( "(setq new-var 23)")
|
18
|
+
puts emacs.elisp_eval( "(+ 1 new-var)")
|
19
|
+
|
20
|
+
# recursive calls
|
21
|
+
puts emacs.elisp_eval( '(ruby-eval "1 + 3")')
|
22
|
+
|
23
|
+
# wrappers around elisp editing data types
|
24
|
+
buffer = Relisp::Buffer.new("ruby-created-buffer")
|
25
|
+
puts buffer
|
26
|
+
puts buffer.name
|
27
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 <don@ohspite.net>
|
3
|
+
#
|
4
|
+
# This file is part of Relisp.
|
5
|
+
#
|
6
|
+
# Relisp is free software: you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Relisp is distributed in the hope that it will be useful, but
|
12
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see
|
18
|
+
# <http://www.gnu.org/licenses/>.
|
19
|
+
#++
|
20
|
+
#
|
21
|
+
# See the documentation in <tt>programming_types.rb</tt>.
|
22
|
+
#
|
23
|
+
# Elisp editing types as described in the elisp info manual:
|
24
|
+
#
|
25
|
+
# Editing Types
|
26
|
+
#
|
27
|
+
# Buffer Type:: The basic object of editing.
|
28
|
+
# Marker Type:: A position in a buffer.
|
29
|
+
# Window Type:: Buffers are displayed in windows.
|
30
|
+
# Frame Type:: Windows subdivide frames.
|
31
|
+
# Window Configuration Type:: Recording the way a frame is subdivided.
|
32
|
+
# Frame Configuration Type:: Recording the status of all frames.
|
33
|
+
# Process Type:: A process running on the underlying OS.
|
34
|
+
# Stream Type:: Receive or send characters.
|
35
|
+
# Keymap Type:: What function a keystroke invokes.
|
36
|
+
# Overlay Type:: How an overlay is represented.
|
37
|
+
#
|
38
|
+
# Unlike with elisp programming data types, ruby does not translate
|
39
|
+
# the editing data types to an equivalent ruby object; instead, the
|
40
|
+
# class corresponding to each data type is just a proxy that acts on
|
41
|
+
# the original object in elisp.
|
42
|
+
|
43
|
+
module Relisp
|
44
|
+
|
45
|
+
# A Buffer object just holds onto the Emacs buffer in an elisp
|
46
|
+
# variable and acts as a proxy.
|
47
|
+
#
|
48
|
+
class Buffer
|
49
|
+
def self.from_elisp(object)
|
50
|
+
new(object[:variable], object[:slave])
|
51
|
+
end
|
52
|
+
|
53
|
+
# When _var_or_name_ is a symbol it is considered to be the name
|
54
|
+
# of a pre-existing buffer in the _slave_ process. If
|
55
|
+
# _var_or_name_ is a string, a new buffer is created with a name
|
56
|
+
# based on that string.
|
57
|
+
def initialize(var_or_name, slave = Relisp.default_slave)
|
58
|
+
@slave = slave
|
59
|
+
|
60
|
+
if var_or_name.kind_of?( Symbol )
|
61
|
+
@elisp_variable = @slave.get_permanent_variable(var_or_name)
|
62
|
+
|
63
|
+
unless @slave.elisp_eval("(type-of #{@elisp_variable})") == :buffer
|
64
|
+
raise ArgumentError, "#{@elisp_variable} isn't a buffer"
|
65
|
+
end
|
66
|
+
elsif var_or_name.kind_of?( String )
|
67
|
+
@slave.elisp_execute("(generate-new-buffer #{var_or_name.to_elisp})")
|
68
|
+
@elisp_variable = @slave.get_permanent_variable(Relisp::Slave::PREVIOUS_ELISP_RESULT)
|
69
|
+
else
|
70
|
+
raise ArgumentError
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_elisp
|
75
|
+
@elisp_variable
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return the name of the buffer.
|
79
|
+
#
|
80
|
+
def name
|
81
|
+
@slave.elisp_eval "(buffer-name #{@elisp_variable})"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|