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")