43 — Project: a habit tracker
Guide 33 saved a todo list of dicts; guide 23 split a project across files. A habit tracker is one dict — each habit's days in a row — saved to JSON.
Steps
Storage lives in a module,
store.nme, exportingload()andsave(habits). A habit is a{name: days}dict entry;load()returns{}when no file exists yet:
run it →# store.nme — file storage for the habit tracker. import os use file latest def load(): if os.path.exists("habits.json"): return json_load("habits.json") return {} def save(habits): json_save("habits.json", habits)The whole project. Save
habit.nmenext tostore.nme:# habit.nme — a habit tracker that survives between runs. # Run: nme r habit from "store.nme" import load, save habits = load() while True: show "" show "Commands: add, check, streak, list, quit" ask command, "? " if command == "add": ask name, "Habit? " habits[name] = 0 save(habits) show f"Added: {name}" elif command == "check": ask name, "Habit? " if name in habits: habits[name] = habits[name] + 1 save(habits) show f"Checked: {name} ({habits[name]} in a row)" else: show f"No habit named {name}" elif command == "streak": ask name, "Habit? " show f"{name}: {habits.get(name, 0)} days in a row" elif command == "list": show f"{len(habits)} habits" for name in habits: show f"{name}: {habits[name]}" elif command == "quit": show "Bye!" breakaddstarts a habit at 0;checkadds 1 and saves;streakreads it back;listvisits every pair.Run it and feed the commands through a pipe:
printf 'add\nwater\ncheck\nwater\ncheck\nwater\nstreak\nwater\nlist\nquit\n' | nme r habitCommands: add, check, streak, list, quit ? Habit? Added: water Commands: add, check, streak, list, quit ? Habit? Checked: water (1 in a row) Commands: add, check, streak, list, quit ? Habit? Checked: water (2 in a row) Commands: add, check, streak, list, quit ? Habit? water: 2 days in a row Commands: add, check, streak, list, quit ? 1 habits water: 2 Commands: add, check, streak, list, quit ? Bye!The habit started at 0 and grew to 2 —
habits.jsonholds{"water": 2}. Korean writes the same menu with물어봐and말해— full pair in 43-habit.ko.md.
Try it yourself
Add a reset command that sets a habit back to 0 — one elif branch and a save.
What you learned
- A habit is a dict of
{name: days};habits[name] = habits[name] + 1grows a streak. - A module file owns
load()andsave(), and the main program imports them. json_savepersists the whole dict after every change.- A
while Truemenu withadd/check/streak/list/quitandbreakdrives the tracker.