EMZETT.
Login

Kurz: 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.

Teil des Kurses Ruby

Kapitel 7 von 12 im Kurs Ruby. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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::PI

Ausgabe:

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.sprich

Ausgabe:

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.peek

Ausgabe:

[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 <=>) und Enumerable (mit each) liefern viele Methoden gratis
  • Enumerator und lazy für unendliche Folgen

Übungsaufgabe

Baue eine Klasse Playlist, die Enumerable einbindet und eine Methode gesamtdauer anbietet.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Klassen und Objekte

Weiter: Fehlerbehandlung, Dateien und JSON

Alle Kapitel: Ruby im Überblick