#irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil...">
1 | 2 | 3 | 4

Ruby in zwanzig Minuten

Lassen Sie uns jetzt ein Greeter-Objekt erstellen und es verwenden

irb(main):035:0> greeter = Greeter.new("Pat")
=> #<Greeter:0x16cac @name="Pat">
irb(main):036:0> greeter.say_hi
Hi Pat!
=> nil
irb(main):037:0> greeter.say_bye
Bye Pat, come back soon.
=> nil

Sobald das greeter-Objekt erstellt ist, merkt es sich, dass der Name Pat ist. Hmm, was ist, wenn wir direkt auf den Namen zugreifen wollen?

irb(main):038:0> greeter.@name
SyntaxError: (irb):38: syntax error, unexpected tIVAR, expecting '('

Nein, das geht nicht.

Unter der Haut des Objekts

Instanzvariablen sind im Objekt versteckt. Sie sind nicht besonders gut versteckt, Sie sehen sie, wenn Sie das Objekt inspizieren, und es gibt andere Möglichkeiten, auf sie zuzugreifen, aber Ruby verwendet den guten objektorientierten Ansatz, Daten irgendwie versteckt zu halten.

Welche Methoden gibt es also für Greeter-Objekte?

irb(main):039:0> Greeter.instance_methods
=> [:say_hi, :say_bye, :instance_of?, :public_send,
    :instance_variable_get, :instance_variable_set,
    :instance_variable_defined?, :remove_instance_variable,
    :private_methods, :kind_of?, :instance_variables, :tap,
    :is_a?, :extend, :define_singleton_method, :to_enum,
    :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?,
    :freeze, :inspect, :display, :send, :object_id, :to_s,
    :method, :public_method, :singleton_method, :nil?, :hash,
    :class, :singleton_class, :clone, :dup, :itself, :taint,
    :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods,
    :protected_methods, :frozen?, :public_methods, :singleton_methods,
    :!, :==, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]

Wow. Das sind viele Methoden. Wir haben nur zwei Methoden definiert. Was ist hier los? Nun, das sind **alle** Methoden für Greeter-Objekte, eine vollständige Liste, einschließlich derer, die von Elterklassen definiert wurden. Wenn wir nur Methoden auflisten wollen, die für Greeter definiert sind, können wir angeben, dass wir keine von Elterklassen definierten Methoden einschließen wollen, indem wir den Parameter false übergeben.

irb(main):040:0> Greeter.instance_methods(false)
=> [:say_hi, :say_bye]

Ah, das ist besser. Lassen Sie uns also sehen, auf welche Methoden unser Greeter-Objekt reagiert

irb(main):041:0> greeter.respond_to?("name")
=> false
irb(main):042:0> greeter.respond_to?("say_hi")
=> true
irb(main):043:0> greeter.respond_to?("to_s")
=> true

Es kennt also say_hi und to_s (was bedeutet, etwas in einen String umwandeln, eine Methode, die standardmäßig für jedes Objekt definiert ist), aber es kennt name nicht.

Klassen ändern – Es ist nie zu spät

Aber was, wenn Sie den Namen sehen oder ändern möchten? Ruby bietet eine einfache Möglichkeit, auf die Variablen eines Objekts zuzugreifen.

irb(main):044:0> class Greeter
irb(main):045:1>   attr_accessor :name
irb(main):046:1> end
=> [:name, :name=]

In Ruby können Sie eine Klasse erneut öffnen und sie ändern. Die Änderungen werden in allen neuen Objekten, die Sie erstellen, vorhanden sein und sogar in bestehenden Objekten dieser Klasse verfügbar sein. Lassen Sie uns also ein neues Objekt erstellen und mit seiner @name-Eigenschaft spielen.

irb(main):047:0> greeter = Greeter.new("Andy")
=> #<Greeter:0x3c9b0 @name="Andy">
irb(main):048:0> greeter.respond_to?("name")
=> true
irb(main):049:0> greeter.respond_to?("name=")
=> true
irb(main):050:0> greeter.say_hi
Hi Andy!
=> nil
irb(main):051:0> greeter.name="Betty"
=> "Betty"
irb(main):052:0> greeter
=> #<Greeter:0x3c9b0 @name="Betty">
irb(main):053:0> greeter.name
=> "Betty"
irb(main):054:0> greeter.say_hi
Hi Betty!
=> nil

Die Verwendung von attr_accessor hat zwei neue Methoden für uns definiert: name zum Abrufen des Werts und name= zum Festlegen.

Begrüßen von allem und jedem, MegaGreeter vernachlässigt niemanden!

Dieser Greeter ist aber nicht besonders interessant, er kann nur eine Person nach der anderen betreuen. Was ist, wenn wir eine Art MegaGreeter hätten, der entweder die Welt, eine Person oder eine ganze Liste von Personen begrüßen könnte?

Schreiben wir diesmal in eine Datei, anstatt direkt im interaktiven Ruby-Interpreter IRB.

Um IRB zu beenden, geben Sie "quit", "exit" ein oder drücken Sie einfach Control-D.

#!/usr/bin/env ruby

class MegaGreeter
  attr_accessor :names

  # Create the object
  def initialize(names = "World")
    @names = names
  end

  # Say hi to everybody
  def say_hi
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")
      # @names is a list of some kind, iterate!
      @names.each do |name|
        puts "Hello #{name}!"
      end
    else
      puts "Hello #{@names}!"
    end
  end

  # Say bye to everybody
  def say_bye
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("join")
      # Join the list elements with commas
      puts "Goodbye #{@names.join(", ")}.  Come back soon!"
    else
      puts "Goodbye #{@names}.  Come back soon!"
    end
  end
end


if __FILE__ == $0
  mg = MegaGreeter.new
  mg.say_hi
  mg.say_bye

  # Change name to be "Zeke"
  mg.names = "Zeke"
  mg.say_hi
  mg.say_bye

  # Change the name to an array of names
  mg.names = ["Albert", "Brenda", "Charles",
              "Dave", "Engelbert"]
  mg.say_hi
  mg.say_bye

  # Change to nil
  mg.names = nil
  mg.say_hi
  mg.say_bye
end

Speichern Sie diese Datei als "ri20min.rb" und führen Sie sie als "ruby ri20min.rb" aus. Die Ausgabe sollte lauten:

Hello World!
Goodbye World.  Come back soon!
Hello Zeke!
Goodbye Zeke.  Come back soon!
Hello Albert!
Hello Brenda!
Hello Charles!
Hello Dave!
Hello Engelbert!
Goodbye Albert, Brenda, Charles, Dave, Engelbert.  Come
back soon!
...
...

In diesem letzten Beispiel gibt es viele neue Dinge, die wir genauer betrachten können.