do
i end
,|
) i nie jest wykonywany, od razu,best_movie = "Young and Beautiful" ["The Great Beauty", "The Wolf of Wall Street", "Il Divo"].each do |movie; best_movie| best_movie = movie if movie.include?('Divo') end puts best_movie # => Young and Beautiful
yield
,yield
,def praise_her(actress) praise = yield actress puts "#{praise} very much!" end praise_her('Marine Vacth') { |a| "I love #{a}" }
inject
bez podania parametru, metoda użyje pierwszego elementu kolekcji jako wartości początkowej i rozpoczyna iterację z drugim elementem: > [1, 2, 3].inject() {|sum, element| sum + element} => 6 > [1, 2, 3].inject(10) {|sum, element| sum + element} => 16
yield
gdy wygeneruje nową wartość), enumeratory to pełnoprawne obiekty, które można przekazywać metodom,to_enum
(lub enum_for
),loop
wykonuje przekazany jej blok w nieskończoność. Kiedy jednak wykorzystamy tam obiekt enumeratora, gdy jego elementy się skończą, loop
zakończy swoje działanie: > short_enum = [1, 2, 3].to_enum => #<Enumerator: [1, 2, 3]:each> > long_enum = ('a' .. 'z').to_enum => #<Enumerator: "a".."z":each> > loop {puts "#{short_enum.next} - #{long_enum.next}"} 1 - a 2 - b 3 - c => nil
yield
. Dzięki temu, można tworzyć nieskończone enumeratory: fib = Enumerator.new do |y| a = b = 1 loop do y.yield a a, b = b, a + b end end p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
yielder
, podany jako parametru bloku, może być wykorzystany by otrzymać wartość, wywołując metodę yield
,&
, Ruby będzie szukać bloku z każdym wywołaniem metody. Blok jest zamieniany na obiekt klasy Proc
i przypisany parametrowi,mixin
),include
tworzy referencję do modułu. Jeśli ten moduł jest w innym pliku, musi zostać wcześniej załadowany (poprzez require
lub load
). Jeśli moduł jest zawarty w wielu klasach i jest zmieniony podczas działania programu, wszystkie klasy będą miały uaktualnione metody z tego modułu,attr_reader
i jemu podobnych aby zdefiniować akcesory dla tych zmiennych,Fixnum
(-2^30…2^30 - 1 lub -2^62…2^62-1)Bignum
. Proces przechodzenia pomiędzy przedziałami jest transparentny-
),0
- ósemkowy, 0d
- dziesiętny, 0x
- szesnastkowy, 0b
- binarny),Float
,Rational(3, 4) * Rational(2, 3) # => (1/2) Complex("1+2i") * Complex("3+4i") # => (-5+10i)
self
,self
,movie.length
wywołuje metodę length
na obiekcie movie
, który nazywamy odbiorcą wywołania). Jeśli wywołujemy metodę bez podania odbiorcy (puts string
), Ruby jako odbiorcę ustawia obecny obiekt, zreferencjonowany przez self
i tam szuka metody. W obu przypadkach, proces ten jest zbliżony, ponieważ podanie odbiorcy spowoduje ustawienie self
na obiekt odbiorcy (w naszym przypadku obiekt zreferencjonowany przez movie
) na czas wywołania metody,self
jest zmieniana również podczas definiowania klasy. Jest to spowodowane tym, że w Rubym klasy to również wykonywalny kod, a jeżeli jesteśmy w stanie wykonać jakiś kod, musi on mieć obiekt. class Vcard puts "self = #{self}, self.class = #{self.class}" end # => self = Vcard, self.class = Class
self
jest ustawiona na klasę Vcard
, która również jest obiektem. Zmienne instancji, zdefiniowane w środku definicji klasy będą dostępne metodom klasy, ponieważ self
będzie takie samo gdy były one definiowane i kiedy metody były uruchamiane.
class Ticket @price = 100 def self.first_price @price end end Ticket.first_price # => 100
class Ticket; end ticket_1 = Ticket.new ticket_2 = Ticket.new def ticket_1.price puts "Too much!" end ticket_1.price ticket_2.price # => Too much! # => singleton_methods.rb:11:in `<main>': undefined method `price' for #<Ticket:0x91292ac> (NoMethodError)
ticket_1
, Ruby utworzył nową anonimową klasę i zdefiniował w niej metodę price
. Ta anonimowa klasa, nazywana klasą singletonową lub eigenclass jest ustawiana jako superklasa klasy Ticket
, ale tylko dla obiektu ticket_1
,Class
i wywołujemy je na tym obiekcie,class << ticket_1 def info puts "I am a #{self}" end end
self
jest ustawiane do klasy singletonowej. Ponieważ definicje klas zwracają wartość ostatnio wykonanego polecenia, możemy to wykorzystać do dostania się do obiektu singletona: class Ticket; end ticket_1 = Ticket.new def ticket_1.price puts "Too much!" end singleton = class << ticket_1 def info puts "Ticket from Knurow to Zernica" end self end puts "Singleton: #{singleton}" puts "Singleton methods: #{singleton.instance_methods - Ticket.new.methods}" # Singleton: #<Class:#<Ticket:0x8bcded4>> # Singleton methods: [:price, :info]
super
i ustawia jej widoczność na tą, którą wybraliśmy; super
może wywoływać metody superklasy bez względu na ich widoczność.include
jest tak zaimplementowane, że wstawiany moduł jest ustawiany jako klasa nadrzędna klasy, do której moduł wstawiamy,Object#extend
,extend
to ekwiwalent self.extend
, metody dodawane są zatem do self
, co w definicji klasy jest tą klasą.class Logger def self.add_logging def log(message) STDERR.puts Time.now.strftime("%H:%M:%S:") + "#{self} (#{message})" end end end class Example < Logger add_logging end ex = Example.new ex.log("Haii")
define_method
, przyjmując nazwę metody i blok, definiuje metodę o podanej nazwie i ciele metody z bloku. Każdy argument w definicji bloku staje się parametrem nowej metody. class Logger def self.add_logging(id_string) define_method(:log) do |msg| now = Time.now.strftime("%H:%M:%S") STDERR.puts "#{now}-#{id_string}: #{self} (#{msg})" end end end class Song < Logger add_logging "Song" end class Album < Logger add_logging "Album" end Song.new.log("tralala")
included
, która jest uruchamiana za każdym razem, gdy dołącza się moduł do klasy. module GeneralLogger def log(msg) puts Time.now.strftime("%H:%M: ") + msg end module ClassMethods def attr_logger(name) attr_reader name define_method("#{name}=") do |val| log "Assigning #{val.inspect} to #{name}" instance_variable_set("@#{name}", val) end end end def self.included(receiver) receiver.extend ClassMethods end end class Example include GeneralLogger attr_logger :value end ex = Example.new ex.log("Hello!") ex.value = 123 puts "Value is #{ex.value}" ex.value = "Snooker" puts "Value is #{ex.value}"
Object#send
umożliwia wywołanie metody na obiekcie. [1, 2, 3, 4].send(:size) # => 4 "Olivia Wilde".send("sub", "livia", "scar") # => "Oscar Wilde"
Method
umożliwia to samo. Zachowuje się jak Proc
, to znaczy że zachowuje kontekst, w którym uruchamia. olivia = "Olivia Wilde".method("sub") # => #<Method: String#sub> olivia.call("livia", "scar") # => "Oscar Wilde" = "Olivia Wilde".method("sub")