package toml_test import ( "bytes" "fmt" "log" "net/mail" "time" "github.com/BurntSushi/toml" ) func ExampleEncoder_Encode() { var ( date, _ = time.Parse(time.RFC822, "14 Mar 10 18:00 UTC") buf = new(bytes.Buffer) ) err := toml.NewEncoder(buf).Encode(map[string]interface{}{ "date": date, "counts": []int{1, 1, 2, 3, 5, 8}, "hash": map[string]string{ "key1": "val1", "key2": "val2", }, }) if err != nil { log.Fatal(err) } fmt.Println(buf.String()) // Output: // counts = [1, 1, 2, 3, 5, 8] // date = 2010-03-14T18:00:00Z // // [hash] // key1 = "val1" // key2 = "val2" } func ExampleMetaData_PrimitiveDecode() { tomlBlob := ` ranking = ["Springsteen", "J Geils"] [bands.Springsteen] started = 1973 albums = ["Greetings", "WIESS", "Born to Run", "Darkness"] [bands."J Geils"] started = 1970 albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"] ` type ( band struct { Started int Albums []string } classics struct { Ranking []string Bands map[string]toml.Primitive } ) // Do the initial decode; reflection is delayed on Primitive values. var music classics md, err := toml.Decode(tomlBlob, &music) if err != nil { log.Fatal(err) } // MetaData still includes information on Primitive values. fmt.Printf("Is `bands.Springsteen` defined? %v\n", md.IsDefined("bands", "Springsteen")) // Decode primitive data into Go values. for _, artist := range music.Ranking { // A band is a primitive value, so we need to decode it to get a real // `band` value. primValue := music.Bands[artist] var aBand band err = md.PrimitiveDecode(primValue, &aBand) if err != nil { log.Fatal(err) } fmt.Printf("%s started in %d.\n", artist, aBand.Started) } // Check to see if there were any fields left undecoded. Note that this // won't be empty before decoding the Primitive value! fmt.Printf("Undecoded: %q\n", md.Undecoded()) // Output: // Is `bands.Springsteen` defined? true // Springsteen started in 1973. // J Geils started in 1970. // Undecoded: [] } func ExampleDecode() { tomlBlob := ` # Some comments. [alpha] ip = "10.0.0.1" [alpha.config] Ports = [ 8001, 8002 ] Location = "Toronto" Created = 1987-07-05T05:45:00Z [beta] ip = "10.0.0.2" [beta.config] Ports = [ 9001, 9002 ] Location = "New Jersey" Created = 1887-01-05T05:55:00Z ` type ( serverConfig struct { Ports []int Location string Created time.Time } server struct { IP string `toml:"ip,omitempty"` Config serverConfig `toml:"config"` } servers map[string]server ) var config servers _, err := toml.Decode(tomlBlob, &config) if err != nil { log.Fatal(err) } for _, name := range []string{"alpha", "beta"} { s := config[name] fmt.Printf("Server: %s (ip: %s) in %s created on %s\n", name, s.IP, s.Config.Location, s.Config.Created.Format("2006-01-02")) fmt.Printf("Ports: %v\n", s.Config.Ports) } // Output: // Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05 // Ports: [8001 8002] // Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05 // Ports: [9001 9002] } type address struct{ *mail.Address } func (a *address) UnmarshalText(text []byte) error { var err error a.Address, err = mail.ParseAddress(string(text)) return err } // Example Unmarshaler shows how to decode TOML strings into your own // custom data type. func Example_unmarshaler() { blob := ` contacts = [ "Donald Duck ", "Scrooge McDuck ", ] ` var contacts struct { // Implementation of the address type: // // type address struct{ *mail.Address } // // func (a *address) UnmarshalText(text []byte) error { // var err error // a.Address, err = mail.ParseAddress(string(text)) // return err // } Contacts []address } _, err := toml.Decode(blob, &contacts) if err != nil { log.Fatal(err) } for _, c := range contacts.Contacts { fmt.Printf("%#v\n", c.Address) } // Output: // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"} // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"} } // Example StrictDecoding shows how to detect if there are keys in the TOML // document that weren't decoded into the value given. This is useful for // returning an error to the user if they've included extraneous fields in their // configuration. func Example_strictDecoding() { var blob = ` key1 = "value1" key2 = "value2" key3 = "value3" ` var conf struct { Key1 string Key3 string } md, err := toml.Decode(blob, &conf) if err != nil { log.Fatal(err) } fmt.Printf("Undecoded keys: %q\n", md.Undecoded()) // Output: // Undecoded keys: ["key2"] } type order struct { // NOTE `order.parts` is a private slice of type `part` which is an // interface and may only be loaded from toml using the UnmarshalTOML() // method of the Umarshaler interface. parts parts } type parts []part type part interface { Name() string } type valve struct { Type string ID string Size float32 Rating int } func (v *valve) Name() string { return fmt.Sprintf("VALVE: %s", v.ID) } type pipe struct { Type string ID string Length float32 Diameter int } func (p *pipe) Name() string { return fmt.Sprintf("PIPE: %s", p.ID) } type cable struct { Type string ID string Length int Rating float32 } func (c *cable) Name() string { return fmt.Sprintf("CABLE: %s", c.ID) } func (o *order) UnmarshalTOML(data interface{}) error { // NOTE the example below contains detailed type casting to show how the // 'data' is retrieved. In operational use, a type cast wrapper may be // preferred e.g. // // func AsMap(v interface{}) (map[string]interface{}, error) { // return v.(map[string]interface{}) // } // // resulting in: // d, _ := AsMap(data) // d, _ := data.(map[string]interface{}) parts, _ := d["parts"].([]map[string]interface{}) for _, p := range parts { typ, _ := p["type"].(string) id, _ := p["id"].(string) // detect the type of part and handle each case switch p["type"] { case "valve": size := float32(p["size"].(float64)) rating := int(p["rating"].(int64)) valve := &valve{ Type: typ, ID: id, Size: size, Rating: rating, } o.parts = append(o.parts, valve) case "pipe": length := float32(p["length"].(float64)) diameter := int(p["diameter"].(int64)) pipe := &pipe{ Type: typ, ID: id, Length: length, Diameter: diameter, } o.parts = append(o.parts, pipe) case "cable": length := int(p["length"].(int64)) rating := float32(p["rating"].(float64)) cable := &cable{ Type: typ, ID: id, Length: length, Rating: rating, } o.parts = append(o.parts, cable) } } return nil } // Example UnmarshalTOML shows how to implement a struct type that knows how to // unmarshal itself. The struct must take full responsibility for mapping the // values passed into the struct. The method may be used with interfaces in a // struct in cases where the actual type is not known until the data is // examined. func Example_unmarshalTOML() { blob := ` [[parts]] type = "valve" id = "valve-1" size = 1.2 rating = 4 [[parts]] type = "valve" id = "valve-2" size = 2.1 rating = 5 [[parts]] type = "pipe" id = "pipe-1" length = 2.1 diameter = 12 [[parts]] type = "cable" id = "cable-1" length = 12 rating = 3.1 ` // See example_test.go in the source for the implementation of the order // type. o := &order{} err := toml.Unmarshal([]byte(blob), o) if err != nil { log.Fatal(err) } fmt.Println(len(o.parts)) for _, part := range o.parts { fmt.Println(part.Name()) } }