În acest al doilea articol despre Rake, ne scufundăm puțin mai adânc și acoperim subiecte ușor avansate, cum ar fi sarcini de fișier, reguli, mai multe sarcini și multe altele care vă vor îmbunătăți semnificativ cotlet-urile.
Vreau să abordez acest subiect dintr-un punct de vedere mai general. Acesta nu este un articol care vă arată o listă de sarcini Rake cu soluții inteligente, care sunt gata să fie copiate și lipite fără prea multă atenție. Este mai intenționată să fie o privire sub capotă, fiind în același timp prietenă cu noiștii și, de asemenea, interesantă pentru oamenii care tocmai nu au jucat încă mult cu Rake-ul în afară de sarcinile evidente Rake în Rails.
Este o înțelegere a instrumentului și a ceea ce oferă, care aduce o rentabilitate mai mare, cred. Sper că nu te superi. Pentru mine, acoperirea principiilor este mai valoroasă - și mai accesibilă pentru începători - și depinde de tine ceea ce faci cu ea în propriile aplicații.
Sunt sigur că ați auzit cel puțin un termen anterior undeva. Dar ce este într-adevăr o sarcină implicită? Nu este nimic magic, dar să lăsăm pe asta să fie rapid. Când alergi greblă
fără niciun nume suplimentar pentru o sarcină rake, se execută sarcina implicită.
greblă
desc "Aceasta este sarcina implicită. Nu există argumente necesare ": setarea implicită pune" Unele sarcini pe care ați putea dori să le desfășurați în mod regulat "
În rails, sarcina implicită trebuie să ruleze testele. Părerea ta este la fel de bună ca și a mea, dar presupun că a fost rezultatul testelor care trebuiau executate mai des decât orice altă sarcină. Când redefiniți Mod implicit
Rake sarcina în Rails, doar se adaugă la sarcina definită de Rails-nu-l va redefini. De fapt, funcționează Rake. Când redefiniți o sarcină Rake, adăugați definițiile anterioare.
După cum sugerează și numele, acestea sunt sarcini pe care le executați pe fișiere (și directoare). Cu toate acestea, au câteva trucuri în mânecă. Rake va lucra, desigur, o mare parte din timp cu fișiere. Nu este o surpriză că cineva a recunoscut acel model și a creat sarcini de fișier specializate pentru confortul dvs. - mai ales pentru simplul motiv pentru a evita dublarea sau pierderea capacităților de procesare.
Transformarea fișierelor de la un tip la altul este o sarcină foarte comună. Sursele sunt dependențele tale și numele de sarcini sunt cele care urmează fişier
cuvinte cheie. Convertirea Markdown în fișiere HTML, convertirea fișierelor HTML în formate ebook, imagini JPG în imagini PNG, compilarea codului sursă, construirea de pagini statice sau doar modificarea extensiilor de fișiere și multe alte opțiuni sunt la dispoziția dumneavoastră. Am putea face toate acestea manual, dar acest lucru este obositor și ineficient, desigur. Codul de scriere pentru acest lucru este mult mai elegant și mai scalabil.
Utilizarea sarcinilor de fișiere nu este mult diferită de sarcinile "obișnuite". Ele se vor afișa, de asemenea, dacă cereți o listă de sarcini Rake via rake -T
. De fapt, Rake tratează toate sarcinile în mod egal - cu excepția multitask
putin. Adăugarea descrierilor și a cerințelor prealabile nu reprezintă o problemă pentru ca sarcinile fișierelor să se ocupe de asemenea.
De fapt, premisele sunt o necesitate pentru menționarea fișierelor sursă înainte de a fi procesate. Avem nevoie ca sursa să existe pentru ca aceasta să funcționeze - ceea ce are sens ca o dependență, desigur. Fără ea, Rake nu ar ști cum să continue - nu poate crea noul dosar din aer subțire, la urma urmei.
fișier 'mi6 / q / gadgets / secret_list.md' => 'mi6 / research / secret_list.md' cp 'mi6 / research / secret_list.md', 'mi6 / q / gadgets / secret_list.md'
Numele pentru sarcina dvs. de fișier este, în principiu, fișierul țintă, fișierul pe care doriți să-l creați. Condiția preliminară este fișierul sursă care este necesar pentru sarcină. În interiorul blocului, îi spui lui Rake cum să creeze ieșirea dorită - cum se construiește folosind fișierele prealabile care există deja. Intrare ieșire. De exemplu, aceasta ar putea fi o comandă shell folosind pandoc
care transformă fișierele Markdown în fișiere HTML. Aplicațiile pentru sarcini de fișiere sunt mai mult decât o mulțime. Sintaxa, totuși, s-ar putea simți puțin ciudată la început. înțeleg.
Rake verifică mai întâi dacă există fișierul țintă și, dacă da, verifică dacă eticheta de timp este mai veche decât fișierele prealabile - o dependență bazată pe timp. Rake va rula sarcina de fișier dacă marca de timp este mai veche decât cerințele prealabile sau dacă fișierul nu există încă. Acest lucru este foarte util dacă trebuie să rezolvați mai mult de două fișiere - ceea ce este deosebit de interesant deoarece nu va trebui să reconstruiți o mulțime de fișiere doar pentru că ați schimbat unul singur dintr-o colecție, de exemplu. Spre deosebire de aceasta, sarcinile regulate de Rake sunt întotdeauna executate - nu verifică nici o marcă de timp sau alte modificări, dacă nu le faceți, bineînțeles.
desc "Modificați unele fișiere de extensii" some_file.new_extension '=>' some_file.old_extension 'do mv' some_file.old_extension ',' some_file.new_extension 'sfârșit
$ rake some_file.new_extension => mv some_file.old_extension some_file.new_extension
În cazul în care vă întrebați cp
în exemplul precedent sau în cele de mai sus mv
comanda, hai sa vorbim despre utilitatile de fisiere. Am fi putut folosi sh mv ...
pentru a executa o comandă Shell din cadrul unei sarcini Rake. Din fericire pentru noi, putem folosi un modul care face comanda Shell ca aceasta mult mai putin verbose si platforma independenta. fileutils
este un modul Ruby cu o mulțime de comenzi unixy pentru operațiile de fișiere:
rm
cp
mv
mkdir
Dacă reinventarea roții nu este chestia ta, FileUtils va fi un companion util care se ocupă de fișiere. Adesea Rake este tot ce aveți nevoie, dar de fiecare dată când veți fi foarte bucuroși că acest modul la îndemână vă are spatele. RakeUtils
a extins acest modul ușor pentru confortul dvs..
Să aruncăm o privire la o listă a ceea ce vă stă la dispoziție și apoi să mărim câteva dintre cele care ar putea fi de interes pentru dvs.:
cd (dir, opțiuni) cd (dir, opțiuni) dir | ... pwd () mkdir (dir, opțiuni) mkdir ) ln_s (list, options, options) ln_s (src, dest, options) lp (src, dest, options) , dest, opțiuni) cp (list, dir, opțiuni) cp_r (listă, dir, opțiuni) ) rm_r (listă, opțiuni) rm_rf (listă, opțiuni) install (src, dest, mode =, opțiuni) chmod (utilizator, grup, listă, opțiuni) chmod (utilizator, grup, listă, opțiuni) chmod_R
Deși presupun că sunteți un începător, presupun, de asemenea, că ați mai jucat cu Rails înainte și că știți utilitățile de bază ale Unix-ului, cum ar fi mv
, CD
, PWD
, mkdir
și chestii. Dacă nu, faceți temele și reveniți.
În rachetele dvs., puteți utiliza aceste metode imediat din cutie. Și pentru a evita neînțelegerile, acesta este un strat Ruby care "imită" aceste comenzi Unix și pe care le puteți folosi în fișierele Rake fără nici un prefix ca SH
-pentru executarea unei comenzi Shell. Apropo, Opțiuni
vedeți în lista de mai sus înseamnă un hash de opțiuni. Să aruncăm o privire la câteva comenzi interesante care ar putea să vină în scrierea unor sarcini de lucru la îndemână:
SH
Aceasta vă permite să executați comenzi de shell din fișierele Ruby.
CD
Acesta este unul foarte fundamental, dar există ceva rău în legătură cu această comandă. Dacă oferiți CD
cu un bloc, modifică directorul curent către destinația sa, își definește afacerea așa cum este definită în bloc și apoi revine la directorul de lucru anterior pentru a continua. Neat, de fapt!
cp_r
Vă permite să copiați fișierele și directoarele în mod recursiv în vrac.
mkdir_p
Creează un director țintă și toți părinții specificați. Din fericire pentru noi, avem director
în Rake, care este și mai convenabil și, prin urmare, nu avem nevoie de ea.
atingere
Aceasta actualizează marcajul de timp al unui fișier, dacă există - dacă nu, acesta este creat.
identic?
Vă permite să verificați dacă două fișiere sunt identice.
În Rake, aveți o modalitate la îndemână de a defini directoare fără a le utiliza mkdir
sau mkdir_p
. Este deosebit de util când trebuie să construiți directoare imbricate. Un arbore de dosare poate fi o durere dacă aveți nevoie pentru a construi o structură de directoare prin mai multe sarcini de fișier care au tone de premise pentru structura de directoare. Gândiți-vă la director
metodă ca sarcină de folder.
directorul "mi6 / q / special_gadgets"
Acest lucru creează directoarele în cauză fără prea multă agitație. Ceea ce ar putea să nu fie evident chiar acum este faptul că puteți depinde de ea ca orice altă sarcină de rake - ca o condiție prealabilă. Doar asigurați-vă că numele de sarcină a fișierului, numele său, include directorul pe care vă depindeți. Dacă mai multe sarcini depind de el, acesta va fi creat încă o singură dată.
directorul 'mi6 / q / gadgets' desc 'Transferați fișierele gadget de cercetare secretă' mi6 / q / gadgets / gadget_list.md '=>' mi6 / q / gadgets 'cp' gadget_list.md ',' mi6 / q / special_gadgets /secret_gadget_list.md "sfârșit
După cum puteți vedea aici, Rake este foarte consistent și se gândește la toate lucrurile pe care trebuie să le construiască ca sarcini. Mulțumesc, Jim, asta face viața ușoară!
Regulile ne pot ajuta să reducem duplicările atunci când ne ocupăm de sarcini - sarcini de fișiere, de fapt. În loc să instruiască Rake să execute sarcini pe anumite fișiere cum ar fi somefile.markdown
, putem preda Rake pentru a executa aceste sarcini pe un anumit tip de fișier, cum ar fi un model sau un plan. Transformarea unui set de fișiere în locul celor unice este o abordare mult mai versatilă și mai uscată. Sarcini ca acestea scară mult mai bine atunci când definim un model pentru fișiere care au caracteristici similare.
fișierul "quartermaster_gadgets.html" => "quartermaster_gadgets.markdown" face sh "pandoc -s quartermaster_gadgets.markdown -o quartermaster_gadgets.html" sfârșit
După cum puteți vedea, având o grămadă de fișiere ar fi nerăbdător să vă mențineți în acest fel. Da, putem scrie propriul nostru scenariu în care păstrăm o listă de fișiere într-un tablou și o repetăm, dar putem face mai bine - mult mai bine.
Un alt efect secundar nedorit ar fi ca de fiecare data cand vom rula un astfel de script, toate fisierele HTML vor fi reconstruite - chiar daca nu s-au schimbat deloc. O listă mare de fișiere vă va face să așteptați mult mai mult sau să aveți mai multe resurse decât este necesar. Nu avem nevoie de niciun cod suplimentar pentru a avea grijă de mai multe fișiere. Rake face o treabă mai bună și mai eficientă în acel departament, deoarece execută doar sarcinile sau regulile fișierului atunci când fișierul a fost atins între timp.
regula ".html" => ".markdown" face | regula | sh "pandoc -s # rule.source -o # rule.name" sfârșit
Când definim o regulă ca cea de mai sus, avem un mecanism în loc de a transforma orice fișier cu un .markdown
extinderea într - un .html
fişier. Cu reguli, Rake caută mai întâi o sarcină pentru un anumit fișier cum ar fi quartermaster_gadgets.html
. Dar când nu-și găsește una, folosește câmpia .html
să căutați o sursă care ar putea realiza o execuție reușită. În acest fel, nu trebuie să creați o listă lungă de fișiere, ci să utilizați numai o "regulă" generală care definește modul de gestionare a anumitor sarcini de fișier. Destul de tare!
În regula de mai sus, am folosit obiectul sarcină - în acest caz un obiect de reguli, pentru a fi chiar mai precis. Putem să-l transmitem ca argument bloc în metodele de închidere și de apel pe el. Ca și în cazul sarcinilor de fișiere, regulile sunt toate despre sursele de sarcini, dependențele lor - un fișier de marcare, de exemplu, și numele de activitate al acestuia.
Din cadrul corpului de reguli din bloc (și sarcinile de fișier), avem acces la numele și sursa regulilor. Putem extrage informații din acel argument trecut - numele prin intermediul rule.name
și sursa acesteia (sursa de fișier aka) prin rule.source
. Mai sus, am putea evita duplicarea numelor fișierelor și generalizarea unui model în schimb. În mod similar, am putea obține lista cu premisele sau dependențele rules.prerequisites
. Pentru sarcini de fișier sau orice altă sarcină, același lucru se aplică, desigur.
Vorbind de dependențe, ele pot funcționa ca o listă care trebuie repetată. Nu este nevoie să creați o secțiune separată fiecare
buclă dacă vă jucați corect cărțile.
sarcina: html =>% W [quartermaster_gadgets.html, research_gadgets.html] regula ".html" => ".md" nu | r | sh "pandoc -s # r.source -o # r.name" sfârșit
După cum puteți vedea, nu este necesar să repetăm manual lista de articole. Pur și simplu l-am pus pe Rake să lucreze și a folosit dependențele - mult mai simplu și mai curat.
Ceea ce este chiar mai răcoroasă pentru a usca lucrurile este că regulile pot lua un obiect proc - un obiect de funcție anonimă, o lambda practic - ca o condiție prealabilă. Asta inseamna ca, in loc de un singur model ca o conditie prealabila, putem trece ceva mai dinamic care ne permite sa aruncam o plasa de modele care capturiaza mai mult decat un singur peste. De exemplu, regulile pentru .markdown
și .md
fișiere.
Ei ar avea același corp al regulii, dar numai un model diferit ca o condiție prealabilă. Este ca și cum ați defini o nouă sarcină Fișier pentru fiecare obiect returnat de obiectul proc. O altă modalitate de a lucra cu reguli este expresia regulată, desigur. Transmiteți un model ca dependență și, dacă aveți o potrivire, sarcina de fișier poate fi executată. Opțiuni dulci, nu?
some_markdown_list = [...] detect_source = proc nu | html_file_name | some_markdown_list.detect | markdown_source | markdown_source.ext == html_file_name.ext regula final ".html" => detect_source do | r | sh "pandoc -s # r.source -o # r.name" sfârșit
Dacă sunteți nou la pământ lambda sau nu ați dat seama încă complet, aici este un mic reîmprospătare. Procs sunt obiecte pe care le puteți trece în jurul valorii de care pot fi executate mai târziu - așa sunt lambdas. Ambele sunt obiecte Proc, apropo. Diferența este subtilă și coboară la argumentele care sunt transmise în ele. Lambdas verifică numărul de argumente și poate arunca cu aerul ArgumentError
din acest motiv - procs nu le pasă. Cealaltă diferență se referă la tratarea declarațiilor de returnare. Procs ies din domeniul unde a fost executat obiectul proc. Lambdas tocmai ieși din domeniul de aplicare lambda și continuă să declanșeze următorul cod care este în linie, ca să spunem așa. Nu este foarte important aici, dar m-am gandit pentru incepatori printre voi, dar nici nu poate rani.
Aceasta este o listă scurtă de steaguri pe care le puteți trece la sarcini rake.
--norme
Vă arată cum Rake încearcă să aplice regulile - o urmă pentru reguli. Inutil, daca te descurci cu cateva reguli si faci bug-uri.
$ rake quartermaster_gadgets.html --rules Regula de încercare quartermaster_gadgets.html => quartermaster_gadgets.md (quartermaster_gadgets.html => quartermaster_gadgets.md ... EXIST) pandoc -s quartermaster_gadgets.md -o quartermaster_gadgets.html
-T
Amintiți-vă solve_bonnie_situation
sarcina de la articolul unu? Să adăugăm acest steag la această sarcină Rake și să pornim urmărirea. De asemenea, avem o backtrace dacă ne confruntăm cu erori. Acest lucru este cu siguranță util pentru depanare.
$ rake solve_bonnie_situation -t ** Invoke solve_bonnie_situation (first_time) ** Invoca get_mr_wolf (first_time) ** Executa get_mr_wolf Nu ai nici o problema Jules, sunt pe ea! Du-te acolo și să le răciți și să așteptați lupul care ar trebui să vină direct! ** Invoca calm_down_jimmy (first_time) ** Executa calm_down_jimmy Jimmy, fa-mi o favoare, nu-i asa? Am mirosit ceva cafea acolo. Vrei să-mi faci o ceașcă? ** Invoca figure_out_bonnie_situation (first_time) ** Executa figure_out_bonnie_situation Daca am fost informat corect, ceasul bate. E drept Jimmy? ** Invoke get_vince_vega_in_line (first_time) ** Executa get_vince_vega_in_line Vino din nou? Ia-o drept buster. Nu sunt aici să vă rog vă rog! Sunt aici să vă spun ce să fac! ** Invoca clean_car (first_time) ** Executa curat_car Am nevoie de doi oameni pentru a lua acele produse de curatat si pentru a curata interiorul masinii. Vorbesc repede, rapid, rapid! ** Invocați clean_crew (first_time) ** Executați clean_crew Jim, săpunul! O.K. domnilor, amândoi ați fost în județ înainte de a fi sigur. Uite ca vine! ** Invoke get_rid_of_evidence_at_monster_joes (first_time) ** Executa get_rid_of_evidence_at_monster_joes Deci, ce e cu tinutele? Voi mergeți la un joc de volei sau ceva? ** Invoca drive_into_the_sunrise (first_time) ** Executați drive_into_the_sunrise Sunați-mă Winston! ** Execute solve_bonnie_situation Știți, m-aș duce la micul dejun. Simțiți-vă ca micul dejun cu mine?
reglaj Rake.application.options.trace_rules = true
într-un Rakefile însăși îi spune lui Rake să ne arate informații despre reguli când conducem o sarcină. Acest lucru este misto, pentru că atunci când executăm o urmă rake -t
, cu un singur drapel, primim toate informațiile de depanare de care avem nevoie. Nu numai că obținem o listă de invocări de sarcini, dar putem vedea și ce reguli au fost aplicate sau încercate.
-P
Afișează o listă de condiții prealabile pentru toate sarcinile. Aici vom folosi din nou solve_bonnie_situation
sarcină. Omiterea de ieșire pentru alte sarcini ar fi o ieșire specifică:
$ rake solve_bonnie_situation -P ... rake solve_bonnie_situation get_mr_wolf calm_down_jimmy imagine_out_bonnie_situation get_vince_vega_in_line clean_car clean_crew get_rid_of_evidence_at_monster_joes drive_into_the_sunrise ...
Dacă ești curios, fugi rake -P
. O ieșire destul de interesantă.
-m
Efectuează sarcini ca mai multe sarcini.
Permiteți-mi să vă prezint multitask
metodă. Acest lucru vă poate ajuta să accelerați puțin lucrurile - la urma urmei, avem mai multe nuclee pe cele mai moderne computere, deci să le folosim. Desigur, puteți obține întotdeauna creșterea vitezei prin scrierea unui cod solid care nu are nici o grăsime, dar executarea sarcinilor în paralel vă poate oferi cu siguranță ceva extra în acest sens. Există însă capcane, pe care le vom acoperi, de asemenea.
Sarcinile pe care le-am executat până acum execută toate sarcinile în ordine, una după alta. Este un pariu sigur dacă codul dvs. este în ordine, dar este și mai lent. Dacă viteza este importantă pentru o anumită sarcină, putem contribui puțin la sarcini cu mai multe fire. Rețineți, totuși, că abordarea secvențială este cea mai bună opțiune în anumite circumstanțe.
Să presupunem că avem trei sarcini Rake care trebuie executate ca o condiție necesară pentru a executa un al patrulea. Acestea sunt patru fire, practic. În imaginea de ansamblu a lucrurilor, atunci când executați mai multe aplicații - sau pentru a fi mai specifice, procese - dintr-o dată, aceeași idee este la lucru.
multitask: shoot_bond_movie => [: shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation] face "Fotografia principală este făcută și putem începe editarea". Sfârșit
Utilizarea multitask
, dependențele din matricea noastră prealabilă nu mai sunt executate în această ordine. În schimb, ele sunt răspândite și executate în paralel - dar înainte de shoot_bond_movie
sarcina, desigur. Un fir Ruby pentru fiecare sarcină va fi rulat în același timp. Odată terminate, shoot_bond_movie
își va face afacerea. Modul în care acționează aici sarcinile este similar cu cel al randomizării, dar, de fapt, ele sunt executate pur și simplu în același timp.
Partea dificilă este doar să vă asigurați că anumite dependențe sunt procesate într-o ordine care se potrivește nevoilor dvs. Din acest motiv, trebuie să avem grijă de condițiile de rasă. Aceasta înseamnă, în esență, că o anumită sarcină intră în dificultăți, deoarece ordinul de execuție a avut efecte secundare involuntare. E un bug.
Dacă putem evita acest lucru, obținem siguranța firului. În ceea ce privește condițiile prealabile comune, interesant, aceste cerințe preliminare vor fi executate o singură dată, deoarece precondițiile multitasking așteaptă încheierea lor.
sarcina: shoot_love_scene nu ... sarcina finala: prepare_italy_set nu ... sarcina finala: shoot_car_chase => [: prepare_italy_set] nu ... sarcina de sfarsit: shoot_final_confrontation => [: prepare_italy_set] nu ... end multitask: shoot_bond_movie => [shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation ] pune "Fotografie principală se face și putem începe editarea." Sfârșit
Ambii shoot_car_chase
și shoot_final_confrontation
sarcinile depind de prepare_italy_set
pentru a termina primul - care se execută doar o dată, apropo. Putem folosi acest mecanism pentru a anticipa ordinea când execută sarcini în paralel. Nu aveți încredere în ordinea execuției dacă este oarecum importantă pentru sarcina dvs..
Păi, cred că acum ești complet echipat pentru a scrie ceva serios. Utilizarea corectă a acestui instrument vă va face să vă faceți viața ca dezvoltator de Ruby și mai bucuroasă. În acest al doilea articol, sper că pot să spun ce este un instrument simplu, dar minunat. A fost creat de un adevărat maestru al meseriei sale.
Toți îi datorăm lui Jim Weirich un respect extraordinar pentru că a venit cu acest instrument elegant de construcție. Comunitatea Ruby nu este cu siguranță aceeași, de când a murit. Moștenirea lui Jim este în mod clar aici să rămână, totuși. Un alt gigant pe care suntem privilegiați să construim.