2011-07-03 34 views
1

我想爲以下多個目錄使用Rake任務。每個目錄都需要定義稍微不同的常量。我該如何處理並保持乾爽?靈活的Rake任務

namespace :assets do 
    EXT  = 'js' 
    OBJDIR = 'public/javascripts' 
    LIBFILE = "#{OBJDIR}/packaged.#{EXT}" 
    SRC  = FileList["#{OBJDIR}/*.#{EXT}"].select {|file| !file.match(/\.min\.#{EXT}|packaged\.#{EXT}/)} 
    OBJ  = SRC.collect {|fn| File.join(OBJDIR, File.basename(fn).ext("min.#{EXT}"))} 
    MINE = %w(4sq app fb mbp).collect {|x| x + ".#{EXT}"} 

    desc "Build #{LIBFILE}" 
    task :build => LIBFILE 

    desc "Remove minified files" 
    task :clean do 
    rm_f OBJ 
    end  

    desc "Remove #{LIBFILE}" 
    task :clobber do 
    rm_f LIBFILE 
    end 

    file LIBFILE => OBJ do 
    sh "cat #{OBJ} >> #{LIBFILE}" 
    end 

    rule ".min.#{EXT}" => lambda{ |objfile| find_source(objfile) } do |t| 
    if EXT == 'js' 
     if MINE.include?(File.basename(t.source)) 
     sh "closure --js #{t.source} --js_output_file #{t.name}" 
     else 
     sh "closure --warning_level QUIET --third_party --js #{t.source} --js_output_file #{t.name}" 
     end 
    elsif EXT == 'css' 
     sh "yuicompressor #{t.source} -o #{t.name}" 
    end 
    end 

    def find_source(objfile) 
    base = File.basename(objfile, ".min.#{EXT}") 
    SRC.find {|s| File.basename(s, ".#{EXT}") == base} 
    end 
end 

回答

1

有了您的幫助,我終於想通了。以下是目前爲止我所做的工作:

namespace :assets do 
    task :set, [:ext, :objdir] do |t, args| 
    @ext = args.ext 
    @objdir = args.objdir 
    @bundle = "#{@objdir}/bundle.#{@ext}" 
    @src = FileList["#{@objdir}/*.#{@ext}"].select {|file| !file.match(/\.min\.#{@ext}|#{Regexp.escape(@bundle)}/)} 
    @min = @src.collect {|fn| File.join(@objdir, File.basename(fn).ext("min.#{@ext}"))} 

    Rake::Task.define_task 'assets:build' => @bundle 

    Rake::FileTask.define_task @bundle => @min do 
     sh "cat #{@min} > #{@bundle}" 
    end 

    Rake::Task.create_rule ".min.#{@ext}" => lambda{ |objfile| find_source(objfile) } do |t| 
     if @ext == 'js' 
     if @mine.include?(File.basename(t.source)) 
      sh "closure --js #{t.source} --js_output_file #{t.name}" 
     else 
      sh "closure --warning_level QUIET --third_party --js #{t.source} --js_output_file #{t.name}" 
     end 
     elsif @ext == 'css' 
     sh "yuicompressor #{t.source} -o #{t.name}" 
     end 
    end 
    end 

    desc "Remove minified files" 
    task :clean do 
    rm_f @min 
    end  

    desc "Remove bundle" 
    task :clobber do 
    rm_f @bundle 
    end 

    def find_source(objfile) 
    base = File.basename(objfile, ".min.#{@ext}") 
    @src.find {|s| File.basename(s, ".#{@ext}") == base} 
    end 
end 
3

首先,您必須通過變量替換常量。 接下來的問題是設置變量。 任務可以獲取變量。

例子:

namespace :assets do |x1,x2| 
    task :doit, :ext, :objdir do |tsk, args| 
    puts tsk 
    p args 
    end 
end 

你可以把它叫做:

rake assets:doit[js,objdir] 

結果:

assets:doit called with {:ext=>"js", :objdir=>"objdir"} 

如果你想避免設置變量爲每個任務,你可以添加一個'設置'任務:

namespace :assets2 do |x1,x2| 
    task :set, :ext, :objdir do |tsk, args| 
    @args = args 
    puts "#{tsk} set: #{@args.inspect}" 
    end 
    task :doit do |tsk| 
    puts "#{tsk} called with #{@args.inspect}" 
    end 
end 

電話: 耙assets2:設置[JS,objdir] assets2:DOIT

結果:

assets2:set set: {:ext=>"js", :objdir=>"objdir"} 
assets2:doit called with {:ext=>"js", :objdir=>"objdir"} 

而不是設置的所有參數,你可以定義配置文件。

有一個缺點。以下任務不起作用:

rake assets:doit[js,objdir] assets:doit[c,objdir2] 

資產:doit會被調用一次。第二個調用被忽略,任務已經被執行。沒有檢查不同的參數(這其中的一個解決方案:也許你可以重置任務)

編輯:我發現並測試了「reset'法:你只需要添加tsk.reenable

namespace :assets do |x1,x2| 
    task :doit, :ext, :objdir do |tsk, args| 
    puts "#{tsk} called with #{args.inspect}" 
    tsk.reenable 
    end 
end 

另一個問題:如果你的參數包含空格。你可能會遇到麻煩。

============== 代碼的通用生成規則的:(見註釋)

namespace :assets3 do |x1,x2| 
    task :set, :ext, :objdir do |tsk, args| 
    @args = args 
    @src = FileList["*.rb"] 

    puts "#{tsk} set: #{@args.inspect}" 

    #Define rule, when extension is set. 
    rule ".min.#{@args[:ext]}" => lambda{ |objfile| find_source(objfile) } do |t| 
     puts "#{t} called with #{@args.inspect}" 
    end 

    end 

    task :doit do |tsk| 
    puts "#{tsk} called with #{@args.inspect}" 
    end 

    def find_source(objfile) 
    base = File.basename(objfile, ".min.#{@args[:ext]}") 
    #If nothing is found, rake will abort with 'can't convert nil into String (TypeError)' 
    #If I return '' in this case, I get 'Don't know how to build task 'test.min.js' (RuntimeError)' 
    @src.find {|s| File.basename(s, ".#{@args[:ext]}") == base} || '' 
    end 

end 
+0

感謝您的幫助,我非常樂意幫助您。我試過這個,但它似乎沒有工作。 'file'任務似乎沒有以這種方式正確定義,'build'任務也沒有得到定義的依賴關係。 –

+0

我得到這個錯誤:'檢測到循環依賴:TOP => assets:build => =>' –

+0

看來這些變量只能在任務定義中使用。 –