File: strings.go

package info (click to toggle)
golang-github-juju-schema 1.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 196 kB
  • sloc: makefile: 5
file content (155 lines) | stat: -rw-r--r-- 4,115 bytes parent folder | download | duplicates (2)
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package schema

import (
	"fmt"
	"net/url"
	"reflect"
	"regexp"
)

// String returns a Checker that accepts a string value only and returns
// it unprocessed.
func String() Checker {
	return stringC{}
}

type stringC struct{}

func (c stringC) Coerce(v interface{}, path []string) (interface{}, error) {
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		return reflect.ValueOf(v).String(), nil
	}
	return nil, error_{"string", v, path}
}

// URL returns a Checker that accepts a string value that must be parseable as a
// URL, and returns a *net.URL.
func URL() Checker {
	return urlC{}
}

type urlC struct{}

func (c urlC) Coerce(v interface{}, path []string) (interface{}, error) {
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		s := reflect.ValueOf(v).String()
		u, err := url.Parse(s)
		if err != nil {
			return nil, error_{"valid url", s, path}
		}
		return u, nil
	}
	return nil, error_{"url string", v, path}
}

// SimpleRegexp returns a checker that accepts a string value that is
// a valid regular expression and returns it unprocessed.
func SimpleRegexp() Checker {
	return sregexpC{}
}

type sregexpC struct{}

func (c sregexpC) Coerce(v interface{}, path []string) (interface{}, error) {
	// XXX The regexp package happens to be extremely simple right now.
	//     Once exp/regexp goes mainstream, we'll have to update this
	//     logic to use a more widely accepted regexp subset.
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		s := reflect.ValueOf(v).String()
		_, err := regexp.Compile(s)
		if err != nil {
			return nil, error_{"valid regexp", s, path}
		}
		return v, nil
	}
	return nil, error_{"regexp string", v, path}
}

// UUID returns a Checker that accepts a string value only and returns
// it unprocessed.
func UUID() Checker {
	return uuidC{}
}

type uuidC struct{}

var uuidregex = regexp.MustCompile(`[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`)

func (c uuidC) Coerce(v interface{}, path []string) (interface{}, error) {
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		uuid := reflect.ValueOf(v).String()
		if uuidregex.MatchString(uuid) {
			return uuid, nil
		}
	}
	return nil, error_{"uuid", v, path}
}

// Stringified returns a checker that accepts a bool/int/float/string
// value and returns its string. Other value types may be supported by
// passing in their checkers.
func Stringified(checkers ...Checker) Checker {
	return stringifiedC{
		checkers: checkers,
	}
}

type stringifiedC struct {
	checkers []Checker
}

func (c stringifiedC) Coerce(v interface{}, path []string) (interface{}, error) {
	if newStr, err := String().Coerce(v, path); err == nil {
		return newStr, nil
	}
	_, err := OneOf(append(c.checkers,
		Bool(),
		Int(),
		Float(),
		String(),
		URL(),
	)...).Coerce(v, path)
	if err != nil {
		return nil, err
	}
	return fmt.Sprintf("%#v", v), nil
}

// NonEmptyString returns a Checker that only accepts non-empty strings. To
// tweak the error message, valueLabel can contain a label of the value being
// checked, e.g. "my special name". If valueLabel is "", "string" will be used
// as a label instead.
//
// Example 1:
// schema.NonEmptyString("widget").Coerce("", nil) will return an error message
// like `expected non-empty widget, got string("")`.
//
// Example 2:
// schema.NonEmptyString("").Coerce("", nil) will return an error message like
// `expected non-empty string, got string("")`.
func NonEmptyString(valueLabel string) Checker {
	if valueLabel == "" {
		valueLabel = "string"
	}
	return nonEmptyStringC{valueLabel}
}

type nonEmptyStringC struct {
	valueLabel string
}

func (c nonEmptyStringC) Coerce(v interface{}, path []string) (interface{}, error) {
	label := fmt.Sprintf("non-empty %s", c.valueLabel)
	invalidError := error_{label, v, path}

	if v == nil || reflect.TypeOf(v).Kind() != reflect.String {
		return nil, invalidError
	}
	if stringValue := reflect.ValueOf(v).String(); stringValue != "" {
		return stringValue, nil
	}
	return nil, invalidError
}