Dans ce deuxième article sur Rake, nous allons un peu plus loin et couvrons des sujets légèrement avancés tels que les tâches liées aux fichiers, les règles, les tâches multiples, etc., qui amélioreront considérablement vos performances de rake..
Je souhaite aborder ce sujet d’un point de vue plus général. Ce n'est pas un article qui vous montre une liste de tâches Rake avec des solutions intelligentes prêtes à être copiées et collées sans trop de réflexion. Il est plus destiné à être un coup d'oeil sous le capot tout en étant convivial pour les débutants et également intéressant pour les personnes qui n'ont pas encore beaucoup joué avec Rake en plus des tâches évidentes de Rake dans Rails..
C'est la compréhension de l'outil et de ce qu'il offre qui génère un rendement plus élevé, je pense. J'espère que ça ne vous dérange pas. Pour moi, couvrir les principes est plus précieux - et plus accessible pour les débutants - et c'est à vous de choisir ce que vous en ferez dans vos propres applications.
Je suis sûr que vous avez au moins entendu le terme auparavant quelque part. Mais quelle est vraiment une tâche par défaut? Ce n'est rien de magique, mais finissons-en vite. Quand tu cours râteau
sans nom supplémentaire pour une tâche rake, la tâche par défaut est exécutée.
râteau
desc 'C'est la tâche par défaut. Pas d'argument nécessaire 'tâche: la valeur par défaut met' Une tâche que vous voudrez peut-être exécuter régulièrement 'fin
Dans Rails, la tâche par défaut est supposée exécuter vos tests. Votre hypothèse est aussi bonne que la mienne, mais je suppose que c'était le résultat d'essais devant être exécutés plus souvent que toute autre tâche. Quand vous redéfinissez le défaut
Rake tâche dans Rails, cela s'ajoute à la tâche définie par Rails - cela ne la redéfinira pas. C'est en fait la façon dont Rake fonctionne. Lorsque vous redéfinissez une tâche Rake, vous ajoutez aux définitions précédentes..
Comme son nom l’indique, il s’agit de tâches que vous exécutez sur des fichiers (et des répertoires). Ils ont cependant quelques tours dans leurs manches. Bien entendu, Rake travaillera beaucoup avec les fichiers. Aucune surprise si quelqu'un a reconnu ce modèle et créé des tâches de fichier spécialisées pour votre commodité, en particulier pour la simple raison d'éviter la duplication ou le gaspillage de capacités de traitement.
Transformer des fichiers d'un type à un autre est une tâche très courante. Les sources sont vos dépendances et les noms de tâches sont ce qui suit les fichier
mot-clé. Convertir Markdown en fichiers HTML, convertir des fichiers HTML en formats ebook, des images JPG en images PNG, compiler du code source, construire des pages statiques ou simplement modifier les extensions de fichiers et bien d’autres options sont à votre disposition. Nous pourrions faire tout cela manuellement, mais c'est fastidieux et inefficace, bien sûr. L'écriture de code pour cela est beaucoup plus élégante et évolutive.
L'utilisation de tâches de fichier n'est pas très différente des tâches «ordinaires». Ils apparaîtront également si vous demandez une liste des tâches de rake via rake -T
. En fait, Rake traite toutes les tâches de la même manière, sauf multitâche
un peu. L'ajout de descriptions et de conditions préalables ne pose aucun problème à la gestion des tâches de fichiers..
En fait, les conditions préalables sont une nécessité pour mentionner les fichiers source avant qu’ils ne soient traités. Il faut que la source existe pour que cela fonctionne - ce qui est logique en tant que dépendance, bien sûr. Sans cela, Rake ne saurait pas continuer, il ne pourrait pas créer le nouveau fichier à partir de rien, après tout.
fichier 'mi6 / q / gadgets / secret_list.md' => 'mi6 / research / secret_list.md' do cp 'mi6 / research / secret_list.md', 'mi6 / q / gadgets / secret_list.md' end
Le nom de votre tâche de fichier est essentiellement votre fichier cible, le fichier que vous souhaitez créer. Le prérequis est le fichier source nécessaire à la tâche. À l'intérieur du bloc, vous indiquez à Rake comment créer la sortie souhaitée. Comment le construire à l'aide du ou des fichiers prérequis déjà existants. Entrée sortie. Par exemple, il peut s’agir d’une commande shell utilisant le pandoc
outil qui transforme les fichiers Markdown en fichiers HTML. Les applications pour les tâches de fichiers sont plus que nombreuses. La syntaxe, cependant, peut sembler un peu étrange au début. j'ai compris.
Rake vérifie d'abord si le fichier cible existe et, si tel est le cas, si l'horodatage est plus ancien que les fichiers prérequis - une dépendance temporelle. Rake exécutera la tâche de fichier si l'horodatage est plus ancien que les conditions préalables ou si le fichier n'existe pas encore. C'est très pratique si vous devez gérer plusieurs fichiers, ce qui est particulièrement intéressant, car vous n'avez pas besoin de reconstruire une tonne de fichiers simplement parce que vous en avez modifié un seul dans une collection. Contrairement à cela, les tâches standard de Rake sont toujours exécutées. Elles ne vérifient ni l'horodatage ni d'autres modifications, à moins que vous ne le fassiez, bien sûr..
desc 'Change une extension de fichier' fichier 'un_fichier.new_extension' => 'un_fichier.old_extension' do mv 'un_fichier.old_extension', 'un_fichier.new_extension'
$ rake un_fichier.new_extension => mv un_fichier.old_extension un_fichier.new_extension
Au cas où vous vous interrogeriez sur le cp
méthode dans l'exemple précédent ou ci-dessus mv
commande, parlons des utilitaires de fichiers. Nous aurions pu utiliser sh mv…
exécuter une commande shell depuis une tâche Rake. Heureusement pour nous, nous pouvons utiliser un module qui rend les commandes Shell beaucoup moins verbeuses et indépendantes de la plate-forme.. FileUtils
est un module Ruby avec beaucoup de commandes unixy pour les opérations sur les fichiers:
rm
cp
mv
mkdir
Si réinventer la roue n’est pas votre affaire, FileUtils sera un compagnon utile dans le traitement des fichiers. Rake est souvent tout ce dont vous avez besoin, mais de temps en temps, vous serez vraiment heureux que ce module pratique soit à votre service.. RakeUtils
étendu légèrement ce module pour votre commodité.
Jetons un coup d'oeil à la liste de ce qui est à votre disposition, puis examinons quelques-uns de ceux qui pourraient vous intéresser:
cd (répertoire, options) cd (répertoire, options) | répertoire |… pwd () mkdir (répertoire, options) mkdir (liste, options) mkdir_p (répertoire, options) mkdir_p (liste, options) rmdir (répertoire, options) ) rmdir (liste, options) ln (ancien, nouveau, options) ln (liste, destinataires, options) ln_s (ancien, nouveau, options) ln_s (liste, destinataires, options) ln_sf (src, destin, options) cp (src , dest, options) cp (liste, répertoire, options) cp_r (src, destination, options) cp_r (liste, répertoire, options) mv (src, destination, options) mv (liste, répertoire, options) rm (liste, options) ) rm_r (liste, options) rm_rf (liste, options) install (src, dest, mode =, options) chmod (mode, liste, options) chmod_R (mode, liste, options) chown (utilisateur, groupe, liste, options) chown_R (utilisateur, groupe, liste, options) tactile (liste, options)
Bien que je suppose que vous êtes un débutant, je suppose également que vous avez déjà joué avec Rails et que vous connaissez les utilitaires Unix de base, comme mv
, CD
, pwd
, mkdir
et d'autres choses. Si non, faites vos devoirs et revenez.
Dans vos Rakefiles, vous pouvez utiliser ces méthodes directement. Et pour éviter les malentendus, il s’agit d’une couche Ruby qui "imite" ces commandes Unix et que vous pouvez utiliser dans vos fichiers Rakefiles sans préfixes tels que sh
-pour exécuter une commande Shell. Au fait, le options
vous voyez dans la liste ci-dessus un hachage d'options. Examinons quelques commandes intéressantes qui pourraient s’avérer utiles lors de l’écriture de tâches de fichier:
sh
Cela vous permet d'exécuter des commandes shell à partir de vos fichiers Ruby..
CD
C'est très basique, mais cette commande a quelque chose de cool. Si vous fournissez CD
avec un bloc, il change le répertoire en cours vers sa destination, exécute ses tâches comme défini dans le bloc, puis retourne au répertoire de travail précédent pour continuer. Neat, en fait!
cp_r
Permet de copier des fichiers et des répertoires de manière récursive en bloc.
mkdir_p
Crée un répertoire cible et tous ses parents spécifiés. Heureusement pour nous, nous avons le annuaire
méthode dans Rake, ce qui est encore plus pratique, et donc nous n'en avons pas besoin.
toucher
Ceci met à jour l'horodatage d'un fichier s'il existe. Sinon, il est créé..
identique?
Permet de vérifier si deux fichiers sont identiques.
Dans Rake, vous avez un moyen pratique de définir des répertoires sans utiliser mkdir
ou mkdir_p
. C'est particulièrement utile lorsque vous devez créer des répertoires imbriqués. Une arborescence de dossiers peut s'avérer difficile si vous devez créer une structure de répertoires à l'aide de plusieurs tâches de fichiers comportant de nombreuses conditions préalables pour la structure de répertoires. Pensez au annuaire
méthode en tant que tâche de dossier.
répertoire 'mi6 / q / special_gadgets'
Cela crée les répertoires en question sans grande difficulté. Ce qui n’est peut-être pas évident tout de suite, c’est le fait que vous pouvez compter sur elle comme toute autre tâche de rake, comme condition préalable. Assurez-vous simplement que le nom de la tâche de fichier, son nom, inclut le répertoire sur lequel vous dépendez. Si plusieurs tâches en dépendent, il ne sera créé qu'une seule fois..
répertoire 'mi6 / q / gadgets' desc 'fichier de transfert des recherches secrètes' mi6 / q / gadgets / gadget_list.md '=>' mi6 / q / gadgets 'do cp' gadget_list.md ',' mi6 / q / special_gadgets /secret_gadget_list.md 'end
Comme vous pouvez le voir ici, Rake est très cohérent et pense à toutes les choses à construire en tant que tâches. Merci, Jim, ça rend la vie facile!
Les règles peuvent nous aider à réduire les doublons lorsque nous traitons des tâches de fichiers, en fait. Au lieu d’instruire Rake d’exécuter des tâches sur des fichiers particuliers tels que un fichier.markdown
, nous pouvons apprendre à Rake à exécuter ces tâches sur un certain type de fichier, tel qu'un motif ou un modèle. Transformer un ensemble de fichiers au lieu de fichiers uniques est une approche beaucoup plus polyvalente et plus sèche. Des tâches comme celles-ci s’échelonnent beaucoup mieux lorsque nous définissons un modèle pour des fichiers partageant des caractéristiques similaires.
fichier "quartermaster_gadgets.html" => "quartermaster_gadgets.markdown" fait shond "pandoc -s quartermaster_gadgets.markdown -o quartermaster_gadgets.html" fin
Comme vous pouvez le constater, il serait fastidieux de conserver de nombreux fichiers. Oui, nous pouvons écrire notre propre script dans lequel nous gardons une liste de fichiers dans un tableau et le parcourons, mais nous pouvons faire mieux, beaucoup mieux..
Un autre effet indésirable serait que, chaque fois que nous exécutons un tel script, tous les fichiers HTML sont reconstruits, même s'ils n'ont pas du tout été modifiés. Une longue liste de fichiers vous obligerait à attendre beaucoup plus longtemps ou à prendre beaucoup plus de ressources que nécessaire. Nous n'avons besoin d'aucun code supplémentaire pour gérer plusieurs fichiers. Rake effectue un travail plus efficace et plus efficace dans ce département, car il n'exécute ses tâches de fichier ou ses règles que lorsque le fichier a été touché entre-temps..
rule ".html" => ".markdown" do | rule | sh "pandoc -s # rule.source -o # rule.name" fin
Lorsque nous définissons une règle comme celle ci-dessus, nous avons un mécanisme en place pour transformer tout fichier avec un .réduction
extension dans un .html
fichier. Avec les règles, Rake cherche d’abord une tâche pour un fichier spécifique comme quartermaster_gadgets.html
. Mais quand il ne peut pas en trouver un, il utilise la plaine .html
règle de rechercher une source qui pourrait réussir son exécution. De cette façon, vous n'avez pas besoin de créer une longue liste de fichiers, mais d'utiliser uniquement une «règle» générale qui définit comment gérer certaines tâches liées aux fichiers. Assez impressionnant!
Dans la règle ci-dessus, nous utilisions l'objet tâche - dans ce cas, un objet règle, pour être encore plus précis. Nous pouvons le passer comme argument de bloc dans la fermeture et appeler des méthodes dessus. Comme pour les tâches de fichier, les règles concernent toutes les sources de tâches, ses dépendances, un fichier de démarquage, par exemple, et son nom de tâche..
Depuis le corps des règles dans le bloc (et les tâches de fichiers), nous avons accès au nom et à la source des règles. Nous pouvons extraire des informations de cet argument passé-le nom à travers nom de règle
et sa source (aka source de fichier) via règle.source
. Ci-dessus, nous pourrions éviter de dupliquer les noms des fichiers et généraliser un motif. De même, nous pourrions obtenir la liste des conditions préalables ou des dépendances avec règles.prerequisites
. Pour les tâches de fichier ou toute autre tâche, il en va de même, bien sûr.
Parlant de dépendances, ils peuvent fonctionner comme une liste à itérer. Il n'y a pas besoin de créer un séparé chaque
boucle si vous jouez bien vos cartes.
tâche: html =>% W [quartermaster_gadgets.html, research_gadgets.html] règle ".html" => ".md" do | r | sh "pandoc -s # r.source -o # r.name" fin
Comme vous pouvez le constater, nous n'avons pas eu besoin de parcourir manuellement la liste des articles. Nous avons simplement mis Rake au travail et utilisé les dépendances, ce qui est beaucoup plus simple et plus propre..
Ce qui est encore plus cool pour le DRYing, c'est que les règles peuvent prendre un objet proc - un objet de fonction anonyme, un lambda - en tant que condition préalable. Cela signifie qu'au lieu de ne disposer que d'un seul modèle comme condition préalable, nous pouvons adopter quelque chose de plus dynamique qui nous permet de créer un réseau de modèles qui capture plus d'un poisson. Par exemple, les règles pour .réduction
et .Maryland
des dossiers.
Ils auraient le même corps de la règle mais seulement un modèle différent comme condition préalable. C'est comme définir une nouvelle tâche de fichier pour chaque objet renvoyé par l'objet proc. Une autre façon de travailler avec des règles consiste bien sûr à utiliser des expressions régulières. Vous transmettez un modèle en tant que dépendance et si vous avez une correspondance, la tâche de fichier peut être exécutée. Options sucrées, non?
some_markdown_list = […] detect_source = proc do | nom_fichier_html | some_markdown_list.detect | markdown_source | markdown_source.ext == html_nom_fichier.ext règle de fin '.html' => detect_source do | r | sh "pandoc -s # r.source -o # r.name" fin
Si vous êtes nouveau sur lambda land ou si vous ne l'avez pas encore complètement compris, voici un petit rappel. Les procs sont des objets que vous pouvez transmettre et qui peuvent être exécutés plus tard, de même que les lambdas. Les deux sont des objets Proc, au fait. La différence est subtile et se résume aux arguments qui leur sont transmis. Lambdas vérifie le nombre d’arguments et peut exploser avec un ArgumentError
pour cette raison, les procs s'en moquent. L'autre différence concerne leur traitement des déclarations de retour. Les procs sortent de la portée où l'objet proc était en cours d'exécution. Lambdas vient de quitter l'étendue lambda et continue de déclencher le code suivant, pour ainsi dire. Pas super important ici, mais je pensais que pour les débutants parmi vous, ça ne pouvait pas faire de mal non plus.
Ceci est une courte liste de drapeaux que vous pouvez passer pour ratisser les tâches.
--règles
Vous montre comment Rake tente d'appliquer des règles - une trace de règles. Inestimable si vous gérez quelques règles et rencontrez des bugs.
$ rake quartermaster_gadgets.html --rules Tentative de règle quartermaster_gadgets.html => quartermaster_gadgets.md (quartermaster_gadgets.html => quartermaster_gadgets.md… EXIST) pandoc -s quartermaster_gadgets.md -o quartermaster_gadgets.html
-t
Se souvenir du resol_bonnie_situation
tâche de l'article un? Ajoutons cet indicateur à cette tâche Rake et activons le traçage. Nous obtenons également une trace si nous rencontrons des erreurs. C'est certainement utile pour le débogage.
$ rake resol_bonnie_situation -t ** Appelez resol_bonnie_situation (première heure) ** Appelez get_mr_wolf (première fois) ** Exécutez get_mr_wolf Vous n'avez pas de problème, Jules, je suis dessus! Allez-y, détendez-vous et attendez le loup qui devrait venir directement! ** Invoke calm_down_jimmy (première heure) ** Exécutez calm_down_jimmy Jimmy, faites-moi une faveur, voulez-vous? J'ai senti du café là-bas. Voulez-vous me faire une tasse? ** Appelez figure_out_bonnie_situation (first_time) ** Exécute figure_out_bonnie_situation Si j'ai été informé correctement, l'horloge tourne. Est-ce vrai Jimmy? ** Appelez get_vince_vega_in_line (première fois) ** Exécutez get_vince_vega_in_line Revenez? Obtenez-le droit buster. Je ne suis pas ici pour dire s'il vous plaît! Je suis ici pour vous dire quoi faire! ** Appelez clean_car (first_time) ** Exécutez clean_car J'ai besoin de vous deux gars pour prendre ces produits de nettoyage et nettoyer l'intérieur de la voiture. Je parle vite, vite, vite! ** Appelez clean_crew (first_time) ** Exécutez clean_crew Jim, le feuilleton! D'ACCORD. Messieurs, vous étiez tous les deux dans le comté avant, j'en suis sûr. Ça vient! ** Appelez get_rid_of_evidence_at_monster_joes (first_time) ** Exécutez get_rid_of_evidence_at_monster_joes Alors, qu'en est-il des tenues? Vous allez à un match de volley-ball? ** Appelez drive_into_the_sunrise (première fois) ** Exécutez drive_into_the_sunrise Appelez-moi Winston! ** Exécutez resol_bonnie_situation Vous savez, j'irais pour le petit-déjeuner. Envie de déjeuner avec moi?
Réglage Rake.application.options.trace_rules = true
dans un Rakefile lui-même dit à Rake de nous montrer des informations de trace sur les règles lorsque nous exécutons une tâche. C’est cool parce que quand on lance une trace via rake -t
, avec un seul drapeau, nous obtenons toutes les informations de débogage dont nous avons besoin. Nous obtenons non seulement une liste d'invocations de tâches, mais nous pouvons également voir quelles règles ont été appliquées ou tentées..
-P
Affiche une liste des conditions préalables pour toutes les tâches. Ici nous utilisons à nouveau le resol_bonnie_situation
tâche. En omettant la sortie pour d'autres tâches, il s'agirait de la sortie sélectionnée:
$ rake resol_bonnie_situation -P… rake resol_bonnie_situation get_mr_wolf calm_down_jimmy figure_out_bonnie_situation get_vince_vega_in_line clean_crew get_rid_of_evidence_at_monster_joes drive_into_the_sunrise…
Si vous êtes curieux, lancez rake -P
. Sortie assez intéressante.
-m
Exécute les tâches en multitâche.
Laissez-moi vous présenter le multitâche
méthode. Cela peut vous aider à accélérer un peu les choses. Après tout, nous avons plusieurs cœurs sur la plupart des ordinateurs modernes, alors utilisons-les. Bien sûr, vous pouvez toujours atteindre les gains de vitesse en écrivant un code solide qui ne manque pas de gras, mais exécuter des tâches en parallèle peut certainement vous apporter quelque chose de plus à cet égard. Il y a cependant des pièges que nous allons également couvrir.
Les tâches que nous avons exécutées jusqu'ici exécutent toutes les tâches les unes après les autres. C’est une valeur sûre si votre code est en ordre, mais il est également plus lent. Si la vitesse est importante pour une tâche, nous pouvons aider un peu en multi-tâches. Gardez toutefois à l'esprit que l'approche séquentielle est la meilleure option dans certaines circonstances..
Supposons que trois tâches de rake doivent être exécutées en tant que conditions préalables pour pouvoir en exécuter une quatrième. Ce sont quatre fils, au fond. Dans l’ensemble, lorsque vous exécutez plusieurs applications - ou pour être plus spécifiques, les processus à la fois, la même idée est à l’œuvre.
multitâche: shoot_bond_movie => [: shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation] ne "La photographie principale est terminée et nous pouvons commencer le montage." fin
En utilisant multitâche
, les dépendances de notre tableau de prérequis ne sont plus exécutées dans cet ordre. Au lieu de cela, ils sont répartis et courus en parallèle, mais avant la shoot_bond_movie
tâche, bien sûr. Un fil Ruby pour chaque tâche sera exécuté en même temps. Une fois qu'ils sont finis, shoot_bond_movie
fera ses affaires. La façon dont les tâches agissent ici est semblable à la randomisation, mais en réalité elles sont simplement exécutées en même temps..
La difficulté consiste simplement à s’assurer que certaines dépendances sont traitées dans l’ordre qui convient le mieux à vos besoins. À cause de cela, nous devons nous occuper des conditions de course. Cela signifie essentiellement que certaines tâches rencontrent des problèmes car l'ordre d'exécution avait des effets secondaires non souhaités. C'est un bug.
Si nous pouvons éviter cela, nous atteignons la sécurité du fil. En ce qui concerne les conditions préalables communes, il est intéressant de noter que ces conditions préalables ne seront exécutées qu’une seule fois car les conditions préalables multitâches attendent d’être complétées en premier..
tache: shoot_love_scene do… fin ] do met "La photographie principale est terminée et nous pouvons commencer le montage." fin
Tous les deux shoot_car_chase
et shoot_final_confrontation
les tâches dépendent de prepare_italy_set
pour finir en premier, qui n’est couru qu’une fois, au fait. Nous pouvons utiliser ce mécanisme pour prédire l'ordre lors de l'exécution de tâches en parallèle. Ne vous fiez pas simplement à l'ordre d'exécution s'il est d'une certaine manière important pour votre tâche.
Eh bien, je suppose que vous êtes maintenant tout à fait à même d’écrire de sérieuses affaires de rake. Faire bon usage de cet outil rendra, espérons-le, votre vie de développeur Ruby encore plus joyeuse. Dans ce deuxième article, j'espère pouvoir expliquer en quoi un outil simple mais merveilleux est vraiment Rake. Il a été créé par un vrai maître de son métier.
Nous avons tous un grand respect envers Jim Weirich pour avoir proposé cet outil de construction élégant. La communauté Ruby n’est certainement pas tout à fait la même depuis son décès. L'héritage de Jim est clairement là pour rester, cependant. Un autre géant sur lequel nous avons le privilège de construire.