Compare commits
No commits in common. "4e99dd5057b159276c29fab7cf7af199f7345844" and "5d60552f123821fa17565c698bc93dae58df1042" have entirely different histories.
4e99dd5057
...
5d60552f12
|
@ -67,8 +67,6 @@ func CompileTo(target *Pattern, uncompiledPattern string) error {
|
||||||
|
|
||||||
target.init(defaultFieldTagName)
|
target.init(defaultFieldTagName)
|
||||||
|
|
||||||
target.template = uncompiledPattern
|
|
||||||
|
|
||||||
s := uncompiledPattern
|
s := uncompiledPattern
|
||||||
for {
|
for {
|
||||||
index := strings.IndexRune(s, '{')
|
index := strings.IndexRune(s, '{')
|
||||||
|
|
44
doc.go
44
doc.go
|
@ -1,43 +1,12 @@
|
||||||
/*
|
/*
|
||||||
Package pathmatch provides pattern matching for path templates.
|
Package pathmatch provides pattern matching for paths.
|
||||||
|
|
||||||
A path template might look something like the following:
|
For example, a path could be a file system path, or a path could be a path from a URL (such as an HTTP or HTTPS based URL).
|
||||||
|
|
||||||
/v1/users/{user_id}
|
The matches can be loaded into variables (when using pathmatch.Find());
|
||||||
|
or can be loaded into a struct (when using pathmatch.Pattern.FindAndLoad()).
|
||||||
|
|
||||||
Or:
|
Example Usage:
|
||||||
|
|
||||||
/account={account_name}/user={user_name}/message={message_hash}
|
|
||||||
|
|
||||||
Or:
|
|
||||||
|
|
||||||
/backup/{folder_name}/
|
|
||||||
Or:
|
|
||||||
|
|
||||||
/v2/select/{fields}/from/{table_name}/where/{filters}
|
|
||||||
|
|
||||||
This path template could be a file system path, or a path could be a path from a URL (such as an HTTP or HTTPS based URL).
|
|
||||||
|
|
||||||
To compile one of these pattern templates, you would do something such as:
|
|
||||||
|
|
||||||
var template string = "/v1/users/{user_id}/messages/{message_id}"
|
|
||||||
|
|
||||||
var pattern pathmatch.Pattern
|
|
||||||
|
|
||||||
err := pathmatch.CompileTo(&pattern, template)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stdout, "ERROR: %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
(In addition to the pathmatch.CompileTo() func, there is also the pathmatch.Compile(), and
|
|
||||||
pathmatch.MustCompile(). But pathmatch.CompileTo() is recommended over the other 2 options
|
|
||||||
for most cases.)
|
|
||||||
|
|
||||||
One you have the compiled pattern, you would either use pathmatch.Match(), pathmatch.Find(),
|
|
||||||
or pathmatch.FindAndLoad() depending on what you were trying to accomplish.
|
|
||||||
|
|
||||||
Example Usage
|
|
||||||
|
|
||||||
var pattern pathmatch.Pattern
|
var pattern pathmatch.Pattern
|
||||||
|
|
||||||
|
@ -66,7 +35,7 @@ Example Usage
|
||||||
fmt.Printf("user_id = %q \n", userId) // user_id = "bMM_kJFMEV"
|
fmt.Printf("user_id = %q \n", userId) // user_id = "bMM_kJFMEV"
|
||||||
fmt.Printf("vehicle_id = %q \n", vehicleId) // vehicle_id = "o_bcU.RZGK"
|
fmt.Printf("vehicle_id = %q \n", vehicleId) // vehicle_id = "o_bcU.RZGK"
|
||||||
|
|
||||||
Alternate Example Usage
|
Alternate Example Usage:
|
||||||
|
|
||||||
var pattern pathmatch.Pattern
|
var pattern pathmatch.Pattern
|
||||||
|
|
||||||
|
@ -95,5 +64,6 @@ Alternate Example Usage
|
||||||
|
|
||||||
fmt.Printf("user_id = %q \n", data.UserId) // user_id = "bMM_kJFMEV"
|
fmt.Printf("user_id = %q \n", data.UserId) // user_id = "bMM_kJFMEV"
|
||||||
fmt.Printf("vehicle_id = %q \n", data.VehicleId) // vehicle_id = "o_bcU.RZGK"
|
fmt.Printf("vehicle_id = %q \n", data.VehicleId) // vehicle_id = "o_bcU.RZGK"
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package pathmatch
|
package pathmatch
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package pathmatch_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/reiver/go-pathmatch"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExamplePattern_String() {
|
|
||||||
|
|
||||||
var template = "/v1/users/{user_id}"
|
|
||||||
|
|
||||||
var pattern pathmatch.Pattern
|
|
||||||
|
|
||||||
err := pathmatch.CompileTo(&pattern, template)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("pattern: %s", pattern)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// pattern: /v1/users/{user_id}
|
|
||||||
}
|
|
|
@ -32,7 +32,6 @@ import (
|
||||||
// }
|
// }
|
||||||
type Pattern struct {
|
type Pattern struct {
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
template string
|
|
||||||
bits []string
|
bits []string
|
||||||
names []string
|
names []string
|
||||||
namesSet map[string]struct{}
|
namesSet map[string]struct{}
|
||||||
|
|
|
@ -12,11 +12,6 @@ var (
|
||||||
errThisShouldNeverHappen = newInternalError("This should never happen.")
|
errThisShouldNeverHappen = newInternalError("This should never happen.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Find compares ‘path’ against its (compiled) pattern template; if it matches it loads the
|
|
||||||
// matches into ‘args’, and then returns true.
|
|
||||||
//
|
|
||||||
// Find may set some, or all of the items in ‘args’ even if it returns false, and even if it
|
|
||||||
// returns an error.
|
|
||||||
func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) {
|
func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) {
|
||||||
if nil == pattern {
|
if nil == pattern {
|
||||||
return false, errNilReceiver
|
return false, errNilReceiver
|
||||||
|
@ -38,32 +33,23 @@ func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) {
|
||||||
|
|
||||||
s = s[len(bit):]
|
s = s[len(bit):]
|
||||||
case wildcardBit:
|
case wildcardBit:
|
||||||
if "" == s {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
index := strings.IndexRune(s, '/')
|
index := strings.IndexRune(s, '/')
|
||||||
|
if -1 == index {
|
||||||
var value string
|
if err := set(s, argsIndex, args...); nil != err {
|
||||||
switch {
|
return doesNotMatter, err
|
||||||
default:
|
|
||||||
return doesNotMatter, errThisShouldNeverHappen
|
|
||||||
case -1 == index:
|
|
||||||
value = s
|
|
||||||
case 0 <= index:
|
|
||||||
value = s[:index]
|
|
||||||
}
|
}
|
||||||
|
argsIndex++
|
||||||
|
} else if 0 <= index {
|
||||||
|
value := s[:index]
|
||||||
if err := set(value, argsIndex, args...); nil != err {
|
if err := set(value, argsIndex, args...); nil != err {
|
||||||
return doesNotMatter, err
|
return doesNotMatter, err
|
||||||
}
|
}
|
||||||
argsIndex++
|
argsIndex++
|
||||||
s = s[len(value):]
|
s = s[index:]
|
||||||
|
} else {
|
||||||
|
return doesNotMatter, errThisShouldNeverHappen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if "" != s {
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package pathmatch_test
|
package pathmatch
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/reiver/go-pathmatch"
|
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,13 +9,13 @@ import (
|
||||||
func TestFind(t *testing.T) {
|
func TestFind(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct{
|
tests := []struct{
|
||||||
Pattern *pathmatch.Pattern
|
Pattern *Pattern
|
||||||
Args []interface{}
|
Args []interface{}
|
||||||
Path string
|
Path string
|
||||||
ExpectedArgs []string
|
ExpectedArgs []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/{this}/{that}/{these}/{those}"),
|
Pattern: MustCompile("/{this}/{that}/{these}/{those}"),
|
||||||
Args: []interface{}{new(string), new(string), new(string), new(string), },
|
Args: []interface{}{new(string), new(string), new(string), new(string), },
|
||||||
Path: "/apple/banana/cherry/grape",
|
Path: "/apple/banana/cherry/grape",
|
||||||
ExpectedArgs: []string{"apple","banana","cherry","grape"},
|
ExpectedArgs: []string{"apple","banana","cherry","grape"},
|
||||||
|
@ -26,65 +24,65 @@ func TestFind(t *testing.T) {
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}"),
|
Pattern: MustCompile("/user/{sessionKey}"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/"),
|
Pattern: MustCompile("/user/{sessionKey}/"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/DEFAULT"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/DEFAULT"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/DEFAULT/"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/DEFAULT/"),
|
||||||
Args: []interface{}{new(string), },
|
Args: []interface{}{new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
|
||||||
Args: []interface{}{new(string), new(string), },
|
Args: []interface{}{new(string), new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
|
||||||
Args: []interface{}{new(string), new(string), },
|
Args: []interface{}{new(string), new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
|
||||||
Args: []interface{}{new(string), new(string), },
|
Args: []interface{}{new(string), new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
|
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
|
||||||
Args: []interface{}{new(string), new(string), },
|
Args: []interface{}{new(string), new(string), },
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7/",
|
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7/",
|
||||||
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},
|
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},
|
||||||
|
|
|
@ -14,13 +14,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// FindAndLoad compares ‘path’ against its (compiled) pattern template; if it matches
|
func (pattern *Pattern) FindAndLoad(path string, strct interface{}) (bool, error) {
|
||||||
// it loads the matches into ‘dest’, and then returns true.
|
|
||||||
//
|
|
||||||
// ‘dest’ can be a pointer struct, or a pointer to a []string.
|
|
||||||
//
|
|
||||||
// Find may set some, or all of the items or fields in ‘dest’ even if it returns false, and even if it returns an error.
|
|
||||||
func (pattern *Pattern) FindAndLoad(path string, dest interface{}) (bool, error) {
|
|
||||||
if nil == pattern {
|
if nil == pattern {
|
||||||
return false, errNilReceiver
|
return false, errNilReceiver
|
||||||
}
|
}
|
||||||
|
@ -45,59 +39,12 @@ func (pattern *Pattern) FindAndLoad(path string, dest interface{}) (bool, error)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
reflectedValue := reflect.ValueOf(dest)
|
reflectedValue := reflect.ValueOf(strct)
|
||||||
if reflect.Ptr != reflectedValue.Kind() {
|
if reflect.Ptr != reflectedValue.Kind() {
|
||||||
//@TODO: change error
|
|
||||||
return doesNotMatter, errExpectedAPointerToAStruct
|
return doesNotMatter, errExpectedAPointerToAStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
reflectedValueElem := reflectedValue.Elem()
|
reflectedValueElem := reflectedValue.Elem()
|
||||||
switch reflectedValueElem.Kind() {
|
|
||||||
case reflect.Slice:
|
|
||||||
var a []string = make([]string, len(args))
|
|
||||||
for i, arg := range args {
|
|
||||||
a[i] = *(arg.(*string))
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadSlice(dest, a...)
|
|
||||||
case reflect.Struct:
|
|
||||||
return pattern.loadStruct(reflectedValueElem, args)
|
|
||||||
default:
|
|
||||||
//@TODO: change error
|
|
||||||
return doesNotMatter, errExpectedAPointerToAStruct
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadSlice(dest interface{}, matches ...string) (bool, error) {
|
|
||||||
if nil == dest {
|
|
||||||
return false, errNilTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
target, casted := dest.(*[]string)
|
|
||||||
if !casted {
|
|
||||||
//@TODO: CHANGE ERROR! ============================
|
|
||||||
return false, errExpectedAPointerToAStruct
|
|
||||||
}
|
|
||||||
if nil == target {
|
|
||||||
return false, errNilTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
*target = (*target)[:0]
|
|
||||||
for _, match := range matches {
|
|
||||||
*target = append(*target, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pattern *Pattern) loadStruct(reflectedValueElem reflect.Value, args []interface{}) (bool, error) {
|
|
||||||
if nil == pattern {
|
|
||||||
return false, errNilReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
if reflect.Struct != reflectedValueElem.Kind() {
|
|
||||||
return doesNotMatter, errExpectedAPointerToAStruct
|
|
||||||
}
|
|
||||||
|
|
||||||
reflectedValueElemType := reflectedValueElem.Type()
|
reflectedValueElemType := reflectedValueElem.Type()
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,11 @@ package pathmatch
|
||||||
import (
|
import (
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func TestFindAndLoadStrucs(t *testing.T) {
|
func TestFindAndLoad(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct{
|
tests := []struct{
|
||||||
Pattern *Pattern
|
Pattern *Pattern
|
||||||
|
@ -168,73 +166,3 @@ func TestFindAndLoadStrucs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindAndLoadStrings(t *testing.T) {
|
|
||||||
|
|
||||||
tests := []struct{
|
|
||||||
Pattern *Pattern
|
|
||||||
Path string
|
|
||||||
Expected []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Pattern: MustCompile("/user/{sessionKey}"),
|
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
|
|
||||||
Expected: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
|
|
||||||
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
|
|
||||||
Expected: []string{
|
|
||||||
"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
|
|
||||||
"DEFAULT",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: MustCompile("/{this}/{that}/{these}/{those}"),
|
|
||||||
Path: "/apple/banana/cherry/grape",
|
|
||||||
Expected: []string{
|
|
||||||
"apple",
|
|
||||||
"banana",
|
|
||||||
"cherry",
|
|
||||||
"grape",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for testNumber, test := range tests {
|
|
||||||
|
|
||||||
var actual []string
|
|
||||||
|
|
||||||
matched, err := test.Pattern.FindAndLoad(test.Path, &actual)
|
|
||||||
if nil != err {
|
|
||||||
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
|
|
||||||
t.Logf("\tPATTERN: %q", test.Pattern)
|
|
||||||
t.Logf("\tPATH: %q", test.Path)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !matched {
|
|
||||||
t.Errorf("For test #%d, expected a match, but it didn't.", testNumber)
|
|
||||||
t.Logf("\tPATTERN: %q", test.Pattern)
|
|
||||||
t.Logf("\tPATH: %q", test.Path)
|
|
||||||
t.Log("\t--")
|
|
||||||
t.Logf("\tMATCHED: %t", matched)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if expected := test.Expected; !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("For test #%d, did not get what was expected.", testNumber)
|
|
||||||
t.Logf("\tPATTERN: %q", test.Pattern)
|
|
||||||
t.Logf("\tPATH: %q", test.Path)
|
|
||||||
t.Log("\t--")
|
|
||||||
t.Logf("\tEXPECTED: %#v", expected)
|
|
||||||
t.Logf("\tACTUAL: %#v", actual)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package pathmatch
|
|
||||||
|
|
||||||
// Match returns true if ‘path’ matches the compiled pattern, else returns false if it doesn't match.
|
|
||||||
func (receiver *Pattern) Match(path string) (bool, error) {
|
|
||||||
if nil == receiver {
|
|
||||||
return false, errNilReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
//@TODO: Is it a good idea to be dynamically creating this?
|
|
||||||
//@TODO: Also, can the struct fields be put in here directly instead?
|
|
||||||
args := []interface{}{}
|
|
||||||
numNames := len(receiver.MatchNames())
|
|
||||||
for i:=0; i<numNames; i++ {
|
|
||||||
args = append(args, new(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
found, err := receiver.Find(path, args...)
|
|
||||||
if nil != err {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
|
@ -1,366 +0,0 @@
|
||||||
package pathmatch_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/reiver/go-pathmatch"
|
|
||||||
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPatternMatch(t *testing.T) {
|
|
||||||
tests := []struct{
|
|
||||||
Pattern string
|
|
||||||
Path string
|
|
||||||
Expected bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/help",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/help/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/help/me",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/help/me/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/helping",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/helping/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v2/help",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v2/HELP",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/apple",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/banana",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help",
|
|
||||||
Path: "/v1/cherry",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/help/",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/help",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/help/me",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/help/me/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/helping",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/helping/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v2/help/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v2/HELP/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/apple/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/banana/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/help/",
|
|
||||||
Path: "/v1/cherry/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1/user/123",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1/user/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1/user/123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "//v1/user/123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1//user/123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1/user//123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "//v1//user/123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "/v1//user//123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "//v1//user//123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}",
|
|
||||||
Path: "//v1//user//123//",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1/user/123/",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1/user/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1/user/123",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "//v1/user/123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1//user/123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1/user//123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "//v1//user/123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "/v1//user//123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "//v1//user//123/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/",
|
|
||||||
Path: "//v1//user//123//",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
|
|
||||||
Path: "/v1/user/123/contact/e-mail",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
|
|
||||||
Path: "/v1/user/123/contact/e-mail/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
|
|
||||||
Path: "/v2/user/123/contact/e-mail",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
|
|
||||||
Path: "/v2/user/123/contact/e-mail",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
|
|
||||||
Path: "/v1/user/123/contact/e-mail/",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
|
|
||||||
Path: "/v1/user/123/contact/e-mail",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
|
|
||||||
Path: "/v2/user/123/contact/e-mail/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
|
|
||||||
Path: "/v2/user/123/contact/e-mail/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}",
|
|
||||||
Path: "/v1/company/acme",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}",
|
|
||||||
Path: "/v1/company/acme/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}",
|
|
||||||
Path: "/v2/company/acme",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}",
|
|
||||||
Path: "/v1/user/acme",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}",
|
|
||||||
Path: "/v1/COMPANY/acme",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}/",
|
|
||||||
Path: "/v1/company/acme/",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}/",
|
|
||||||
Path: "/v1/company/acme",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}/",
|
|
||||||
Path: "/v2/company/acme/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}/",
|
|
||||||
Path: "/v1/user/acme/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: "/v1/company/{company_name}/",
|
|
||||||
Path: "/v1/COMPANY/acme/",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for testNumber, test := range tests {
|
|
||||||
var pattern pathmatch.Pattern
|
|
||||||
|
|
||||||
if err := pathmatch.CompileTo(&pattern, test.Pattern); nil != err {
|
|
||||||
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
|
|
||||||
t.Errorf("\t: PATTERN: %q", test.Pattern)
|
|
||||||
t.Errorf("\t: PATH: %q", test.Path)
|
|
||||||
t.Errorf("\t: EXPECTED: %t", test.Expected)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
matched, err := pattern.Match(test.Path)
|
|
||||||
if nil != err {
|
|
||||||
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
|
|
||||||
t.Errorf("\t: PATTERN: %q", test.Pattern)
|
|
||||||
t.Errorf("\t: PATH: %q", test.Path)
|
|
||||||
t.Errorf("\t: EXPECTED: %t", test.Expected)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if expected, actual := test.Expected, matched; expected != actual {
|
|
||||||
t.Errorf("For test #%d, expected %t, but actually got %t.", testNumber, expected, actual)
|
|
||||||
t.Errorf("\t: PATTERN: %q", test.Pattern)
|
|
||||||
t.Errorf("\t: PATH: %q", test.Path)
|
|
||||||
t.Errorf("\t: EXPECTED: %t", test.Expected)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package pathmatch
|
|
||||||
|
|
||||||
// String makes pathmatch.Pattern fit the fmt.Stringer interface.
|
|
||||||
//
|
|
||||||
// String returns the (pre-compiled) pattern template.
|
|
||||||
func (receiver Pattern) String() string {
|
|
||||||
return receiver.template
|
|
||||||
}
|
|
Loading…
Reference in New Issue