فهرست منبع

Null Objekt eingeführt und Readme aktualisiert

hmt 10 سال پیش
والد
کامیت
079af28e92
4فایلهای تغییر یافته به همراه105 افزوده شده و 3 حذف شده
  1. 18 0
      README.md
  2. 55 2
      lib/schild.rb
  3. 1 1
      lib/schild/version.rb
  4. 31 0
      specs/type_safe_spec.rb

+ 18 - 0
README.md

@@ -4,6 +4,8 @@
 
 Mit `schild` kann man eigenen Skripte schreiben und komfortabel auf die Datenbank zugreifen. Lediglich ein paar Kenntnisse in der Programmiersprache Ruby werden erwartet. Mit Hilfe der [Prawn-Bibliothek](http://prawnpdf.org/) lassen sich sehr schöne und v.a. genau beschriebene PDF-Dokumente erstellen, die ganz ohne grafische Oberfläche auskommen und vollständig programmiert werden.
 
+Auch möglich ist die Nutzung von HTML und CSS zur Erzeugung von Dokumenten. Dazu eigenet sich bespielsweise [slim](http://slim-lang.com).
+
 Um `schild` nutzen zu können muss es zuerst installiert werden:
 
 ```sh
@@ -93,6 +95,22 @@ Alle zur Verfügung stehenden Hilfsmethoden werden in den API-Docs erläutert.
 
 Ziel von `schild` ist es, möglichst viele Daten aus der Datenbank komfortabel zur Verfügung zu stellen.
 
+## Erweiterte Funktionalität
+Der Formulardesigner in Schild ignoriert fehlende Felder. Das kann `schild` auch. Anstelle der in der Datenbank verwendenten Tabellenspalten, die mit Großbuchstaben geschrieben werden, bietet `schild` die Möglichkeit Kleinbuchstaben zu verwenden:
+
+```ruby
+s = Schueler.first
+=> #<Schild::Schueler @values={:ID=>1, ........}>
+
+s.Bemerkungen
+=> nil
+
+s.bemerkungen
+=> ""
+```
+
+Mit Hilfe dieser zusätzlichen Methoden können Fehlermeldungen in den erstellten Berichten komfortabel umgangen werden. Je nach Bedarf kann auf Typensicherheit gesetzt werden oder etwas mehr Freiheit.
+
 ## Das sollte beachtet werden
 `schild` läuft nur unter Ruby. Es ist wahrscheinlich möglich auch über JRuby andere Sprachen zu verwenden, die auf der JVM laufen. Also Java zum Beispiel. Gleiches gilt für Python. Leider nicht getestet.
 

+ 55 - 2
lib/schild.rb

@@ -1,9 +1,48 @@
-require "schild/version"
+require 'schild/version'
 require 'sequel'
 
+# String und Symbol werden um snake_case ergänzt, das die Schild-Tabellen umbenennt
+module CoreExtensions
+  module String
+    def snake_case
+      return downcase if match(/\A[A-Z]+\z/)
+      gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
+        gsub(/([a-z])([A-Z])/, '\1_\2').
+        downcase
+    end
+  end
+
+  module Symbol
+    def snake_case
+      to_s.snake_case
+    end
+  end
+end
+
+# Schild hat teilweise nil in DB-Feldern. SchildTypeSaver gibt entweder einen
+# "Fehlt"-String zurück oder bei strftime das 1899 Datum zurück.
+module SchildTypeSaver
+  Symbol.include CoreExtensions::Symbol
+  String.include CoreExtensions::String
+
+# bei include wird für jede Spalte in der Schild-Tabelle eine Ersatzmethode
+# erstellt, die bei nil ein Null-Objekt erstellt.
+  def self.included(klass)
+    klass.columns.each do  |column|
+      name = column.snake_case
+      define_method(name) { public_send(column) || Null.new("")}
+    end
+  end
+
+  class Null < String
+    def strftime(args)
+      Time.new("1899").strftime(args)
+    end
+  end
+end
+
 # Das Schild Modul, das alle Klassen für die Datenbankanbindung bereitstellt
 module Schild
-
   # ist die Datenbank-Verbindung. Alle Daten können über diese Konstante abgerufen werden
   DB = Sequel.connect(:adapter=>ENV['S_ADAPTER'], :host=>ENV['S_HOST'], :user=>ENV['S_USER'], :password=>ENV['S_PASSWORD'], :database=>ENV['S_DB'])
 
@@ -14,6 +53,8 @@ module Schild
 
   # Stellt die Schüler-Tabelle samt Assoziationen bereit.
   class Schueler < Sequel::Model(:schueler)
+    include SchildTypeSaver
+
     many_to_one :fachklasse, :class => :Fachklasse, :key => :Fachklasse_ID
     one_to_many :abschnitte, :class => :Abschnitt
 
@@ -60,16 +101,22 @@ module Schild
 
   # Dient als Assoziation für Schüler und deren Klassenbezeichnung etc.
   class Fachklasse < Sequel::Model(:eigeneschule_fachklassen)
+    include SchildTypeSaver
+
     one_to_one :schueler
   end
 
   # Assoziation für Lehrer, hauptsächlich für Klassenlehrer
   class Klassenlehrer < Sequel::Model(:k_lehrer)
+    include SchildTypeSaver
+
     one_to_one :abschnitt, :primary_key=>:Kuerzel, :key=>:KlassenLehrer
   end
 
   # Ist die Assoziation, die Halbjahre, sog. Abschnitte zurückgibt.
   class Abschnitt < Sequel::Model(:schuelerlernabschnittsdaten)
+    include SchildTypeSaver
+
     many_to_one :schueler, :class => :Schueler, :key => :Schueler_ID
     one_to_many :noten, :class => :Noten
     many_to_one :klassenlehrer, :class => :Klassenlehrer, :primary_key=>:Kuerzel, :key=>:KlassenLehrer
@@ -137,6 +184,8 @@ module Schild
 
   # Assoziation für Noten
   class Noten < Sequel::Model(:schuelerleistungsdaten)
+    include SchildTypeSaver
+
     many_to_one :abschnitt, :class => :Abschnitt, :key => :Abschnitt_ID
     many_to_one :fach, :class => :Faecher, :key => :Fach_ID
 
@@ -175,11 +224,15 @@ module Schild
 
   # Assoziation für Fächer
   class Faecher < Sequel::Model(:eigeneschule_faecher)
+    include SchildTypeSaver
+
     one_to_one :noten
   end
 
   # Schul-Tabelle mit vereinfachtem Zugriff auf Datenfelder.
   class Schule < Sequel::Model(:eigeneschule)
+    include SchildTypeSaver
+
     # gibt die Schulnummer zurück
     def self.schulnummer
       self.first.SchulNr

+ 1 - 1
lib/schild/version.rb

@@ -1,3 +1,3 @@
 module Schild
-  VERSION = "0.2.1"
+  VERSION = "0.3.0"
 end

+ 31 - 0
specs/type_safe_spec.rb

@@ -0,0 +1,31 @@
+require "#{File.dirname(__FILE__)}/spec_helper"
+
+describe Schueler do
+  describe 'typen sicherheit von objekten' do
+  before do
+    # lade einen Standardschueler
+    @sm = Schueler.where(:Status => 2, :Geloescht => "-", :Gesperrt => "-").first
+  end
+
+    it 'gibt nil zurück, wenn leer' do
+      @sm.Bemerkungen.must_equal nil
+    end
+
+    it 'gibt leeren String zurück, wenn leer und typensicher' do
+      @sm.bemerkungen.must_equal ""
+    end
+
+    it 'gibt Fehler zurück, wenn Methode nicht existiert' do
+      proc {@sm.bemerrrrrrrrrkungen}.must_raise NoMethodError
+    end
+
+    it 'gibt 1899 als Datum zurück, wenn strftime aufgerufen wird' do
+      @sm.geburtsdatum.strftime("%Y").must_equal "1899"
+    end
+
+    it 'gibt nil zurück, wenn Geburtsdatum leer ist' do
+      @sm.Geburtsdatum.must_equal nil
+    end
+  end
+end
+