2016-02-15 30 views
0

我需要:如何從Rakefile中提取任務和變量?

  1. 打開Rake文件
  2. 查找,如果某個任務被定義
  3. 查找,如果某個變量定義

這個工作找一個Rake文件中定義的任務,但它會污染全局命名空間(即,如果運行它兩次,則第一個中定義的所有任務將顯示在第二個任務中):

sub_rake = Rake::DefaultLoader.new 
sub_rake.load("Rakefile") 
puts Rake.application.tasks 

在耙,這裏是它加載的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'] 

這裏的一些事情,我試過,沒有工作。在Rake文件使用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 

這解析desc部分Rake文件時失敗。我也嘗試過類似的事情

puts Rake.instance_variables 
puts Rake.class_variables 

但這些都沒有得到,我尋找的@source_dir

+0

你能否提供一個示例Rakefile?很難說除此之外(即,如果var在任務中被定義,是否是有效的?你應該能夠純粹從語法中識別它,還是可以動態地構造這個值,要求你實際運行它?如果你能從語法,可能只是解析文件(解析器和ruby_parser gems都可以這樣做),否則,你可能不得不評估文件。但實際上,基於var名稱,它可能最好把它拉入某種配置文件然後從Rakefile和你的腳本中使用這個文件 –

+0

謝謝,剛剛添加了示例文件,現在我正在查看'ruby_parser'來查看這個文件是否能正常工作。 –

+0

我更新了,以顯示我曾嘗試過的內容,並且還顯示了Rake中確切的一行是負責獲取文件的負載,但我不知道如何獲取那些被加載的變量。 –

回答

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 module運行load()的Rake文件裏面load_rakefile。您可以使用公共API輕鬆獲取任務。

Rake.load_rakefile("Rakefile") 
puts Rake.application.tasks 

顯然的是load()調用導致加載的變量被捕獲到mainObject。這是Ruby的頂級Object。 (I預期它被捕獲到Rake由於load呼叫在Rake模塊的上下文製造)

因此,有可能使用這種醜陋的代碼從main對象訪問實例變量:

main = eval 'self', TOPLEVEL_BINDING 
puts main.instance_variable_get('@staging_dir') 

這裏是封裝Rake文件的解析,使得打開兩個文件將不具有所有從第一個節目,當你正在分析的第二個事情的方式:

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

我通過使用'ObjectSpace.each_object do | the.instance_variables.ea ch do | var |把var end end'發現變量確實存在* somewhere *。 –

+0

如果有人好奇,我在這裏使用這個:https://github.com/fulldecent/Sites –

相關問題