Einstieg in Crystal: Kompilierte Sprache mit modernen Konzepten

Seite 3: Erzeugen einer simplen Webapplikation mit einem Framework

Inhaltsverzeichnis

Crystal bringt ebenfalls eine Paket- und Projektverwaltung mit, die sich analog zu pip und Co. verhält. Eine kleine Webapplikation auf Basis des Frameworks Athena soll die Besonderheiten der Paketverwaltung von Crystal näher beleuchten.

Der im Crystal-Compiler enthaltene Projektverwalter erzeugt anhand der nachfolgenden Kommandos eine neue Projektstruktur:

tamhan@tamhan-VirtualBox:~$ mkdir crystalspace
tamhan@tamhan-VirtualBox:~$ cd crystalspace/
tamhan@tamhan-VirtualBox:~/crystalspace$ crystal init app tamswebapp
    . . .
    create  /home/tamhan/crystalspace/tamswebapp/shard.yml
    . . .
tamhan@tamhan-VirtualBox:~/crystalspace$ cd tamswebapp/
tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ 

Der Aufruf crystal init app generiert ein neues Unterverzeichnis im aktuellen Arbeitsverzeichnis der Shell, in dem alle zum Projekt gehörenden Dateien unterkommen. Neben einer Readme- und verschiedenen Steuerungsdateien für das Git-Versionskontrollsystem ist vor allem die Datei /home/tamhan/crystalspace/tamswebapp/shard.yml relevant. Sie legt fest, welche der als Shard (englisch für (Ton-)Scherbe) bezeichneten Bibliotheken das vorliegende Projekt zum erfolgreichen Kompilieren benötigt.

Die Weiterentwicklung von Crystal-Modulen erfolgt im Allgemeinen auf GitHub. Das Athena-Modul und dessen jeweils aktuelle Version finden sich allerdings auf einer eigenen Website.

Sobald die Datei shard.yml zur Bearbeitung freigegeben ist, lässt sich die Athena-Bibliothek hinzufügen. Nach dem Öffnen der Konfigurationsdatei präsentiert sie unter anderem den targets-Block. Er legt fest, welches Deliverable aus dem vorliegenden Crystal-Projekt zu generieren ist. Das eigentliche Einbinden des Athena-Frameworks erfolgt dann durch das Einfügen eines dependencies-Blocks:

targets:
  tamswebapp:
    main: src/tamswebapp.cr

dependencies:
  athena:  
    github: athena-framework/framework
    version: ~> 0.17.0
    
crystal: 1.6.2

Während der version: ~> 0.17.0-Operator die zu verwendende Version festlegt, ist die in Crystal enthaltene Paketverwaltung in der Lage, speziell formatierte GitHub-Repositories zu durchforsten und die in ihnen enthaltenen Inhalte direkt in den Kompilierungsprozess einzubinden.

Anders als Gradle lädt Crystal in der Regel nicht bei jedem Build-Prozess alle Bibliotheksressourcen herunter und vermeidet so unnötige Latenzen. Kehrseite dieser Optimierung ist jedoch, dass Entwicklerinnen und Entwickler das Herunterladen und Aktualisieren der diversen Dependencies gegebenenfalls manuell anstoßen müssen:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ shards install
Resolving dependencies
. . .

Das Kommandozeilenwerkzeug shards ist in der Lage, die in den verschiedenen Bibliotheken enthaltenen Unterabhängigkeiten zu berücksichtigen (s. Abb. 6). Das Tool ist jedoch nicht Teil der Hauptdistribution von Crystal.

Shards komplettiert die Arbeitsumgebung (Abb. 6).

Die Umsetzung der Webapplikation erfolgt bei Nutzung des Athena-Frameworks im MVC-Pattern (Model, View, Controller). Crystal bringt darüber hinaus eine durchaus vollständige Implementierung der diversen objektorientierten Designparadigmata mit. Damit sind auch komplexe Web-Anwendungen umsetzbar. Wichtig für den Anfang ist, dass der Einsprungspunkt in die Webapplikation immer in Form einer Athena:: Framework:: Controller-Klasse vorliegen muss. Die Applikationslogik muss von dieser "erben" und der neu erzeugten Klasse – wie etwa aus JavaScript bekannt – die verschiedenen, für die Verarbeitung der eingehenden URLs notwendigen Event Handler einschreiben.

Zum Ableiten muss das Programm allerdings einen Einsprungspunkt erhalten. Eine Analyse der Build-Steuerungsdatei informiert darüber, dass der Hauptteil des Codes in der folgenden Datei zu finden ist:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp/src$ code tamswebapp.cr

In Visual Studio Code präsentiert sich nach dem Öffnen der folgende Korpus:

# TODO: Write documentation for `Tamswebapp`
module Tamswebapp
  VERSION = "0.1.0"

  # TODO: Put your code here
end

Module übernehmen in Crystal dabei die Rolle der unter anderem aus C# bekannten Namespaces. Um den in anderen Programmiersprachen erforderlichen Einsprungspunkt (Methode Main) zu simulieren, lässt sich mit dem folgenden Code im Modul-Korpus ein aktiver Aufruf unterbringen:

require "athena"
# TODO: Write documentation for `Tamswebapp`
module Tamswebapp
  VERSION = "0.1.0"
  # TODO: Put your code here
  p "Hallo Welt"
end

Neben einer Begrüßungsmeldung taucht in der Ausgabe auch erstmals das Statement Require auf. Es legt fest, dass das vorliegende Produkt von der Athena-Bibliothek abhängig ist.

Im nächsten Schritt lässt sich der Code mit Crystal Run kompilieren:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ crystal run src/tamswebapp.cr 
"Hallo Welt"

Ungewöhnlich ist am vorliegenden Code lediglich, dass der Aufruf nicht unter Verwendung der Spezifikationsdatei, sondern der Codedatei erfolgt. Die Ausgabe des Begrüßungsstrings informiert darüber, dass das Ausführen des Einsprungspunkts erfolgreich verlief.

Wie bei JavaScript gilt auch im Fall von Crystal, dass auf modulglobaler Ebene angelegter Code im Rahmen der Initialisierung beziehungsweise der Bereitstellung des Moduls zur Ausführung gelangt.

Das Erzeugen der Zugriffslogik beginnt mit:

module Tamswebapp
  VERSION = "0.1.0"
  class ExampleController < ATH::Controller
    @[ARTA::Get("/")]
    def index : String
      "Hello World"
    end
  end

Das Symbol < informiert Crystal über die anzulegende Vererbungsbeziehung.

Für das Festlegen der Route kommt eine Action zum Einsatz, die wie im vorangehenden Listing gezeigt angelegt wird. Der mit def beginnende Teil deklariert eine gewöhnliche Methode, die den Namen index aufweist, keine Parameter entgegennimmt und den Aufrufer mit einem String ausstattet. Interessant ist hier die Art des Zurückgebens des Strings: Crystal nutzt kein Statement wie return, sondern es reicht aus, den Rückgabewert allein in einer Zeile stehen zu lassen.

Anstelle des vorher als Instrumentierung dienenden Print-Aufrufs ist nun ATH.run aufzurufen. Die Methode durchsucht die gesamte Solution nach als Route markierten Methoden und bringt diese danach selbsttätig zur Ausführung:

  ATH.run
end

Nach dem Speichern der .cr-Datei lässt sich die Kompilierung anstoßen:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ crystal run src/tamswebapp.cr 
/usr/bin/ld: cannot find -lpcre2-8 (this usually means you need to install the development package for libpcre2-8): No such file or directory

crystal run lässt sich an dieser Stelle etwas Zeit, um anschließend die gezeigte Fehlermeldung zu retournieren.

Ursache dafür ist, dass Frameworks in der Welt von Crystal eigene Dependencies zu weiteren Binärdateien deklarieren dürfen. Leider löst shard diese im Rahmen der Bereitstellung des Moduls nicht selbsttätig auf. Ubuntu informiert an dieser Stelle allerdings durch Ausgabe einer Fehlermeldung darüber, dass zum Ausführen des Programms die PCRE-Bibliothek erforderlich ist.

Dieses Problem lässt sich durch Einsatz von apt-get beheben:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ sudo apt-get install libpcre2-dev

Nach dem erfolgreichen Herunterladen der Bibliothek lässt sich ein erneuter Ausführungsversuch wagen:

tamhan@tamhan-VirtualBox:~/crystalspace/tamswebapp$ crystal run src/tamswebapp.cr 
2022-11-08T04:17:14.363019Z   INFO - athena.framework: Server has started and 
is listening at http://0.0.0.0:3000

Da Ports kleiner als 1024 unter Linux privilegiert sind, entscheidet sich das Athena-Framework eigenständig für einen anderen Port.

Beim Testen der Applikation erweist sich der Browser Firefox mitunter als etwas widerspenstig, weil er bei Eingabe von localhost:3000/ automatisch den HTTPS-Präfix angefügt (s. Abb. 7).

Athena unterstützt HTTPS nicht (Abb. 7).

Nach dem Editieren der Adresszeile ergibt sich das in Abbildung 8 gezeigte Ergebnis. Es informiert darüber, dass Firefox die Informationen erfolgreich aus der Applikation entnehmen konnte.

Die Athena-Framework-Applikation liefert die geforderten Informationen aus (Abb. 8).