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/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
+