relisp 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+