Module
Ein Modul ist eine Sammlung von Methoden und Konstanten. Es dient als Namensraum und als Mixin (Code in Klassen einmischen). Module lassen sich nicht instanziieren.
module Geometrie
PI = 3.14159
def self.kreisflaeche(r) = PI * r * r
class Kreis
def initialize(r) = @r = r
def flaeche = Geometrie.kreisflaeche(@r)
end
end
puts Geometrie.kreisflaeche(2)
puts Geometrie::Kreis.new(1).flaeche
puts Geometrie::PIAusgabe
12.56636 3.14159 3.14159
Mixins mit include
module Begruessung
def hallo = "Hallo, ich bin #{name}"
end
module Laufend
def laufe = "#{name} läuft"
end
class Mensch
include Begruessung, Laufend
attr_reader :name
def initialize(name) = @name = name
end
m = Mensch.new("Mia")
puts m.hallo, m.laufe
p Mensch.ancestors.first(4), m.is_a?(Begruessung)Ausgabe
Hallo, ich bin Mia Mia läuft [Mensch, Begruessung, Laufend, Object] true
include macht Modulmethoden zu Instanzmethoden, extend zu Klassenmethoden, prepend setzt das Modul vor die Klasse.
module Zaehler
def zaehle = @n = (@n || 0) + 1
end
module Info
def info = "Klasse #{name}"
end
module Laut
def sprich = super.upcase
end
class Robot
include Zaehler
extend Info
prepend Laut
def sprich = "piep"
end
r = Robot.new
r.zaehle
puts r.zaehle, Robot.info, r.sprichAusgabe
2 Klasse Robot PIEP
Comparable und Enumerable
Zwei eingebaute Module machen eigene Klassen mächtig: Wer <=> definiert und Comparable einbindet, bekommt <, >, between?, clamp. Wer each definiert und Enumerable einbindet, bekommt map, select, sort, min, sum, first, include? ... geschenkt:
class Regal
include Enumerable
def initialize(*buecher) = @buecher = buecher
def each(&block)
return to_enum(:each) unless block
@buecher.each(&block)
self
end
end
r = Regal.new("Faust", "Emil", "Momo", "Ronja")
p r.sort, r.map(&:length), r.select { |b| b.length == 4 }, r.min_by(&:length), r.first(2)
p r.include?("Momo"), r.each_slice(2).to_a, r.sum(&:length), r.to_a.last, r.each_with_index.to_a.first
p r.lazy.map(&:upcase).first(2), r.reduce { |a, b| a.length > b.length ? a : b }Ausgabe
["Emil", "Faust", "Momo", "Ronja"] [5, 4, 4, 5] ["Emil", "Momo"] "Emil" ["Faust", "Emil"] true [["Faust", "Emil"], ["Momo", "Ronja"]] 18 "Ronja" ["Faust", 0] ["FAUST", "EMIL"] "Ronja"
Eigene Iteratoren und Enumeratoren
class Fibonacci
include Enumerable
def each
a, b = 0, 1
loop do
yield a
a, b = b, a + b
end
end
end
p Fibonacci.new.lazy.select(&:even?).first(5)
p Fibonacci.new.take(10)
zaehler = Enumerator.new do |y|
n = 0
loop { y << (n += 1) }
end
p zaehler.take(3), zaehler.next, zaehler.next, zaehler.peekAusgabe
[0, 2, 8, 34, 144] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] [1, 2, 3] 1 2 3
Merke
- Module sind Namensräume und Mixins;
include,extend,prepend - Vererbungsreihenfolge siehst du mit
ancestors Comparable(mit<=>) undEnumerable(miteach) liefern viele Methoden gratisEnumeratorundlazyfür unendliche Folgen
Aufgabe
Baue eine Klasse Playlist, die Enumerable einbindet und eine Methode gesamtdauer anbietet.