#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 end
Mamy 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: end
Mamy 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: end
To 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.