Skip to content

Commit 7f1a403

Browse files
Updated README and added additional tString Assure func
1 parent 19869ab commit 7f1a403

File tree

4 files changed

+99
-29
lines changed

4 files changed

+99
-29
lines changed

README.md

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,21 @@ import "github.com/andreimerlescu/figtree"
2929
| `figtree.Grow()` | Provides `Mutation` tracking. |
3030
| `figtree.With(figtree.Options{Tracking: true})` | Provides `Mutation` tracking. |
3131

32+
Configurable properties have whats called metagenesis to them, which are types, like `String`, `Bool`, `Float64`, etc.
33+
34+
New properties can be registered before calling Parse() using a metagenesis pattern of `figs.New<Metagenesis>()`, like
35+
`figs.NewString()` or `figs.NewFloat64()`, etc.
36+
37+
Only one validator per property is permitted, and additional WithValidator() calls with duplicate name entries will
38+
record an error in the `Fig.Error` property of the property's "fruit, aka `*Fig{}`".
39+
40+
Figtree keeps a withered copy of `figs.New<Metagenesis>()` property declarations and has an `Options{Tracking: true}`
41+
argument that can be passed into `figs.New()` that enables the `figs.Mutations()` receiver channel to receive anytime
42+
a property value changes, a new `figtree.Mutation`.
43+
44+
Figtree includes 36 different built-in `figs.WithValidator(name, figtree.Assure<Rule>[()])` that can
45+
validate your various Mutageneses without needing to write every validation yourself. For larger or
46+
custom validations, the 2nd argument requires a `func (interface{}) error` signature in order use.
3247

3348
```go
3449
package main
@@ -41,22 +56,59 @@ import (
4156
)
4257

4358
func main() {
44-
figs := figtree.Grow()
45-
figs.NewUnitDuration("minutes", 1, time.Minute, "minutes for timer")
46-
figs.Parse()
47-
48-
go func() {
49-
for mutation := range figs.Mutations() {
50-
log.Printf("Mutation: %s changed from %v to %v", mutation.Property, mutation.Old, mutation.New)
51-
}
52-
}()
53-
54-
timer := time.NewTimer(*figs.UnitDuration("minutes", time.Minute))
55-
<-timer.C
56-
fmt.Println("Timer fired after 1 minute!")
59+
figs := figtree.Grow()
60+
figs.NewUnitDuration("minutes", 1, time.Minute, "minutes for timer")
61+
figs.WithValidator("minutes", figtree.AssureDurationLessThan(time.Hour))
62+
err := figs.Parse()
63+
if err != nil {
64+
log.Fatal(err)
65+
}
66+
log.Println(*figs.UnitDuration("minutes"))
5767
}
5868
```
5969

70+
### Available Validators
71+
72+
| Mutagenesis | `figtree.ValidatorFunc` | Notes |
73+
|-------------|---------------------------|----------------------------------------------------------------------------------|
74+
| tString | AssureStringLength | Ensures a string is a specific length. |
75+
| tString | AssureStringSubstring | Ensures a string contains a specific substring (case-sensitive). |
76+
| tString | AssureStringNotEmpty | Ensures a string is not empty. |
77+
| tString | AssureStringContains | Ensures a string contains a specific substring. |
78+
| tBool | AssureBoolTrue | Ensures a boolean value is true. |
79+
| tBool | AssureBoolFalse | Ensures a boolean value is false. |
80+
| tInt | AssurePositiveInt | Ensures an integer is positive (greater than zero). |
81+
| tInt | AssureNegativeInt | Ensures an integer is negative (less than zero). |
82+
| tInt | AssureIntGreaterThan | Ensures an integer is greater than a specified value (exclusive). |
83+
| tInt | AssureIntLessThan | Ensures an integer is less than a specified value (exclusive). |
84+
| tInt | AssureIntInRange | Ensures an integer is within a specified range (inclusive). |
85+
| tInt64 | AssureInt64GreaterThan | Ensures an int64 is greater than a specified value (exclusive). |
86+
| tInt64 | AssureInt64LessThan | Ensures an int64 is less than a specified value (exclusive). |
87+
| tInt64 | AssurePositiveInt64 | Ensures an int64 is positive (greater than zero). |
88+
| tInt64 | AssureInt64InRange | Ensures an int64 is within a specified range (inclusive). |
89+
| tFloat64 | AssureFloat64Positive | Ensures a float64 is positive (greater than zero). |
90+
| tFloat64 | AssureFloat64InRange | Ensures a float64 is within a specified range (inclusive). |
91+
| tFloat64 | AssureFloat64GreaterThan | Ensures a float64 is greater than a specified value (exclusive). |
92+
| tFloat64 | AssureFloat64LessThan | Ensures a float64 is less than a specified value (exclusive). |
93+
| tFloat64 | AssureFloat64NotNaN | Ensures a float64 is not NaN. |
94+
| tDuration | AssureDurationGreaterThan | Ensures a time.Duration is greater than a specified value (exclusive). |
95+
| tDuration | AssureDurationLessThan | Ensures a time.Duration is less than a specified value (exclusive). |
96+
| tDuration | AssureDurationPositive | Ensures a time.Duration is positive (greater than zero). |
97+
| tDuration | AssureDurationMax | Ensures a time.Duration does not exceed a maximum value. |
98+
| tDuration | AssureDurationMin | Ensures a time.Duration is at least a minimum value. |
99+
| tList | AssureListNotEmpty | Ensures a list (*ListFlag, *[]string, or []string) is not empty. |
100+
| tList | AssureListMinLength | Ensures a list has at least a minimum number of elements. |
101+
| tList | AssureListContains | Ensures a list contains a specific string value. |
102+
| tList | AssureListContainsKey | Ensures a list contains a specific string. |
103+
| tList | AssureListLength | Ensures a list has exactly the specified length. |
104+
| tMap | AssureMapNotEmpty | Ensures a map (*MapFlag, *map[string]string, or map[string]string) is not empty. |
105+
| tMap | AssureMapHasKey | Ensures a map contains a specific key. |
106+
| tMap | AssureMapValueMatches | Ensures a map has a specific key with a matching value. |
107+
| tMap | AssureMapHasKeys | Ensures a map contains all specified keys. |
108+
| tMap | AssureMapLength | Ensures a map has exactly the specified length. |
109+
110+
111+
60112
### Complex Example Usage
61113

62114
```go
@@ -98,12 +150,7 @@ func main() {
98150
return nil
99151
})
100152
figs.NewInt64("maxRetries", 5, "Maximum retry attempts")
101-
figs.WithValidator("maxRetries", func(v interface{}) error {
102-
if val, ok := v.(int64); ok && val < 0 {
103-
return fmt.Errorf("maxRetries cannot be negative")
104-
}
105-
return nil
106-
})
153+
figs.WithValidator("maxRetries", figtree.AssurePositiveInt64)
107154
figs.NewFloat64("threshold", 0.75, "Threshold value")
108155
figs.WithValidator("threshold", func(v interface{}) error {
109156
if val, ok := v.(float64); ok && (val < 0 || val > 1) {
@@ -121,12 +168,7 @@ func main() {
121168
figs.NewBool("debug", false, "Enable debug mode")
122169
figs.NewDuration("timeout", 30*time.Second, "Request timeout")
123170
figs.NewUnitDuration("interval", 1, time.Minute, "Polling interval in minutes")
124-
figs.WithValidator("interval", func(v interface{}) error {
125-
if val, ok := v.(time.Duration); ok && val < time.Minute {
126-
return fmt.Errorf("interval must be at least 1 minute")
127-
}
128-
return nil
129-
})
171+
figs.WithValidator("interval", figtree.AssureDurationGreaterThan(30*time.Second))
130172
figs.NewList("servers", []string{"server1", "server2"}, "List of servers")
131173
figs.NewMap("metadata", map[string]string{"env": "prod", "version": "1.0"}, "Metadata key-value pairs")
132174
// Note: Each New* method registers a flag and initializes withered; WithValidator adds validation logic
@@ -135,7 +177,10 @@ func main() {
135177
configFile := filepath.Join(".", "config.yaml")
136178
if err := figs.ParseFile(configFile); err != nil {
137179
log.Printf("No config file at %s, using defaults: %v", configFile, err)
138-
figs.Parse() // Parse command-line flags and environment variables
180+
err := figs.Parse() // Parse command-line flags and environment variables
181+
if err != nil {
182+
log.Fatal(err)
183+
}
139184
}
140185
// Note: LoadFile tries the specified file, then env vars; Parse handles flags/env if file fails
141186

@@ -167,7 +212,7 @@ func main() {
167212
*figs.String("endpoint"),
168213
*figs.Bool("debug"),
169214
*figs.Duration("timeout"),
170-
*figs.UnitDuration("interval", time.Minute),
215+
*figs.UnitDuration("interval"),
171216
*figs.List("servers"),
172217
*figs.Map("metadata"),
173218
)
@@ -378,6 +423,9 @@ To generate a usage string with information about your configuration variables,
378423
fmt.Println(figtree.New().Usage())
379424
```
380425

426+
On any runtime with `figs.Parse()` or subsequently activated figtree, you can run on your command line `-h` or `-help`
427+
and print the `Usage()` func's output.
428+
381429
The generated usage string includes information about each configuration variable, including its name, default value, description, and the source from which it was set (flag, environment, JSON, YAML, or INI).
382430
383431
## License
@@ -388,4 +436,6 @@ This package is distributed under the MIT License. See the [LICENSE](LICENSE) fi
388436
389437
Contributions to this package are welcome. If you find any issues or have suggestions for improvements, please open an issue or submit a pull request.
390438
391-
Enjoy using the Figtree package in your projects!
439+
Enjoy using the Figtree package in your projects!
440+
441+

assure.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ var AssureStringSubstring = func(sub string) ValidatorFunc {
2121
}
2222
}
2323

24+
// AssureStringLength ensures a string contains a specific substring.
25+
// Returns a ValidatorFunc that checks for the substring (case-sensitive).
26+
var AssureStringLength = func(length int) ValidatorFunc {
27+
return func(value interface{}) error {
28+
if v, ok := value.(string); ok {
29+
if len(v) < length {
30+
return fmt.Errorf("string must be at least %d chars, got %q", length, len(v))
31+
}
32+
return nil
33+
}
34+
return fmt.Errorf("invalid type, expected string, got %T", value)
35+
}
36+
}
37+
2438
// AssureStringNotEmpty ensures a string is not empty.
2539
// Returns an error if the value is an empty string or not a string.
2640
var AssureStringNotEmpty = func(value interface{}) error {

assure_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ func TestSomeAssurances(t *testing.T) {
2222

2323
figs.NewUnitDuration(k4, 33, time.Second, "usage")
2424
figs.WithValidator(k4, AssureDurationMin(30*time.Second))
25-
assert.Nil(t, figs.Parse())
25+
assert.NotNil(t, figs.Parse())
2626
}

validators_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ func TestTree_WithValidator(t *testing.T) {
1414
fig.WithValidator(t.Name(), AssureStringNotEmpty)
1515
assert.NotNil(t, fig.Parse())
1616
})
17+
t.Run("AssureStringLength ", func(t *testing.T) {
18+
fig := With(Options{Germinate: true, Tracking: false})
19+
fig.NewString(t.Name(), "i love yahuah", "usage")
20+
fig.WithValidator(t.Name(), AssureStringLength(13))
21+
assert.Nil(t, fig.Parse())
22+
})
1723
t.Run("AssureStringSubstring", func(t *testing.T) {
1824
fig := With(Options{Germinate: true, Tracking: false})
1925
fig.NewString(t.Name(), "i love yahuah", "usage")

0 commit comments

Comments
 (0)