Ruby 1.9 besitzt eine mächtigere Syntax als 1.8. Ich zeige meist nur, was in 1.8 geht!
receiver.method(arguments) { ...block... }
Außer dem Methodennamen ist alles optional!
Es kann höchstens ein Block übergeben werden
class A def fun1 ... end def fun2 fun1 end end
Wenn keiner angegeben, ist self
implizit der Receiver!
puts("Hello world")
Was ist hier der receiver, und wieso ist Kernel#puts
hier aufrufbar?
Methodennamen können auf !
oder ?
enden.
Die Bedeutungen sind reine Konvention!
Methoden mit ?
am Ende liefern true
oder false
zurück:
"abc".instance_of?(String) # => true
!
am Ende des Namensa = [[0, 1]] a.flatten a.length # => 1
a = [[0, 1]] a.flatten! a.length # => 2
class MyClass def ==(other) ... end end a = A.new a == 1 a.== 1
Hierzu bietet die Syntax zwei äquivalente Möglichkeiten:
object.method(args) { |a1, a2| a1 + a2 } object.method(args) do |a1, a2| a1 + a2 end
Konvention: do ... end
wenn der Block über mehrere Zeilen geht
Achtung: return
im Block beendet umgebende Methode, nicht den Block!
irb(main):019:0> call_with 4 { |n| puts n } SyntaxError: compile error
puts html_escape("here & there")
return
class MyClass def fun(a1, a2) a1 + a2 + @ivar end endRückgabewert: Wert des letzten Ausdrucks
class YourClass def self.fun(a1, a2) return a1 + a2 end endRückgabewert: Argument von
return
def fun(arg) return yield(arg + 1) * 2 end fun(3) { |a| a.to_s } # => "44"
Der übergebene Block wird mit yield
aufgerufen, Parameter und Rückgabe sind möglich.
irb(main):023:0> fun 0 LocalJumpError: no block given
Mit block_given?
lässt sich prüfen, ob ein Block übergeben wurde.
if block_given? ... else ... end
oder so:
raise ArgumentError, "fun expects a block parameter" unless block_given?
def fun(arg, &block) raise ArgumentError, "fun expects a block parameter" if block.nil? return 2 * block.call(arg + 1) end
Der übergebene Block wird in ein Proc-Objekt verwandelt.
Dieses lässt sich wegspeichern und an ganz anderer Stelle aufrufen!
def takes_block(arg, &block) @block = block end def invokes_block @block.call end def fun takes_block(0) { return } end fun invokes_block
Was passiert, wenn return
aufgerufen wird?
Statt eine Proc-Objekt (hier in my_block
gespeichert) mit
my_block.call(3)
direkt aufzurufen, kann es auch anstelle eines Block-Arguments übergeben werden:
call_with(3, &my_block)
Achtung: Ohne das &
würde einfach das Proc-Objekt selbst übergeben! (auch manchmal sinnvoll)
def divide(arg, by = 2, allow_0 = false) ... end
self
) ausgeführt wirddef obj.fun(arg = @ivar) ... end
def announce(channel, *items) items.each { |i| channel << i } return items.length end announce(broadcast) # => 0 announce(broadcast, "gaga") # => 1 announce(secure, "secret", "token") # => 2
Alle Parameter ab der Stelle werden in einem Array gesammelt und übergeben.
#Ab Ruby 1.9 moeglich: def fun(arg1, *splat, arg2)
def fun(*arguments) case arguments.length when 1 name = arguments[0] ... when 2 name, value = arguments ... else raise ArgumentError, "detailed complaint" end end
Man kann auch auf den "Typ" der Argumente prüfen.
fun("abc", 0, 1, 2) #macht das gleiche wie fun("abc", *[0, 1, 2])
Statt
notify("x", { :async => false, :count => 3 })
geht auch, dank syntaktischem Zucker:
notify("x", :async => false, :count => 3)
oder, da Klammern optional sind:
notify "x", :async => false, :count => 3
Der Hash muss als letztes übergeben werden
Dies ermöglicht benannte Parameter!
Best practice dabei:
def fun(arg, option_hsh = {}) ... end
Nun ist das Hash-Argument optional.
&block
vs. yield
Und von der Aufrufseite kommt noch hinzu
class MyClass ... private def fun end end
class MyClass def fun1 end private :fun end
Genauso: public
, protected
private
private
Methoden können nicht mit explizitem Receiver aufgerufen werden.
Zugriff bleibt innerhalb der Instanz.
protected
protected
Methoden können nur aus Objekten der gleichen Klasse (oder einer abgeleiteten)
aufgerufen werden.
Zugriff bleibt innerhalb der Familie.
__send__
object.__send__(:fun, arg1, arg2) { ... }
__send__
umgeht access controlsuper
Überladende Methoden können die zuletzt gültige Definition aufrufen:
class FilledRectangle < Rectangle def paint super fill end private def fill ... end end
Achtung: Ohne explizite Argumente an super
werden
die Argumente der überladenden Methode weitergereicht!
class Base def fun(arg) arg * 2 end end class Derived < Base def fun(arg) super end end Derived.new.fun(3) # => 6
method_missing
class MyClass def method_missing(method, *args, &block) case method when :fun1 ... when :fun2 ... else super #raises NoMethodError end end end
def fun @p_proc = Proc.new { |args| ... } @p_lambda = lambda { |args| ... } end
speichert zwei Proc-Objekte. Unterschiede:
@p_lambda.call(...)
wird die Anzahl der übergebenen Argumente geprüftlambda
beendet return
im Block nur den Block,
nicht die umgebende Funktion fun
⇒ lambda
-Procs mehr wie Funktionen!
p = object.method(:fun) p.call(arg) #macht jetzt das Gleiche wie object.fun(arg)
p = :fun.to_proc p.call(obj, arg) #macht jetzt das Gleiche wie obj.fun(arg)
Dies ist nützlich für dieses Idiom mit sehr funktionalem Geschmack:
irb(main):001:0> ["a", "b", "c"].reduce(&:+) => "abc" irb(main):002:0> ["a", "b", "c"].reduce { |memo, nxt| memo + nxt } => "abc"(Verwendung von
&
ruft implizit to_proc
auf)