relisp 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ == 1.1.0 / 2011-01-05
2
+
3
+ * 2 major enhancements
4
+ * Multiple ruby slaves can be run from Emacs at once.
5
+ * The method_missing stuff now retreives and sets elisp variables in
6
+ addition to calling functions.
7
+ * Ruby slaves can call elisp while starting up.
8
+ * minor enhancements
9
+ * Less temporary variables created in elisp, and those that can be
10
+ are `makunbound'ed when they can be.
11
+ * Eval used in fewer places in ruby and elisp.
12
+ * New and better examples.
13
+ * Code is DRYer, prettier and sucks less in general.
14
+
1
15
  == 1.0.1 / 2009-09-09
2
16
 
3
17
  * 1 tiny backwards-incompatible enhancement
data/README CHANGED
@@ -8,8 +8,7 @@ Emacs is great. So is Ruby. This purpose of this library is to:
8
8
  * manipulate Emacs without using Elisp to some extent (Ruby wrappers
9
9
  around some Elisp functions and objects)
10
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. ..."
11
+ lisp?"
13
12
 
14
13
  == Install
15
14
 
@@ -18,13 +17,15 @@ Emacs is great. So is Ruby. This purpose of this library is to:
18
17
  Then the library is installed, and you can call elisp from ruby. But
19
18
  if you want to call ruby from emacs (and you do, right?) you need to
20
19
  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 lines
20
+ <tt>relisp.elc</tt> to your elisp folder (probably <tt>~/.elisp</tt>
21
+ or <tt>~/.emacs.d/site-lisp</tt>). Then you might want to add the
22
+ lines
23
23
 
24
24
  (autoload 'relisp-start-slave "relisp" nil t)
25
25
  (autoload 'ruby-eval "relisp" nil t)
26
26
 
27
- to your emacs initialization file (probably <tt>~/.emacs'</tt>).
27
+ to your emacs initialization file (<tt>~/.emacs'</tt> or
28
+ <tt>~/.emacs.d/init.el</tt>).
28
29
 
29
30
  If you don't know where to find the files for this gem, run the
30
31
  command <tt>gem env gemdir</tt>. Or you can download the tarball for
@@ -32,8 +33,8 @@ this gem and get the files there.
32
33
 
33
34
  == Usage
34
35
 
35
- The stuff below is all in the +examples+ directory if you want to try
36
- running it.
36
+ The stuff below and a lot more is all in the +examples+ directory if
37
+ you want to try running it.
37
38
 
38
39
  === Emacs calling Ruby
39
40
 
@@ -52,19 +53,17 @@ Then make calls to ruby with <tt>ruby_eval</tt>:
52
53
  (type-of (ruby-eval "{:name => 'john'}"))
53
54
  => hash-table
54
55
 
55
- If you need to use an elisp variable or expression in the middle of
56
- the command, <tt>relisp-to-ruby</tt> will provide a string that, when
57
- evaluated by ruby, is equal to the original elisp object. For example:
56
+ If you need to use the value of an elisp variable,
57
+ <tt>method_missing</tt> will give it to you:
58
58
 
59
- (setq vect [1 2 3 4 5 6])
60
- (ruby-eval (concat (relisp-to-ruby vect) ".class"))
61
- => Relisp::Vector
62
- (ruby-eval (concat (relisp-to-ruby vect) ".kind_of?(Array)"))
63
- => t
64
- (ruby-eval (concat (relisp-to-ruby vect) ".reverse"))
65
- => [6 5 4 3 2 1]
66
- (type-of (ruby-eval (concat (relisp-to-ruby vect) ".reverse")))
67
- => vector
59
+ (setq list '(3 5 2 6 4 1))
60
+ (ruby-eval "list = symbol_value(:list)")
61
+
62
+ (setq elisp-vector [1 2 3 4 5 6])
63
+ (ruby-eval "vect = symbol_value(:\"elisp-vector\")")
64
+ (ruby-eval "vect = self.elisp_vector")
65
+ ; or even
66
+ (ruby-eval "vect = elisp_vector")
68
67
 
69
68
  Note that the data types/classes are correct in both languages. The
70
69
  results are converted--it's not just strings getting passed back and
@@ -147,12 +146,13 @@ use the <tt>ElispSlave#debugging</tt> method:
147
146
 
148
147
  == Author
149
148
 
150
- <don@ohspite.net>
149
+ Don March <don@ohspite.net>
151
150
 
152
151
  == Copyright
153
152
 
154
- Copyright (C) 2009 <don@ohspite.net>.
155
- Licensed under the GNU General Public License.
153
+ Copyright (C) 2009, 2010 Don March.
154
+
155
+ Licensed under the GNU General Public License.
156
156
 
157
157
  Relisp is free software: you can redistribute it and/or modify it
158
158
  under the terms of the GNU General Public License as published by
data/Rakefile CHANGED
@@ -31,13 +31,14 @@ Wait! You're not finished!
31
31
  The gem is installed, and you can now call elisp from ruby. But if
32
32
  you want to call ruby from emacs (and you do, right?) you need to go
33
33
  into the 'src' directory of this gem and copy 'relisp.el' and/or
34
- 'relisp.elc' to your elisp folder (probably '~/.elisp'). Then you
35
- might want to add the lines
34
+ 'relisp.elc' to your elisp folder (probably something like
35
+ '~/.emacs.d/site-lisp' or '~/.elisp'). Then you might want to add the
36
+ lines
36
37
 
37
38
  (autoload 'relisp-start-slave "relisp" nil t)
38
39
  (autoload 'ruby-eval "relisp" nil t)
39
40
 
40
- to your emacs initialization file (probably '~/.emacs').
41
+ to your emacs initialization file ('~/.emacs' or ~/.emacs.d/init.el).
41
42
 
42
43
  If you don't know where to find the files for this gem, run the
43
44
  command "gem env gemdir". Or you can download the tarball for this
@@ -1,49 +1,85 @@
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.
1
+ ;; You might want to look at the *Relisp* buffer to see what messages
2
+ ;; are being passed. Or you might not. But it's there if you want it.
3
3
 
4
- (relisp-start-slave "ruby_slave")
4
+ ;; To evaluate each examples below, move point after the closing
5
+ ;; parenthesis and press C-x C-e.
5
6
 
6
- (ruby-eval "sample_ruby_method1")
7
- (ruby-eval "sample_ruby_method2")
7
+ ;; This is how to start the ruby slave without a file, but if you
8
+ ;; don't `ruby-eval' and `ruby-exec' will start one for you.
9
+ ;; This stops the old slave first:
10
+ (relisp-start-slave)
8
11
 
9
- (member "ruby-created-buffer" (mapcar 'buffer-name (buffer-list)))
10
- (ruby-exec "sample_ruby_method3")
11
- (member "ruby-created-buffer" (mapcar 'buffer-name (buffer-list)))
12
-
13
- (ruby-exec "sample_ruby_method4")
12
+ ;; Note that return values are not strings but actual elisp data
13
+ ;; types:
14
+ (ruby-eval "1 + 2 + 3")
15
+ (ruby-eval "'gnirts ybur'.reverse")
14
16
 
15
- ;; How to start the ruby slave without a file. The rest of the
16
- ;; commands will work fine with a slave started either way.
17
+ ;; Variable persistence between calls:
18
+ (ruby-exec "a = 5")
19
+ (ruby-eval "a + 1")
17
20
 
18
- (relisp-start-slave) ;; stops the old slave first
21
+ ;; Recursive calls:
22
+ (ruby-eval "elisp_eval('(+ 1 2)')")
23
+ (ruby-eval "elisp_eval('(ruby-eval \"1 + 2\")')")
19
24
 
20
- ;; Basic functionality--note that return values are not strings but
21
- ;; actual elisp data types:
22
- (ruby-eval "1 + 2 + 3")
23
- (ruby-eval "'ruby string'.reverse")
25
+ (setq list '(3 5 2 6 4 1))
26
+ (ruby-eval "list = symbol_value(:list)")
27
+ (ruby-eval "list.class")
28
+ (ruby-eval "list.to_list.class")
29
+ (ruby-eval "list.to_list.sort")
30
+ (type-of (ruby-eval "list.to_list"))
24
31
 
25
- (setq vect [1 2 3 4 5 6])
26
- (ruby-eval (concat (relisp-to-ruby vect) ".class"))
27
- (ruby-eval (concat (relisp-to-ruby vect) ".kind_of?(Array)"))
28
- (ruby-eval (concat (relisp-to-ruby vect) ".reverse"))
29
- (type-of (ruby-eval (concat (relisp-to-ruby vect) ".reverse")))
32
+ ;; Because of the method_missing stuff, getting the symbol value
33
+ ;; directly isn't even necessary most of the time (it was for `list',
34
+ ;; however, because it's a function and method_missing tries that
35
+ ;; first.
30
36
 
31
- (setq list '(3 5 2 6 4 1))
32
- (ruby-eval (concat (relisp-to-ruby list) ".class"))
33
- (ruby-eval (concat (relisp-to-ruby list) ".to_list.class"))
34
- (ruby-eval (concat (relisp-to-ruby list) ".to_list.sort"))
35
- (type-of (ruby-eval (concat (relisp-to-ruby list) ".to_list")))
37
+ (setq elisp-vector [1 2 3 4 5 6])
38
+ ;; (ruby-eval "vect = symbol_value(:\"elisp-vector\")")
39
+ (ruby-eval "vect = self.elisp_vector")
40
+ ;; or even
41
+ (ruby-eval "vect = elisp_vector")
42
+ (ruby-eval "vect.class")
43
+ (ruby-eval "vect.kind_of? Array")
44
+ (ruby-eval "vect.reverse")
45
+ (type-of (ruby-eval "vect.reverse"))
46
+ (ruby-eval "self.elisp_vector= vect.reverse")
47
+ (symbol-value 'elisp-vector)
36
48
 
37
49
  (setq str "a couple of words")
38
- (ruby-eval (concat (relisp-to-ruby str) ".split"))
50
+ (ruby-eval "self.str.split")
39
51
 
40
- ;; Recursive calls:
41
- (ruby-eval "elisp_eval('(+ 1 2)')")
42
- (ruby-eval "elisp_eval('(ruby-eval \"1 + 2\")')")
52
+ ; If you need an elisp value in ruby but don't want it in an elisp
53
+ ; variable, just elisp_eval it:
54
+ (ruby-exec "vect = elisp_eval '[1 2 3 4]'")
55
+ (ruby-eval "vect.reverse")
43
56
 
44
- ;; Variable persistence between calls:
45
- (ruby-exec "a = 5")
46
- (ruby-eval "a + 1")
57
+ ;; Running multiple slaves is possible by specifying `t' as a an
58
+ ;; optional second argument to `relisp-start-slave'.
47
59
 
60
+ ;; This stops the old slave first:
61
+ (setq p1 (relisp-start-slave))
62
+ ;; This doesn't:
63
+ (setq p2 (relisp-start-slave nil t))
64
+ (ruby-exec "p=1" p1)
65
+ (ruby-exec "p=2" p2)
66
+ (ruby-eval "p" p1)
67
+ (ruby-eval "p" p2)
68
+ (relisp-stop-slave p1)
69
+ (relisp-slave-alive-p p1)
70
+ (relisp-stop-slave p2)
48
71
 
72
+ ;; How to specify a file when running the slave. This ruby file runs
73
+ ;; some window stuff and then exits, i.e., it doesn't turn itself into
74
+ ;; a slave.
75
+ (setq p (relisp-start-slave "ruby_slave2.rb"))
76
+ (relisp-slave-alive-p p)
49
77
 
78
+ ;; This ruby file defines some methods, runs some frame stuff at
79
+ ;; startup, and then starts itself as a slave.
80
+ (setq p (relisp-start-slave "ruby_slave.rb"))
81
+ (relisp-slave-alive-p p)
82
+ (ruby-exec "kill_the_new_buffer")
83
+ (ruby-eval "ruby_elisp_eval")
84
+ (ruby-eval "ruby_elisp_eval_ruby_eval")
85
+ (ruby-exec "frame_class")
@@ -0,0 +1,37 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "../../lib")
2
+ require 'relisp'
3
+
4
+ slave = Relisp::RubySlave.new
5
+
6
+ def kill_the_new_buffer
7
+ switch_to_buffer('*relisp_test_buffer*')
8
+ kill_buffer
9
+ end
10
+
11
+ def ruby_elisp_eval
12
+ elisp_eval("(+ 1 5)")
13
+ end
14
+
15
+ def ruby_elisp_eval_ruby_eval
16
+ elisp_eval('(ruby-eval "(1 + 5)")')
17
+ end
18
+
19
+ def frame_class
20
+ frame = Relisp::Frame.new({:width => 80, :height => 20, :name => "ruby frame"})
21
+ frame.height=30
22
+ frame.width=60
23
+ 10.times { frame.width += 2 }
24
+ 10.times { frame.width -= 2 }
25
+ 10.times { frame.height += 2 }
26
+ 10.times { frame.height -= 2 }
27
+ 5.times { frame.height +=2; frame.width += 2 }
28
+ 5.times { frame.height -=2; frame.width -= 2 }
29
+ frame.delete
30
+ end
31
+
32
+ buffer = Relisp::Buffer.new('*relisp_test_buffer*')
33
+ slave.display_buffer buffer
34
+ buffer.insert "This buffer was created by the startup stuff in `ruby_slave.rb\'\n"
35
+ buffer.insert "It will go away when you run `kill_the_new_buffer'"
36
+
37
+ slave.start
@@ -0,0 +1,33 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "../../lib")
2
+ require 'relisp'
3
+
4
+ slave = Relisp::RubySlave.new
5
+
6
+ w = slave.selected_window
7
+ w2 = w.split_vertically
8
+ w3 = w2.split_horizontally
9
+ 10.times do
10
+ w.shrink(1)
11
+ slave.redisplay
12
+ sleep 0.01
13
+ end
14
+ 10.times do
15
+ w.enlarge(1)
16
+ slave.redisplay
17
+ sleep 0.01
18
+ end
19
+ 10.times do
20
+ w2.shrink(0,1)
21
+ slave.redisplay
22
+ sleep 0.01
23
+ end
24
+ 10.times do
25
+ w2.enlarge(0,1)
26
+ slave.redisplay
27
+ sleep 0.01
28
+ end
29
+
30
+ w2.delete
31
+ w3.delete
32
+
33
+
@@ -0,0 +1,20 @@
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
+ puts "elisp_eval '(+ 1 2)'"
10
+ puts '=> ' + emacs.elisp_eval("(+ 1 2)").to_s
11
+ puts
12
+ puts "elisp_exec '(+ 1 2)'"
13
+ puts '=> ' + emacs.elisp_exec("(+ 1 2)").to_s
14
+ puts "elisp_exec '(setq a (+ 1 2))'"
15
+ puts '=> ' + emacs.elisp_exec("(setq a (+ 1 2))").to_s
16
+ puts "elisp_eval 'a'"
17
+ puts '=> ' + emacs.elisp_eval("a").to_s
18
+
19
+
20
+
@@ -0,0 +1,32 @@
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
+
10
+ puts 'buffer = Relisp::Buffer.new("ruby-created-buffer"); buffer.to_s'
11
+ emacs.debugging do
12
+ @buffer = Relisp::Buffer.new("ruby-created-buffer")
13
+ end
14
+ puts '=> ' + @buffer.to_s
15
+
16
+ puts
17
+
18
+ puts "buffer.insert 'some text'; buffer.to_s"
19
+ emacs.debugging do
20
+ @buffer.insert 'some text'
21
+ end
22
+ puts '=> ' + @buffer.to_s
23
+
24
+ puts
25
+ puts "Hashes are currently the most complex thing to convert (press Enter to see it):"
26
+ gets
27
+
28
+ ruby_hash = ({ :time => "money",
29
+ :money => "power" })
30
+ emacs.debugging do
31
+ emacs.emacs_hash= ruby_hash
32
+ end
@@ -0,0 +1,26 @@
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
+ puts 'buffer = Relisp::Buffer.new("ruby-created-buffer"); buffer.to_s'
10
+ buffer = Relisp::Buffer.new("ruby-created-buffer")
11
+ puts '=> ' + buffer.to_s
12
+ puts "buffer.insert 'some text'; buffer.to_s"
13
+ buffer.insert 'some text'
14
+ puts '=> ' + buffer.to_s
15
+ puts 'buffer.name'
16
+ puts '=> ' + buffer.name.to_s
17
+ puts "buffer.name= 'fred'"
18
+ puts '=> ' + buffer.name= 'fred'.to_s
19
+ puts 'buffer.name'
20
+ puts '=> ' + buffer.name
21
+
22
+ puts
23
+
24
+ puts 'emacs.create_file_buffer("blah.txt").class'
25
+ puts '=> ' + emacs.create_file_buffer("blah.txt").class.to_s
26
+
@@ -0,0 +1,24 @@
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
+ puts "emacs.elisp_eval '(concat \"two\" \"words\")"
10
+ puts '=> ' + (emacs.elisp_eval '(concat "two " "words")')
11
+ puts "emacs.concat \"two\", \"words\""
12
+ puts '=> ' + emacs.concat("two ", "words")
13
+
14
+ puts
15
+
16
+ puts 'emacs.set(:a, 3); emacs.symbol_value(:a)'
17
+ emacs.set(:a, 3).to_s
18
+ puts '=> ' + emacs.symbol_value(:a).to_s
19
+ puts 'emacs.a'
20
+ puts '=> ' + emacs.a.to_s
21
+ puts 'emacs.a= 5; emacs.a'
22
+ emacs.a= 5
23
+ puts '=> ' + emacs.a.to_s
24
+
@@ -0,0 +1,11 @@
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
+ puts "emacs.elisp_eval '(ruby-eval \"1 + 3\")'"
10
+ puts '=> ' + emacs.elisp_eval('(ruby-eval "1 + 3")').to_s
11
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (C) 2009 <don@ohspite.net>
2
+ # Copyright (C) 2009, 2010 Don March
3
3
  #
4
4
  # This file is part of Relisp.
5
5
  #
@@ -83,23 +83,40 @@ module Relisp
83
83
 
84
84
  private
85
85
 
86
- # Forward any missing method to elisp, writing the function and
87
- # arguments in prefix notation (calling the +to_elisp+ method of
88
- # each of the _args_).
86
+ # Forward any missing method to elisp.
87
+ #
88
+ # If a function with that name exists, write the rubyized (swap _
89
+ # for -) function and arguments in prefix notation (calling the
90
+ # +to_elisp+ method of each of the _args_).
91
+ #
92
+ # If a symbol with that name exists, return its value.
93
+ #
94
+ # If the last char of the missing method is `=', set the symbol
95
+ # formed by the characters before the `=' to the first argument.
96
+ #
97
+ # For example:
98
+ #
99
+ # emacs = Relisp::ElispSlave.new
100
+ # puts emacs.concat "two", "words"
101
+ # emacs.a= 5
102
+ # puts emacs.a
89
103
  #
90
104
  # This automatically allows access to a large portion of elisp
91
- # functions a rubyish way.
105
+ # in a rubyish way.
92
106
  #
93
107
  def method_missing(function, *args) # :doc:
94
- function = function.to_s.gsub('_', '-')
95
- unless elisp_eval("(functionp '#{function})")
96
- raise NameError, "#{function} is not an elisp function"
97
- end
108
+ lisp_name = function.to_s.gsub('_', '-')
98
109
 
99
- elisp_eval('(' +
100
- function + ' ' +
101
- args.map{|a| a.to_elisp}.join(' ') +
102
- ')')
110
+ if elisp_eval "(functionp '#{lisp_name})"
111
+ elisp_eval "(#{lisp_name} #{args.map{|a| a.to_elisp}.join(' ')})"
112
+ elsif elisp_eval("(boundp '#{lisp_name})") && args.empty? # if there are args, it was meant to be a function
113
+ elisp_eval "#{lisp_name}"
114
+ elsif lisp_name[lisp_name.size-1..lisp_name.size-1] == "="
115
+ elisp_eval "(setq #{lisp_name[0..lisp_name.size-2]} #{args[0].to_elisp})"
116
+ else
117
+ raise NameError, "#{function} is undefined variable/method/function in Ruby and Elisp"
118
+ end
119
+ # elisp_eval("(if (functionp '#{function}) (#{function} #{args.map{|a| a.to_elisp}.join(' ')}) #{function})")
103
120
  end
104
121
 
105
122
  end