首頁 > 後端開發 > Golang > 主體

基於 Go CLI 的 Todo 應用程式

PHPz
發布: 2024-09-10 06:39:32
原創
1264 人瀏覽過

Go CLI based Todo app

Go CLI based Todo app

安裝使用的外部函式庫


去取得 github.com/aquasecurity/table

目錄結構

Go CLI based Todo app

主機程式

package main

func main() {
    todos := Todos{}

    storage := NewStorage[Todos]("todos.json")
    storage.Load(&todos)

    CmdFlags := NewCmdflags()
    CmdFlags.Execute(&todos)

    storage.Save(todos)
}
登入後複製
  1. 建立結構名稱為 Todos 的切片
  2. 在先前使用 storage.Save 建立的「todo.json」檔案中為系統中現有的待辦事項建立動態記憶體
  3. 如果沒有,它將載入為空
  4. 解析並驗證使用者提供的命令標誌
  5. 依照提供的標誌執行

功能實現

package main

import (
    "errors"
    "fmt"
    "os"
    "strconv"
    "time"

    "github.com/aquasecurity/table"
)

type Todo struct {
    Title     string
    Completed bool
    CreatedAt time.Time
    // this field here is a pointer reference because it can be null
    CompletedAt *time.Time
}

// a slice(array) of Todo
type Todos []Todo

// Passing Todo slice here as a reference
// declares a parameter named todos that is a pointer to a Todos slice.
// the function receives a copy of the slice under the name todos
func (todos *Todos) add(title string) {
    todo := Todo{
        Title:       title,
        Completed:   false,
        CompletedAt: nil,
        CreatedAt:   time.Now(),
    }
    *todos = append(*todos, todo)

}

func (todos *Todos) validateIndex(index int) error {
    if index < 0 || index >= len(*todos) {
        err := errors.New("invalid index")
        fmt.Println(err)
    }
    return nil
}

func (todos *Todos) delete(index int) error {
    t := *todos

    if err := t.validateIndex(index); err != nil {
        return err
    }

    *todos = append(t[:index], t[index+1:]...)

    return nil
}

func (todos *Todos) toggle(index int) error {
    t := *todos

    if err := t.validateIndex(index); err != nil {
        return err
    }

    isCompleted := t[index].Completed

    if !isCompleted {
        completionTime := time.Now()
        t[index].CompletedAt = &completionTime
    }

    t[index].Completed = !isCompleted

    return nil
}

func (todos *Todos) edit(index int, title string) error {
    t := *todos

    if err := t.validateIndex(index); err != nil {
        return err
    }

    t[index].Title = title

    return nil
}

func (todos *Todos) print() {
    table := table.New(os.Stdout)
    table.SetRowLines(false)
    table.SetHeaders("#", "Title", "Status", "Created", "Completed")

    for index, t := range *todos {
        mark := "❌"
        completedAt := ""

        if t.Completed {
            mark = "✅"
            if t.CompletedAt != nil {
                completedAt = t.CompletedAt.Format(time.RFC1123)
            }
        }
        table.AddRow(strconv.Itoa(index), t.Title, mark, t.CreatedAt.Format(time.RFC1123), completedAt)
    }

    table.Render()
}

登入後複製

儲存實現

package main

import (
    "encoding/json"
    "os"
)

type Storage[T any] struct {
    FileName string
}

func NewStorage[T any](filename string) *Storage[T] {
    return &Storage[T]{FileName: filename}
}

func (s *Storage[T]) Save(data T) error {
    fileData, err := json.MarshalIndent(data, "", "\t")

    if err != nil {
        return err
    }

    return os.WriteFile(s.FileName, fileData, 0644)

}

func (s *Storage[T]) Load(data *T) error {
    fileData, err := os.ReadFile(s.FileName)

    if err != nil {
        return err
    }

    return json.Unmarshal(fileData, data)
}
登入後複製

命令列標誌驗證和執行

package main

import (
    "flag"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type CmdFlags struct {
    Help   bool
    Add    string
    Del    int
    Edit   string
    Update int
    List   bool
}

func NewCmdflags() *CmdFlags {
    cf := CmdFlags{}

    flag.BoolVar(&cf.Help, "help", false, "List existing commands")
    flag.StringVar(&cf.Add, "add", "", "Add a new todo specify title")
    flag.StringVar(&cf.Edit, "edit", "", "Edit an existing todo, enter #index and specify a new title. \"id:new title\"")
    flag.IntVar(&cf.Del, "del", -1, "Specify a todo by #index to delete")
    flag.IntVar(&cf.Update, "update", -1, "Specify a todo #index to update")
    flag.BoolVar(&cf.List, "list", false, "List all todos")

    for _, arg := range os.Args[1:] {
        if strings.HasPrefix(arg, "-") && !isValidFlag(arg) {
            fmt.Printf("Unknown flag: %s\n", arg)
            fmt.Println("try --help to know more")

            os.Exit(0)
        }
    }

    flag.Parse()
    return &cf
}

func isValidFlag(flag string) bool {

    validFlags := []string{
        "-help", "--help",
        "-add", "--add",
        "-edit", "--edit",
        "-del", "--del",
        "-update", "--update",
        "-list", "--list",
    }

    if idx := strings.Index(flag, "="); idx != -1 {
        flag = flag[:idx]
    }

    for _, validFlag := range validFlags {
        if flag == validFlag {
            return true
        }
    }

    return false
}

func (cf *CmdFlags) Execute(todos *Todos) {
    switch {
    case cf.List:
        todos.print()

    case cf.Add != "":
        todos.add(cf.Add)

    case cf.Edit != "":
        parts := strings.SplitN(cf.Edit, ":", 2)
        if len(parts) != 2 {
            fmt.Printf("Error, invalid format for edit.\nCorrect Format: \"id:new title\" ")
            os.Exit(1)
        }

        index, err := strconv.Atoi(parts[0])

        if err != nil {
            fmt.Printf("Error, Invalid index for edit")
            os.Exit(1)
        }

        todos.edit(index, parts[1])

    case cf.Update != -1:
        todos.toggle(cf.Update)

    case cf.Del != -1:
        todos.delete(cf.Del)

    case cf.Help:
        fmt.Println("usage:")
        fmt.Println("--help\t\t| List existing commands")
        fmt.Println("--add\t\t| Add new task")
        fmt.Println("--del\t\t| Delete an existing task")
        fmt.Println("--update\t| Check/Uncheck existing task")
        fmt.Println("--edit\t\t| Edit an existing task")
    }
}
登入後複製

Github 儲存庫: CLI Todo 應用程式

以上是基於 Go CLI 的 Todo 應用程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板