Wikipedysta:Szymon wro/Brudnopis
Przykład kolorowania składni Rubiego
[edytuj]def metoda(*args)
wynik = ""
args.each {|arg| wynik += "#{arg}, "}
wynik[0...-2] # ucinamy 2 ostanie znaki: ", "
end
puts metoda("a", "b", 3) #=> a, b, 3
Przykład kolorowania w tekście def puts. Nie działa :( Ideałem było by używanie {podświetl|rb} ;)
Ruby kolorowanie a'la Barbie
# Wymaga terminala ANSI!
st = "\033[7m"
en = "\033[m"
puts "I'm a barbie girl in a barbie world."
while true
print "tekst> "; STDOUT.flush; tekst = gets.chop
break if tekst.empty?
print "wzor> "; STDOUT.flush; wzor = gets.chop
break if wzor.empty?
wyr = Regexp.new(wzor)
puts tekst.gsub(wyr,"#{st}\\&#{en}")
end
Różne
[edytuj]Domknięcia i obiekty procedurowe
[edytuj]Domknięcia
[edytuj]Ruby jest językiem korzystającym w dużym stopniu z domknięć. Domknięcie jest blokiem kodu przekazywanym do metody. Samo w sobie nie jest obiektem. Domknięcie zawierające niewiele instrukcji, które można zapisać w jednej linii zapisujemy pomiędzy nawiasami klamrowymi ({}), zaraz za wywołaniem metody:
3.times { print "Bla" } #=> BlaBlaBla
Domknięcia dłuższe zapisujemy w bloku do ... end
i = 0
3.times do
print i
i += 2
end
#=> 024
Obsługa bloku przekazanego do funkcji odbywa się poprzez słowo kluczowe yield, które przekazuje sterowanie do bloku. Spójrzmy na przykład metody powtorz.
def powtorz(ilosc)
while ilosc > 0
yield # tu przekazujemy sterowanie do domkniecia
ilosc -= 1
end
end
powtorz(3) { print "Bla"} #=> BlaBlaBla
Po zakończeniu wykonywania przekazanego bloku sterowanie wraca z powrotem do metody. Dzięki słowu kluczowemu yield możemy również przekazywać do bloku obiekty:
def powtorz(ilosc)
while ilosc > 0
yield ilosc
ilosc -= 1
end
end
Aby użyć wartości przekazanej do bloku stosujemy identyfikator ujęty w znaki |:
powtorz(3) { |n| print "#{n}.Bla " } #=> 3. Bla 2. Bla 1.Bla
Co jednak, gdy używamy yield, a do metody nie przekazaliśmy żadnego bloku? Aby uchronić się przed wystąpieniem wyjątku używamy metody block_given?, która zwraca true, gdy blok został przekazany.
def powtorz(ilosc)
if block_given?
while ilosc > 0
yield ilosc
ilosc -= 1
end
else
puts "Brak bloku"
end
end
powtorz(3) # nie przekazujemy bloku
#=> Brak bloku
Obiekty procedurowe
[edytuj]Bloki można zamienić w łatwy sposób na obiekty (są to obiekty klasy Proc). Można użyć do w tym celu słów kluczowych lambda lub proc, z czego zalecane jest to pierwsze. Poniższy kod utworzy dwa obiekty procedurowe:
hej = lambda { print "Hej" }
witaj = proc do
puts "Witaj!"
end
Aby wykonać dany blok zawarty w obiekcie procedurowym (wywołać go) należy użyć metody call:
hej.call #=> Hej
witaj.call #=> Witaj!
W wywołaniu call możemy również przekazać parametry do bloku:
drukuj = lambda { |tekst| print tekst }
drukuj.call("Hop hop!") #=> Hop hop!
Obiekty procedurowe mogą być, jak każde inne obiekty, przekazywane jako parametry. Możemy zdefiniować alternatywną metodę powtorz która bedzie wykorzystywać lambdę przekazaną jako parametr. Rozważmy poniższy przykład:
def powtorz(ile, co)
while ile > 0
co.call(ile) # wywołujemy blok "co"
ile -= 1
end
end
l = lambda do |x|
print x
end
powtorz(3, l) #=> 321
powtorz(3, lambda { print "bla" }) #=> blablabla
Jak widzimy w ostatniej linii, obiekty lambda mogą być anonimowe (nie nadajemy im żadnej nazwy). Więcej o tym, co to są obiekty anonimowe dowiesz się w rozdziale o klasach. Natomiast w rozdziale o zmiennych lokalnych zobaczysz, że obiekty procedurowe i domknięcia zachowują kontekst (stan zmiennych lokalnych) w jakim zostały wywołane.
Różnice między lambdą a Proc.new
[edytuj]Obiekty procedurowe można również tworzyć używając konstrukcji Proc.new. Bardziej szczegółowo omówimy tę konstrukcję w rozdziale dotyczącym klas, tutaj jedynie powiemy o pewnych różnicach pomiędzy lambdami a obiektami utworzonymi za pomocą Proc.new.
Surowe obiekty Proc (ang. raw procs), czyli utworzone poprzez Proc.new, posiadają jedną niedogodność: użycie instrukcji return powoduje nie tyle wyjście z domknięcia obiektu procedurowego, co wyjście z całego bloku, w którym domknięcie było wywołane. Może to powodować niespodziewane wyniki działania naszych programów, dlatego zaleca się używanie lambd, a nie surowych obiektów Proc.
def proc1
p = Proc.new { return -1 }
p.call
puts "Nikt mnie nie widzi :-("
end
def proc2
p = lambda { return -1 }
puts "Blok zwraca #{p.call}"
end
Wywołany proc1 zwraca jedynie wartość, nie wypisze żadnego tekstu. Odmiennie działa proc2 - tutaj return powoduje, że sama lambda zwraca wartość, do której można się odwołać w dalszej części bloku, w którym utworzono lambdę.
Fragmenty
[edytuj]Konia z rzędem temu, kto wie, gdzie to wsadzić... :P
* czyli zmienna lista argumentów
[edytuj]Gwiazdka (*) oznacza zmienną listę argumentów. Jeżeli * pojawia się w nagłówku definiowanej metody, poprzedzając ostatni parametr, oznacza to, że począwszy od tego tego argumentu do metody można przekazać dowolną ich ilość. Wszystkie te argumenty są widoczne w metodzie jako tablica.
def metoda(*args)
wynik = ""
args.each {|arg| wynik += "#{arg}, "}
wynik[0...-2] # ucinamy 2 ostanie znaki: ", "
end
puts metoda("a", "b", 3) #=> a, b, 3
Gwiazdkę * można też stosować w wywołaniu metody, przed ostatnim argumentem - tablicą. Powoduje ona wtedy konwersję z tablicy na poszczególne argumenty:
def inna_metoda(a, b, c)
"#{a}, #{b}, #{c}"
end
puts inna_metoda(*["a", "b", 3]) #=> a, b, 3
puts inna_metoda("a", *["b", 3]) #=> a, b, 3
& czyli przekazywanie bloku
[edytuj]Poznaliśmy już domknięcia i sposoby przekazywania ich do metody. Domknięcie możemy przekazać, definiując je bezpośrednio za nazwą metody. Natomiast obiekt procedurowy możemy przekazywać jako parametr. Wiemy też, że sterowanie do domknięcia przekazujemy przez yield, natomiast procedurę obiektu procedurowego wywołujemy przez metodę call. Co jednak, gdy chcielibyśmy użyć bloku przekazanego jako domknięcie tak jakby był obiektem (stosując call zamiast yield)? Albo gdybyśmy chcieli utworzony już obiekt procedurowy przekazać tak jakby był blokiem?
Rozważmy naszą metodę powtórz z rozdziału o domknięciach:
def powtorz(ilosc)
while ilosc > 0
yield ilosc
ilosc -= 1
end
end
Aby przekazać do tej metody blok, który mamy w postaci np. lambdy, należy użyć symbolu & i przekazać nasz blok jako ostatni (niby fikcyjny) argument. Fikcyjny, bo nie jest on jawnie zdefiniowany w nagłówku metody.
l = lambda { |x| print x }
powtorz(3, &l) #=> 321
Efekt jest taki sam jakbyśmy przekazali blok tradycyjnie:
powtorz(3) { |x| print x } #=> 321
Symbolu & możemy też używać przed ostatnim parametrem w definicji metody. Dzięki temu, możemy uzyskać niejako odwrotne działanie: odwoływać się do bloku jak do obiektu procedurowego:
def powtorz(ilosc, &blok)
while ilosc > 0
blok.call(ilosc) # to samo co yield ilosc
ilosc -= 1
end
end
powtorz(3) { |x| print x } #=> 321
l = lambda { |x| print x }
powtorz(3, &l) #=> 321
Jak widzimy, jawne przekazanie obiektu l jako bloku również jest poprawne.