DictMinder: Setup Project ~ Parsing commands
DictMinder DIY is CLI english dictionary and word reminder.
Why am I making this?
As a Korean, I am struggling with being familiar with English.
The hardest part is memorizing words—when I learn something new, I forget it in a few days.
One day, I thought “Wouldn’t it be nice if something reminded me of the words repeatedly and unconsciously?”
So, I started this project.
Features
Store word data
Can be added by interactions(manually with standard I/O)
Can be addad by external API
Can be added by JSON file
Can be added by CSV file
Delete word data
Show word(s) with definitions (+ randomly)
- By appending this command in the end of
~/.zshrc
, we can see random words when terminal is initialized.
- By appending this command in the end of
And so on..
Database Table
I made two tables: words
and definitions
.
Words can have 0~N definitions.
While definition must have one word.
All columns has ‘NOT NULL’ constraint.
Connecting to Database & Creating Table
Here’s the package I imported:
database/sql
: standard db connection librarymodernc.org/sqlite
: sqlite engine with pure go
package db
import (
"database/sql"
"log"
_ "modernc.org/sqlite"
)
type Database struct {
DB *sql.DB
}
func NewDatabase() (*Database, error) {
DB, err := sql.Open("sqlite", "data.db?_foreign_keys=on")
if err != nil {
return nil, err
}
return &Database{DB: DB}, nil
}
func (d *Database) Close() {
if d.DB != nil {
err := d.DB.Close()
if err != nil {
log.Fatal("Failed to close DB:\n", err.Error())
}
}
}
func (d *Database) InitTable() error {
tx, err := d.DB.Begin()
if err != nil {
return err
}
defer tx.Rollback()
_, err = tx.Exec(`
CREATE TABLE IF NOT EXISTS words (
word_id INTEGER PRIMARY KEY AUTOINCREMENT,
content VARCHAR(255) NOT NULL
);
`)
if err != nil {
return err
}
_, err = tx.Exec(`
CREATE TABLE IF NOT EXISTS definitions (
definition_id INTEGER PRIMARY KEY AUTOINCREMENT,
word_id INTEGER NOT NULL,
pos VARCHAR(255) NOT NULL,
def text NOT NULL,
FOREIGN KEY(word_id) REFERENCES words(word_id) ON DELETE CASCADE
);
`)
if err != nil {
return err
}
return tx.Commit()
}
In main:
// Connect To Database(SQLite)
database, err := db.NewDatabase()
if err != nil {
log.Println("[DictMinder] DB connection Failed: \n", err.Error())
return
}
defer database.Close()
err = database.InitTable()
if err != nil {
log.Println("[DictMinder] DB table initialization failed: \n", err.Error())
return
}
Defining Commands
dictminder -v
: show current versiondictminder -r <n>
: randomly show word <n> times.dictminder -ai <word>
: add <word> with standard I/O interaction.dictminder -aa <word>
: add <word> via external apidictminder -aj <json file>
: add words from json filedictminder -ac <dictdata.csv>
: add words from csv filedictminder —license
: show licensedictminder -q <word>
search about <word>.dictminder -e <word>
delete <word> in database.dictminder -l <n>
list <n> words in date order(oldest to newest)dictminder --enable-autoload
→ enable random word show when terminal session created.dictminder --disable-autoload
→ disable it.
Parsing flags
Imported package flag
to parsing flag arguments.
The number of flags were 11, So flags can be managed by one integer with bitmask.
// Set Const Bit Flags..
const (
FlagVersion = 1 << iota
FlagRandom
FlagInteractive
FlagAPI
FlagJSON
FlagCSV
FlagLicense
FlagQuery
FlagErase
FlagList
FlagEnableAutoload
FlagDisableAutoload
)
// flag variables
var (
version bool
randomWord int
appendWithIntraction bool
appendWithAPI string
appendWithJSON string
appendWithCSV string
license bool
query string
erase string
list int
enableAutoload bool
disableAutoload bool
total int = 0 // total flags
)
Attach flags with variables with default value and help messages..
Check Each flags whether is different from its default value.
If total
is not power of 2, multiple flags were turned on.
So, print error message and exit.
flag.BoolVar(&version, "v", false, "Print current version of this program.")
flag.IntVar(&randomWord, "r", 0, "Print random word with definition `<x>` times")
flag.StringVar(&appendWithIntraction, "ai", "", "Add word `<word>` to DB via interaction")
flag.StringVar(&appendWithAPI, "aa", "", "Add word `<word>` to DB via Dictionary API.")
flag.StringVar(&appendWithJSON, "aj", "", "Add word(s) to DB via JSON File `<path>`")
flag.StringVar(&appendWithCSV, "ac", "", "Add word(s) to DB via CSV File `<path>`")
flag.BoolVar(&license, "license", false, "Print license of this program")
flag.StringVar(&query, "q", "", "Search `<word>` in DB.")
flag.StringVar(&erase, "e", "", "Erase a `<word>` from the DB.")
flag.IntVar(&list, "l", 0, "Print list of last-appended words with `<x>` rows")
flag.BoolVar(&enableAutoload, "enable-autoload", false, "Enable to print a single random word when terminal session is created.")
flag.BoolVar(&disableAutoload, "disable-autoload", false, "Disable to print a single random word when terminal session is created")
flag.Parse()
// Flag check wiht bitmask..
if version {
total |= FlagVersion
}
if randomWord > 0 {
total |= FlagRandom
}
if appendWithIntraction != "" {
total |= FlagInteractive
}
if appendWithAPI != "" {
total |= FlagAPI
}
if appendWithJSON != "" {
total |= FlagJSON
}
if appendWithCSV != "" {
total |= FlagCSV
}
if license {
total |= FlagLicense
}
if query != "" {
total |= FlagQuery
}
if erase != "" {
total |= FlagErase
}
if list > 0 {
total |= FlagList
}
if enableAutoload {
total |= FlagEnableAutoload
}
if disableAutoload {
total |= FlagDisableAutoload
}
// If multiple flags are used, then error
if total&(total-1) != 0 {
log.Println("[DictMinder] You can use only one flag for a command.")
exit
}
This is the help message.
❯ go run main.go -h
Usage of ....-d/main:
-aa <word>
Add word <word> to DB via Dictionary API.
-ac <path>
Add word(s) to DB via CSV File <path>
-ai <word>
Add word <word> to DB via interaction
-aj <path>
Add word(s) to DB via JSON File <path>
-disable-autoload
Disable to print a single random word when terminal session is created
-e <word>
Erase a <word> from the DB.
-enable-autoload
Enable to print a single random word when terminal session is created.
-l <x>
Print list of last-appended words with <x> rows
-license
Print license of this program
-q <word>
Search <word> in DB.
-r <x>
Print random word with definition <x> times
-v Print current version of this program.
To do next:
Connect to DatabaseParsing FlagsFlag-to-command Routing
Implement each command
Test
Version tagging
Build tools
Deploy