diff options
Diffstat (limited to 'todolist')
| -rw-r--r-- | todolist/file_store.go | 34 | ||||
| -rw-r--r-- | todolist/file_store_test.go | 14 | ||||
| -rw-r--r-- | todolist/parser.go | 87 | ||||
| -rw-r--r-- | todolist/parser_test.go | 83 | ||||
| -rw-r--r-- | todolist/store.go | 11 | ||||
| -rw-r--r-- | todolist/todo_item.go | 22 | ||||
| -rw-r--r-- | todolist/todo_test.go | 23 | ||||
| -rw-r--r-- | todolist/todos.json | 1 |
8 files changed, 275 insertions, 0 deletions
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}] |
