#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)
translated by Paweł Lenart
Pry jest alternatywą dla IRB i tak, jak IRB, pozwala na wykonywanie kodu Ruby, ale posiada sporo dodatkowych cech. W tym odcinku pokażemy Wam, jak działa Pry i jak zintegrować go z Twoimi aplikacjami w Rails.
Pry jest gemem i prosto go zainstalować. Zainstalujemy dodatkowo gem pry-doc, do czego wrócimy później.
$ gem install pry pry-doc
Jako, że używamy gemsetów w RVM, zainstalujemy Pry tak, żeby był dostępny globalnie we wszystkich gemsetach. Można to zrobić za pomocą poniższego polecenia.
$ rvm gemset use global $ gem install pry pry-doc
Po zainstalowaniu Pry możemy uruchomić go za pomocą polecenia pry i wykonać kod Ruby tak, jakbyśmy używali zwykłego irb.
$ pry pry(main)> 1 + 2 => 3
Pry jest czymś więcej, jak tylko zwykłym kalkulatorem, ale zanim przejdziemy dalej, przyjrzymy się, jak zmusić go do pracy z aplikacją w Rails. Aplikacja, którą używamy jest znajomy blog, który pojawiał się w kilku poprzednich odcinkach.
Jeżeli uruchomimy rails c w katalogu naszej aplikacji, to uruchomi się IRB. Żeby użyć Pry, musimy jedynie uruchomić pry i przekazać ścieżkę do pliku environment. Po tym będziemy mieli dostęp do wszelkich modeli naszej aplikacji, jak w standardowej konsoli Rails.
$ pry -r ./config/environment pry(main)> Article.count => 3
Teraz, gdy Pry jest skonfigurowany, możemy spojrzeć na niektóre jego cechy. Jeżeli wpiszemy help, dostaniemy listę wszystkich poleceń, które są wspierane przez Pry. Dwiema najczęściej używanymi będą cd oraz ls, więc przyjrzyjmy się im. Komenda cd zmienia bieżący zasięg (scope). Tak więc, jeżeli wpiszemy cd Article, znajdziemy się wewnątrz klasy Article. Bieżący zasięg możemy zawsze sprawdzić, wydając polecenie 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)
Będąc wewnątrz klasy Article, możemy wywołać dowolną jej metodę, jak np. first, która zwróci pierwszy artykuł.
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">
Możemy użyć cd w stosunku do dowolnego obiektu. Jeśli wpiszemy cd first będąc wewnątrz klasy Article, zmienimy bieżący zasięg na ten konkretny artykuł. Możemy wywoływać dowolne metody i modyfikować dowolne właściwości, jak name.
pry(#<Class:0x1022f60e0>):1> cd first pry(#<Article:0x102300c98>):2> name => "What is Music"
Możemy nawet dostać się do wewnątrz właściwości name i sięgać do metod łańcucha znaków.
pry(#<Article:0x102300c98>):2> cd name
pry("What is Music"):3> upcase
=> "WHAT IS MUSIC"Pry śledzi nasz poziom zagnieżdżenia i możemy się dowiedzieć, gdzie aktualnie jesteśmy wpisując nesting.
pry("What is Music"):3> nesting
Nesting status:
--
0. main (Pry top level)
1. #<Class:0x1022f60e0>
2. #<Article:0x102300c98>
3. "What is Music"Polecenie zwróci listę obiektów, wewnątrz których jesteśmy. Możemy wrócić do poprzedniego obiektu wpisując exit, w tym przypadku do pierwszego artykułu. Wpisując exit ponownie, zostaniemy cofnięci z powrotem do klasy Article.
Innym powszechnie używanym poleceniem jest ls, które wyświetla listę zmiennych i metod. Domyślnie wyświetla listę wszystkich zmiennych w bieżącym zasięgu, więc jeśli znajdujemy się obecnie wewnątrz klasy Article, to wykonując polecenie zobaczymy listę jej metod.
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]
Niektóre polecenia Pry wspierają użycie flag. Aby zobaczyć listę flag danego polecenia, należy wykonać polecenie dodając do niego opcję -h. Jeżeli wpiszemy ls -h, zobaczymy wszystkie opcje tego polecenia, jak na przykład -m, która służy do wyświetlenia wszystkich metod w klasie lub -M, która zwraca metody instancji. Możemy również przekazać dowolny obiekt, żeby zobaczyć listę metod tego obiektu, aniżeli metod w bieżącym zasięgu.
Kolejnym użytecznym poleceniem Pry jest show-doc. Załóżmy, że chcemy się dowiedzieć, jak działa metoda in_groups_of klasy Array. Rozwiązaniem jest użycie 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"]Możliwe jest wywołanie show-doc bezpośrednio na obiektach. Znajdujemy się obecnie wewnątrz klasy Article, więc możemy wywołać all, aby zwrócić tablicę artykułów. Wywołanie show-doc all.in_groups_of zwróci taką samą dokumentację, jak powyżej.
Innym przydatnym poleceniem jest show-method, które pozwala na obejrzenie kodu źródłowego dowolnej metody. Może być użyte do wyświetlenia kodu źródłowego metody in_groups_of. (Warto wspomnieć, że Pry wspiera uzupełnianie za pomocą klawisza 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
endMamy również polecenie edit-method, które po uruchomieniu otworzy właściwy plik z kodem źródłowym w odpowiedniej linii.
Możliwe jest również wywoływanie poleceń powłoki poprzedzając je kropką. Wykonanie polecenia .ls w Pry wywoła polecenie ls w powłoce i wyświetli listę plików w bieżącym katalogu.
Pry jest przydatny do debugowania. W naszym modelu Article mamy metodę word_count, która powinna zwrocić liczbę wyrazów w artykule. W metodzie jest błąd, ponieważ zawsze zwraca 0, bez względu na zawartość artykułu. Możemy przyjrzeć się metodzie poprzez wykonanie cd do pierwszego artykułu, a następnie wywołując edit-method word_count. Metoda wygląda tak:
/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
Możemy dodać do kodu punkt przerwania (breakpoint) poprzez wywołanie binding.pry. Jeśli dodamy to bezpośrednio przed words.size i zapiszemy plik, to przy następnym wywołaniu metody word_count aplikacja zatrzyma się w miejscu binding.pry i możemy wtedy wrócić do 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: endMamy w tej chwili dostęp do wszystkich zmiennych lokalnych, więc możemy wywołać words, żeby zobaczyć zawartość tablicy words.
pry(#<Article:0x1008c3f38>):3> words => []
Tablica jest pusta, więc wygląda na to, że jest jakiś problem z wyrażeniem regularnym, które przetwarza zawartość. Jeśli się mu przyjrzymy, to zauważymy, że są tam dwa backslashe zamiast jednego. Aby to naprawić, możemy uruchomić edit-method word_count ponownie, poprawić wyrażenie regularne, usunąć linię binding.pry i zapisać plik.
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\w+/) words.size end end
Możemy przetestować poprawkę wywołując word_count ponownie i okazuje się, że tym razem działa zgodnie z oczekiwaniami.
pry(#<Article:0x1008c3f38>):3> word_count => 55
Czasem będziemy chcieli znaleźć błąd w kontrolerze lub w widoku niekoniecznie przy użyciu konsoli. Pry może również pomóc w tej kwestii. Najpierw będziemy musieli dodać Pry w Gemfile.
source 'http://rubygems.org' gem 'rails', '3.0.10' gem 'sqlite3' gem 'nifty-generators' gem 'pry', :group => :development
Następnie wywołujemy bundle, aby zainstalować gem i rails s, żeby uruchomić serwer. Możemy dodać binding.pry gdziekolwiek w naszych kontrolerach, żeby dodać punkt przerwania.
def index @articles = Article.all binding.pry end
Jeżeli przejdziemy do tej strony w przeglądarce, okaże się, że “utknie” w czasie ładowania, a w terminalu uruchomi się Pry dokładnie w miejscu przerwania. Tak, jak w modelu, możemy się przyjrzeć dowolnym zmiennym lokalnym lub zmiennym instancji. Po zakończeniu czynności możemy wpisać exit-all, aby dokończyć żądanie.
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: endTo by było na tyle, jeśli chodzi o odcinek o Pry. Pry jest bardzo użytecznym narzędziem i potrafi o wiele więcej, niż zostało tutaj wymienione. Więcej można zobaczyć na stronie wiki projektu i w screencaście autorstwa Joshuy Cheek.


