From 2976acd639b57853df315f80172b61ff75b9d7f3 Mon Sep 17 00:00:00 2001 From: Stuart Skelton Date: Sun, 6 Aug 2017 21:40:19 +0100 Subject: Allow for ranged ids in some commands --- todolist/app.go | 72 +++++++++++++++++++++++---------- todolist/app_test.go | 18 +++++++++ todolist/todo_list.go | 110 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 142 insertions(+), 58 deletions(-) diff --git a/todolist/app.go b/todolist/app.go index 367cc2f..5045fdf 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -38,55 +38,55 @@ func (a *App) AddTodo(input string) { func (a *App) DeleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Delete(id) + a.TodoList.Delete(ids...) a.Save() fmt.Println("Todo deleted.") } func (a *App) CompleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Complete(id) + a.TodoList.Complete(ids...) a.Save() fmt.Println("Todo completed.") } func (a *App) UncompleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Uncomplete(id) + a.TodoList.Uncomplete(ids...) a.Save() fmt.Println("Todo uncompleted.") } func (a *App) ArchiveTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Archive(id) + a.TodoList.Archive(ids...) a.Save() fmt.Println("Todo archived.") } func (a *App) UnarchiveTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Unarchive(id) + a.TodoList.Unarchive(ids...) a.Save() fmt.Println("Todo unarchived.") } @@ -154,22 +154,22 @@ func (a *App) ListTodos(input string) { func (a *App) PrioritizeTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Prioritize(id) + a.TodoList.Prioritize(ids...) a.Save() fmt.Println("Todo prioritized.") } func (a *App) UnprioritizeTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Unprioritize(id) + a.TodoList.Unprioritize(ids...) a.Save() fmt.Println("Todo un-prioritized.") } @@ -193,6 +193,36 @@ func (a *App) getId(input string) (int, *Todo) { } } +func (a *App) getIds(input string) []int { + var ids []int + idGroups := strings.Split(input, ",") + + singleNumberRE, _ := regexp.Compile("\\d+") + rangeNumberRE, _ := regexp.Compile("(\\d+)-(\\d+)") + + for _, idGroup := range idGroups { + if matches := rangeNumberRE.FindStringSubmatch(idGroup); len(matches) > 0 { + lowerID, _ := strconv.Atoi(matches[1]) + upperID, _ := strconv.Atoi(matches[2]) + if lowerID >= upperID { + fmt.Printf("Invalid id group: %s.\n", idGroup) + break + } + for id := lowerID; id <= upperID; id++ { + ids = append(ids, id) + } + + } else if singleNumberRE.MatchString(idGroup) { + id, _ := strconv.Atoi(singleNumberRE.FindString(idGroup)) + ids = append(ids, id) + + } else { + fmt.Printf("Invalid id: %s.\n", idGroup) + } + } + return ids +} + func (a *App) getGroups(input string, todos []*Todo) *GroupedTodos { grouper := &Grouper{} contextRegex, _ := regexp.Compile(`by c.*$`) diff --git a/todolist/app_test.go b/todolist/app_test.go index f29a1b6..72a0292 100644 --- a/todolist/app_test.go +++ b/todolist/app_test.go @@ -108,3 +108,21 @@ func TestListbyContext(t *testing.T) { } assert.Equal(true, hasACompletedTodo) } + +func TestGetIds(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + // no valid id here + assert.Equal(0, len(app.getIds("p"))) + // one valid value here + assert.Equal([]int{6}, app.getIds("6")) + // lots of single post numbers + assert.Equal([]int{6, 10, 8, 4}, app.getIds("6,10,8,4")) + // a correct range + assert.Equal([]int{6, 7, 8}, app.getIds("6-8")) + // some incorrect ranges + assert.Equal(0, len(app.getIds("6-6"))) + assert.Equal(0, len(app.getIds("8-6"))) + // some compsite ranges + assert.Equal([]int{5, 6, 7, 8, 10, 11, 9}, app.getIds("5,6-8,10-11,9")) +} diff --git a/todolist/todo_list.go b/todolist/todo_list.go index 4623a22..dc3add4 100644 --- a/todolist/todo_list.go +++ b/todolist/todo_list.go @@ -15,57 +15,93 @@ func (t *TodoList) Add(todo *Todo) { t.Data = append(t.Data, todo) } -func (t *TodoList) Delete(id int) { - i := -1 - for index, todo := range t.Data { - if todo.Id == id { - i = index +func (t *TodoList) Delete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + break + } + i := -1 + for index, todo := range t.Data { + if todo.Id == id { + i = index + } } - } - t.Data = append(t.Data[:i], t.Data[i+1:]...) + t.Data = append(t.Data[:i], t.Data[i+1:]...) + } } -func (t *TodoList) Complete(id int) { - todo := t.FindById(id) - todo.Complete() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Complete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Complete() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Uncomplete(id int) { - todo := t.FindById(id) - todo.Uncomplete() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Uncomplete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Uncomplete() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Archive(id int) { - todo := t.FindById(id) - todo.Archive() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Archive(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Archive() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Unarchive(id int) { - todo := t.FindById(id) - todo.Unarchive() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Unarchive(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Unarchive() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Prioritize(id int) { - todo := t.FindById(id) - todo.Prioritize() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Prioritize(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Prioritize() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Unprioritize(id int) { - todo := t.FindById(id) - todo.Unprioritize() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Unprioritize(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Unprioritize() + t.Delete(id) + t.Data = append(t.Data, todo) + } } func (t *TodoList) IndexOf(todoToFind *Todo) int { -- cgit v1.3 From d435ab85b203765e27b165d47e6155a73d84034c Mon Sep 17 00:00:00 2001 From: Stuart Skelton Date: Tue, 8 Aug 2017 16:11:37 +0100 Subject: Swap a break for a continue. --- todolist/todo_list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todolist/todo_list.go b/todolist/todo_list.go index dc3add4..55c250d 100644 --- a/todolist/todo_list.go +++ b/todolist/todo_list.go @@ -19,7 +19,7 @@ func (t *TodoList) Delete(ids ...int) { for _, id := range ids { todo := t.FindById(id) if todo == nil { - break + continue } i := -1 for index, todo := range t.Data { -- cgit v1.3 From 8f8dcb6def8ef78c6b144f96e61dc627dd1cc3a8 Mon Sep 17 00:00:00 2001 From: Stuart Skelton Date: Tue, 8 Aug 2017 19:36:58 +0100 Subject: Refactor GetID to only return an ID, and not a ID and Todo --- todolist/app.go | 33 +++++++++++++-------------------- todolist/app_test.go | 11 +++++++++++ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/todolist/app.go b/todolist/app.go index 5045fdf..ffac17f 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -93,10 +93,15 @@ func (a *App) UnarchiveTodo(input string) { func (a *App) EditTodo(input string) { a.Load() - id, todo := a.getId(input) + id := a.getId(input) if id == -1 { return } + todo := a.TodoList.FindById(id) + if todo == nil { + fmt.Println("No such id.") + return + } parser := &Parser{} if parser.ParseEditTodo(todo, input) { @@ -107,7 +112,7 @@ func (a *App) EditTodo(input string) { func (a *App) ExpandTodo(input string) { a.Load() - id, _ := a.getId(input) + id := a.getId(input) parser := &Parser{} if id == -1 { return @@ -174,30 +179,21 @@ func (a *App) UnprioritizeTodo(input string) { fmt.Println("Todo un-prioritized.") } -func (a *App) getId(input string) (int, *Todo) { +func (a *App) getId(input string) int { re, _ := regexp.Compile("\\d+") if re.MatchString(input) { id, _ := strconv.Atoi(re.FindString(input)) - todo := a.TodoList.FindById(id) - if todo == nil { - fmt.Println("No such id.") - return -1, nil - - } - return id, todo - - } else { - fmt.Println("Invalid id.") - return -1, nil - + return id } + + fmt.Println("Invalid id.") + return -1 } func (a *App) getIds(input string) []int { var ids []int idGroups := strings.Split(input, ",") - singleNumberRE, _ := regexp.Compile("\\d+") rangeNumberRE, _ := regexp.Compile("(\\d+)-(\\d+)") for _, idGroup := range idGroups { @@ -211,11 +207,8 @@ func (a *App) getIds(input string) []int { for id := lowerID; id <= upperID; id++ { ids = append(ids, id) } - - } else if singleNumberRE.MatchString(idGroup) { - id, _ := strconv.Atoi(singleNumberRE.FindString(idGroup)) + } else if id := a.getId(idGroup); id != -1 { ids = append(ids, id) - } else { fmt.Printf("Invalid id: %s.\n", idGroup) } diff --git a/todolist/app_test.go b/todolist/app_test.go index 72a0292..2fb7717 100644 --- a/todolist/app_test.go +++ b/todolist/app_test.go @@ -109,6 +109,17 @@ func TestListbyContext(t *testing.T) { assert.Equal(true, hasACompletedTodo) } +func TestGetId(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + // not a valid id + assert.Equal(-1, app.getId("p")) + // a single digit id + assert.Equal(6, app.getId("6")) + // a double digit id + assert.Equal(66, app.getId("66")) +} + func TestGetIds(t *testing.T) { assert := assert.New(t) app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} -- cgit v1.3 From 180dd57d27f8d7b0add8005ee46026e6f89fabbb Mon Sep 17 00:00:00 2001 From: Stuart Skelton Date: Tue, 8 Aug 2017 21:00:12 +0100 Subject: Refactor getIds so the parsing can be reused. --- todolist/app.go | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/todolist/app.go b/todolist/app.go index ffac17f..d4513ac 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -190,23 +190,16 @@ func (a *App) getId(input string) int { return -1 } -func (a *App) getIds(input string) []int { - var ids []int - idGroups := strings.Split(input, ",") - - rangeNumberRE, _ := regexp.Compile("(\\d+)-(\\d+)") +func (a *App) getIds(input string) (ids []int) { + idGroups := strings.Split(input, ",") for _, idGroup := range idGroups { - if matches := rangeNumberRE.FindStringSubmatch(idGroup); len(matches) > 0 { - lowerID, _ := strconv.Atoi(matches[1]) - upperID, _ := strconv.Atoi(matches[2]) - if lowerID >= upperID { - fmt.Printf("Invalid id group: %s.\n", idGroup) - break - } - for id := lowerID; id <= upperID; id++ { - ids = append(ids, id) + if rangedIds, err := a.parseRangedIds(idGroup); len(rangedIds) > 0 || err != nil { + if err != nil { + fmt.Printf("Invalid id group: %s.\n", input) + continue } + ids = append(ids, rangedIds...) } else if id := a.getId(idGroup); id != -1 { ids = append(ids, id) } else { @@ -216,6 +209,21 @@ func (a *App) getIds(input string) []int { return ids } +func (a *App) parseRangedIds(input string) (ids []int, err error) { + rangeNumberRE, _ := regexp.Compile("(\\d+)-(\\d+)") + if matches := rangeNumberRE.FindStringSubmatch(input); len(matches) > 0 { + lowerID, _ := strconv.Atoi(matches[1]) + upperID, _ := strconv.Atoi(matches[2]) + if lowerID >= upperID { + return ids, fmt.Errorf("Invalid id group: %s.\n", input) + } + for id := lowerID; id <= upperID; id++ { + ids = append(ids, id) + } + } + return ids, err +} + func (a *App) getGroups(input string, todos []*Todo) *GroupedTodos { grouper := &Grouper{} contextRegex, _ := regexp.Compile(`by c.*$`) -- cgit v1.3 From b1607ce3bfaf54936338d8639087dee52f7d7bc2 Mon Sep 17 00:00:00 2001 From: Stuart Skelton Date: Sat, 12 Aug 2017 17:35:05 +0100 Subject: Have a util function to pluralize todo. --- todolist/app.go | 2 +- todolist/util.go | 7 +++++++ todolist/util_test.go | 13 +++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 todolist/util_test.go diff --git a/todolist/app.go b/todolist/app.go index d4513ac..f63c41b 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -44,7 +44,7 @@ func (a *App) DeleteTodo(input string) { } a.TodoList.Delete(ids...) a.Save() - fmt.Println("Todo deleted.") + fmt.Printf("%s deleted.\n", pluralize(len(ids), "Todo", "Todos")) } func (a *App) CompleteTodo(input string) { diff --git a/todolist/util.go b/todolist/util.go index 34f9dd1..ff3dbba 100644 --- a/todolist/util.go +++ b/todolist/util.go @@ -52,3 +52,10 @@ func getNearestMonday(t time.Time) time.Time { } } } + +func pluralize(count int, singular, plural string) string { + if count > 1 { + return plural + } + return singular +} diff --git a/todolist/util_test.go b/todolist/util_test.go new file mode 100644 index 0000000..40ecb54 --- /dev/null +++ b/todolist/util_test.go @@ -0,0 +1,13 @@ +package todolist + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPluralize(t *testing.T) { + assert := assert.New(t) + assert.Equal("todo", pluralize(1, "todo", "todos")) + assert.Equal("todos", pluralize(2, "todo", "todos")) +} -- cgit v1.3