Une idée qui me vient à l'esprit est de créer une tâche SBT SourceGenerator
tâche.
Qui lira un fichier d'entrée JSON, CSV, XML ou autre, qui fait partie de votre projet et créera un fichier scala.
// ----- Fichier : project/VendorsGenerator.scala -----
import sbt.Keys._
import sbt._
/**
* Une tâche SBT qui génère un fichier source géré avec toutes les inspections Scalastyle.
*/
objet VendorsGenerator {
// Pour la démonstration, j'utiliserai cette simple List[String] pour générer le code,
// vous pouvez changer le code pour lire un fichier à la place.
// Ou peut-être que cela suffira.
final val vendors: List[String] =
List(
"Chrysler",
"Toyota",
...
"Inconnu"
)
val generatorTask = Def.task {
// Faites la liste 'tipos', qui contient tous les vendeurs.
val tipos =
vendors
.map(nomVendeur => s"${nomVendeur}Vendor")
.mkString("val tipos: List[Vendeur] = List(", ",", ")")
// Faites un objet de cas pour chaque vendeur.
val vendorObjects = vendors.map { nomVendeur =>
s"""objet cas ${nomVendeur}Vendor étend Vendeur { override val value final : String = "${nomVendeur}" }"""
}
// Remplissez le modèle de code.
val code =
List(
List(
"forfait vendeurs",
"trait scellé Vendeur étend Produit avec Serializable {",
"déf value: String",
"override final def toString: String = value",
"}",
"objet Vendeurs étend (String => Option[Vendeur]) {"
),
vendorObjects,
List(
tipos,
"valeur finale privée de la carte fromStringMap: Map[String, Vendeur] = tipos.map(v => v.toString -> v).toMap",
"remplacer la méthode appliquer(clé: String): Option[Vendeur] = fromStringMap.get(key.toLowerCase)",
"}"
)
).flatten
// Enregistrez le nouveau fichier dans le répertoire des sources gérées.
val vendorsFile = (sourceManaged dans Compile).valeur / "vendeurs.scala"
IO.writeLines(vendorsFile, code)
Seq(vendorsFile)
}
}
Maintenant, vous pouvez activer votre générateur de sources.
Cette tâche sera exécutée à chaque fois, avant l'étape de compilation.
// ----- Fichier : build.sbt -----
sourceGenerators dans Compile += VendorsGenerator.generatorTask.taskValue
Veuillez noter que je suggère ceci, car je l'ai déjà fait et parce que je n'ai aucune expérience en macros ou en méta-programmation.
Aussi, notez que cet exemple repose beaucoup sur les Strings, ce qui rend le code un peu difficile à comprendre et à maintenir.
Au fait, je n'ai pas utilisé enumeratum
, mais en y jetant un coup d'œil rapide, cela semble être la meilleure solution à ce problème
Éditer
J'ai mon code prêt à lire un fichier HOCON et générer le code correspondant. Ma question maintenant est où placer le fichier scala dans le répertoire du projet et où les fichiers seront-ils générés. Je suis un peu confus car il semble qu'il y ait plusieurs étapes 1) compiler mon générateur scala, 2) exécuter le générateur et 3) compiler et construire le projet. Est-ce correct ?
Votre générateur ne fait pas partie du code de votre projet, mais plutôt de votre méta-projet (Je sais que cela semble confus, vous pouvez lire ceci pour comprendre) - en tant que tel, vous placez le générateur à l'intérieur du dossier project
au niveau de la racine (le même dossier où se trouve le fichier build.properties
pour spécifier la version sbt).
Si votre générateur a besoin de dépendances (je suis sûr que c'est le cas pour lire le HOCON) vous les placez dans un fichier build.sbt
à l'intérieur de ce dossier project
.
Si vous prévoyez d'ajouter des tests unitaires au générateur, vous pouvez créer un projet scala entier à l'intérieur du méta-projet (vous pouvez jeter un œil au dossier
project d'un projet open source (Oui, oui, je sais, encore une fois la confusion) sur lequel je travaille pour référence) - Ma suggestion personnelle est qu'au lieu de tester le générateur lui-même, vous devriez tester le fichier généré à la place, ou les deux, encore mieux.
Le fichier généré sera automatiquement placé dans le dossier src_managed
(qui se trouve à l'intérieur de target
et est donc ignoré par votre gestion de version du code source).
Le chemin à l'intérieur de celui-ci est juste par ordre, car tout à l'intérieur du dossier src_managed
est inclus par défaut lors de la compilation.
val vendorsFile = (sourceManaged dans Compile).valeur / "vendeurs.scala" // Chemin vers le fichier à écrire.`
Pour accéder aux valeurs définies dans le fichier généré dans votre code source, il vous suffit d'ajouter un package au fichier généré et d'importer les valeurs de ce package dans votre code (comme avec n'importe quel fichier normal).
Vous n'avez pas besoin de vous soucier de quoi que ce soit en rapport avec l'ordre de compilation, si vous incluez votre générateur de source dans votre fichier build.sbt
, SBT s'occupera automatiquement de tout.
sourceGenerators in Compile += VendorsGenerator.generatorTask.taskValue // Activer le générateur de sources.
SBT relancera votre générateur à chaque fois qu'il aura besoin de compiler.
"Au fait, je reçois "non trouvé : objet sbt" sur les imports".
Si le projet est à l'intérieur de l'espace méta-projet, il trouvera le package sbt par défaut, ne vous inquiétez pas à ce sujet.