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.