From 92fb6e5161e7b73f2fafc17ecdf4b716278a2e8c Mon Sep 17 00:00:00 2001 From: Qi Xiao Date: Fri, 26 Feb 2016 04:05:47 +0100 Subject: [PATCH] Support shared variable. This fixes #15. Only string is supported ATM. --- eval/eval.go | 7 +++++++ eval/shared.go | 19 +++++++++++++++++ store/sharedVar.go | 35 ++++++++++++++++++++++++++++++++ store/sharedVar_test.go | 45 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 eval/shared.go create mode 100644 store/sharedVar.go create mode 100644 store/sharedVar_test.go diff --git a/eval/eval.go b/eval/eval.go index a2257237..dfdbe59d 100644 --- a/eval/eval.go +++ b/eval/eval.go @@ -349,6 +349,8 @@ func (ev *Evaler) Global() Namespace { return map[string]Variable(ev.global) } +var ErrStoreUnconnected = errors.New("store unconnected") + // ResolveVar resolves a variable. When the variable cannot be found, nil is // returned. func (ec *EvalCtx) ResolveVar(ns, name string) Variable { @@ -372,6 +374,11 @@ func (ec *EvalCtx) ResolveVar(ns, name string) Variable { return NewRoVariable(ExternalCmd{name[len(FnPrefix):]}) } return envVariable{name} + case "shared": + if ec.store == nil { + throw(ErrStoreUnconnected) + } + return sharedVariable{ec.store, name} default: use(ec, ns, nil) return ec.modules[ns][name] diff --git a/eval/shared.go b/eval/shared.go new file mode 100644 index 00000000..659001a2 --- /dev/null +++ b/eval/shared.go @@ -0,0 +1,19 @@ +package eval + +import "github.com/elves/elvish/store" + +type sharedVariable struct { + store *store.Store + name string +} + +func (sv sharedVariable) Set(val Value) { + err := sv.store.SetSharedVar(sv.name, ToString(val)) + maybeThrow(err) +} + +func (sv sharedVariable) Get() Value { + value, err := sv.store.GetSharedVar(sv.name) + maybeThrow(err) + return String(value) +} diff --git a/store/sharedVar.go b/store/sharedVar.go new file mode 100644 index 00000000..a8adf549 --- /dev/null +++ b/store/sharedVar.go @@ -0,0 +1,35 @@ +package store + +import ( + "database/sql" + "errors" +) + +var ErrNoVar = errors.New("no such variable") + +func init() { + initTable["shared"] = func(db *sql.DB) error { + _, err := db.Exec(`create table if not exists shared_var (name text unique primary key, value text)`) + return err + } +} + +func (s *Store) GetSharedVar(n string) (string, error) { + row := s.db.QueryRow(`select value from shared_var where name = ?`, n) + var value string + err := row.Scan(&value) + if err == sql.ErrNoRows { + err = ErrNoVar + } + return value, err +} + +func (s *Store) SetSharedVar(n, v string) error { + _, err := s.db.Exec(`insert or replace into shared_var (name, value) values (?, ?)`, n, v) + return err +} + +func (s *Store) DelSharedVar(n string) error { + _, err := s.db.Exec(`delete from shared_var where name = ?`, n) + return err +} diff --git a/store/sharedVar_test.go b/store/sharedVar_test.go new file mode 100644 index 00000000..7079973b --- /dev/null +++ b/store/sharedVar_test.go @@ -0,0 +1,45 @@ +package store + +import "testing" + +func TestSharedVar(t *testing.T) { + varname := "foo" + value1 := "lorem ipsum" + value2 := "o mores, o tempora" + + // Getting an nonexistent variable should return ErrNoVar. + _, err := tStore.GetSharedVar(varname) + if err != ErrNoVar { + t.Error("want ErrNoVar, got", err) + } + + // Setting a variable for the first time creates it. + err = tStore.SetSharedVar(varname, value1) + if err != nil { + t.Error("want no error, got", err) + } + v, err := tStore.GetSharedVar(varname) + if v != value1 || err != nil { + t.Errorf("want %q and no error, got %q and %v", value1, v, err) + } + + // Setting an existing variable updates its value. + err = tStore.SetSharedVar(varname, value2) + if err != nil { + t.Error("want no error, got", err) + } + v, err = tStore.GetSharedVar(varname) + if v != value2 || err != nil { + t.Errorf("want %q and no error, got %q and %v", value2, v, err) + } + + // After deleting a variable, access to it cause ErrNoVar. + err = tStore.DelSharedVar(varname) + if err != nil { + t.Error("want no error, got", err) + } + _, err = tStore.GetSharedVar(varname) + if err != ErrNoVar { + t.Error("want ErrNoVar, got", err) + } +}