如何从Rakefile中提取任务和变量?

问题描述 投票:0回答:3

我需要:

  1. 打开 Rakefile
  2. 查找是否定义了某个任务
  3. 查找某个变量是否已定义

这可以查找 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

ruby rake
3个回答
1
投票
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"

0
投票

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]

0
投票
rake = Rake::Application.new
rake.load_rakefile
Rake::Task.tasks # Returns tasks
© www.soinside.com 2019 - 2024. All rights reserved.