如何在Rake中处理单独目录中的输入和输出?

如何在Rake中处理单独目录中的输入和输出?,rake,Rake,我正在尝试使用Rake将Haml文件转换为HTML文件,这样,如果Haml文件没有更改,我就不会重新生成现有的HTML 但是,我不希望我的输入文件、输出文件和Rakefile都放在一个目录中。相反,我希望输入文件位于src/中,输出文件位于build/output/中。因此,我想从以下几点开始: Rakefile src/ slides.haml 最后我想说: Rakefile src/ slides.haml build/ output/ slides.html 我尝试

我正在尝试使用Rake将Haml文件转换为HTML文件,这样,如果Haml文件没有更改,我就不会重新生成现有的HTML

但是,我不希望我的输入文件、输出文件和
Rakefile
都放在一个目录中。相反,我希望输入文件位于
src/
中,输出文件位于
build/output/
中。因此,我想从以下几点开始:

Rakefile
src/
  slides.haml
最后我想说:

Rakefile
src/
  slides.haml
build/
  output/
    slides.html
我尝试了几段Rake代码,但没有成功

首先,我尝试了穴居人方法,对我正在尝试的精确文件进行硬编码:

task "build/output/slides.html" => "src/slides.haml" do
  touch task.name
end

task :slides => "src/slides.haml"
task :default => "slides"
运行
rake--trace
会导致:

** Invoke default (first_time)
** Invoke slides (first_time)
** Invoke src/slides.haml (first_time, not_needed)
** Execute slides
** Execute default
目录未生成,并且我没有空的
build/output/slides.html
文件

理想情况下,我更喜欢使用
规则
-和-
文件列表
方法,使用或之类的东西。然而,我尝试了一些关于这个主题的变化,我得到了相同的结果,这表明我有更严重的混乱。我把我的
耙形锉
修剪回穴居人的方法,只是想看看这里发生了什么


为什么Rake不能识别我的
“build/output/slides.html”
任务?在Rake中使用子目录(输入或输出)有什么神奇之处吗?

首先,任务被声明为
task:name=>dependency
。您的
:幻灯片
任务命名源,而不是输出依赖项。此外,您的
:默认
任务依赖于文件
“幻灯片”
,而不是任务
:幻灯片
。将这些行更改为

task :slides => "build/output/slides.html"
task :default => :slides
接下来,实际执行的代码块应该是规则,而不是任务,您可以通过
{t.}
访问规则的内部信息:

有更好的方法使规则更通用,建立源文件列表并将其映射到输出等。这里有一些有用的教程


如果
build/output/
目录不存在,可能还有更多类似Ruby的方法来创建它,而不是调用shell来实现它。

我不知道文件任务使用
file
而不是
task
,而且还有一个
目录
任务

穴居人方法的工作版本是:

namespace :build do
  directory "build/output"

  file "build/output/slides.html" => ["build/output", "src/slides.haml"] do |t|
    touch t.name
  end

  task :all => "build/output/slides.html"
end

task :default => ['build:all']

这是我今天总结的一些东西,我相信它能完成你想要完成的事情。首先,我定义
mv_rule
(可以在一个单独的ruby文件中导入
/
require
),然后为输出目录定义一个
目录
任务,最后创建一个描述输出模式(包括目录)和输入模式(包括目录)的规则

我可以使用
rake
运行它来执行
:default
任务。或者,由于我在适当的目录中指定了从
haml
生成
html
的一般规则,我可以使用
rake build/output/more\u slides.html
(假设存在
src/more\u slides.haml
)运行它

我有点惊讶,没有一种内置的方法来指定不同的输出目录。这似乎是一个相当普遍的情况


我制定了我的
mv_规则
,用一种非常直截了当的语法为这个问题提供了一个通用的解决方案。它可能有一些我还没有想到的局限性。我使用和获得灵感。

这项工作的非穴居人工具是
pathmap

SOURCES=FileList['src/*.haml']
目录“生成/输出”
规则'.html'do | t|
sh‘touch’,t.name
结束
任务:默认值=>['build/output',SOURCES.pathmap('build/output/%n.html')]
输出:

$ mkdir src && touch src/slides.haml
$ rake --trace
** Invoke default (first_time)
** Invoke build/output (first_time)
** Execute build/output
mkdir -p build/output
** Invoke build/output/slides.html (first_time)
** Execute build/output/slides.html
touch build/output/slides.html
** Execute default
对于此类任务,您可能还对
rake/clean
感兴趣,以便生成任务以将项目恢复到原始状态:

要求“耙/清理”
CLOBBER.include'build'#运行'rake CLOBBER'将删除生成目录

谢谢!我会给你赏金,主要是因为你触发了我(在试图弄清楚我在你的答案上哪里出了错的时候)注意到我的穴居人方法在哪里出了差错。
# Declare a rule for auto-tasks that have input and output in different directories
#
# Example:
#  mv_rule 'obj/*.o' => 'src/*.c' do |t|
#    sh "gcc -c #{t.source} -o #{t.name}"
#
def mv_rule(*args, &block) # :doc:
  outFile, inFile = args[0].keys[0], args[0].values[0]
  outExt = File.extname outFile
  outDir = File.dirname outFile
  inExt = File.extname inFile
  inDir = File.dirname inFile
  destPattern = Regexp.new("#{outDir}/.*\\#{outExt}")
  srcPattern = ->(o){o.pathmap("%{^#{outDir}/,#{inDir}/}X#{inExt}")}
  Rake::Task.create_rule(destPattern => [srcPattern, outDir], &block)
end

directory "build/output"

mv_rule 'build/output/*.html' => 'src/*.haml' do |t|
    touch t.name
end

task :all => "build/output/slides.html"

task :default => [:all]
$ mkdir src && touch src/slides.haml
$ rake --trace
** Invoke default (first_time)
** Invoke build/output (first_time)
** Execute build/output
mkdir -p build/output
** Invoke build/output/slides.html (first_time)
** Execute build/output/slides.html
touch build/output/slides.html
** Execute default