Property.kt

  1. package com.hexagontk.shell

  2. import com.hexagontk.core.text.parsedClasses
  3. import kotlin.reflect.KClass

  4. /**
  5.  * TODO
  6.  *
  7.  * Properties passed by the command line.
  8.  *
  9.  * @param T
  10.  */
  11. sealed interface Property<T : Any> {
  12.     val type: KClass<T>
  13.     val names: Set<String>
  14.     val description: String?
  15.     val regex: Regex?
  16.     val optional: Boolean
  17.     val multiple: Boolean
  18.     /**
  19.      * TODO To group properties (for listing or alternatives). I.e.:
  20.      *  '|alternate|' for grouping options that are exclusive or 'Common Options' to group in help
  21.      */
  22.     val tag: String?
  23.     val values: List<T>

  24.     fun addValues(value: Property<*>): Property<T>

  25.     fun addValue(value: String): Property<T>

  26.     fun clearValues(): Property<T>

  27.     fun typeText(): String =
  28.         type.simpleName ?: error("Unknown type name")

  29.     fun check(component: String, namePattern: Regex) {
  30.         require(type in parsedClasses) {
  31.             val types = parsedClasses.map(KClass<*>::simpleName)
  32.             "Type ${type.simpleName} not in allowed types: $types"
  33.         }
  34.         require(names.isNotEmpty()) { "$component must have a name" }
  35.         require(names.all { it.matches(namePattern) }) {
  36.             "Names must comply with ${namePattern.pattern} regex: $names"
  37.         }
  38.         require(regex == null || type == String::class) {
  39.             "$component regex can only be used for 'string' type: ${type.simpleName}"
  40.         }

  41.         require(description?.isNotBlank() ?: true) { "$component description can not be blank" }

  42.         if (regex != null)
  43.             values.forEach {
  44.                 require(regex?.matches(it as String) ?: true) {
  45.                     "Value should match the '${regex?.pattern}' regex: $it"
  46.                 }
  47.             }

  48.         if (!multiple)
  49.             require(values.size <= 1) {
  50.                 "$component '${names.first()}' can only have one value: $values"
  51.             }
  52.     }

  53.     companion object {
  54.         val VERSION: Flag = Flag('v', "version", "Show the program's version along its description")
  55.         val HELP: Flag = Flag('h', "help", "Display detailed information on running this command")
  56.     }
  57. }