我有许多Ruby文件,每个文件声明一个Class
,但每个文件都可以从命令行运行.
我想将以下功能放在每个文件的底部,尽可能减少重复:
if __FILE__ == $0 # instantiate the class and pass ARGV to instance.run end
我的第一直觉是这样做:
# /lib/scriptize.rb: Kernel.class_eval do def scriptize(&block) block.call(ARGV) if __FILE__ == $0 end end # /lib/some_other_file.rb: include 'scriptize' class Foo # ... end scriptize { |args| Foo.new.run(args) }
但这不起作用因为__FILE__
被评估scriptize.rb
,所以它永远不会 Foo.
我想解决方案是字面上内容scriptize.rb
,但我不知道语法.我可以使用eval
,但这仍然是相当多的重复 - 它不能真正简化为我添加的方法Kernel
.
尝试评估它.
eval(IO.read(rubyfile), binding)
这就是Rails的初始化程序在加载文件时所做的事情config/environments
,因为它需要在Rails::Initializer.run
块中对它们进行评估.
binding
是一个ruby方法,它将返回当前上下文,当传递给eval
它时,会使它评估调用环境中的代码.
试试这个:
# my_class.rb class MyClass def run puts 'hi' end end eval(IO.read('whereami.rb'), binding) # whereami.rb puts __FILE__ $ ruby my_class.rb my_class.rb