Hlavní navigace

Utilitky pro Ruby: buildovací systém Rake III

Jakub Šťastný

Metoda task není zdaleka jedinou možností tvorby úkolů. Řeč bude jak o tascích umožňující spouštět úlohy paralelně, tak o tascích souborových, které se používají například pro rozdílové kompilace. Povíme si něco i o pravidlech, která definují akce pro více souborů zároveň.

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?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í.

Asi vás zarazilo, že volám přímo 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.

Odkazy

Našli jste v článku chybu?