relisp 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|