ruby:如何在本地上下文中加载.rb文件
如何在Ruby中完成这个简单的任务?ruby:如何在本地上下文中加载.rb文件,ruby,variables,scope,load,local,Ruby,Variables,Scope,Load,Local,如何在Ruby中完成这个简单的任务? 我有一些简单的配置文件 === config.rb config = { 'var' => 'val' } class App def loader config = eval(File.open(File.expand_path('~/config.rb')).read) p config['var'] end end 我想从main.rb文件中定义的某个方法加载配置文件,以便config.rb中的局部变量成为该方法的局部
我有一些简单的配置文件
=== config.rb
config = { 'var' => 'val' }
class App
def loader
config = eval(File.open(File.expand_path('~/config.rb')).read)
p config['var']
end
end
我想从main.rb
文件中定义的某个方法加载配置文件,以便config.rb
中的局部变量成为该方法的局部变量。大概是这样的:
=== main.rb
Class App
def loader
load('config.rb') # or smth like that
p config['var'] # => "val"
end
end
我知道我可以在
config.rb
中使用全局变量,然后在完成后取消定义它们,但我希望有一种ruby方法)您当然可以使用eval和File.read找到一个解决方案,但事实上这很难,这应该会给您一个信号,即这不是解决问题的ruby方式。两种可选设计是将yaml用于配置api,或者定义一个简单的dsl
YAML案例是最简单的,您只需在main.rb中使用类似的内容:
Class App
def loader
config = YAML.load('config.yml')
p config['var'] # => "val"
end
end
您的配置文件如下所示:
---
var: val
我不建议这样做,除非是在受控环境中 将模块保存到具有预定义名称的文件中,该文件定义了
初始化
和运行它
方法。对于本例,我使用test.rb作为文件名:
module Test
@@classvar = 'Hello'
def initialize
@who = 'me'
end
def get_who
@who
end
def run_it
print "#{@@classvar} #{get_who()}"
end
end
然后编写一个简单的应用程序来加载并执行它:
require 'test'
class Foo
include Test
end
END {
Foo.new.run_it
}
# >> Hello me
仅仅因为你能做某事并不意味着你应该做。我想不出为什么我会在制作中这样做,而只是在这里展示它作为一种好奇心和概念的证明。将此代码提供给不认识的人将是让您的计算机遭到黑客攻击的一个好方法,因为代码可以做拥有帐户的人可以做的任何事情。配置文件
{ 'var' => 'val' }
加载配置文件
=== config.rb
config = { 'var' => 'val' }
class App
def loader
config = eval(File.open(File.expand_path('~/config.rb')).read)
p config['var']
end
end
我只需要做一件类似的事情,因为我想能够加载一个“Ruby DLL”,它返回一个匿名类(一个实例的工厂),我创建了这个类,它跟踪已经加载的项,并允许加载的文件返回一个值,可以是任何值-一个完全匿名的类、模块,数据等。它可以是一个模块,您可以在加载对象后将其“包含”在对象中,并且可以提供大量“属性”或方法。您还可以添加一个“unload”项,将其从加载的散列中清除,并取消对其加载的任何对象的引用
module LoadableModule
@@loadedByFile_ = {};
def self.load(fileName)
fileName = File.expand_path(fileName);
mod = @@loadedByFile_[fileName];
return mod if mod;
begin
Thread.current[:loadReturn] = nil;
Kernel.load(fileName);
mod = Thread.current[:loadReturn];
@@loadedByFile_[fileName] = mod if(mod);
rescue => e
puts(e);
puts(e.backtrace);
mod = nil;
end
Thread.current[:loadReturn] = nil;
mod
end
def self.onLoaded(retVal)
Thread.current[:loadReturn] = retVal;
end
end
在加载的文件中:
LoadableModule.onLoaded("a value to return from the loaded file");
正如其他人所说,对于配置,最好使用YAML或JSON。评估文件
binding.eval(File.open(File.expand_path('~/config.rb'))。读“config.rb”)
binding.eval(File.read(File.expand_path('~/config.rb'),“config.rb”)
此语法允许您在回溯中查看文件名,这一点很重要。参见api文档[1]
更新了eval
命令以避免FD(文件描述符)泄漏。我一定是睡着了,或者我应该在晚上的那个时候睡觉,而不是在桌子上写字
[1] Yaml不起作用:config.rb只是一个例子——应该有一些处理——而不仅仅是序列化数据。事实上,我需要一个简单的命令“exec\u file\u as\u it\u在这里键入(file)”。顺便说一句,php可以做到这一点)而且,dsl,尤其是eval不是变体。至少现在是这样。我只想让事情保持简单。简短的版本是ruby不能做到这一点,较长的版本是你应该定义和执行DSL,而不是依靠一个聪明的黑客来确定范围。“php可以做到这一点”。。。尽量不尖叫。。。互联网上有数不清的网站证明PHP可以做到这一点,这导致我们其他人诅咒允许它的程序员。你可以用eval来做,但这不是一个好主意(在任何语言中)。有沙盒允许你在控制器环境中执行代码,因此,我将投票支持该方法,以弥补您的不足,但正如您自己所见,这是一个比“php风格”更冗余的解决方案……我对元编程不是特别热情,但php对我来说是地狱。我认为像ruby这样强大的动态工具可以完成如此原始的任务。坏消息。不可能。谢谢大家的关注!您可能需要将行
require'test'
更改为require./test'