Ruby Aus anderen Sprachen

Wenn Sie sich zum ersten Mal mit Ruby-Code beschäftigen, wird er Sie wahrscheinlich an andere Programmiersprachen erinnern, die Sie bereits verwendet haben. Das ist beabsichtigt. Ein Großteil der Syntax ist für Benutzer von Perl, Python und Java (unter anderem) vertraut, sodass das Erlernen von Ruby ein Kinderspiel ist, wenn Sie diese bereits kennen.

Dieses Dokument enthält zwei Hauptabschnitte. Der erste ist eine schnelle Zusammenfassung dessen, was Sie erwarten können, wenn Sie von Sprache X zu Ruby wechseln. Der zweite Abschnitt befasst sich mit den wichtigsten Sprachmerkmalen und wie diese mit dem verglichen werden können, was Sie bereits kennen.

Was zu erwarten ist: Sprache X zu Ruby

Wichtige Sprachmerkmale und einige Stolpersteine

Hier sind einige Hinweise und Tipps zu wichtigen Ruby-Funktionen, die Sie beim Erlernen von Ruby sehen werden.

Iteration

Zwei Ruby-Funktionen, die sich von dem, was Sie vielleicht zuvor gesehen haben, ein wenig unterscheiden und an die man sich erst gewöhnen muss, sind „Blocks“ und Iteratoren. Anstatt über einen Index zu loopen (wie bei C, C++ oder Java vor Version 1.5) oder über eine Liste zu loopen (wie bei Perl’s for (@a) {...} oder Python’s for i in aList: ...), werden Sie in Ruby sehr oft stattdessen sehen

some_list.each do |this_item|
  # We're inside the block.
  # deal with this_item.
end

Weitere Informationen zu each (und seinen Freunden collect, find, inject, sort, usw.) finden Sie unter ri Enumerable (und dann ri Enumerable#some_method).

Alles hat einen Wert

Es gibt keinen Unterschied zwischen einem Ausdruck und einer Anweisung. Alles hat einen Wert, auch wenn dieser Wert nil ist. Das ist möglich

x = 10
y = 11
z = if x < y
      true
    else
      false
    end
z # => true

Symbole sind keine leichten Strings

Viele Ruby-Neulinge kämpfen damit, Symbole zu verstehen und wofür sie verwendet werden können.

Symbole können am besten als Identitäten beschrieben werden. Ein Symbol dreht sich alles um wer es ist, nicht was es ist. Starten Sie irb und sehen Sie den Unterschied

irb(main):001:0> :george.object_id == :george.object_id
=> true
irb(main):002:0> "george".object_id == "george".object_id
=> false
irb(main):003:0>

Die Methode object_id gibt die Identität eines Objekts zurück. Wenn zwei Objekte dieselbe object_id haben, sind sie identisch (verweisen auf dasselbe Objekt im Speicher).

Sobald Sie ein Symbol einmal verwendet haben, verweist jedes Symbol mit denselben Zeichen auf dasselbe Objekt im Speicher. Für beliebige zwei Symbole, die dieselben Zeichen darstellen, stimmen die object_ids überein.

Betrachten Sie nun den String („george“). Die object_ids stimmen nicht überein. Das bedeutet, sie verweisen auf zwei verschiedene Objekte im Speicher. Immer wenn Sie einen neuen String verwenden, reserviert Ruby Speicher dafür.

Wenn Sie sich nicht sicher sind, ob Sie ein Symbol oder einen String verwenden sollen, überlegen Sie, was wichtiger ist: die Identität eines Objekts (z. B. ein Hash-Schlüssel) oder der Inhalt (im obigen Beispiel „george“).

Alles ist ein Objekt

„Alles ist ein Objekt“ ist keine Übertreibung. Sogar Klassen und ganze Zahlen sind Objekte, und Sie können mit ihnen dasselbe tun wie mit jedem anderen Objekt

# This is the same as
# class MyClass
#   attr_accessor :instance_var
# end
MyClass = Class.new do
  attr_accessor :instance_var
end

Variable Konstanten

Konstanten sind nicht wirklich konstant. Wenn Sie eine bereits initialisierte Konstante ändern, wird eine Warnung ausgelöst, aber Ihr Programm wird nicht angehalten. Das soll jedoch nicht heißen, dass Sie Konstanten neu definieren sollten.

Namenskonventionen

Ruby erzwingt einige Namenskonventionen. Wenn ein Bezeichner mit einem Großbuchstaben beginnt, ist es eine Konstante. Wenn er mit einem Dollarzeichen ($) beginnt, ist es eine globale Variable. Wenn er mit @ beginnt, ist es eine Instanzvariable. Wenn er mit @@ beginnt, ist es eine Klassenvariable.

Methodennamen dürfen jedoch mit Großbuchstaben beginnen. Dies kann zu Verwirrung führen, wie das folgende Beispiel zeigt

Constant = 10
def Constant
  11
end

Nun ist Constant 10, aber Constant() ist 11.

Schlüsselwortargumente

Wie in Python können seit Ruby 2.0 Methoden mit Schlüsselwortargumenten definiert werden

def deliver(from: "A", to: nil, via: "mail")
  "Sending from #{from} to #{to} via #{via}."
end

deliver(to: "B")
# => "Sending from A to B via mail."
deliver(via: "Pony Express", from: "B", to: "A")
# => "Sending from B to A via Pony Express."

Die universelle Wahrheit

In Ruby werden alle außer nil und false als wahr betrachtet. In C, Python und vielen anderen Sprachen gelten 0 und möglicherweise andere Werte wie leere Listen als falsch. Werfen Sie einen Blick auf den folgenden Python-Code (das Beispiel gilt auch für andere Sprachen)

# in Python
if 0:
  print("0 is true")
else:
  print("0 is false")

Dies gibt „0 ist false“ aus. Das Äquivalent in Ruby

# in Ruby
if 0
  puts "0 is true"
else
  puts "0 is false"
end

Gibt „0 is true“ aus.

Zugriffsmodifikatoren gelten bis zum Ende des Gültigkeitsbereichs

Im folgenden Ruby-Code,

class MyClass
  private
  def a_method; true; end
  def another_method; false; end
end

Erwarten Sie vielleicht, dass another_method öffentlich ist. Nicht so. Der Zugriffsmodifikator private gilt bis zum Ende des Gültigkeitsbereichs oder bis ein anderer Zugriffsmodifikator auftaucht, je nachdem, was zuerst eintritt. Standardmäßig sind Methoden öffentlich.

class MyClass
  # Now a_method is public
  def a_method; true; end

  private

  # another_method is private
  def another_method; false; end
end

public, private und protected sind eigentlich Methoden, daher können sie Parameter haben. Wenn Sie ihnen ein Symbol übergeben, wird die Sichtbarkeit dieser Methode geändert.

Methodenzugriff

In Java bedeutet public, dass eine Methode für jeden zugänglich ist. protected bedeutet, dass Instanzen der Klasse, Instanzen von abgeleiteten Klassen und Instanzen von Klassen im selben Paket darauf zugreifen können, aber sonst niemand, und private bedeutet, dass niemand außer den Instanzen der Klasse auf die Methode zugreifen kann.

Ruby unterscheidet sich leicht. public ist natürlich öffentlich. private bedeutet, dass die Methode(n) nur zugänglich sind, wenn sie ohne expliziten Empfänger aufgerufen werden können. Nur self darf der Empfänger eines privaten Methodenaufrufs sein.

protected ist diejenige, auf die man achten sollte. Eine geschützte Methode kann von Instanzen einer Klasse oder abgeleiteten Klasse aufgerufen werden, aber auch mit einer anderen Instanz als Empfänger. Hier ist ein Beispiel (angepasst aus The Ruby Language FAQ)

class Test
  # public by default
  def identifier
    99
  end

  def ==(other)
    identifier == other.identifier
  end
end

t1 = Test.new  # => #<Test:0x34ab50>
t2 = Test.new  # => #<Test:0x342784>
t1 == t2       # => true

# now make `identifier' protected; it still works
# because protected allows `other' as receiver

class Test
  protected :identifier
end

t1 == t2  # => true

# now make `identifier' private

class Test
  private :identifier
end

t1 == t2
# NoMethodError: private method `identifier' called for #<Test:0x342784>

Klassen sind offen

Ruby-Klassen sind offen. Sie können sie öffnen, ergänzen und jederzeit ändern. Sogar Kernklassen wie Integer oder Object, die Elternklasse aller Objekte. Ruby on Rails definiert eine Reihe von Methoden für den Umgang mit Zeit auf Integer. Achten Sie

class Integer
  def hours
    self * 3600 # number of seconds in an hour
  end
  alias hour hours
end

# 14 hours from 00:00 January 1st
# (aka when you finally wake up ;)
Time.mktime(2006, 01, 01) + 14.hours # => Sun Jan 01 14:00:00

Lustige Methodennamen

In Ruby dürfen Methoden mit Fragezeichen oder Ausrufezeichen enden. Per Konvention enden Methoden, die Fragen beantworten, mit Fragezeichen (z. B. Array#empty?, die true zurückgibt, wenn der Empfänger leer ist). Potenziell „gefährliche“ Methoden enden per Konvention mit Ausrufezeichen (z. B. Methoden, die self oder die Argumente ändern, exit! usw.). Nicht alle Methoden, die ihre Argumente ändern, enden jedoch mit Ausrufezeichen. Array#replace ersetzt den Inhalt eines Arrays durch den Inhalt eines anderen Arrays. Es ergibt nicht viel Sinn, eine Methode wie diese zu haben, die self nicht verändert.

Singleton-Methoden

Singleton-Methoden sind pro-Objekt-Methoden. Sie sind nur auf dem Objekt verfügbar, auf dem Sie sie definiert haben.

class Car
  def inspect
    "Cheap car"
  end
end

porsche = Car.new
porsche.inspect # => Cheap car
def porsche.inspect
  "Expensive car"
end

porsche.inspect # => Expensive car

# Other objects are not affected
other_car = Car.new
other_car.inspect # => Cheap car

Fehlende Methoden

Ruby gibt nicht auf, wenn es eine Methode nicht finden kann, die auf eine bestimmte Nachricht reagiert. Es ruft die Methode method_missing mit dem Namen der nicht gefundenen Methode und den Argumenten auf. Standardmäßig löst method_missing eine NameError-Ausnahme aus, aber Sie können sie neu definieren, um sie besser an Ihre Anwendung anzupassen, und viele Bibliotheken tun dies. Hier ist ein Beispiel

# id is the name of the method called, the * syntax collects
# all the arguments in an array named 'arguments'
def method_missing(id, *arguments)
  puts "Method #{id} was called, but not found. It has " +
       "these arguments: #{arguments.join(", ")}"
end

__ :a, :b, 10
# => Method __ was called, but not found. It has these
# arguments: a, b, 10

Der obige Code gibt nur die Details des Aufrufs aus, aber Sie können die Nachricht nach Belieben behandeln.

Nachrichtenübermittlung, keine Funktionsaufrufe

Ein Methodenaufruf ist eigentlich eine Nachricht an ein anderes Objekt

# This
1 + 2
# Is the same as this ...
1.+(2)
# Which is the same as this:
1.send "+", 2

Blöcke sind Objekte, sie wissen es nur noch nicht

Blöcke (eigentlich Closures) werden von der Standardbibliothek intensiv genutzt. Um einen Block aufzurufen, können Sie entweder yield verwenden oder ihn zu einem Proc machen, indem Sie ein spezielles Argument an die Argumentliste anhängen, so:

def block(&the_block)
  # Inside here, the_block is the block passed to the method
  the_block # return the block
end
adder = block { |a, b| a + b }
# adder is now a Proc object
adder.class # => Proc

Sie können Blöcke auch außerhalb von Methodenaufrufen erstellen, indem Sie Proc.new mit einem Block aufrufen oder die Methode lambda aufrufen.

Ähnlich sind auch Methoden Objekte im Entstehen

method(:puts).call "puts is an object!"
# => puts is an object!

Operatoren sind syntaktischer Zucker

Die meisten Operatoren in Ruby sind nur syntaktischer Zucker (mit einigen Vorrangregeln) für Methodenaufrufe. Sie können beispielsweise die +-Methode von Integer überschreiben

class Integer
  # You can, but please don't do this
  def +(other)
    self - other
  end
end

Sie benötigen nicht C++’s operator+, usw.

Sie können sogar Array-ähnlichen Zugriff haben, wenn Sie die Methoden [] und []= definieren. Um die unären + und - (denken Sie an +1 und -2) zu definieren, müssen Sie die Methoden +@ bzw. -@ definieren. Die folgenden Operatoren sind jedoch kein syntaktischer Zucker. Sie sind keine Methoden und können nicht neu definiert werden.

=, .., ..., not, &&, and, ||, or, ::

Außerdem sind +=, *= usw. nur Abkürzungen für var = var + other_var, var = var * other_var, usw. und können daher nicht neu definiert werden.

Mehr erfahren

Wenn Sie bereit für mehr Ruby-Wissen sind, besuchen Sie unseren Abschnitt Dokumentation.