patternMinor
Journal Application in D
Viewed 0 times
applicationjournalstackoverflow
Problem
Started picking up D recently. I wrote an application to create journal entries (text files) based on user input.
```
//this program will write to files. It should be able to read them.
//implement a command interface?
import std.stdio;
import std.string;
import std.datetime;
import fileio = std.file;
import std.conv;
enum Commands {exit = "EXIT", create = "CREATE"};
string menuText(){
return "\nType a command:\n\t- create\n\t- exit\n>";
}
void checkJournalEntriesFolder(){
string path = "journalEntries/";
if(fileio.exists(path) == 0){
writeln("Creating a journalEntries folder for you.");
fileio.mkdir(path);
}
}
string getFileName(){
return "entry_" ~ std.conv.to!string(stdTimeToUnixTime(Clock.currStdTime())) ~ ".txt";
}
int main(string[] argv)
{
writeln("\nWelcome to myJournal.");
checkJournalEntriesFolder();
string mode = "COMMAND";
char[] buf;
Commands command;
while (mode != "EXIT"){
while (mode == "COMMAND"){
string journalContent;
write(menuText);
stdin.readln(buf);
switch(toUpper(buf[0..$-1])) // cut off the /n at the end of the buffer.
{
case command.exit:
{
mode = "EXIT";
writeln("Oh, I'll exit.");
break;
}
case command.create:
{
writeln("create journal entry selected");
mode = "CREATE";
//create file
writeln("You are now typing in your journal.");
writeln("To exit this file, type #EOF");
writeln("----------------------------");
break;
}
default:
{
writeln("\nunrecognized command");
```
//this program will write to files. It should be able to read them.
//implement a command interface?
import std.stdio;
import std.string;
import std.datetime;
import fileio = std.file;
import std.conv;
enum Commands {exit = "EXIT", create = "CREATE"};
string menuText(){
return "\nType a command:\n\t- create\n\t- exit\n>";
}
void checkJournalEntriesFolder(){
string path = "journalEntries/";
if(fileio.exists(path) == 0){
writeln("Creating a journalEntries folder for you.");
fileio.mkdir(path);
}
}
string getFileName(){
return "entry_" ~ std.conv.to!string(stdTimeToUnixTime(Clock.currStdTime())) ~ ".txt";
}
int main(string[] argv)
{
writeln("\nWelcome to myJournal.");
checkJournalEntriesFolder();
string mode = "COMMAND";
char[] buf;
Commands command;
while (mode != "EXIT"){
while (mode == "COMMAND"){
string journalContent;
write(menuText);
stdin.readln(buf);
switch(toUpper(buf[0..$-1])) // cut off the /n at the end of the buffer.
{
case command.exit:
{
mode = "EXIT";
writeln("Oh, I'll exit.");
break;
}
case command.create:
{
writeln("create journal entry selected");
mode = "CREATE";
//create file
writeln("You are now typing in your journal.");
writeln("To exit this file, type #EOF");
writeln("----------------------------");
break;
}
default:
{
writeln("\nunrecognized command");
Solution
I'm not entirely sure what you are asking for, but if this were my program I would do a few things differently.
SQLite
I would place the journal entries in a sqlite database rather than raw files and directories.
D provides an interface to sqlite. Sqlite provides great abstraction over raw files. Keeping your files consistent, and not corrupting them is difficult. sqlite already does the right thing, and more!
Command Pattern instead of switch
I would provide a nicer abstraction for commands instead of a switch statement. This Python code works as a template.
By implementing a switch statement, each new command increases the cyclomatic-complexity of the main() function. Thus your testing requirements increase exponentially. By breaking out each command to implement an ICommand interface, your testing requirement increases linearly. The visitor pattern might also provide a nice mechanism to process each command.
SQLite
I would place the journal entries in a sqlite database rather than raw files and directories.
D provides an interface to sqlite. Sqlite provides great abstraction over raw files. Keeping your files consistent, and not corrupting them is difficult. sqlite already does the right thing, and more!
Command Pattern instead of switch
I would provide a nicer abstraction for commands instead of a switch statement. This Python code works as a template.
By implementing a switch statement, each new command increases the cyclomatic-complexity of the main() function. Thus your testing requirements increase exponentially. By breaking out each command to implement an ICommand interface, your testing requirement increases linearly. The visitor pattern might also provide a nice mechanism to process each command.
Context
StackExchange Code Review Q#100847, answer score: 3
Revisions (0)
No revisions yet.