我需要:
这可以查找 Rakefile 中定义的任务,但它会污染全局命名空间(即,如果运行两次,第一个中定义的所有任务将显示在第二个中):
sub_rake = Rake::DefaultLoader.new
sub_rake.load("Rakefile")
puts Rake.application.tasks
在 Rake 中,这里是加载 Makefile 的位置:
https://github.com/ruby/rake/blob/master/lib/rake/rake_module.rb#L28
如何访问加载到那里的变量?
这是我正在解析的 Rakefile 示例:
load '../common.rake'
@source_dir = 'source'
desc "Run all build and deployment tasks, for continuous delivery"
task :deliver => ['git:pull', 'jekyll:build', 'rsync:push']
以下是我尝试过的一些方法,但没有成功。在 Rakefile 上使用
eval
:
safe_object = Object.new
safe_object.instance_eval("Dir.chdir('" + f + "')\n" + File.read(folder_rakefile))
if safe_object.instance_variable_defined?("@staging_dir")
puts " Staging directory is " + f.yellow + safe_object.instance_variable_get("@staging_dir").yellow
else
puts " Staging directory is not specified".red
end
解析 Rakefile 的
desc
部分时失败。我也尝试过类似的事情
puts Rake.instance_variables
puts Rake.class_variables
但是这些并没有得到我正在寻找的
@source_dir
。
rakefile_body = <<-RUBY
load '../common.rake'
@source_dir = 'some/source/dir'
desc "Run all build and deployment tasks, for continuous delivery"
task :deliver => ['git:pull', 'jekyll:build', 'rsync:push']
RUBY
def source_dir(ast)
return nil unless ast.kind_of? AST::Node
if ast.type == :ivasgn && ast.children[0] == :@source_dir
rhs = ast.children[1]
if rhs.type != :str
raise "@source_dir is not a string literal! #{rhs.inspect}"
else
return rhs.children[0]
end
end
ast.children.each do |child|
value = source_dir(child)
return value if value
end
nil
end
require 'parser/ruby22'
body = Parser::Ruby22.parse(rakefile_body)
source_dir body # => "some/source/dir"
Rake 在
load()
模块中的
load_rakefile
内的 Rakefile 上运行
Rake
。并且您可以通过公共API轻松获取任务。
Rake.load_rakefile("Rakefile")
puts Rake.application.tasks
显然,
load()
调用会导致加载的变量被捕获到main
Object
中。这是Ruby的顶级Object
。 (我预计它会被捕获到 Rake
中,因为 load
调用是在 Rake
模块的上下文中进行的。)
因此,可以使用以下丑陋的代码从
main
对象访问实例变量:
main = eval 'self', TOPLEVEL_BINDING
puts main.instance_variable_get('@staging_dir')
这里有一种封装 Rakefile 解析的方法,这样打开两个文件时,在分析第二个文件时就不会显示第一个文件的所有内容:
class RakeBrowser
attr_reader :tasks
attr_reader :variables
include Rake::DSL
def task(*args, &block)
if args.first.respond_to?(:id2name)
@tasks << args.first.id2name
elsif args.first.keys.first.respond_to?(:id2name)
@tasks << args.first.keys.first.id2name
end
end
def initialize(file)
@tasks = []
Dir.chdir(File.dirname(file)) do
eval(File.read(File.basename(file)))
end
@variables = Hash.new
instance_variables.each do |name|
@variables[name] = instance_variable_get(name)
end
end
end
browser = RakeBrowser.new(f + "Rakefile")
puts browser.tasks
puts browser.variables[:@staging_dir]
rake = Rake::Application.new
rake.load_rakefile
Rake::Task.tasks # Returns tasks