Rake 201

En este segundo artículo sobre Rake, profundizamos un poco más y cubrimos temas ligeramente avanzados como tareas de archivos, reglas, multitareas y más que mejorarán significativamente tus chuletas de Rake.

Los temas

  • Renuncia
  • Tarea predeterminada
  • El objeto de tarea
  • Tareas de archivo
  • Método de directorio
  • Utilidades de archivo
  • Reglas
  • Bandera del rastro
  • Tareas paralelas

Renuncia

Quiero abordar este tema desde un punto de vista más general. Este no es un artículo que muestra una lista de tareas de Rake con soluciones inteligentes que están listas para ser copiadas y pegadas sin mucha reflexión. Está más pensado para ser una mirada bajo el capó al tiempo que es amigable para los principiantes y también es interesante para las personas que simplemente no han jugado mucho con Rake, además de las tareas obvias de Rake en Rails. 

Es la comprensión de la herramienta y lo que ofrece lo que produce un mayor rendimiento, creo. Espero que no te moleste. Para mí, cubrir los principios es más valioso y más accesible para los principiantes, y depende de usted lo que haga con él en sus propias aplicaciones..

Tarea predeterminada

Estoy seguro de que al menos has escuchado el término anteriormente en algún lugar. Pero, ¿qué es realmente una tarea por defecto? No es nada mágico, pero saquemos esto rápidamente. Cuando corres rastrillo sin ningún nombre adicional para una tarea de rake, la tarea predeterminada se ejecuta.

Cáscara

rastrillo

Algunos Rakefile

desc 'Esta es la tarea por defecto. No es necesario ningún argumento 'tarea: por defecto se pone' Alguna tarea que quieras ejecutar regularmente 'final

En Rails, se supone que la tarea predeterminada ejecuta sus pruebas. Su conjetura es tan buena como la mía, pero supongo que fue el resultado de las pruebas que deben realizarse con más frecuencia que cualquier otra tarea. Cuando redefine el defecto Rake task en Rails, simplemente se suma a la tarea definida por Rails: no la redefinirá. En realidad es cómo funciona Rake. Al redefinir una tarea de Rake, se agregan las definiciones anteriores..

Tareas de archivo

Como su nombre puede sugerir, son tareas que usted ejecuta en archivos (y directorios). Sin embargo, tienen algunos trucos bajo la manga. Rake, por supuesto, trabajará mucho tiempo con archivos. No sorprende que alguien haya reconocido ese patrón y haya creado tareas de archivos especializadas para su conveniencia, especialmente por el simple motivo de evitar la duplicación o el desperdicio de capacidades de procesamiento..

Transformar archivos de un tipo a otro es una tarea muy común. Las fuentes son sus dependencias y los nombres de tareas son los que siguen a expediente palabra clave. Conversión de Markdown a archivos HTML, conversión de archivos HTML a formatos de libros electrónicos, imágenes JPG a imágenes PNG, compilación de código fuente, creación de páginas estáticas o simplemente cambio de extensiones de archivos y muchas más opciones están a su disposición. Podríamos hacer todo esto manualmente, pero esto es tedioso e ineficaz, por supuesto. Escribir código para esto es mucho más elegante y escalable..

El uso de tareas de archivo no es muy diferente de las tareas "regulares". También aparecerán si pides una lista de tareas de Rake a través de rastrillo -T. De hecho, Rake trata todas las tareas por igual, excepto Tarea múltiple un poco. Agregar descripciones y requisitos previos no es un problema para que las tareas de archivos se manejen también. 

En realidad, los requisitos previos son una necesidad para mencionar los archivos de origen antes de que se procesen. Necesitamos la fuente para existir para que esto funcione, lo que tiene sentido como una dependencia, por supuesto. Sin él, Rake no sabría cómo continuar, no puede crear el nuevo archivo de la nada, después de todo.

Algunos Rakefile

archivo 'mi6 / q / gadgets / secret_list.md' => 'mi6 / research / secret_list.md' do cp 'mi6 / research / secret_list.md', 'mi6 / q / gadgets / secret_list.md' final

El nombre para su tarea de archivo es básicamente su archivo de destino, el archivo que desea crear. El requisito previo es el archivo de origen que se necesita para la tarea. Dentro del bloque, le está diciendo a Rake cómo crear la salida deseada, cómo construirla usando los archivos de requisitos previos que ya existen. De entrada y salida. Por ejemplo, esto podría ser un comando de shell utilizando el pandoc Herramienta que transforma los archivos Markdown en archivos HTML. Las aplicaciones para tareas de archivo son más que suficientes. Sin embargo, la sintaxis puede parecer un poco rara al principio. lo entiendo.

Rake primero verifica si el archivo de destino existe y, si es así, comprueba si la marca de tiempo es más antigua que los archivos de requisitos previos, una dependencia basada en el tiempo. Rake ejecutará la tarea del archivo si la marca de tiempo es anterior a los requisitos previos o si el archivo aún no existe. Esto es muy útil si necesita manejar más de un par de archivos, lo cual es especialmente bueno porque no necesitará reconstruir una tonelada de archivos solo porque cambió uno solo en una colección, por ejemplo. En contraste con eso, las tareas regulares de Rake siempre se ejecutan, no comprueban ninguna marca de tiempo u otros cambios, a menos que los haga, por supuesto..

Utilidades de archivo

Algunos Rakefile

desc 'Cambiar alguna extensión de archivo' archivo 'some_file.new_extension' => 'some_file.old_extension' do mv 'some_file.old_extension', 'some_file.new_extension' end

Cáscara

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

En caso de que te preguntes por el cp método en el ejemplo anterior o el anterior mv comando, vamos a hablar de utilidades de archivos. Podríamos haber utilizado sh mv ... para ejecutar un comando de Shell desde dentro de una tarea de Rake. Afortunadamente para nosotros, podemos usar un módulo que hace que los comandos de Shell como este sean mucho menos detallados e independientes de la plataforma. FileUtils es un módulo de Ruby con muchos comandos Unixy para operaciones de archivos: 

  • rm 
  • cp 
  • mv
  • mkdir
  • y así…

Si reinventar la rueda no es lo tuyo, FileUtils será un compañero útil para tratar archivos. A menudo, Rake es todo lo que necesita, pero de vez en cuando, se alegrará mucho de que este práctico módulo tenga su respaldo. RakeUtils extendió este módulo ligeramente para su conveniencia. 

Vamos a echar un vistazo a una lista de lo que está a su disposición y luego hacer zoom en algunos en particular que podrían ser de su interés:

cd (dir, opciones) cd (dir, opciones) | dir |… pwd () mkdir (dir, opciones) mkdir (lista, opciones) mkdir_p (dir, opciones) mkdir_p (lista, opciones) rmdir (dir, opciones ) rmdir (lista, opciones) ln (antiguo, nuevo, opciones) ln (lista, destdir, opciones) ln_s (antiguo, nuevo, opciones) ln_s (lista, destdir, opciones) ln_sf (src, dest, opciones) cp (src , dest, opciones) cp (list, dir, options) cp_r (src, dest, options) cp_r (list, dir, options) mv (src, dest, options) mv (list, dir, options) rm (list, opciones ) rm_r (lista, opciones) rm_rf (lista, opciones) instalar (src, dest, mode = , opciones) chmod (modo, lista, opciones) chmod_R (modo, lista, opciones) chown (usuario, grupo, lista, opciones) chown_R (usuario, grupo, lista, opciones) toque (lista, opciones)

Aunque asumo que eres un novato, también asumo que has jugado con Rails antes y que conoces las utilidades muy básicas de Unix, como mv, discos compactos, pwd, mkdir y esas cosas Si no, haz tu tarea y vuelve.. 

En tus Rakefiles, puedes usar estos métodos de inmediato. Y para evitar malentendidos, esta es una capa de Ruby que 'imita' estos comandos de Unix y que puede usar en sus archivos de Rake sin ningún prefijo como sh-para ejecutar un comando de shell. Por cierto, el opciones ves en la lista anterior significa un hash de opciones. Veamos algunos comandos interesantes que pueden ser útiles para escribir tareas de archivos:

  • sh

Esto te permite ejecutar comandos de shell desde tus archivos de Ruby.

  • discos compactos

Este es uno muy básico, pero hay algo bueno en este comando. Si usted proporciona discos compactos con un bloque, cambia el directorio actual a su destino, hace su trabajo como se define en el bloque y luego regresa al directorio de trabajo anterior para continuar. Limpio, en realidad!

  • cp_r

Te permite copiar archivos y directorios de forma recursiva en masa.

  • mkdir_p

Crea un directorio de destino y todos sus padres especificados. Por suerte para nosotros, tenemos la directorio Método en Rake, que es aún más conveniente, y por lo tanto no lo necesitamos.

  • toque

Esto actualiza la marca de tiempo de un archivo si existe, si no, se crea.

  • idéntico?

Le permite comprobar si dos archivos son iguales.

Método de directorio

En Rake, tiene una forma práctica de definir directorios sin usar mkdir o mkdir_p. Es especialmente útil cuando necesita crear directorios anidados. Un árbol de carpetas puede ser una molestia si necesita crear una estructura de directorios a través de múltiples tareas de archivos que tienen muchos requisitos previos para la estructura de directorios. Pensar en directorio método como una tarea de carpeta.

Algunos Rakefile

directorio 'mi6 / q / special_gadgets'

Esto crea los directorios en cuestión sin mucho alboroto. Lo que podría no ser obvio de inmediato es el hecho de que puede depender de él como cualquier otra tarea de rake, como requisito previo. Solo asegúrese de que el nombre de la tarea del archivo, su nombre, incluya el directorio en el que depende. Si varias tareas dependen de él, se creará una sola vez..

directorio 'mi6 / q / gadgets' desc 'Transferir el archivo secreto de investigación gadgets' mi6 / q / gadgets / gadget_list.md '=>' mi6 / q / gadgets 'do cp' gadget_list.md ',' mi6 / q / special_gadgets /secret_gadget_list.md 'end

Como puede ver aquí, Rake es muy consistente y piensa en todas las cosas para construir como tareas. Gracias, Jim, eso hace la vida más fácil.!

Reglas

Las reglas pueden ayudarnos a reducir las duplicaciones cuando nos ocupamos de tareas, tareas de archivo, en realidad. En lugar de indicar a Rake que ejecute tareas en archivos particulares como somefile.markdown, podemos enseñar a Rake a ejecutar estas tareas en un determinado tipo de archivo, como un patrón o plano. Transformar un conjunto de archivos en lugar de uno solo es un enfoque mucho más versátil y SECO. Las tareas como estas se escalan mucho mejor cuando definimos un patrón para archivos que comparten características similares.

Algunos Rakefile

archivo "quartermaster_gadgets.html" => "quartermaster_gadgets.markdown" do sh "pandoc -s quartermaster_gadgets.markdown -o quartermaster_gadgets.html" end

Como puede ver, tener un montón de archivos sería tedioso mantenerlo así. Sí, podemos escribir nuestra propia secuencia de comandos donde guardamos una lista de archivos en una matriz y la repetimos, pero podemos hacerlo mejor, mucho mejor. 

Otro efecto secundario no deseado sería que cada vez que ejecutamos un script de este tipo, todos los archivos HTML se reconstruyen, incluso si no han cambiado en absoluto. Una gran lista de archivos lo haría esperar mucho más tiempo o requeriría muchos más recursos de los necesarios. No necesitamos ningún código adicional para cuidar varios archivos. Rake hace un trabajo mejor y más eficiente en ese departamento, ya que solo ejecuta sus tareas o reglas de archivo cuando el archivo fue tocado mientras tanto.

Algunos Rakefile

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

Cuando definimos una regla como la anterior, tenemos un mecanismo para transformar cualquier archivo con una .reducción extensión en un .html expediente. Con las reglas, Rake primero busca una tarea para un archivo específico como quartermaster_gadgets.html. Pero cuando no puede encontrar uno, está utilizando el plano .html Regla para buscar una fuente que pueda lograr una ejecución exitosa. De esa manera, no tiene que crear una larga lista de archivos, sino que solo use una "regla" general que defina cómo manejar ciertas tareas de archivos. Bastante impresionante!

Objeto de tarea

En la regla anterior, utilizamos el objeto de tarea, en este caso un objeto de regla, para ser aún más precisos. Podemos pasarlo como un argumento de bloqueo en los métodos de cierre y llamada. Al igual que con las tareas de archivos, las reglas se refieren a los orígenes de tareas, sus dependencias (por ejemplo, un archivo de reducción) y su nombre de tarea. 

Desde dentro del cuerpo de las reglas en el bloque (y tareas de archivo), tenemos acceso al nombre y la fuente de las reglas. Podemos extraer información de ese argumento pasado el nombre a través nombre de la regla y su fuente (fuente de archivo aka) a través de fuente.. Anteriormente, podríamos evitar duplicar los nombres de los archivos y generalizar un patrón en su lugar. Del mismo modo, podríamos obtener la lista de requisitos previos o dependencias con reglas.prerrequisitos. Para tareas de archivo o cualquier otra tarea, lo mismo se aplica, por supuesto..

Hablando de dependencias, pueden funcionar como una lista para ser iteradas. No hay necesidad de crear un separado cada bucle si juegas bien tus cartas. 

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

Como puede ver, no tuvimos que recorrer manualmente la lista de artículos. Simplemente ponemos a trabajar a Rake y usamos las dependencias, que es mucho más simple y limpia..

Lo que es aún más interesante para el SECADO es que las reglas pueden tomar un objeto proc, un objeto de función anónima, un lambda básicamente, como requisito previo. Eso significa que en lugar de un solo patrón como requisito previo, podemos pasar algo más dinámico que nos permita lanzar una red de patrones que atrapen más que un solo pez. Por ejemplo, reglas para .reducción y .Maryland archivos. 

Tendrían el mismo cuerpo de la regla pero solo un patrón diferente como requisito previo. Es como definir una nueva tarea de archivo para cada objeto devuelto por el objeto proc. Otra forma de trabajar con reglas es expresiones regulares, por supuesto. Pasa un patrón como una dependencia y si tiene una coincidencia, la tarea de archivo se puede ejecutar. Opciones dulces, no?

some_markdown_list = […] detect_source = proc do | html_file_name | some_markdown_list.detect | markdown_source | markdown_source.ext == html_file_name.ext regla final '.html' => detect_source do | r | sh "pandoc -s # r.source -o # r.name" fin

La diferencia entre Procs y Lambdas

Si eres nuevo en Lambda Land o aún no lo has descubierto por completo, aquí tienes un pequeño repaso. Los Procs son objetos que se pueden pasar y que se pueden ejecutar más tarde, al igual que las lambdas. Ambos son objetos Proc, por cierto. La diferencia es sutil y se reduce a los argumentos que se pasan a ellos. Lambdas verifica el número de argumentos y puede explotar con un ArgumentError Por esa razón, a los procs no les importa. La otra diferencia es en cuanto a su manejo de declaraciones de devolución. Procs sale del ámbito donde se estaba ejecutando el objeto proc. Lambdas acaba de salir del ámbito lambda y continúa activando el siguiente código que está en línea, por así decirlo. No es muy importante aquí, pero pensé que para los novatos entre ustedes, tampoco puede hacer daño..

Banderas útiles

Esta es una breve lista de indicadores que puede pasar a las tareas de rake.

  • --reglas

Te muestra cómo Rake intenta aplicar reglas, una traza para reglas. Es invaluable si lidias con un par de reglas y te encuentras con errores.

Cáscara

$ rake quartermaster_gadgets.html --rules Intento de la regla quartermaster_gadgets.html => quartermaster_gadgets.md (quartermaster_gadgets.html => quartermaster_gadgets.md ... EXIST) pandoc -s quartermaster_gadgets.md -o quartermaster_gadgets.html
  • -t

Recuerda el resolver_bonnie_situation tarea del artículo uno? Agreguemos este indicador a esta tarea de Rake y activemos el rastreo. También recibimos un seguimiento si nos encontramos con errores. Esto es ciertamente útil para la depuración.

Cáscara

$ rake solve_bonnie_situation -t ** Invocar solve_bonnie_situation (first_time) ** Invoke get_mr_wolf (first_time) ** Ejecutar get_mr_wolf No tienes ningún problema, Jules, ¡estoy en ello! Entra allí, relájalos y espera al lobo que debería venir directamente. ** Involar calm_down_jimmy (primera vez) ** Ejecutar calm_down_jimmy Jimmy, hazme un favor, ¿quieres? Olí un poco de café allí. ¿Me harías una taza? ** Invocar figure_out_bonnie_situation (first_time) ** Ejecutar figure_out_bonnie_situation Si se me informó correctamente, el reloj está marcando. ¿Es cierto Jimmy? ** Invocar get_vince_vega_in_line (first_time) ** Ejecutar get_vince_vega_in_line ¿Volverás? Que sea directo buster. No estoy aquí para decir por favor! Estoy aquí para decirte qué hacer! ** Invocar clean_car (first_time) ** Ejecutar clean_car Necesito que dos muchachos tomen esos productos de limpieza y limpien el interior del auto. Estoy hablando rápido, rápido, rápido! ** Invoque clean_crew (first_time) ** ¡Ejecuta clean_crew Jim, el jabón! DE ACUERDO. señores, ambos han estado en el condado antes de que esté seguro. ¡Aquí viene! ** Invocar get_rid_of_evidence_at_monster_joes (first_time) ** Ejecutar get_rid_of_evidence_at_monster_joes Entonces, ¿qué pasa con los trajes? ¿Ustedes van a un juego de voleibol o algo? ** Invocar drive_into_the_sunrise (first_time) ** Ejecutar drive_into_the_sunrise Call me Winston! ** Ejecutar resolver_bonnie_situation Sabes, iré a desayunar. Ganas de desayunar conmigo?

Reglas de rastreo

Ajuste Rake.application.options.trace_rules = true en un mismo Rakefile le dice a Rake que nos muestre información de seguimiento sobre las reglas cuando ejecutamos una tarea. Esto es genial porque cuando ejecutamos un seguimiento a través rastrillo -t, con una sola bandera, obtenemos toda la información de depuración que necesitamos. No solo obtenemos una lista de invocaciones de tareas, sino que también podemos ver qué reglas se aplicaron o intentaron.

  • -PAG

Muestra una lista de requisitos previos para todas las tareas. Aquí volvemos a utilizar el resolver_bonnie_situation tarea. Omitiendo salida para otras tareas, esta sería su salida individualizada:

Cáscara

$ 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_crew get_rid_of_evidence_at_monster_joes drive_into_the_sunrise ... 

Si tienes curiosidad corre rastrillo -P. Salida bastante interesante.

  • -metro

Ejecuta tareas como multitareas..

Tareas paralelas

Déjame presentarte a la Tarea múltiple método. Esto puede ayudarle a acelerar un poco las cosas, después de todo, tenemos varios núcleos en la mayoría de las computadoras modernas, así que hagámoslas uso. Por supuesto, siempre puede lograr los aumentos de velocidad escribiendo un código sólido que carezca de grasa, pero ejecutar tareas en paralelo sin duda le puede dar algo más en ese sentido. Hay fallas, sin embargo, que también cubriremos.

Las tareas que ejecutamos hasta ahora ejecutan todas las tareas en secuencia, una después de la otra. Es una apuesta segura si su código está en orden, pero también es más lento. Si la velocidad es importante para alguna tarea, podemos ayudarlo un poco mediante tareas de subprocesos múltiples. Sin embargo, tenga en cuenta que el enfoque secuencial es la mejor opción en algunas circunstancias.

Digamos que tenemos tres tareas de Rake que deben ejecutarse como un requisito previo para ejecutar un cuarto. Estos son cuatro hilos, básicamente. En la imagen más grande de las cosas, cuando se ejecutan varias aplicaciones, o para ser más específicos, los procesos a la vez, la misma idea funciona..

multitask: shoot_bond_movie => [: shoot_car_chase,: shoot_love_scene,: shoot_final_confrontation] do pone "La fotografía principal está lista y podemos comenzar a editar". fin

Utilizando Tarea múltiple, las dependencias en nuestra matriz de requisitos previos ahora ya no se ejecutan en este orden. En su lugar, se extienden y se ejecutan en paralelo, pero antes de la shoot_bond_movie tarea, por supuesto. Un hilo de Ruby para cada tarea se ejecutará al mismo tiempo. Una vez terminados, shoot_bond_movie Hará su negocio. La forma en que actúan las tareas aquí es similar a la aleatorización, pero en realidad se ejecutan al mismo tiempo..

La parte difícil es simplemente asegurarse de que ciertas dependencias se procesen en un orden que se adapte a sus necesidades. Por eso, tenemos que cuidar las condiciones de la raza. Básicamente, esto significa que algunas tareas tienen problemas porque el orden de ejecución tuvo efectos secundarios no deseados. Es un bicho. 

Si podemos evitar eso, logramos la seguridad del hilo. En lo que respecta a los requisitos previos comunes, estos requisitos previos se ejecutarán solo una vez porque los requisitos previos de multitarea esperan su finalización primero.

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_ital____ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ ___ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ menavión, pero no a la par. ] do pone "La fotografía principal está hecha y podemos comenzar a editar". fin

Ambos shoot_car_chase y shoot_final_confrontation las tareas dependen de prepare_italy_set para terminar primero, que solo se ejecuta una vez, por cierto. Podemos usar ese mecanismo para predecir el orden cuando se ejecutan tareas en paralelo. No solo confíe en el orden de ejecución si es de alguna manera importante para su tarea.

Pensamientos finales

Bueno, supongo que ahora estás completamente equipado para escribir un serio negocio de Rake. Hacer un uso adecuado de esta herramienta con suerte hará que tu vida como desarrollador de Ruby sea aún más feliz. En este segundo artículo, espero poder transmitir lo que realmente es una herramienta simple pero maravillosa Rake. Fue creado por un verdadero maestro de su oficio..  

Todos le debemos a Jim Weirich un tremendo respeto por crear esta elegante herramienta de construcción. La comunidad de Ruby ciertamente no es la misma desde que falleció. Sin embargo, el legado de Jim está claramente aquí para quedarse. Otro gigante que tenemos el privilegio de construir sobre.