git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/toml/example_test.go (about) 1 package toml_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "net/mail" 8 "time" 9 10 "git.sr.ht/~pingoo/stdx/toml" 11 ) 12 13 func ExampleEncoder_Encode() { 14 var ( 15 date, _ = time.Parse(time.RFC822, "14 Mar 10 18:00 UTC") 16 buf = new(bytes.Buffer) 17 ) 18 err := toml.NewEncoder(buf).Encode(map[string]interface{}{ 19 "date": date, 20 "counts": []int{1, 1, 2, 3, 5, 8}, 21 "hash": map[string]string{ 22 "key1": "val1", 23 "key2": "val2", 24 }, 25 }) 26 if err != nil { 27 log.Fatal(err) 28 } 29 fmt.Println(buf.String()) 30 31 // Output: 32 // counts = [1, 1, 2, 3, 5, 8] 33 // date = 2010-03-14T18:00:00Z 34 // 35 // [hash] 36 // key1 = "val1" 37 // key2 = "val2" 38 } 39 40 func ExampleMetaData_PrimitiveDecode() { 41 tomlBlob := ` 42 ranking = ["Springsteen", "J Geils"] 43 44 [bands.Springsteen] 45 started = 1973 46 albums = ["Greetings", "WIESS", "Born to Run", "Darkness"] 47 48 [bands."J Geils"] 49 started = 1970 50 albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"] 51 ` 52 53 type ( 54 band struct { 55 Started int 56 Albums []string 57 } 58 classics struct { 59 Ranking []string 60 Bands map[string]toml.Primitive 61 } 62 ) 63 64 // Do the initial decode; reflection is delayed on Primitive values. 65 var music classics 66 md, err := toml.Decode(tomlBlob, &music) 67 if err != nil { 68 log.Fatal(err) 69 } 70 71 // MetaData still includes information on Primitive values. 72 fmt.Printf("Is `bands.Springsteen` defined? %v\n", 73 md.IsDefined("bands", "Springsteen")) 74 75 // Decode primitive data into Go values. 76 for _, artist := range music.Ranking { 77 // A band is a primitive value, so we need to decode it to get a real 78 // `band` value. 79 primValue := music.Bands[artist] 80 81 var aBand band 82 err = md.PrimitiveDecode(primValue, &aBand) 83 if err != nil { 84 log.Fatal(err) 85 } 86 fmt.Printf("%s started in %d.\n", artist, aBand.Started) 87 } 88 89 // Check to see if there were any fields left undecoded. Note that this 90 // won't be empty before decoding the Primitive value! 91 fmt.Printf("Undecoded: %q\n", md.Undecoded()) 92 93 // Output: 94 // Is `bands.Springsteen` defined? true 95 // Springsteen started in 1973. 96 // J Geils started in 1970. 97 // Undecoded: [] 98 } 99 100 func ExampleDecode() { 101 tomlBlob := ` 102 # Some comments. 103 [alpha] 104 ip = "10.0.0.1" 105 106 [alpha.config] 107 Ports = [ 8001, 8002 ] 108 Location = "Toronto" 109 Created = 1987-07-05T05:45:00Z 110 111 [beta] 112 ip = "10.0.0.2" 113 114 [beta.config] 115 Ports = [ 9001, 9002 ] 116 Location = "New Jersey" 117 Created = 1887-01-05T05:55:00Z 118 ` 119 120 type ( 121 serverConfig struct { 122 Ports []int 123 Location string 124 Created time.Time 125 } 126 server struct { 127 IP string `toml:"ip,omitempty"` 128 Config serverConfig `toml:"config"` 129 } 130 servers map[string]server 131 ) 132 133 var config servers 134 _, err := toml.Decode(tomlBlob, &config) 135 if err != nil { 136 log.Fatal(err) 137 } 138 139 for _, name := range []string{"alpha", "beta"} { 140 s := config[name] 141 fmt.Printf("Server: %s (ip: %s) in %s created on %s\n", 142 name, s.IP, s.Config.Location, 143 s.Config.Created.Format("2006-01-02")) 144 fmt.Printf("Ports: %v\n", s.Config.Ports) 145 } 146 147 // Output: 148 // Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05 149 // Ports: [8001 8002] 150 // Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05 151 // Ports: [9001 9002] 152 } 153 154 type address struct{ *mail.Address } 155 156 func (a *address) UnmarshalText(text []byte) error { 157 var err error 158 a.Address, err = mail.ParseAddress(string(text)) 159 return err 160 } 161 162 // Example Unmarshaler shows how to decode TOML strings into your own 163 // custom data type. 164 func Example_unmarshaler() { 165 blob := ` 166 contacts = [ 167 "Donald Duck <donald@duckburg.com>", 168 "Scrooge McDuck <scrooge@duckburg.com>", 169 ] 170 ` 171 172 var contacts struct { 173 // Implementation of the address type: 174 // 175 // type address struct{ *mail.Address } 176 // 177 // func (a *address) UnmarshalText(text []byte) error { 178 // var err error 179 // a.Address, err = mail.ParseAddress(string(text)) 180 // return err 181 // } 182 183 Contacts []address 184 } 185 186 _, err := toml.Decode(blob, &contacts) 187 if err != nil { 188 log.Fatal(err) 189 } 190 191 for _, c := range contacts.Contacts { 192 fmt.Printf("%#v\n", c.Address) 193 } 194 195 // Output: 196 // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"} 197 // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"} 198 } 199 200 // Example StrictDecoding shows how to detect if there are keys in the TOML 201 // document that weren't decoded into the value given. This is useful for 202 // returning an error to the user if they've included extraneous fields in their 203 // configuration. 204 func Example_strictDecoding() { 205 var blob = ` 206 key1 = "value1" 207 key2 = "value2" 208 key3 = "value3" 209 ` 210 211 var conf struct { 212 Key1 string 213 Key3 string 214 } 215 md, err := toml.Decode(blob, &conf) 216 if err != nil { 217 log.Fatal(err) 218 } 219 220 fmt.Printf("Undecoded keys: %q\n", md.Undecoded()) 221 // Output: 222 // Undecoded keys: ["key2"] 223 } 224 225 type order struct { 226 // NOTE `order.parts` is a private slice of type `part` which is an 227 // interface and may only be loaded from toml using the UnmarshalTOML() 228 // method of the Umarshaler interface. 229 parts parts 230 } 231 232 type parts []part 233 234 type part interface { 235 Name() string 236 } 237 238 type valve struct { 239 Type string 240 ID string 241 Size float32 242 Rating int 243 } 244 245 func (v *valve) Name() string { 246 return fmt.Sprintf("VALVE: %s", v.ID) 247 } 248 249 type pipe struct { 250 Type string 251 ID string 252 Length float32 253 Diameter int 254 } 255 256 func (p *pipe) Name() string { 257 return fmt.Sprintf("PIPE: %s", p.ID) 258 } 259 260 type cable struct { 261 Type string 262 ID string 263 Length int 264 Rating float32 265 } 266 267 func (c *cable) Name() string { 268 return fmt.Sprintf("CABLE: %s", c.ID) 269 } 270 271 func (o *order) UnmarshalTOML(data interface{}) error { 272 // NOTE the example below contains detailed type casting to show how the 273 // 'data' is retrieved. In operational use, a type cast wrapper may be 274 // preferred e.g. 275 // 276 // func AsMap(v interface{}) (map[string]interface{}, error) { 277 // return v.(map[string]interface{}) 278 // } 279 // 280 // resulting in: 281 // d, _ := AsMap(data) 282 // 283 284 d, _ := data.(map[string]interface{}) 285 parts, _ := d["parts"].([]map[string]interface{}) 286 287 for _, p := range parts { 288 289 typ, _ := p["type"].(string) 290 id, _ := p["id"].(string) 291 292 // detect the type of part and handle each case 293 switch p["type"] { 294 case "valve": 295 296 size := float32(p["size"].(float64)) 297 rating := int(p["rating"].(int64)) 298 299 valve := &valve{ 300 Type: typ, 301 ID: id, 302 Size: size, 303 Rating: rating, 304 } 305 306 o.parts = append(o.parts, valve) 307 308 case "pipe": 309 310 length := float32(p["length"].(float64)) 311 diameter := int(p["diameter"].(int64)) 312 313 pipe := &pipe{ 314 Type: typ, 315 ID: id, 316 Length: length, 317 Diameter: diameter, 318 } 319 320 o.parts = append(o.parts, pipe) 321 322 case "cable": 323 324 length := int(p["length"].(int64)) 325 rating := float32(p["rating"].(float64)) 326 327 cable := &cable{ 328 Type: typ, 329 ID: id, 330 Length: length, 331 Rating: rating, 332 } 333 334 o.parts = append(o.parts, cable) 335 336 } 337 } 338 339 return nil 340 } 341 342 // Example UnmarshalTOML shows how to implement a struct type that knows how to 343 // unmarshal itself. The struct must take full responsibility for mapping the 344 // values passed into the struct. The method may be used with interfaces in a 345 // struct in cases where the actual type is not known until the data is 346 // examined. 347 func Example_unmarshalTOML() { 348 blob := ` 349 [[parts]] 350 type = "valve" 351 id = "valve-1" 352 size = 1.2 353 rating = 4 354 355 [[parts]] 356 type = "valve" 357 id = "valve-2" 358 size = 2.1 359 rating = 5 360 361 [[parts]] 362 type = "pipe" 363 id = "pipe-1" 364 length = 2.1 365 diameter = 12 366 367 [[parts]] 368 type = "cable" 369 id = "cable-1" 370 length = 12 371 rating = 3.1 372 ` 373 374 // See example_test.go in the source for the implementation of the order 375 // type. 376 o := &order{} 377 378 err := toml.Unmarshal([]byte(blob), o) 379 if err != nil { 380 log.Fatal(err) 381 } 382 383 fmt.Println(len(o.parts)) 384 for _, part := range o.parts { 385 fmt.Println(part.Name()) 386 } 387 }