<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rubysfera &#187; Warte uwagi</title>
	<atom:link href="http://rubysfera.pl/category/warte-uwagi/feed/" rel="self" type="application/rss+xml" />
	<link>http://rubysfera.pl</link>
	<description>Kolejna witryna oparta na WordPressie</description>
	<lastBuildDate>Wed, 02 May 2012 19:17:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Warte uwagi: CoffeeScript</title>
		<link>http://rubysfera.pl/2011/05/warte-uwagi-coffeescript/</link>
		<comments>http://rubysfera.pl/2011/05/warte-uwagi-coffeescript/#comments</comments>
		<pubDate>Mon, 16 May 2011 06:51:49 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=914</guid>
		<description><![CDATA[Dziś parę słów o <strong>CoffeScript</strong>, elegancki język, który sprawi, że pisanie <strong>Javascriptu</strong> będzie przyjemne.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2011/05/warte-uwagi-coffeescript/coffe_script/" rel="attachment wp-att-922"><img src="http://rubysfera.pl/wp-content/uploads/2011/05/coffe_script.png" alt="" title="coffe_script" width="300" height="200" class="alignright size-full wp-image-922" /></a></p>
<p>Javascript szturmem zdobywa popularność jako język ogólnego rażenia. Nie jest to już język do wstawiania zabawnych skryptów na stronie. Coraz częściej jest on używany również po <a href="http://pow.cx/">stronie</a> <a href="http://nodejs.org/">back-endu</a>. </p>
<p>Rosnąca popularność nie zmienia jednej rzeczy, mianowicie tego, że:</p>
<h3>Javascript jest brzydki jak noc!</h3>
<p>Rozwiązaniem tego problemu jest <strong>CoffeeScript</strong>. Jest to prosty język, który kompiluje się do poprawnego JavaScriptu, a składnią przypomina Rubiego lub Pythona. Poniżej próbka:
<pre class="sh_ruby">
# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)
</pre>
<p>Prawda, że wygląda nieźle?  Jeśli wam się to podoba, to polecam zajrzeć na <a href="http://jashkenas.github.com/coffee-script/">oficjalną stronę</a> lub do <a href="http://kawoskrypt.heroku.com/">prezentacji</a>, którą wygłosiłem na ostatnim <a href="http://wrug.eu/2011/05/11/2011-05-spotkanie-majowe/">wrugu</a>.
<p> Dla tych którym nie chcę się instalować Kawoskryptu poprzez <a href="http://npmjs.org/">Node Package Managera</a> (co jest sugerowanym sposobem instalacji) polecam <a href="http://weblog.rubyonrails.org/2011/5/5/rails-3-1-beta-1-released">Railsy 3.1</a> &#8211; tam CoffeeScript jest na dzień dobry. </p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/05/warte-uwagi-coffeescript/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Ruby z napędem odrzutowym &#8211; o kompilacji słów kilka</title>
		<link>http://rubysfera.pl/2011/02/ruby-z-napedem-odrzutowym-o-kompilacji-slow-kilka/</link>
		<comments>http://rubysfera.pl/2011/02/ruby-z-napedem-odrzutowym-o-kompilacji-slow-kilka/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 09:00:57 +0000</pubDate>
		<dc:creator>Jan Stępień</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=775</guid>
		<description><![CDATA[Post gościnny, w którym Jan Stępień opisuje swój kompilator tłumaczący podzbiór Ruby do C.]]></description>
			<content:encoded><![CDATA[<h3>Maszyna wirtualna to za mało</h3>
<p>Czytelnicy tego bloga dobrze znają i cenią sobie zalety języka Ruby. Wysoka ekspresywność, zwięzła składnia, dynamiczne dopisywanie metod, mechanizmy refleksji i ogromna, aktywna społeczność to tylko niektóre z nich. Niestety w życiu nic nie ma za darmo. Ruby to niemal przysłowiowy przykład języka o bardzo niskiej wydajności. Zmiany wprowadzone w wydaniu 1.9 poprawiły w pewnym stopniu szybkość wykonania ale nie przyniosły rewolucji. MRI nadal zajmuje <a href="http://shootout.alioth.debian.org/u32/which-programming-languages-are-fastest.php">ostatnie miejsca w rankingach wydajności</a> różnych języków programowania.</p>
<p>Na przestrzeni ostatnich lat podejmowano różne próby poradzenia sobie z tym problemem. Jako przykład należy wskazać aktywnie rozwijany projekt <a href="http://jruby.org">JRuby</a>, kompilujący Ruby to bytecode&#8217;u JVM. Podobne rozwiązanie zaproponował Microsoft przedstawiając projekt <a href="http://ironruby.net">IronRuby</a> oparty o .NET Framework. Własną maszynę wirtualną zaprojektowali autorzy <a href="http://rubini.us">Rubinius</a>, którzy pracują nad implementacją Ruby wykorzystującą LLVM do kompilacji <a href="http://en.wikipedia.org/wiki/Just-in-time_compilation">JIT</a>.</p>
<p>Wspólnie z Julianem Zubkiem, moim kolegą z wydziału, postanowiliśmy podejść do zagadnienia z innej strony. Spojrzeliśmy na przeciwległy koniec rankingów wydajności, gdzie dominują języki kompilowane do kodu maszynowego. Zdecydowaliśmy się stworzyć własną implementację Ruby tłumaczącą wejściowy kod do C. Wyjściowy kod miał być następnie kompilowany przez GCC lub inny kompilator do pliku wykonywalnego z natywnym kodem maszynowym.</p>
<p>Na dobrą sprawę jedyną cechą wspólną Ruby i C jest pisanie kodu od lewej do prawej i z góry na dół. Poza tym podobieństwem dzieli je przepaść. W C ze świecą szukać obiektowości, wyjątków, mechanizmów refleksji, automatycznego odśmiecania pamięci czy domknięć, w Ruby znanych jako bloki. Wyróżnia go jednak jedna istotna zaleta &#8211; powstały zeń kod maszynowy jest wyjątkowo szybki. Stąd nasza decyzja o wybraniu go jako język docelowy.</p>
<h3>Przetwarzanie drzew</h3>
<p><a rel="attachment wp-att-786" href="http://rubysfera.pl/2011/02/ruby-z-napedem-odrzutowym-o-kompilacji-slow-kilka/ast/"><img class="alignleft size-large wp-image-786" src="http://rubysfera.pl/wp-content/uploads/2011/02/ast-1024x419.png" alt="abstract syntax tree" width="300" height="123" /></a></p>
<p>Nasz projekt został zaimplementowany w Ruby. Jego ogólna architektura jest dość prosta. Wejściowy kod w Ruby przetwarzamy przy pomocy gema <a href="http://parsetree.rubyforge.org">ruby_parser</a> uzyskując z niego tzw. AST, <em>abstract syntax tree</em>, czyli drzewiastą reprezentację struktury programu ułatwiającą dalszą manipulację. Otrzymane drzewo jest następnie przekazywane do serca naszego kompilatora, który analizuje je i stopniowo buduje z niego AST wyjściowego kodu C. Odpowiadający za to zadanie moduł to kluczowy element naszego projektu, w którym zawarta jest cała logika translacji. W oparciu o powstałe AST C generowany jest właściwy kod wyjściowy. Na koniec otrzymany kod jest kompilowany przez GCC i linkowany z zaimplementowanym przez nas skrawkiem biblioteki standardowej Ruby.</p>
<p>Moduł przetwarzający drzewo Ruby na drzewo C analizuje wejściowy kod w sposób naśladujący proces jego wykonania. Najpierw zapoznaje się z deklaracjami wszystkich klas i ich metod, ale nie analizuje od razu ich wnętrza. Analizę kodu wewnątrz danej metody rozpoczyna dopiero przy napotkaniu jej wywołania. Podejście to ma pewną istotną zaletę. Analizując metodę w momencie jej wywołania uzyskujemy wiedzę na temat typów przekazywanych do niej argumentów. Dzięki temu możemy poczynić pewne optymalizacje w kodzie wynikowym, które omówię w dalszej części artykułu.</p>
<p>Statyczna analiza całego kodu przed jego wykonaniem pozwala uzyskać wiele innych cennych informacji. Dzięki niej możemy ustalić na etapie kompilacji nazwy wszystkich zmiennych klasowych i instancyjnych. Jesteśmy też w stanie sprawdzić czy metody w obrębie danej klasy są nadpisywane lub czy klasa jest rozszerzana. Możemy też jednoznacznie przewidzieć typy obiektów, na które wskazywać będą poszczególne zmienne. Wszystkie te informacje są bardzo przydatne. Mogą być wykorzystane do zastąpienia wielu dynamicznych i &#8211; co za tym idzie &#8211; wolnych operacji statycznymi i szybkimi rozwiązaniami.</p>
<h3>Do rzeczy, co działa?</h3>
<p>Po trzech miesiącach prac nasz projekt wspiera strukturalną i obiektową składnię Ruby, nadpisywanie metod, proste bloki i odśmiecanie pamięci. Różnice między wejściowym a wyjściowym językiem wymusiły na nas zaimplementowanie powyższych wysokopoziomowych funkcjonalności w czystym C. Postaram się pokrótce przedstawić realizację każdej z nich.</p>
<p>Obiektowość Ruby została zrealizowana w C przy pomocy dostępnych w nim struktur i funkcji. Obiekty reprezentowane są jako struktury zawierające informację o swoim typie oraz wskaźniki na zawarte w nich pola. Pozwala na to analiza całego kodu na etapie kompilacji, w trakcie której jesteśmy w stanie ustalić wszystkie zmienne instancyjne w obrębie danej klasy.</p>
<p>Metody są realizowane jako funkcje, do których jako pierwszy argument przekazywany jest wskaźnik na obiekt <code>self</code> a następnie przekazywane są właściwe argumenty wywołania. Ze względu możliwość pominięcia w Ruby <code>return</code> na końcu ciała metody, nasz translator zapamiętuje ostatnie wyrażenie i automatycznie zwraca je z wynikowej funkcji w C. Dotyczy to też bardziej złożonych konstrukcji, jak choćby <code>if</code> na przykładzie wartości bezwzględnej:</p>
<pre>def abs(x)
  if x &gt; 0
    x
  else
    -x
  end
end</pre>
<p>W tym miejscu warto wspomnieć o innej ciekawej cesze Ruby. Poza nielicznym wyjątkami, każda instrukcja jest wyrażeniem, co na polski tłumaczy się jako ,,wszystko zwraca jakąś wartość&#8221;. Widać to na przykładzie powyższej metody <code>abs</code>. Zwraca ona wartość ostatniego wyrażenia, czyli <code>if</code>, który zwraca z kolei wartość ostatniego wyrażenia z jednej ze swoich odnóg. Cała ta funkcjonalność również musiała zostać sztucznie przeniesiona w C. Nasz kompilator zapamiętuje wartości zwracane przez wszystkie wyrażenia na wypadek konieczności zwrócenia lub wykorzystania ich na późniejszym etapie.</p>
<p>Bloki są traktowane podobnie jak metody. Każdy z nich jest tłumaczony do funkcji w C. Podczas wykonania, przed wywołaniem metody do której przekazujemy blok, umieszczamy odpowiadający mu wskaźnik na funkcję go na specjalnym stosie. Metoda wykorzystująca blok pobiera wskaźnik w momencie skorzystania z instrukcji <code>yield</code>. Dzięki rozwiązaniu ze stosem rozwiązanie pozwala na zagnieżdżone bloki, wszechobecne m.in. w testach utworzonych przy pomocy RSpeca. Obecna implementacja nie pozwala jeszcze na korzystanie ze zmiennych zdefiniowanych poza blokiem, ale jest to jedna z priorytetowych pozycji na naszej liście zadań do zrobienia.</p>
<p>Automatyczne odśmiecanie pamięci jest bardzo skomplikowanym zagadnieniem. Śledzenie wszystkich odwołań do obiektów, ustalanie, czy są nadal używane, czy też efektywne algorytmy zarządzania alokacją to tylko wierzchołek góry lodowej jaką stanowi utworzenie własnego <em>garbage collectora</em>. Na szczęście istnieją jednak gotowe rozwiązania, które rozwiązują ten problem.</p>
<p>W naszym projekcie wykorzystaliśmy <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm GC</a> &#8212; dojrzałą bibliotekę pozwalającą na bardzo proste dołączenie automatycznego odśmiecania pamięci do swoich projektów w C. Dzięki temu cały proces zwalniania pamięci odbywa się w tworzonych przez nasz kompilator programach automatycznie i efektywnie, a my mogliśmy bez przeszkód poświęcić całą swoją uwagę procesowi translacji.</p>
<h3>Metody po raz wtóry</h3>
<p><a rel="attachment wp-att-798" href="http://rubysfera.pl/2011/02/ruby-z-napedem-odrzutowym-o-kompilacji-slow-kilka/uml/"><img class="alignright size-large wp-image-798" src="http://rubysfera.pl/wp-content/uploads/2011/02/uml-798x1024.png" alt="" width="300" height="385" /></a></p>
<p>Dynamiczne wiązanie metod, które pozwala między innymi na pisanie bardzo zwięzłych testów przy pomocy RSpeca, jest operacją wyjątkowo kosztowną. Przeanalizujmy proces wywoływania metody w Ruby. Najpierw musimy ustalić klasę obiektu. Następnie, znając typ, możemy sprawdzić w odpowiedniej strukturze danych, czy dana klasa ma metodę o zadanej nazwie. Jeśli nie, przechodzimy do nadklasy i powtarzamy procedurę aż do <code>Object</code>. W przypadku niepowodzenia wołamy <code>method_missing</code>. Jeśli uda nam się znaleźć odpowiednią metodę, możemy wreszcie przekazać do niej argumenty. Zainteresowanych szczegółami odsyłam do pliku vm_method.c w źródłach MRI.</p>
<p>Zwróćcie uwagę, że wspomniana struktura przechowująca informacje o metodach musi pozwalać na modyfikacje. Jak wiemy, w Ruby metody klas możemy zmieniać niczym rękawiczki, co każdorazowo wymusza naniesienie zmian w owej tablicy. Stawiając wymaganie możliwości rozszerzania i modyfikowania tablicy metod musimy liczyć się z tym, że odbije się to na wydajności operacji przeszukiwania.</p>
<p>Zastanówmy się teraz co możemy zyskać przy pomocy statycznej analizy kodu dokonywanej przez nasz kompilator. Zakładając, że nie użyta zostanie metoda <code>send</code> lub <code>eval</code>, jesteśmy w stanie ustalić nazwy wszystkich metod danej klasy. Jeśli nie miały miejsca żadne nadpisania, możemy nawet na etapie kompilacji przypisać poszczególnym nazwom konkretne funkcje w C. Zysk jest oczywisty. Zamiast całej przedstawionej wyżej procedury wywołanie metod sprowadza się do wykonania funkcji C.</p>
<p>Powyższej optymalizacji nie można zastosować we wszystkich przypadkach. Bardzo często nie potrafimy w czasie kompilacji ustalić typu danej zmiennej. Przykład takiej sytuacji to metoda, która w pewnych warunkach zwraca <code>nil</code> a w innych obiekt <code>String</code>. W takim wypadku musimy zastosować inną strategię. Na etapie kompilacji zapisujemy w pliku wynikowym strukturę danych pozwalającą na możliwie szybkie skojarzenie typu i nazwy metody ze wskaźnikiem na funkcję C. Dodatkowe informacje uzyskane na etapie kompilacji pozwalają nam na poczynienie w tym miejscu kolejnych usprawnień.</p>
<p>Zauważmy, że biorąc pod uwagę znajomość nazw wszystkich metod podczas translacji, struktura przechowująca metody nie musi wspierać operacji dodawania. Jest tworzona tylko raz, podczas kompilacji, a na późniejszym etapie nie potrzebujemy dodawać do niej nowych elementów. Stawiamy przed nią tylko dwa wymagania. Po pierwsze, ma pozwalać na bardzo szybkie znajdowanie elementów &#8211; funkcji &#8211; po kluczu &#8211; nazwie metody &#8211; a po drugie ma pozwalać na nadpisanie wartości przypisanej kluczowi w razie nadpisania metody wewnątrz klasy.</p>
<p>Okazuje się, że wymagania te pozwalają nam na wykorzystanie struktury o lepszych właściwościach od drzewa czy tablicy z haszowaniem. Do przechowywania informacji o metodach stosujemy tzw. perfekcyjne tablice z haszowaniem. Nie chcę w tym miejscu rozpoczynać szczegółowego opisu tych struktur &#8211; zainteresowanych odsyłam na Wikipedię. Podkreślę tylko, że podobnie jak tradycyjne tablice z haszowaniem struktury te zapewniają nam dostęp w czasie stałym. Na ich korzyść świadczy brak kolizji, zagwarantowany przez funkcję haszującą zoptymalizowaną pod kątem zadanego zestawu kluczu, który w naszym wypadku jest zbiorem nazw metod danej klasy.</p>
<p>Połączenie wyszukiwania metod w perfekcyjnych tablicach z haszowaniem ze statycznym wywoływaniem funkcji tam, gdzie jest to możliwe, pozwala nam na osiągnięcie zdecydowanego zysku w porównaniu z MRI. Wynik ten da się jeszcze poprawić przy pomocy cache&#8217;owania wyników przeszukiwania tablic metod lub zastosowania w ich miejsce tradycyjnych tablic C. Jest to jedno z głównych zagadnień, któremu chcemy stawić czoła w trakcie dalszego rozwoju naszego projektu.</p>
<h3>Wyniki i plany na przyszłość</h3>
<p>Mógłbym dalej mnożyć przykłady ciekawych cech Ruby, których translacja do C nie była oczywista. Każda z nich stanowiła dla nas ciekawe zadanie wymagające przemyślenia i eksperymentów z różnymi podejściami. Czas jednak nagli, a ja nie przedstawiłem jeszcze wyników.</p>
<p>Poza garniturem testów funkcjonalnych weryfikujących poprawność naszej implementacji w porównaniu z Ruby 1.9.2 przygotowaliśmy kilka testów wydajnościowych. Są to proste, akademickie testy, jak choćby mnożenie macierzy, dwa różne sortowania, operacje na liczbach zmiennoprzecinkowych czy test głębokiej rekurencji przy pomocy funkcji Ackermanna. Uruchomiliśmy je na naszej implementacji oraz porównaliśmy ich czas wykonania z wynikami osiągniętymi przez Ruby 1.9.2.</p>
<p>W kilku spośród powyższych testów uzyskaliśmy zdecydowaną, niemal pięciokrotną przewagę. Były jednak przypadki, w których to MRI osiągnęło lepsze wyniki. Motywuje nas to do dalszej pracy, tym bardziej, że mamy jeszcze wiele pomysłów na dalsze usprawnienia i optymalizacje.</p>
<p>Wyniki profilowania testów pokazały, że koszt dynamicznego wołania metod przy braku znajomości typu obiektu jest dość wysoki. Podczas dalszych prac mamy zamiar skupić się na rozwiązaniach, które pozwoliłyby go zredukować. Poza optymalizacją mechanizmów wyszukiwania odpowiednich funkcji do wywołania, kluczowe jest tutaj uzyskanie na etapie translacji jak najwięcej informacji o typach obiektów, których metody wołamy. Zysk wydajności można by uzyskać na przykład ustalając typy obiektów przechowywane w kolekcjach takich jak <code>Array</code> czy <code>Hash</code>. Śledząc wszystkie operacje wykonywane na tych strukturach moglibyśmy stwierdzić, że niektóre z nich przechowują obiekty tylko jednego typu, np. <code>String</code>, co pozwoliłoby na przyspieszenie wołania ich metod.</p>
<p>Poza próbami wyciśnięcia z generowanego przez nas kodu jak najlepszych wyników musimy również zabrać się ze implementację niewspieranych jeszcze cech Ruby. Przykłady to m.in. system wyjątków, moduły, lambdy i praca nad biblioteką standardową. Mamy już pomysł na implementację niektórych spośród tych funkcjonalności, jak np. wyjątków czy modułów, więc już wkrótce powinny zostać dodane do listy obsługiwanych przez nasz kompilator elementów Ruby. Z drugiej strony wielowątkowość jest bardzo skomplikowanym zagadnieniem, którego obsługa niesie za sobą konieczność wielu kosztownych zmian w naszym projekcie, zarówno z punktu widzenia czasu programisty jak i czasu wykonania wyjściowych programów.</p>
<p>Obecnie staramy się doprowadzić nasz kod do stanu, w którym będziemy mogli bez obciachu pochwalić się nim przed społecznością. Tu i ówdzie potrzeba refaktoringu, przyda się napisać trochę dokumentacji. Poza tym czeka nas wybór licencji. Nadal nie mamy też nazwy dla projektu &#8211; pomysły mile widziane. Liczymy na to, że projekt uda się opublikować w drugim kwartale tego roku.</p>
<p>Cały czas zastanawiamy się w którą stronę skierować nasz projekt. Czy ma być to kolejna implementacja Ruby? Czy też jedynie narzędzie pozwalające na statyczną kompilację wybranych fragmentów projektów w Ruby w celu ich przyspieszenia, co zaproponował Tomasz Stachewicz? Jesteśmy otwarci na pomysły. Bardzo chętnie poznamy opinie i pomysły czytelników.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/02/ruby-z-napedem-odrzutowym-o-kompilacji-slow-kilka/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>A czy ty używasz generatorów w Railsach?</title>
		<link>http://rubysfera.pl/2011/02/a-czy-ty-uzywasz-generatorow-w-railsach/</link>
		<comments>http://rubysfera.pl/2011/02/a-czy-ty-uzywasz-generatorow-w-railsach/#comments</comments>
		<pubDate>Wed, 02 Feb 2011 17:02:43 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=720</guid>
		<description><![CDATA[Jak skonfigurować <strong>generatory</strong> w <strong>Rails 3</strong> tak, by w końcu działały jak trzeba.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2011/02/a-czy-ty-uzywasz-generatorow-w-railsach/waiter/" rel="attachment wp-att-721"><img src="http://rubysfera.pl/wp-content/uploads/2011/02/waiter.jpg" alt="Fotothek df roe-neg 0006486 018 Porträt eines Kellners mit Eis und Desserts" title="waiter" width="300" height="200" class="alignright size-full wp-image-721" /></a></p>
<p>Dobrzy kelnerzy potrafią zapamiętać nasze ulubione zamówienia i witają nas słowami &#8222;Podać to co zwykle?&#8221;. Kto tego nie lubi? </p>
<p>Railsy też są takim dobrym kelnerem i oferują mechanizm <a href="http://www.apohllo.pl/guides/command_line.html#generate">generatorów</a>. Powiedziałem dobrym? Przecież zawsze tworzą mi testy w <code>test/unit</code> (a chciałbym w <code>rspecu</code>), widoki są w <code>erb</code> zamiast w <code>hamlu</code>, do tego te nieszczęsne helpery. To zdecydowanie nie jest tak jak lubię.</p>
<p>Wpisywanie za każdym razem kombinacji w stylu:</p>
<pre>
rails generate controller products --helper -t rspec -e haml
</pre>
<p>nie jest rozwiązaniem. To ja już wolę sam tworzyć te pliki zamiast zapamiętwać ich składnię i opcję. Nie można Railsom powiedzieć jak najbardziej lubimy podane nasze danie? Ależ można.</p>
<h3>Konfiguracja generatorów</h3>
<p>Aby podać domyślne ustawienia w Rails 3 należy dodać do pliku <code>config/application.rb</code> sekcję dotyczącą generatorów. Może ona zawierać poniższe opcje:</p>
<pre class="sh_ruby">
config.generators do |g|
  g.orm :data_mapper
  g.template_engine :haml
  g.test_framework  :rspec, :fixture => true
  g.fixture_replacement :factory_girl
  g.helper false
  g.stylesheets false
end
</pre>
<p>Potrzebujemy jeszcze odpowiednich generatorów (zakładam, że odpowienie gemy są już zainstalowane), dodajmy więc do <code>Gemfile</code> odpowiedni wpis:</p>
<pre>
gem "rails3-generators", :group => :development
</pre>
<p>Powyższy gem nie zawiera generatorów dla <code>hamla</code>. <a href="http://paulbarry.com/articles/2010/01/13/customizing-generators-in-rails-3">PaulBarry</a> przygotował odpowiednią paczkę, wystarczy ją sklonować:</p>
<pre>
git clone git://github.com/pjb3/rails3-generators.git lib/generators
</pre>
<p>Więcej informacji o generatorach znajdziecie poniżej:<br />
<a href="http://railscasts.com/episodes/216-generators-in-rails-3">Railscast 216</a><br />
<a href="https://github.com/indirect/rails3-generators/tree/master/lib/generators">Zbiór najpopularniejszych generatorów</a><br />
<a href="https://github.com/rails/rails/tree/master/railties/lib/rails/generators">Generatory w kodzie Railsów</a><br />
<a href="https://github.com/psynix/rails3_haml_scaffold_generator">Kolejny generator dla Hamla</a></p>
<p>Zachęcam do poświęcenia ten raz kilku minut na konfigurację. Bardzo szybko się zwracają.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/02/a-czy-ty-uzywasz-generatorow-w-railsach/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Czego użyć do &#8230;?</title>
		<link>http://rubysfera.pl/2010/11/czego-uzyc-do/</link>
		<comments>http://rubysfera.pl/2010/11/czego-uzyc-do/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 09:30:17 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=629</guid>
		<description><![CDATA[Odpowiadamy na trapiące początkujących programistów pytania: czego użyć do ...?]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2010/11/czego-uzyc-do/toolbox_red-256x256/" rel="attachment wp-att-687"><img src="http://rubysfera.pl/wp-content/uploads/2010/11/Toolbox_Red-256x256.png" alt="" title="Ruby Toolbox" width="256" height="256" class="alignright size-full wp-image-687" /></a>Młodzi programiści często stają przed problemem jakiego gemu użyć do rozwiązania danego problemu. Praktycznie do wszystkiego znajdziemy po kilka narzędzi, a małe obeznanie z Railsowym środowiskiem sprawia, że wybór jest trudny i może być dziełem przypadku. Dlatego przygotowałem tę listę. Nie chcę pokazywać wszystkich możliwości. Chcę pokazać jedną z popularniejszych (często najpopularniejszą), najaktywniej rozwijaną. Jeśli kilka bibliotek jest porównywalnych, to wybór jest czysto subiektywny. Jednym słowem chcę ograniczyć wybór. Poniższe gemy zostały wielokrotnie użyte w środowisku produkcyjnym i jeśli nie wiesz co wybrać wybierz właśnie je. Nie gwarantuje, że jest to najlepszy wybór, ale na pewno jest to wybór dobry.</p>
<h3>Jak samemu znaleźć właściwy gem?</h3>
<p>Całkiem pokaźna lista kategorii i rozwiązań jest zgromadzona na <a href="http://www.ruby-toolbox.com/">ruby-toolbox.com</a>. Warto zwrócić uwagę na liczbę osób, które danego rozwiązania używają. Przy szukaniu odpowiedniego gemu warto kierować się:</p>
<ul>
<li><strong>dostępnymi funkcjami</strong> &#8211; nie wymaga komentarza.</li>
<li><strong>dokumentacją</strong> &#8211; nawet najlepszy gem będzie na nic, jeśli nie będziemy potrafili z niego skorzystać. Chociaż w ostateczności można zawsze zajrzeć do kodu.</li>
<li><strong>jakoś kodu (testy)</strong> &#8211; im ważniejsza jest dla nas jakaś biblioteka, tym ważniejsze jest, by przyjrzeć się jak jest napisana. Pozwoli nam to zorientować się, czy można twórcom zaufać i czy będziemy w stanie coś w niej poprawić lub zmienić, gdy zajdzie taka potrzeba.</li>
<li><strong>rozszerzalność</strong> &#8211; jak wyżej.</li>
<li><strong>czy projekt żyje</strong> &#8211; głupio by było, gdyby się okazało, że rozwój użytego gemu zatrzymał się wiele miesięcy temu. Bardzo ważna jest możliwość otrzymania pomocy, gdy znajdziemy bug, lub będziemy mieli z czymś problem.</li>
</ul>
<p>Zawsze można również zadać pytanie na <a href="http://blip.pl/tags/ruby">blipie z tagiem #ruby</a> lub <a href="http://rubyonrails.pl/forum/">forum</a>.</p>
<h4>Uwierzytelnianie</h4>
<p><a href="https://github.com/plataformatec/devise">Devise</a> jest obecnie najprostszym rozwiązaniem, jego jedyną wadą (zaletą?) jest to, że bardzo dynamicznie się zmienia. </p>
<h4>Wyszukiwanie</h4>
<p><a href="http://freelancing-god.github.com/ts/en/">Thinking Sphinx</a>. Kropka.</p>
<h4>Przechowywanie plików i obrazków</h4>
<p><a href="https://github.com/thoughtbot/paperclip">Paperclip</a>. Warto zajrzeć również do innych projektów ze <a href="http://thoughtbot.com/community/">stajni thoughtbot</a>, bo są to zawsze produkcje warte polecenia.</p>
<h4>Testowanie</h4>
<p>Użyj <a href="http://rspec.info/">Rspeca</a>, <a href="http://cukes.info/">Cucumbera</a> i <a href="https://github.com/jnicklas/capybara">Capybary</a>. Ponieważ można ten zestaw uznać za standardowy, warto się nimi pobawić i ewentualnie dopiero gdy zauważymy jego wady, poszukać alternatywy. Warto się również zaprzyjaźnić z <a href="https://github.com/thoughtbot/factory_girl">factory girl</a>.</p>
<h4>Layouty</h4>
<p>Erb jest brzydki i passe. <a href="http://haml-lang.com/">Haml</a> jest ładny i dżezi.</p>
<h4>Inherited resources</h4>
<p>Kiedy już zostaniesz fanatykiem REST&#8217;u, dobrze zacząć się rozglądać za czymś w stylu <a href="https://github.com/josevalim/inherited_resources">Inherited Resources</a> i zacząć pisać kontrolery w bardziej <a href="http://blog.peepcode.com/tutorials/2010/rethinking-rails-3-routes">deklaratywnym stylu</a>.</p>
<h4>Continuous Integration</h4>
<p>Chyba nikogo nie trzeba przekonywać do korzyści jakie daje CI. Najprościej <a href="http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/">postawić serwer continous integration</a> można z użyciem <a href="http://integrityapp.com/">Integrity</a>.</p>
<h4>Deploy</h4>
<p>Mam nadzieję, że nie wrzucasz kodu na serwer poprzez FTP? Do tego służy <a href="http://www.capistranorb.com/">Capistrano</a>. I tyle w tym temacie.</p>
<h4>Obsługa błędów</h4>
<p>Instalacja <a href="https://hoptoadapp.com/pages/home">Hoptoadapp</a> sprowadza się do kilku komend, dzięki którym dostaniesz email z każdym błędem, który się pojawił na produkcji i jedno miejsce, w którym tymi błędami możesz zarządzać. Jeśli wystarczy Ci jeden użytkownik i projekt, to jest również <a href="https://hoptoadapp.com/account/new/Egg">plan darmowy</a>.</p>
<h4>Mierzenie wydajności</h4>
<p>Sposób w jaki <a href="http://www.newrelic.com/">New Relic</a> zbiera i prezentuje informacje o obciążeniu jest imponujący. Często jeden rzut oka wystarczy, by zorientować się, co powoduje problemy z wydajnością. W wersji podstawowej daje podgląd ostatnich 30 minut.</p>
<h4>Serwer www</h4>
<p>Użyj <a href="http://www.modrails.com/">Nginxa z mod_rails</a>. Zużywa trochę mniej zasobów niż Apache, jest banalny w instalacji i konfiguracji i napisany przez człowieka z naszej wschodniej granicy (w sumie północnej).</p>
<h4>Paginacja</h4>
<p>Na koniec niepodważalny kanon służący do paginacji: <a href="https://github.com/mislav/will_paginate">Will Paginate</a>.</p>
<h3>Na koniec</h3>
<p>Jeśli uważasz że do czegoś istnieje lepsze rozwiązanie napisz w komentarzu (flame! flame!) A jeśli uważasz, że ta lista jest przydatna i myślisz, że warto, by było regularnie aktualizowana, to napisz tym bardziej.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/11/czego-uzyc-do/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: RVM</title>
		<link>http://rubysfera.pl/2010/09/warte-uwagi-rvm/</link>
		<comments>http://rubysfera.pl/2010/09/warte-uwagi-rvm/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 05:30:02 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=499</guid>
		<description><![CDATA[Pojawił się praktycznie znikąd i dziś jest jednym z ważniejszych projektów w ekosystemie Ruby'ego. Piszemy o RVM, czyli Ruby Version Manager.]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-502" title="rvm" src="http://rubysfera.pl/wp-content/uploads/2010/09/rvm.jpg" alt="" width="300" height="200" />W cieniu wydania <a href="http://www.ruby-lang.org/en/news/2010/08/18/ruby-1-9-2-is-released/">Ruby&#8217;ego 1.9.2</a> czy <a href="http://weblog.rubyonrails.org/2010/8/29/rails-3-0-it-s-done">Rails 3.0</a> bez większego echa przemknęła <a href="http://wayneeseguin.beginrescueend.com/2010/08/22/ruby-environment-version-manager-rvm-1-0-0/">wersja 1.0</a> projektu, który w krótkim czasie wkradł się do arsenału wielu developerów i jest jednym z niezastąpionych narzędzi w pracy z Rubym. <a href="http://rvm.beginrescueend.com/">RVM</a>, czyli Ruby Version Manager służy do łatwej instalacji, zarządzania i wydajnej pracy z różnymi wersjami interpretera Ruby&#8217;ego. Jeśli jeszcze nie korzystasz, myślę, że po tym krótkim tekście zaczniesz.</p>
<h3>Po co mi to?</h3>
<p>W większości porządnych systemów operacyjnych Ruby jest instalowany domyślnie lub dostępny na wyciągnięcie ręki (czyt. na wywołanie <code>apt-get</code>, <code>yum</code> czy innego <code>port</code>). Trzeba jednak pogodzić się z &#8211; jedyną słuszną &#8211; wersją dostępną w pakietach systemowych lub podjąć walkę i konfigurować, kompilować i instalować żądaną wersję ręcznie. Tu nie koniec schodów, gdyż któregoś radosnego dnia przychodzi czas na instalację 1.9 i mamy kłopot. Siedem rozgrzebanych projektów wykorzystujących 1.8 pewnie nie będzie zadowolonych kiedy nagle <code>?o</code> zwróci <code>"o"</code> zamiast <code>111</code>. Niektóre dystrybucje przygotowały się na to i dystrybuują pliki binarne z suffixami <code>18</code> lub <code>19</code>. Mamy wtedy już 2 opcje. Ale co z <a href="http://jruby.org/">JRuby</a>? A co z gemami?</p>
<p>I tak narodził się RVM.</p>
<p>Dla niecierpliwych:</p>
<pre>
$ rvm install 1.9.2
$ rvm use 1.9.2
$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.3.0]
$ rvm use system
$ ruby -v
ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-darwin10]
</pre>
<h3>Jak zacząć?</h3>
<p><a href="http://rvm.beginrescueend.com/rvm/install/">Sugerowaną metodą</a> instalacji jest wykorzystanie skryptu dostarczonego przez autora. Jedna komenda załatwi 95% instalacji &#8211; sklonuje repozytorium z <a href="http://github.com/wayneeseguin/rvm">GitHuba</a>, przygotuje katalog w <code>$HOME</code> i wgra wszystkie skrypty RVMa:</p>
<pre>
$ bash &lt; &lt;( curl http://rvm.beginrescueend.com/releases/rvm-install-head )
</pre>
<p>Po zakończeniu skryptu należy tylko dodać jedną linię na końcu <code>.profile</code> (lub <code>.bash_profile</code> etc):</p>
<pre>
[[ -s "$HOME/.rvm/scripts/rvm" ]] &amp;&amp; . "$HOME/.rvm/scripts/rvm"
</pre>
<p>Pamiętaj, aby dodać tę linię po wszystkich zmianach w <code>$PATH</code>. Inaczej mogą one nadpisać ścieżki ustawianie przez RVM (tak dzieje się np. z <a href="http://www.macports.org/">MacPortsami</a>, które zawsze doklejają swoje ustawienia ścieżek na końcu <code>.bash_profile</code>).</p>
<p>Aby zobaczyć listę dostępnych środowisk wywołaj:</p>
<pre>
$ rvm list known
</pre>
<p>Lista aktualnie zawiera MRI w wersjach 1.8.6, 1.8.7, 1.9.1 i 1.9.2 (każda w kilku odmianach), kilka wersji <a href="http://jruby.org/">JRuby</a>, <a href="http://rubini.us/">Rubiniusa</a>, <a href="http://www.rubyenterpriseedition.com/">REE</a>, <a href="http://ruby.gemstone.com/">MagLev</a> i <a href="http://www.macruby.org/">MacRuby</a>. Instalujemy wywołując jedynie:</p>
<pre>
$ rvm install 1.9.2
</pre>
<p>Jeśli życzysz sobie konkretną wersję, wpisz np:</p>
<pre>
$ rvm install 1.9.2-head
</pre>
<p>RVM ściągnie, skonfiguruje i skompiluje wybrany wariant. Cała instalacja odbywa się w katalogu domowym bieżącego usera, pamiętaj więc aby nie używać <code>sudo</code>! Wszystkie wersje Ruby&#8217;ego będą sobie grzecznie mieszkały w <code>$HOME/.rvm/rubies</code>, zaś gemy dla każdej z nich w <code>$HOME/.rvm/gems</code>.<br />
Po zakończeniu instalacji przełącz się do wybranej używając:</p>
<pre>
$ rvm use 1.9.2
</pre>
<p>Sprawdźmy czy zadziałało</p>
<pre>
$ which ruby
/Users/Czak/.rvm/rubies/ruby-1.9.2-p0/bin/ruby
$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.3.0]
</pre>
<h3>Co dalej?</h3>
<p>W każdej chwili możemy przywrócić stan <em>przed-RVM</em>, czyli wrócić do wykorzystania systemowego interpretera:</p>
<pre>
$ rvm use system
</pre>
<p>RVM nie narzuca wykorzystania żadnej z zainstalowanych wersji. Domyślnie każda sesja shella wykorzystuje systemowy interpreter, a dopiero po użyciu <code>rvm</code> use jest on przełączany na jedną z zainstalowanych wersji. Aby wymusić domyślną wersję możesz jednak wywołać:</p>
<pre>
$ rvm --default 1.9.2
</pre>
<p>Komenda <code>rvm</code> daje potężną możliwość pracy na wielu interpreterach na raz. Modelowym przykładem jest uruchomienie skryptu na wszystkich &#8211; lub niektórych &#8211; zainstalowanych wersjach Ruby&#8217;ego:</p>
<pre>
$ rvm list
rvm rubies
=> ruby-1.8.7-p302 [ x86_64 ]
   ruby-1.9.2-p0 [ x86_64 ]
$ echo "puts RUBY_VERSION" &gt; version.rb
$ rvm version.rb
1.8.7
1.9.2
</pre>
<p>Analogicznie można pracować z gemami, instalując wymagane na kilku wersjach jednocześnie:</p>
<pre>
$ rvm 1.8.7,1.9.2 gem install rails --no-ri --no-rdoc
</pre>
<p>Bardzo przydatną funkcją są <a href="http://rvm.beginrescueend.com/gemsets/basics/">gemsety</a>, czyli zestawy gemów, między którymi można wygodnie przełączać się i w ten sposób testować np. współpracę naszej aplikacji z nową wersją Rails. Chcąc np. uaktualnić aplikację z 2.3.5 do 2.3.9 możemy utworzyć niezależny zestaw gemów nazwany np. <code>rails239</code> i w trakcie migracji przełączać się między nim a domyślnym:</p>
<pre>
$ rvm 1.8.7
$ rails --version
Rails 2.3.5
$ rvm gemset create rails239
'rails239' gemset created (/Users/Czak/.rvm/gems/ruby-1.8.7-p302@rails239).
$ rvm 1.8.7@rails239
$ gem install rails -v 2.3.9
$ rails --version
Rails 2.3.9
</pre>
<h3>Co (jeszcze) dalej?</h3>
<p>Powyższe wprowadzenie bynajmniej nie wyczerpuje możliwości RVM. Zachęcam do czytania świetnej dokumentacji dostępnej na <a href="http://rvm.beginrescueend.com">stronie domowej projektu</a>. W razie pytań możecie też śmiało walić na nasz rubysferowy <a href="http://rubysfera.blip.pl/">blip</a> lub <a href="http://www.facebook.com/pages/Rubysfera/153667694653147">stronę Rubysfery na Facebooku</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/09/warte-uwagi-rvm/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: Bundler</title>
		<link>http://rubysfera.pl/2010/08/warte-uwagi-bundler/</link>
		<comments>http://rubysfera.pl/2010/08/warte-uwagi-bundler/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 14:21:47 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=195</guid>
		<description><![CDATA[Wraz z nadchodzącymi wielkimi krokami Rails 3 sporo mówi się o jednym konkretnym gemie. Ma ułatwić zarządzanie zależnościami w aplikacjach. Ma uprościć pracę przy tworzeniu i korzystaniu z gemów. Generalnie ma zbawić świat, uzależnić wszystkich developerów od siebie, a następnie odpalić cap deploy:skynet i po sprawie&#8230; OK, może bez tego ostatniego. Warto jednak wiedzieć, że [...]]]></description>
			<content:encoded><![CDATA[<p><a rel="attachment wp-att-214" href="http://rubysfera.pl/2010/08/warte-uwagi-bundler/bundler-small/"><img class="alignright size-full wp-image-214" title="bundler-small" src="http://rubysfera.pl/wp-content/uploads/2010/08/bundler-small.png" alt="" width="300" height="200" /></a></p>
<p>Wraz z <a href="http://weblog.rubyonrails.org/2010/7/26/rails-3-0-release-candidate">nadchodzącymi wielkimi krokami</a> Rails 3 sporo mówi się o jednym konkretnym gemie. Ma ułatwić zarządzanie zależnościami w aplikacjach. Ma uprościć pracę przy tworzeniu i korzystaniu z gemów. Generalnie ma zbawić świat, uzależnić wszystkich developerów od siebie, a następnie odpalić <code>cap deploy:skynet</code> i po sprawie&#8230; OK, może bez tego ostatniego.</p>
<p><span id="more-195"></span></p>
<p>Warto jednak wiedzieć, że <a href="http://gembundler.com/">Bundler</a> nie jest jedynie <em>częścią Rails 3</em>. Jest niezależnym, potężnym narzędziem, które można &#8211; i warto &#8211; używać przy tworzeniu wszelkich aplikacji w Rubym.</p>
<h3>Dlaczego?</h3>
<p>Wszystko zaczęło się w 428 r. p.n.e&#8230; nie wróć to znowu nie to. Budowa aplikacji, choćby najmniejszych, wymaga od programisty korzystania z wielu narzędzi. Dzięki dobrodziejstwom open-source mamy do dyspozycji tysiące bibliotek napisanych przez tysiące innych developerów. Każda z nich to żyjący własnym życiem twór, który w trakcie rozwoju i działania naszego projektu może przechodzić przez multum zmian. Jak zapewnić, że zmiana w zewnętrznym module nie wpłynie negatywnie na działanie naszej aplikacji? Jak zadbać o to, by każdy developer w zespole miał identyczne środowisko? <a href="http://rubyonrails.org/">Railsy</a> radziły sobie do tej pory korzystając z wpisów <code>config.gem</code> w pliku <code>environment.rb</code> &#8211; możliwość określenia specyficznej wersji i źródła gema daje pewne zabezpieczenie, choć mocno ogranicza.</p>
<p>Ale świat nie kończy się na Rails, rozbudowane zależności mogą mieć wszystkie aplikacje w Rubym. Co więcej, same gemy zależą nierzadko od innych gemów i tu zaczynają się poważne schody. Developerzy wynajdowali patenty na zapewnienie zgodności, m.in. hardkodując je w źródle swoich bibliotek. Takie potworki zamiast sprawę rozwiązywać, tylko ją komplikowały.</p>
<p>Bundler ma na celu wszystkie te problemy rozwiązać.</p>
<h3>Jak?</h3>
<p>Weźmy na warsztat prosty skrypt z jedną zależnością:</p>
<pre class="sh_ruby">require "rubygems"
require "nokogiri"
require "open-uri"

doc = Nokogiri::HTML(open('http://www.google.com/search?q=lukasz+adamczak'))
link = doc.css('h3.r a.l').first
puts link.content</pre>
<p>Jeśli w systemie mamy <code>nokogiri</code>, program powinien wypisać:</p>
<pre>lans musi być</pre>
<p>Jeśli nie, przeczytamy całkiem słuszny komunikat:</p>
<pre>no such file to load -- nokogiri</pre>
<p>Idąc tradycyjną ścieżką, moglibyśmy teraz zainstalować <code>gem install nokogiri</code> i problem rozwiązany. Pojdźmy jednak <strong>The Bundler Way</strong>. Instalujemy <code>bundlera</code> (na dzień dzisiejszy aktualna wersja to 1.0.0.rc.2, więc trzeba użyć <code>--pre</code>)</p>
<pre>gem install bundler --pre</pre>
<p>Otrzymujemy bardzo potężne polecenie <code>bundle</code>, którego możemy użyć już teraz. <code>bundle init</code> utworzy w bieżącym katalogu prosty wzorcowy plik <code>Gemfile</code>, który będzie opisywał wszystkie zależności naszego projektu. Drugi krok to użycie Bundlera w kodzie. Zmieniamy układ <code>require</code>&#8216;ów na:</p>
<pre class="sh_ruby">require "rubygems"
require "bundler/setup"
require "nokogiri"
require "open-uri"</pre>
<p><code>require "bundler/setup"</code> gwarantuje, że projekt będzie wykorzystywał do zarządzania zależnościami właśnie bundlera. W tym momencie cały projekt stał się odizolowaną &#8222;bańką&#8221;. Całe środowisko jest opisane przez <code>Gemfile</code>. Nie mają znaczenia gemy jakie masz w systemie. Tylko to, co wyraźnie zaznaczysz w <code>Gemfile</code>&#8216;u będzie należało do projektu. Aby się przekonać zainstaluj:</p>
<pre>sudo gem install nokogiri</pre>
<p>Mogłoby się wydawać, że teraz skrypt wykona się poprawnie. Błąd! Bundler sprawdzi plik <code>Gemfile</code> (domyślnie pusty) i uzna, że nie wie co to <code>nokogiri</code>:</p>
<pre>no such file to load -- nokogiri (LoadError)</pre>
<p>Dodaj więc do <code>Gemfile</code> linię:</p>
<pre class="sh_ruby">gem "nokogiri"</pre>
<p>Teraz skrypt wykonuje się poprawnie. Standardowa kolejność pracy z Bundlerem powinna jednak być odwrotna. Po dodaniu lub zmianie czegokolwiek w <code>Gemfile</code>, pamiętaj o odpaleniu polecenia <code>bundle install</code>. Zajmie się ono instalacją brakujących gemów, w razie potrzeby prosząc nawet o hasło do <code>sudo</code>. Zainstalowane w ten sposób gemy trafiają domyślnie w to samo miejsce gdzie instalowane przez <code>gem install</code>.</p>
<p><code>bundle</code> ma też kilka innych ciekawych opcji. <code>check</code> do sprawdzenia czy posiadamy wszystko co wymagane.</p>
<pre>$ bundle check
Could not find gem 'nokogiri (= 1.4.3.1, runtime)' in any of the gem sources.</pre>
<p>(a po instalacji)</p>
<pre>$ bundle check
The Gemfile's dependencies are satisfied</pre>
<p><code>console</code> uruchamia <code>irb</code> z wczytanym kompletnym środowiskiem:</p>
<pre>$ bundle console
ruby-1.8.7-p249 &gt; Nokogiri
 =&gt; Nokogiri</pre>
<p><code>bundle exec</code> umożliwia uruchomienie wykonywalnego skryptu z gema &#8211; z tej konkretnej wersji, którą podaliśmy w <code>Gemfile</code>:</p>
<pre>$ bundle exec nokogiri http://rubysfera.pl
Your document is stored in @doc...
ruby-1.8.7-p249 &gt;</pre>
<p><code>show</code> i <code>open</code> pozwalają znaleźć i otworzyć katalog ze źródłem gema:</p>
<pre>$ bundle show
Gems included by the bundle:
  * bundler (1.0.0.rc.2)
  * nokogiri (1.4.1)

$ bundle show nokogiri
/Users/Czak/.rvm/gems/ruby-1.8.7-p249/gems/nokogiri-1.4.1

$ bundle open nokogiri  # otwiera powyższy katalog w domyślnym edytorze</pre>
<h3>Aha!</h3>
<p>Bundler podczas pracy tworzy automatycznie plik <code>Gemfile.lock</code> na bazie <code>Gemfile</code> oraz stanu Twojego aktualnego środowiska. Jeśli w <code>Gemfile</code> nie określisz wymaganej wersji nokogiri, a w systemie masz zainstalowaną 1.4.1, wtedy do <code>Gemfile.lock</code> trafi:</p>
<pre>GEM
  remote: http://rubygems.org/
  specs:
    nokogiri (1.4.1)</pre>
<p>Należy pamiętać aby <code>Gemfile.lock</code> dodać do repozytorium wraz z źródłowym <code>Gemfile</code>. To zagwarantuje, że cały zespół będzie pracował na identycznym środowisku. Jeśli w którymś momencie wymusisz w <code>Gemfile</code> wersję:</p>
<pre class="sh_ruby">gem "nokogiri", "1.4.3.1"</pre>
<p>wtedy <code>Gemfile.lock</code> zostanie uaktualniony automatycznie przez bundlera i obie zmiany należy wcommitować. Po każdej zmianie w <code>Gemfile</code> (a właściwie jak często się da, np. po <code>git pull</code>) warto uruchamiać <code>bundle install</code> aby zsynchronizować oba pliki i &#8211; w razie potrzeby &#8211; uaktualnić lokalne środowisko.</p>
<h3>Na koniec</h3>
<p>Takim krótkim tekstem ledwo musnąłem powierzchnię Bundlera. Może jednak przekonałem kogoś, że jest to narzędzie warte uwagi i jednocześnie łatwe w użyciu. Warto już teraz wyrobić sobie nawyk wywoływania <code>bundle init</code> zaraz po <code>git init</code>, niezależnie od rodzaju budowanej aplikacji. Bundler może w niedługim czasie wprowadzić trochę ładu do Rubinowego światka, na czym skorzysta każdy developer.</p>
<p>Aby dowiedzieć się więcej:</p>
<ul>
<li><a href="http://gembundler.com/v1.0/index.html">http://gembundler.com/v1.0/index.html</a></li>
<li><a href="http://github.com/carlhuda/bundler">http://github.com/carlhuda/bundler</a></li>
<li><a href="http://railscasts.com/episodes/201-bundler">http://railscasts.com/episodes/201-bundler</a></li>
<li><a href="http://asciicasts.com/episodes/201-bundler">http://asciicasts.com/episodes/201-bundler</a></li>
<li><a href="http://yehudakatz.com/2010/07/26/whats-new-in-bundler-1-0-0-rc-1/">http://yehudakatz.com/2010/07/26/whats-new-in-bundler-1-0-0-rc-1/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/08/warte-uwagi-bundler/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: Steak</title>
		<link>http://rubysfera.pl/2010/07/testowanie-steak-ruby/</link>
		<comments>http://rubysfera.pl/2010/07/testowanie-steak-ruby/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 20:23:00 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[steak]]></category>
		<category><![CDATA[testy]]></category>

		<guid isPermaLink="false">http:///2010/07/13/testowanie-steak-ruby</guid>
		<description><![CDATA[<p>Kiedy będziecie mieli już dość mizerii z <strong>Cucumbera</strong>, czas przyjrzeć się krwistemu <strong>Steakowi</strong>, czyli testom akceptacyjnym w czystym Rubim.</p>]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" src="http://rubysfera.pl/assets/2010/7/13/steak_big_1.jpg" alt="" /></p>
<p>Zainspirowani komentarzem Huberta pod naszym <a href="http://rubysfera.pl/2010/7/10-porad-o-cucumber">ostatnim postem</a> dotyczącym cucumbera, postanowiliśmy bliżej się przyjrzeć jego alternatywie, czyli <a href="http://github.com/cavalle/steak">Steakowi</a>.</p>
<h3>Co to?</h3>
<p>Jednym zdaniem: <strong>Steak</strong> umożliwia pisanie testów akceptacyjnych w czystym Rubim.</p>
<h3>Dla kogo?</h3>
<p>Steak jest dla wszystkich, którym przeszkadza narzut związany z pisaniem testów przy użyciu <a href="http://github.com/aslakhellesoy/cucumber">Cucumbera</a><a></a>. Jedną z największych zalet “ogórka”, jest jego naturalny język. Teoretycznie umożliwia on nietechnicznym osobom przygotowywanie scenariuszy, które po drobnych modyfikacjach mogą być przekształcone przez programistę w pełnoprawne testy akceptacyjne. Prawda jest jednak taka, że w większości przypadków scenariusze pisane są przez programistów dla programistów. Z takiego założenia wyszli twórcy Steaka. Pozbyli się więc pisania kroków i konieczności ich późniejszego definiowania, scenariusze są po prostu kodem. Oczywiście stek możemy podać z Capybarą (to coś pokrewnego do <a href="http://pl.wikipedia.org/wiki/Kapibara">świnki morskiej</a>), Webratem, Rspec, Factory Girl itp.</p>
<h3>Jak to wygląda?</h3>
<p>Przykładowy scenariusz cucumbera:</p>
<pre class="sh_ruby">Scenario: User signs in with invalid email address
  Given a user exists with email: "email@person.com", password: "password"
  When I go to the sign in page
  And I fill in "email" with "somewrongemail"
  And I fill in "password" with "password"
  And I press "Login"
  Then I should see "Invalid e-mail address"</pre>
<p>Ten sam scenariusz z użyciem steaka może mieć następującą składnię (doprawione <a href="http://rubysfera.pl/2010/4/sinatra-cucumber-capybara">capybarą</a>):</p>
<pre class="sh_ruby">scenario "User signs in with invalid email address" do
  User.create!(:email =&gt; "email@person.com", :password =&gt; "password"
  visit '/sign_in'
  fill_in "email", :with =&gt; "somewrongemail"
  fill_in "password", :with =&gt; "password"
  press "Login"
  page.should have_content("Invalid e-mail address")
end</pre>
<p>Całkiem zgrabne, prawda?</p>
<h3>Co dalej?</h3>
<p>Wszystkich zainteresowanych odsyłamy na <a href="http://github.com/cavalle/steak">stronę projektu</a> oraz polecamy <a href="http://jeffkreeftmeijer.com/2010/steak-because-cucumber-is-for-vegetarians/">szybki tutorial</a>.</p>
<p>Mimo tego, że w naszym zespole scenariusze oglądają tylko programiści i scrum master, na razie nie zanosi się na to, żebyśmy zaczęli przyrządzać surowe steki. Przyzwyczaiłem się do składni Cucumbera, a przy użyciu <a href="http://rubysfera.pl/2010/3/warte-uwagi-pickle">pickle</a> i odrobinie wprawy, można naprawdę szybko pisać scenariusze. Podoba mi się również warstwa abstrakcji, którą narzuca Cucumber, ponieważ pozwala mi lepiej skupić się na opisaniu i zrozumieniu zadania z punktu widzenia użytkownika. Widocznie jestem wegetarianinem.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/07/testowanie-steak-ruby/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: DataMapper</title>
		<link>http://rubysfera.pl/2010/06/warte-uwagi-datamapper/</link>
		<comments>http://rubysfera.pl/2010/06/warte-uwagi-datamapper/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 05:30:00 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>
		<category><![CDATA[datamapper]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http:///2010/06/14/warte-uwagi-datamapper</guid>
		<description><![CDATA[<p>Wydanie wersji 1.0. <strong>DataMappera</strong> to dobra okazja, by poznać, lub przypomnieć sobie ten wydawałoby się, lekko przykurzony <strong><span class="caps">ORM</span></strong>.</p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://rubysfera.pl/assets/2010/6/13/datamapper.png" class="alignright"/></p>
<p>O DataMapperze, czyli <a href="http://en.wikipedia.org/wiki/Object-relational_mapping"><span class="caps">ORM</span></a> w Rubym, zaczęło być głośno przy okazji <A href="http://www.merbivore.com/">Merba</a>. Mogłoby się wydawać, że ogłoszenie połączenia Railsów z Merbem, sprawi, że DataMapper przestanie być rozwijany. Tak się jednak nie stało i stał się on chyba drugim po ActiveRecordzie ORMem w Rubiowym środowskiu. W trakcie tegorocznego <a href="http://en.oreilly.com/rails2010">RailsConf</a> została opublikowania wersja 1.0.</p>
<h3>Przecież jest już ActiveRecord</h3>
<p>Po co nam DataMapper? Po pierwsze oczywiście można ograniczyć się do stwierdzenia, że konkurencja jest dobra i wymusza rozwój. Ale kilka konkretnych cech, które mogą zachęcić do przyjrzenia się mu bliżej to:</p>
<ul>
<li><strong>Jeden rekord = jeden obiekt</strong> &#8211; każdy rekord w tabeli jest reprezentowany przed tylko jeden obiekt. Pozwala to na zwiększenie szybkości i oszczędza pamięć.</li>
<li><strong>Czysty Ruby</strong> &#8211; <del>nie da się używać <span class="caps">SQL</span>&#8217;a w DataMapperze, wszystko jest pisane w Rubym. Chroni to przed nadużywaniem zapytań <span class="caps">SQL</span> i daje większą niezależność od konkretnej bazy danych.</del> Mimo, że <a href="http://www.yardoc.org/docs/datamapper-dm-core/DataMapper/Adapters/DataObjectsAdapter#select-instance_method">można pisać <span class="caps">SQL</span>&#8217;owe</a> zapytania, to twórcy uważają, że dostarczone helpery sprawiają, że w większości przypadków nie jest to konieczne. </li>
<li><strong>Adaptery</strong> &#8211; nie jest wymagane korzystanie z relacyjnej bazy danych. Istnieje ponad 40 adapterów, umożliwiających podłączenie DataMappera między innymi do CouchDB, YAMLa, <span class="caps">CVS</span>, Sphinxa, albo np <a href="http://merbist.com/2008/09/29/write-your-own-custom-datamapper-adapter/"><span class="caps">API</span> google video</a>.</li>
<li><strong>Kolumny definiowane jawnie</strong> &#8211; wszystkie kolumny należy zdefiniować w modelu. Na pierwszy rzut oka wydaje się to niepotrzebnym wysiłkiem, ale dzięki temu znika ActiveRecordowa &#8220;magia&#8221; i wszystkie pola są od razu widoczne. Nie ma również potrzeba pisać migracji, wystarczy użyć metody <code>auto_migrate</code>, a baza zostanie uaktualniona do wersji przechowywanej w modelach.</li>
<li><strong>Domyślne opóźnione ładowanie (lazy loading)</strong> &#8211; rekordy ładowane są w tle dopiero w momencie, gdy wymagany jest do nich dostęp, pozwala to DataMapperowi na zwiększanie wydajności, poprzez zastosowanie prostych reguł.  Na przykład dzięki temu poniższa linijka wykona tylko dwa zapytania, niezależnie od tego ile rekordów jest w bazie.</li>
</ul>
<pre class="sh_ruby">
 Zoo.all.each { |zoo| zoo.exhibits.to_a }
</pre>
<p>Oczywiście punkty te można potraktować zarówno jako wady i zalety, zależy czego oczekujemy od ORMa. Ale jeśli jeszcze nie jesteście przekonani by spróbować, można zajrzeć na stronę <a href="http://datamapper.org/why">Why DataMapper</a>.</p>
<h3>Jak wypróbować?</h3>
<p>Najprościej po prostu zacząć od <a href="http://datamapper.org/getting-started">przewodnika na oficjalnej stronie</a>. Miłej zabawy.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/06/warte-uwagi-datamapper/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: rpx_now</title>
		<link>http://rubysfera.pl/2010/04/warte-uwagi-rpx-now/</link>
		<comments>http://rubysfera.pl/2010/04/warte-uwagi-rpx-now/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 18:52:00 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rpx]]></category>

		<guid isPermaLink="false">http:///2010/04/22/warte-uwagi-rpx-now</guid>
		<description><![CDATA[<p>Wreszcie proste uwierzytelnianie &#8211; usługa <span class="caps">RPX</span> i gem rpx_now</p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://rubysfera.pl/assets/2010/4/22/co-nowego-rpx.jpg" alt="Warte uwagi: rpx_now" class="alignright" /></p>
<p>Zmuszenie <a href="http://github.com/binarylogic/authlogic">Authlogica</a> do współpracy z <a href="https://www.google.com/accounts/Login?hl=pl">kontami Google</a> i <a href="http://developers.facebook.com/docs/guides/web">Facebook Connectem</a> jednocześnie było jednym z bardziej frustrujących doświadczeń w mojej pracy z Railsami. Z pozoru wszystko wygląda pięknie &#8211; Authlogic daje się rozszerzać i istnieją moduły <a href="http://github.com/binarylogic/authlogic_openid">OpenID</a>, <a href="http://github.com/kalasjocke/authlogic_facebook_connect">Facebook Connect</a> czy <a href="http://github.com/jrallison/authlogic_oauth">OAuth</a> współpracujące z nim. W rzeczywistości każdy taki moduł, pisany przez kogo innego wymaga dodatkowych śmieci w modelu użytkownika i po miesiącu nikt już nie pamięta skąd w <code>Userze</code> te 10 dziwnych metod&#8230;</p>
<p>I tak przeglądając <a href="http://ruby-toolbox.com/categories/rails_authentication.html">alternatywy dla Authlogica</a> na piątym miejscu listy w <a href="http://ruby-toolbox.com">Ruby-Toolboksie</a> znalazłem wybawienie &#8211; <a href="http://github.com/grosser/rpx_now">rpx_now</a></p>
<h3>Co to?</h3>
<p><a href="https://rpxnow.com/"><span class="caps">RPX</span></a> to usługa, która dość powoli zdobywa popularność w Internecie. Jej podstawową rolą jest ułatwienie integracji budowanych aplikacji (stron, serwisów, &#8230;) z kontami Facebook, Google, Twitter i innymi &#8211; kompletna lista zawiera <a href="https://rpxnow.com/features">12 sytemów uwierzytelniania</a>. Decydując się na <span class="caps">RPX</span>, po stronie developera pozostaje jedynie prosta konfiguracja usług w panelu <span class="caps">RPX</span> oraz wykorzystanie jednego &#8211; a nie dwunastu &#8211; <span class="caps">API</span>. Cała robota w obsłużeniu wszystkich 12 back-endów spada na <span class="caps">RPX</span> i &#8211; nie ma co ukrywać &#8211; system robi to znakomicie, zapewniając jednolity <em>user experience</em> dla każdego użytkownika, niezależnie od wybranej przez niego opcji.</p>
<p>A na dokładkę dla leniwego (jak ja) developera powstał gem <a href="http://github.com/grosser/rpx_now">rpx_now</a>.</p>
<h3>Jak to?</h3>
<p>Opis całej funkcjonalności gema mieści się w krótkim <span class="caps">README</span>, a zapamiętać wystarczy 4 punkty:</p>
<ul>
<li>załóż konto i pobierz klucz <span class="caps">API</span> ze strony <span class="caps">RPX</span></li>
<li>uruchom <a href="http://github.com/grosser/rpx_now/raw/master/MIGRATION">migrację</a></li>
<li>przygotuj widok z logowaniem</li>
<li>pobierz dane użytkownika z <span class="caps">RPX</span> aby zalogować lub zarejestrować <code>Usera</code></li>
</ul>
<p>Migracja dodaje <strong>jedno</strong> pole <code>identifier</code> do modelu User. W widoku należy wstawić skrypt <span class="caps">RPX</span>&#8217;a z użyciem helperów <code>RPXNow.embed_code</code> lub <code>RPXNow.popup_code</code>, a w jedynej akcji kontrolera zalogować lub zarejestrować użytkownika przy użyciu danych otrzymanych z usługi.</p>
<h3>Na koniec</h3>
<p><span class="caps">RPX</span> oferuje darmowy plan, który moim zdaniem wystarcza do większości zastosowań. Dopiero bardziej zaawansowane, społecznościowe funkcje zintegrowanych serwisów są dostępne w taryfach płatnych. Jest też haczyk &#8211; wersja bezpłatna wyświetla link &#8220;Powered by <span class="caps">RPX</span>&#8221; w okienku logowania. Żadne jednak z tych ograniczeń nie osłabiły mojego zapału do korzystania z <span class="caps">RPX</span> i gem rpx_now na pewno trafi do niejednego przyszłego railsowego projektu.</p>
<ul>
<li><a href="http://github.com/grosser/rpx_now">http://github.com/grosser/rpx_now</a></li>
<li><a href="http://github.com/grosser/rpx_now_example">http://github.com/grosser/rpx_now_example</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/04/warte-uwagi-rpx-now/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Warte uwagi: pickle</title>
		<link>http://rubysfera.pl/2010/03/warte-uwagi-pickle/</link>
		<comments>http://rubysfera.pl/2010/03/warte-uwagi-pickle/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 07:19:00 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Warte uwagi]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[ping pong]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[sinatra]]></category>

		<guid isPermaLink="false">http:///2010/03/31/warte-uwagi-pickle</guid>
		<description><![CDATA[<p>Zwracamy uwagę na smaczniejszą odmianę ogórka &#8211; pickle.</p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://rubysfera.pl/assets/2010/3/25/pickle.jpg" alt="Warte uwagi: pickle" class="alignright" /></p>
<p>W sekcji <strong>&#8220;Warte uwagi&#8221;</strong> prezentujemy narzędzia, biblioteki, gemy, pluginy, które naszym zdaniem na uwagę zasługują, a być może nie są dobrze znane i doceniane wśród developerów. Nie będzie tu dogłębnych tutoriali &#8211; tylko kilka słów na zaciekawienie i zaostrzenie apetytu.</p>
<p>W dzisiejszym odcinku: <a href="http://github.com/ianwhite/pickle">pickle</a></p>
<h3>Co to?</h3>
<p><a href="http://github.com/ianwhite/pickle">Pickle</a> to gem, który znacznie ułatwia pisanie scenariuszy <a href="http://github.com/aslakhellesoy/cucumber">Cucumbera</a> dla aplikacji railsowych. Nie da się ukryć, że &#8220;ogórki&#8221; w RoR bywają do siebie podobne. Jest sobie użytkownik, loguje się, klika w przycisk i na końcu widzi napis &#8220;Dziękujemy&#8221;. Lwią część tych kroków dostajemy za darmo od <a href="http://github.com/aslakhellesoy/cucumber-rails">cucumber-rails</a> &#8211; w szczególności wszystkie typu <code>When</code> symulujące interakcję użytkownika z aplikacją i kilka kroków <code>Then</code> sprawdzających zawartość strony po wykonaniu akcji. Pozostaje jednak sporo <code>Givenów</code> i <code>Thenów</code>, które trzeba zdefiniować samemu.</p>
<p>Chyba, że użyjemy pickle.</p>
<h3>Jak to?</h3>
<p>Instalacja to 3 kroki:</p>
<ul>
<li>dodanie wpisu <code>config.gem</code> w <code>environments/cucumber.rb</code></li>
<li>instalacja gema</li>
<li>odpalenie generatora <code>script/generate pickle</code></li>
</ul>
<p>Od tego momentu możemy pisać takie cuda:</p>
<pre>
  Given a user: "Ala" exists with email: "ala@makota.pl"
  And another user: "Marek" exists with email: "marek@zegarek.pl"
  And an admin exists with email: "site@admin.com"
  And user: "Ala" is in that admin's contacts
  ...
  ...
  Then 0 users should exist with email: "marek@zegarek.pl"
  But a user should exist with email: "ala@makota.pl"
  And that user should be happy
</pre>
<p>Wszystkie powyższe kroki pickle &#8220;zrozumie&#8221; i obsłuży jak swoje. Wystarczy, że mamy odpowiednie modele i/lub fabryki, pierwsze cztery <strong>Giveny</strong> przygotują stan &#8220;przed&#8221;, a trzy ostatnie <strong>Theny</strong> sprawdzą stan &#8220;po&#8221;.</p>
<p>Ten mało wyszukany przykład to dopiero początek. Polecam przejrzeć dokumentację i rzucić okiem na multum form, które akceptuje pickle.</p>
<h3>Warto wiedzieć</h3>
<p>Choć dokumentacja sugeruje, że moduły <code>paths</code> i <code>email</code> są opcjonalne, zdecydowanie polecam dołączenie ich bez zastanowienia. Generator pickle&#8217;a jest bardzo ostrożny z nadpisywaniem plików, a dodatkowe funkcjonalności z tych modułów są warte zachodu.</p>
<p>Od razu polecam też odkomentować linię w <code>pickle.rb</code>:</p>
<pre>
config.map 'I', 'myself', 'me', 'my', :to =&gt; 'user: "me"'
</pre>
<p>Dzięki temu możemy używać zamiennie określeń &#8220;I&#8221;, &#8220;me&#8221; itd, a kolejne kroki będą wiedziały o którym użytkowniku mowa.</p>
<p>Pickle świetnie współpracuje z fabrykami <a href="http://github.com/thoughtbot/factory_girl">Factory Girl</a> lub <a href="http://github.com/notahat/machinist">Machinist</a>. Powyższy przykład z użytkownikami i adminem to w najprostszym przypadku jeden model <code>User</code> i dwie fabryki: <code>user</code> i <code>admin</code>, obie powiązane z tym modelem, a różniące się np. tylko flagą <code>admin</code> lub polem <code>status</code>.</p>
<p>Wszystkie potrzebne informacje &#8211; na stronie projektu: <a href="http://github.com/ianwhite/pickle">http://github.com/ianwhite/pickle</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/03/warte-uwagi-pickle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

