-
Notifications
You must be signed in to change notification settings - Fork 121
/
range.kt
102 lines (93 loc) · 3.57 KB
/
range.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package com.github.ajalt.clikt.parameters.types
import com.github.ajalt.clikt.parameters.arguments.ProcessedArgument
import com.github.ajalt.clikt.parameters.options.OptionWithValues
private inline fun <T : Comparable<T>> checkRange(it: T, min: T? = null, max: T? = null,
clamp: Boolean, fail: (String) -> Unit): T {
require(min == null || max == null || min < max) { "min must be less than max" }
if (clamp) {
if (min != null && it < min) return min
if (max != null && it > max) return max
} else if (min != null && it < min || max != null && it > max) {
fail(when {
min == null -> "$it is larger than the maximum valid value of $max."
max == null -> "$it is smaller than the minimum valid value of $min."
else -> "$it is not in the valid range of $min to $max."
})
}
return it
}
// Arguments
/**
* Restrict the argument values to fit into a range.
*
* By default, conversion fails if the value is outside the range, but if [clamp] is true, the value will be
* silently clamped to fit in the range.
*
* This must be called before transforms like `pair`, `default`, or `multiple`, since it checks each
* individual value.
*
* ### Example:
*
* ```
* argument().int().restrictTo(max=10, clamp=true).default(10)
* ```
*/
fun <T : Comparable<T>> ProcessedArgument<T, T>.restrictTo(min: T? = null, max: T? = null, clamp: Boolean = false)
: ProcessedArgument<T, T> {
return copy({ checkRange(transformValue(it), min, max, clamp) { m -> fail(m) } }, transformAll, transformValidator)
}
/**
* Restrict the argument values to fit into a range.
*
* By default, conversion fails if the value is outside the range, but if [clamp] is true, the value will be
* silently clamped to fit in the range.
*
* This must be called before transforms like `pair`, `default`, or `multiple`, since it checks each
* individual value.
*
* ### Example:
*
* ```
* argument().int().restrictTo(1..10, clamp=true).default(10)
* ```
*/
fun <T : Comparable<T>> ProcessedArgument<T, T>.restrictTo(range: ClosedRange<T>, clamp: Boolean = false): ProcessedArgument<T, T> {
return restrictTo(range.start, range.endInclusive, clamp)
}
// Options
/**
* Restrict the option values to fit into a range.
*
* By default, conversion fails if the value is outside the range, but if [clamp] is true, the value will be
* silently clamped to fit in the range.
*
* This must be called before transforms like `pair`, `default`, or `multiple`, since it checks each
* individual value.
*
* ### Example:
*
* ```
* option().int().restrictTo(max=10, clamp=true).default(10)
* ```
*/
fun <T : Comparable<T>> OptionWithValues<T?, T, T>.restrictTo(min: T? = null, max: T? = null, clamp: Boolean = false): OptionWithValues<T?, T, T> {
return copy({ checkRange(transformValue(it), min, max, clamp) { m -> fail(m) } }, transformEach, transformAll, transformValidator)
}
/**
* Restrict the option values to fit into a range.
*
* By default, conversion fails if the value is outside the range, but if [clamp] is true, the value will be
* silently clamped to fit in the range.
*
* This must be called before transforms like `pair`, `default`, or `multiple`, since it checks each
* individual value.
*
* ### Example:
*
* ```
* option().int().restrictTo(1..10, clamp=true).default(10)
* ```
*/
fun <T : Comparable<T>> OptionWithValues<T?, T, T>.restrictTo(range: ClosedRange<T>, clamp: Boolean = false): OptionWithValues<T?, T, T> {
return restrictTo(range.start, range.endInclusive, clamp)
}