aboutsummaryrefslogtreecommitdiffstats
path: root/todolist
diff options
context:
space:
mode:
authorGrant Ammons <gammons@gmail.com>2016-04-24 10:22:33 -0400
committerGrant Ammons <gammons@gmail.com>2016-04-24 10:22:33 -0400
commit63893587cb41a1980318b60bf05fafbf433a24ab (patch)
tree39c93f3a1735ef33d028ab9ef44fc0ac15049208 /todolist
parent6bb90375f4efb2f390a61ede0df70eea1ef1f50f (diff)
Organize things a bit better
Diffstat (limited to 'todolist')
-rw-r--r--todolist/file_store.go34
-rw-r--r--todolist/file_store_test.go14
-rw-r--r--todolist/parser.go87
-rw-r--r--todolist/parser_test.go83
-rw-r--r--todolist/store.go11
-rw-r--r--todolist/todo_item.go22
-rw-r--r--todolist/todo_test.go23
-rw-r--r--todolist/todos.json1
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}]