我正在制作一个Ruby REPL,用于内部应用程序。下面是代码:
a = 1
b = 2
currentScope = []
Kernel.local_variables.each do |var|
currentScope << [var,Kernel.eval(var.to_s)]
end
launchREPL(currentScope)
在 REPL 内部,我可以执行以下代码:
@a #=>1
@a+@b #=>3
理想情况下,在启动REPL之前,我不需要编写这四行代码,而是希望在
launchREPL
函数内部运行它们。但是,这将需要从launchREPL
函数内部访问先前的作用域。
测试1
特别值得注意的是,我尝试过:
launchREPL(Kernel)
当我执行以下操作时:
def launchREPL(scope)
F = 0
puts scope.local_variables # => [:F]
end
显然,这种方法是无效的。
测试2
launchREPL(Kernel.binding)
def launchREPL(scope)
Kernel.binding.local_variables #= Error: private method 'local_variables' called for #<Binding>
end
有没有办法做我正在尝试做的事情?
编辑:附上目前在launchREPL中的代码:
def launchREPL(scope=nil,winName="Ruby REPL")
# ICM RB file Begin:
puts "\"Starting REPL...\""
__b = binding #Evaluating in a binding, keeps track of local variables
__s = ""
###############################################################################
# SEND INSTANCE VARIABLES TO REPL
###############################################################################
#
#How to prepare scope
# currentScope = []
# Kernel.local_variables.each do |var|
# currentScope << [var,Kernel.eval(var.to_s)]
# end
# launchREPL(currentScope)
if scope != nil
scope.each do |varDef|
__b.instance_variable_set "@#{varDef[0].to_s}" , varDef[1]
__b.eval("@#{varDef[0].to_s} = __b.instance_variable_get(:@#{varDef[0].to_s})")
end
end
# to get instance variables: __b.instance_variable_get(__b.instance_variables[0])
# or better: __b.instance_variable_get(:@pipe1)
#
###############################################################################
bStartup = true
while bStartup || __s != ""
# If startup required skip evaluation step
if !bStartup
#Evaluate command
begin
__ret = __s + "\n>" + __b.eval(__s).to_s
rescue
__ret = __s + "\n> Error: " + $!.to_s
end
puts __ret
else
#REPL is already running
bStartup = false
end
#Read user input & print previous output
__s = WSApplication.input_box(__ret,winName,"")
__s == nil ? __s = "" : nil
end
end
launchREPL
的修正版本,作为另一个答案。我仍然不建议使用它。这个实现是有漏洞的,可能不够健壮。 - Aleksei Matiushkin