Rake 201

In questo secondo articolo su Rake, ci immergiamo un po 'più in profondità e trattiamo argomenti leggermente avanzati come le attività sui file, le regole, i multitasks e molto altro ancora che miglioreranno in modo significativo i tuoi chop Rake.

Temi

  • disconoscimento
  • Task predefinito
  • L'oggetto compito
  • Attività file
  • Metodo di directory
  • File Utilities
  • Regole
  • Trace Flag
  • Attività parallele

disconoscimento

Voglio affrontare questo argomento da un punto di vista più generale. Questo non è un articolo che ti mostra una lista di attività di Rake con soluzioni intelligenti che sono pronte per essere copiate e incollate senza troppo ripensamenti. È più destinato ad essere uno sguardo sotto il cofano pur essendo newbie-friendly e anche interessante per le persone che non hanno ancora giocato molto con Rake oltre agli ovvi compiti di Rake in Rails. 

È la comprensione dello strumento e ciò che offre un rendimento più alto, penso. Spero non ti dispiaccia. Per me, coprire i principi è più prezioso e più accessibile ai principianti, e sta a te decidere cosa farai con le tue applicazioni.

Task predefinito

Sono sicuro che hai almeno sentito il termine precedentemente da qualche parte. Ma quale è un compito predefinito in realtà? Non è niente di magico, ma liberiamoci di questo in fretta. Quando corri rastrello senza alcun nome aggiuntivo per un'attività rake, l'attività predefinita viene eseguita.

Conchiglia

rastrello

Alcuni Rakefile

desc 'Questa è l'attività predefinita. Nessun argomento necessario 'task: default fa' Termine di alcuni task che potresti voler eseguire su base regolare '

In Rails, l'attività predefinita dovrebbe eseguire i test. La tua ipotesi è buona come la mia, ma suppongo che sia il risultato di test che devono essere eseguiti più spesso di qualsiasi altro compito. Quando ridefinite il predefinito Rastrella il compito in Rails, si limita al compito definito da Rails-non lo ridefinirà. In realtà è così che funziona Rake. Quando ridefinisci un'attività di Rake, aggiungi le definizioni precedenti.

Attività file

Come suggerisce il nome, sono compiti che esegui su file (e directory). Tuttavia hanno qualche asso nella manica. Ovviamente Rake lavorerà molto con i file. Non sorprende che qualcuno abbia riconosciuto questo modello e creato attività di file specializzate per la vostra convenienza, soprattutto per il semplice motivo di evitare duplicazioni o sprechi di capacità di elaborazione.

Trasformare file da un tipo all'altro è un'attività molto comune. Le fonti sono le tue dipendenze e i nomi delle attività sono le seguenti file parola chiave. Conversione di Markdown in file HTML, conversione di file HTML in formati di ebook, immagini JPG in immagini PNG, compilazione di codice sorgente, creazione di pagine statiche o semplicemente modifica delle estensioni di file e molte altre opzioni sono a vostra disposizione. Potremmo fare tutto questo manualmente, ma questo è noioso e inefficace, ovviamente. Scrivere codice per questo è molto più elegante e scalabile.

L'utilizzo delle attività sui file non è molto diverso dalle attività "regolari". Verranno visualizzati anche se richiedi un elenco di attività di Rake tramite rastrello -T. In effetti, Rake tratta tutte le attività allo stesso modo, tranne multitasking un po. Aggiungere descrizioni e prerequisiti non è un problema anche per le attività dei file. 

In realtà, i prerequisiti sono una necessità per menzionare i file di origine prima che vengano elaborati. Abbiamo bisogno che la fonte esista perché funzioni, il che ha senso in quanto dipendenza, ovviamente. Senza di esso, Rake non saprebbe come continuare, dopotutto non è possibile creare il nuovo file dal nulla.

Alcuni Rakefile

file 'mi6 / q / gadgets / secret_list.md' => 'mi6 / research / secret_list.md' do cp 'mi6 / research / secret_list.md', 'mi6 / q / gadgets / secret_list.md' fine

Il nome dell'attività del file è fondamentalmente il file di destinazione, il file che si desidera creare. Il prerequisito è il file di origine necessario per l'attività. All'interno del blocco, stai dicendo a Rake come creare l'output desiderato: come costruirlo usando i file prerequisiti che esistono già. Input Output. Ad esempio, questo potrebbe essere un comando di shell che usa il Pandoc strumento che trasforma i file Markdown in file HTML. Le applicazioni per le attività sui file sono più che abbondanti. La sintassi, però, potrebbe sembrare un po 'strana all'inizio. capisco.

Rake controlla innanzitutto se il file di destinazione esiste e, in caso affermativo, controlla se il timestamp è precedente ai file prerequisiti, una dipendenza basata sul tempo. Rake eseguirà l'attività file se il timestamp è precedente ai prerequisiti o se il file non esiste ancora. Ciò è molto utile se devi gestire più di un paio di file, il che è particolarmente interessante perché non dovrai ricostruire un sacco di file solo perché ne hai modificato uno solo in una raccolta, ad esempio. Al contrario, le normali attività di Rake sono sempre eseguite, non controllano alcun timestamp o altre modifiche, a meno che non le facciate così, ovviamente.

File Utilities

Alcuni Rakefile

desc 'Cambia alcuni file extension' file 'some_file.new_extension' => 'some_file.old_extension' do mv 'some_file.old_extension', 'some_file.new_extension' end

Conchiglia

$ rake some_file.new_extension => mv some_file.old_extension some_file.new_extension

Nel caso ti stia chiedendo il cp metodo nell'esempio precedente o sopra mv comando, parliamo di utilità per i file. Avremmo potuto usarlo sh mv ... per eseguire un comando Shell da un'attività Rake. Fortunatamente per noi, possiamo usare un modulo che rende i comandi di Shell di questo tipo molto meno prolissi e indipendenti dalla piattaforma. fileutils è un modulo Ruby con molti comandi unixy per le operazioni sui file: 

  • rm 
  • cp 
  • mv
  • mkdir
  • e così via…

Se reinventare la ruota non fa per te, FileUtils sarà un utile compagno per i file. Spesso Rake è tutto ciò di cui hai bisogno, ma ogni tanto sarai felice che questo pratico modulo ti abbia dato le spalle. RakeUtils esteso questo modulo leggermente per la vostra convenienza. 

Diamo un'occhiata a un elenco di ciò che è a tua disposizione e quindi ingrandisci alcuni particolari che potrebbero interessarti:

cd (dir, options) cd (dir, options) | dir | ... pwd () mkdir (dir, options) mkdir (lista, opzioni) mkdir_p (dir, options) mkdir_p (list, options) rmdir (dir, options ) rmdir (lista, opzioni) ln (vecchio, nuovo, opzioni) ln (lista, destdir, opzioni) ln_s (vecchio, nuovo, opzioni) ln_s (lista, destdir, opzioni) ln_sf (src, dest, opzioni) cp (src , dest, options) cp (list, dir, options) cp_r (src, dest, options) cp_r (list, dir, options) mv (src, dest, options) mv (lista, dir, opzioni) rm (lista, opzioni ) rm_r (lista, opzioni) rm_rf (lista, opzioni) install (src, dest, mode = , opzioni) chmod (modalità, elenco, opzioni) chmod_R (modalità, elenco, opzioni) chown (utente, gruppo, elenco, opzioni) chown_R (utente, gruppo, elenco, opzioni) touch (elenco, opzioni)

Anche se presumo che tu sia un principiante, presumo anche che tu abbia già giocato con Rails e che tu conosca le utility di base Unix, cose come mv, CD, pwd, mkdir e cose. Altrimenti, fai i compiti e torna indietro. 

Nei tuoi RakeFiles puoi utilizzare questi metodi fin da subito. E per evitare fraintendimenti, questo è un livello di Ruby che "imita" questi comandi Unix e che puoi usare nei tuoi RakeFiles senza prefissi come sh-per l'esecuzione di un comando Shell. A proposito, il opzioni vedi nella lista sopra significa un hash di opzioni. Diamo un'occhiata ad alcuni comandi interessanti che potrebbero rivelarsi utili per scrivere attività sui file:

  • sh

Questo ti permette di eseguire i comandi della shell all'interno dei tuoi file Ruby.

  • CD

Questo è molto semplice, ma c'è qualcosa di interessante in questo comando. Se fornisci CD con un blocco, cambia la directory corrente nella sua destinazione, svolge la sua attività come definita nel blocco e quindi torna alla directory di lavoro precedente per continuare. Neat, in realtà!

  • cp_r

Consente di copiare file e directory in modo ricorsivo in blocco.

  • mkdir_p

Crea una directory di destinazione e tutti i suoi genitori specificati. Fortunatamente per noi, abbiamo il elenco metodo in Rake, che è ancora più conveniente, e quindi non ne abbiamo bisogno.

  • toccare

Questo aggiorna il timestamp di un file, se esiste, altrimenti viene creato.

  • identico?

Consente di controllare se due file sono uguali.

Metodo di directory

In Rake, hai un modo pratico per definire le directory senza usare mkdir o mkdir_p. È particolarmente utile quando è necessario creare directory annidate. Un albero di cartelle può essere un problema se è necessario creare una struttura di directory tramite più attività di file che hanno tonnellate di prerequisiti per la struttura di directory. Pensa al elenco metodo come attività di cartella.

Alcuni Rakefile

directory 'mi6 / q / special_gadgets'

Questo crea le directory in questione senza troppi problemi. Ciò che potrebbe non essere ovvio è il fatto che si può fare affidamento su di esso come qualsiasi altro rake-come prerequisito. Assicurati solo che il nome dell'attività del file, il suo nome, includa la directory da cui dipendi. Se più attività dipendono da esso, verrà comunque creato una sola volta.

directory 'mi6 / q / gadget' desc 'Trasferisci gadget di ricerca segreti' file 'mi6 / q / gadget / gadget_list.md' => 'mi6 / q / gadget' fai cp 'gadget_list.md', 'mi6 / q / special_gadgets /secret_gadget_list.md 'fine

Come puoi vedere qui, Rake è molto coerente e pensa a tutte le cose da costruire come attività. Grazie, Jim, questo rende la vita facile!

Regole

Le regole possono aiutarci a ridurre le duplicazioni quando ci occupiamo delle attività dei file, in realtà. Invece di istruire Rake per eseguire compiti su file particolari come somefile.markdown, possiamo insegnare a Rake ad eseguire queste attività su un certo tipo di file, come un modello o un progetto. Trasformare un insieme di file anziché singoli è un approccio molto più versatile e ASCIUTTO. Attività come queste si adattano molto meglio quando definiamo un modello per file che condividono caratteristiche simili.

Alcuni Rakefile

file "quartermaster_gadgets.html" => "quartermaster_gadgets.markdown" do sh "pandoc -s quartermaster_gadgets.markdown -o quartermaster_gadgets.html" fine

Come puoi vedere, avere un sacco di file sarebbe noioso mantenere questo modo. Sì, possiamo scrivere il nostro script in cui teniamo un elenco di file in un array e iteriamo su di esso, ma possiamo fare di meglio, molto meglio. 

Un altro effetto indesiderato sarebbe che ogni volta che eseguiamo un tale script, tutti i file HTML vengono ricostruiti, anche se non sono stati modificati affatto. Un ampio elenco di file ti farebbe aspettare molto più tempo o impiegare molte più risorse del necessario. Non abbiamo bisogno di alcun codice aggiuntivo per prendersi cura di più file. Rake svolge un lavoro migliore e più efficiente in quel dipartimento, poiché esegue le sue attività o regole sui file solo quando il file è stato toccato nel frattempo.

Alcuni Rakefile

regola ".html" => ".markdown" do | regola | sh "pandoc -s # rule.source -o # rule.name" fine

Quando definiamo una regola come sopra, abbiamo un meccanismo in atto per trasformare qualsiasi file con a .riduione di prezzo estensione in un .html file. Con le regole, Rake cerca innanzitutto un'attività per un file specifico come quartermaster_gadgets.html. Ma quando non riesce a trovarne uno, sta usando la pianura .html regola per cercare una fonte che potrebbe raggiungere l'esecuzione di successo. In questo modo non è necessario creare un lungo elenco di file, ma solo utilizzare una "regola" generale che definisce come gestire determinate attività di file. Abbastanza bello!

Task Object

Nella regola precedente, stavamo facendo uso dell'oggetto task, in questo caso un oggetto rule, per essere ancora più preciso. Possiamo passarlo come argomento di blocco nella chiusura e chiamare i metodi su di esso. Come per le attività sui file, le regole riguardano tutte le origini delle attività, le sue dipendenze, ad esempio un file di svalorizzazione, e il relativo nome dell'attività. 

Dal corpo delle regole nel blocco (e dalle attività sui file), abbiamo accesso al nome e alla fonte delle regole. Possiamo estrarre informazioni da quell'argomento passato, il nome attraverso rule.name e la sua fonte (aka file source) via rule.source. Sopra, potremmo evitare di duplicare i nomi dei file e generalizzare invece un pattern. Allo stesso modo, potremmo ottenere l'elenco dei prerequisiti o delle dipendenze rules.prerequisites. Per le attività su file o qualsiasi altra attività, lo stesso vale, ovviamente.

Parlando di dipendenze, possono funzionare come una lista da iterare. Non è necessario creare un separato ogni loop se giochi bene le tue carte. 

task: html =>% W [quartermaster_gadgets.html, research_gadgets.html] regola ".html" => ".md" do | r | sh "pandoc -s # r.source -o # r.name" fine

Come puoi vedere, non è stato necessario scorrere manualmente l'elenco degli articoli. Abbiamo semplicemente messo Rake al lavoro e utilizzato le dipendenze, il che è molto più semplice e più pulito.

Ciò che è ancora più interessante per DRYing è che le regole possono prendere un oggetto proc, un oggetto funzione anonimo, un lambda fondamentalmente, come un prerequisito. Ciò significa che invece di un solo pattern come prerequisito, possiamo passare qualcosa di più dinamico che ci consenta di creare una rete di pattern che catturi più di un singolo pesce. Ad esempio, regole per .riduione di prezzo e .md File. 

Avrebbero lo stesso corpo della regola, ma solo un modello diverso come prerequisito. È come definire una nuova attività File per ogni oggetto restituito dall'oggetto proc. Un altro modo di lavorare con le regole sono le espressioni regolari, ovviamente. Si passa un modello come dipendenza e se si ottiene una corrispondenza, è possibile eseguire l'attività del file. Opzioni dolci, no?

some_markdown_list = [...] detect_source = proc do | html_file_name | some_markdown_list.detect | markdown_source | markdown_source.ext == html_file_name.ext end rule '.html' => detect_source do | r | sh "pandoc -s # r.source -o # r.name" fine

La differenza tra procs e lambda

Se sei nuovo a lambda land o non l'hai ancora capito completamente, ecco un piccolo aggiornamento. I Proc sono oggetti che puoi passare e che possono essere eseguiti in seguito, così come i lambda. Entrambi sono oggetti Proc, comunque. La differenza è sottile e si riduce agli argomenti che sono passati in loro. Lambdas controlla il numero di argomenti e può saltare in aria con un ArgumentError per quel motivo non ci importa. L'altra differenza riguarda la gestione delle dichiarazioni di reso. I processi escono dall'ambito in cui è stato eseguito l'oggetto proc. Lambdas esce dalla lambda scope e continua ad attivare il prossimo codice che è in linea, per così dire. Non è molto importante qui, ma ho pensato per i neofiti tra di voi, non può ferire nessuno dei due.

Bandiere utili

Questa è una breve lista di flag che puoi passare alle attività di rake.

  • --regole

Mostra come Rake cerca di applicare le regole: una traccia per le regole. Inestimabile se ti occupi di un paio di regole e incappi in bug.

Conchiglia

$ rake quartermaster_gadgets.html --rules Attempting Rule quartermaster_gadgets.html => quartermaster_gadgets.md (quartermaster_gadgets.html => quartermaster_gadgets.md ... ESIST) pandoc -s quartermaster_gadgets.md -o quartermaster_gadgets.html
  • -t

Ricorda il solve_bonnie_situation compito dall'articolo uno? Aggiungiamo questo flag a questa attività di Rake e attiviamo la traccia. Otteniamo anche un backtrace se ci imbattiamo in errori. Questo è certamente utile per il debug.

Conchiglia

$ rake solve_bonnie_situation -t ** Invoke solve_bonnie_situation (first_time) ** Invoke get_mr_wolf (first_time) ** Esegui get_mr_wolf Non hai nessun problema Jules, ci sono! Entra li e rilassali e aspetta il lupo che dovrebbe venire direttamente! ** Invoca calm_down_jimmy (first_time) ** Esegui calm_down_jimmy Jimmy, fammi un favore, vuoi? Ho sentito un po 'di caffè laggiù. Mi faresti una tazza? ** Richiama figure_out_bonnie_situation (first_time) ** Esegui figure_out_bonnie_situation Se sono stato informato correttamente, l'orologio sta ticchettando. È giusto Jimmy? ** Invoke get_vince_vega_in_line (first_time) ** Esegui get_vince_vega_in_line Vieni di nuovo? Ottienilo dritto. Non sono qui per dire per favore! Sono qui per dirti cosa fare! ** Richiama clean_car (first_time) ** Esegui clean_car Ho bisogno di te due ragazzi per prendere quei prodotti per la pulizia e pulire l'interno dell'auto. Sto parlando veloce, veloce, veloce! ** Invoca clean_crew (first_time) ** Esegui clean_crew Jim, il sapone! OK. signori, siete stati entrambi della contea prima che ne sia sicuro. Ecco che arriva! ** Richiama get_rid_of_evidence_at_monster_joes (first_time) ** Esegui get_rid_of_evidence_at_monster_joes Allora, qual è l'abbigliamento? Ragazzi state andando a una partita di pallavolo o qualcosa del genere? ** Richiamare drive_into_the_sunrise (first_time) ** Esegui drive_into_the_sunrise Chiamami Winston! ** Esegui solve_bonnie_situation Sai, andrei a fare colazione. Senti come fare colazione con me?

Regole di tracciamento

Ambientazione Rake.application.options.trace_rules = true in un Rakefile stesso dice a Rake di mostrarci informazioni sulle regole quando eseguiamo un'attività. Questo è bello perché quando eseguiamo una traccia via rastrello -t, con un singolo flag, otteniamo tutte le informazioni di debug di cui abbiamo bisogno. Non solo riceviamo un elenco di invocazioni delle attività, ma possiamo anche vedere quali regole sono state applicate o tentate.

  • -P

Mostra un elenco di prerequisiti per tutte le attività. Qui usiamo di nuovo il solve_bonnie_situation compito. Omettere l'output per altre attività, questo sarebbe il suo output evidenziato:

Conchiglia

$ rake solve_bonnie_situation -P ... rake solve_bonnie_situation get_mr_wolf calm_down_jimmy figure_out_bonnie_situation get_vince_vega_in_line clean_car clean_crew get_rid_of_evidence_at_monster_joes drive_into_the_sunrise ... 

Se sei curioso, corri rastrello -P. Uscita piuttosto interessante.

  • -m

Esegue attività come multitasks.

Attività parallele

Lascia che ti presenti al multitasking metodo. Questo può aiutarti ad accelerare un po 'le cose, dopotutto, abbiamo molti core nella maggior parte dei computer moderni, quindi usiamoli. Ovviamente, è sempre possibile ottenere aumenti di velocità scrivendo codice solido che non ha alcun grasso, ma eseguire attività in parallelo può certamente darti qualcosa in più a tale riguardo. Ci sono tuttavia delle insidie ​​che copriremo anche.

Le attività eseguite fino ad ora eseguono tutte le attività in sequenza, una dopo l'altra. È una scommessa sicura se il tuo codice è in ordine, ma è anche più lento. Se la velocità è importante per alcune attività, possiamo aiutare un po 'con le attività multi-thread. Tieni presente, tuttavia, che l'approccio sequenziale è l'opzione migliore in alcune circostanze.

Diciamo che abbiamo tre attività Rake che devono essere eseguite come prerequisito per poterne eseguire una quarta. Questi sono quattro thread, fondamentalmente. Nell'immagine più grande delle cose, quando si eseguono più applicazioni, o per essere più specifici, processi contemporaneamente, la stessa idea è al lavoro.

multitask: shoot_bond_movie => [: shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation] do puts "La fotografia principale è finita e possiamo iniziare a modificarla." fine

utilizzando multitasking, le dipendenze nel nostro array di prerequisiti ora non sono più eseguite in questo ordine. Invece, sono distribuiti e corrono in parallelo, ma prima del shoot_bond_movie compito, ovviamente. Un thread Ruby per ogni attività verrà eseguito contemporaneamente. Una volta finiti, shoot_bond_movie farà i suoi affari. Il modo in cui i compiti agiscono qui è simile alla randomizzazione, ma in realtà vengono semplicemente eseguiti allo stesso tempo.

La parte difficile è solo per assicurarsi che certe dipendenze vengano elaborate in un ordine che si adatta alle tue esigenze. Per questo motivo, dobbiamo occuparci delle condizioni di gara. Ciò significa fondamentalmente che alcune attività si sono incappate in problemi perché l'ordine di esecuzione ha avuto effetti collaterali indesiderati. È un bug. 

Se possiamo evitarlo, otteniamo la sicurezza del filo. Per quanto riguarda i prerequisiti comuni, è interessante notare che questi prerequisiti verranno eseguiti una sola volta perché i prerequisiti del multitask attendono il loro completamento prima.

task: shoot_love_scene do ... end task: prepare_italy_set do ... end task: shoot_car_chase => [: prepare_italy_set] do ... end task: shoot_final_confrontation => [: prepare_italy_set] do ... fine multitask: shoot_bond_movie => [: shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation ] do puts "La fotografia principale è terminata e possiamo iniziare a modificare". fine

Tutti e due shoot_car_chase e shoot_final_confrontation le attività dipendono da prepare_italy_set per finire in primo luogo, che è eseguito solo una volta, a proposito. Possiamo utilizzare tale meccanismo per prevedere l'ordine durante l'esecuzione di attività in parallelo. Non fidarti solo dell'ordine di esecuzione se è in qualche modo importante per il tuo compito.

Pensieri finali

Bene, immagino che ora tu sia completamente attrezzato per scrivere degli affari seri di Rake. Speriamo che fare buon uso di questo strumento renderà la tua vita da sviluppatore Ruby ancora più gioiosa. In questo secondo articolo, spero di poter trasmettere quello che è uno strumento semplice ma meraviglioso. È stato creato da un vero maestro del suo mestiere.  

Tutti dobbiamo a Jim Weirich un enorme rispetto per questo elegante strumento di costruzione. La comunità Ruby non è certo la stessa da quando è morto. L'eredità di Jim è chiaramente qui per restare, però. Un altro gigante su cui abbiamo il privilegio di costruire.