ReLast - Klassik


Ruby


Allgemein

Hello World

def gruessen
  puts "Hallo Welt!"
end

Grundlagen und Prinzipien

  • Alles ist ein Objekt
  • Alles hat einen Wert
  • Alles kann während der Laufzeit verändert werden (auch Konstanten)

Komplexeres Beispiel

Datei "greeter.rb" erzeugen:
#!/usr/bin/env ruby

class MegaGreeter
  attr_accessor :names

  # Erzeuge das Objekt
  def initialize(names = "Welt")
    @names = names
  end

  # Sag Hallo zu allen
  def sag_hallo
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")

      # @names ist eine Liste, durchlaufe sie!
      @names.each do |name|
        puts "Hallo, #{name}!"
      end
    else
      puts "Hallo, #{@names}!"
    end
  end

  # Sag Tschuess zu allen
  def sag_tschuess
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("join")
      # Verbinde die Listenelemente mit einem Komma
      puts "Tschuess, #{@names.join(", ")}, bis bald!"
    else
      puts "Tschuess, #{@names}, bis bald!"
    end
  end

end


if __FILE__ == $0
  mg = MegaGreeter.new
  mg.sag_hallo
  mg.sag_tschuess

  # Aendere den Namen in "Maximilian"
  mg.names = "Maximilian"
  mg.sag_hallo
  mg.sag_tschuess

  # Aendere den Namen in ein Array von Namen
  mg.names = ["Albert", "Bianca", "Carl-Heinz",
    "David", "Engelbert"]
  mg.sag_hallo
  mg.sag_tschuess

  # Aendere in nil
  mg.names = nil
  mg.sag_hallo
  mg.sag_tschuess
end
Aufruf:
ruby greeter.rb
Ergibt:
Hallo, Welt!
Tschuess, Welt, bis bald!
Hallo, Maximilian!
Tschuess, Maximilian, bis bald!
Hallo, Albert!
Hallo, Bianca!
Hallo, Carl-Heinz!
Hallo, David!
Hallo, Engelbert!
Tschuess, Albert, Bianca, Carl-Heinz, David, Engelbert, bis bald!
...
...

Beispiel qruby

#!/usr/bin/ruby
# Author: ReLast
# File: qruby
# Date: Thu May 31 10:00:00 +0200 2012
# Version: 0.1
# Parameter: Dateiname
#
usage_message = "Usage: \n Parameter = Filename opens file or new file \n No Parameter starts irb"

#
# Parameter prüfen
#
# Wenn Parameter mehr als 1: Hilfsmeldung ausgeben
if ARGV.length>1
        puts usage_message
        exit 1
end
# Wenn kein Parameter: irb starten
if ARGV.length==0
        exec "irb"
end
# Wenn Datei schon existiert: merken für später
file_exists = false
if File.exist?(ARGV[0])
        file_exists = true
end
#
# Parameter übernehmen
#
dateiname = ARGV[0]

#
# Versuche Ruby zu finden
#
ruby_binary=`which ruby`


#
# Textkopf mit zwei Leerzeilen am Ende
#
filecontent = <<endmark
#!#{ruby_binary}
# Author: Rene Lauenstein
# File: #{dateiname}
# Date: #{Time.new}
# Version: 0.1
# Parameter:

=begin rdoc
= Klasse/Modul ...
== Parameter
== Variablen
== Methoden
== Ablauf
=end


endmark

#
# Wenn die Datei existiert: öffnen mit Eingabe am Kopfende
#
exec "vi "+dateiname if file_exists
#
# Andernfalls: Datei anlegen und mit Dateikopf füllen
#
datei = File.open(dateiname, "w")
datei.puts filecontent
datei.close
# Datei modifizieren
system("chmod 740 "+dateiname)
#
# Editor starten, Eingabe am
#
exec "vi + "+dateiname
#
# Success exit (sollte hier nie ankommen, da exec das Programm vorher verlässt)
#
exit 0
# ende

Konsolenaufruf

Einzeiler

ruby -e '3.times do puts "Hello" end'

Interaktive konsole

irb
Verlassen der Konsole wahlweise mit:
exit
quit
STRG-D

Skripte

Aufruf:
ruby greeter.rb
Angabe des Interpreters (Unixoid):
#!/usr/bin/env ruby
Unterscheidung Einzelaufruf oder Bibliotheksaufruf:
if __FILE__ == $0

__FILE__ ist die magische Variable, die den Namen der gerade benutzen Datei als Wert hat, während $0 der Name der Datei ist, mit dem das Programm gestartet wurde. Die oben angegebene Anweisung besagt also “Wenn diese Datei die Haupt-Programmdatei ist …”. Dies erlaubt es, eine Datei als Bibliothek (“library”) zu benutzen und in diesem Zusammenhang keinen Code auszuführen, aber wenn die Datei als ausführbare Datei benutzt wird, wird der Code ausgeführt.

Kommentare

#

Variablen

@Instanzvariable
@@Klassenvariable
$globale Variable

Konstanten

Beginnt ein Bezeichner mit einem Großbuchstaben, ist er eine Konstante:
Constant = 10

Symbole

Symbole sind am einfachsten als Identitäten (IDs) zu verstehen. Bei einem Symbol ist wichtig, wer es ist, nicht was es ist. Der Unterschied:

> :george.object_id == :george.object_id
=> true
> "george".object_id == "george".object_id
=> false

Die Methode object_id liefert die ID eines Objektes. Haben zwei Objekte dieselbe object_id, dann sind sie identisch (zeigen auf dasselbe Objekt im Speicher.)

Jedes gleichnamige Symbol zeigt auf dasselbe Objekt im Speicher, und zwar von dem Moment an, in dem das Symbol zum ersten mal benutzt wird. Für zwei Symbole mit denselben Zeichen sind die object_ids gleich.

Bei den Strings hingegen ("george") sind die object_ids nicht gleich. Das bedeutet, dass sie auf zwei verschiedene Objekte im Speicher zeigen. Immer wenn du einen neuen String benutzt, reserviert Ruby dafür Speicher.

Klassen und Objekte

> class Greeter
>   def initialize(name = "Welt")
>     @name = name
>   end
>   def sag_hallo
>     puts "Hallo, #{@name}!"
>   end
>   def sag_tschuess
>     puts "Tschuess, #{@name}, bis bald!"
>   end
> end
=> nil
> g = Greeter.new("ReLast")
=> #<Greeter:0x16cac @name="ReLast">
> gw = Greeter.new
=> #<Greeter:0x16cac @name="Welt">
> g.sag_hallo
=> Hallo, ReLast!
> gw.sag_hallo
=> Hallo, Welt!
> g.sag_tschuess
=> Tschuess, ReLast, bis bald!

Reflection

Abruf von verfügbaren Methoden
> Greeter.instance_methods
=> ["method", "send", "object_id", ...]
> Greeter.instance_methods(false)
=> ["sag_hallo", "sag_tschuess"]
> g.respond_to?("name")
=> false
> g.respond_to?("sag_hallo")
=> true
> g.respond_to?("to_s")
=> true
Wenn das Objekt die Methode besitzt, nutze sie, sonst eben nicht (Duck-Typing. Wenn es aussieht wie eine Ente und quakt, lass es quaken).
  if @names.respond_to?("join")
    # Verbinde die Listenelemente mit Kommata
    puts "Tschuess, #{@names.join(", ")}, bis bald!"
  elsif @names.respond_to?("each")
	# @names ist eine Liste, durchlaufe sie!
	@names.each do |name|
	puts "Hallo, #{name}!"
  end

Dynamik

Klassen können im laufenden Betrieb verändert werden. Alle neuen Objekte haben die neuen Eigenschaften. Bereits bestehende Objekte werden nicht verändert.
> class Greeter
>   attr_accessor :name
> end
=> nil
"attr_accessor" definiert zwei neue Methoden. "g.name" liefert den Inhalt, mit "g.name=" wird der Inhalt gesetzt.
g = Greeter.new("Andreas")
=> #<Greeter:0x3c9b0 @name="Andreas">
> g.respond_to?("name")
=> true
> g.respond_to?("name=")
=> true
> g.sag_hallo
Hallo, Andreas!
=> nil
> g.name="Bettina"
=> "Bettina"
> g
=> #<Greeter:0x3c9b0 @name="Bettina">
> g.name
=> "Bettina"
> g.sag_hallo
Hallo, Bettina!
=> nil

Kontrollstrukturen

Fallunterscheidungen

	if @names.nil?
	  puts "..."
	elsif @names.respond_to?("join")
	  # Verbinde die Listenelemente mit Kommata
	  puts "Tschuess, #{@names.join(", ")}, bis bald!"
	else
	  puts "Tschuess, #{@names}, bis bald!"
	end

Iterationen

	if @names.nil?
	  puts "..."
	elsif @names.respond_to?("each")
	  # @names ist eine Liste, durchlaufe sie!
	  @names.each do |name|
		puts "Hallo, #{name}!"
	  end
	else
	  puts "Hallo, #{@names}!"
	end

Debugging

gem install ruby-debug
Breakpoints setzen mit "debugger".
def create
  @person = Person.new(params[:person])
  debugger
  ...
end
Skript oder Server mit Debug-Option starten
ruby [script|server] --debugger
ruby [script|server] -u
Bei erreichen eines Haltepunktes stoppt die Ausführung, und in der Konsole besteht voller Zugriff auf alle zu dem Zeitpunkt vorhandenen Objekte.
y @objekt
y params
y env
@objekt.name = "neuer_name"
Fortsetzung des Ablaufs mit
continue

Mixins

Bis vor einiger Zeit wurden Mixins als reine Ergänzung zu klassenbasierter Objektorientierung angesehen. Spätestens aber seit Sprachen wie Potion ist klar, dass es sich hierbei um ein eigenes Konzept der Objektorientierung handelt. Dieses wird auch von Ruby unterstützt.

In Ruby sind Mixins Module, die in andere Objekte eingebunden werden. Die Methoden des Beispiels aus den beiden oberen Abschnitten ließe sich zum Beispiel so in Module teilen:

Ruby hat keine Mehrfachvererbung, auch statt dessen können Mixins verwendet werden.

module Gaspedal
  def beschleunigen
    puts "brumm brumm brumm"
  end
end
 
module Bremse
  def bremsen
    puts "quietsch"
  end
end

Ein Auto mit Gaspedal und Bremsen ließe sich dann wie folgt zusammenbauen:

auto = Object.new
auto.extend Gaspedal
auto.extend Bremse

Natürlich lässt sich das mit Klassen kombinieren:

class Auto
  include Gaspedal
end
 
class GutesAuto < Auto
  include Bremse
end

Aber auch mit Prototypen ist es nutzbar:

auto1 = Object.new
auto1.extend Gaspedal
 
auto2 = auto1.clone
auto2.extend Bremse

eRuby

Einbetten von Ruby-Code in HTML. Ähnlich PHP.

Code ausführen:

<% %>

Ausruck auswerten und Ergebnis ausgeben

<%= %>

Ganze Zeile auswerten

%

eRuby ist eine Implementierung in C, währen erb eine Implementierung von eRuby in Ruby darstellt. Diese werden dann von Rails verwendet.

Mehr zur ERB-Syntax

Die hier verwendete Syntax erzeugt nach dem schliesenden "%>"-Tag einen Zeilenvorschub im HTML. Im Browser ist das whitespace und wird ignoriert. Wenn wir diesen Zeilenvorschub vermeiden wollen, können wir den Ruby Code mit "-%>" statt "%>" beenden (Minus-Zeichen ergänzt). Also beispielsweise

Es ist jetzt <%= Time.now -%>. Und so ..

Wenn in der "<%="-Ruby-Ausgabe Zeichenkombinationen vorkommen, die fälschlicherweise als HTML interpretiert werden könnten, können wir das mit html_escape() bzw. kurz h() vermeiden.

Bei xy haben Sie <%= h(params[:xy]) %> eingegeben.

Ruby erweitern

http://home.vrweb.de/~juergen.katins/ruby/buch/ext_ruby.html

Deployment

Capistrano

Copyright © 2024

Datenschutz | Impressum