#280 Pry with Rails
- Download:
- source codeProject Files in Zip (208 KB)
- mp4Full Size H.264 Video (19.5 MB)
- m4vSmaller H.264 Video (9.74 MB)
- webmFull Size VP8 Video (9.99 MB)
- ogvFull Size Theora Video (25.3 MB)
Pry es una consola de órdenes alternativa a IRB pero con la diferencia de que incluye muchas funcionalidades extra, en este episodio veremos cómo funciona y cómo la podemos integrar en nuestras aplicaciones Rails.
Pry se instala fácilmente como gema. Instalaremos también la gema pry-doc
, más adelante veremos por qué.
$ gem install pry pry-doc
Como estamos usando gemsets de RVM instalaremos Pry para que esté disponible globalmente en todos los gemsets que tengamos. Esto lo podemos hacer con las siguientes órdenes:
$ rvm gemset use global $ gem install pry pry-doc
Tras la instalación de Pry podemos ejecutarlo con pry
. Como con irb
podemos ejecutar el código Ruby que queramos.
$ pry pry(main)> 1 + 2 => 3
Pero Pry es mucho más que una simple calculadora. Antes de adentrarnos en su funcionamiento veremos cómo se configura para trabajar con una aplicación Rails. La aplicación que utilizaremos es la conocida aplicación de blog que hemos usado en varios episodios anteriores.
Si ejecutamos rails c
en el directorio de la aplicación se activará IRB. Para utilizar Pry sólo tenemos que ejecutar pry
pasando el fichero de entorno de Rails. Cuando lo hagamos tendremos acceso a todos los modelos de nuestra aplicación igual que con una consola estándar de Rails.
$ pry -r ./config/environment pry(main)> Article.count => 3
Con esto ya podemos pasar a ver las funcionalidades de Pry. Si escribimos help
veremos un listado con todas las órdenes soportadas pero las dos que usaremos con más frecuencia son cd
y ls
. La orden cd
cambia el ámbito actual, por lo que si escribimos cd Article
nos moveremos a la clase Article
. Podemos comprobar el ámbito en todo momento escribiendo self
.
pry(main)> cd Article pry(#<Class:0x1022f60e0>):1> self => Article(id: integer, name: string, content: text, created_at: datetime, updated_at: datetime, published_at: datetime)
Una vez que estamos dentro de la clase Article
podemos invocar cualquiera de sus métodos, como first
, que devuelve el primer artículo, igual que si escribiésemos Article.first
.
pry(#<Class:0x1022f60e0>):1> first => #<Article id: 1, name: "What is Music", content: "Music is an art form in which the medium is sound o...", created_at: "2011-08-24 20:35:29", updated_at: "2011-08-24 20:37:22", published_at: "2011-05-13 23:00:00">
También podemos hacer cd
en cualquier objeto por lo que si hacemos cd first
en el ámbito Article
cambiaremos al ámbito de ese artículo donde podemos llamar métodos de instancia como por ejemplo name
.
pry(#<Class:0x1022f60e0>):1> cd first pry(#<Article:0x102300c98>):2> name => "What is Music"
También podemos hacer cd
al atributo name
del artículo y trabajar con los métodos de dicha cadena.
pry(#<Article:0x102300c98>):2> cd name pry("What is Music"):3> upcase => "WHAT IS MUSIC"
Pry toma nota del nivel de anidamiento en que nos encontramos.
pry("What is Music"):3> nesting Nesting status: -- 0. main (Pry top level) 1. #<Class:0x1022f60e0> 2. #<Article:0x102300c98> 3. "What is Music"
Esta orden devuelve la lista de objetos en los que hemos entrado. Si escribimos exit
volveremos al objeto anterior, en este caso el primer artículo. Y si volvemos a salir , volveremos a la clase Article
.
La siguiente orden más utilizada es ls
, que enumera las variables y sus métodos. Por defecto lista todas las variables del ámbito actual, por lo que si estamos en Article
, veremos todos los métodos disponibles:
pry(#<Class:0x1022f60e0>):1> ls [:_, :_pry_, :inp, :out, :@_create_callbacks, :@_defined_class_methods, :@_save_callbacks, :@_update_callbacks, :@_validate_callbacks, :@arel_engine, :@arel_table, :@attribute_methods_generated, :@cached_attributes, :@column_names, :@columns, :@columns_hash, :@finder_needs_type_condition, :@generated_attribute_methods, :@inheritable_attributes, :@inheritance_column, :@parent_name, :@quoted_primary_key, :@quoted_table_name, :@relation]
Algunas órdenes de Pry soportan modificadores, que podemos consultar ejecutando la orden con la opción -h
. Si ejecutamos ls -h
veremos todas las opciones soportadas, incluyendo -m
que podemos usar para mostrar un listado de métodos de la clase y -M
que devuelve el listado de los métodos de instancia. También podemos pasarle cualquier objeto o clase para ver sus métodos en lugar de los del ámbito actual.
Otra orden muy útil de Pry es show-doc
. Supongamos que queremos saber cómo funciona el método in_groups_of
de la clase Array. Podemos hacerlo con show-doc Array#in_groups_of
.
pry(#<Class:0x1022f60e0>):1> show-doc Array#in_groups_of From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19: Number of lines: 15 signature: in_groups_of(number, fill_with=?) Splits or iterates over the array in groups of size number, padding any remaining slots with fill_with unless it is false. %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} ["1", "2", "3"] ["4", "5", "6"] ["7", nil, nil] %w(1 2 3).in_groups_of(2, ' ') {|group| p group} ["1", "2"] ["3", " "] %w(1 2 3).in_groups_of(2, false) {|group| p group} ["1", "2"] ["3"]
También podemos invocar show-doc
directamente sobre objetos. Nuestro ámbito es la clase Article
por lo que podemos invocar all
para devolver el listado de artículos. Podemos invocar show-doc all.in_groups_of
para recuperar la misma información que antes.
Otra orden útil es show-method
, que muestra el código fuente de cualquier método. Podemos utilizarlo para ver el código fuente de in_groups_of
(cabe destacar que Pry ofrece autocompletado de los métodos que vamos introduciendo con la tecla de tabulación).
pry(#<Class:0x104e63de0>):1> show-method all.in_groups_of From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19: Number of lines: 19 def in_groups_of(number, fill_with = nil) if fill_with == false collection = self else # size % number gives how many extra we have; # subtracting from number gives how many to add; # modulo number ensures we don't add group of just fill. padding = (number - size % number) % number collection = dup.concat([fill_with] * padding) end if block_given? collection.each_slice(number) { |slice| yield(slice) } else groups = [] collection.each_slice(number) { |group| groups << group } groups end end
Igualmente tenemos la orden edit-method
. Si lo ejecutamos contra un método abrirá el fichero de texto correspondiente en un editor de texto, llevándonos a la línea adecuada.
También podemos ejecutar órdenes de la shell si vienen precedidas por un punto. Si ejecutamos .ls
en Pry, éste ejecutará la orden ls
de la shell y veremos los ficheros del directorio actual.
Pry resulta útil para depurar. En nuestro modelo Article
tenemos el método word_count
que debería devolver el número de palabras que tiene el atributo content
de un artículo. Pero hay un error en dicho código porque siempre devuelve 0
independientemente del contenido que tenga el artículo. Podemos mirar el método haciendo cd
al primer Article
y luego invocando edit-method word_count
. El método tiene el siguiente aspecto:
/app/models/article.rb
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\\w+/) words.size end end
Podemos poner un punto de ruptura en el código con binding.pry
. Si lo hacemos justo antes de la línea words.size
y guardamos el archivo, la próxima que ejecutemos word_count
se parará en la invocación de binding.pry
y nos devolverá a la interfaz de órdenes de Pry.
> word_count From: /Users/eifion/blog/app/models/article.rb @ line 7 in Article#word_count: 2: attr_accessible :name, :content, :published_at 3: has_many :comments 4: 5: def word_count 6: words = content.scan(/\\w+/) => 7: binding.pry 8: words.size 9: end 10: end
Tenemos acceso a todas las variables locales del método, por lo que podemos invocar words
para ver los contenidos del array.
pry(#<Article:0x1008c3f38>):3> words => []
Parece que hay algo mal con la expresión regular que recupera el contenido, porque éste se encuentra vacío. Examinándola con más detalle veremos que hay dos barras invertidas donde debería haber sólo una. Para corregir esto podemos ejecutar edit-method word_count
, arreglar la expresión regular, quitar la línea binding.pry
y guardar el archivo.
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\w+/) words.size end end
Podemos comprobar nuestro arreglo llamado a word_count
de nuevo, y esta vez funciona como sería de esperar.
pry(#<Article:0x1008c3f38>):3> word_count => 55
Gemfile
.</o>
source 'http://rubygems.org' gem 'rails', '3.0.10' gem 'sqlite3' gem 'nifty-generators' gem 'pry', :group => :development
Luego podemos ejecutar bundle
para instalar las gemas y luego rails s
para arrancar el servidor, y ya podemos ir dejando llamadas a binding.pry
en nuestros controladores para establecer puntos de ruptura.
def index @articles = Article.all binding.pry end
Si abrimos dicha página con un navegador se quedará pegada durante la carga pero en el terminal veremos la interfaz de Pry que ha detenido la ejecución en el punto de ruptura, donde podemos inspeccionar los valores de las variables locales o de instancia del modelo. Una vez que hayamos terminado podemos hacer exit
para que la petición finalice.
From: /Users/eifion/blog/app/controllers/articles_controller.rb @ line 4 in ArticlesController#index: 1: class ArticlesController < ApplicationController 2: def index 3: @articles = Article.all => 4: binding.pry 5: end 6: 7: def show 8: @article = Article.find(params[:id]) 9: end
Con esto terminamos este episodio sobre Pry. Se trata de una gema muy útil que hace mucho más que lo que hemos visto hoy. El wiki detalla mucha más información e incluye un enlace a un vídeo realizado por Joshua Cheek.