W zeszłym tygodniu wspomniałem o debugowaniu elixir z wykorzystaniem IEx.pry/0
– metody umożliwiającej za pomocą edycji pliku z kodem ustawienie breakpointa. Taki brakpoint będzie za każdym razem wywołany jak metoda będzie wykonana. Do tego wymagane było dodanie require z iex na samym początku pliku. Ogólnie dużo zachodu z edytowaniem pliku którego lepiej nie mieć. Na szczęście o tym samym pomyśleli twórcy elixir i wraz z wersją 1.5 dali nam do dyspozycji szereg komend umożliwiających prawie to samo co IEx.pry/0
.
Zanim więc będziecie mogli przetestować nową funkcjonalność trzeba zaktualizować elixir do najnowszej wersji. Jak? To zależy od platform i pozostawiam wam do zarobienia. Mając już wersje 1.5 zainstalowaną, możemy zacząć bawić się nowymi komendami.
Tylko, że…… nowe komendy działają, jeżeli nasz kod jest przekompilowany i plik beam dostępny. Najszybciej to się robi za pomocą…… mix
:) Więc polecam stworzyć mały projekt i wrzucić tam po prostu nasz ukochany plik testowy Bencode.ex
. Najlepiej jakby nie zawierał on modyfikacji z zeszłego tygodnia.
Możemy teraz odpalić nasz nowy projekt za pomocą:
iex -S mix
Wraz z nowym elixir mamy do dyspozycji makro break!
Które ustawia nam breakpoint na danej metodzie. Na przykład w bencode możemy ustawić sobie breakpoint w następujący sposób:
break! Bencode.decode/1 break!(Bencode, :decode, 1, 1)
Obydwa makra zrobią to samo, ustawią nam breakpoint na wejściu do funkcji decode/1
i ustawią go tylko na jedno uruchomienie.
Możemy podejrzeć wszystkie dostępne breakpointy jakie mamy za pomocą polecenia breaks
:
iex(2)> breaks ID Module.function/arity Pending stops ---- ----------------------- --------------- 1 Bencode.decode/1 1
Całość wygląda mniej więcej tak:
Jeżeli teraz byśmy chcieli przetestować breakpoint to wystarczy, że wywołamy naszą funkcję a elixir zwróci nam:
iex(3)> Bencode.decode("i15e") Break reached: Bencode.decode/1 (lib/bencode.ex:31) 29: 30: """ 31: def decode (input) do 32: 33: val = input |> do_decode |> elem(0) pry(1)>
Jak widać pokarze on nam miejsce, w którym się zatrzymał nasz kod i odpali pry
. A to już znamy :) możemy tutaj dowiedzieć się o wartościach itp. Jest jednak jedno, ale – nie możemy ustawić linii. Możemy jedynie ustawiać breakpointy na metodzie. Co ma swoje plusy i minusy.
Jak już jesteśmy w breakpoint to za pomocą whereami/1
możemy wypisać sobie X
linii kodu przed i po naszym breakpointcie.
pry(5)> whereami 5 Location: lib/bencode.ex:31 26: 27: iex> Bencode.decode("d4:testi1ee") 28: {:ok, %{"test" => 1}} 29: 30: """ 31: def decode (input) do 32: 33: val = input |> do_decode |> elem(0) 34: 35: 36: case val do
To wygląda mniej więcej tak:
Oczywiście, możemy sprawdzić wartość input jak chcemy. To działa jak działało. Powrót jest taki sam – respawn/0
.
Jeżeli zaś mamy więcej breakpointów to możemy zrobić continue/0
i kod będzie działał aż do kolejnego breakpointa jeżeli jest. Jeżeli go nie ma to nam się iex zawiesi :)
Jeżeli zaś powróciliśmy do iex to możemy wykonać polecenie breaks
jeszcze raz by zobaczyć, że wartość w kolumnie stop uległa zmianie. A to znaczy, że jak wykonamy naszą metodę a cyfra tam jest na 0 to nasz breakpoint nie zadziała.
Możemy wyresetować wartość stop za pomocą reset_break/1
gdzie wartością jest ID naszego breakpointa z listy breaks
– jednak u mnie to nie działało.
Podsumowanie
Najlepszą rzeczą jaką daje nam ta cała funkcjonalność to testowanie i debugowanie już istniejącego kodu – kodu elixira. Na przykład interesuje nas co się stanie kiedy wykonamy IO.puts/1
?
break! IO.puts/1
Teraz jak wpiszemy:
IO.puts "test"
To zatrzymamy się w danym kontekście. Fajne to i przydatne jak się nie wiemy co nie działa i może to być wina zewnętrznej biblioteki.
Fajnie, że takie opcje dodali twórcy do elixira bo mogą być one przydatne. Na pewno jest to lepsze niż IEx.pry/0
– nie ma edycji kodu za cenę breakpointa na metodzie a nie na konkretnej linijce.
A wy co o tym sądzicie?
Ja poczekam co powiesz, jak zajmiesz się tracingiem i podobnymi elementami dostępnymi w ERTS / OTP w temacie “introspekcji”. ;)
;) tez jestem ciekaw :)
Comments are closed.