From 63893587cb41a1980318b60bf05fafbf433a24ab Mon Sep 17 00:00:00 2001 From: Grant Ammons Date: Sun, 24 Apr 2016 10:22:33 -0400 Subject: Organize things a bit better --- file_store.go | 34 ------------------ file_store_test.go | 14 -------- parser.go | 87 --------------------------------------------- parser_test.go | 83 ------------------------------------------ store.go | 11 ------ todo.go | 28 +++++---------- todo_test.go | 23 ------------ todolist/file_store.go | 34 ++++++++++++++++++ todolist/file_store_test.go | 14 ++++++++ todolist/parser.go | 87 +++++++++++++++++++++++++++++++++++++++++++++ todolist/parser_test.go | 83 ++++++++++++++++++++++++++++++++++++++++++ todolist/store.go | 11 ++++++ todolist/todo_item.go | 22 ++++++++++++ todolist/todo_test.go | 23 ++++++++++++ todolist/todos.json | 1 + 15 files changed, 284 insertions(+), 271 deletions(-) delete mode 100644 file_store.go delete mode 100644 file_store_test.go delete mode 100644 parser.go delete mode 100644 parser_test.go delete mode 100644 store.go delete mode 100644 todo_test.go create mode 100644 todolist/file_store.go create mode 100644 todolist/file_store_test.go create mode 100644 todolist/parser.go create mode 100644 todolist/parser_test.go create mode 100644 todolist/store.go create mode 100644 todolist/todo_item.go create mode 100644 todolist/todo_test.go create mode 100644 todolist/todos.json diff --git a/file_store.go b/file_store.go deleted file mode 100644 index 3f71ba2..0000000 --- a/file_store.go +++ /dev/null @@ -1,34 +0,0 @@ -package todolist - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "os/user" -) - -type FileStore struct { - FileLocation string - Data []Todo -} - -func NewFileStore() *FileStore { - usr, _ := user.Current() - return &FileStore{FileLocation: usr.HomeDir + "/.todos.json"} -} - -func (f *FileStore) Load() { - data, err := ioutil.ReadFile(f.FileLocation) - if err != nil { - fmt.Println("Error reading file", err) - os.Exit(1) - } - - jerr := json.Unmarshal(data, &f.Data) - if jerr != nil { - fmt.Println("Error reading json data", jerr) - os.Exit(1) - } - -} diff --git a/file_store_test.go b/file_store_test.go deleted file mode 100644 index 8bb23e0..0000000 --- a/file_store_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package todolist - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFileStore(t *testing.T) { - assert := assert.New(t) - store := &FileStore{FileLocation: "todos.json"} - store.Load() - assert.Equal(store.Data[0].Subject, "this is the first subject", "") -} diff --git a/parser.go b/parser.go deleted file mode 100644 index d3b5968..0000000 --- a/parser.go +++ /dev/null @@ -1,87 +0,0 @@ -package todolist - -import ( - "fmt" - "regexp" - "strings" - "time" - - "github.com/jinzhu/now" -) - -type Parser struct{} - -func (p *Parser) Parse(input string) *Todo { - todo := NewTodo() - todo.Subject = p.Subject(input) - todo.Projects = p.Projects(input) - todo.Contexts = p.Contexts(input) - if p.hasDue(input) { - todo.FormattedDue = p.Due(input) - } - return todo -} - -func (p *Parser) Subject(input string) string { - if strings.Contains(input, " due") { - index := strings.LastIndex(input, " due") - return input[0:index] - } else { - return input - } -} - -func (p *Parser) Projects(input string) []string { - r, _ := regexp.Compile(`\+\w+`) - return p.matchWords(input, r) -} - -func (p *Parser) Contexts(input string) []string { - r, err := regexp.Compile(`\@\w+`) - if err != nil { - fmt.Println("regex error", err) - } - return p.matchWords(input, r) -} - -func (p *Parser) hasDue(input string) bool { - r, _ := regexp.Compile(`due \w+$`) - return r.MatchString(input) -} - -func (p *Parser) Due(input string) time.Time { - r, _ := regexp.Compile(`due .*$`) - - res := r.FindString(input) - res = res[4:len(res)] - switch { - case res == "today": - return now.BeginningOfDay() - case res == "tomorrow" || res == "tom": - return now.BeginningOfDay().AddDate(0, 0, 1) - case res == "monday" || res == "mon": - n := now.BeginningOfDay() - return now.New(n).Monday().AddDate(0, 0, 7) - case res == "tuesday" || res == "tue": - n := now.BeginningOfDay() - return now.New(n).Monday().AddDate(0, 0, 1) - case res == "wednesday" || res == "wed": - n := now.BeginningOfDay() - return now.New(n).Monday().AddDate(0, 0, 2) - case res == "next week": - n := now.BeginningOfDay() - return now.New(n).Monday().AddDate(0, 0, 7) - } - //return now.Parse(input) - return time.Now() -} - -func (p *Parser) matchWords(input string, r *regexp.Regexp) []string { - results := r.FindAllString(input, -1) - ret := []string{} - - for _, val := range results { - ret = append(ret, val[1:len(val)]) - } - return ret -} diff --git a/parser_test.go b/parser_test.go deleted file mode 100644 index 1ab2826..0000000 --- a/parser_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package todolist - -import ( - "fmt" - "testing" - "time" - - "github.com/jinzhu/now" -) - -func TestParseSubject(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing") - if todo.Subject != "do this thing" { - t.Error("Expected todo.Subject to equal 'do this thing'") - } -} - -func TestParseSubjectWithDue(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing due tomorrow") - if todo.Subject != "do this thing" { - t.Error("Expected todo.Subject to equal 'do this thing', got ", todo.Subject) - } -} - -func TestParseProjects(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing +proj1 +proj2 due tomorrow") - if len(todo.Projects) != 2 { - t.Error("Expected Projects length to be 2") - } - if todo.Projects[0] != "proj1" { - t.Error("todo.Projects[0] should equal 'proj1' but got", todo.Projects[0]) - } - if todo.Projects[1] != "proj2" { - t.Error("todo.Projects[1] should equal 'proj2' but got", todo.Projects[1]) - } -} - -func TestParseContexts(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing with @bob and @mary due tomorrow") - if len(todo.Contexts) != 2 { - t.Error("Expected Projects length to be 2") - } - if todo.Contexts[0] != "bob" { - t.Error("todo.Contexts[0] should equal 'mary' but got", todo.Contexts[0]) - } - if todo.Contexts[1] != "mary" { - t.Error("todo.Contexts[1] should equal 'mary' but got", todo.Contexts[1]) - } -} - -func TestDueToday(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing with @bob and @mary due today") - if todo.FormattedDue != now.BeginningOfDay() { - fmt.Println("Date is different", todo.Due, time.Now()) - } -} - -func TestDueTomorrow(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing with @bob and @mary due tomorrow") - if todo.FormattedDue != now.BeginningOfDay().AddDate(0, 0, 1) { - fmt.Println("Date is different", todo.Due, time.Now()) - } -} - -//func TestDueNextWeek(t *testing.T) { -// parser := &Parser{} -// -// fmt.Println("about to parse") -// todo := parser.Parse("do this thing with @bob and @mary due next week") -// fmt.Println(todo.Due) -//} - -func TestDueMonday(t *testing.T) { - parser := &Parser{} - todo := parser.Parse("do this thing with @bob and @mary due mon") - fmt.Println(todo.Due) -} diff --git a/store.go b/store.go deleted file mode 100644 index 006583a..0000000 --- a/store.go +++ /dev/null @@ -1,11 +0,0 @@ -package todolist - -type Store interface { - Load() - Save() - - Find(id int) Todo - Add(t *Todo) - Remove(t *Todo) - NextId() int -} diff --git a/todo.go b/todo.go index 1319132..0f62340 100644 --- a/todo.go +++ b/todo.go @@ -1,22 +1,12 @@ -package todolist +package main -import "time" +import "fmt" +import "github.com/gammons/todolist/todolist" -type Todo struct { - Id int - Subject string - Projects []string - Contexts []string - Due string - FormattedDue time.Time - Completed bool - Archived bool -} - -func NewTodo() *Todo { - return &Todo{Completed: false, Archived: false} -} - -func (t Todo) Valid() bool { - return (t.Subject != "") +func main() { + store := todolist.NewFileStore() + store.Load() + for _, item := range store.Data { + fmt.Println(item) + } } diff --git a/todo_test.go b/todo_test.go deleted file mode 100644 index aab2a74..0000000 --- a/todo_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package todolist - -import "testing" - -func TestNewTodo(t *testing.T) { - todo := NewTodo() - - if todo.Completed || todo.Archived { - t.Error("Completed should be false for new todos") - } -} - -func TestValidity(t *testing.T) { - todo := &Todo{Subject: "test"} - if !todo.Valid() { - t.Error("Expected valid todo to be valid") - } - - invalidTodo := &Todo{Subject: ""} - if invalidTodo.Valid() { - t.Error("Invalid todo is being reported as valid") - } -} diff --git a/todolist/file_store.go b/todolist/file_store.go new file mode 100644 index 0000000..3f71ba2 --- /dev/null +++ b/todolist/file_store.go @@ -0,0 +1,34 @@ +package todolist + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/user" +) + +type FileStore struct { + FileLocation string + Data []Todo +} + +func NewFileStore() *FileStore { + usr, _ := user.Current() + return &FileStore{FileLocation: usr.HomeDir + "/.todos.json"} +} + +func (f *FileStore) Load() { + data, err := ioutil.ReadFile(f.FileLocation) + if err != nil { + fmt.Println("Error reading file", err) + os.Exit(1) + } + + jerr := json.Unmarshal(data, &f.Data) + if jerr != nil { + fmt.Println("Error reading json data", jerr) + os.Exit(1) + } + +} diff --git a/todolist/file_store_test.go b/todolist/file_store_test.go new file mode 100644 index 0000000..8bb23e0 --- /dev/null +++ b/todolist/file_store_test.go @@ -0,0 +1,14 @@ +package todolist + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFileStore(t *testing.T) { + assert := assert.New(t) + store := &FileStore{FileLocation: "todos.json"} + store.Load() + assert.Equal(store.Data[0].Subject, "this is the first subject", "") +} diff --git a/todolist/parser.go b/todolist/parser.go new file mode 100644 index 0000000..d3b5968 --- /dev/null +++ b/todolist/parser.go @@ -0,0 +1,87 @@ +package todolist + +import ( + "fmt" + "regexp" + "strings" + "time" + + "github.com/jinzhu/now" +) + +type Parser struct{} + +func (p *Parser) Parse(input string) *Todo { + todo := NewTodo() + todo.Subject = p.Subject(input) + todo.Projects = p.Projects(input) + todo.Contexts = p.Contexts(input) + if p.hasDue(input) { + todo.FormattedDue = p.Due(input) + } + return todo +} + +func (p *Parser) Subject(input string) string { + if strings.Contains(input, " due") { + index := strings.LastIndex(input, " due") + return input[0:index] + } else { + return input + } +} + +func (p *Parser) Projects(input string) []string { + r, _ := regexp.Compile(`\+\w+`) + return p.matchWords(input, r) +} + +func (p *Parser) Contexts(input string) []string { + r, err := regexp.Compile(`\@\w+`) + if err != nil { + fmt.Println("regex error", err) + } + return p.matchWords(input, r) +} + +func (p *Parser) hasDue(input string) bool { + r, _ := regexp.Compile(`due \w+$`) + return r.MatchString(input) +} + +func (p *Parser) Due(input string) time.Time { + r, _ := regexp.Compile(`due .*$`) + + res := r.FindString(input) + res = res[4:len(res)] + switch { + case res == "today": + return now.BeginningOfDay() + case res == "tomorrow" || res == "tom": + return now.BeginningOfDay().AddDate(0, 0, 1) + case res == "monday" || res == "mon": + n := now.BeginningOfDay() + return now.New(n).Monday().AddDate(0, 0, 7) + case res == "tuesday" || res == "tue": + n := now.BeginningOfDay() + return now.New(n).Monday().AddDate(0, 0, 1) + case res == "wednesday" || res == "wed": + n := now.BeginningOfDay() + return now.New(n).Monday().AddDate(0, 0, 2) + case res == "next week": + n := now.BeginningOfDay() + return now.New(n).Monday().AddDate(0, 0, 7) + } + //return now.Parse(input) + return time.Now() +} + +func (p *Parser) matchWords(input string, r *regexp.Regexp) []string { + results := r.FindAllString(input, -1) + ret := []string{} + + for _, val := range results { + ret = append(ret, val[1:len(val)]) + } + return ret +} diff --git a/todolist/parser_test.go b/todolist/parser_test.go new file mode 100644 index 0000000..1ab2826 --- /dev/null +++ b/todolist/parser_test.go @@ -0,0 +1,83 @@ +package todolist + +import ( + "fmt" + "testing" + "time" + + "github.com/jinzhu/now" +) + +func TestParseSubject(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing") + if todo.Subject != "do this thing" { + t.Error("Expected todo.Subject to equal 'do this thing'") + } +} + +func TestParseSubjectWithDue(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing due tomorrow") + if todo.Subject != "do this thing" { + t.Error("Expected todo.Subject to equal 'do this thing', got ", todo.Subject) + } +} + +func TestParseProjects(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing +proj1 +proj2 due tomorrow") + if len(todo.Projects) != 2 { + t.Error("Expected Projects length to be 2") + } + if todo.Projects[0] != "proj1" { + t.Error("todo.Projects[0] should equal 'proj1' but got", todo.Projects[0]) + } + if todo.Projects[1] != "proj2" { + t.Error("todo.Projects[1] should equal 'proj2' but got", todo.Projects[1]) + } +} + +func TestParseContexts(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing with @bob and @mary due tomorrow") + if len(todo.Contexts) != 2 { + t.Error("Expected Projects length to be 2") + } + if todo.Contexts[0] != "bob" { + t.Error("todo.Contexts[0] should equal 'mary' but got", todo.Contexts[0]) + } + if todo.Contexts[1] != "mary" { + t.Error("todo.Contexts[1] should equal 'mary' but got", todo.Contexts[1]) + } +} + +func TestDueToday(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing with @bob and @mary due today") + if todo.FormattedDue != now.BeginningOfDay() { + fmt.Println("Date is different", todo.Due, time.Now()) + } +} + +func TestDueTomorrow(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing with @bob and @mary due tomorrow") + if todo.FormattedDue != now.BeginningOfDay().AddDate(0, 0, 1) { + fmt.Println("Date is different", todo.Due, time.Now()) + } +} + +//func TestDueNextWeek(t *testing.T) { +// parser := &Parser{} +// +// fmt.Println("about to parse") +// todo := parser.Parse("do this thing with @bob and @mary due next week") +// fmt.Println(todo.Due) +//} + +func TestDueMonday(t *testing.T) { + parser := &Parser{} + todo := parser.Parse("do this thing with @bob and @mary due mon") + fmt.Println(todo.Due) +} diff --git a/todolist/store.go b/todolist/store.go new file mode 100644 index 0000000..006583a --- /dev/null +++ b/todolist/store.go @@ -0,0 +1,11 @@ +package todolist + +type Store interface { + Load() + Save() + + Find(id int) Todo + Add(t *Todo) + Remove(t *Todo) + NextId() int +} diff --git a/todolist/todo_item.go b/todolist/todo_item.go new file mode 100644 index 0000000..1319132 --- /dev/null +++ b/todolist/todo_item.go @@ -0,0 +1,22 @@ +package todolist + +import "time" + +type Todo struct { + Id int + Subject string + Projects []string + Contexts []string + Due string + FormattedDue time.Time + Completed bool + Archived bool +} + +func NewTodo() *Todo { + return &Todo{Completed: false, Archived: false} +} + +func (t Todo) Valid() bool { + return (t.Subject != "") +} diff --git a/todolist/todo_test.go b/todolist/todo_test.go new file mode 100644 index 0000000..aab2a74 --- /dev/null +++ b/todolist/todo_test.go @@ -0,0 +1,23 @@ +package todolist + +import "testing" + +func TestNewTodo(t *testing.T) { + todo := NewTodo() + + if todo.Completed || todo.Archived { + t.Error("Completed should be false for new todos") + } +} + +func TestValidity(t *testing.T) { + todo := &Todo{Subject: "test"} + if !todo.Valid() { + t.Error("Expected valid todo to be valid") + } + + invalidTodo := &Todo{Subject: ""} + if invalidTodo.Valid() { + t.Error("Invalid todo is being reported as valid") + } +} diff --git a/todolist/todos.json b/todolist/todos.json new file mode 100644 index 0000000..dac8b93 --- /dev/null +++ b/todolist/todos.json @@ -0,0 +1 @@ +[{"subject":"this is the first subject","projects":[],"contexts":["root"],"due":"2016-04-04","completed":true,"id":1,"archived":true},{"subject":" audit userify for 2FA","projects":[],"contexts":[],"due":null,"completed":null,"id":2,"archived":false}] -- cgit v1.3