2007.09_Ruby_[Programowanie].pdf

(833 KB) Pobierz
439031367 UNPDF
dla programistów
Ruby
Ruby
Tomasz Gajewski
Ruby (czyt. Rubi) to nowy język programowania rodem z Japonii. No, może nie taki nowy, bo autor
– Yukihiro „Matz” Matsumoto, zaczął go pisać już ponad 10 lat temu. Przez długi czas rozwijany był
jako projekt opensource tylko przez pasjonatów z Japonii i dlatego pozostawał nierozpoznawalny w
szerszych kręgach.
buje jeszcze jednego języka? Matsumto, ja-
ko administrator Linuksa, marzył o języku
skryptowym, który wspierałby pełną obiek-
towość. Pisanie skryptów – krótkich programików, naj-
częściej jednorazowego użytku, w Javie czy C# jest mało
efektywne. Matsumoto miał ponadto wizję co do sposobu
programowania, która uczyniła Ruby wyjątkowym, któ-
ra swoją oryginalnością zauroczyła rzesze programistów.
Dzięki odrobinie szczęścia (wyjaśnię to za chwilę) Ruby
stał się językiem do pisania nie tylko skryptów, ale i więk-
szych aplikacji biznesowych.
Dave Thomas, autor „Pragmatycznego Programisty”
i wielu innych ciekawych książek, jest gorącym zwolenni-
kiem nauki możliwie wielu języków programowania. Nie
dlatego żeby pisać aplikacje dla klienta, ale dlatego żeby
ustawicznie rozszerzać swój sposób myślenia, jak efektyw-
niej rzeczy mogą być kodowane.
Język, który nie zmienia Twojego myślenia o programowa-
niu, nie jest wart nauki ” (Alan Peris)
Ruby idealnie wkomponowuje się w tą wizję. Dlate-
go Dave Thomas, razem z całym swoim wydawnictwem
pragmaticprogrammer.com zaangażowali się w jego pro-
mocję. To dzięki niemu Ruby przekroczył granice Japonii i
opanował resztę świata.
Język skryptowy – bez kontroli typu da-
nych, do pisania prawdziwych programów
Tak, Ruby, podobnie jak większość języków skryptowych,
nie posiada kontroli typu danych (ang. weekly typed ). Jest
też dynamiczny, co oznacza że kompilowany dopiero w
trakcie wykonania.
Miałem pisać o tym na samym końcu, ale boję się że
wielu czytelników doświadczonych w PERLu czy zwłasz-
cza PHP nie dotrze tam. Zbyt wiele niemiłych wspomnień
w ich głowach, aby zaczynać drogę raz jeszcze z niekom-
pilowanym językiem.
PHP też wydawał się kiedyś idealny do pisania apli-
kacji web'owych. Przy odpowiedniej skali wielkości
projektu szybko nim przestawał być. Brak kontroli ty-
pów powodował znacznie większą ilość błędów aniże-
li w aplikacjach Java/C#. To był dobry język „jednooso-
bowy” – jedna osoba panuje nad nim, rozumie co jest
wewnątrz. Ale kilka osób nie jest w stanie pracować w
56
wrzesień 2007
D laczego powstał Ruby? Czy świat potrze-
439031367.038.png 439031367.039.png 439031367.040.png
 
dla programistów
Ruby
Listing 1. Deinicja metody Listing
Listing 4. Konsola interaktywnej pracy z Ruby
def will_you_marry_me ( she )
expectations = she.ind_
expectation
( expectations < my_savings )
end
Irb ( main ) : 001 : 0 > puts "Hello Ruby"
Hello Ruby
=> nil
irb ( main ) : 002 : 0 > 100. times { puts "I love you" }
I love you
I love you
...
I love you
=> 100
Listing 2. Równoważne warunki if
if expectations < my_savings
huraaaa
end
huraaaa if expectations < my_
savings
huraaaa unless expectations >
my_savings
bre). Piszą więc krótkie metody (jak refakto-
ryzacja zaleca) i od razu krótkie testy do nich.
Dzięki temu kod jest programowo testowal-
ny, luźno powiązany i bardziej czytelny. To
niewiarygodnie skuteczna metoda, która za-
wsze wygra z aplikacjami testowanymi ręcz-
nie, ale w językach kompilowalnych.
W obszarze testów jednostkowych Ru-
by jest prawdziwym liderem – nigdzie nie są
lepiej wspierane. Ruby On Rails , framework
do pisania aplikacji internetowych, na tyle
mocno je zintegrował, iż potrzeba dużo wy-
siłku aby je zignorować lub, o zgrozo, usu-
nąć. Tu jest ta zasadnicza różnica – inni da-
ją opcję dołączenia testów, Ruby daję opcję
wyłączenia.
Jeśli więc wciąż nie stosujesz TFD, naucz
się Ruby i pozostań przy skryptowaniu. Nie
pisz jednak nic dużego dla klienta – najpraw-
dopodobniej sobie i innym przysporzysz kło-
potów.
tekstowy. Jak szybko i skutecznie wyrazić
miłość? W Ruby nawet to jest możliwe:
100.times { puts "I love you"}
jednym projekcie jednocześnie, bez wyso-
kiej kultury (świadomości) pisania aplika-
cji w zespole.
Niektórzy zarzucą mi, że obecnie najpo-
pularniejszy CMS - Joomla, napisany jest w
PHP. To prawda. Ale jego popularność wyni-
ka głównie z architektury – Ty pisz tylko ma-
łe niezależne od siebie komponenty, a ich po-
łączenie zostaw nam. Inaczej mówiąc – koduj
co chcesz, tylko nic wielkiego.
Czy Ruby może być lepszy pod tym
względem? Przecież też jest niekompilowa-
ny, jak PHP. Na początku powiedziałem że
Ruby miał odrobinę szczęścia i można w nim
kodować większe aplikacje. To szczęście na-
zywa się „odpowiedni czas i miejsce”. A do-
kładniej mówiąc – Testy jednostkowe i Refak-
toryzacja, które upowszechniły się stosunko-
wo niedawno.
Programiści, którzy opanowali praktykę
Test First Development (TFD), czyli pisania te-
stów w trakcie kodowania (a nie kiedyś tam
po, jak wystarczy czasu) przyzwyczaili się, że
nie muszą „ręcznie” oceniać swoich wyni-
ków pracy, tzn. klikając coś tam i obserwując
czy mniej więcej działa. Dla nich kompilacja
też nie jest potrzebna. Jedyne co jest dla nich
wiarygodne, to wynik zakończenia testów. I
oczywiście obszar kodu, jaki pokryty został
testami (80% to idealny stan, ale i 50% jest do-
Semantyka jest wyrazista; syntaktyka stanie
zrozumiała w trakcie dalszego czytania.
Na Listingu 4 przedstawiono wynik ich
wykonania z konsoli irb (skrót od ang. interac-
tive ruby ), pozwalającej wykonywać komendy
Ruby w trybie konwersacji (komenda – odpo-
wiedź). Teraz czas na coś bardziej skompliko-
wanego. Stworzymy pierwszą metodę. W Ru-
by możemy deiniować je bez klasy.
Jak widać, linie nie kończą się żadnym
średnikiem. Nie jest to potrzebne, dopóki in-
strukcje separowane są osobnymi liniami. Me-
toda jest pytaniem, więc powinna zwracać wy-
nik. Gdzie jest wynik? W Ruby jest to rezultat
ostatniej wykonanej instrukcji. Można co praw-
da ostatnią instrukcję poprzedzić słowem re-
turn , ale to niekonieczne. Podobnie jak PERL,
Ruby chce być blisko języka mówionego i do-
puszcza dowolność budowania zdań. Każde ze
zdań przedstawionych na Listingu 2 jest rów-
noważne: Aby być jeszcze bliżej języka mówio-
nego, pozwala się na dowolność używania na-
wiasów () przy wywoływaniu metod. Każdy z
poniższych sposobów jest akceptowalny:
Hello Ruby
Czas w końcu zobaczyć Ruby w praktyce.
Na początku wypada się przywitać. Pamięta-
cie, ile zachodu potrzeba było w Javie czy C#,
aby wykonać tak prostą rzecz? Jaki przerost
formy nad treścią? Deiniowanie klasy, meto-
dy statycznej main etc.? Ruby to język dla bar-
dziej zdecydowanych – proste rzeczy wyko-
nujemy bez namysłu:
will_you_marry_me(Joanne)
will_you_marry_me Joanne
puts "Hello Ruby"
Wyrażenia regularne
W języku skryptowym nie może oczywi-
ście zabraknąć operacji na tekstach. Do
Puts jest metodą wypisująca tekst na ekran.
Między apostrofami umieszczamy literał
Listing 3. Przykłady operacji na tekstach
" Tom " .trim >> "Tom" # obetnij spacje z przodu i tyłu
" I like you much" .squeeze >> "I like you much" # zamień wielokrotne spacje na pojedyncze
"man" .pluralize >> "people" # liczba mnoga słówka "man"
"apple banna orange" .split >> [ apple , banana , orange ] # podziel na osobne wyrazy
www.lpmagazine.org
57
439031367.001.png 439031367.002.png 439031367.003.png 439031367.004.png 439031367.005.png 439031367.006.png 439031367.007.png 439031367.008.png 439031367.009.png 439031367.010.png 439031367.011.png 439031367.012.png 439031367.013.png 439031367.014.png
 
dla programistów
Ruby
Listing 5. Przykład deinicji i użycia prostej klasy
silibyśmy się do nich używając kolejno $2 , $3
... etc. Są to jedne z wielu predeiniowanych
zmiennych, ustawianych zależnie od kontek-
stu. Gdy nasze umiejętności rosną, używamy
ich coraz częściej.
do zmiennych instancji odwołać się później
w kodzie, musimy stworzyć dla nich opako-
wania, powszechniej znane jako metody set ,
get . Opakowania get tworzymy wywołując
specjalną metodę attr_reader , a 'set' po-
przez attr_writer .
Class Man
attr_reader : name , : age
def initialize ( name , age )
@name , @age = name , age
end
end
man = Man.new ( "Tom" , 20 )
Szybka podmiana
Wieczór rozdania nagród bliski i znów ko-
lejna komplikacja – dwójka aktorów nie da-
rzy się zbytnią sympatią, a my posadziliśmy
ich obok siebie. Jednego z nich trzeba szybko
przesadzić. Jak? W każdym innym języku po-
trzebne jest aby na sale wniesiono dodatkowe
"krzesło tymczasowe". W Ruby przebiega to
trochę sprawniej:
puts man.name
puts "I am adult" unless (man.age <
18)
dyspozycji ma bogatą bibliotekę, jak na
przykład:
Dużo ciekawsze są jednak funkcje, któ-
re przyjmują wyrażenia regularne jako pa-
rametr.
Załóżmy że jesteśmy organizatorem aka-
demii rozdania Oscarów, i mamy już przygo-
towane, niewydrukowane zaproszenia. Po
bliższym przyjrzeniu zauważyliśmy, że data
rozpoczęcia gali jest czasami nieprawidłowa.
Musimy to poprawić.
Wprawni programiści zauważyli pewien
detal – operator new pojawia się za nazwą
klasy a nie przed. Wygląda jak nazwa meto-
dy statycznej, a nie specjalne słowo kluczo-
we języka. I tak w rzeczywistości jest – nie
zdeiniowaliśmy w istocie klasy, a tylko
stałą posiadającą metodę new. Tutaj docho-
dzimy do najciekawszej własności. W Ru-
by wszystko jest obiektem. I to nie tak jak
w Javie, gdzie wszystko było klasą, z drob-
nymi wyjątkami (np: typy prymitywne). W
Ruby nie ma wyjątków – literały liczbowe
są obiektem, nawet nil jest obiektem. Ozna-
cza to możliwość wykonywania metod bez-
pośrednio na nich.
Niestety, obiekt tutaj różni się trochę od
znanych nam dotychczas obiektów z Java
czy C#. Nie ma klasy przypisanej jako typ
– nie wykorzystuje się operatorów ( instan-
ceof etc.) do sprawdzania typu. Zamiast za-
stosowano podejście ducktyping , czyli je-
śli obiekt chodzi jak kaczka, i odpowiada
jak kaczka to prawdopodobnie jest to kacz-
ka. Kluczową w takim podejściu jest metoda
respond_to? , zwracająca wynik posiadania
metody przez obiekt.
W ducktyping sprawdza się więc, czy
obiekt zawiera metody, a nie jakiego jest ty-
pu. Trochę jak w życiu – dla niektórych bar-
dziej liczą się umiejętności niż dyplom. Trud-
no powiedzieć którzy maja rację.
Sam fakt posiadania metody nie jest
oczywiście wystarczający aby jej użyć – na-
leży znać również listę parametrów. Jak to
zrobić? W Ruby nie ma przeciążania metod
więc jedna powinna być dobra dla wszyst-
kich. Zaprawieni w ducktyping programi-
ści zadają sobie więc pytanie, co się stanie
gdy do metody przekazana zostanie np. li-
actor_place, other_guy_place = other_
guy_place, actor_place
Jednocześnie możemy więc zwracać wy-
nik do kilku zmiennych. Oczywiście w ten
sam sposób moglibyśmy przesadzić i więcej
uczestników gali na raz.
Spójrzmy jeszcze raz na przykład z po-
przedniego akapitu, na metodę split, rozdzie-
lającą owoce po spacjach:
invitation_text.sub(/\dd-\dd\-d\dd\d/
, "10-10-2007")
W Ruby wyrażenia tworzymy albo z pomo-
cą klasy RegExp , albo w wersji szybszej, we-
wnątrz backslashów /../ .
W powyższym przykładzie podmienia-
my tylko pierwszy tekst pasujący do wyra-
żenia regularnego. Gdybyśmy chcieli zamie-
nić wszystkie wystąpienia, należy użyć me-
tody gsub .
Spójrzmy teraz na trochę trudniejszy
przypadek. Dostajemy informację, że w
tym roku pojawi się dwójka gości honoro-
wych i należy im przyznać miejsca o nume-
rach 1, 2. Musimy więc wszystkich pozosta-
łych przesunąć o 2 miejsca. Skorzystamy w
tym celu z grupowania w wyrażeniach re-
gularnych:
"apple banna orange".split =>
["apple", "banana", "orange"]
Aby pobrać tylko pierwsze dwa owoce, za-
miast wszystkich, napiszemy następująco
fruit1, fruit2 = "apple banna
orange".split
Co by się stało, gdyby metoda zwróciła tylko
jeden owoc? fruit2 otrzymałby wartość nil .
Wszystko jest obiektem
Ruby jest językiem obiektowo zorientowa-
nym. Nie jest to „dostawka”, jak w PERLu
czy PHPie, ale obiektowość jest wbudowana
od samego początku. Na Listingu 5 zdeinio-
waliśmy klasę z domyślnym konstruktorem
dwuparametrowym. Symbol @ daje sygnał,
aby odwołać się do zmiennych instancji kla-
sy, a jeśli takich nie ma – to utworzyć je. Stwo-
rzyliśmy więc dwie zmienne instancji i prze-
pisaliśmy do nich wartości parametrów. Aby
invitation_text.gsub(/Place: (\d*)/,
"Place: #{$1+2}")
Magiczny symbol $1 oznacza treść tekstu pa-
sującego do wyrażenia ujętego w nawiasach
(). Gdybyśmy mieli więcej nawiasów, odno-
Listing 6. Wszystko jest obiektem
"Apple" .downcase >> "apple" # przekształć do małych liter
100. times { .. } # wykonaj 100 razy blok (w dalszej części poznamy bloki)
nil.methods # zwróć listę metod należących do obiektu
1 .. 5. each { .. } # wykonaj blok 5 razy
will_you_marry_me.methods # zwróć listę metod należących do .... metody !
58
wrzesień 2007
439031367.015.png 439031367.016.png 439031367.017.png 439031367.018.png 439031367.019.png
 
dla programistów
Ruby
sta zamiast pojedynczej wartości. I kodu-
ją tak, aby metoda potraiła obsłużyć każdą
ewentualność.
Hmm, ciekawe. Ale wciąż nie rozumie dla-
czego nie możemy skorzystać ze sprawdzania kla-
sy obiektu? ”. W Ruby istnieje nawet metoda
pozwalająca to zrobić – kind_of? . W polskim
tłumaczeniu – „jakiś taki”, co też trafnie od-
powiada na to pytanie. Słowo klasa występu-
je tu bowiem bardziej jako oznaczenie zbioru
metod wyjściowych, niż coś, na czym może-
my polegać. Dzieje się tak dlatego, bo w trak-
cie działania aplikacji możemy obiekt dowol-
nie modelować, dodając nowe metody i mo-
dyikując istniejące. Możemy to czynić za-
równo dla pojedynczych obiektów jak i ca-
łych klas.
Możemy również skorzystać z MixIn ,
czyli dołączanych do klasy całych modu-
łów metod. Czasami wielu na raz. W Javie
nie ma wielodziedziczenia, ale jest imple-
mentacja wielu interfejsów na raz. Pustych
interfejsów.
Moduły pozwalają osiągnąć podob-
ną funkcjonalność – są jak interfejsy, z w
tym wyjątkiem, że częściowo wypełnione.
Naszym obowiązkiem jest dopisane tylko
jednej – dwóch kluczowych metod, a po-
zostałe dostajemy „za darmo”. Weźmy ja-
ko przykład moduł Comparable – zawie-
ra 6 gotowych metod, a brakuje tylko jed-
nej, aby mogły zostać użyte – nierówności
obiektów <=> .
Generalnie, MixIn przypominają trochę
wzorzec projektowy Template – metody w
klasie bazowej polegają na implementacjach
metod abstrakcyjnych w klasach wywiedzio-
nych. Jeszcze ogólniej, MixIn przypominają
również... wielodziedziczenie!
• Wszystko co zaczyna się z wielkiej litery,
jest stałą:
• SOME_CONSTANTS
• OtherConstants
• Klasa, jak powiedzieliśmy, też jest stałą
– musi więc zaczynać się z dużej litery.
• Metody w klasie nie są natomiast stały-
mi, dlatego zawsze zaczynają się z małej
litery.
• Do zmiennych instancji odwołujemy się
poprzez symbol @, a do zmiennych glo-
balnych – $
• @instance_variables
• @@class_variables
• $global_variables
• Metody tylko odpytujące obiekt powin-
niśmy kończyć znakiem ?, a metody
zmieniające obiekt – znakiem !.
{ |param1, param2 | puts "Params
values are: #{param1}, #{param2}"}
Spójrzmy teraz w jaki sposób możemy bez-
piecznie z pomocą bloku operować na pli-
kach.
File.open("message.txt") { |ile|
ile.print_lines }
Co tu się stało? Do metody statycznej open
przekazaliśmy blok kodu. W nim zawarli-
śmy wszystko, co chcemy wykonać na pli-
ku. Sama metoda open zatroszczyła się na-
tomiast o detale, jak otwarcie pliku, wyko-
nanie bloku i kolejno zamknięcie. Imple-
mentację open przedstawiono na Listin-
gu 11.
Konstrukcja begin ... ensure ...
end to znane z Java/C# try ... inally .
Yield natomiast wykonuje przekazany blok,
o ile tylko został przekazany – sprawdza to
block_given ?.
W taki oto sposób myślałem o blo-
kach: użyteczne tylko do obsługi plików,
połączeń z bazą danych, czyli wszędzie
tam, gdzie zasoby muszą zostać zwolnio-
ne. To jednak nieprawda. Blok kryje w so-
bie znacznie więcej. W połączeniu z itera-
torami zmieniają sposób, w jaki dotychczas
zwykliśmy budować pętle. Aby to jednak
zobaczyć, najpierw musimy poznać kon-
tenery.
Martin Fowler pisze [9], że wszystkie metody
w systemie powinny być wyraźnie podzielone
na dwie kategorie: odpytujące i modyikują-
ce. Jeśli metoda zawiera w sobie kalkulację/
logikę (odpytywanie) i modyikacje, to powin-
na zostać zrefaktoryzowana do dwóch metod.
Dlaczego? Bo metody odpytujące bezpiecznie
używać – przecież nic nie modyikują! Dodat-
kowo możemy czynić to w dowolnej kolejno-
ści. Tego samego nie można powiedzieć o me-
todach modyikujących, zwłaszcza kiedy wy-
wołują poniżej kolejne podobne sobie meto-
dy. Każda z nich musi być osobno zanalizo-
wana. No i dowolność wywołania to czyste
szaleństwo. Spójrzmy jeszcze raz na metodę
will_you_marry_me z początku i poprawmy
ją, aby pasowała do konwencji. Metoda zde-
cydowanie niczego nie zmienia, więc powin-
na kończyć się znakiem zapytania.
Druga metoda, która teraz dodaliśmy
get_married_with! z pewnością niesie
za sobą modyikacje. I niemałe konsekwen-
cje. Byłoby nie fair, gdybyśmy nie ostrzegli
wykrzyknikiem przed jej użyciem.
Listing 7. Ducktyping – czy metoda odpowiada
if obiekt.respond_to? ( sing )
#to zaśpiewaj
obiekt.sing
end
Konwencje
Jestem pewien, że niektórzy mają już na-
prawdę dosyć. Zmiany pojedynczych obiek-
tów, dowolność wykonywania operatorów,
zmiany istniejących klas, quasi wielodziedzi-
czenie! Wszyscy mogą robić wszystko. Jak z
tym żyć?!
Są miejsca, gdzie można na wiele sobie
pozwolić. Ale są i takie, gdzie Ruby jest re-
strykcyjny bardziej niż jakikolwiek inny ję-
zyk. Są to konwencje nazewnicze. Bardzo je
lubię, bo we wszystkich dotychczasowych
projektach, w jakich uczestniczyłem, wpro-
wadzenie konwencji nigdy się całkowicie
nie powiodło. Zawsze ktoś miał „istotny”
powód, aby ich nie stosować. Fakt, sam Ru-
by nie ma ich jeszcze tak wiele, jak np. czyni
to Ruby On Rails , ale i tak więcej niż pozosta-
li. Najważniejsze konwencje to:
Listing 8. Dynamiczne dodawanie metody do
pojedynczego obiektu
Bloki – nigdy więcej zamykania
plików
Ruby wprowadza pojęcie bloków, czyli ka-
wałka kodu, który może być przekazany jako
parametr. No bo i dlaczego nie?!
Blok budujemy na dwa sposoby: krótki
blok jednoliniowy zamykamy w nawiasach
klamrowych
class << obiekt
def sing
end
end
Listing 9. Dynamiczne dodawanie metody do
klasy
{ puts "Hello" }
a wieloliniowy blok z pomocą słów do ...
end (Listing 12).
Do bloku możemy przekazywać parame-
try, jak do zwykłej funkcji.
class << String
def sing
end
end
www.lpmagazine.org
59
439031367.020.png 439031367.021.png 439031367.022.png 439031367.023.png 439031367.024.png 439031367.025.png 439031367.026.png 439031367.027.png 439031367.028.png 439031367.029.png 439031367.030.png 439031367.031.png 439031367.032.png
 
dla programistów
Ruby
Listing 10. Podział na metody odpytujące i mo-
dyikujące
fruits = ['apple', 'orange', 'bannan']
fruits.each {|fruit| puts "I am
#{fruit}"}
Listing 11. Źródło metody open
class Man
def will_you_mary_me ? ( she )
end
def get_married_with ! ( she )
end
end
Co zrobiliśmy? Na każdym elemencie z ta-
blicy wykonaliśmy blok, wypisujący nazwę
owocu na ekran.
A oto dwa powyższe przykłady z Ha-
skell, przepisane do Ruby:
Def File .open ( *args )
result = f = File.new ( * args )
if block_given?
Begin
result = yield f
ensure
f.close
end
end
return result
end
Kontenery
Kontenery to nic innego jak zwykle listy i
hash-listy . Listy budujemy z pomocą nawia-
sów kwadratowych []
[1, 2, 3, 4].map {|i| i+1} =>
[1,2,3,4]
[-1,2,-3,5].select {|i| i>0} =>
[2,5]
I na sam koniec coś trudniejszego
XML'a – dla wygody i szybkości implementa-
cji. Oni i wielu innych programistów.
Cechą narzędzi napisanych w Ruby jest
właściwie całkowity brak plików XML. Po
części wynika to z zastąpienia go Yaml'em,
ale Yaml nie jest używany do konigurowa-
nia. Dlaczego tak się dzieje? Dlaczego nie ma
XMLa? Bo Ruby jest na tyle dynamicznym ję-
zykiem, że wszystkie DSLe łatwiej budować
w samym Ruby, niż uciekać się do XMLa. Jest
jakby połową drogi między prawdziwym par-
serem a nieelastyczną Javą/C#. Spójrzmy na
Listing 13. – porównanie prostego przykładu
ANTa i jego odpowiednika w Ruby – Rake'a.
Kto czytał uważnie ten artykuł, zauwa-
ży że przykład z Rake'a to zwykła składnia
Ruby – jest to wywołanie metody task , do
fruits = ['apple', 'orange', 'bannan']
[ 1, 2, 3, 4, 5 ].inject (0) {|v,n|
v+n } => 15
a hash-listy z pomocą nawiasów klamrowych
{} , lub bez.
Jest to zsumowanie wszystkich elementów.
W zmiennej v trzymamy wynik, „wstrzyku-
jąc” mu na początek 0, a do zmiennej n prze-
kazujemy kolejne elementy z listy.
Im więcej pracujemy w Ruby, tym co-
raz częściej korzystamy z takiej kombinacji.
W pewnym momencie zauważamy, że w na-
szym kodzie nie ma prawie pętli while i for .
Przypomina to trochę sytuację z refaktory-
zacji, gdzie na brak zrozumienia polimori-
zmu wskazywano nadużywanie w kodzie if
i switch . Tutaj takim wyznacznikiem braku
zrozumienia myślenia w Ruby, będzie nad-
używanie właśnie instrukcji while i for .
fruits = {'a' => 'apple', 'o' =>
orange , 'b' => 'bannan'}
fruits = 'a' => 'apple', 'o' => orange
, 'b' => 'bannan'
Same kontenery oczywiście nie wnoszą
nic nowego – spotykamy je w każdym ję-
zyku obiektowym. To co jest interesujące,
to sposób ich używania, albo raczej nad-
używania.
Języki funkcyjne, takie jak Haskell, ma-
ją tą własność, że rzadko operują na poje-
dynczych wartościach. Funkcje matematycz-
ne (operacje) stosuje się na całych listach, a
wynikiem jest zwykle nowa lista. Spójrzmy
na przykład:
DSL
Być może część czytelników już usłyszała
gdzieś ten skrót, ale duża część na pewno
jeszcze nie. Uprzedzam, że nie mam na my-
śli modelu modemu. DSL to skrót od Doma-
in Speciic Language czyli język specyiczny w
danej domenie zastosowania. A konkretniej?
Język, który ma bardzo wąskie zastosowanie.
Takim językiem jest np. ANT – jego instrukcje
służą zasadniczo tylko do kompilacji. Dzięki
temu ograniczeniu czytając plik ANT operu-
jemy na dużo wyższym poziomie abstrakcji,
niż gdybyśmy musieli czytać te same instruk-
cje napisane w Java.
Ok – widzę jak wielu się śmieje. XML?
Język programowania? Co to za język?! Ma-
ją rację! Ironią losu jest jednak, że programu-
jąc w Java, więcej czasu konigurujemy coś w
XML niż piszemy w samej Javie. A dlaczego
wszystkie koniguracje są w XML? Bo napi-
sanie parsera do własnego języka DSL jest
wciąż bardzo trudne (można to uczynić np.
w ANTLR) i niewielu programistów to potra-
i. Tylko z tego względu autorzy ANT'a użyli
map (+) 1 [0,1,2,3] => [1,2,3,4] #
dla każdego elementu z listy stosujemy funk-
cję zwiększenia o 1.
Albo inny:
ilter (>) 0 [-1, 2, -3, 5] => [2,5] #
z listy wybieramy tylko elementy większe
od zera.
Jeśli spojrzymy na listę metod dowolne-
go kontenera w Ruby, wśród wyników znaj-
dziemy zadziwiająco podobne funkcje: each ,
map , select , collect etc. Są to tzw. iterato-
ry. Czy Ruby to język funkcyjny? Jeszcze nie.
Wydaje się być w połowie drogi.
for, while – a co to?
Zobaczmy w końcu, jak „złota trójka” czyli
kontenery, iteratory i bloki pracują razem.
Rysunek 1. Programowanie ducktyping, czyli wszyst-
ko, co porusza się i mówi jak kaczka, jest kaczką
60
wrzesień 2007
439031367.033.png 439031367.034.png 439031367.035.png 439031367.036.png 439031367.037.png
 
Zgłoś jeśli naruszono regulamin