Option.kt

  1. package com.hexagontk.shell

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

  4. class Option<T : Any>(
  5.     override val type: KClass<T>,
  6.     override val names: Set<String>,
  7.     override val description: String? = null,
  8.     override val regex: Regex? = null,
  9.     override val optional: Boolean = true,
  10.     override val multiple: Boolean = false,
  11.     override val tag: String? = null,
  12.     override val values: List<T> = emptyList(),
  13. ) : Property<T> {

  14.     companion object {
  15.         val optionRegex = "([A-Za-z0-9]|[a-z0-9\\-]{2,})".toRegex()

  16.         private fun namesOf(shortName: Char? = null, name: String? = null): Set<String> =
  17.             setOfNotNull(shortName?.toString(), name)
  18.     }

  19.     constructor(
  20.         type: KClass<T>,
  21.         shortName: Char? = null,
  22.         name: String? = null,
  23.         description: String? = null,
  24.         regex: Regex? = null,
  25.         optional: Boolean = true,
  26.         multiple: Boolean = false,
  27.         tag: String? = null,
  28.     ) : this(type, namesOf(shortName, name), description, regex, optional, multiple, tag)

  29.     constructor(
  30.         type: KClass<T>,
  31.         shortName: Char? = null,
  32.         name: String? = null,
  33.         description: String? = null,
  34.         regex: Regex? = null,
  35.         tag: String? = null,
  36.         values: List<T>,
  37.     ) : this(type, namesOf(shortName, name), description, regex, true, true, tag, values)

  38.     constructor(
  39.         type: KClass<T>,
  40.         shortName: Char? = null,
  41.         name: String? = null,
  42.         description: String? = null,
  43.         regex: Regex? = null,
  44.         tag: String? = null,
  45.         value: T,
  46.     ) : this(type, namesOf(shortName, name), description, regex, true, false, tag, listOf(value))

  47.     init {
  48.         check("Option", optionRegex)
  49.     }

  50.     @Suppress("UNCHECKED_CAST") // Types checked at runtime
  51.     override fun addValues(value: Property<*>): Property<T> =
  52.         Option(
  53.             type,
  54.             names,
  55.             description,
  56.             regex,
  57.             optional,
  58.             multiple,
  59.             tag,
  60.             values + value.values as List<T>
  61.         )

  62.     override fun addValue(value: String): Option<T> =
  63.         value.parseOrNull(type)
  64.             ?.let { Option(type, names, description, regex, optional, multiple, tag, values + it) }
  65.             ?: error("Option '${names.first()}' of type '${typeText()}' can not hold '$value'")

  66.     override fun clearValues(): Option<T> =
  67.         Option(type, names, description, regex, optional, multiple, tag, emptyList())

  68.     // TODO Only used in tests
  69.     fun copy(
  70.         type: KClass<T> = this.type,
  71.         names: Set<String> = this.names,
  72.         description: String? = this.description,
  73.         regex: Regex? = this.regex,
  74.         optional: Boolean = this.optional,
  75.         multiple: Boolean = this.multiple,
  76.         tag: String? = this.tag,
  77.         values: List<T> = this.values,
  78.     ): Option<T> =
  79.         Option(type, names, description, regex, optional, multiple, tag, values)

  80.     // TODO Only used in tests
  81.     override fun equals(other: Any?): Boolean {
  82.         if (this === other) return true
  83.         if (javaClass != other?.javaClass) return false

  84.         other as Option<*>

  85.         if (type != other.type) return false
  86.         if (names != other.names) return false
  87.         if (description != other.description) return false
  88.         if (regex != other.regex) return false
  89.         if (optional != other.optional) return false
  90.         if (multiple != other.multiple) return false
  91.         if (tag != other.tag) return false
  92.         if (values != other.values) return false

  93.         return true
  94.     }

  95.     // TODO Only used in tests
  96.     override fun hashCode(): Int {
  97.         var result = type.hashCode()
  98.         result = 31 * result + names.hashCode()
  99.         result = 31 * result + (description?.hashCode() ?: 0)
  100.         result = 31 * result + (regex?.hashCode() ?: 0)
  101.         result = 31 * result + optional.hashCode()
  102.         result = 31 * result + multiple.hashCode()
  103.         result = 31 * result + (tag?.hashCode() ?: 0)
  104.         result = 31 * result + values.hashCode()
  105.         return result
  106.     }
  107. }