created 'type checker' using 'plugins'
This commit is contained in:
parent
2afa4759fc
commit
3c9e154162
|
@ -0,0 +1,96 @@
|
||||||
|
package checker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"plugin"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateRegistry creates an empty type registry
|
||||||
|
// if TRUE is given, it will use default Types
|
||||||
|
// see ./default_types.go
|
||||||
|
func CreateRegistry(useDefaultTypes bool) *TypeRegistry {
|
||||||
|
return &TypeRegistry{
|
||||||
|
Types: make([]Type, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a type to the registry; it must be a
|
||||||
|
// valid and existing plugin name without the .so extension
|
||||||
|
func (tr *TypeRegistry) Add(pluginName string) error {
|
||||||
|
|
||||||
|
/* (1) Check plugin name */
|
||||||
|
if len(pluginName) < 1 {
|
||||||
|
return fmt.Errorf("Plugin name must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Check plugin extension */
|
||||||
|
if strings.HasSuffix(pluginName, ".so") {
|
||||||
|
return fmt.Errorf("Plugin name must be provided without extension: '%s'", pluginName[0:len(pluginName)-3])
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Try to load the plugin */
|
||||||
|
p, err := plugin.Open(fmt.Sprintf("%s.so", pluginName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Export wanted properties */
|
||||||
|
matcher, err := p.Lookup("Match")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Missing method 'Match()'; %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checker, err := p.Lookup("Check")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Missing method 'Check()'; %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Cast Match+Check */
|
||||||
|
matcherCast, ok := matcher.(func(string) bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Match() is malformed")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkerCast, ok := checker.(func(interface{}) bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Check() is malformed")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (6) Add type to registry */
|
||||||
|
tr.Types = append(tr.Types, Type{
|
||||||
|
Match: matcherCast,
|
||||||
|
Check: checkerCast,
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks the 'value' which must be of type 'name'
|
||||||
|
func (tr TypeRegistry) Run(name string, value interface{}) bool {
|
||||||
|
|
||||||
|
var T *Type = nil
|
||||||
|
|
||||||
|
/* (1) Iterate to find matching type (take first) */
|
||||||
|
for _, t := range tr.Types {
|
||||||
|
|
||||||
|
// stop if found
|
||||||
|
if t.Match(name) {
|
||||||
|
T = &t
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// else log
|
||||||
|
fmt.Printf("does not match\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Abort if no matching type */
|
||||||
|
if T == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Check */
|
||||||
|
fmt.Printf("Check is %t\n", T.Check(value))
|
||||||
|
return T.Check(value)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package checker
|
||||||
|
|
||||||
|
// Matcher returns whether a type 'name' matches a type
|
||||||
|
type Matcher func(name string) bool
|
||||||
|
|
||||||
|
// Checker returns whether 'value' is valid to this Type
|
||||||
|
// note: it is a pointer because it can be formatted by the checker if matches
|
||||||
|
// to provide indulgent type check if needed
|
||||||
|
type Checker func(value interface{}) bool
|
||||||
|
|
||||||
|
// Type contains all necessary methods
|
||||||
|
// for a type provided by user/developer
|
||||||
|
type Type struct {
|
||||||
|
Match func(string) bool
|
||||||
|
Check func(interface{}) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeRegistry represents a registry containing all available
|
||||||
|
// Type-s to be used by the framework according to the configuration
|
||||||
|
type TypeRegistry struct {
|
||||||
|
Types []Type // registered Type-s
|
||||||
|
}
|
Loading…
Reference in New Issue