灵活的佣金任务

时间:2011-07-03 15:58:13

标签: ruby 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

2 个答案:

答案 0 :(得分: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

呼叫:     rake assets2:set [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将被调用一次。第二个调用被忽略,任务已经执行。没有检查不同的参数(一个解决方案:也许你可以重置任务)

编辑:我发现并测试了'重置'方法:你只需要添加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

答案 1 :(得分: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