Skip to content

Commit

Permalink
rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
matryer committed Feb 9, 2015
1 parent 415aa64 commit c77a0f1
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
# persist
Persist loads and saves Go objects to files

## Usage

First get it:

```
go get github.com/matryer/persist
```

Then save objects like this:

```
var conf Config
if err := persist.Save("./project.conf", &conf); err != nil {
log.Fatalln("failed to save config:", err)
}
```

And load them like this:


```
var conf Config
if err := persist.Load("./project.conf", &conf); err != nil {
log.Fatalln("failed to load config:", err)
}
```
2 changes: 2 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package persist loads and saves Go objects to files.
package persist
60 changes: 60 additions & 0 deletions persist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package persist

import (
"bytes"
"encoding/json"
"io"
"os"
"sync"
)

var lock sync.Mutex

// Marshal is a function that marshals the object into an
// io.Reader.
// By default, it uses the JSON marshaller.
var Marshal = func(v interface{}) (io.Reader, error) {
b, err := json.MarshalIndent(v, "", "\t")
if err != nil {
return nil, err
}
return bytes.NewReader(b), nil
}

// Unmarshal is a function that unmarshals the data from the
// reader into the specified value.
// By default, it uses the JSON unmarshaller.
var Unmarshal = func(r io.Reader, v interface{}) error {
return json.NewDecoder(r).Decode(v)
}

// Save saves a representation of v to the file at path.
func Save(path string, v interface{}) error {
lock.Lock()
defer lock.Unlock()
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
r, err := Marshal(v)
if err != nil {
return err
}
_, err = io.Copy(f, r)
return err
}

// Load loads the file at path into v.
// Use os.IsNotExist() to see if the returned error is due
// to the file being missing.
func Load(path string, v interface{}) error {
lock.Lock()
defer lock.Unlock()
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
return Unmarshal(f, v)
}
50 changes: 50 additions & 0 deletions persist_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package persist_test

import (
"os"
"testing"
"time"

"github.com/cheekybits/is"
"github.com/matryer/persist"
)

type obj struct {
Name string
Number int
When time.Time
}

func TestNoFile(t *testing.T) {
is := is.New(t)

var v interface{}
err := persist.Load("no-such-file.conf", &v)
is.Equal(true, os.IsNotExist(err))

}

func TestPersist(t *testing.T) {
is := is.New(t)
defer os.Remove("./file.tmp")

o := &obj{
Name: "Mat",
Number: 47,
When: time.Now(),
}

// save it
err := persist.Save("./file.tmp", o)
is.NoErr(err)

// load it
var o2 obj
err = persist.Load("./file.tmp", &o2)
is.NoErr(err)

is.Equal(o.Name, o2.Name)
is.Equal(o.Number, o2.Number)
is.Equal(o.When, o2.When)

}

0 comments on commit c77a0f1

Please sign in to comment.