relisp 1.0.1 → 1.1.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/lib/relisp/slaves.rb CHANGED
@@ -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
  #
@@ -18,6 +18,7 @@
18
18
  # <http://www.gnu.org/licenses/>.
19
19
  #++
20
20
  #
21
+
21
22
  # TODO: maybe catch Errno::EPIPE to see if slave died
22
23
 
23
24
  module Relisp
@@ -53,6 +54,7 @@ module Relisp
53
54
  CONSTANTS << BEGIN_ANSWER_CODE = '___WHATIS___'
54
55
  CONSTANTS << ANSWER_CODE = '___FORTYTWO___'
55
56
  CONSTANTS << ERROR_CODE = '___NO_THATSNOTTRUE_THATSIMPOSSIBLE___'
57
+ CONSTANTS << BEGIN_SLAVE_CODE = '___LETSDOTHISLIKEBRUTUS___'
56
58
  TRANSMISSION_CODES_REGEXP = Regexp.new(CONSTANTS.join('|'))
57
59
 
58
60
  # Every time ruby asks elisp to evaluate an expression, the result
@@ -67,7 +69,7 @@ module Relisp
67
69
  # elisp it is in a context where any new variables set will drop
68
70
  # out of scope immediately. The @local_binding is a way of
69
71
  # allowing these variables to persist through multiple calls.
70
- @local_binding = nil
72
+ @local_binding = binding
71
73
  @current_elisp_variable_num = '0'
72
74
  @debug = nil
73
75
  Relisp.default_slave = self
@@ -93,7 +95,7 @@ module Relisp
93
95
  # Run _code_ in the elisp process.
94
96
  #
95
97
  def elisp_exec(code)
96
- code = code.to_s # maybe code is a symbol or something
98
+ code = code.to_s # maybe code is nil or something
97
99
  write_to_emacs code
98
100
  write_to_emacs COMMAND_CODE
99
101
  receive_answer
@@ -125,7 +127,6 @@ module Relisp
125
127
  output = ''
126
128
  elsif output_line.strip == COMMAND_CODE
127
129
  eval output, @local_binding
128
- # write_to_emacs ""
129
130
  write_to_emacs ANSWER_CODE
130
131
  output = ''
131
132
  elsif output_line.strip == ERROR_CODE
@@ -141,32 +142,29 @@ module Relisp
141
142
  end
142
143
 
143
144
  # Pass an elisp evaluation result to the appropriate Relisp class
144
- # for translation. The first line of _result_string_ is the
145
+ # for translation. The first line of _result_ is the
145
146
  # 'type-of' the elisp object. The line(s) after that are the text
146
147
  # version of the object. In case the string representation isn't
147
148
  # enough information to translate the object, the result needs to
148
149
  # be kept (in emacs) in the variable +PREVIOUS_ELISP_RESULT+.
149
150
  #
150
- def to_ruby(result_string)
151
+ def to_ruby(result)
151
152
 
152
- # The result_string might have junk at the begining caused by
153
+ # The result might have junk at the beginning caused by
153
154
  # whatever emacs sends to the echo area while evaluating ruby's
154
155
  # instructions (it doesn't seem possible to get around this
155
156
  # using with-output-to-string because the output from
156
157
  # save-buffer and other functions is 'message'd). It is also
157
158
  # not possible to just pull off the last two elements, because
158
159
  # sometimes the string representation of the result has newlines
159
- # in it (Buffer#to_s, for example). Otherwise, you could just
160
- # do:
161
- # object_string = result_string.pop
162
- # elisp_type = result_string.pop
163
-
164
- result_string = result_string.split("\n")
165
- start_index = result_string.index(BEGIN_ANSWER_CODE) + 1
166
- result_string = result_string[start_index..(result_string.size-1)]
160
+ # in it (Buffer#to_s, for example).
161
+
162
+ result = result.split("\n")
163
+ start_index = result.index(BEGIN_ANSWER_CODE) + 1
164
+ result = result[start_index..(result.size-1)]
167
165
 
168
- elisp_type = result_string.reverse!.pop
169
- object_string = result_string.reverse!.join("\n")
166
+ elisp_type = result.shift
167
+ object_string = result.join("\n")
170
168
 
171
169
  object_info = {
172
170
  :string => object_string,
@@ -177,10 +175,11 @@ module Relisp
177
175
  # Just one more reason to love Ruby. Call the Relisp class
178
176
  # formed by rubyizing the 'type-of' the result (i.e., hash-table
179
177
  # becomes HashTable).
180
- ruby_type = (eval elisp_type.split("-").map { |a| a.capitalize }.join)
178
+ ruby_type = Relisp.const_get(elisp_type.split("-").map { |a| a.capitalize }.join)
181
179
  unless ruby_type.kind_of? Class
182
180
  raise "#{ruby_type} not implemented"
183
181
  end
182
+
184
183
  ruby_type.from_elisp(object_info)
185
184
  end
186
185
 
@@ -189,8 +188,9 @@ module Relisp
189
188
  def send_constants
190
189
  CONSTANTS.each do |constant|
191
190
  read_from_emacs
192
- write_to_emacs constant
191
+ write_to_emacs constant.to_s + "\n"
193
192
  end
193
+ read_from_emacs
194
194
  end
195
195
 
196
196
  public
@@ -214,7 +214,7 @@ module Relisp
214
214
  # emacs.elisp_eval('(ruby-eval "number")') # => 5
215
215
  #
216
216
  def provide(symbol, binding)
217
- eval "@__#{symbol.to_s}__binding = binding"
217
+ instance_variable_set "@__#{symbol.to_s}__binding".to_sym, binding
218
218
 
219
219
  instance_eval <<-endstr
220
220
  def #{symbol.to_s}
@@ -230,12 +230,17 @@ module Relisp
230
230
  #
231
231
  class RubySlave < Slave
232
232
 
233
+ # Creates a new RubySlave and immediately starts it.
234
+ #
235
+ def self.start
236
+ self.new.start
237
+ end
238
+
233
239
  # Can be provided with a block, in which case the block is run in
234
- # the context of the slave and then the slave is automatically
235
- # started. This makes slave methods available to the block
236
- # without specifying an explicit receiver, and variables and
237
- # functions defined in the block are in scope when requests from
238
- # elisp are evaluated.
240
+ # the context of the slave. This makes slave methods available to
241
+ # the block without specifying an explicit receiver, and variables
242
+ # and functions defined in the block are in scope when requests
243
+ # from elisp are later evaluated.
239
244
  #
240
245
  def initialize
241
246
  super
@@ -243,17 +248,17 @@ module Relisp
243
248
 
244
249
  if block_given?
245
250
  yield self
246
- start
251
+ # start
247
252
  end
248
-
249
253
  end
250
254
 
251
255
  # Begin the main listening loop.
252
256
  #
253
257
  def start
258
+ write_to_emacs BEGIN_SLAVE_CODE
259
+ write_to_emacs ANSWER_CODE
260
+
254
261
  begin
255
- @local_binding = binding
256
-
257
262
  loop do
258
263
  code = ''
259
264
  input = read_from_emacs
@@ -275,7 +280,7 @@ module Relisp
275
280
  dag_yo.backtrace.each do |b|
276
281
  msg << " " + b + "\n"
277
282
  end
278
- write_to_emacs(msg)
283
+ write_to_emacs msg.chomp
279
284
  #write_to_emacs(dag_yo.message)
280
285
  write_to_emacs ERROR_CODE
281
286
  retry
@@ -288,7 +293,8 @@ module Relisp
288
293
  # the ruby process.
289
294
  #
290
295
  def write_to_emacs(code)
291
- puts code
296
+ # puts code
297
+ print code
292
298
  end
293
299
 
294
300
  # Messages appear on ruby's stdin after emacs sends them to ruby
@@ -298,7 +304,7 @@ module Relisp
298
304
  gets
299
305
  end
300
306
  end
301
-
307
+
302
308
  # Provides an interface to an instance of emacs started as an IO
303
309
  # object. See Relisp::Slave.
304
310
  #
@@ -313,11 +319,9 @@ module Relisp
313
319
  #
314
320
  def initialize(cli_options = "--no-site-file --no-init-file", load_files = [])
315
321
  super()
316
- # load relisp.elc if available
322
+ # leave off '.el' to load relisp.elc if available
317
323
  elisp_path = File.expand_path(File.join(File.dirname(__FILE__), '../../src/relisp'))
318
324
 
319
- @local_binding = binding
320
-
321
325
  emacs_command = if RUBY_PLATFORM.downcase.include?('mswin')
322
326
  "start emacs --batch "
323
327
  else