Paralelní tasky
Jistě si vybavíte bezpočet případů, kdy by se hodilo spouštět některé úkoly paralelně. V Rake to je snadné – stačí použít metodu multitask:
multitask :backup_all => [:backup_src, :backup_doc, :backup_bin]
Tím bude :backup_src, :backup_doc a :backup_bin spuštěno současně, tedy každé ve svém threadu. Stejně jako metodě task, i metodě multitask lze předat blok kódu, požadováno to však není.
Souborové tasky
Souborové tasky jsou tasky směřující k vygenerování určitého souboru. K jejich konstrukci slouží metoda file, které jako první parametr předáme jméno souboru, který chceme získat na výstupu. Pokud tento soubor již existuje, Rake to zjistí a task nebude vykonán:
file "index.html" do
touch "index.html"
STDERR.puts("Your index.html is ready!")
end
rubybook> rake index.html (in /Users/botanicus/Documents/Publications/RubyBook) Your index.html is ready! rubybook> rake index.html (in /Users/botanicus/Documents/Publications/RubyBook) rubybook>
Souborové tasky mohou záviset na dalších souborech. Podmínka pro vykonání tasku je pak rozšířena o klauzuli „task bude proveden, pokud výstupní soubor ještě neexistuje, a nebo jsou soubory uvedené v závislostech mladšího data než soubor výstupní”:
content = FileList["#{document}.tex", "chapters.tex", "chapters/**/*.tex"]
desc "Typeset the #{document}.pdf."
file "#{document}.pdf" => content do
sh("texexec #{document}")
end
Zde je možná na místě udělat drobnou odbočku k metodě uptodate? z FileUtils, která nám může povědět, zda je soubor novější než ostatní dotazované soubory, která lze metodě předat například jako pole. Výše uvedený úkol bychom „klasickou” cestou přes metodu task implementovali takto:
content = FileList["#{document}.tex", "chapters.tex", "chapters/**/*.tex"]
desc "Typeset the #{document}.pdf."
task :build do
sh("texexec #{document}") unless uptodate?("#{document}.pdf", content)
end
Osobně považuji alternativu s file za rozumnější, čitelnější a čistší, ale metodu uptodate? je rozhodně vhodné znát, poměrně často se (nejen) v Rake hodí.
uptodate? a nikoliv FileUtils.uptodate? s předcházejícím požadavkem na nahrání FileUtils. Je tomu tak proto, že FileUtils již nahrané jsou ( require) a navíc jsou inkludovány do namespace Objectu ( include). Rake na FileUtils hodně staví a samo si je i rozšiřuje. O úpravách FileUtils v Rake bude řeč v příštím díle. V některých případech by bylo zbytečné tvořit souborový task pro každý ze souborů. Od toho slouží pravidla, která jsou konstruována metodou rule:
rule '.o' => ['.c'] do |task|
sh %{cc #{task.source} -c -o #{task.name}}
end
Jak jste jistě pochopili, task.source vrací jméno zdrojového souboru, kdežto task.name zase jméno tasku, které je v našem případě shodné s jménem výstupního souboru.
Metodě rule lze krom přípony předat i například celý regulární výraz. Možnosti pravidel jsou velmi komplexní, zájemce tedy odkazuji na dokumentaci.
Vzhledem k tomu, že v Rake máte k dispozici komplexní možnosti jazyka Ruby, je také možné tvořit tasky v průchodu cyklem each. To může být často velmi užitečné. Například metodu rule bychom mohli pro náš výše uvedený příklad stejně dobře zastoupit procházením všech souborů s příponou .o, tvorbou souborového tasku z jeho jména a jeho kompilaci z jemu příslušejícímu zdrojovému souboru. Ačkoliv tento konkrétní případ řeší přímočařejší cestou metoda rule, jsou případy, kdy řešení s each oceníme.
Příště
Protože jsme se dnes proti očekávání již nedostali na velmi užitečnou třídu FileList, věnovat se jí budeme příště. Povíme si také pár slov o knihovně FileUtils, která je jednak pro použití v Rake velmi užitečná, ale hlavně si ji Rake rozšiřuje, takže FileUtils v Rakefile umí více než běžné FileUtils.