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
.