-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
344 additions
and
11 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package edn_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
"gopkg.in/edn.v1" | ||
) | ||
|
||
type Point3 struct { | ||
X, Y, Z int64 | ||
} | ||
|
||
type Unit struct { | ||
Type edn.Keyword | ||
HP int | ||
} | ||
|
||
// EDN, in contrast to JSON, supports arbitrary values as keys. | ||
func Example_arbitraryKeys() { | ||
input := `{{:x 1 :y 2 :z 3} "Greybeard" | ||
{:y 10 :x 1 :z -10} "Blackwind"}` | ||
|
||
var locStarships map[Point3]string | ||
err := edn.UnmarshalString(input, &locStarships) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
p := Point3{1, 10, -10} | ||
|
||
fmt.Printf("Starship at location %v is %s\n", p, locStarships[p]) | ||
|
||
input = `{[0 2] {:type :scout :hp 55} | ||
[-3 10] {:type :villager :hp 25} | ||
[5 5] {:type :bowman :hp 32} | ||
[5 6] {:type :bowman :hp 29}}` | ||
|
||
var locUnits map[[2]int]Unit | ||
err = edn.UnmarshalString(input, &locUnits) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
loc := [2]int{5, 5} | ||
|
||
fmt.Printf("Unit at location %v is %+v\n", loc, locUnits[loc]) | ||
|
||
// Output: | ||
// Starship at location {1 10 -10} is Blackwind | ||
// Unit at location [5 5] is {Type::bowman HP:32} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package edn_test | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"gopkg.in/edn.v1" | ||
) | ||
|
||
type Notifiable interface { | ||
Notify() | ||
} | ||
|
||
type User struct { | ||
Username string | ||
} | ||
|
||
func (u User) MarshalEDN() ([]byte, error) { | ||
return edn.Marshal(edn.Tag{"myapp/user", u.Username}) | ||
} | ||
|
||
func (u *User) Notify() { | ||
fmt.Printf("Notified user %s.\n", u.Username) | ||
} | ||
|
||
type Group struct { | ||
GroupId int | ||
} | ||
|
||
func (g Group) MarshalEDN() ([]byte, error) { | ||
return edn.Marshal(edn.Tag{"myapp/group", g.GroupId}) | ||
} | ||
|
||
func (g *Group) Notify() { | ||
fmt.Printf("Notified group with id %d.\n", g.GroupId) | ||
} | ||
|
||
var notifyTagMap edn.TagMap | ||
|
||
// We use a tagMap to avoid adding these values to the entire system. | ||
func init() { | ||
err := notifyTagMap.AddTagFn("myapp/user", func(s string) (*User, error) { | ||
return &User{s}, nil | ||
}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
err = notifyTagMap.AddTagFn("myapp/group", func(id int) (*Group, error) { | ||
return &Group{id}, nil | ||
}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
// This example shows how to read and write basic EDN tags, and how this can be | ||
// utilised: In contrast to encoding/json, you can read in data where you only | ||
// know that the input satisfies some sort of interface, provided the value is | ||
// tagged. | ||
func Example_polymorphicTags() { | ||
input := `[#myapp/user "eugeness" | ||
#myapp/group 10 | ||
#myapp/user "jeannikl" | ||
#myapp/user "jeremiah" | ||
#myapp/group 100]` | ||
|
||
rdr := strings.NewReader(input) | ||
dec := edn.NewDecoder(rdr) | ||
dec.UseTagMap(¬ifyTagMap) | ||
|
||
var toNotify []Notifiable | ||
err := dec.Decode(&toNotify) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, notify := range toNotify { | ||
notify.Notify() | ||
} | ||
|
||
// Print out the values as well | ||
out, err := edn.Marshal(toNotify) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
fmt.Println(string(out)) | ||
// Output: | ||
// Notified user eugeness. | ||
// Notified group with id 10. | ||
// Notified user jeannikl. | ||
// Notified user jeremiah. | ||
// Notified group with id 100. | ||
// [#myapp/user"eugeness" #myapp/group 10 #myapp/user"jeannikl" #myapp/user"jeremiah" #myapp/group 100] | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package edn_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
"gopkg.in/edn.v1" | ||
) | ||
|
||
type UserOption edn.Keyword | ||
|
||
type UnknownUserOptionError UserOption | ||
|
||
func (err UnknownUserOptionError) Error() string { | ||
return fmt.Sprintf("Unknown user option %s", edn.Keyword(err)) | ||
} | ||
|
||
const ( | ||
UnknownOption = UserOption("") | ||
ShowEmail = UserOption("show-email") | ||
Notifications = UserOption("notifications") | ||
DailyEmail = UserOption("daily-email") | ||
RememberMe = UserOption("remember-me") | ||
) | ||
|
||
func ListUserOptions() []UserOption { | ||
return []UserOption{ | ||
ShowEmail, | ||
Notifications, | ||
DailyEmail, | ||
RememberMe, | ||
} | ||
} | ||
|
||
func (uo *UserOption) UnmarshalEDN(bs []byte) error { | ||
var kw edn.Keyword | ||
err := edn.Unmarshal(bs, &kw) | ||
if err != nil { | ||
return err | ||
} | ||
opt := UserOption(kw) | ||
switch opt { | ||
case ShowEmail, Notifications, DailyEmail, RememberMe: | ||
*uo = opt | ||
return nil | ||
default: | ||
return UnknownUserOptionError(opt) | ||
} | ||
} | ||
|
||
type UserOptions map[UserOption]bool | ||
|
||
func (opts *UserOptions) UnmarshalEDN(bs []byte) error { | ||
var kw edn.Keyword | ||
// try to decode into keyword first | ||
err := edn.Unmarshal(bs, &kw) | ||
if err == nil && kw == edn.Keyword("all") { | ||
// Put all options into the user option map | ||
*opts = UserOptions(make(map[UserOption]bool)) | ||
for _, opt := range ListUserOptions() { | ||
(*opts)[opt] = true | ||
} | ||
return nil | ||
} | ||
// then try to decode into user map | ||
var rawOpts map[UserOption]bool | ||
err = edn.Unmarshal(bs, &rawOpts) | ||
*opts = UserOptions(rawOpts) | ||
return err | ||
} | ||
|
||
// This example shows how one can implement enums and sets, and how to support | ||
// multiple different forms for a specific value type. The set implemented here | ||
// supports the notation `:all` for all values. | ||
func Example_enumsAndSets() { | ||
inputs := []string{ | ||
"#{:show-email :notifications}", | ||
"#{:notifications :show-email :remember-me}", | ||
":all", | ||
"#{:doot-doot}", | ||
":none", | ||
"#{} ;; no options", | ||
} | ||
for _, input := range inputs { | ||
var opts UserOptions | ||
err := edn.UnmarshalString(input, &opts) | ||
if err != nil { | ||
fmt.Println(err) | ||
// Do proper error handling here if something fails | ||
continue | ||
} | ||
// Cannot print out a map, as its ordering is nondeterministic. | ||
fmt.Printf("show email? %t, notifications? %t, daily email? %t, remember me? %t\n", | ||
opts[ShowEmail], opts[Notifications], opts[DailyEmail], opts[RememberMe]) | ||
} | ||
|
||
// Output: | ||
// show email? true, notifications? true, daily email? false, remember me? false | ||
// show email? true, notifications? true, daily email? false, remember me? true | ||
// show email? true, notifications? true, daily email? true, remember me? true | ||
// Unknown user option :doot-doot | ||
// edn: cannot unmarshal keyword into Go value of type map[edn_test.UserOption]bool | ||
// show email? false, notifications? false, daily email? false, remember me? false | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package edn_test | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"strings" | ||
|
||
"gopkg.in/edn.v1" | ||
) | ||
|
||
// Typically, you'd also include timestamps here. Imagine that they are here. | ||
type LogEntry struct { | ||
Level edn.Keyword | ||
Message string `edn:"msg"` | ||
Environment string `edn:"env"` | ||
Service string | ||
} | ||
|
||
// This example shows how one can do streaming with the decoder, and how to | ||
// properly know when the stream has no elements left. | ||
func Example_streaming() { | ||
const input = ` | ||
{:level :debug :msg "1 < 2 ? true" :env "dev" :service "comparer"} | ||
{:level :warn :msg "slow response time from 127.0.1.39" :env "prod" :service "worker 10"} | ||
{:level :warn :msg "worker 8 has been unavailable for 30s" :env "prod" :service "gateway"} | ||
{:level :info :msg "new processing request: what.png" :env "prod" :service "gateway"} | ||
{:level :debug :msg "1 < nil? error" :env "dev" :service "comparer"} | ||
{:level :warn :msg "comparison failed: 1 < nil" :env "dev" :service "comparer"} | ||
{:level :info :msg "received new processing request: what.png" :env "prod" :service "worker 3"} | ||
{:level :warn :msg "bad configuration value :timeout, using 3h" :env "staging" :service "worker 3"} | ||
` | ||
|
||
rdr := strings.NewReader(input) | ||
dec := edn.NewDecoder(rdr) | ||
var err error | ||
for { | ||
var entry LogEntry | ||
err = dec.Decode(&entry) | ||
if err != nil { | ||
break | ||
} | ||
if entry.Level == edn.Keyword("warn") && entry.Environment != "dev" { | ||
fmt.Println(entry.Message) | ||
} | ||
} | ||
if err != nil && err != io.EOF { | ||
// Something bad happened to our reader | ||
fmt.Println(err) | ||
return | ||
} | ||
// If err == io.EOF then we've reached end of stream | ||
fmt.Println("End of stream!") | ||
// Output: | ||
// slow response time from 127.0.1.39 | ||
// worker 8 has been unavailable for 30s | ||
// bad configuration value :timeout, using 3h | ||
// End of stream! | ||
} |
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