moar documentation

I'm on a train!
master v0.0.1
Jordan Orelli 10 years ago
parent d4068eff9f
commit 9a966a37f5

@ -57,10 +57,36 @@ func (d *Doc) MarshalMoon() ([]byte, error) {
return buf.Bytes(), nil
}
// retrieve a value from the moon document and assign it to provided
// destination. dest must be a pointer. path may be a path to the desired
// field, e.g., people/1/name would get the name field of the second element of
// the people list.
// Get reads a value from the Moon document at a given path, assigning the
// value to supplied destination pointer. The argument dest MUST be a pointer,
// otherwise Get will be unable to overwrite the value that it (should) point
// to.
//
// path may represent either a top-level key or a path to a value found within the document.
//
// Let's say you have a simple document that contains just a few values:
// name: jordan
// city: brooklyn
// Calling Get("name", &name) would read the value in the document at the
// "name" key and assign it to the location pointed at by the *string name.
//
// Let's take a more complex example:
// @webserver: {
// host: www.example.com
// port: 80
// }
//
// @mailserver: {
// host: mail.example.com
// port: 25
// }
//
// servers: [@webserver @mailserver]
//
// Calling Get("servers/1/host", &host) would look a list at the key "servers",
// retrieve the item at index 1 in that list, and then read the field named
// "host" within that item, assigning the value to the address pointed to by
// the *string named host
func (d *Doc) Get(path string, dest interface{}) error {
if d.items == nil {
return fmt.Errorf("no item found at path %s (doc is empty)", path)
@ -85,9 +111,10 @@ func (d *Doc) Get(path string, dest interface{}) error {
return nil
}
// Fill takes the raw values from the moon document and assigns them to the
// struct pointed at by dest. Dest must be a struct pointer; any other type
// for dest will result in an error.
// Fill takes the raw values from the Moon document and assigns them to the
// fields of the struct pointed at by dest. Dest must be a struct pointer; any
// other type for dest will result in an error. Please see the Parse
// documentation for a description of how the values will be filled.
func (d *Doc) Fill(dest interface{}) error {
dt := reflect.TypeOf(dest)
if dt.Kind() != reflect.Ptr {

@ -1,6 +1,7 @@
package moon
import (
"fmt"
"testing"
)
@ -55,3 +56,87 @@ func TestFill(t *testing.T) {
}
}
func ExampleDoc_Fill() {
input := `
name: jordan
age: 29
`
var config struct {
Name string `name: "name"`
Age int `name: "age"`
City string `name: "city" default: "Brooklyn"`
}
doc, err := ReadString(input)
if err != nil {
fmt.Printf("error reading input: %s", err)
return
}
if err := doc.Fill(&config); err != nil {
fmt.Printf("error filling config value: %s", err)
return
}
fmt.Println(config)
// Output: {jordan 29 Brooklyn}
}
func ExampleDoc_Get_one() {
input := `
name: jordan
age: 29
`
doc, err := ReadString(input)
if err != nil {
fmt.Printf("error reading input: %s", err)
return
}
var name string
if err := doc.Get("name", &name); err != nil {
fmt.Printf("error filling config value: %s", err)
return
}
fmt.Println(name)
// Output: jordan
}
func ExampleDoc_Get_two() {
input := `
@todd: {
name: todd
age: 38
}
@sean: {
name: sean
age: 34
}
@jordan: {
name: jordan
age: 29
}
brothers: [@todd @sean @jordan]
`
doc, err := ReadString(input)
if err != nil {
fmt.Printf("error reading input: %s", err)
return
}
var name string
if err := doc.Get("brothers/1/name", &name); err != nil {
fmt.Printf("error filling config value: %s", err)
return
}
fmt.Println(name)
// Output: sean
}

@ -21,7 +21,9 @@ var nodes = map[tokenType]func(p *parser) node{
t_duration: func(p *parser) node { return new(durationNode) },
}
var DefaultPath = "./config.moon"
// Static path for configuration file. By default, a call to Parse wil look for
// a file at the path specified by Path.
var Path = ""
func bail(status int, t string, args ...interface{}) {
if status == 0 {
@ -32,7 +34,55 @@ func bail(status int, t string, args ...interface{}) {
os.Exit(status)
}
func Parse(dest interface{}) {
// Parse reads in all command line arguments in addition to parsing the Moon
// configuration file found at moon.Path. If moon.Path is not set, Parse does
// not automatically look for a configuration file.
//
// The command-line options as well as the values found in the Moon document
// will be used to fill the destination object pointed to by the dest argument.
// Clients may use struct tags to dictate how values will be filled in the
// destination struct. Within the struct tag, the client may provide a moon
// document describing how the value is to be parsed.
//
// The following tags are currently recognized:
//
// - name: the value's name inside of the moon document
// - help: help text to be printed when running your program as "program help"
// - required: whether or not the specified field is required.
// - default: default value for the given field
// - short: single character to be used as a command-line flag
// - long: a string of characters to be used as a command-line option
//
// Here's an example of a struct definition that is annotated to inform the
// Moon parser how to fill the struct with values from a Moon document.
//
// var config struct {
// Host string `
// name: host
// help: target host with whom we will connect
// required: true
// short: h
// long: host
// `
//
// Port int `
// name: port
// help: port to dial on the target host
// default: 12345
// short: p
// long: port
// `
// }
//
// .. and here's how we would parse our command-line arguments and config file
// at path "./config.moon" to fill the struct at config:
//
// moon.Path = "./config"
// moon.Parse(&config)
//
// Any value provied as a command-line argument will override the value
// supplied by the config file at "./config"
func Parse(dest interface{}) *Doc {
cliArgs, err := parseArgs(os.Args, dest)
if err != nil {
bail(1, "unable to parse cli args: %s", err)
@ -40,15 +90,19 @@ func Parse(dest interface{}) {
var doc *Doc
f, err := os.Open(DefaultPath)
if err == nil {
defer f.Close()
d, err := Read(f)
if err != nil {
bail(1, "unable to parse moon config file at path %s: %s", DefaultPath, err)
if Path != "" {
f, err := os.Open(Path)
if err == nil {
defer f.Close()
d, err := Read(f)
if err != nil {
bail(1, "unable to parse moon config file at path %s: %s", Path, err)
}
doc = d
}
doc = d
} else {
}
if doc == nil {
doc = &Doc{items: make(map[string]interface{})}
}
@ -59,6 +113,7 @@ func Parse(dest interface{}) {
if err := doc.Fill(dest); err != nil {
bail(1, "unable to fill moon config values: %s", err)
}
return doc
}
// Reads a moon document from a given io.Reader. The io.Reader is advanced to

@ -9,7 +9,6 @@ import (
type req struct {
name string // name as it appears in moon config file. Defaults to the field name.
cliName string // name as it appears on the command line
help string // text given in help documentation
required bool // whether or not the option must be configured
d_fault interface{} // default value for when the option is missing
@ -55,10 +54,9 @@ func field2req(field reflect.StructField) (*req, error) {
}
req := req{
name: field.Name,
cliName: field.Name,
t: field.Type,
long: field.Name,
name: field.Name,
t: field.Type,
long: field.Name,
}
// this is called by Fill, so we have to do Fill's work by hand, otherwise
@ -66,7 +64,6 @@ func field2req(field reflect.StructField) (*req, error) {
errors := map[string]error{
"name": doc.Get("name", &req.name),
"cli_name": doc.Get("cli_name", &req.cliName),
"help": doc.Get("help", &req.help),
"required": doc.Get("required", &req.required),
"default": doc.Get("default", &req.d_fault),

Loading…
Cancel
Save