219 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ## TOML parser and encoder for Go with reflection
 | |
| 
 | |
| TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
 | |
| reflection interface similar to Go's standard library `json` and `xml`
 | |
| packages. This package also supports the `encoding.TextUnmarshaler` and
 | |
| `encoding.TextMarshaler` interfaces so that you can define custom data
 | |
| representations. (There is an example of this below.)
 | |
| 
 | |
| Spec: https://github.com/toml-lang/toml
 | |
| 
 | |
| Compatible with TOML version
 | |
| [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
 | |
| 
 | |
| Documentation: https://godoc.org/github.com/BurntSushi/toml
 | |
| 
 | |
| Installation:
 | |
| 
 | |
| ```bash
 | |
| go get github.com/BurntSushi/toml
 | |
| ```
 | |
| 
 | |
| Try the toml validator:
 | |
| 
 | |
| ```bash
 | |
| go get github.com/BurntSushi/toml/cmd/tomlv
 | |
| tomlv some-toml-file.toml
 | |
| ```
 | |
| 
 | |
| [](https://travis-ci.org/BurntSushi/toml) [](https://godoc.org/github.com/BurntSushi/toml)
 | |
| 
 | |
| ### Testing
 | |
| 
 | |
| This package passes all tests in
 | |
| [toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
 | |
| and the encoder.
 | |
| 
 | |
| ### Examples
 | |
| 
 | |
| This package works similarly to how the Go standard library handles `XML`
 | |
| and `JSON`. Namely, data is loaded into Go values via reflection.
 | |
| 
 | |
| For the simplest example, consider some TOML file as just a list of keys
 | |
| and values:
 | |
| 
 | |
| ```toml
 | |
| Age = 25
 | |
| Cats = [ "Cauchy", "Plato" ]
 | |
| Pi = 3.14
 | |
| Perfection = [ 6, 28, 496, 8128 ]
 | |
| DOB = 1987-07-05T05:45:00Z
 | |
| ```
 | |
| 
 | |
| Which could be defined in Go as:
 | |
| 
 | |
| ```go
 | |
| type Config struct {
 | |
|   Age int
 | |
|   Cats []string
 | |
|   Pi float64
 | |
|   Perfection []int
 | |
|   DOB time.Time // requires `import time`
 | |
| }
 | |
| ```
 | |
| 
 | |
| And then decoded with:
 | |
| 
 | |
| ```go
 | |
| var conf Config
 | |
| if _, err := toml.Decode(tomlData, &conf); err != nil {
 | |
|   // handle error
 | |
| }
 | |
| ```
 | |
| 
 | |
| You can also use struct tags if your struct field name doesn't map to a TOML
 | |
| key value directly:
 | |
| 
 | |
| ```toml
 | |
| some_key_NAME = "wat"
 | |
| ```
 | |
| 
 | |
| ```go
 | |
| type TOML struct {
 | |
|   ObscureKey string `toml:"some_key_NAME"`
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Using the `encoding.TextUnmarshaler` interface
 | |
| 
 | |
| Here's an example that automatically parses duration strings into
 | |
| `time.Duration` values:
 | |
| 
 | |
| ```toml
 | |
| [[song]]
 | |
| name = "Thunder Road"
 | |
| duration = "4m49s"
 | |
| 
 | |
| [[song]]
 | |
| name = "Stairway to Heaven"
 | |
| duration = "8m03s"
 | |
| ```
 | |
| 
 | |
| Which can be decoded with:
 | |
| 
 | |
| ```go
 | |
| type song struct {
 | |
|   Name     string
 | |
|   Duration duration
 | |
| }
 | |
| type songs struct {
 | |
|   Song []song
 | |
| }
 | |
| var favorites songs
 | |
| if _, err := toml.Decode(blob, &favorites); err != nil {
 | |
|   log.Fatal(err)
 | |
| }
 | |
| 
 | |
| for _, s := range favorites.Song {
 | |
|   fmt.Printf("%s (%s)\n", s.Name, s.Duration)
 | |
| }
 | |
| ```
 | |
| 
 | |
| And you'll also need a `duration` type that satisfies the
 | |
| `encoding.TextUnmarshaler` interface:
 | |
| 
 | |
| ```go
 | |
| type duration struct {
 | |
| 	time.Duration
 | |
| }
 | |
| 
 | |
| func (d *duration) UnmarshalText(text []byte) error {
 | |
| 	var err error
 | |
| 	d.Duration, err = time.ParseDuration(string(text))
 | |
| 	return err
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### More complex usage
 | |
| 
 | |
| Here's an example of how to load the example from the official spec page:
 | |
| 
 | |
| ```toml
 | |
| # This is a TOML document. Boom.
 | |
| 
 | |
| title = "TOML Example"
 | |
| 
 | |
| [owner]
 | |
| name = "Tom Preston-Werner"
 | |
| organization = "GitHub"
 | |
| bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
 | |
| dob = 1979-05-27T07:32:00Z # First class dates? Why not?
 | |
| 
 | |
| [database]
 | |
| server = "192.168.1.1"
 | |
| ports = [ 8001, 8001, 8002 ]
 | |
| connection_max = 5000
 | |
| enabled = true
 | |
| 
 | |
| [servers]
 | |
| 
 | |
|   # You can indent as you please. Tabs or spaces. TOML don't care.
 | |
|   [servers.alpha]
 | |
|   ip = "10.0.0.1"
 | |
|   dc = "eqdc10"
 | |
| 
 | |
|   [servers.beta]
 | |
|   ip = "10.0.0.2"
 | |
|   dc = "eqdc10"
 | |
| 
 | |
| [clients]
 | |
| data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
 | |
| 
 | |
| # Line breaks are OK when inside arrays
 | |
| hosts = [
 | |
|   "alpha",
 | |
|   "omega"
 | |
| ]
 | |
| ```
 | |
| 
 | |
| And the corresponding Go types are:
 | |
| 
 | |
| ```go
 | |
| type tomlConfig struct {
 | |
| 	Title string
 | |
| 	Owner ownerInfo
 | |
| 	DB database `toml:"database"`
 | |
| 	Servers map[string]server
 | |
| 	Clients clients
 | |
| }
 | |
| 
 | |
| type ownerInfo struct {
 | |
| 	Name string
 | |
| 	Org string `toml:"organization"`
 | |
| 	Bio string
 | |
| 	DOB time.Time
 | |
| }
 | |
| 
 | |
| type database struct {
 | |
| 	Server string
 | |
| 	Ports []int
 | |
| 	ConnMax int `toml:"connection_max"`
 | |
| 	Enabled bool
 | |
| }
 | |
| 
 | |
| type server struct {
 | |
| 	IP string
 | |
| 	DC string
 | |
| }
 | |
| 
 | |
| type clients struct {
 | |
| 	Data [][]interface{}
 | |
| 	Hosts []string
 | |
| }
 | |
| ```
 | |
| 
 | |
| Note that a case insensitive match will be tried if an exact match can't be
 | |
| found.
 | |
| 
 | |
| A working example of the above can be found in `_examples/example.{go,toml}`.
 |