Created
September 22, 2013 09:59
-
-
Save ndrew/6658542 to your computer and use it in GitHub Desktop.
stagosaurus: iteration_1 — configuration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package stagosaurus | |
import ( | |
"errors" | |
) | |
// Constructor for Config. If defaults are not needed just do new(Config) | |
// | |
func NewConfig(defaults *Config) *Config { | |
cfg := new(Config) | |
cfg.Defaults = defaults | |
return cfg | |
} | |
// Generic configuration class | |
// | |
type Config struct { | |
Defaults *Config | |
cfg map[interface{}]interface{} | |
} | |
// Get value by key from configuration dictionary | |
// | |
// Note: as go doesn't support polymorphic funcs, I do trick with variable arguments to have | |
// fluent interface for providing optional overriding default value | |
func (this *Config) Get(key ...interface{}) interface{} { | |
if this.cfg == nil { | |
this.cfg = make(map[interface{}]interface{}) | |
} | |
switch { | |
case 0 == len(key): | |
return this | |
case 1 == len(key): | |
if nil != this.Defaults && this != this.Defaults && nil == this.cfg[key[0]] { | |
return this.Defaults.Get(key[0]) | |
} | |
return this.cfg[key[0]] | |
case 2 == len(key): | |
v := this.cfg[key[0]] | |
if nil == v { | |
return key[1] | |
} | |
return v | |
default: | |
panic("Incorrect number of params passed to Config.Get") | |
} | |
} | |
// Sets value for key in configuration dictionary | |
// | |
func (this *Config) Set(key interface{}, value interface{}) interface{} { | |
if this.cfg == nil { | |
this.cfg = make(map[interface{}]interface{}) | |
} | |
this.cfg[key] = value | |
return this.Get(key) | |
} | |
// Configuration validation via key => validity-predicate map. Returns result of validation and list of failed keys, if any | |
// | |
func (this *Config) Validate(predicateMap map[interface{}]func(interface{}) bool) (bool, []interface{}) { | |
res := true | |
noErrors := [0]interface{}{} | |
errors := noErrors[:] | |
for k, predicate := range predicateMap { | |
if valid := predicate(this.Get(k)); false == valid { | |
res = false | |
errors = append(errors, k) | |
} | |
} | |
return res, errors | |
} | |
// convenience getters | |
// string | |
// | |
func (this *Config) String(key ...interface{}) (string, error) { | |
v := this.Get(key...) | |
if nil != v { | |
if ret, ok := v.(string); ok { | |
return ret, nil | |
} | |
} | |
iv := "" // identity value | |
return iv, errors.New("Value in config is not String") | |
} | |
// func (v Value) Bytes() []byte | |
func (this *Config) Bool(key ...interface{}) (bool, error) { | |
v := this.Get(key...) | |
if nil != v { | |
if ret, ok := v.(bool); ok { | |
return ret, nil | |
} | |
} | |
iv := false // identity value | |
return iv, errors.New("Value in config is not Bool") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// example.go | |
package main | |
import ( | |
site "./.." // substite this to "github.com/ndrew/stagosaurus" for production use | |
"errors" | |
"strings" | |
) | |
func main() { | |
// provide defaults for configuration | |
defaults := new(site.Config) | |
defaults.Set("greeting", "Hello") | |
config := site.NewConfig(defaults) | |
config.Set("blogName", "Stagosaurus") | |
// create 'blog' example | |
blog, err := New(config) | |
if err != nil { | |
// config validation: ["greeting"=>"Hello"] won't pass, so we fix config and recreate blog | |
config.Set("greeting", "Rhoaarrrr") | |
blog, err = New(config) | |
} | |
// we don't have any posts yet, so will be rendering data from config | |
if err = blog.HelloWorld(); err == nil { | |
println("\nCongratulation, you did it!") | |
} else { | |
println(err.Error()) | |
} | |
} | |
func New(config *site.Config) (*Blog, error) { // blog constructor | |
// validate the config key 'greeting' | |
validator := map[interface{}](func(interface{}) bool){ | |
"greeting": func(v interface{}) bool { | |
return v != nil && v != "Hello" | |
}, | |
} | |
if original, _ := config.Validate(validator); !original { | |
return nil, errors.New("You've provided too trivial value! Try again, be original!") | |
} | |
blog := new(Blog) | |
blog.Config = config | |
return blog, nil | |
} | |
// your future blog generator | |
type Blog struct { | |
Config *site.Config | |
} | |
// test validation and 'publish' hello-world | |
// | |
func (this *Blog) HelloWorld() error { | |
output := "" | |
// cast to type manually | |
hello := this.Config.Get("greeting") | |
if hello != nil { | |
if helloStr, ok := hello.(string); ok { | |
output = helloStr | |
} else { | |
return errors.New("hello is not a string!") | |
} | |
} | |
// or use shorthand for common types: string/bool/int | |
world, err := this.Config.String("blogName") | |
if err != nil { | |
return err | |
} | |
output = output + " " + world + "!" | |
return this.Render(output) | |
} | |
// rendering text in a fancy border | |
// | |
func (this *Blog) Render(output string) error { | |
filler := strings.Repeat("═", len(output)) | |
println("╔═" + filler + "═╗") | |
println("╟ " + output + " ╢") | |
println("╚═" + filler + "═╝") | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment