#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 est une alternative à IRB et, comme IRB, il fournit une invite de commande permettant d'exécuter du code Ruby. Ce qui fait la différence, c'est un nombre important de fonctionnalités en plus. Dans cet épisode, nous allons vous montrer comment Pry fonctionne et comment l'intégrer dans vos applications Rails.
Pry est fournit sous forme de gem et est facile à installer. Nous allons également installer la gem pry-doc
, nous reviendrons dessus plus loin.
$ gem install pry pry-doc
Comme nous utilisons les gemsets RVM, nous allons installer Pry de manière à ce qu'il soit accessible globalement, peu importe le gemset utilisé. Nous pouvons le faire grâce aux deux commandes suivantes.
$ rvm gemset use global $ gem install pry pry-doc
Une fois Pry installé, nous pouvons lancer la commande pry
et exécuter du code Ruby comme nous le ferions avec irb.
$ pry pry(main)> 1 + 2 => 3
Pry est bien plus qu'un simple calculateur mais, avant d'aller plus loin, nous allons voir comment le faire fonctionner avec une application Rails. Nous allons utiliser l'application de blog qui nous a déjà servi dans de précédents épisodes.
Si nous lançons rails c
depuis le dossier de l'application, IRB va démarrer. Pour utiliser Pry à la place, nous devons juste appeler la commande pry
et lui passer le fichier d'environnement Rails. Cela fait, nous pouvons accéder aux modèles de notre application, comme dans la console Rails classique.
$ pry -r ./config/environment pry(main)> Article.count => 3
Maintenant que Pry est en place, nous pouvons voir certaines de ses fonctionnalités de plus près. Si nous tapons help
, nous allons obtenir la liste de toutes les commandes à notre disposition. Les deux que nous allons utiliser le plus souvent sont cd
et ls
, jetons-y un œil. La commande cd
change le scope courant. Si nous tapons cd Article
, nous allons nous placer dans la classe Article
. Nous pouvons connaitre le scope courant à tout moment en appelant 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)
Maintenant que nous somme dans la classe Article, nous pouvons appeler n'importe laquelle de ses méthodes, first
par exemple, pour retourner le premier article, comme si nous appelions 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">
Nous pouvons également faire cd
sur un objet. Si nous appelons cd first
en étant dans le scope Article
, nous allons changer de scope pour être dans celui du premier article. Nous pouvons dès lors appeler n'importe quelle méthode ou propriété dessus, name
par exemple.
pry(#<Class:0x1022f60e0>):1> cd first pry(#<Article:0x102300c98>):2> name => "What is Music"
Nous pouvons même faire cd
dans le name
de l'article et appeler des méthodes sur cette chaine de caractères.
pry(#<Article:0x102300c98>):2> cd name pry("What is Music"):3> upcase => "WHAT IS MUSIC"
Pry conserve une trace de nos déplacements que nous pouvons voir en appelant nesting
.
pry("What is Music"):3> nesting Nesting status: -- 0. main (Pry top level) 1. #<Class:0x1022f60e0> 2. #<Article:0x102300c98> 3. "What is Music"
Cette commande retourne une liste des objets que nous avons traversé. Si nous tapons exit
, nous allons remonter dans l'objet précédant, dans notre cas, le premier article. Si nous remontons de nouveau, nous serons de retour dans la classe Article
.
L'autre commande fréquemment utilisée est ls
. Cette commande liste les variables et méthodes. Par défaut, elle va lister celles du scope courant. Si, par exemple, nous sommes dans la classe Article
, nous verrons ses méthodes lorsque nous appellerons ls
.
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]
Certaines commandes Pry supportent des options et nous pouvons obtenir une liste des options d'une commande en la lançant avec l'option -h
. Si nous lançons ls -h
, nous verrons la liste des options qu'elle supporte, y compris -m
qui permet de lister les méthodes de classe et -M
qui liste les méthodes d'instance. Nous pouvons également passer en paramètre un objet ou une classe pour obtenir une liste des méthodes de celui-ci plutôt que pour le scope courant.
Une autre commande Pry utile est show-doc
. Disons que nous voulons savoir comment fonctionne la méthode in_groups_of
de la classe Array
. Nous pouvons le savoir en lançant 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"]
Nous pouvons également appeler show-doc
directement sur un objet. Notre scope courant est celui de la classe Article
, nous pouvons donc appeler all
pour obtenir un tableau des articles. Nous pouvons ensuite lancer show-doc all.in_groups_of
pour voir la même documentation que ci-dessus.
Autre commande utile, show-method
. Cette dernière nous montre le code source d'une méthode. Nous pouvons l'utiliser pour voir la source de in_groups_of
(notons que Pry offre l'auto-complétion des commandes grâce à la touche TAB).
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
Conjointement, nous trouvons la commande edit-method
. Lorsque nous la lançons en lui passant une méthode en paramètre, elle va ouvrir le fichier adéquat dans un éditeur de texte et nous placer sur la ligne appropriée.
Nous pouvons également lancer une commande shell en la préfixant d'un point. Si nous lançons .ls
dans Pry, la commande shell ls
va être appelée et va lister les fichiers du dossier courant.
Pry est également très utile pour le debug. Dans notre modèle Article
, nous avons une méthode word_count
qui devrait retourner le nombre de mots dans le contenu d'un article. Il y a un bug dans cette méthode car elle retourne toujours 0
, quelque soit le contenu de l'article. Nous pouvons voir la méthode en faisant cd
dans le premier Article
et en lançant edit-method word_count
. Cette méthode ressemble à ceci :
/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
Nous pouvons ajouter un breakpoint à n'importe quel endroit du code en appelant binding.pry
. Si nous le faisons juste avant la ligne words.size
et sauvons le fichier, lorsque nous appelons la méthode word_count
de nouveau, l'exécution va s'arrêter sur binding.pry
et nous redonner la main sur 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
Nous avons accès à toutes les variables locales à la méthode. Nous pouvons donc appeler words
pour voir le contenu du tableau words
.
pry(#<Article:0x1008c3f38>):3> words => []
Le tableau est vide, il semble donc qu'il y ait un problème avec l'expression régulière qui scanne le contenu. Si nous y jetons un œil, nous voyons qu'il y a deux backslashes là où il ne devrait y en avoir qu'un seul. Pour corriger cela, nous pouvons de nouveau faire appel à edit-method word_count
, corriger l'expression, retirer binding.pry
et sauver le fichier.
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\w+/) words.size end end
Nous pouvons tester notre correctif en appelant une nouvelle fois word_count
. Cette fois, elle fonctionne comme désiré.
pry(#<Article:0x1008c3f38>):3> word_count => 55
Nous avons parfois besoin de debugger un contrôleur ou une vue de notre application et la console Rails n'est pas toujours le plus simple pour cela. Pry nous aide également à le faire. Tout d'abord, nous devons ajouter Pry à notre Gemfile.
source 'http://rubygems.org' gem 'rails', '3.0.10' gem 'sqlite3' gem 'nifty-generators' gem 'pry', :group => :development
Nous appelons ensuite bundle
pour installer la gem puis nous lançons rails s
pour démarrer le serveur. Nous pouvons maintenant ajouter un appel à binding.pry
n'importe où dans nos contrôleurs pour ajouter un breakpoint.
def index @articles = Article.all binding.pry end
Si nous visitons cette page dans le navigateur, elle va bloquer sur le chargement. Dans le terminal, on peut voir une invite de commande Pry et nous sommes dans le contexte du breakpoint. Comme nous le faisions dans les modèles, nous pouvons inspecter les valeurs de toutes les variables locales. Une fois notre travail terminé, nous pouvons taper exit-all
pour permettre à la requête de se terminer.
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
C'est tout pour cet épisode sur Pry. C'est une gem très utile et elle fournit bien plus de fonctionnalités que ce que nous venons de vous montrer. Le wiki couvre beaucoup plus et contient un lien vers un très bon screencast réalisé par Joshua Cheek.