schild.rb 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. require 'schild/version'
  2. require 'sequel'
  3. # erst Ruby 2.1.0 macht include zu einer public-Methode
  4. if Module.private_method_defined? :include
  5. class Module
  6. public :include
  7. end
  8. end
  9. # String und Symbol werden um snake_case ergänzt, das die Schild-Tabellen umbenennt
  10. module CoreExtensions
  11. module String
  12. def snake_case
  13. return downcase if match(/\A[A-Z]+\z/)
  14. gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
  15. gsub(/([a-z])([A-Z])/, '\1_\2').
  16. downcase
  17. end
  18. end
  19. module Symbol
  20. def snake_case
  21. to_s.snake_case
  22. end
  23. end
  24. end
  25. # Schild hat teilweise nil in DB-Feldern. SchildTypeSaver gibt entweder einen
  26. # "Fehlt"-String zurück oder bei strftime das 1899 Datum zurück.
  27. module SchildTypeSaver
  28. Symbol.include CoreExtensions::Symbol
  29. String.include CoreExtensions::String
  30. # bei include wird für jede Spalte in der Schild-Tabelle eine Ersatzmethode
  31. # erstellt, die bei nil ein Null-Objekt erstellt.
  32. def self.included(klass)
  33. klass.columns.each do |column|
  34. name = column.snake_case
  35. define_method(name) { public_send(column) || create_null_object(klass, column)}
  36. end
  37. end
  38. def create_null_object(klass, column)
  39. k = DB.schema_type_class(klass.db_schema[column][:type])
  40. if k.class == Array
  41. # Sequel stellt :datetime als [Time, DateTime] dar
  42. DateTime.new(1899)
  43. else
  44. # alle anderen types werden als Klasse zurückgegeben
  45. k.new
  46. end
  47. end
  48. end
  49. # Das Schild Modul, das alle Klassen für die Datenbankanbindung bereitstellt
  50. module Schild
  51. # ist die Datenbank-Verbindung. Alle Daten können über diese Konstante abgerufen werden
  52. DB = Sequel.connect(:adapter=>ENV['S_ADAPTER'], :host=>ENV['S_HOST'], :user=>ENV['S_USER'], :password=>ENV['S_PASSWORD'], :database=>ENV['S_DB'])
  53. # Stellt eine Verbindung zu einem Schild-Server her. Sollte nur aufgerufen werden, wenn wechselnde Verbindungen nötig sind.
  54. def self.connect
  55. Sequel.connect(:adapter=>ENV['S_ADAPTER'], :host=>ENV['S_HOST'], :user=>ENV['S_USER'], :password=>ENV['S_PASSWORD'], :database=>ENV['S_DB'])
  56. end
  57. # Stellt die Schüler-Tabelle samt Assoziationen bereit.
  58. class Schueler < Sequel::Model(:schueler)
  59. include SchildTypeSaver
  60. many_to_one :fachklasse, :class => :Fachklasse, :key => :Fachklasse_ID
  61. one_to_many :abschnitte, :class => :Abschnitt
  62. # gibt das z.Zt. aktuelle Halbjahr zurück.
  63. def akt_halbjahr
  64. abschnitte.last
  65. end
  66. # gibt das erste Halbjahr von +jahr+ zurück.
  67. def erstes_halbjahr(jahr)
  68. halbjahr(jahr, 1)
  69. end
  70. # gibt das zweite Halbjahr von +jahr+ zurück.
  71. def zweites_halbjahr(jahr)
  72. halbjahr(jahr, 2)
  73. end
  74. # gibt aus +jahr+ das Halbjahr +1+ oder +2+ zurück.
  75. def halbjahr(jahr, abschnitt)
  76. abschnitte_dataset.where(:jahr => jahr, :abschnitt => abschnitt).first
  77. end
  78. # gibt +Herr+ oder +Frau+ als Anrede für Schüler zurück.
  79. def anrede
  80. if self.Geschlecht == 3
  81. return "Herr"
  82. elsif self.Geschlecht == 4
  83. return "Frau"
  84. end
  85. end
  86. # gibt +true+ zurück, wenn Schüler volljährig.
  87. def volljaehrig?
  88. self.Volljaehrig == "+"
  89. end
  90. # gibt das aktuelle Schuljahr als String im Format "2014/15" zurück.
  91. def schuljahr
  92. jahr = self.AktSchuljahr
  93. "#{jahr}/#{jahr-1999}"
  94. end
  95. end
  96. # Dient als Assoziation für Schüler und deren Klassenbezeichnung etc.
  97. class Fachklasse < Sequel::Model(:eigeneschule_fachklassen)
  98. include SchildTypeSaver
  99. one_to_one :schueler
  100. end
  101. # Assoziation für Lehrer, hauptsächlich für Klassenlehrer
  102. class Klassenlehrer < Sequel::Model(:k_lehrer)
  103. include SchildTypeSaver
  104. one_to_one :abschnitt, :primary_key=>:Kuerzel, :key=>:KlassenLehrer
  105. end
  106. # Ist die Assoziation, die Halbjahre, sog. Abschnitte zurückgibt.
  107. class Abschnitt < Sequel::Model(:schuelerlernabschnittsdaten)
  108. include SchildTypeSaver
  109. many_to_one :schueler, :class => :Schueler, :key => :Schueler_ID
  110. one_to_many :noten, :class => :Noten
  111. many_to_one :klassenlehrer, :class => :Klassenlehrer, :primary_key=>:Kuerzel, :key=>:KlassenLehrer
  112. dataset_module do
  113. # filtert den Datensatz nach Jahr
  114. def jahr(i)
  115. where(:Jahr => i)
  116. end
  117. # filtert den Datensatz nach Halbjahr
  118. def halbjahr(i,j)
  119. jahr(i).where(:Abschnitt => j)
  120. end
  121. # filtert und gibt den Datensatz als Abschnitt des aktuellen Halbjahrs zurück
  122. def akt_halbjahr
  123. halbjahr(Time.new.year-1, 1).first
  124. end
  125. end
  126. # Hilfsmethode für die folgenden Methoden
  127. def faecher_nach_id(id)
  128. noten.sort_by{ |n| n.fach.SortierungS2 }.select{ |n| n.fach.Fachgruppe_ID == id && n.AufZeugnis == '+' }
  129. end
  130. # wählt alle berufsübergreifenden Fächer des gewählten Schülers in angegeben Halbjahr.
  131. def berufsuebergreifend
  132. faecher_nach_id 10
  133. end
  134. # wählt alle berufsbezogenen Fächer des gewählten Schülers in angegeben Halbjahr.
  135. def berufsbezogen
  136. faecher_nach_id 20
  137. end
  138. # wählt alle Fächer des Differenzierungsbreichs des gewählten Schülers in angegeben Halbjahr.
  139. def differenzierungsbereich
  140. faecher_nach_id 30
  141. end
  142. # wählt alle Fächergruppen aus.
  143. def faechergruppen
  144. [berufsuebergreifend, berufsbezogen, differenzierungsbereich]
  145. end
  146. # gibt den Namen des Klassenlehrers mit gekürztem Vornamen.
  147. def v_name_klassenlehrer
  148. v = klassenlehrer.Vorname
  149. n = klassenlehrer.Nachname
  150. "#{v[0]}. #{n}"
  151. end
  152. # gibt "Klassenlehrer" entsprechend Geschlecht zurück
  153. def klassenlehrer_in
  154. klassenlehrer.Geschlecht == "3" ? "Klassenlehrer" : "Klassenlehrerin"
  155. end
  156. # gibt das aktuelle Schuljahr als String im Format "2014/15" zurück.
  157. def schuljahr
  158. jahr = self.Jahr
  159. "#{jahr}/#{jahr-1999}"
  160. end
  161. end
  162. # Assoziation für Noten
  163. class Noten < Sequel::Model(:schuelerleistungsdaten)
  164. include SchildTypeSaver
  165. many_to_one :abschnitt, :class => :Abschnitt, :key => :Abschnitt_ID
  166. many_to_one :fach, :class => :Faecher, :key => :Fach_ID
  167. # Notenbezeichnung als String
  168. def note
  169. case self.NotenKrz
  170. when "1"
  171. "sehr gut"
  172. when "2"
  173. "gut"
  174. when "3"
  175. "befriedigend"
  176. when "4"
  177. "ausreichend"
  178. when "5"
  179. "mangelhaft"
  180. when "6"
  181. "ungenügend"
  182. when 'NB'
  183. "----------"
  184. when 'E3'
  185. "teilgenommen"
  186. end
  187. end
  188. # Bezeichnung des Fachs
  189. def bezeichnung
  190. fach.Bezeichnung
  191. end
  192. # Die Fachgruppen ID des Fachs
  193. def fachgruppe_ID
  194. fach.Fachgruppe_ID
  195. end
  196. end
  197. # Assoziation für Fächer
  198. class Faecher < Sequel::Model(:eigeneschule_faecher)
  199. include SchildTypeSaver
  200. one_to_one :noten
  201. end
  202. # Schul-Tabelle mit vereinfachtem Zugriff auf Datenfelder.
  203. class Schule < Sequel::Model(:eigeneschule)
  204. include SchildTypeSaver
  205. # gibt die Schulnummer zurück
  206. def self.schulnummer
  207. self.first.SchulNr
  208. end
  209. def self.v_name_schulleiter
  210. "#{self.first.SchulleiterVorname[0]}. #{self.first.SchulleiterName}"
  211. end
  212. def self.schulleiter_in
  213. self.first.SchulleiterGeschlecht == 3 ? "Schulleiter" : "Schulleiterin"
  214. end
  215. def self.ort
  216. self.first.Ort
  217. end
  218. end
  219. end