Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
3
Task/Simple-database/00-META.yaml
Normal file
3
Task/Simple-database/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Simple_database
|
||||
note: Data Structures
|
||||
37
Task/Simple-database/00-TASK.txt
Normal file
37
Task/Simple-database/00-TASK.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
;Task:
|
||||
Write a simple tool to track a small set of data.
|
||||
|
||||
The tool should have a command-line interface to enter at least two different values.
|
||||
|
||||
The entered data should be stored in a structured format and saved to disk.
|
||||
|
||||
It does not matter what kind of data is being tracked. It could be a collection (CDs, coins, baseball cards, books), a diary, an electronic organizer (birthdays/anniversaries/phone numbers/addresses), etc.
|
||||
|
||||
|
||||
You should track the following details:
|
||||
* A description of the item. (e.g., title, name)
|
||||
* A category or tag (genre, topic, relationship such as “friend” or “family”)
|
||||
* A date (either the date when the entry was made or some other date that is meaningful, like the birthday); the date may be generated or entered manually
|
||||
* Other optional fields
|
||||
|
||||
<br>
|
||||
The command should support the following [[Command-line arguments]] to run:
|
||||
* Add a new entry
|
||||
* Print the latest entry
|
||||
* Print the latest entry for each category
|
||||
* Print all entries sorted by a date
|
||||
|
||||
<br>
|
||||
The category may be realized as a tag or as structure (by making all entries in that category subitems)
|
||||
|
||||
The file format on disk should be human readable, but it need not be standardized. A natively available format that doesn't need an external library is preferred. Avoid developing your own format if you can use an already existing one. If there is no existing format available, pick one of:
|
||||
:::* [[JSON]]
|
||||
:::* [[S-Expressions]]
|
||||
:::* [[YAML]]
|
||||
:::* [[wp:Comparison_of_data_serialization_formats|others]]
|
||||
|
||||
|
||||
;Related task:
|
||||
* [[Take notes on the command line]]
|
||||
<br><br>
|
||||
|
||||
79
Task/Simple-database/11l/simple-database.11l
Normal file
79
Task/Simple-database/11l/simple-database.11l
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
T Item
|
||||
String name, date, category
|
||||
|
||||
F (name, date, category)
|
||||
.name = name
|
||||
.date = date
|
||||
.category = category
|
||||
|
||||
F String()
|
||||
R .name‘, ’(.date)‘, ’(.category)
|
||||
|
||||
V db_filename = ‘simdb.csv’
|
||||
|
||||
F load()
|
||||
[Item] db
|
||||
L(line) File(:db_filename).read().rtrim("\n").split("\n")
|
||||
V item = line.split(‘, ’)
|
||||
db.append(Item(item[0], item[1], item[2]))
|
||||
R db
|
||||
|
||||
F store(item)
|
||||
File(:db_filename, ‘a’).write(String(item)"\n")
|
||||
|
||||
F printUsage()
|
||||
print(|‘
|
||||
Usage:
|
||||
simdb cmd [categoryName]
|
||||
add add item, followed by optional category
|
||||
latest print last added item(s), followed by optional category
|
||||
all print all
|
||||
For instance: add "some item name" "some category name’)
|
||||
|
||||
F addItem(args)
|
||||
I args.len < 2
|
||||
printUsage()
|
||||
R
|
||||
|
||||
V date = Time().strftime(‘%Y-%m-%d %H:%M:%S’)
|
||||
V cat = I args.len == 3 {args[2]} E ‘none’
|
||||
store(Item(args[1], date, cat))
|
||||
|
||||
F printLatest(a)
|
||||
V db = load()
|
||||
I db.empty
|
||||
print(‘No entries in database.’)
|
||||
R
|
||||
|
||||
I a.len == 2
|
||||
L(item) reversed(db)
|
||||
I item.category == a[1]
|
||||
print(item)
|
||||
L.break
|
||||
L.was_no_break
|
||||
print(‘There are no items for category '’a[1]‘'’)
|
||||
E
|
||||
print(db.last)
|
||||
|
||||
F printAll()
|
||||
V db = load()
|
||||
I db.empty
|
||||
print(‘No entries in database.’)
|
||||
R
|
||||
|
||||
L(item) db
|
||||
print(item)
|
||||
|
||||
:start:
|
||||
I :argv.len C 2..4
|
||||
S :argv[1].lowercase()
|
||||
‘add’
|
||||
addItem(:argv[1..])
|
||||
‘latest’
|
||||
printLatest(:argv[1..])
|
||||
‘all’
|
||||
printAll()
|
||||
E
|
||||
printUsage()
|
||||
E
|
||||
printUsage()
|
||||
79
Task/Simple-database/Bracmat/simple-database.bracmat
Normal file
79
Task/Simple-database/Bracmat/simple-database.bracmat
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
whl
|
||||
' ( arg$:?command
|
||||
& ( get'db
|
||||
| (db=1)&lst$(db,db,NEW)
|
||||
)
|
||||
& !command
|
||||
: ( add
|
||||
& :?name:?tag:?date
|
||||
& whl
|
||||
' ( arg$:?argmnt
|
||||
& arg$:?value
|
||||
& (!argmnt.!value)
|
||||
: ( (title|name.?name)
|
||||
| (category|tag.?tag)
|
||||
| (date.?date)
|
||||
)
|
||||
)
|
||||
& ( !name:~
|
||||
& !tag:~
|
||||
& !date:~
|
||||
& ( !db:?*!tag^(?+(!date.!name)+?)*?
|
||||
& out$"This record already exists"
|
||||
| !tag^(!date.!name)*!db:?db
|
||||
& lst$(db,db,NEW)
|
||||
)
|
||||
| out$"invalid data"
|
||||
)
|
||||
| latest
|
||||
& :?date
|
||||
& nothing found:?latest
|
||||
& ( !db
|
||||
: ?
|
||||
* ?tag
|
||||
^ ( ?
|
||||
+ ( (>!date:?date.?name)
|
||||
& (!name,!tag,!date):?latest
|
||||
& ~
|
||||
)
|
||||
+ ?
|
||||
)
|
||||
* ?
|
||||
| out$!latest
|
||||
)
|
||||
| latest/category
|
||||
& :?date:?latests:?latest
|
||||
& ( !db
|
||||
: ?
|
||||
* ( ?tag
|
||||
& !latests !latest:?latests
|
||||
& :?latest:?date
|
||||
)
|
||||
^ ( ?
|
||||
+ ( (>!date:?date.?name)
|
||||
& (!name,!tag,!date):?latest
|
||||
& ~
|
||||
)
|
||||
+ ?
|
||||
)
|
||||
* ?
|
||||
| !latests !latest:?latests&out$!latests
|
||||
)
|
||||
| sorted
|
||||
& 0:?sorted
|
||||
& ( !db
|
||||
: ?
|
||||
* ?tag
|
||||
^ ( ?
|
||||
+ ( (?date.?name)
|
||||
& (!date.!name,!tag,!date)+!sorted:?sorted
|
||||
& ~
|
||||
)
|
||||
+ ?
|
||||
)
|
||||
* ?
|
||||
| whl
|
||||
' (!sorted:(?.?row)+?sorted&out$!row)
|
||||
)
|
||||
)
|
||||
);
|
||||
323
Task/Simple-database/C-sharp/simple-database.cs
Normal file
323
Task/Simple-database/C-sharp/simple-database.cs
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Simple_database
|
||||
{
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
//
|
||||
// For appropriate use of this program
|
||||
// use standard Windows Command Processor or cmd.exe
|
||||
//
|
||||
// Create cmd.bat file at the same folder with executive version
|
||||
// of program Simple_database.exe, so when started, the correct
|
||||
// file path will be automatically set to cmd console.
|
||||
//
|
||||
// Start notepad, write only cmd.exe and save file as cmd.bat
|
||||
//
|
||||
// To start cmd just double click at cmd.bat file.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Console application command line start command
|
||||
//
|
||||
// application name.exe [argument] [argument parameters]
|
||||
//
|
||||
//
|
||||
// Command line argument followed by parameters
|
||||
//
|
||||
// [a] - Add new entry
|
||||
//
|
||||
// ["data1"]["data2"]["data3"]...["data n"]
|
||||
//
|
||||
// ["data1"] - Data category !
|
||||
// ["data2"] - Data
|
||||
// ["data3"] - Data
|
||||
//
|
||||
//
|
||||
// NOTICE !
|
||||
//
|
||||
// First parameter is taken for data category.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Command line argument with no parameters
|
||||
//
|
||||
// [p1] - Print the latest entry
|
||||
//
|
||||
// [p2] - Print the latest entry for each category
|
||||
//
|
||||
// [p3] - Print all entries sorted by a date
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
// Command line example
|
||||
//
|
||||
// Small_database.exe [a] ["home"] ["+398125465458"] ["My tel number"]
|
||||
//
|
||||
// Small_database.exe [a] ["office"] ["+398222789000"] ["Boss"]
|
||||
//
|
||||
// Small_database.exe [a] [cd] ["Action movie"] ["Movie title"]
|
||||
// Small_database.exe [a] [cd] ["SF movie"] ["Movie title"]
|
||||
// Small_database.exe [a] [dvd] ["Action movie"] ["Movie title"]
|
||||
//
|
||||
//
|
||||
// NOTICE !
|
||||
//
|
||||
// Brackets and space between arguments and parameters are necessary.
|
||||
// Quotes must be used when parameters have more than one word.
|
||||
//
|
||||
// If not used as shown in examples, program will show error message.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Check command line for arguments
|
||||
//
|
||||
//
|
||||
if(args.Length==0)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Missing Argument Error. ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (args[0])
|
||||
{
|
||||
case "[a]" : Add_New_Entry(args);
|
||||
break;
|
||||
|
||||
case "[p1]": Print_Document("Print the latest entry.txt");
|
||||
break;
|
||||
|
||||
case "[p2]": Print_Document("Print the latest entry for each category.txt");
|
||||
break;
|
||||
|
||||
case "[p3]": Print_Document("Print all entries sorted by a date.txt");
|
||||
break;
|
||||
|
||||
default :
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Incorrect Argument Error. ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Add_New_Entry(string [] args)
|
||||
{
|
||||
|
||||
//
|
||||
// Check parameters
|
||||
//
|
||||
//
|
||||
// Minimum one parameter, category
|
||||
//
|
||||
if(args.Length==1)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Missing Parameters Error..... ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool parameters_ok = true;
|
||||
foreach (string a in args)
|
||||
{
|
||||
if(!a.StartsWith("[") || !a.EndsWith("]"))
|
||||
{
|
||||
parameters_ok = !parameters_ok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Add new entry to Data base document
|
||||
//
|
||||
if(parameters_ok)
|
||||
{
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Parameters are ok..... ");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Writing new entry to database..... ");
|
||||
//
|
||||
// Create new Data base entry
|
||||
//
|
||||
args[0] = string.Empty;
|
||||
string line = string.Empty;
|
||||
foreach (string a in args)
|
||||
{
|
||||
line+=a;
|
||||
}
|
||||
line+="[" + DateTime.Now.ToString() + "]";
|
||||
args[0] = "[" + DateTime.Now.ToString() + "]";
|
||||
//
|
||||
// Write entry to Data base
|
||||
//
|
||||
StreamWriter w = new StreamWriter("Data base.txt",true);
|
||||
w.WriteLine(line);
|
||||
//
|
||||
// Close and dispose stream writer
|
||||
//
|
||||
w.Close();
|
||||
w.Dispose();
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" New entry is written to database. ");
|
||||
|
||||
Create_Print_Documents(args);
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Add new entry command executed. ");
|
||||
//
|
||||
//
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" ! Parameters are not ok ! ");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Add new entry command is not executed. ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Create_Print_Documents(string [] args)
|
||||
{
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Creating new print documents. ");
|
||||
//
|
||||
// Create "Print all entries sorted by a date.txt"
|
||||
//
|
||||
File.Copy("Data base.txt","Print all entries sorted by a date.txt",true);
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Print all entries sorted by a date.txt created. ");
|
||||
//
|
||||
// Create "Print the latest entry.txt"
|
||||
//
|
||||
//
|
||||
// Create new entry
|
||||
//
|
||||
string line = string.Empty;
|
||||
foreach (string a in args)
|
||||
{
|
||||
line+=a;
|
||||
}
|
||||
//
|
||||
StreamWriter w = new StreamWriter("Print the latest entry.txt");
|
||||
//
|
||||
w.WriteLine(line);
|
||||
//
|
||||
w.Close();
|
||||
w.Dispose();
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Print the latest entry.txt created. ");
|
||||
//
|
||||
// Create "Print the latest entry for each category.txt"
|
||||
//
|
||||
string latest_entry = string.Empty;
|
||||
foreach (string a in args)
|
||||
{
|
||||
latest_entry+=a;
|
||||
}
|
||||
|
||||
if(!File.Exists("Print the latest entry for each category.txt"))
|
||||
{
|
||||
File.WriteAllText("Print the latest entry for each category.txt",latest_entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
StreamReader r = new StreamReader("Print the latest entry for each category.txt");
|
||||
//
|
||||
w = new StreamWriter("Print the latest entry for each category 1.txt",true);
|
||||
//
|
||||
line = string.Empty;
|
||||
//
|
||||
while(!r.EndOfStream)
|
||||
{
|
||||
line = r.ReadLine();
|
||||
if(line.Contains(args[1].ToString()))
|
||||
{
|
||||
w.WriteLine(latest_entry);
|
||||
latest_entry = "ok";
|
||||
}
|
||||
else
|
||||
{
|
||||
w.WriteLine(line);
|
||||
}
|
||||
}
|
||||
// add new category
|
||||
if(latest_entry != "ok")
|
||||
w.WriteLine(latest_entry);
|
||||
//
|
||||
w.Close();
|
||||
w.Dispose();
|
||||
//
|
||||
r.Close();
|
||||
r.Dispose();
|
||||
//
|
||||
File.Copy("Print the latest entry for each category 1.txt",
|
||||
"Print the latest entry for each category.txt",true);
|
||||
//
|
||||
File.Delete("Print the latest entry for each category 1.txt");
|
||||
//
|
||||
//
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Print the latest entry for each category.txt created. ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void Print_Document(string file_name)
|
||||
{
|
||||
//
|
||||
// Print document
|
||||
//
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(file_name.Replace(".txt","")+ " : ");
|
||||
Console.WriteLine();
|
||||
//
|
||||
StreamReader r = new StreamReader(file_name);
|
||||
//
|
||||
string line = string.Empty;
|
||||
//
|
||||
line = r.ReadToEnd();
|
||||
//
|
||||
Console.WriteLine(line);
|
||||
//
|
||||
r.Close();
|
||||
r.Dispose();
|
||||
//
|
||||
//
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Task/Simple-database/C/simple-database.c
Normal file
193
Task/Simple-database/C/simple-database.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <string.h> /* strlen */
|
||||
#define _XOPEN_SOURCE /* requred for time functions */
|
||||
#define __USE_XOPEN
|
||||
#include <time.h>
|
||||
#define DB "database.csv" /* database name */
|
||||
#define TRY(a) if (!(a)) {perror(#a);exit(1);}
|
||||
#define TRY2(a) if((a)<0) {perror(#a);exit(1);}
|
||||
#define FREE(a) if(a) {free(a);a=NULL;}
|
||||
#define sort_by(foo) \
|
||||
static int by_##foo (const void*p1, const void*p2) { \
|
||||
return strcmp ((*(const pdb_t*)p1)->foo, (*(const pdb_t*)p2)->foo); }
|
||||
typedef struct db {
|
||||
char title[26];
|
||||
char first_name[26];
|
||||
char last_name[26];
|
||||
time_t date;
|
||||
char publ[100];
|
||||
struct db *next;
|
||||
}
|
||||
db_t,*pdb_t;
|
||||
typedef int (sort)(const void*, const void*);
|
||||
enum {CREATE,PRINT,TITLE,DATE,AUTH,READLINE,READ,SORT,DESTROY};
|
||||
static pdb_t dao (int cmd, FILE *f, pdb_t db, sort sortby);
|
||||
static char *time2str (time_t *time);
|
||||
static time_t str2time (char *date);
|
||||
/* qsort callbacks */
|
||||
sort_by(last_name);
|
||||
sort_by(title);
|
||||
static int by_date(pdb_t *p1, pdb_t *p2);
|
||||
/* main */
|
||||
int main (int argc, char **argv) {
|
||||
char buf[100];
|
||||
const char *commands[]={"-c", "-p", "-t", "-d", "-a", NULL};
|
||||
db_t db;
|
||||
db.next=NULL;
|
||||
pdb_t dblist;
|
||||
int i;
|
||||
FILE *f;
|
||||
TRY (f=fopen(DB,"a+"));
|
||||
if (argc<2) {
|
||||
usage: printf ("Usage: %s [commands]\n"
|
||||
"-c Create new entry.\n"
|
||||
"-p Print the latest entry.\n"
|
||||
"-t Print all entries sorted by title.\n"
|
||||
"-d Print all entries sorted by date.\n"
|
||||
"-a Print all entries sorted by author.\n",argv[0]);
|
||||
fclose (f);
|
||||
return 0;
|
||||
}
|
||||
for (i=0;commands[i]&&strcmp(argv[1],commands[i]);i++);
|
||||
switch (i) {
|
||||
case CREATE:
|
||||
printf("-c Create a new entry.\n");
|
||||
printf("Title :");if((scanf(" %25[^\n]",db.title ))<0)break;
|
||||
printf("Author Firstname:");if((scanf(" %25[^\n]",db.first_name))<0)break;
|
||||
printf("Author Lastname :");if((scanf(" %25[^\n]",db.last_name ))<0)break;
|
||||
printf("Date 10-12-2000 :");if((scanf(" %10[^\n]",buf ))<0)break;
|
||||
printf("Publication :");if((scanf(" %99[^\n]",db.publ ))<0)break;
|
||||
db.date=str2time (buf);
|
||||
dao (CREATE,f,&db,NULL);
|
||||
break;
|
||||
case PRINT:
|
||||
printf ("-p Print the latest entry.\n");
|
||||
while (!feof(f)) dao (READLINE,f,&db,NULL);
|
||||
dao (PRINT,f,&db,NULL);
|
||||
break;
|
||||
case TITLE:
|
||||
printf ("-t Print all entries sorted by title.\n");
|
||||
dblist = dao (READ,f,&db,NULL);
|
||||
dblist = dao (SORT,f,dblist,by_title);
|
||||
dao (PRINT,f,dblist,NULL);
|
||||
dao (DESTROY,f,dblist,NULL);
|
||||
break;
|
||||
case DATE:
|
||||
printf ("-d Print all entries sorted by date.\n");
|
||||
dblist = dao (READ,f,&db,NULL);
|
||||
dblist = dao (SORT,f,dblist,(int (*)(const void *,const void *)) by_date);
|
||||
dao (PRINT,f,dblist,NULL);
|
||||
dao (DESTROY,f,dblist,NULL);
|
||||
break;
|
||||
case AUTH:
|
||||
printf ("-a Print all entries sorted by author.\n");
|
||||
dblist = dao (READ,f,&db,NULL);
|
||||
dblist = dao (SORT,f,dblist,by_last_name);
|
||||
dao (PRINT,f,dblist,NULL);
|
||||
dao (DESTROY,f,dblist,NULL);
|
||||
break;
|
||||
default: {
|
||||
printf ("Unknown command: %s.\n",strlen(argv[1])<10?argv[1]:"");
|
||||
goto usage;
|
||||
} }
|
||||
fclose (f);
|
||||
return 0;
|
||||
}
|
||||
/* Data Access Object (DAO) */
|
||||
static pdb_t dao (int cmd, FILE *f, pdb_t in_db, sort sortby) {
|
||||
pdb_t *pdb=NULL,rec=NULL,hd=NULL;
|
||||
int i=0,ret;
|
||||
char buf[100];
|
||||
switch (cmd) {
|
||||
case CREATE:
|
||||
fprintf (f,"\"%s\",",in_db->title);
|
||||
fprintf (f,"\"%s\",",in_db->first_name);
|
||||
fprintf (f,"\"%s\",",in_db->last_name);
|
||||
fprintf (f,"\"%s\",",time2str(&in_db->date));
|
||||
fprintf (f,"\"%s\" \n",in_db->publ);
|
||||
break;
|
||||
case PRINT:
|
||||
for (;in_db;i++) {
|
||||
printf ("Title : %s\n", in_db->title);
|
||||
printf ("Author : %s %s\n", in_db->first_name, in_db->last_name);
|
||||
printf ("Date : %s\n", time2str(&in_db->date));
|
||||
printf ("Publication : %s\n\n", in_db->publ);
|
||||
if (!((i+1)%3)) {
|
||||
printf ("Press Enter to continue.\n");
|
||||
ret = scanf ("%*[^\n]");
|
||||
if (ret<0) return rec; /* handle EOF */
|
||||
else getchar();
|
||||
}
|
||||
in_db=in_db->next;
|
||||
}
|
||||
break;
|
||||
case READLINE:
|
||||
if((fscanf(f," \"%[^\"]\",",in_db->title ))<0)break;
|
||||
if((fscanf(f," \"%[^\"]\",",in_db->first_name))<0)break;
|
||||
if((fscanf(f," \"%[^\"]\",",in_db->last_name ))<0)break;
|
||||
if((fscanf(f," \"%[^\"]\",",buf ))<0)break;
|
||||
if((fscanf(f," \"%[^\"]\" ",in_db->publ ))<0)break;
|
||||
in_db->date=str2time (buf);
|
||||
break;
|
||||
case READ:
|
||||
while (!feof(f)) {
|
||||
dao (READLINE,f,in_db,NULL);
|
||||
TRY (rec=malloc(sizeof(db_t)));
|
||||
*rec=*in_db; /* copy contents */
|
||||
rec->next=hd;/* to linked list */
|
||||
hd=rec;i++;
|
||||
}
|
||||
if (i<2) {
|
||||
puts ("Empty database. Please create some entries.");
|
||||
fclose (f);
|
||||
exit (0);
|
||||
}
|
||||
break;
|
||||
case SORT:
|
||||
rec=in_db;
|
||||
for (;in_db;i++) in_db=in_db->next;
|
||||
TRY (pdb=malloc(i*sizeof(pdb_t)));
|
||||
in_db=rec;
|
||||
for (i=0;in_db;i++) {
|
||||
pdb[i]=in_db;
|
||||
in_db=in_db->next;
|
||||
}
|
||||
qsort (pdb,i,sizeof in_db,sortby);
|
||||
pdb[i-1]->next=NULL;
|
||||
for (i=i-1;i;i--) {
|
||||
pdb[i-1]->next=pdb[i];
|
||||
}
|
||||
rec=pdb[0];
|
||||
FREE (pdb);
|
||||
pdb=NULL;
|
||||
break;
|
||||
case DESTROY: {
|
||||
while ((rec=in_db)) {
|
||||
in_db=in_db->next;
|
||||
FREE (rec);
|
||||
} } }
|
||||
return rec;
|
||||
}
|
||||
/* convert numeric time to date string */
|
||||
static char *time2str (time_t *time) {
|
||||
static char buf[255];
|
||||
struct tm *ptm;
|
||||
ptm=localtime (time);
|
||||
strftime(buf, 255, "%m-%d-%Y", ptm);
|
||||
return buf;
|
||||
}
|
||||
/* convert date string to numeric time */
|
||||
static time_t str2time (char *date) {
|
||||
struct tm tm;
|
||||
memset (&tm, 0, sizeof(struct tm));
|
||||
strptime(date, "%m-%d-%Y", &tm);
|
||||
return mktime(&tm);
|
||||
}
|
||||
/* sort by date callback for qsort */
|
||||
static int by_date (pdb_t *p1, pdb_t *p2) {
|
||||
if ((*p1)->date < (*p2)->date) {
|
||||
return -1;
|
||||
}
|
||||
else return ((*p1)->date > (*p2)->date);
|
||||
}
|
||||
262
Task/Simple-database/COBOL/simple-database.cobol
Normal file
262
Task/Simple-database/COBOL/simple-database.cobol
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. simple-database.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT OPTIONAL database-file ASSIGN Database-Path
|
||||
ORGANIZATION INDEXED
|
||||
ACCESS SEQUENTIAL
|
||||
RECORD KEY data-title
|
||||
ALTERNATE RECORD KEY data-tag
|
||||
WITH DUPLICATES
|
||||
ALTERNATE RECORD KEY date-added
|
||||
WITH DUPLICATES
|
||||
FILE STATUS file-status
|
||||
.
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD database-file.
|
||||
01 database-record.
|
||||
*> Date is in YYYYMMDD format.
|
||||
03 date-added PIC 9(8).
|
||||
03 data-tag PIC X(20).
|
||||
03 data-title PIC X(50).
|
||||
03 data-contents PIC X(200).
|
||||
*> Adding extra space is considered good style so the record
|
||||
*> can be expanded in the future.
|
||||
03 FILLER PIC X(50).
|
||||
|
||||
WORKING-STORAGE SECTION.
|
||||
78 Database-Path VALUE "database.dat".
|
||||
|
||||
01 file-status PIC XX.
|
||||
88 file-ok VALUE "00".
|
||||
88 duplicate-key VALUE "22".
|
||||
88 key-not-found VALUE "23".
|
||||
|
||||
01 num-args PIC 99.
|
||||
|
||||
01 action PIC XX.
|
||||
88 create-entry VALUE "-c".
|
||||
88 remove-entry VALUE "-r".
|
||||
88 find-entry VALUE "-f".
|
||||
88 print-latest VALUE "-l".
|
||||
88 print-database VALUES "-a", "-d", "-t".
|
||||
*> Printed by title.
|
||||
88 print-by-title VALUE "-a".
|
||||
88 print-by-date VALUE "-d".
|
||||
88 print-by-tag VALUE "-t".
|
||||
88 print-help VALUES "-h", SPACES.
|
||||
|
||||
01 read-direction-flag PIC X VALUE SPACE.
|
||||
88 read-backwards VALUE "B".
|
||||
|
||||
01 edited-date PIC 9(4)/99/99.
|
||||
PROCEDURE DIVISION.
|
||||
DECLARATIVES.
|
||||
database-file-error SECTION.
|
||||
USE AFTER ERROR ON database-file
|
||||
|
||||
DISPLAY "An error has occurred while using " Database-Path
|
||||
". Error no. " file-status
|
||||
DISPLAY "The program will terminate."
|
||||
|
||||
CLOSE database-file
|
||||
|
||||
GOBACK
|
||||
.
|
||||
END DECLARATIVES.
|
||||
|
||||
main-line.
|
||||
DISPLAY 1 UPON ARGUMENT-NUMBER
|
||||
ACCEPT action FROM ARGUMENT-VALUE
|
||||
|
||||
ACCEPT num-args FROM ARGUMENT-NUMBER
|
||||
|
||||
EVALUATE TRUE
|
||||
WHEN create-entry
|
||||
IF num-args >= 4
|
||||
PERFORM write-entry
|
||||
ELSE
|
||||
DISPLAY "-a requires arguments to enter in the "
|
||||
"database. See help (-h) for details."
|
||||
END-IF
|
||||
|
||||
WHEN remove-entry
|
||||
IF num-args >= 2
|
||||
PERFORM delete-entry
|
||||
ELSE
|
||||
DISPLAY "-r requires the title of the entry to "
|
||||
"delete."
|
||||
END-IF
|
||||
|
||||
WHEN find-entry
|
||||
IF num-args >= 2
|
||||
PERFORM display-specified-entry
|
||||
ELSE
|
||||
DISPLAY "-f requires the title of the entry to "
|
||||
"find."
|
||||
END-IF
|
||||
|
||||
WHEN print-latest
|
||||
PERFORM show-latest
|
||||
|
||||
WHEN print-database
|
||||
PERFORM show-database
|
||||
|
||||
WHEN print-help
|
||||
PERFORM show-general-help
|
||||
|
||||
WHEN OTHER
|
||||
DISPLAY action " is not a valid option."
|
||||
END-EVALUATE
|
||||
|
||||
GOBACK
|
||||
.
|
||||
write-entry.
|
||||
OPEN EXTEND database-file
|
||||
|
||||
DISPLAY 2 UPON ARGUMENT-NUMBER
|
||||
ACCEPT data-tag FROM ARGUMENT-VALUE
|
||||
DISPLAY 3 UPON ARGUMENT-NUMBER
|
||||
ACCEPT data-title FROM ARGUMENT-VALUE
|
||||
IF data-title = SPACES
|
||||
DISPLAY "The title cannot be blank."
|
||||
PERFORM close-and-terminate
|
||||
END-IF
|
||||
|
||||
DISPLAY 4 UPON ARGUMENT-NUMBER
|
||||
ACCEPT data-contents FROM ARGUMENT-VALUE
|
||||
|
||||
ACCEPT date-added FROM DATE YYYYMMDD
|
||||
|
||||
WRITE database-record
|
||||
INVALID KEY
|
||||
IF duplicate-key
|
||||
DISPLAY "An entry in the database already has "
|
||||
"that title. Please choose a different "
|
||||
"title or remove the entry."
|
||||
ELSE
|
||||
PERFORM database-file-error
|
||||
END-IF
|
||||
END-WRITE
|
||||
|
||||
PERFORM close-database
|
||||
.
|
||||
delete-entry.
|
||||
PERFORM get-title-arg
|
||||
OPEN I-O database-file
|
||||
PERFORM read-title
|
||||
|
||||
DELETE database-file
|
||||
|
||||
PERFORM close-database
|
||||
.
|
||||
display-specified-entry.
|
||||
PERFORM get-title-arg
|
||||
OPEN INPUT database-file
|
||||
PERFORM read-title
|
||||
|
||||
PERFORM show-record
|
||||
|
||||
PERFORM close-database
|
||||
.
|
||||
get-title-arg.
|
||||
DISPLAY 2 UPON ARGUMENT-NUMBER
|
||||
ACCEPT data-title FROM ARGUMENT-VALUE
|
||||
.
|
||||
read-title.
|
||||
START database-file KEY IS = data-title
|
||||
INVALID KEY
|
||||
IF key-not-found
|
||||
DISPLAY "An entry with that title was not found."
|
||||
PERFORM close-and-terminate
|
||||
ELSE
|
||||
PERFORM database-file-error
|
||||
END-IF
|
||||
END-START
|
||||
|
||||
READ database-file
|
||||
.
|
||||
close-and-terminate.
|
||||
PERFORM close-database
|
||||
GOBACK
|
||||
.
|
||||
show-latest.
|
||||
OPEN INPUT database-file
|
||||
|
||||
PERFORM start-at-last-date
|
||||
READ database-file
|
||||
PERFORM show-record
|
||||
|
||||
PERFORM close-database
|
||||
.
|
||||
show-database.
|
||||
OPEN INPUT database-file
|
||||
|
||||
EVALUATE TRUE
|
||||
WHEN print-by-title
|
||||
*> Primary key is the title.
|
||||
CONTINUE
|
||||
WHEN print-by-tag
|
||||
MOVE LOW-VALUES TO data-tag
|
||||
START database-file KEY IS > data-tag
|
||||
WHEN print-by-date
|
||||
PERFORM start-at-last-date
|
||||
SET read-backwards TO TRUE
|
||||
END-EVALUATE
|
||||
|
||||
PERFORM FOREVER
|
||||
*> The problem with statements instead of functions...
|
||||
IF NOT read-backwards
|
||||
READ database-file NEXT
|
||||
AT END
|
||||
EXIT PERFORM
|
||||
END-READ
|
||||
ELSE
|
||||
READ database-file PREVIOUS
|
||||
AT END
|
||||
EXIT PERFORM
|
||||
END-READ
|
||||
END-IF
|
||||
|
||||
PERFORM show-record
|
||||
DISPLAY SPACE
|
||||
END-PERFORM
|
||||
|
||||
PERFORM close-database
|
||||
.
|
||||
start-at-last-date.
|
||||
MOVE HIGH-VALUES TO date-added
|
||||
START database-file KEY IS < date-added
|
||||
.
|
||||
close-database.
|
||||
CLOSE database-file
|
||||
.
|
||||
show-record.
|
||||
MOVE date-added TO edited-date
|
||||
DISPLAY "Date added: " edited-date " Tag: " data-tag
|
||||
DISPLAY "Title: " data-title
|
||||
DISPLAY "Contents:"
|
||||
DISPLAY " " FUNCTION TRIM(data-contents)
|
||||
.
|
||||
show-general-help.
|
||||
DISPLAY "Help: Possible options are:"
|
||||
DISPLAY " -a - Show all the entries (sorted by title)."
|
||||
DISPLAY " -c - Create a new entry in the database. -c needs"
|
||||
" further arguments in this format:"
|
||||
DISPLAY ' "tag" "title" "content"'
|
||||
DISPLAY " Max argument sizes (in characters): tag - 20, "
|
||||
"title - 50, content - 200"
|
||||
DISPLAY " The title must be unique and not be blank."
|
||||
DISPLAY " -d - Show all the entries sorted by date added."
|
||||
DISPLAY " -f - Finds and displays entry with the title "
|
||||
"provided. The title should be specified as shown for "
|
||||
"-c."
|
||||
DISPLAY " -h - Show this help menu."
|
||||
DISPLAY " -l - Show the latest entry."
|
||||
DISPLAY " -r - Remove the entry with the title provided. "
|
||||
"The title should be specified as shown for -c."
|
||||
DISPLAY " -t - Show all the entries sorted by tag."
|
||||
.
|
||||
118
Task/Simple-database/Common-Lisp/simple-database.lisp
Normal file
118
Task/Simple-database/Common-Lisp/simple-database.lisp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
(defvar *db* nil)
|
||||
|
||||
(defvar *db-cat* (make-hash-table :test 'equal))
|
||||
|
||||
(defvar *db-file* "db.txt")
|
||||
|
||||
(defstruct item
|
||||
"this is the unit of data stored/displayed in *db*"
|
||||
(title " ")
|
||||
(category "default")
|
||||
(date (progn (get-universal-time))))
|
||||
|
||||
(defun set-category(new-item)
|
||||
(setf (gethash (item-category new-item) *db-cat*) 't))
|
||||
|
||||
(defun find-item-in-db (&optional category)
|
||||
(if (null category)
|
||||
(car *db*)
|
||||
(find category *db* :key #'item-category :test #'string=)))
|
||||
|
||||
(defun scan-category ()
|
||||
"scan categories from an existing database -- after reading it from disk"
|
||||
(dolist (itm *db*) (set-category itm)))
|
||||
|
||||
(defun pr-univ-time (utime)
|
||||
(multiple-value-bind
|
||||
(second minute hour date month year day-of-week dst-p tz)
|
||||
(decode-universal-time utime)
|
||||
(declare (ignore day-of-week dst-p tz))
|
||||
(format nil "~4,'0d-~2,'0d-~2,'0d ~2,'0d:~2,'0d:~2,'0d" year month date hour minute second)))
|
||||
|
||||
(defun pr (&optional (item (find-item-in-db)) (stream t))
|
||||
"print an item"
|
||||
(when item
|
||||
(format stream "~a: (~a) (~a)~%"
|
||||
(item-title item)
|
||||
(item-category item)
|
||||
(pr-univ-time (item-date item)))))
|
||||
|
||||
(defun pr-per-category ()
|
||||
"print the latest item from each category"
|
||||
(loop for k being the hash-keys in *db-cat*
|
||||
do (pr (find-item-in-db k))))
|
||||
|
||||
(defun pr-all ()
|
||||
"print all the items, *db* is sorted by time."
|
||||
(dolist (itm *db*) (pr itm)))
|
||||
|
||||
(defun pr-all-categories (&optional (stream t))
|
||||
(loop for k being the hash-keys in *db-cat*
|
||||
do (format stream "(~a) " k)))
|
||||
|
||||
(defun insert-item (item)
|
||||
"insert item into database in a time sorted list. okay for a small list, as per spec."
|
||||
(let ((first-item (car *db*)) (new-itm item))
|
||||
(set-category new-itm)
|
||||
(push new-itm *db*)
|
||||
(when (and first-item (>= (item-date new-itm) (item-date first-item)))
|
||||
(setf *db* (sort *db* #'> :key #'item-date)))
|
||||
*db*))
|
||||
|
||||
(defun read-db-from-file (&optional (file *db-file*))
|
||||
(with-open-file (in file :if-does-not-exist nil)
|
||||
(when in
|
||||
(with-standard-io-syntax (setf *db* (read in)))
|
||||
(scan-category))))
|
||||
|
||||
(defun save-db-to-file (&optional (file *db-file*))
|
||||
(with-open-file (out file :direction :output :if-exists :supersede)
|
||||
(with-standard-io-syntax
|
||||
(print *db* out))))
|
||||
|
||||
(defun del-db ()
|
||||
(setf *db* nil)
|
||||
(save-db-to-file))
|
||||
|
||||
(defun del-item (itm)
|
||||
(read-db-from-file)
|
||||
(setf *db* (remove itm *db* :key #'item-title :test #'string=))
|
||||
(save-db-to-file))
|
||||
|
||||
(defun add-item-to-db (args)
|
||||
(read-db-from-file)
|
||||
(insert-item (make-item :title (first args) :category (second args)))
|
||||
(save-db-to-file))
|
||||
|
||||
(defun help-menu ()
|
||||
(format t "clisp db.lisp ~{~15T~a~^~% ~}"
|
||||
'("delete <item-name> ------------------- delete an item"
|
||||
"delete-all --------------------------- delete the database"
|
||||
"insert <item-name> <item-category> --- insert an item with its category"
|
||||
"show --------------------------------- shows the latest inserted item"
|
||||
"show-categories ---------------------- show all categories"
|
||||
"show-all ----------------------------- show all items"
|
||||
"show-per-category -------------------- show the latest item per category")))
|
||||
|
||||
(defun db-cmd-run (args)
|
||||
(cond ((and (> (length args) 1) (equal (first args) "delete"))
|
||||
(del-item (second args)))
|
||||
((equal (first args) "delete-all") (del-db))
|
||||
((and (> (length args) 2) (equal (first args) "insert"))
|
||||
(add-item-to-db (rest args)))
|
||||
((equal (first args) "show") (read-db-from-file) (pr))
|
||||
((equal (first args) "show-categories") (read-db-from-file) (pr-all-categories))
|
||||
((equal (first args) "show-all") (read-db-from-file) (pr-all))
|
||||
((equal (first args) "show-per-category") (read-db-from-file) (pr-per-category))
|
||||
(t (help-menu))))
|
||||
|
||||
;; modified https://rosettacode.org/wiki/Command-line_arguments#Common_Lisp
|
||||
(defun db-argv ()
|
||||
(or
|
||||
#+clisp ext:*args*
|
||||
#+sbcl (cdr sb-ext:*posix-argv*)
|
||||
#+allegro (cdr (sys:command-line-arguments))
|
||||
#+lispworks (cdr sys:*line-arguments-list*)
|
||||
nil))
|
||||
|
||||
(db-cmd-run (db-argv))
|
||||
87
Task/Simple-database/D/simple-database.d
Normal file
87
Task/Simple-database/D/simple-database.d
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import std.stdio, std.algorithm, std.string, std.conv, std.array,
|
||||
std.file, std.csv, std.datetime;
|
||||
|
||||
private {
|
||||
immutable filename = "simdb.csv";
|
||||
|
||||
struct Item {
|
||||
string name, date, category;
|
||||
}
|
||||
|
||||
void addItem(in string[] item) {
|
||||
if (item.length < 3)
|
||||
return printUsage();
|
||||
auto db = load();
|
||||
const date = (cast(DateTime)Clock.currTime).toISOExtString;
|
||||
const cat = (item.length == 4) ? item[3] : "none";
|
||||
db ~= Item(item[2], date, cat);
|
||||
store(db);
|
||||
}
|
||||
|
||||
void printLatest(in string[] a) {
|
||||
auto db = load();
|
||||
if (db.empty)
|
||||
return writeln("No entries in database.");
|
||||
db.sort!q{ a.date > b.date };
|
||||
if (a.length == 3) {
|
||||
foreach (item; db)
|
||||
if (item.category == a[2])
|
||||
writefln("%s, %s, %s", item.tupleof);
|
||||
} else {
|
||||
writefln("%s, %s, %s", db[0].tupleof);
|
||||
}
|
||||
}
|
||||
|
||||
void printAll() {
|
||||
auto db = load();
|
||||
if (db.empty)
|
||||
return writeln("No entries in database.");
|
||||
db.sort!q{ a.date < b.date };
|
||||
foreach (item; db)
|
||||
writefln("%s, %s, %s", item.tupleof);
|
||||
}
|
||||
|
||||
Item[] load() {
|
||||
Item[] db;
|
||||
if (filename.exists && filename.isFile) {
|
||||
try {
|
||||
const text = filename.readText;
|
||||
if (!text.empty)
|
||||
db = csvReader!Item(text).array;
|
||||
} catch (CSVException e) {
|
||||
writeln(e.msg);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
void store(in Item[] db) {
|
||||
auto f = File(filename, "w+");
|
||||
foreach (item; db)
|
||||
f.writefln("%s,%s,%s", item.tupleof);
|
||||
}
|
||||
|
||||
void printUsage() {
|
||||
writeln(
|
||||
`Usage:
|
||||
simdb cmd [categoryName]
|
||||
|
||||
add add item, followed by optional category
|
||||
latest print last added item(s), followed by optional category
|
||||
all print all
|
||||
|
||||
For instance: add "some item name" "some category name"`);
|
||||
}
|
||||
}
|
||||
|
||||
void main(in string[] args) {
|
||||
if (args.length < 2 || args.length > 4)
|
||||
return printUsage();
|
||||
|
||||
switch (args[1].toLower) {
|
||||
case "add": addItem(args); break;
|
||||
case "latest": printLatest(args); break;
|
||||
case "all": printAll(); break;
|
||||
default: printUsage(); break;
|
||||
}
|
||||
}
|
||||
50
Task/Simple-database/Emacs-Lisp/simple-database.l
Normal file
50
Task/Simple-database/Emacs-Lisp/simple-database.l
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
(defun dbe-next-id ()
|
||||
(unless (boundp '**dbe-current-id**) (setq **dbe-current-id** 1))
|
||||
(let ((id **dbe-current-id**))
|
||||
(cl-incf **dbe-current-id**)
|
||||
id ) )
|
||||
|
||||
(defun dbe-rows (fn-handle-row &rest params)
|
||||
(let ((has-more 't) current-line linum1 linum2
|
||||
(fn-continue (plist-get params :continue)))
|
||||
(save-window-excursion
|
||||
(switch-to-buffer "**content**")
|
||||
(beginning-of-buffer)
|
||||
(if fn-continue (setq has-more (funcall fn-continue)))
|
||||
(while has-more
|
||||
(setq current-line
|
||||
(buffer-substring (line-beginning-position)
|
||||
(line-end-position)))
|
||||
(unless (string= current-line "")
|
||||
(funcall fn-handle-row (read current-line)))
|
||||
(if fn-continue (setq has-more (funcall fn-continue)))
|
||||
(setq linum1 (line-number-at-pos (point)))
|
||||
(forward-line)
|
||||
(setq linum2 (line-number-at-pos (point)))
|
||||
(if (= linum1 linum2) (setq has-more nil))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun dbe-insert (row)
|
||||
(interactive "xPlease enter the row data in plist format: ")
|
||||
(save-window-excursion
|
||||
(switch-to-buffer "**content**")
|
||||
(end-of-buffer)
|
||||
(let (row-data)
|
||||
(setq row-data (append (list 'id (dbe-next-id)) (ensure-list row)))
|
||||
(insert (format "%s\n" row-data))
|
||||
(message ">> Row added: %s" row-data) ) ) )
|
||||
|
||||
(defun dbe-find-by-id (row-id)
|
||||
(interactive "nPlease enter row id: ")
|
||||
(let (row-found)
|
||||
(dbe-rows (lambda (row)
|
||||
(when (equal (plist-get row 'id) row-id)
|
||||
(setq row-found row)) )
|
||||
:continue (lambda () (null row-found)))
|
||||
(message ">> Row found: %s" row-found)
|
||||
)
|
||||
|
||||
)
|
||||
54
Task/Simple-database/Erlang/simple-database.erl
Normal file
54
Task/Simple-database/Erlang/simple-database.erl
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#! /usr/bin/env escript
|
||||
|
||||
-compile({no_auto_import,[date/0]}).
|
||||
|
||||
main( ["add", Tag | Descriptions] ) -> add( date(), Tag, Descriptions );
|
||||
main( ["add_date", Date, Tag | Descriptions] ) -> add( date_internal(string:tokens(Date, "-")), Tag, Descriptions );
|
||||
main( ["print_latest"] ) -> print_latest( contents() );
|
||||
main( ["print_latest_for_each"] ) -> print_latest_for_each( contents() );
|
||||
main( ["print_all_date", Date] ) -> print_all_date( date_internal(string:tokens(Date, "-")), contents() );
|
||||
main( _Error ) -> usage().
|
||||
|
||||
|
||||
|
||||
add( Date, Tag, Descriptions ) ->
|
||||
Contents = contents(),
|
||||
file:write_file( file(), io_lib:format("simple_database_v1.~n~p.~n", [[{Date, Tag, Descriptions} | Contents]]) ).
|
||||
|
||||
date() ->
|
||||
{{Date, _Time}} = calendar:local_time(),
|
||||
Date.
|
||||
|
||||
date_external( {Year, Month, Day} ) -> string:join( [erlang:integer_to_list(Year), erlang:integer_to_list(Month), erlang:integer_to_list(Day)], "-" );
|
||||
date_external( _Error ) -> usage().
|
||||
|
||||
date_internal( [Year, Month, Day] ) -> {erlang:list_to_integer(Year), erlang:list_to_integer(Month), erlang:list_to_integer(Day)};
|
||||
date_internal( _Error ) -> usage().
|
||||
|
||||
file() -> "simple_database_contents".
|
||||
|
||||
contents() -> contents( file:consult(file()) ).
|
||||
|
||||
contents( {ok, [simple_database_v1, Contents]} ) -> Contents;
|
||||
contents( {error, Error} ) when is_atom(Error) -> [];
|
||||
contents( {error, _Error} ) ->
|
||||
io:fwrite( "Error: ~p corrupt. Starting from scratch~n", [file()] ),
|
||||
[].
|
||||
|
||||
print_all_date( _Date, [] ) -> ok;
|
||||
print_all_date( Date, Contents ) -> [print_latest([{D, Tag, Descriptions}]) || {D, Tag, Descriptions} <- Contents, D =:= Date].
|
||||
|
||||
print_latest( [] ) -> ok;
|
||||
print_latest( [{Date, Tag, Descriptions} | _T] ) -> io:fwrite( "~s~n", [string:join( [date_external(Date), Tag | Descriptions], " ")] ).
|
||||
|
||||
print_latest_for_each( [] ) -> ok;
|
||||
print_latest_for_each( Contents ) ->
|
||||
Tags = lists:usort( [Tag || {_Date, Tag, _Descriptions} <- Contents] ),
|
||||
[print_latest([lists:keyfind(X, 2, Contents)]) || X <- Tags].
|
||||
|
||||
usage() ->
|
||||
io:fwrite( "Usage: ~p [add | add_date <date>] tag description ...~n", [escript:script_name()] ),
|
||||
io:fwrite( "Or: ~p [print_latest | print_latest_for_each | print_all_date <date>]~n", [escript:script_name()] ),
|
||||
io:fwrite( "Date format is YYYY-MM-DD~n" ),
|
||||
io:fwrite( "Data stored in ~p~n", [file()] ),
|
||||
init:stop().
|
||||
129
Task/Simple-database/Forth/simple-database.fth
Normal file
129
Task/Simple-database/Forth/simple-database.fth
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
\ sdb.fs Simple database. Gforth 0.7.0 specific
|
||||
' noop is bootmessage
|
||||
|
||||
wordlist constant USER: \ USER functions
|
||||
wordlist constant SDB \ DB keys
|
||||
wordlist constant FIELDS \ DB fields
|
||||
|
||||
: -SDB?EXIT ( -- ; Continue if `SDB' non-empty )
|
||||
SDB cell+ @ 0= IF rdrop exit THEN ;
|
||||
|
||||
\ MACROS
|
||||
: |comp| ( MACRO: | code to be compiled | )
|
||||
char parse evaluate ; immediate
|
||||
: LIST ( node -- ) ]] BEGIN @ dup WHILE >R [[ ; immediate
|
||||
: LOOP-LIST ( -- ) ]] R> REPEAT drop [[ ; immediate
|
||||
: UNLIST ( -- ) POSTPONE rdrop ; immediate
|
||||
|
||||
\ Helper words
|
||||
: .; [char] ; emit ;
|
||||
: !+ dup cell+ -rot ! ;
|
||||
: ($+) ( cas us cad ud -- cad us+ud ; append source string to destination )
|
||||
swap >R 2dup + R> swap >R tuck + swap >R swap move R> R> ;
|
||||
|
||||
\ --- Working Record Fields
|
||||
current @ FIELDS current !
|
||||
2variable person
|
||||
2variable birthday
|
||||
2variable relationship
|
||||
2variable hobby
|
||||
current ! FIELDS >order
|
||||
|
||||
\ --- Ring list
|
||||
: new-node ( -- node ; root of circular list )
|
||||
here dup , ;
|
||||
: do-link ( node new-node -- ; do link after current node )
|
||||
over @ over ! swap ! ;
|
||||
: empty-ring? ( node -- f ) dup @ = ;
|
||||
|
||||
: RING ( node -- ) ]] dup BEGIN @ 2dup <> WHILE 2>R [[ ; immediate
|
||||
: LOOP-RING ( -- ) ]] 2R> REPEAT 2drop [[ ; immediate
|
||||
: UNRING ( -- ) postpone 2RDROP ; immediate
|
||||
|
||||
:noname
|
||||
s" " person 2! s" 9999.01.01" birthday 2! s" " relationship 2! s" " hobby 2! ;
|
||||
new-node swap , CONSTANT OLD
|
||||
|
||||
\ --- Insertion into ring
|
||||
: node>xt ( node -- xt ) cell+ @ ;
|
||||
: bday@ ( node -- ca u ) node>xt execute birthday 2@ ;
|
||||
: datecmp ( node node -- -1|0|1 ) bday@ rot bday@ compare ;
|
||||
|
||||
: search-by-date ( new-node node -- node' ; Linear search by birth date )
|
||||
dup
|
||||
RING ( new-node node )
|
||||
over I datecmp 0<
|
||||
IF nip UNRING exit
|
||||
ELSE drop I THEN
|
||||
LOOP-RING nip ;
|
||||
|
||||
: insert-ordered ( new-node -- )
|
||||
OLD dup empty-ring? 0=
|
||||
IF over swap search-by-date THEN swap do-link ;
|
||||
|
||||
\ --- Field compiling
|
||||
: fld: [char] ; parse postpone sliteral ; immediate
|
||||
|
||||
: _sdb-walk ( MACRO: | xt[--] -- | )
|
||||
]] -SDB?EXIT here dup SDB cell+
|
||||
LIST I name>int swap !+ LOOP-LIST [[ 1 cells ]] literal -
|
||||
DO I @ |comp| [[ -1 cells ]] literal +LOOP [[ ; immediate
|
||||
|
||||
2variable category
|
||||
: msg_nocategory ( -- )
|
||||
." No such category!" cr ;
|
||||
|
||||
\ --- USER definitions
|
||||
user: >order current @ USER: current !
|
||||
: bye bye ;
|
||||
: .s .s ;
|
||||
: newline cr ;
|
||||
: godb SDB >order ;
|
||||
: .keys SDB wordlist-words ;
|
||||
: .person person 2@ type ;
|
||||
: .birthday birthday 2@ type ;
|
||||
: .relationship relationship 2@ type ;
|
||||
: .hobby hobby 2@ type ;
|
||||
: .record .person 1 spaces .birthday .; .relationship .; .hobby .; ;
|
||||
|
||||
: .last SDB cell+ @ dup
|
||||
IF name>int execute .record ELSE drop THEN ;
|
||||
|
||||
: .lastbycategory ( "field-name" -- )
|
||||
here 0 category 2! parse-name FIELDS search-wordlist
|
||||
IF sdb cell+
|
||||
LIST ( xt )
|
||||
I name>int execute dup execute 2@ category 2@ 2swap search nip nip 0=
|
||||
IF .record cr dup execute 2@ category 2@ ($+) category 2! THEN
|
||||
LOOP-LIST drop
|
||||
ELSE ['] msg_nocategory stderr OUTFILE-EXECUTE THEN ;
|
||||
|
||||
: .bydate ( -- )
|
||||
OLD RING I node>xt execute .record cr LOOP-RING ;
|
||||
|
||||
: .sdb _sdb-walk | execute .record cr | ;
|
||||
: sdb-dump _sdb-walk | execute ." +: " .record cr | ;
|
||||
|
||||
: dump ( "db-file" -- )
|
||||
parse-name w/o
|
||||
CREATE-FILE throw dup
|
||||
['] sdb-dump swap OUTFILE-EXECUTE
|
||||
CLOSE-FILE throw ;
|
||||
|
||||
: load ( "db-file" -- ) include ;
|
||||
|
||||
: +: ( "person birth-day;relationship;hobby; -- )
|
||||
new-node dup cell+ >R 0 , \ post `xt'
|
||||
current @ SDB current ! \ compile into `sdb' wordlist
|
||||
: latestxt dup R> ! \ fix-up `xt'
|
||||
]] literal >name name>string person 2! fld: birthday 2! fld: relationship 2! fld: hobby 2! ; [[
|
||||
current !
|
||||
insert-ordered ;
|
||||
|
||||
: HELP cr
|
||||
cr ." KEYWORDS: " USER: wordlist-words cr ." ---"
|
||||
cr ." Prefix `.' means print"
|
||||
cr ." To add a record, type: +: name yyyy.mm.dd;relationship;hobby;"
|
||||
cr cr ;
|
||||
current !
|
||||
SEAL godb
|
||||
340
Task/Simple-database/Go/simple-database.go
Normal file
340
Task/Simple-database/Go/simple-database.go
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Database record format. Time stamp and name are required.
|
||||
// Tags and notes are optional.
|
||||
type Item struct {
|
||||
Stamp time.Time
|
||||
Name string
|
||||
Tags []string `json:",omitempty"`
|
||||
Notes string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Item implements stringer interface
|
||||
func (i *Item) String() string {
|
||||
s := i.Stamp.Format(time.ANSIC) + "\n Name: " + i.Name
|
||||
if len(i.Tags) > 0 {
|
||||
s = fmt.Sprintf("%s\n Tags: %v", s, i.Tags)
|
||||
}
|
||||
if i.Notes > "" {
|
||||
s += "\n Notes: " + i.Notes
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// collection of Items
|
||||
type db []*Item
|
||||
|
||||
// db implements sort.Interface
|
||||
func (d db) Len() int { return len(d) }
|
||||
func (d db) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
func (d db) Less(i, j int) bool { return d[i].Stamp.Before(d[j].Stamp) }
|
||||
|
||||
// hard coded database file name
|
||||
const fn = "sdb.json"
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 1 {
|
||||
latest()
|
||||
return
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "add":
|
||||
add()
|
||||
case "latest":
|
||||
latest()
|
||||
case "tags":
|
||||
tags()
|
||||
case "all":
|
||||
all()
|
||||
case "help":
|
||||
help()
|
||||
default:
|
||||
usage("unrecognized command")
|
||||
}
|
||||
}
|
||||
|
||||
func usage(err string) {
|
||||
if err > "" {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(`usage: sdb [command] [data]
|
||||
where command is one of add, latest, tags, all, or help.`)
|
||||
}
|
||||
|
||||
func help() {
|
||||
usage("")
|
||||
fmt.Println(`
|
||||
Commands must be in lower case.
|
||||
If no command is specified, the default command is latest.
|
||||
|
||||
Latest prints the latest item.
|
||||
All prints all items in chronological order.
|
||||
Tags prints the lastest item for each tag.
|
||||
Help prints this message.
|
||||
|
||||
Add adds data as a new record. The format is,
|
||||
|
||||
name [tags] [notes]
|
||||
|
||||
Name is the name of the item and is required for the add command.
|
||||
|
||||
Tags are optional. A tag is a single word.
|
||||
A single tag can be specified without enclosing brackets.
|
||||
Multiple tags can be specified by enclosing them in square brackets.
|
||||
|
||||
Text remaining after tags is taken as notes. Notes do not have to be
|
||||
enclosed in quotes or brackets. The brackets above are only showing
|
||||
that notes are optional.
|
||||
|
||||
Quotes may be useful however--as recognized by your operating system shell
|
||||
or command line--to allow entry of arbitrary text. In particular, quotes
|
||||
or escape characters may be needed to prevent the shell from trying to
|
||||
interpret brackets or other special characters.
|
||||
|
||||
Examples:
|
||||
sdb add Bookends // no tags, no notes
|
||||
sdb add Bookends rock my favorite // tag: rock, notes: my favorite
|
||||
sdb add Bookends [rock folk] // two tags
|
||||
sdb add Bookends [] "Simon & Garfunkel" // notes, no tags
|
||||
sdb add "Simon&Garfunkel [artist]" // name: Simon&Garfunkel, tag: artist
|
||||
|
||||
As shown in the last example, if you use features of your shell to pass
|
||||
all data as a single string, the item name and tags will still be identified
|
||||
by separating whitespace.
|
||||
|
||||
The database is stored in JSON format in the file "sdb.json"
|
||||
`)
|
||||
}
|
||||
|
||||
// load data for read only purposes.
|
||||
func load() (db, bool) {
|
||||
d, f, ok := open()
|
||||
if ok {
|
||||
f.Close()
|
||||
if len(d) == 0 {
|
||||
fmt.Println("no items")
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
return d, ok
|
||||
}
|
||||
|
||||
// open database, leave open
|
||||
func open() (d db, f *os.File, ok bool) {
|
||||
var err error
|
||||
f, err = os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("cant open??")
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
jd := json.NewDecoder(f)
|
||||
err = jd.Decode(&d)
|
||||
// EOF just means file was empty. That's okay with us.
|
||||
if err != nil && err != io.EOF {
|
||||
fmt.Println(err)
|
||||
f.Close()
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// handle latest command
|
||||
func latest() {
|
||||
d, ok := load()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
sort.Sort(d)
|
||||
fmt.Println(d[len(d)-1])
|
||||
}
|
||||
|
||||
// handle all command
|
||||
func all() {
|
||||
d, ok := load()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
sort.Sort(d)
|
||||
for _, i := range d {
|
||||
fmt.Println("-----------------------------------")
|
||||
fmt.Println(i)
|
||||
}
|
||||
fmt.Println("-----------------------------------")
|
||||
}
|
||||
|
||||
// handle tags command
|
||||
func tags() {
|
||||
d, ok := load()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// we have to traverse the entire list to collect tags so there
|
||||
// is no point in sorting at this point.
|
||||
// collect set of unique tags associated with latest item for each
|
||||
latest := make(map[string]*Item)
|
||||
for _, item := range d {
|
||||
for _, tag := range item.Tags {
|
||||
li, ok := latest[tag]
|
||||
if !ok || item.Stamp.After(li.Stamp) {
|
||||
latest[tag] = item
|
||||
}
|
||||
}
|
||||
}
|
||||
// invert to set of unique items, associated with subset of tags
|
||||
// for which the item is the latest.
|
||||
type itemTags struct {
|
||||
item *Item
|
||||
tags []string
|
||||
}
|
||||
inv := make(map[*Item][]string)
|
||||
for tag, item := range latest {
|
||||
inv[item] = append(inv[item], tag)
|
||||
}
|
||||
// now we sort just the items we will output
|
||||
li := make(db, len(inv))
|
||||
i := 0
|
||||
for item := range inv {
|
||||
li[i] = item
|
||||
i++
|
||||
}
|
||||
sort.Sort(li)
|
||||
// finally ready to print
|
||||
for _, item := range li {
|
||||
tags := inv[item]
|
||||
fmt.Println("-----------------------------------")
|
||||
fmt.Println("Latest item with tags", tags)
|
||||
fmt.Println(item)
|
||||
}
|
||||
fmt.Println("-----------------------------------")
|
||||
}
|
||||
|
||||
// handle add command
|
||||
func add() {
|
||||
if len(os.Args) < 3 {
|
||||
usage("add command requires data")
|
||||
return
|
||||
} else if len(os.Args) == 3 {
|
||||
add1()
|
||||
} else {
|
||||
add4()
|
||||
}
|
||||
}
|
||||
|
||||
// add command with one data string. look for ws as separators.
|
||||
func add1() {
|
||||
data := strings.TrimLeftFunc(os.Args[2], unicode.IsSpace)
|
||||
if data == "" {
|
||||
// data must have at least some non-whitespace
|
||||
usage("invalid name")
|
||||
return
|
||||
}
|
||||
sep := strings.IndexFunc(data, unicode.IsSpace)
|
||||
if sep < 0 {
|
||||
// data consists only of a name
|
||||
addItem(data, nil, "")
|
||||
return
|
||||
}
|
||||
name := data[:sep]
|
||||
data = strings.TrimLeftFunc(data[sep:], unicode.IsSpace)
|
||||
if data == "" {
|
||||
// nevermind trailing ws, it's still only a name
|
||||
addItem(name, nil, "")
|
||||
return
|
||||
}
|
||||
if data[0] == '[' {
|
||||
sep = strings.Index(data, "]")
|
||||
if sep < 0 {
|
||||
// close bracketed list for the user. no notes.
|
||||
addItem(name, strings.Fields(data[1:]), "")
|
||||
} else {
|
||||
// brackets make things easy
|
||||
addItem(name, strings.Fields(data[1:sep]),
|
||||
strings.TrimLeftFunc(data[sep+1:], unicode.IsSpace))
|
||||
}
|
||||
return
|
||||
}
|
||||
sep = strings.IndexFunc(data, unicode.IsSpace)
|
||||
if sep < 0 {
|
||||
// remaining word is a tag
|
||||
addItem(name, []string{data}, "")
|
||||
} else {
|
||||
// there's a tag and some data
|
||||
addItem(name, []string{data[:sep]},
|
||||
strings.TrimLeftFunc(data[sep+1:], unicode.IsSpace))
|
||||
}
|
||||
}
|
||||
|
||||
// add command with multiple strings remaining on command line
|
||||
func add4() {
|
||||
name := os.Args[2]
|
||||
tag1 := os.Args[3]
|
||||
if tag1[0] != '[' {
|
||||
// no brackets makes things easy
|
||||
addItem(name, []string{tag1}, strings.Join(os.Args[4:], " "))
|
||||
return
|
||||
}
|
||||
if tag1[len(tag1)-1] == ']' {
|
||||
// tags all in one os.Arg is easy too
|
||||
addItem(name, strings.Fields(tag1[1:len(tag1)-1]),
|
||||
strings.Join(os.Args[4:], " "))
|
||||
return
|
||||
}
|
||||
// start a list for tags
|
||||
var tags []string
|
||||
if tag1 > "[" {
|
||||
tags = []string{tag1[1:]}
|
||||
}
|
||||
for x, tag := range os.Args[4:] {
|
||||
if tag[len(tag)-1] != ']' {
|
||||
tags = append(tags, tag)
|
||||
} else {
|
||||
// found end of tag list
|
||||
if tag > "]" {
|
||||
tags = append(tags, tag[:len(tag)-1])
|
||||
}
|
||||
addItem(name, tags, strings.Join(os.Args[5+x:], " "))
|
||||
return
|
||||
}
|
||||
}
|
||||
// close bracketed list for the user. no notes.
|
||||
addItem(name, tags, "")
|
||||
}
|
||||
|
||||
// complete the add command
|
||||
func addItem(name string, tags []string, notes string) {
|
||||
db, f, ok := open()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
// add the item and format JSON
|
||||
db = append(db, &Item{time.Now(), name, tags, notes})
|
||||
sort.Sort(db)
|
||||
js, err := json.MarshalIndent(db, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
// time to overwrite the file
|
||||
if _, err = f.Seek(0, 0); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
f.Truncate(0)
|
||||
if _, err = f.Write(js); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
128
Task/Simple-database/Haskell/simple-database.hs
Normal file
128
Task/Simple-database/Haskell/simple-database.hs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import Control.Monad.State
|
||||
import Data.List (sortBy, nub)
|
||||
import System.Environment (getArgs, getProgName)
|
||||
import System.Directory (doesFileExist)
|
||||
import System.IO (openFile, hGetContents, hClose, IOMode(..),
|
||||
Handle, hPutStrLn)
|
||||
|
||||
-- for storing dates
|
||||
data Date = Date Integer Int Int deriving (Show, Read, Eq, Ord)
|
||||
|
||||
-- for storing database items
|
||||
data Item = Item {description :: String
|
||||
,category :: [String]
|
||||
,date :: Date
|
||||
,optional :: [String]}
|
||||
deriving (Show, Read)
|
||||
|
||||
-- a state monad transformer which wraps IO actions.
|
||||
-- the database (state) is passed implicitly between functions.
|
||||
type ItemList a = StateT [Item] IO a
|
||||
|
||||
-- add an item to the database
|
||||
addItem :: Item -> ItemList ()
|
||||
addItem i = modify (++ [i])
|
||||
|
||||
-- get the newest of a list of items
|
||||
latest :: [Item] -> [Item]
|
||||
latest [] = []
|
||||
latest [x]= [x]
|
||||
latest xs = take 1 $ sortBy newer xs
|
||||
|
||||
-- compare two items to see which one is newer
|
||||
newer :: Item -> Item -> Ordering
|
||||
newer a b = compare (date b) (date a)
|
||||
|
||||
-- list all different categories (no duplicates)
|
||||
categories :: ItemList [String]
|
||||
categories = liftM (nub . concatMap category) get
|
||||
|
||||
-- list only the items with the given category tag
|
||||
filterByCategory :: String -> ItemList [Item]
|
||||
filterByCategory c = liftM (filter (\i -> c `elem` category i)) get
|
||||
|
||||
-- get the newest of all items
|
||||
lastOfAll :: ItemList [Item]
|
||||
lastOfAll = liftM latest get
|
||||
|
||||
-- get the newest item in each category
|
||||
latestByCategory :: ItemList [Item]
|
||||
latestByCategory = do
|
||||
cats <- categories
|
||||
filt <- mapM filterByCategory cats
|
||||
return $ concatMap latest filt
|
||||
|
||||
-- sort all items chronologically, newest first
|
||||
sortByDate :: ItemList [Item]
|
||||
sortByDate = liftM (sortBy newer) get
|
||||
|
||||
toScreen :: Item -> IO ()
|
||||
toScreen (Item desc cats (Date y m d) opt) = putStrLn $
|
||||
"Description:\t" ++ desc ++ "\nCategories:\t" ++ show cats ++
|
||||
"\nDate:\t\t" ++ show y ++ "-" ++ show m ++ "-" ++ show d ++
|
||||
"\nOther info:\t" ++ show opt
|
||||
|
||||
-- command line argument handling
|
||||
-- if the user called the program with the option "add", the
|
||||
-- new item is returned to main so that it can be saved to disk.
|
||||
-- the argument "opt" is a list.
|
||||
arguments :: ItemList [Item]
|
||||
arguments = do
|
||||
args <- liftIO getArgs
|
||||
case args of
|
||||
("add":desc:cat:year:month:day:opt) -> do
|
||||
let newItem = parseItem args
|
||||
addItem newItem
|
||||
return [newItem]
|
||||
("latest":[]) -> do
|
||||
item <- lastOfAll
|
||||
lift $ mapM_ toScreen item
|
||||
return []
|
||||
("category":[]) -> do
|
||||
items <- latestByCategory
|
||||
lift $ mapM_ toScreen items
|
||||
return []
|
||||
("all":[]) -> do
|
||||
sorted <- sortByDate
|
||||
lift $ mapM_ toScreen sorted
|
||||
return []
|
||||
_ -> do
|
||||
lift usage
|
||||
return []
|
||||
|
||||
parseItem :: [String] -> Item
|
||||
parseItem (_:desc:cat:year:month:day:opt) =
|
||||
Item {description = desc, category = words cat,
|
||||
date = Date (read year) (read month) (read day),
|
||||
optional = opt}
|
||||
|
||||
usage :: IO ()
|
||||
usage = do
|
||||
progName <- getProgName
|
||||
putStrLn $ "Usage: " ++ progName ++ " add|all|category|latest \
|
||||
\OPTIONS\n\nadd \"description\" \"category1 category2\"... \
|
||||
\year month day [\"note1\" \"note2\"...]\n\tAdds a new record \
|
||||
\to the database.\n\nall\n\tPrints all items in chronological \
|
||||
\order.\n\ncategory\n\tPrints the latest item for each category.\
|
||||
\\n\nlatest\n\tPrints the latest item."
|
||||
|
||||
-- the program creates, reads and writes to a file in the current directory
|
||||
main :: IO ()
|
||||
main = do
|
||||
progName <- getProgName
|
||||
let fileName = progName ++ ".db"
|
||||
e <- doesFileExist fileName
|
||||
if e
|
||||
then do
|
||||
hr <- openFile fileName ReadMode
|
||||
f <- hGetContents hr
|
||||
v <- evalStateT arguments (map read $ lines f)
|
||||
hClose hr -- must be called after working with contents!
|
||||
hw <- openFile fileName AppendMode
|
||||
mapM_ (hPutStrLn hw . show) v
|
||||
hClose hw
|
||||
else do
|
||||
v <- evalStateT arguments []
|
||||
hw <- openFile fileName WriteMode
|
||||
mapM_ (hPutStrLn hw . show) v
|
||||
hClose hw
|
||||
108
Task/Simple-database/J/simple-database-1.j
Normal file
108
Task/Simple-database/J/simple-database-1.j
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
HELP=: 0 :0
|
||||
Commands:
|
||||
|
||||
DBNAME add DATA
|
||||
DBNAME display the latest entry
|
||||
DBNAME display the latest entry where CATEGORY contains WORD
|
||||
DBNAME display all entries
|
||||
DBNAME display all entries order by CATEGORY
|
||||
|
||||
1) The first add with new DBNAME assign category names.
|
||||
2) lower case arguments verbatim.
|
||||
3) UPPER CASE: substitute your values.
|
||||
|
||||
Examples, having saved this program as a file named s :
|
||||
$ jconsole s simple.db display all entries
|
||||
$ jconsole s simple.db add "first field" "2nd field"
|
||||
)
|
||||
|
||||
Q=: '''' NB. quote character
|
||||
time=: 6!:0@:('YYYY-MM-DD:hh:mm:ss.sss'"_)
|
||||
|
||||
embed=: >@:{.@:[ , ] , >@:{:@:[
|
||||
assert '(x+y)' -: '()' embed 'x+y'
|
||||
|
||||
Duplicate=: 1 :'#~ m&= + 1 #~ #'
|
||||
assert 0 1 2 3 3 4 -: 3 Duplicate i.5
|
||||
|
||||
prepare=: LF ,~ [: }:@:; (Q;Q,';')&embed@:(Q Duplicate)&.>@:(;~ time)
|
||||
assert (-: }.@:".@:}:@:prepare) 'boxed';'';'li''st';'of';'''strings'''
|
||||
|
||||
categorize=: dyad define
|
||||
i=. x i. y
|
||||
if. (1 (~: #) i) +. i (= #) x do.
|
||||
smoutput 'choose 1 of'
|
||||
smoutput x
|
||||
exit 1
|
||||
end.
|
||||
{. i NB. "index of" frame has rank 1.
|
||||
)
|
||||
assert 0 -: 'abc' categorize 'a'
|
||||
|
||||
loadsdb=: (<'time') (<0 0)} ".;._2@:(1!:1)
|
||||
|
||||
Dispatch=: conjunction define
|
||||
help
|
||||
:
|
||||
commands=. y
|
||||
command=. {. commands
|
||||
x (u`help@.(command(i.~ ;:)n)) }.commands
|
||||
)
|
||||
|
||||
NB. the long fork in show groups (": #~ (1 1 embed (1j1 }:@:# (1 #~ #))))
|
||||
show=: smoutput@:(": #~ 1 1 embed 1j1 }:@:# 1 #~ #)
|
||||
|
||||
in=: +./@:E.
|
||||
assert 'the' in'quick brown fox jumps over the lazy dog'
|
||||
assert 'the'-.@:in'QUICK BROWN FOX JUMPS OVER THE LAZY DOG'
|
||||
|
||||
where=: dyad define
|
||||
'category contains word'=. 3 {. y
|
||||
if. 'contains' -.@:-: contains do.
|
||||
help''
|
||||
exit 1
|
||||
end.
|
||||
i=. x ({.@:[ categorize <@:]) category
|
||||
j=. {: I. ; word&in&.> i {"1 x
|
||||
if. 0 (= #) j do.
|
||||
smoutput 'no matches'
|
||||
else.
|
||||
x (show@:{~ 0&,) j
|
||||
end.
|
||||
)
|
||||
|
||||
entry=: 4 : 0
|
||||
if. a: = y do.
|
||||
show@:({. ,: {:) x
|
||||
else.
|
||||
x ''`where Dispatch'where' y
|
||||
end.
|
||||
)
|
||||
|
||||
latest=: ''`entry Dispatch'entry'
|
||||
the=: ''`latest Dispatch'latest'
|
||||
|
||||
by=: 4 : 0
|
||||
i=. x (categorize~ {.)~ y
|
||||
show ({. , (/: i&{"1)@:}.) x
|
||||
)
|
||||
|
||||
order=: ''`by Dispatch'by'
|
||||
|
||||
entries=: 4 : 0
|
||||
if. a: = y do.
|
||||
show x
|
||||
else.
|
||||
x ''`order Dispatch'order' y
|
||||
end.
|
||||
)
|
||||
|
||||
all=: ''`entries Dispatch'entries'
|
||||
|
||||
help=: smoutput@:(HELP"_)
|
||||
add=: 1!:3~ prepare NB. minimal---no error tests
|
||||
display=: (the`all Dispatch'the all'~ loadsdb)~ NB. load the simple db for some sort of display
|
||||
|
||||
({. add`display Dispatch'add display' }.)@:(2&}.)ARGV
|
||||
|
||||
exit 0
|
||||
13
Task/Simple-database/J/simple-database-2.j
Normal file
13
Task/Simple-database/J/simple-database-2.j
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
D='jconsole s dataflow'
|
||||
|
||||
$D add name expression algebraic rank valence example explanation
|
||||
$D add insert 'f/ y' 'insert f within y' infinite dyad 'sum=: +/' 'continued_fraction=:+`%/'
|
||||
$D add fork '(f g h)y' 'g(f(y),h(y))' infinite monad 'average=: +/ % #' 'sum divided by tally'
|
||||
$D add hook '(f g)y' 'f(y,g(y))' infinite monad '(/: 2&{"1)table' 'sort by third column'
|
||||
$D add hook 'x(f g)y' 'f(x,g(y))' infinite dyad 'display verb in s' 'a reflexive dyadic hook'
|
||||
$D add fork 'x(f g h)y' 'g(f(x,y),h(x,y))' infinite dyad '2j1(+ * -)9 12' 'product of sum and difference'
|
||||
$D add reflexive 'f~ y' 'f(y,y)' infinite monad '^~y' 'y raised to the power of y'
|
||||
$D add passive 'x f~ y' 'f(y,x)' 'ranks of f' dyad '(%~ i.@:>:) 8x' '8 intervals from 0 to 1'
|
||||
$D add atop 'f@g y' 'f(g(y))' 'rank of g' monad '*:@(+/)' 'square the sum'
|
||||
$D add atop 'x f@g y' 'f(g(x,y))' 'rank of g' dyad '>@{.' '(lisp) open the car'
|
||||
$D add 'many more!'
|
||||
76
Task/Simple-database/J/simple-database-3.j
Normal file
76
Task/Simple-database/J/simple-database-3.j
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
$ . input # source the input
|
||||
$ echo $D
|
||||
jconsole s dataflow
|
||||
$ $D display the latest entry
|
||||
┌───────────────────────┬──────────┬──────────┬─────────┬────┬───────┬───────┬───────────┐
|
||||
│time │name │expression│algebraic│rank│valence│example│explanation│
|
||||
│2012-02-07:20:36:54.749│many more!│ │ │ │ │ │ │
|
||||
└───────────────────────┴──────────┴──────────┴─────────┴────┴───────┴───────┴───────────┘
|
||||
$ $D display the latest entry where 'part of speech' contains verb
|
||||
choose 1 of
|
||||
┌────┬────┬──────────┬─────────┬────┬───────┬───────┬───────────┐
|
||||
│time│name│expression│algebraic│rank│valence│example│explanation│
|
||||
└────┴────┴──────────┴─────────┴────┴───────┴───────┴───────────┘
|
||||
$ $D display the latest entry where example contains average
|
||||
┌───────────────────────┬────┬──────────┬────────────┬────────┬───────┬────────────────┬────────────────────┐
|
||||
│time │name│expression│algebraic │rank │valence│example │explanation │
|
||||
│2012-02-07:20:36:54.564│fork│(f g h)y │g(f(y),h(y))│infinite│monad │average=: +/ % #│sum divided by tally│
|
||||
└───────────────────────┴────┴──────────┴────────────┴────────┴───────┴────────────────┴────────────────────┘
|
||||
$ $D display all entries ordre by valence # oops! transposition typo.
|
||||
Commands:
|
||||
|
||||
DBNAME add DATA
|
||||
DBNAME display the latest entry
|
||||
DBNAME display the latest entry where CATEGORY contains WORD
|
||||
DBNAME display all entries
|
||||
DBNAME display all entries order by CATEGORY
|
||||
|
||||
1) The first add with new DBNAME assign category names.
|
||||
2) lower case arguments verbatim.
|
||||
3) UPPER CASE: substitute your values.
|
||||
|
||||
Examples, having saved this program as a file named s :
|
||||
$ jconsole s simple.db display all entries
|
||||
$ jconsole s simple.db add "first field" "2nd field"
|
||||
|
||||
$ $D display all entries order by valence
|
||||
┌───────────────────────┬──────────┬──────────┬─────────────────┬──────────┬───────┬─────────────────┬─────────────────────────────┐
|
||||
│time │name │expression│algebraic │rank │valence│example │explanation │
|
||||
│2012-02-08:23:45:06.539│many more!│ │ │ │ │ │ │
|
||||
│2012-02-08:23:45:06.329│insert │f/ y │insert f within y│infinite │dyad │sum=: +/ │continued_fraction=:+`%/ │
|
||||
│2012-02-08:23:45:06.400│hook │x(f g)y │f(x,g(y)) │infinite │dyad │display verb in s│a reflexive dyadic hook │
|
||||
│2012-02-08:23:45:06.426│fork │x(f g h)y │g(f(x,y),h(x,y)) │infinite │dyad │2j1(+ * -)9 12 │product of sum and difference│
|
||||
│2012-02-08:23:45:06.471│passive │x f~ y │f(y,x) │ranks of f│dyad │(%~ i.@:>:) 8x │8 intervals from 0 to 1 │
|
||||
│2012-02-08:23:45:06.515│atop │x f@g y │f(g(x,y)) │rank of g │dyad │>@{. │(lisp) open the car │
|
||||
│2012-02-08:23:45:06.353│fork │(f g h)y │g(f(y),h(y)) │infinite │monad │average=: +/ % # │sum divided by tally │
|
||||
│2012-02-08:23:45:06.376│hook │(f g)y │f(y,g(y)) │infinite │monad │(/: 2&{"1)table │sort by third column │
|
||||
│2012-02-08:23:45:06.448│reflexive │f~ y │f(y,y) │infinite │monad │^~y │y raised to the power of y │
|
||||
│2012-02-08:23:45:06.493│atop │f@g y │f(g(y)) │rank of g │monad │*:@(+/) │square the sum │
|
||||
└───────────────────────┴──────────┴──────────┴─────────────────┴──────────┴───────┴─────────────────┴─────────────────────────────┘
|
||||
$ $D display all entries
|
||||
┌───────────────────────┬──────────┬──────────┬─────────────────┬──────────┬───────┬─────────────────┬─────────────────────────────┐
|
||||
│time │name │expression│algebraic │rank │valence│example │explanation │
|
||||
│2012-02-08:23:45:06.329│insert │f/ y │insert f within y│infinite │dyad │sum=: +/ │continued_fraction=:+`%/ │
|
||||
│2012-02-08:23:45:06.353│fork │(f g h)y │g(f(y),h(y)) │infinite │monad │average=: +/ % # │sum divided by tally │
|
||||
│2012-02-08:23:45:06.376│hook │(f g)y │f(y,g(y)) │infinite │monad │(/: 2&{"1)table │sort by third column │
|
||||
│2012-02-08:23:45:06.400│hook │x(f g)y │f(x,g(y)) │infinite │dyad │display verb in s│a reflexive dyadic hook │
|
||||
│2012-02-08:23:45:06.426│fork │x(f g h)y │g(f(x,y),h(x,y)) │infinite │dyad │2j1(+ * -)9 12 │product of sum and difference│
|
||||
│2012-02-08:23:45:06.448│reflexive │f~ y │f(y,y) │infinite │monad │^~y │y raised to the power of y │
|
||||
│2012-02-08:23:45:06.471│passive │x f~ y │f(y,x) │ranks of f│dyad │(%~ i.@:>:) 8x │8 intervals from 0 to 1 │
|
||||
│2012-02-08:23:45:06.493│atop │f@g y │f(g(y)) │rank of g │monad │*:@(+/) │square the sum │
|
||||
│2012-02-08:23:45:06.515│atop │x f@g y │f(g(x,y)) │rank of g │dyad │>@{. │(lisp) open the car │
|
||||
│2012-02-08:23:45:06.539│many more!│ │ │ │ │ │ │
|
||||
└───────────────────────┴──────────┴──────────┴─────────────────┴──────────┴───────┴─────────────────┴─────────────────────────────┘
|
||||
$ cat dataflow
|
||||
'2012-02-08:23:45:06.304';'name';'expression';'algebraic';'rank';'valence';'example';'explanation'
|
||||
'2012-02-08:23:45:06.329';'insert';'f/ y';'insert f within y';'infinite';'dyad';'sum=: +/';'continued_fraction=:+`%/'
|
||||
'2012-02-08:23:45:06.353';'fork';'(f g h)y';'g(f(y),h(y))';'infinite';'monad';'average=: +/ % #';'sum divided by tally'
|
||||
'2012-02-08:23:45:06.376';'hook';'(f g)y';'f(y,g(y))';'infinite';'monad';'(/: 2&{"1)table';'sort by third column'
|
||||
'2012-02-08:23:45:06.400';'hook';'x(f g)y';'f(x,g(y))';'infinite';'dyad';'display verb in s';'a reflexive dyadic hook'
|
||||
'2012-02-08:23:45:06.426';'fork';'x(f g h)y';'g(f(x,y),h(x,y))';'infinite';'dyad';'2j1(+ * -)9 12';'product of sum and difference'
|
||||
'2012-02-08:23:45:06.448';'reflexive';'f~ y';'f(y,y)';'infinite';'monad';'^~y';'y raised to the power of y'
|
||||
'2012-02-08:23:45:06.471';'passive';'x f~ y';'f(y,x)';'ranks of f';'dyad';'(%~ i.@:>:) 8x';'8 intervals from 0 to 1'
|
||||
'2012-02-08:23:45:06.493';'atop';'f@g y';'f(g(y))';'rank of g';'monad';'*:@(+/)';'square the sum'
|
||||
'2012-02-08:23:45:06.515';'atop';'x f@g y';'f(g(x,y))';'rank of g';'dyad';'>@{.';'(lisp) open the car'
|
||||
'2012-02-08:23:45:06.539';'many more!'
|
||||
$
|
||||
125
Task/Simple-database/Java/simple-database.java
Normal file
125
Task/Simple-database/Java/simple-database.java
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
public class SimpleDatabase {
|
||||
|
||||
final static String filename = "simdb.csv";
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length < 1 || args.length > 3) {
|
||||
printUsage();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "add":
|
||||
addItem(args);
|
||||
break;
|
||||
case "latest":
|
||||
printLatest(args);
|
||||
break;
|
||||
case "all":
|
||||
printAll();
|
||||
break;
|
||||
default:
|
||||
printUsage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Item implements Comparable<Item>{
|
||||
final String name;
|
||||
final String date;
|
||||
final String category;
|
||||
|
||||
Item(String n, String d, String c) {
|
||||
name = n;
|
||||
date = d;
|
||||
category = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Item item){
|
||||
return date.compareTo(item.date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s,%s,%s%n", name, date, category);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addItem(String[] input) {
|
||||
if (input.length < 2) {
|
||||
printUsage();
|
||||
return;
|
||||
}
|
||||
List<Item> db = load();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String date = sdf.format(new Date());
|
||||
String cat = (input.length == 3) ? input[2] : "none";
|
||||
db.add(new Item(input[1], date, cat));
|
||||
store(db);
|
||||
}
|
||||
|
||||
private static void printLatest(String[] a) {
|
||||
List<Item> db = load();
|
||||
if (db.isEmpty()) {
|
||||
System.out.println("No entries in database.");
|
||||
return;
|
||||
}
|
||||
Collections.sort(db);
|
||||
if (a.length == 2) {
|
||||
for (Item item : db)
|
||||
if (item.category.equals(a[1]))
|
||||
System.out.println(item);
|
||||
} else {
|
||||
System.out.println(db.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
private static void printAll() {
|
||||
List<Item> db = load();
|
||||
if (db.isEmpty()) {
|
||||
System.out.println("No entries in database.");
|
||||
return;
|
||||
}
|
||||
Collections.sort(db);
|
||||
for (Item item : db)
|
||||
System.out.println(item);
|
||||
}
|
||||
|
||||
private static List<Item> load() {
|
||||
List<Item> db = new ArrayList<>();
|
||||
try (Scanner sc = new Scanner(new File(filename))) {
|
||||
while (sc.hasNext()) {
|
||||
String[] item = sc.nextLine().split(",");
|
||||
db.add(new Item(item[0], item[1], item[2]));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
private static void store(List<Item> db) {
|
||||
try (FileWriter fw = new FileWriter(filename)) {
|
||||
for (Item item : db)
|
||||
fw.write(item.toString());
|
||||
} catch (IOException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" simdb cmd [categoryName]");
|
||||
System.out.println(" add add item, followed by optional category");
|
||||
System.out.println(" latest print last added item(s), followed by "
|
||||
+ "optional category");
|
||||
System.out.println(" all print all");
|
||||
System.out.println(" For instance: add \"some item name\" "
|
||||
+ "\"some category name\"");
|
||||
}
|
||||
}
|
||||
60
Task/Simple-database/Julia/simple-database.julia
Normal file
60
Task/Simple-database/Julia/simple-database.julia
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using CSV, DataFrames, ArgParse, Dates
|
||||
|
||||
setting = ArgParseSettings()
|
||||
@add_arg_table setting begin
|
||||
"--add"
|
||||
help = "add an entry, within double quotes, comma separated as \"name,birthdate,state,relation,email\" with birthdate as yyyy-mm-dd"
|
||||
"--latest"
|
||||
action = :store_true
|
||||
nargs = 0
|
||||
help = "print latest (last) entry"
|
||||
"--latestfriend"
|
||||
action = :store_true
|
||||
nargs = 0
|
||||
help = "print last friend listed"
|
||||
"--latestfamily"
|
||||
action = :store_true
|
||||
nargs = 0
|
||||
help = "print last family member listed"
|
||||
"--listbyage"
|
||||
action = :store_true
|
||||
nargs = 0
|
||||
help = "print all ages and entries in birth order"
|
||||
end
|
||||
|
||||
const filename = "example.csv"
|
||||
const df = CSV.File(filename, dateformat="yyyy-mm-dd") |> DataFrame
|
||||
const commands = parse_args(setting)
|
||||
if length(ARGS) == 0
|
||||
ArgParse.show_help(setting)
|
||||
end
|
||||
const changeflag = [false]
|
||||
|
||||
for (k, v) in commands
|
||||
if k == "add" && v != nothing
|
||||
newrow = Vector{Any}(split(v, r","))
|
||||
if length(newrow) == 5 && tryparse(DateTime, newrow[2]) != nothing
|
||||
newrow[2] = DateTime(newrow[2])
|
||||
push!(df, newrow)
|
||||
changeflag[1] = true
|
||||
println("Added entry $newrow.")
|
||||
end
|
||||
elseif k == "latest" && v
|
||||
println("The latest entry is $(df[end, :])")
|
||||
elseif k == "latestfriend" && v
|
||||
println(df[df.Relation .== "friend", :][end, :])
|
||||
elseif k == "latestfamily" && v
|
||||
println(df[df.Relation .== "family", :][end, :])
|
||||
elseif k == "listbyage" && v
|
||||
dobcol = df[:Birthdate]
|
||||
age = map(x -> round((now() - DateTime(x)).value /(1000*3600*24*365.25), digits=1), dobcol)
|
||||
df2 = deepcopy(df)
|
||||
df2 = insert!(df, 1, age, :Age)
|
||||
println(sort(df2, (:Age)))
|
||||
end
|
||||
end
|
||||
|
||||
if changeflag[1]
|
||||
CSV.write(filename, df)
|
||||
println("Changes written to file $filename.")
|
||||
end
|
||||
110
Task/Simple-database/Kotlin/simple-database.kotlin
Normal file
110
Task/Simple-database/Kotlin/simple-database.kotlin
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// version 1.2.31
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
val file = File("simdb.csv")
|
||||
|
||||
class Item(
|
||||
val name: String,
|
||||
val date: String,
|
||||
val category: String
|
||||
) : Comparable<Item> {
|
||||
|
||||
override fun compareTo(other: Item) = date.compareTo(other.date)
|
||||
|
||||
override fun toString() = "$name, $date, $category"
|
||||
}
|
||||
|
||||
fun addItem(input: Array<String>) {
|
||||
if (input.size < 2) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
||||
val date = sdf.format(Date())
|
||||
val cat = if (input.size == 3) input[2] else "none"
|
||||
store(Item(input[1], date, cat))
|
||||
}
|
||||
|
||||
fun printLatest(a: Array<String>) {
|
||||
val db = load()
|
||||
if (db.isEmpty()) {
|
||||
println("No entries in database.")
|
||||
return
|
||||
}
|
||||
// no need to sort db as items are added chronologically
|
||||
if (a.size == 2) {
|
||||
var found = false
|
||||
for (item in db.reversed()) {
|
||||
if (item.category == a[1]) {
|
||||
println(item)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) println("There are no items for category '${a[1]}'")
|
||||
}
|
||||
else println(db[db.lastIndex])
|
||||
}
|
||||
|
||||
fun printAll() {
|
||||
val db = load()
|
||||
if (db.isEmpty()) {
|
||||
println("No entries in database.")
|
||||
return
|
||||
}
|
||||
// no need to sort db as items are added chronologically
|
||||
for (item in db) println(item)
|
||||
}
|
||||
|
||||
fun load(): MutableList<Item> {
|
||||
val db = mutableListOf<Item>()
|
||||
try {
|
||||
file.forEachLine { line ->
|
||||
val item = line.split(", ")
|
||||
db.add(Item(item[0], item[1], item[2]))
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
println(e)
|
||||
System.exit(1)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
fun store(item: Item) {
|
||||
try {
|
||||
file.appendText("$item\n")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
println(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun printUsage() {
|
||||
println("""
|
||||
|Usage:
|
||||
| simdb cmd [categoryName]
|
||||
| add add item, followed by optional category
|
||||
| latest print last added item(s), followed by optional category
|
||||
| all print all
|
||||
| For instance: add "some item name" "some category name"
|
||||
""".trimMargin())
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size !in 1..3) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
file.createNewFile() // create file if it doesn't already exist
|
||||
when (args[0].toLowerCase()) {
|
||||
"add" -> addItem(args)
|
||||
"latest" -> printLatest(args)
|
||||
"all" -> printAll()
|
||||
else -> printUsage()
|
||||
}
|
||||
}
|
||||
181
Task/Simple-database/M2000-Interpreter/simple-database.m2000
Normal file
181
Task/Simple-database/M2000-Interpreter/simple-database.m2000
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
MODULE GLOBAL interpret {
|
||||
global filename$="base1.xml"
|
||||
module latest {
|
||||
PrintConsoleLn("The latest entry is:")
|
||||
if exist(filename$) else exit
|
||||
declare xml xmlData
|
||||
with xml, "xml" as doc$, "beautify" as beautify
|
||||
doc$=string$(eval$(buffer(filename$)) as UTF8dec)
|
||||
with xml, "lastchild" set child
|
||||
with child,"attr" as attr$()
|
||||
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
|
||||
declare xml nothing
|
||||
}
|
||||
module latestForEachTag {
|
||||
PrintConsoleLn("latest entry for each tag:")
|
||||
if exist(filename$) else exit
|
||||
declare xml xmlData
|
||||
with xml, "xml" as doc$, "beautify" as beautify
|
||||
doc$=string$(eval$(buffer("base1.xml")) as UTF8dec)
|
||||
with xml, "firstchild" as firstchild
|
||||
child=firstchild
|
||||
with child,"attr" as attr$()
|
||||
inventory alfa
|
||||
do
|
||||
if not exist(alfa, @tag$()) then
|
||||
append alfa, @tag$():=child
|
||||
else
|
||||
return alfa, @tag$():=child
|
||||
end if
|
||||
Method xml, "EndOffChilds", &child as ok
|
||||
when ok
|
||||
sort alfa
|
||||
k=each(alfa)
|
||||
while k
|
||||
child=eval(k)
|
||||
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
|
||||
end while
|
||||
declare xml nothing
|
||||
}
|
||||
module All {
|
||||
PrintConsoleLn("All entries sorted by date:")
|
||||
if exist(filename$) else exit
|
||||
declare xml xmlData
|
||||
with xml, "xml" as doc$, "beautify" as beautify
|
||||
doc$=string$(eval$(buffer("base1.xml")) as UTF8dec)
|
||||
with xml, "firstchild" as firstchild
|
||||
child=firstchild
|
||||
with child,"attr" as attr$()
|
||||
inventory alfa
|
||||
i=0
|
||||
do
|
||||
// prevent same keys using a unique patch key
|
||||
append alfa, attr$("date")+str$(i,"000000"):=child
|
||||
i++
|
||||
Method xml, "EndOffChilds", &child as ok
|
||||
when ok
|
||||
sort alfa
|
||||
k=each(alfa)
|
||||
while k
|
||||
child=eval(k)
|
||||
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
|
||||
end while
|
||||
declare xml nothing
|
||||
}
|
||||
module add (line$) {
|
||||
line$=trim$(line$)
|
||||
if line$="" then exit
|
||||
declare xml xmlData
|
||||
with xml, "xml" as doc$, "beautify" as beautify
|
||||
bom$=str$(format$("\uef\ubb\ubf"))
|
||||
// len(bom$)=1.5 (1.5*2=3 bytes)
|
||||
k=0
|
||||
if exist(filename$) then try {k=filelen(filename$)}
|
||||
if k<10 then
|
||||
method xml, "PrepareNodeSimple", "xml" as ProcessInstructions
|
||||
method xml, "PlaceAttributeToNode", ProcessInstructions, "version", "1.0"
|
||||
method xml, "PlaceAttributeToNode", ProcessInstructions, "encoding", "utf-8-sig"
|
||||
method xml, "PlaceProcessingInstructions", ProcessInstructions
|
||||
method xml, "PrepareNode", "MyFile" as Node
|
||||
method xml, "InsertNode", Node
|
||||
else
|
||||
doc$=string$(eval$(buffer(filename$)) as UTF8dec)
|
||||
end if
|
||||
a$=""""+line$
|
||||
def name$, tag$,date$
|
||||
do
|
||||
a$=rightpart$(a$, """") : what$=lcase$(trim$(leftpart$(a$, """")))
|
||||
if what$="" then exit
|
||||
a$=rightpart$(a$, """") :par$=leftpart$(a$, """")
|
||||
select case what$
|
||||
case "name"
|
||||
name$=par$
|
||||
case "tag"
|
||||
tag$=par$
|
||||
case "date"
|
||||
date$=par$
|
||||
end select
|
||||
always
|
||||
if name$<>"" and date$<>"" then
|
||||
method xml, "PrepareNode", "Row", "" as Node1
|
||||
method xml, "PlaceAttributeToNode", Node1, "name", name$
|
||||
if tag$<>"" then method xml, "PlaceAttributeToNode", Node1, "tag", tag$
|
||||
method xml, "PlaceAttributeToNode", Node1, "date", date$
|
||||
method xml, "AppendChild", Node1
|
||||
open filename$ for wide output as #f
|
||||
print #f, bom$;string$(doc$ as UTF8enc);
|
||||
close #f
|
||||
beautify=-4
|
||||
PrintConsoleLn(doc$)
|
||||
end if
|
||||
declare xml nothing
|
||||
}
|
||||
declare FreeConsole lib "Kernel32.FreeConsole"
|
||||
declare GetStdHandle lib "Kernel32.GetStdHandle" {long a}
|
||||
declare AttachConsole lib "Kernel32.AttachConsole" {long a}
|
||||
declare CloseHandle lib "Kernel32.CloseHandle" {long a}
|
||||
declare global WriteCons Lib "Kernel32.WriteConsoleW" {long cons, a$, long n, Long p, long u}
|
||||
long STD_OUTPUT_HANDLE=-11
|
||||
global retvalue
|
||||
buffer clear retvalue as long
|
||||
ret=AttachConsole(-1)
|
||||
global m=GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
if ret=0 then beep: exit
|
||||
if not islet then
|
||||
try {
|
||||
open "tool.bat" for output as #f
|
||||
print #f, {@}+appdir$+{m2000.exe data {%*}: dir %cd%:load tool
|
||||
}
|
||||
close #f
|
||||
}
|
||||
PrintConsoleLn("")
|
||||
dos "tool.bat"
|
||||
|
||||
else
|
||||
read cmd$
|
||||
cmd$=trim$(cmd$)+" "
|
||||
select case lcase$(leftpart$(cmd$, " "))
|
||||
case "add"
|
||||
add rightpart$(cmd$," ")
|
||||
case "latest"
|
||||
latest
|
||||
case "latest-per-tag"
|
||||
latestForEachTag
|
||||
case "all-entries"
|
||||
all
|
||||
case else
|
||||
help()
|
||||
end select
|
||||
end if
|
||||
call void closehandle(m)
|
||||
call void freeconsole()
|
||||
|
||||
Sub PrintConsole(a$)
|
||||
Call Void WriteCons(m, a$, Len(a$), retvalue(0), 0)
|
||||
End Sub
|
||||
Sub PrintConsoleLn(a$)
|
||||
a$+={
|
||||
}
|
||||
Call Void WriteCons(m, a$, Len(a$), retvalue(0), 0)
|
||||
End Sub
|
||||
// function is static here but can be called from child modules, because there are in the same block of code
|
||||
// although attr$() must defined in each module. (scope constrain to module block, for local identifiers).
|
||||
function tag$()
|
||||
try { // if no tag exist error raised
|
||||
=attr$("tag")
|
||||
}
|
||||
end function
|
||||
Sub Help()
|
||||
h$={Commands:
|
||||
tool add name "anyname" tag "tagtext" date "YYYY.MM.DD.HH:MM"
|
||||
tool latest
|
||||
tool latest-per-tag
|
||||
tool all-entries
|
||||
}
|
||||
PrintConsole(h$)
|
||||
End Sub
|
||||
}
|
||||
module interpret1 {
|
||||
try {interpret}
|
||||
}
|
||||
interpret1: end
|
||||
101
Task/Simple-database/Nim/simple-database.nim
Normal file
101
Task/Simple-database/Nim/simple-database.nim
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import algorithm, json, os, strformat, strutils, times
|
||||
|
||||
const FileName = "simdb.json"
|
||||
|
||||
type
|
||||
|
||||
Item = object
|
||||
name: string
|
||||
date: string
|
||||
category: string
|
||||
|
||||
Database = seq[Item]
|
||||
|
||||
DbError = object of CatchableError
|
||||
|
||||
|
||||
proc load(): Database =
|
||||
if fileExists(FileName):
|
||||
let node = try: FileName.parseFile()
|
||||
except JsonParsingError:
|
||||
raise newException(DbError, getCurrentExceptionMsg())
|
||||
result = node.to(DataBase)
|
||||
|
||||
|
||||
proc store(db: Database) =
|
||||
try:
|
||||
FileName.writeFile $(%* db)
|
||||
except IOError:
|
||||
quit "Unable to save database.", QuitFailure
|
||||
|
||||
|
||||
proc addItem(args: seq[string]) =
|
||||
var db = try: load()
|
||||
except DbError: quit getCurrentExceptionMsg(), QuitFailure
|
||||
|
||||
let date = now().format("yyyy-MM-dd HH:mm:ss")
|
||||
let cat = if args.len == 2: args[1] else: "none"
|
||||
db.add Item(name: args[0], date: date, category: cat)
|
||||
db.store()
|
||||
|
||||
|
||||
proc printLatest(args: seq[string]) =
|
||||
let db = try: load()
|
||||
except DbError: quit getCurrentExceptionMsg(), QuitFailure
|
||||
if db.len == 0:
|
||||
echo "No entries in database."
|
||||
return
|
||||
|
||||
# No need to sort db as items are added chronologically.
|
||||
if args.len == 1:
|
||||
var found = false
|
||||
for item in reversed(db):
|
||||
if item.category == args[0]:
|
||||
echo item
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
echo &"There are no items for category '{args[0]}'"
|
||||
else:
|
||||
echo db[^1]
|
||||
|
||||
|
||||
proc printAll() =
|
||||
let db = try: load()
|
||||
except DbError: quit getCurrentExceptionMsg(), QuitFailure
|
||||
if db.len == 0:
|
||||
echo "No entries in database."
|
||||
return
|
||||
for item in db:
|
||||
echo item
|
||||
|
||||
|
||||
proc printUsage() =
|
||||
echo &"""
|
||||
Usage:
|
||||
{getAppFilename().splitPath().tail} cmd [categoryName]
|
||||
|
||||
add add item, followed by optional category
|
||||
latest print last added item(s), followed by optional category
|
||||
all print all
|
||||
|
||||
For instance: add "some item name" "some category name"
|
||||
"""
|
||||
quit QuitFailure
|
||||
|
||||
|
||||
if paramCount() notin 1..3: printUsage()
|
||||
|
||||
var params = commandLineParams()
|
||||
let command = params[0].toLowerAscii
|
||||
params.delete(0)
|
||||
case command
|
||||
of "add":
|
||||
if params.len == 0: printUsage()
|
||||
addItem(params)
|
||||
of "latest":
|
||||
if params.len > 1: printUsage()
|
||||
printLatest(params)
|
||||
of "all":
|
||||
if params.len != 0: printUsage()
|
||||
printAll()
|
||||
118
Task/Simple-database/Perl/simple-database.pl
Normal file
118
Task/Simple-database/Perl/simple-database.pl
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/perl
|
||||
use warnings;
|
||||
use strict;
|
||||
use feature qw{ say };
|
||||
|
||||
use JSON::PP;
|
||||
use Time::Piece;
|
||||
|
||||
use constant {
|
||||
NAME => 0,
|
||||
CATEGORY => 1,
|
||||
DATE => 2,
|
||||
DB => 'simple-db',
|
||||
};
|
||||
|
||||
my $operation = shift // "";
|
||||
|
||||
my %dispatch = (
|
||||
n => \&add_new,
|
||||
l => \&print_latest,
|
||||
L => \&print_latest_for_categories,
|
||||
a => \&print_all,
|
||||
);
|
||||
|
||||
if ($dispatch{$operation}) {
|
||||
$dispatch{$operation}->(@ARGV);
|
||||
} else {
|
||||
die "Invalid option. Use one of n, l, L, a.\n"
|
||||
}
|
||||
|
||||
sub add_new {
|
||||
my ($name, $category, $date) = @_;
|
||||
my $db = eval { load() } || {};
|
||||
if (defined $date) {
|
||||
eval { 'Time::Piece'->strptime($date, '%Y-%m-%d'); 1 }
|
||||
or die "Invalid date format: YYYY-MM-DD.\n";
|
||||
|
||||
} else {
|
||||
$date //= localtime->ymd;
|
||||
}
|
||||
|
||||
my @ids = keys %{ $db->{by_id} };
|
||||
my $max_id = max(num => @ids) || 0;
|
||||
$db->{by_id}{ ++$max_id } = [ $name, $category, $date ];
|
||||
save($db);
|
||||
}
|
||||
|
||||
sub print_latest {
|
||||
build_indexes( my $db = load(), 0, 1 );
|
||||
_print_latest($db);
|
||||
}
|
||||
|
||||
sub _print_latest {
|
||||
my ($db, $category) = @_;
|
||||
my @dates = keys %{ $db->{by_date} };
|
||||
@dates = grep {
|
||||
grep $db->{by_id}{$_}[CATEGORY] eq $category,
|
||||
@{ $db->{by_date}{$_} };
|
||||
} @dates if defined $category;
|
||||
|
||||
my $last_date = max(str => @dates);
|
||||
say for map $db->{by_id}{$_}[NAME],
|
||||
grep ! defined $category
|
||||
|| $db->{by_id}{$_}[CATEGORY] eq $category,
|
||||
@{ $db->{by_date}{$last_date} };
|
||||
}
|
||||
|
||||
sub max {
|
||||
my $type = shift;
|
||||
my $max = $_[0];
|
||||
{ num => sub { $_ > $max },
|
||||
str => sub { $_ gt $max},
|
||||
}->{$type}->() and $max = $_
|
||||
for @_[ 1 .. $#_ ];
|
||||
return $max
|
||||
}
|
||||
|
||||
sub print_latest_for_categories {
|
||||
build_indexes( my $db = load(), 1, 1 );
|
||||
|
||||
for my $category (sort keys %{ $db->{by_category} }){
|
||||
say "* $category";
|
||||
_print_latest($db, $category);
|
||||
}
|
||||
}
|
||||
|
||||
sub print_all {
|
||||
build_indexes( my $db = load(), 0, 1 );
|
||||
|
||||
for my $date (sort keys %{ $db->{by_date} }) {
|
||||
for my $id (@{ $db->{by_date}{$date} }) {
|
||||
say $db->{by_id}{$id}[NAME];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load {
|
||||
open my $in, '<', DB or die "Can't open database: $!\n";
|
||||
local $/;
|
||||
return { by_id => decode_json(<$in>) };
|
||||
}
|
||||
|
||||
sub save {
|
||||
my ($db) = @_;
|
||||
open my $out, '>', DB or die "Can't save database: $!\n";
|
||||
print {$out} encode_json($db->{by_id});
|
||||
close $out;
|
||||
}
|
||||
|
||||
sub build_indexes {
|
||||
my ($db, $by_category, $by_date) = @_;
|
||||
for my $id (keys %{ $db->{by_id} }) {
|
||||
push @{ $db->{by_category}{ $db->{by_id}{$id}[CATEGORY] } }, $id
|
||||
if $by_category;
|
||||
push @{ $db->{by_date}{ $db->{by_id}{$id}[DATE] } }, $id
|
||||
if $by_date;
|
||||
}
|
||||
}
|
||||
101
Task/Simple-database/Phix/simple-database.phix
Normal file
101
Task/Simple-database/Phix/simple-database.phix
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
(notonline)-->
|
||||
<span style="color: #000080;font-style:italic;">--
|
||||
-- demo\rosetta\Simple_db.exw
|
||||
-- ==========================
|
||||
--</span>
|
||||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o, gets(0), getenv)</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #004080;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">filename</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getenv</span><span style="color: #0000FF;">(</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">WINDOWS</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"APPDATA"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"HOME"</span><span style="color: #0000FF;">))&</span><span style="color: #008000;">"/simple_db.csv"</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)></span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"usage: add name [cat]\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
|
||||
<span style="color: #000000;">cat</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">?</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]:</span><span style="color: #008000;">"none"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">datestr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">format_timedate</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">date</span><span style="color: #0000FF;">(),</span><span style="color: #008000;">"YYYY/MM/DD h:mmpm"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"a"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s,%s,%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cat</span><span style="color: #0000FF;">,</span><span style="color: #000000;">datestr</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"file not found\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">lc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lc</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"<no entries for that category>\n"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"<empty>\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">lc</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">,</span><span style="color: #008000;">','</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">line</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">last</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">dates</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">by_date</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">d1</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">d2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d2</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sort_by_date</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000080;font-style:italic;">-- (simple_db.csv should be edited manually to prove the date sort works)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"file not found\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #000000;">dates</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">dates</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">,</span><span style="color: #008000;">','</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">by_date</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)))</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">switch</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">case</span> <span style="color: #008000;">"add"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
|
||||
<span style="color: #008080;">case</span> <span style="color: #008000;">"last"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
|
||||
<span style="color: #008080;">case</span> <span style="color: #008000;">"sort"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sort_by_date</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">default</span><span style="color: #0000FF;">:</span> <span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"unknown command: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">helptext</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
|
||||
p demo\rosetta\Simple_db -- interactive mode, commands as below
|
||||
p demo\rosetta\Simple_db add name [cat] -- add entry
|
||||
p demo\rosetta\Simple_db last [cat] -- show last entry [in specified category]
|
||||
p demo\rosetta\Simple_db sort -- show full list sorted by date
|
||||
"""</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">cl</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">command_line</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cl</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">3</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000080;font-style:italic;">-- interactive mode</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">helptext</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">">"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cl</span><span style="color: #0000FF;">[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">..$])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<!--
|
||||
36
Task/Simple-database/PicoLisp/simple-database.l
Normal file
36
Task/Simple-database/PicoLisp/simple-database.l
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/pil
|
||||
|
||||
(de usage ()
|
||||
(prinl
|
||||
"Usage:^J\
|
||||
sdb <file> add <title> <cat> <date> ... Add a new entry^J\
|
||||
sdb <file> get <title> Retrieve an entry^J\
|
||||
sdb <file> latest Print the latest entry^J\
|
||||
sdb <file> categories Print the latest for each cat^J\
|
||||
sdb <file> Print all, sorted by date" ) )
|
||||
|
||||
(de printEntry (E)
|
||||
(apply println (cdddr E) (car E) (cadr E) (datStr (caddr E))) )
|
||||
|
||||
(ifn (setq *File (opt))
|
||||
(usage)
|
||||
(case (opt)
|
||||
(add
|
||||
(let (Ttl (opt) Cat (opt))
|
||||
(if (strDat (opt))
|
||||
(rc *File Ttl (cons Cat @ (argv)))
|
||||
(prinl "Bad date") ) ) )
|
||||
(get
|
||||
(let Ttl (opt)
|
||||
(when (rc *File Ttl)
|
||||
(printEntry (cons Ttl @)) ) ) )
|
||||
(latest
|
||||
(printEntry (maxi caddr (in *File (read)))) )
|
||||
(categories
|
||||
(for Cat (by cadr group (in *File (read)))
|
||||
(printEntry (maxi caddr Cat)) ) )
|
||||
(NIL
|
||||
(mapc printEntry (by caddr sort (in *File (read)))) )
|
||||
(T (usage)) ) )
|
||||
|
||||
(bye)
|
||||
154
Task/Simple-database/Pike/simple-database.pike
Normal file
154
Task/Simple-database/Pike/simple-database.pike
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
mapping db = ([]);
|
||||
|
||||
mapping make_episode(string series, string title, string episode, array date)
|
||||
{
|
||||
return ([ "series":series, "episode":episode, "title":title, "date":date ]);
|
||||
}
|
||||
|
||||
void print_episode(mapping episode)
|
||||
{
|
||||
write(" %-30s %10s %-30s (%{%d.%})\n",
|
||||
episode->series, episode->episode, episode->title, episode->date);
|
||||
}
|
||||
|
||||
void print_series(mapping series)
|
||||
{
|
||||
write("%-30s %-10s\n", series->series, series->status);
|
||||
map(series->episodes, print_episode);
|
||||
}
|
||||
|
||||
void dump_db(mapping database)
|
||||
{
|
||||
foreach(database; string name; mapping series)
|
||||
{
|
||||
print_series(series);
|
||||
}
|
||||
}
|
||||
|
||||
array get_latest(mapping database)
|
||||
{
|
||||
array latest = ({});
|
||||
foreach(database; string name; mapping series)
|
||||
{
|
||||
latest += ({ series->episodes[0] });
|
||||
}
|
||||
return latest;
|
||||
}
|
||||
|
||||
int(0..1) compare_date(array a, array b)
|
||||
{
|
||||
if (!arrayp(a) && !arrayp(b)) return false;
|
||||
if (!arrayp(a) || !sizeof(a)) return arrayp(b) && sizeof(b);
|
||||
if (!arrayp(b) || !sizeof(b)) return arrayp(a) && sizeof(a);
|
||||
if (a[0] == b[0]) return compare_date(a[1..], b[1..]);
|
||||
return a[0] < b[0];
|
||||
}
|
||||
|
||||
int(0..1) compare_by_date(mapping a, mapping b)
|
||||
{
|
||||
return compare_date(reverse(a->date), reverse(b->date));
|
||||
}
|
||||
|
||||
void watch_list(mapping database)
|
||||
{
|
||||
map(Array.sort_array(get_latest(database), compare_by_date),
|
||||
print_episode);
|
||||
}
|
||||
|
||||
string prompt_read(string prompt)
|
||||
{
|
||||
write("%s: ", prompt);
|
||||
return Stdio.stdin.gets();
|
||||
}
|
||||
|
||||
array parse_date(string date)
|
||||
{
|
||||
return (array(int))(date/".");
|
||||
}
|
||||
|
||||
mapping prompt_for_episode()
|
||||
{
|
||||
return make_episode(prompt_read("Series"),
|
||||
prompt_read("Title"),
|
||||
prompt_read("Episode"),
|
||||
parse_date(prompt_read("Date watched")));
|
||||
}
|
||||
|
||||
// pike offers encode_value() and decode_value() as standard ways
|
||||
// to save and read data, but that is not a human readable format.
|
||||
// therefore we are instead printing the structure as debug-output
|
||||
// which is a readable form as long as it only contains integers,
|
||||
// strings, mappings, arrays and multisets this format can be read by pike.
|
||||
// to read it we are creating a class that contains the data as a value,
|
||||
// which is then compiled and instantiated to allow us to pull the data out.
|
||||
void save_db(string filename, mapping database)
|
||||
{
|
||||
Stdio.write_file(filename, sprintf("%O", database));
|
||||
}
|
||||
|
||||
void watch_save()
|
||||
{
|
||||
save_db("pwatch", db);
|
||||
}
|
||||
|
||||
mapping load_db(string filename)
|
||||
{
|
||||
if (file_stat(filename))
|
||||
return compile_string("mixed data = " +
|
||||
Stdio.read_file(filename) + ";")()->data;
|
||||
else return ([]);
|
||||
}
|
||||
|
||||
mapping get_series(string name, mapping database)
|
||||
{
|
||||
return database[name];
|
||||
}
|
||||
|
||||
array get_episode_list(string series, mapping database)
|
||||
{
|
||||
return database[series]->episodes;
|
||||
}
|
||||
|
||||
void watch_new_series(string name, string status, mapping database)
|
||||
{
|
||||
database[name] = (["series":name, "status":status, "episodes":({}) ]);
|
||||
}
|
||||
|
||||
mapping get_or_add_series(string name, mapping database)
|
||||
{
|
||||
if (!database[name])
|
||||
{
|
||||
string answer = prompt_read("Add new series? [y/n]: ");
|
||||
if (answer == "y")
|
||||
watch_new_series(name, "active", database);
|
||||
}
|
||||
return database[name];
|
||||
}
|
||||
|
||||
void watch_add(mapping database)
|
||||
{
|
||||
mapping episode = prompt_for_episode();
|
||||
string series_name = episode->series;
|
||||
mapping series = get_or_add_series(series_name, database);
|
||||
if (!series)
|
||||
watch_add(database);
|
||||
else
|
||||
series->episodes = Array.unshift(series->episodes, episode);
|
||||
}
|
||||
|
||||
void watch_load()
|
||||
{
|
||||
db = load_db("pwatch");
|
||||
}
|
||||
|
||||
int main(int argc, array argv)
|
||||
{
|
||||
watch_load();
|
||||
if (argc>1 && argv[1] == "add")
|
||||
{
|
||||
watch_add(db);
|
||||
watch_save();
|
||||
}
|
||||
else
|
||||
watch_list(db);
|
||||
}
|
||||
81
Task/Simple-database/PowerShell/simple-database-1.psh
Normal file
81
Task/Simple-database/PowerShell/simple-database-1.psh
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
function db
|
||||
{
|
||||
[CmdletBinding(DefaultParameterSetName="None")]
|
||||
[OutputType([PSCustomObject])]
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$false,
|
||||
Position=0,
|
||||
ParameterSetName="Add a new entry")]
|
||||
[string]
|
||||
$Path = ".\SimpleDatabase.csv",
|
||||
|
||||
[Parameter(Mandatory=$true,
|
||||
ParameterSetName="Add a new entry")]
|
||||
[string]
|
||||
$Name,
|
||||
|
||||
[Parameter(Mandatory=$true,
|
||||
ParameterSetName="Add a new entry")]
|
||||
[string]
|
||||
$Category,
|
||||
|
||||
[Parameter(Mandatory=$true,
|
||||
ParameterSetName="Add a new entry")]
|
||||
[datetime]
|
||||
$Birthday,
|
||||
|
||||
[Parameter(ParameterSetName="Print the latest entry")]
|
||||
[switch]
|
||||
$Latest,
|
||||
|
||||
[Parameter(ParameterSetName="Print the latest entry for each category")]
|
||||
[switch]
|
||||
$LatestByCategory,
|
||||
|
||||
[Parameter(ParameterSetName="Print all entries sorted by a date")]
|
||||
[switch]
|
||||
$SortedByDate
|
||||
)
|
||||
|
||||
if (-not (Test-Path -Path $Path))
|
||||
{
|
||||
'"Name","Category","Birthday"' | Out-File -FilePath $Path
|
||||
}
|
||||
|
||||
$db = Import-Csv -Path $Path | Foreach-Object {
|
||||
$_.Birthday = $_.Birthday -as [datetime]
|
||||
$_
|
||||
}
|
||||
|
||||
switch ($PSCmdlet.ParameterSetName)
|
||||
{
|
||||
"Add a new entry"
|
||||
{
|
||||
[PSCustomObject]@{Name=$Name; Category=$Category; Birthday=$Birthday} | Export-Csv -Path $Path -Append
|
||||
}
|
||||
"Print the latest entry"
|
||||
{
|
||||
$db[-1]
|
||||
}
|
||||
"Print the latest entry for each category"
|
||||
{
|
||||
($db | Group-Object -Property Category).Name | ForEach-Object {($db | Where-Object -Property Category -Contains $_)[-1]}
|
||||
}
|
||||
"Print all entries sorted by a date"
|
||||
{
|
||||
$db | Sort-Object -Property Birthday
|
||||
}
|
||||
Default
|
||||
{
|
||||
$db
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db -Name Bev -Category friend -Birthday 3/3/1983
|
||||
db -Name Bob -Category family -Birthday 7/19/1987
|
||||
db -Name Gill -Category friend -Birthday 12/9/1986
|
||||
db -Name Gail -Category family -Birthday 2/11/1986
|
||||
db -Name Vince -Category family -Birthday 3/10/1960
|
||||
db -Name Wayne -Category coworker -Birthday 5/29/1962
|
||||
1
Task/Simple-database/PowerShell/simple-database-2.psh
Normal file
1
Task/Simple-database/PowerShell/simple-database-2.psh
Normal file
|
|
@ -0,0 +1 @@
|
|||
db
|
||||
1
Task/Simple-database/PowerShell/simple-database-3.psh
Normal file
1
Task/Simple-database/PowerShell/simple-database-3.psh
Normal file
|
|
@ -0,0 +1 @@
|
|||
db -Latest
|
||||
1
Task/Simple-database/PowerShell/simple-database-4.psh
Normal file
1
Task/Simple-database/PowerShell/simple-database-4.psh
Normal file
|
|
@ -0,0 +1 @@
|
|||
db -LatestByCategory
|
||||
1
Task/Simple-database/PowerShell/simple-database-5.psh
Normal file
1
Task/Simple-database/PowerShell/simple-database-5.psh
Normal file
|
|
@ -0,0 +1 @@
|
|||
db -SortedByDate
|
||||
108
Task/Simple-database/Python/simple-database.py
Normal file
108
Task/Simple-database/Python/simple-database.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
'''\
|
||||
Simple database for: http://rosettacode.org/wiki/Simple_database
|
||||
|
||||
'''
|
||||
|
||||
import argparse
|
||||
from argparse import Namespace
|
||||
import datetime
|
||||
import shlex
|
||||
|
||||
|
||||
def parse_args():
|
||||
'Set up, parse, and return arguments'
|
||||
|
||||
parser = argparse.ArgumentParser(epilog=globals()['__doc__'])
|
||||
|
||||
parser.add_argument('command', choices='add pl plc pa'.split(),
|
||||
help='''\
|
||||
add: Add a new entry
|
||||
pl: Print the latest entry
|
||||
plc: Print the latest entry for each category/tag
|
||||
pa: Print all entries sorted by a date''')
|
||||
parser.add_argument('-d', '--description',
|
||||
help='A description of the item. (e.g., title, name)')
|
||||
parser.add_argument('-t', '--tag',
|
||||
help=('''A category or tag (genre, topic, relationship '''
|
||||
'''such as “friend” or “family”)'''))
|
||||
parser.add_argument('-f', '--field', nargs=2, action='append',
|
||||
help='Other optional fields with value (can be repeated)')
|
||||
|
||||
return parser
|
||||
|
||||
def do_add(args, dbname):
|
||||
'Add a new entry'
|
||||
if args.description is None:
|
||||
args.description = ''
|
||||
if args.tag is None:
|
||||
args.tag = ''
|
||||
del args.command
|
||||
print('Writing record to %s' % dbname)
|
||||
with open(dbname, 'a') as db:
|
||||
db.write('%r\n' % args)
|
||||
|
||||
def do_pl(args, dbname):
|
||||
'Print the latest entry'
|
||||
print('Getting last record from %s' % dbname)
|
||||
with open(dbname, 'r') as db:
|
||||
for line in db: pass
|
||||
record = eval(line)
|
||||
del record._date
|
||||
print(str(record))
|
||||
|
||||
def do_plc(args, dbname):
|
||||
'Print the latest entry for each category/tag'
|
||||
print('Getting latest record for each tag from %s' % dbname)
|
||||
with open(dbname, 'r') as db:
|
||||
records = [eval(line) for line in db]
|
||||
tags = set(record.tag for record in records)
|
||||
records.reverse()
|
||||
for record in records:
|
||||
if record.tag in tags:
|
||||
del record._date
|
||||
print(str(record))
|
||||
tags.discard(record.tag)
|
||||
if not tags: break
|
||||
|
||||
def do_pa(args, dbname):
|
||||
'Print all entries sorted by a date'
|
||||
print('Getting all records by date from %s' % dbname)
|
||||
with open(dbname, 'r') as db:
|
||||
records = [eval(line) for line in db]
|
||||
for record in records:
|
||||
del record._date
|
||||
print(str(record))
|
||||
|
||||
def test():
|
||||
import time
|
||||
parser = parse_args()
|
||||
for cmdline in [
|
||||
"""-d Book -f title 'Windy places' -f type hardback --tag DISCOUNT add""",
|
||||
"""-d Book -f title 'RC spammers' -f type paperback -t DISCOUNT add""",
|
||||
"""-d Book -f title 'Splat it' -f type hardback -f special 'first edition' -t PREMIUM add""",
|
||||
"""pl""",
|
||||
"""plc""",
|
||||
]:
|
||||
args = parser.parse_args(shlex.split(cmdline))
|
||||
now = datetime.datetime.utcnow()
|
||||
args._date = now.isoformat()
|
||||
do_command[args.command](args, dbname)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
|
||||
do_command = dict(add=do_add, pl=do_pl, plc=do_plc, pa=do_pa)
|
||||
dbname = '_simple_db_db.py'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if 0:
|
||||
test()
|
||||
else:
|
||||
parser = parse_args()
|
||||
args = parser.parse_args()
|
||||
now = datetime.datetime.utcnow()
|
||||
args._date = now.isoformat()
|
||||
do_command[args.command](args, dbname)
|
||||
15
Task/Simple-database/REBOL/simple-database.rebol
Normal file
15
Task/Simple-database/REBOL/simple-database.rebol
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
rebol [author: "Nick Antonaccio"]
|
||||
write/append %rdb "" db: load %rdb
|
||||
switch system/options/args/1 [
|
||||
"new" [write/append %rdb rejoin [now " " mold/only next system/options/args newline]]
|
||||
"latest" [print copy/part tail sort/skip db 4 -4]
|
||||
"latestcat" [
|
||||
foreach cat unique extract at db 3 4 [
|
||||
t: copy []
|
||||
foreach [a b c d] db [if c = cat [append t reduce [a b c d]]]
|
||||
print copy/part tail sort/skip t 4 -4
|
||||
]
|
||||
]
|
||||
"sort" [probe sort/skip db 4]
|
||||
]
|
||||
halt
|
||||
77
Task/Simple-database/REXX/simple-database.rexx
Normal file
77
Task/Simple-database/REXX/simple-database.rexx
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* REXX ---------------------------------------------------------------
|
||||
* 05.10.2014
|
||||
*--------------------------------------------------------------------*/
|
||||
x05='05'x
|
||||
mydb='sidb.txt'
|
||||
Say 'Enter your commands, ?, or end'
|
||||
Do Forever
|
||||
Parse Pull l
|
||||
Parse Var l command text
|
||||
Select
|
||||
When command='?' Then
|
||||
Call help
|
||||
When command='add' Then Do
|
||||
Parse Var text item ',' category ',' date
|
||||
If date='' Then
|
||||
date=date('S') /*yyyymmdd*/
|
||||
Say 'adding item' item'/'category 'dated' date
|
||||
Call lineout mydb,date item x05 category
|
||||
End
|
||||
When command='latest' Then Do
|
||||
Call lineout mydb
|
||||
Parse Var text category
|
||||
hidt='00000000'
|
||||
ol=''
|
||||
Do While lines(mydb)>0
|
||||
l=linein(mydb)
|
||||
Parse Var l dt a (x05) b
|
||||
If category=''|,
|
||||
category='-' & b='' |,
|
||||
b=category Then Do
|
||||
If dt>>hidt Then Do
|
||||
ol=l
|
||||
hidt=dt
|
||||
End
|
||||
End
|
||||
End
|
||||
If ol>'' Then
|
||||
Call o ol
|
||||
Else
|
||||
Say 'no matching item found'
|
||||
End
|
||||
When command='all' Then Do
|
||||
Call lineout mydb
|
||||
Parse Var text category
|
||||
Do While lines(mydb)>0
|
||||
l=linein(mydb)
|
||||
Parse Var l a (x05) b
|
||||
If category=''|,
|
||||
category='-' & b=''|,
|
||||
b=category Then
|
||||
Call o l
|
||||
End
|
||||
End
|
||||
When command='end' Then
|
||||
Leave
|
||||
Otherwise Do
|
||||
Say 'invalid command ('command')'
|
||||
Call help
|
||||
End
|
||||
End
|
||||
End
|
||||
Say 'Bye'
|
||||
Exit
|
||||
|
||||
o: Parse Value arg(1) With dt text
|
||||
Say left(dt,8) text
|
||||
Return
|
||||
|
||||
help:
|
||||
Say 'add item[,[category][,date]] to add an item'
|
||||
Say 'latest category to list the latest item of a category'
|
||||
Say 'latest to list the latest item'
|
||||
Say 'all category to list all items of a category'
|
||||
Say 'all to list all items'
|
||||
Say 'end to end this program'
|
||||
Say 'Use category - to list items without category'
|
||||
Return
|
||||
26
Task/Simple-database/Racket/simple-database.rkt
Normal file
26
Task/Simple-database/Racket/simple-database.rkt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env racket
|
||||
#lang racket
|
||||
|
||||
(define (*write file data) ; write data in human readable format (sexpr/line)
|
||||
(with-output-to-file file #:exists 'replace
|
||||
(lambda () (for ([x data]) (printf "~s\n" x)))))
|
||||
(define *read file->list) ; read our "human readable format"
|
||||
|
||||
(command-line
|
||||
#:once-any
|
||||
[("-a") file title category date "Add an entry"
|
||||
(*write file `(,@(*read file) (,title ,category ,date)))]
|
||||
[("-d") file title "Delete an entry (all matching)"
|
||||
(*write file (filter-not (lambda (x) (equal? (car x) title)) (*read file)))]
|
||||
[("-p") file mode "Print entries, mode = latest, latest/cat, all, by-date"
|
||||
(define data (*read file))
|
||||
(define (show item)
|
||||
(match item [(list title cat date) (printf "[~a] ~a; ~a\n" cat title date)]))
|
||||
(case (string->symbol mode)
|
||||
[(all) (for-each show data)]
|
||||
[(by-date) (for-each show (sort data string<? #:key cadr))]
|
||||
[(latest) (show (last data))]
|
||||
[(latest/cat)
|
||||
(define (last/cat c) (for/last ([x data] #:when (equal? c (cadr x))) x))
|
||||
(for-each (compose1 show last/cat) (remove-duplicates (map cadr data)))]
|
||||
[else (error 'sdb "bad printout mode")])])
|
||||
104
Task/Simple-database/Raku/simple-database-1.raku
Normal file
104
Task/Simple-database/Raku/simple-database-1.raku
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env raku
|
||||
use JSON::Fast ;
|
||||
sub MAIN( :$server='0.0.0.0', :$port=3333, :$dbfile='db' ) {
|
||||
my %db;
|
||||
my %index;
|
||||
my $dbdata = slurp "$dbfile.json" ;
|
||||
my $indexdata = slurp "{$dbfile}_index.json" ;
|
||||
%db = from-json($dbdata) if $dbdata ;
|
||||
%index = from-json($indexdata) if $indexdata ;
|
||||
react {
|
||||
whenever IO::Socket::Async.listen( $server , $port ) -> $conn {
|
||||
whenever $conn.Supply.lines -> $line {
|
||||
my %response = 'status' => '' ;
|
||||
my $msg = from-json $line ;
|
||||
say $msg.perl ;
|
||||
given $msg<function> {
|
||||
when 'set' {
|
||||
%db{ $msg<topic> } = $msg<message> ;
|
||||
%response<status> = 'ok' ;
|
||||
%index<last_> = $msg<topic> ;
|
||||
for %index<keys_>.keys -> $key {
|
||||
if $msg<message>{$key} {
|
||||
%index<lastkey_>{ $key }{ $msg<message>{$key} } = $msg<topic> ;
|
||||
%index<idx_>{ $key }{ $msg<message>{$key} }{ $msg<topic> } = 1 ;
|
||||
}
|
||||
}
|
||||
spurt "$dbfile.json", to-json(%db);
|
||||
spurt "{$dbfile}_index.json", to-json(%index);
|
||||
}
|
||||
when 'get' {
|
||||
%response<topic> = $msg<topic> ;
|
||||
%response<message> = %db{ $msg<topic> } ;
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
when 'dump' {
|
||||
%response{'data'} = %db ;
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
when 'dumpindex' {
|
||||
%response{'data'} = %index ;
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
when 'delete' {
|
||||
%db{ $msg<topic> }:delete;
|
||||
%response<status> = 'ok' ;
|
||||
spurt "$dbfile.json", to-json(%db);
|
||||
reindex();
|
||||
}
|
||||
when 'addindex' {
|
||||
%response<status> = 'ok' ;
|
||||
%index<keys_>{ $msg<key>} =1 ;
|
||||
reindex();
|
||||
}
|
||||
when 'reportlast' {
|
||||
%response{'data'} = %db{%index<last_>} ;
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
when 'reportlastindex' {
|
||||
%response<key> = $msg<key> ;
|
||||
for %index<lastkey_>{$msg<key>}.keys -> $value {
|
||||
#%response{'data'}.push: %db{ %index<lastkey_>{ $msg<key> }{ $value } } ;
|
||||
%response{'data'}{$value} = %db{ %index<lastkey_>{ $msg<key> }{ $value } } ;
|
||||
}
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
when 'reportindex' {
|
||||
%response<status> = 'ok' ;
|
||||
for %index<idx_>{$msg<key>}.keys.sort -> $value {
|
||||
for %index<idx_>{ $msg<key> }{ $value }.keys.sort -> $topic {
|
||||
%response<data>.push: %db{ $topic } ;
|
||||
#%response<data>{$value} = %db{ $topic } ;
|
||||
}
|
||||
}
|
||||
}
|
||||
when 'commit' {
|
||||
spurt "$dbfile.json", to-json(%db);
|
||||
spurt "{$dbfile}_index.json", to-json(%index);
|
||||
%response<status> = 'ok' ;
|
||||
}
|
||||
default {
|
||||
%response<status> = 'error';
|
||||
%response<error> = 'no function or not supported';
|
||||
}
|
||||
}
|
||||
$conn.print( to-json(%response, :!pretty) ~ "\n" ) ;
|
||||
LAST { $conn.close ; }
|
||||
QUIT { default { $conn.close ; say "oh no, $_";}}
|
||||
CATCH { default { say .^name, ': ', .Str , " handled in $?LINE";}}
|
||||
}
|
||||
}
|
||||
}
|
||||
sub reindex {
|
||||
%index<idx_>:delete;
|
||||
for %db.keys -> $topic {
|
||||
my $msg = %db{$topic} ;
|
||||
for %index<keys_>.keys -> $key {
|
||||
if $msg{$key} {
|
||||
%index<idx_>{ $key }{ $msg{$key} }{ $topic } = 1 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
spurt "{$dbfile}_index.json", to-json(%index) ;
|
||||
}
|
||||
}
|
||||
50
Task/Simple-database/Raku/simple-database-2.raku
Normal file
50
Task/Simple-database/Raku/simple-database-2.raku
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env raku
|
||||
use JSON::Fast ;
|
||||
multi MAIN('set', $topic, $message='', :$server='localhost', :$port='3333', :$json='') {
|
||||
my %msg = function => 'set' , topic=> $topic , message=> $message ;
|
||||
%msg{"message"} = from-json( $json ) if $json ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('add', $topic, $json, :$server='localhost', :$port='3333' ) {
|
||||
my %msg = function => 'set' , topic=> $topic;
|
||||
%msg{"message"} = from-json( $json ) if $json ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('get', $topic, :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'get' , topic=> $topic ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('delete', $topic, :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'delete' , topic=> $topic ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('dump', :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'dump' ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('addindex', $key, :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'addindex', key => $key ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('reportindex', $key, :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'reportindex', key => $key ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('reportlastindex', $key, :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'reportlastindex', key => $key ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
multi MAIN('reportlast', :$server='localhost', :$port='3333') {
|
||||
my %msg = function => 'reportlast' ;
|
||||
sendmsg( %msg , $server, $port) ;
|
||||
}
|
||||
sub sendmsg( %msg , $server, $port){
|
||||
my $conn = await IO::Socket::Async.connect( $server , $port );
|
||||
$conn.print: to-json( %msg,:!pretty)~"\n";
|
||||
react {
|
||||
whenever $conn.Supply -> $data {
|
||||
print $data;
|
||||
$conn.close;
|
||||
}
|
||||
}
|
||||
}
|
||||
187
Task/Simple-database/Ruby/simple-database.rb
Normal file
187
Task/Simple-database/Ruby/simple-database.rb
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
require 'date'
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
|
||||
class SimpleDatabase
|
||||
def initialize(dbname, *fields)
|
||||
@dbname = dbname
|
||||
@filename = @dbname + ".dat"
|
||||
@fields = fields
|
||||
@maxl = @fields.collect {|f| f.length}.max
|
||||
@data = {
|
||||
'fields' => fields,
|
||||
'items' => {},
|
||||
'history' => [],
|
||||
'tags' => {},
|
||||
}
|
||||
end
|
||||
attr_reader :dbname, :fields
|
||||
|
||||
def self.open(dbname)
|
||||
db = new(dbname)
|
||||
db.read
|
||||
db
|
||||
end
|
||||
|
||||
def read()
|
||||
if not File.exists?(@filename)
|
||||
raise ArgumentError, "Database #@dbname has not been created"
|
||||
end
|
||||
@data = JSON.parse(File.read(@filename))
|
||||
@fields = @data['fields']
|
||||
@maxl = @fields.collect {|f| f.length}.max
|
||||
end
|
||||
|
||||
def write()
|
||||
File.open(@filename, 'w') {|f| f.write(JSON.generate(@data))}
|
||||
end
|
||||
|
||||
def add(*values)
|
||||
id = SecureRandom.uuid
|
||||
@data['items'][id] = Hash[ @fields.zip(values) ]
|
||||
@data['history'] << [Time.now.to_f, id]
|
||||
id
|
||||
end
|
||||
|
||||
def tag(id, *tags)
|
||||
tags.each do |tag|
|
||||
if @data['tags'][tag].nil?
|
||||
@data['tags'][tag] = [id]
|
||||
else
|
||||
@data['tags'][tag] << id
|
||||
end
|
||||
end
|
||||
id
|
||||
end
|
||||
|
||||
def latest
|
||||
@data['history'].sort_by {|val| val[0]}.last.last
|
||||
end
|
||||
|
||||
def get_item(id)
|
||||
@data['items'][id]
|
||||
end
|
||||
|
||||
def tags()
|
||||
@data['tags'].keys.sort
|
||||
end
|
||||
|
||||
def ids_for_tag(tag)
|
||||
@data['tags'][tag]
|
||||
end
|
||||
|
||||
def tags_for_id(id)
|
||||
@data['tags'].keys.inject([]) do |tags, tag|
|
||||
tags << tag if @data['tags'][tag].include?(id)
|
||||
tags
|
||||
end
|
||||
end
|
||||
|
||||
def display(id)
|
||||
item = get_item(id)
|
||||
fmt = "%#{@maxl}s - %s\n"
|
||||
puts fmt % ['id', id]
|
||||
@fields.each {|f| print fmt % [f, item[f]]}
|
||||
puts fmt % ['tags', tags_for_id(id).join(',')]
|
||||
added = @data['history'].find {|x| x[1] == id}.first
|
||||
puts fmt % ['date added', Time.at(added).ctime]
|
||||
puts ""
|
||||
end
|
||||
|
||||
def each()
|
||||
@data['history'].each {|time, id| yield id}
|
||||
end
|
||||
|
||||
def each_item_with_tag(tag)
|
||||
@data['tags'][tag].each {|id| yield id}
|
||||
end
|
||||
end
|
||||
def usage()
|
||||
puts <<END
|
||||
usage: #{$0} command args ...
|
||||
|
||||
commands:
|
||||
help
|
||||
create dbname field ...
|
||||
fields dbname
|
||||
add dbname value ...
|
||||
tag dbname id tag ...
|
||||
tags dbname
|
||||
list dbname [tag ...]
|
||||
latest dbname
|
||||
latest_by_tag dbname
|
||||
END
|
||||
end
|
||||
|
||||
def open_database(args)
|
||||
dbname = args.shift
|
||||
begin
|
||||
SimpleDatabase.open(dbname)
|
||||
rescue ArgumentError => e
|
||||
STDERR.puts e.message
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
def process_command_line(command, *args)
|
||||
case command
|
||||
when 'help'
|
||||
usage
|
||||
|
||||
when 'create'
|
||||
db = SimpleDatabase.new(*args)
|
||||
db.write
|
||||
puts "Database #{args[0]} created"
|
||||
|
||||
when 'fields'
|
||||
db = open_database(args)
|
||||
puts "Database #{db.dbname} fields:"
|
||||
puts db.fields.join(',')
|
||||
|
||||
when 'add'
|
||||
db = open_database(args)
|
||||
id = db.add(*args)
|
||||
db.write
|
||||
puts "Database #{db.dbname} added id #{id}"
|
||||
|
||||
when 'tag'
|
||||
db = open_database(args)
|
||||
id = args.shift
|
||||
db.tag(id, *args)
|
||||
db.write
|
||||
db.display(id)
|
||||
|
||||
when 'tags'
|
||||
db = open_database(args)
|
||||
puts "Database #{db.dbname} tags:"
|
||||
puts db.tags.join(',')
|
||||
|
||||
when 'list'
|
||||
db = open_database(args)
|
||||
if args.empty?
|
||||
db.each {|id| db.display(id)}
|
||||
else
|
||||
args.each do |tag|
|
||||
puts "Items tagged #{tag}"
|
||||
db.each_item_with_tag(tag) {|id| db.display(id)}
|
||||
end
|
||||
end
|
||||
|
||||
when 'latest'
|
||||
db = open_database(args)
|
||||
db.display(db.latest)
|
||||
|
||||
when 'latest_by_tag'
|
||||
db = open_database(args)
|
||||
db.tags.each do |tag|
|
||||
puts tag
|
||||
db.display(db.ids_for_tag(tag).last)
|
||||
end
|
||||
|
||||
else
|
||||
puts "Error: unknown command '#{command}'"
|
||||
usage
|
||||
end
|
||||
end
|
||||
|
||||
process_command_line *ARGV
|
||||
100
Task/Simple-database/Run-BASIC/simple-database.basic
Normal file
100
Task/Simple-database/Run-BASIC/simple-database.basic
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
sqliteconnect #sql, "f:\client.db" ' Connect to the DB
|
||||
|
||||
' -------------------------------
|
||||
' show user options
|
||||
' -------------------------------
|
||||
[sho]
|
||||
cls ' clear screen
|
||||
button #acd, "Add a new entry", [add]
|
||||
button #acd, "Print the latest entry", [last]
|
||||
button #acd, "Print the latest entry for each category", [lastCat]
|
||||
button #acd, "Print all entries sorted by a date", [date]
|
||||
button #ex, "Exit", [exit]
|
||||
wait
|
||||
|
||||
' ------------------------------------
|
||||
' add a new entry (user input screen)
|
||||
' ------------------------------------
|
||||
[add]
|
||||
cls ' clear the screen
|
||||
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 bgcolor=wheat>"
|
||||
html "<TR align=center BGCOLOR=tan><TD colspan=2>Client Maintenance</TD></TR><TR>"
|
||||
html "<TD bgcolor=tan align=right>Client Num</TD><TD>"
|
||||
textbox #clientNum,clientNum$,5
|
||||
|
||||
html "</TD></TR><TR><TD bgcolor=tan align=right>Name</TD><TD>"
|
||||
textbox #name,name$,30
|
||||
|
||||
html "</TD></TR><TR><TD bgcolor=tan align=right>Client Date</TD><TD>"
|
||||
textbox #clientDate,clientDate$,19
|
||||
|
||||
html "</TD></TR><TR><TD bgcolor=tan align=right>Category</TD><TD>"
|
||||
textbox #category,category$,10
|
||||
|
||||
html "</TD></TR><TR><TR bgcolor=tan><TD colspan=2 ALIGN=CENTER>"
|
||||
button #acd, "Add", [addIt]
|
||||
button #ex, "Exit", [sho]
|
||||
html "</TD></TR></TABLE>"
|
||||
wait
|
||||
|
||||
' ---------------------------------------------
|
||||
' Get data from the screen
|
||||
' ---------------------------------------------
|
||||
[addIt]
|
||||
clientNum = #clientNum contents$()
|
||||
name$ = trim$(#name contents$())
|
||||
clientDate$ = trim$(#clientDate contents$())
|
||||
category$ = trim$(#category contents$())
|
||||
dbVals$ = clientNum;",'";name$;"','";clientDate$;"','";category$;"'"
|
||||
sql$ = "INSERT into client VALUES ("; dbVals$ ; ")"
|
||||
#sql execute(sql$)
|
||||
goto [sho]
|
||||
|
||||
' ------------------------------------
|
||||
' Select last entry
|
||||
' ------------------------------------
|
||||
[last]
|
||||
sql$ = "SELECT *,client.rowid as rowid FROM client ORDER BY rowid desc LIMIT 1"
|
||||
what$ = "---- Last Entry ----"
|
||||
goto [shoQuery]
|
||||
|
||||
' ------------------------------------
|
||||
' Select by category (Last date only)
|
||||
' ------------------------------------
|
||||
[lastCat]
|
||||
sql$ = "SELECT * FROM client
|
||||
WHERE client.clientDate = (SELECT max(c.clientDate)
|
||||
FROM client as c WHERE c.category = client.category)
|
||||
ORDER BY category"
|
||||
what$ = "---- Last Category Sequence ----"
|
||||
goto [shoQuery]
|
||||
|
||||
' ------------------------------------
|
||||
' Select by date
|
||||
' ------------------------------------
|
||||
[date]
|
||||
sql$ = "SELECT * FROM client ORDER BY clientDate"
|
||||
what$ = "---- By Date ----"
|
||||
|
||||
[shoQuery]
|
||||
cls
|
||||
print what$
|
||||
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>"
|
||||
html "<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>" ' heading
|
||||
#sql execute(sql$)
|
||||
WHILE #sql hasanswer()
|
||||
#row = #sql #nextrow()
|
||||
clientNum = #row clientNum()
|
||||
name$ = #row name$()
|
||||
clientDate$ = #row clientDate$()
|
||||
category$ = #row category$()
|
||||
|
||||
html "<TR><TD align=right>";clientNum;"</TD><TD>";name$;"</TD><TD>";clientDate$;"</TD><TD>";category$;"</TD></TR>"
|
||||
WEND
|
||||
html "</TABLE>"
|
||||
button #c, "Continue", [sho]
|
||||
wait
|
||||
|
||||
' ------ the end -------
|
||||
[exit]
|
||||
end
|
||||
38
Task/Simple-database/Scala/simple-database.scala
Normal file
38
Task/Simple-database/Scala/simple-database.scala
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
object SimpleDatabase extends App {
|
||||
type Entry = Array[String]
|
||||
def asTSV(e: Entry) = e mkString "\t"
|
||||
def fromTSV(s: String) = s split "\t"
|
||||
val header = asTSV(Array("TIMESTAMP", "DESCRIPTION", "CATEGORY", "OTHER"))
|
||||
|
||||
def read(filename: String) = try {
|
||||
scala.io.Source.fromFile(filename).getLines.drop(1).map(fromTSV)
|
||||
} catch {
|
||||
case e: java.io.FileNotFoundException => Nil
|
||||
}
|
||||
|
||||
def write(filename: String, all: Seq[Entry]) = {
|
||||
import java.nio.file.{Files,Paths}
|
||||
import scala.collection.JavaConversions.asJavaIterable
|
||||
Files.write(Paths.get(filename), asJavaIterable(header +: all.map(asTSV)))
|
||||
all.size
|
||||
}
|
||||
|
||||
def add(filename: String, description: String, category: String = "none", optional: Seq[String] = Nil) {
|
||||
val format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
||||
val e = Array(format.format(new java.util.Date), description, category) ++ optional
|
||||
println(write(filename, read(filename).toBuffer :+ e) + " entries")
|
||||
}
|
||||
|
||||
def print(filename: String, filter: Seq[Entry] => TraversableOnce[Entry]) =
|
||||
filter(read(filename).toList.sortBy(_.headOption)) map(_ mkString ",") foreach println
|
||||
|
||||
args match {
|
||||
case Array(f, "latest") => print(f, _ takeRight 1)
|
||||
case Array(f, "latest", cat) => print(f, _ filter(_.lift(2) == Some(cat)) takeRight 1)
|
||||
case Array(f, "all") => print(f, _.toSeq)
|
||||
case Array(f, "all", "latest") => print(f, _ groupBy (_ lift 2 getOrElse "") map{case (_, cat) => cat.last})
|
||||
case Array(f, "add", desc) => add(f, desc, category = "")
|
||||
case Array(f, "add", desc, cat, opt @ _*) => add(f, desc, cat, opt)
|
||||
case _ => println("Usage: SimpleDatabase filename.tsv [all [latest]| latest [CATEGORY] | add [DESCRIPTION [CATEGORY [OPTIONAL]...]]]")
|
||||
}
|
||||
}
|
||||
101
Task/Simple-database/Tcl/simple-database-1.tcl
Normal file
101
Task/Simple-database/Tcl/simple-database-1.tcl
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/env tclsh8.6
|
||||
package require Tcl 8.6
|
||||
namespace eval udb {
|
||||
variable db {}
|
||||
|
||||
proc Load {filename} {
|
||||
variable db
|
||||
if {[catch {set f [open $filename]}]} {
|
||||
set db {}
|
||||
return
|
||||
}
|
||||
set db [read $f]
|
||||
close $f
|
||||
}
|
||||
proc Store {filename} {
|
||||
variable db
|
||||
if {[catch {set f [open $filename w]}]} return
|
||||
dict for {nm inf} $db {
|
||||
puts $f [list $nm $inf]
|
||||
}
|
||||
close $f
|
||||
}
|
||||
|
||||
proc add {title category {date "now"} args} {
|
||||
variable db
|
||||
if {$date eq "now"} {
|
||||
set date [clock seconds]
|
||||
} else {
|
||||
set date [clock scan $date]
|
||||
}
|
||||
dict set db $title [list $category $date $args]
|
||||
return
|
||||
}
|
||||
proc Rec {nm cat date xtra} {
|
||||
dict create description $nm category $cat date [clock format $date] \
|
||||
{*}$xtra _names [dict keys $xtra]
|
||||
}
|
||||
proc latest {{category ""}} {
|
||||
variable db
|
||||
if {$category eq ""} {
|
||||
set d [lsort -stride 2 -index {1 1} -integer -decreasing $db]
|
||||
dict for {nm inf} $d break
|
||||
return [list [Rec $nm {*}$inf]]
|
||||
}
|
||||
set latestbycat {}
|
||||
dict for {nm inf} [lsort -stride 2 -index {1 1} -integer $db] {
|
||||
dict set latestbycat [lindex $inf 0] [list $nm {*}$inf]
|
||||
}
|
||||
return [list [Rec {*}[dict get $latestbycat $category]]]
|
||||
}
|
||||
proc latestpercategory {} {
|
||||
variable db
|
||||
set latestbycat {}
|
||||
dict for {nm inf} [lsort -stride 2 -index {1 1} -integer $db] {
|
||||
dict set latestbycat [lindex $inf 0] [list $nm {*}$inf]
|
||||
}
|
||||
set result {}
|
||||
dict for {- inf} $latestbycat {
|
||||
lappend result [Rec {*}$inf]
|
||||
}
|
||||
return $result
|
||||
}
|
||||
proc bydate {} {
|
||||
variable db
|
||||
set result {}
|
||||
dict for {nm inf} [lsort -stride 2 -index {1 1} -integer $db] {
|
||||
lappend result [Rec $nm {*}$inf]
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
namespace export add latest latestpercategory bydate
|
||||
namespace ensemble create
|
||||
}
|
||||
|
||||
if {$argc < 2} {
|
||||
puts stderr "wrong # args: should be \"$argv0 dbfile subcommand ?args...?\""
|
||||
exit 1
|
||||
}
|
||||
udb::Load [lindex $argv 0]
|
||||
set separator ""
|
||||
if {[catch {udb {*}[lrange $argv 1 end]} msg]} {
|
||||
puts stderr [regsub "\"udb " $msg "\"$argv0 dbfile "]
|
||||
exit 1
|
||||
}
|
||||
foreach row $msg {
|
||||
puts -nonewline $separator
|
||||
apply {row {
|
||||
dict with row {
|
||||
puts "Title: $description"
|
||||
puts "Category: $category"
|
||||
puts "Date: $date"
|
||||
foreach v $_names {
|
||||
puts "${v}: [dict get $row $v]"
|
||||
}
|
||||
}
|
||||
}} $row
|
||||
set separator [string repeat - 70]\n
|
||||
}
|
||||
|
||||
udb::Store [lindex $argv 0]
|
||||
91
Task/Simple-database/Tcl/simple-database-2.tcl
Normal file
91
Task/Simple-database/Tcl/simple-database-2.tcl
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
bash$ udb.tcl db
|
||||
wrong # args: should be "udb.tcl dbfile subcommand ?args...?"
|
||||
bash$ udb.tcl db ?
|
||||
unknown or ambiguous subcommand "?": must be add, bydate, latest, or latestpercategory
|
||||
bash$ udb.tcl db add
|
||||
wrong # args: should be "udb.tcl dbfile add title category ?date? ?arg ...?"
|
||||
bash$ udb.tcl db add "Title 1" foo
|
||||
bash$ udb.tcl db add "Title 2" foo
|
||||
bash$ udb.tcl db add "Title 3" bar
|
||||
bash$ udb.tcl db bydate
|
||||
Title: Title 1
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:11:58 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 2
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:12:01 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
bash$ udb.tcl db latest
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
bash$ udb.tcl db latest foo
|
||||
Title: Title 2
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:12:01 GMT 2011
|
||||
bash$ udb.tcl db latest bar
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
bash$ udb.tcl db latestpercategory
|
||||
Title: Title 2
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:12:01 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
bash$ udb.tcl db add "Title 4" bar "12:00 Monday last week"
|
||||
bash$ udb.tcl db bydate
|
||||
Title: Title 4
|
||||
Category: bar
|
||||
Date: Mon Nov 14 12:00:00 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 1
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:11:58 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 2
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:12:01 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
bash$ cat db
|
||||
{Title 1} {foo 1321380718 {}}
|
||||
{Title 2} {foo 1321380721 {}}
|
||||
{Title 3} {bar 1321380727 {}}
|
||||
{Title 4} {bar 1321272000 {}}
|
||||
bash$ udb.tcl db add "Title 5" foo "12:00 Monday last week" Comment 'Wholly excellent!'
|
||||
bash$ cat db
|
||||
{Title 1} {foo 1321380718 {}}
|
||||
{Title 2} {foo 1321380721 {}}
|
||||
{Title 3} {bar 1321380727 {}}
|
||||
{Title 4} {bar 1321272000 {}}
|
||||
{Title 5} {foo 1321272000 {Comment {Wholly excellent!}}}
|
||||
bash$ udb.tcl db bydate
|
||||
Title: Title 4
|
||||
Category: bar
|
||||
Date: Mon Nov 14 12:00:00 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 5
|
||||
Category: foo
|
||||
Date: Mon Nov 14 12:00:00 GMT 2011
|
||||
Comment: Wholly excellent!
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 1
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:11:58 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 2
|
||||
Category: foo
|
||||
Date: Tue Nov 15 18:12:01 GMT 2011
|
||||
----------------------------------------------------------------------
|
||||
Title: Title 3
|
||||
Category: bar
|
||||
Date: Tue Nov 15 18:12:07 GMT 2011
|
||||
85
Task/Simple-database/ToffeeScript/simple-database.toffee
Normal file
85
Task/Simple-database/ToffeeScript/simple-database.toffee
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/local/bin/toffee
|
||||
|
||||
prog = require 'commander'
|
||||
fs = require 'fs-extra'
|
||||
|
||||
if not fs.exists! 'data.json'
|
||||
fs.outputJson! 'data.json', {}
|
||||
|
||||
prog
|
||||
.command('add <name> <category> [date]')
|
||||
.description('Add a new entry')
|
||||
.option('-n <text>', 'notes')
|
||||
.option('-t <tags>', 'tags')
|
||||
.action addentry
|
||||
|
||||
prog
|
||||
.command('latest')
|
||||
.description('Print the latest entry')
|
||||
.action latest
|
||||
|
||||
prog
|
||||
.command('catlatest')
|
||||
.description('Print the latest entry for each category')
|
||||
.action catlatestout
|
||||
|
||||
prog
|
||||
.command('list')
|
||||
.description('Print all entries sorted by date')
|
||||
.action bydate
|
||||
|
||||
|
||||
addentry = (name, category, dt, options) ->
|
||||
if dt? then dat = new Date(dt) else dat = new Date()
|
||||
update =
|
||||
name: name
|
||||
category: category
|
||||
tags: options?.T
|
||||
notes: options?.N
|
||||
date: dat.getTime()
|
||||
e, data = fs.readJson! 'data.json'
|
||||
if not data[category]?
|
||||
data[category] = []
|
||||
data[category].push update
|
||||
fs.outputJson 'data.json', data
|
||||
|
||||
byDateNew = (a, b) ->
|
||||
if a.date<b.date then return 1
|
||||
if b.date>a.date then return -1
|
||||
return 0
|
||||
|
||||
catlatest = (cb) ->
|
||||
e, data = fs.readJson! 'data.json'
|
||||
ret = []
|
||||
for cat, list of data
|
||||
list.sort byDateNew
|
||||
ret.push list[0]
|
||||
cb ret
|
||||
|
||||
printFormatted = (entry) ->
|
||||
tmp = entry.date
|
||||
entry.date = new Date(entry.date).toDateString()
|
||||
console.log entry
|
||||
entry.date = tmp
|
||||
|
||||
latest = ->
|
||||
newpercat = catlatest!
|
||||
newpercat.sort byDateNew
|
||||
printFormatted newpercat[0]
|
||||
|
||||
catlatestout = ->
|
||||
items = catlatest!
|
||||
for item in items
|
||||
printFormatted item
|
||||
|
||||
bydate = ->
|
||||
e, data = fs.readJson! 'data.json'
|
||||
entries = []
|
||||
for cat, list of data
|
||||
for item in list
|
||||
entries.push item
|
||||
entries.sort byDateNew
|
||||
for entry in entries
|
||||
printFormatted entry
|
||||
|
||||
prog.parse process.argv
|
||||
96
Task/Simple-database/UNIX-Shell/simple-database-1.sh
Normal file
96
Task/Simple-database/UNIX-Shell/simple-database-1.sh
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/sh
|
||||
|
||||
db_create() {
|
||||
mkdir ./"$1" && mkdir "./$1/.tag" && echo "Create DB \`$1'"
|
||||
}
|
||||
|
||||
db_delete() {
|
||||
rm -r ./"$1" && echo "Delete DB \`$1'"
|
||||
}
|
||||
|
||||
db_show() {
|
||||
if [ -z "$2" ]; then show_help; fi
|
||||
for x in "./$1/$2/"*; do
|
||||
echo "$x:" | sed "s/.*\///"
|
||||
cat "$x" | sed "s/^/ /"
|
||||
echo
|
||||
done
|
||||
|
||||
printf "Tags: "
|
||||
ls "./$1/$2/.tag"
|
||||
}
|
||||
|
||||
db_tag() {
|
||||
local db="$1" item="$2"
|
||||
shift
|
||||
shift
|
||||
for tag in $@; do
|
||||
mkdir "./$db/.tag/$tag"
|
||||
ln -s "$PWD/$db/$item" "./$db/.tag/$tag/"
|
||||
touch "./$db/$item/.tag/$tag"
|
||||
done
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "Usage: $0 command [args]"
|
||||
echo "Commands:"
|
||||
cat $0 | grep ") ##" | grep -v grep | sed 's/) ## /:\t/'
|
||||
exit
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then show_help; fi
|
||||
|
||||
action=$1 it=database
|
||||
shift
|
||||
case $action in
|
||||
create) ## db -- create $it
|
||||
db_create "$@" ;;
|
||||
|
||||
drop) ## db -- delete $it
|
||||
db_delete "$@" ;;
|
||||
|
||||
add) ## db item -- add new item to $it
|
||||
mkdir -p "./$1/$2/.tag" && touch "./$1/$2/Description" ;;
|
||||
|
||||
rem) ## db item -- delete item from $it
|
||||
rm -r "./$1/$2"
|
||||
rm "./$1/.tag/"*"/$2"
|
||||
;;
|
||||
|
||||
show) ## db item -- show item
|
||||
db_show "$@" ;;
|
||||
|
||||
newtag) ## db new-tag-name -- create new tag name
|
||||
mkdir "./$1/.tag/$2" ;;
|
||||
|
||||
prop) ## db item property-name property-content -- add property to item
|
||||
echo "$4" > "./$1/$2/$3" ;;
|
||||
|
||||
tag) ## db item tag [more-tags...] -- mark item with tags
|
||||
db_tag "$@" ;;
|
||||
|
||||
last) ## db -- show latest item
|
||||
ls "$1" --sort=time | tail -n 1
|
||||
;;
|
||||
|
||||
list) ## db -- list all items
|
||||
ls "$1" -1 --sort=time
|
||||
;;
|
||||
|
||||
last-all) ## db -- list items in each category
|
||||
for x in "$1/.tag/"*; do
|
||||
echo "$x" | sed 's/.*\//Tag: /'
|
||||
printf " "
|
||||
ls "$x" --sort=time | tail -n 1
|
||||
echo
|
||||
done
|
||||
;;
|
||||
|
||||
help) ## this message
|
||||
show_help
|
||||
;;
|
||||
|
||||
*) echo Bad DB command: $1
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
37
Task/Simple-database/UNIX-Shell/simple-database-2.sh
Normal file
37
Task/Simple-database/UNIX-Shell/simple-database-2.sh
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
$ sdb create CDs
|
||||
Create DB `CDs'
|
||||
$ sdb add CDs Bookends
|
||||
$ sdb prop CDs Bookends artists "Simon & Garfunkel"
|
||||
$ sdb add CDs "Ode to joy"
|
||||
$ sdb prop CDs "Ode to joy" artist "Beethoven"
|
||||
$ sdb tag CDs Bookends rock folk # I'm not sure about this
|
||||
$ sdb tag CDs "Ode to joy" classical
|
||||
$ sdb show CDs Bookends
|
||||
Description:
|
||||
|
||||
artists:
|
||||
Simon & Garfunkel
|
||||
|
||||
Tags: folk rock
|
||||
$ sdb prop CDs "Ode to joy" Description "Sym. No. 9"
|
||||
$ sdb show CDs "Ode to joy"
|
||||
Description:
|
||||
Sym. No. 9
|
||||
|
||||
artist:
|
||||
Beethoven
|
||||
|
||||
Tags: classical
|
||||
$ sdb last-all CDs
|
||||
Tag: classical
|
||||
Ode to joy
|
||||
|
||||
Tag: folk
|
||||
Bookends
|
||||
|
||||
Tag: rock
|
||||
Bookends
|
||||
|
||||
$ sdb drop CDs
|
||||
Delete DB `CDs'
|
||||
$
|
||||
120
Task/Simple-database/Wren/simple-database-1.wren
Normal file
120
Task/Simple-database/Wren/simple-database-1.wren
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/* simdb.wren */
|
||||
|
||||
import "os" for Process
|
||||
import "/ioutil" for File, FileFlags, FileUtil
|
||||
import "/trait" for Comparable
|
||||
import "/iterate" for Reversed
|
||||
import "/date" for Date
|
||||
import "/sort" for Sort
|
||||
import "/str" for Str
|
||||
|
||||
var fileName = "simdb.csv"
|
||||
|
||||
Date.default = Date.isoDate
|
||||
|
||||
class Item is Comparable {
|
||||
construct new(name, date, category) {
|
||||
_name = name
|
||||
_date = date
|
||||
_category = category
|
||||
}
|
||||
|
||||
name { _name }
|
||||
date { _date }
|
||||
category { _category }
|
||||
|
||||
compare(other) { _date.compare(other.date) }
|
||||
|
||||
toString { "%(name), %(date.toString), %(category)" }
|
||||
}
|
||||
|
||||
var printUsage = Fn.new {
|
||||
System.print("""
|
||||
Usage:
|
||||
wren simdb.wren cmd [categoryName]
|
||||
add add item name and date, followed by optional category
|
||||
latest print item with latest date, followed by optional category
|
||||
all print all
|
||||
For instance: add "some item name", "some item date", "some category name"
|
||||
Dates should be in format: yyyy-mm-dd
|
||||
""")
|
||||
}
|
||||
|
||||
var load = Fn.new {
|
||||
var db = []
|
||||
var lines = FileUtil.readLines(fileName)
|
||||
for (line in lines) {
|
||||
if (line == "") break // end of file
|
||||
var item = line.split(", ")
|
||||
db.add(Item.new(item[0], Date.parse(item[1]), item[2]))
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
var store = Fn.new { |item|
|
||||
File.openWithFlags(fileName, FileFlags.writeOnly) { |f|
|
||||
f.writeBytes("%(item)\n")
|
||||
}
|
||||
}
|
||||
|
||||
var addItem = Fn.new { |input|
|
||||
if (input.count < 2) {
|
||||
printUsage.call()
|
||||
return
|
||||
}
|
||||
var date = Date.parse(input[1])
|
||||
var cat = (input.count == 3) ? input[2] : "none"
|
||||
store.call(Item.new(input[0], date, cat))
|
||||
}
|
||||
|
||||
var printLatest = Fn.new { |a|
|
||||
var db = load.call()
|
||||
if (db.isEmpty) {
|
||||
System.print("No entries in database.")
|
||||
return
|
||||
}
|
||||
Sort.quick(db) // sort by ascending date
|
||||
if (a.count == 1) {
|
||||
var found = false
|
||||
for (item in Reversed.new(db)) {
|
||||
if (item.category == a[0]) {
|
||||
System.print(item)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) System.print("There are no items for category '%(a[0])'.")
|
||||
} else System.print(db[-1])
|
||||
}
|
||||
|
||||
var printAll = Fn.new {
|
||||
var db = load.call()
|
||||
if (db.isEmpty) {
|
||||
System.print("No entries in database.")
|
||||
return
|
||||
}
|
||||
Sort.quick(db) // sort by ascending date
|
||||
for (item in db) System.print(item)
|
||||
}
|
||||
|
||||
var args = Process.arguments
|
||||
if (!(1..4).contains(args.count)) {
|
||||
printUsage.call()
|
||||
return
|
||||
}
|
||||
// create file if it doesn't already exist
|
||||
if (!File.exists(fileName)) {
|
||||
var f = File.create(fileName)
|
||||
f.close()
|
||||
}
|
||||
|
||||
var cmd = Str.lower(args[0])
|
||||
if (cmd == "add") {
|
||||
addItem.call(args[1..-1])
|
||||
} else if (cmd == "latest") {
|
||||
printLatest.call(args[1..-1])
|
||||
} else if (cmd == "all") {
|
||||
printAll.call()
|
||||
} else {
|
||||
printUsage.call()
|
||||
}
|
||||
68
Task/Simple-database/Wren/simple-database-2.wren
Normal file
68
Task/Simple-database/Wren/simple-database-2.wren
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import "os" for Process
|
||||
import "./table" for Table, FieldInfo, File
|
||||
import "./str" for Str
|
||||
|
||||
var printUsage = Fn.new {
|
||||
System.print("""
|
||||
Usage:
|
||||
wren simdb.wren cmd [categoryName]
|
||||
add add item name and date, followed by optional category
|
||||
latest print item with latest date, followed by optional category
|
||||
all print all
|
||||
For instance: add "some item name", "some item date", "some category name"
|
||||
Dates should be in format: yyyy-mm-dd
|
||||
""")
|
||||
}
|
||||
|
||||
var printLatest = Fn.new { |table, a|
|
||||
if (table.isEmpty) {
|
||||
System.print("No entries in table.")
|
||||
return
|
||||
}
|
||||
var records = table.records
|
||||
records.sort { |s, t| Str.lt(s[1], t[1]) } // sort by ascending date
|
||||
if (a.count == 1) {
|
||||
var found = false
|
||||
for (record in records[-1..0]) {
|
||||
if (record[2] == a[0]) {
|
||||
System.print(record)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) System.print("There are no records for category '%(a[0])'.")
|
||||
} else System.print(records[-1])
|
||||
}
|
||||
|
||||
var args = Process.arguments
|
||||
if (!(1..4).contains(args.count)) {
|
||||
printUsage.call()
|
||||
return
|
||||
}
|
||||
|
||||
// create a new Table object
|
||||
var tableName = "simdb"
|
||||
var table
|
||||
if (Table.fileExists(tableName)) {
|
||||
table = Table.load(tableName)
|
||||
} else {
|
||||
var fis = [
|
||||
FieldInfo.new("name", String),
|
||||
FieldInfo.new("date", String),
|
||||
FieldInfo.new("category", String)
|
||||
]
|
||||
table = Table.new(tableName, fis)
|
||||
}
|
||||
|
||||
var cmd = Str.lower(args[0])
|
||||
if (cmd == "add") {
|
||||
if (args.count < 4) args.add("none")
|
||||
table.add(args[1..-1])
|
||||
table.save()
|
||||
} else if (cmd == "latest") {
|
||||
printLatest.call(table, args[1..-1])
|
||||
} else if (cmd == "all") {
|
||||
table.list()
|
||||
} else {
|
||||
printUsage.call()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue