Change expr/stmt in examples to untyped (#6734)

This commit is contained in:
Lynn C. Rees 2017-11-15 13:58:11 -07:00 • committed by Andreas Rumpf
commit ac5dff2e04
16 changed files with 56 additions and 119 deletions

View file

@ -85,7 +85,7 @@
<int key="IBUITag">2</int> <int key="IBUITag">2</int>
<bool key="IBUIUserInteractionEnabled">NO</bool> <bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText">Nimrod Crossplatform Calculator</string> <string key="IBUIText">Nim Crossplatform Calculator</string>
<object class="NSColor" key="IBUITextColor" id="128895179"> <object class="NSColor" key="IBUITextColor" id="128895179">
<int key="NSColorSpace">1</int> <int key="NSColorSpace">1</int>
<bytes key="NSRGB">MCAwIDAAA</bytes> <bytes key="NSRGB">MCAwIDAAA</bytes>

View file

@ -42,7 +42,7 @@ function myAdd(x, y: longint): longint; cdecl; external;
procedure TForm1.FormCreate(Sender: TObject); procedure TForm1.FormCreate(Sender: TObject);
begin begin
// we initialize the Nimrod data structures here: // we initialize the Nim data structures here:
NimMain(); NimMain();
end; end;

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nim configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nim_backend" path="../nim_backend"

View file

@ -2,7 +2,7 @@ The cross platform calculator illustrates how to use Nim to create a backend
called by different native user interfaces. called by different native user interfaces.
Since the purpose of the example is to show how the cross platform code Since the purpose of the example is to show how the cross platform code
interacts with Nimrod the actual backend code is just a simple addition proc. interacts with Nim the actual backend code is just a simple addition proc.
By keeping your program logic in Nim you can easily reuse it in different By keeping your program logic in Nim you can easily reuse it in different
platforms. platforms.

View file

@ -4,9 +4,8 @@
import db_sqlite, parseutils, strutils, times import db_sqlite, parseutils, strutils, times
type type
TTodo* = object Todo* = object
## A todo object holding the information serialized to the database. ## A todo object holding the information serialized to the database.
id: int64 ## Unique identifier of the object in the id: int64 ## Unique identifier of the object in the
## database, use the getId() accessor to read it. ## database, use the getId() accessor to read it.
@ -17,7 +16,7 @@ type
## outside of this module, use the ## outside of this module, use the
## getModificationDate accessor. ## getModificationDate accessor.
TPagedParams* = object PagedParams* = object
## Contains parameters for a query, initialize default values with ## Contains parameters for a query, initialize default values with
## initDefaults(). ## initDefaults().
pageSize*: int64 ## Lines per returned query page, -1 for pageSize*: int64 ## Lines per returned query page, -1 for
@ -27,11 +26,10 @@ type
showUnchecked*: bool ## Get unchecked objects. showUnchecked*: bool ## Get unchecked objects.
showChecked*: bool ## Get checked objects. showChecked*: bool ## Get checked objects.
# - General procs # - General procs
#
proc initDefaults*(params: var TPagedParams) = proc initDefaults*(params: var PagedParams) =
## Sets sane defaults for a TPagedParams object. ## Sets sane defaults for a PagedParams object.
## ##
## Note that you should always provide a non zero pageSize, either a specific ## Note that you should always provide a non zero pageSize, either a specific
## positive value or negative for unbounded query results. ## positive value or negative for unbounded query results.
@ -41,7 +39,6 @@ proc initDefaults*(params: var TPagedParams) =
params.showUnchecked = true params.showUnchecked = true
params.showChecked = false params.showChecked = false
proc openDatabase*(path: string): DbConn = proc openDatabase*(path: string): DbConn =
## Creates or opens the sqlite3 database. ## Creates or opens the sqlite3 database.
## ##
@ -56,16 +53,14 @@ proc openDatabase*(path: string): DbConn =
desc TEXT NOT NULL, desc TEXT NOT NULL,
modification_date INTEGER NOT NULL, modification_date INTEGER NOT NULL,
CONSTRAINT Todos UNIQUE (id))""" CONSTRAINT Todos UNIQUE (id))"""
db_sqlite.exec(conn, query) db_sqlite.exec(conn, query)
result = conn result = conn
# - Procs related to Todo objects
# - Procs related to TTodo objects
#
proc initFromDB(id: int64; text: string; priority: int, isDone: bool; proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
modificationDate: Time): TTodo = modificationDate: Time): Todo =
## Returns an initialized TTodo object created from database parameters. ## Returns an initialized Todo object created from database parameters.
## ##
## The proc assumes all values are right. Note this proc is NOT exported. ## The proc assumes all values are right. Note this proc is NOT exported.
assert(id >= 0, "Identity identifiers should not be negative") assert(id >= 0, "Identity identifiers should not be negative")
@ -75,29 +70,25 @@ proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
result.isDone = isDone result.isDone = isDone
result.modificationDate = modificationDate result.modificationDate = modificationDate
proc getId*(todo: Todo): int64 =
proc getId*(todo: TTodo): int64 =
## Accessor returning the value of the private id property. ## Accessor returning the value of the private id property.
return todo.id return todo.id
proc getModificationDate*(todo: Todo): Time =
proc getModificationDate*(todo: TTodo): Time = ## Returns the last modification date of a Todo entry.
## Returns the last modification date of a TTodo entry.
return todo.modificationDate return todo.modificationDate
proc update*(todo: var Todo; conn: DbConn): bool =
proc update*(todo: var TTodo; conn: DbConn): bool =
## Checks the database for the object and refreshes its variables. ## Checks the database for the object and refreshes its variables.
## ##
## Use this method if you (or another entity) have modified the database and ## Use this method if you (or another entity) have modified the database and
## want to update the object you have with whatever the database has stored. ## want to update the object you have with whatever the database has stored.
## Returns true if the update succeeded, or false if the object was not found ## Returns true if the update succeeded, or false if the object was not found
## in the database any more, in which case you should probably get rid of the ## in the database any more, in which case you should probably get rid of the
## TTodo object. ## Todo object.
assert(todo.id >= 0, "The identifier of the todo entry can't be negative") assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
let query = sql"""SELECT desc, priority, is_done, modification_date let query = sql"""SELECT desc, priority, is_done, modification_date
FROM Todos WHERE id = ?""" FROM Todos WHERE id = ?"""
try: try:
let rows = conn.getAllRows(query, $todo.id) let rows = conn.getAllRows(query, $todo.id)
if len(rows) < 1: if len(rows) < 1:
@ -111,8 +102,7 @@ proc update*(todo: var TTodo; conn: DbConn): bool =
except: except:
echo("Something went wrong selecting for id " & $todo.id) echo("Something went wrong selecting for id " & $todo.id)
proc save*(todo: var Todo; conn: DbConn): bool =
proc save*(todo: var TTodo; conn: DbConn): bool =
## Saves the current state of text, priority and isDone to the database. ## Saves the current state of text, priority and isDone to the database.
## ##
## Returns true if the database object was updated (in which case the ## Returns true if the database object was updated (in which case the
@ -127,15 +117,13 @@ proc save*(todo: var TTodo; conn: DbConn): bool =
WHERE id = ?""" WHERE id = ?"""
rowsUpdated = conn.execAffectedRows(query, $todo.text, rowsUpdated = conn.execAffectedRows(query, $todo.text,
$todo.priority, $todo.isDone, $int(currentDate), $todo.id) $todo.priority, $todo.isDone, $int(currentDate), $todo.id)
if 1 == rowsUpdated: if 1 == rowsUpdated:
todo.modificationDate = currentDate todo.modificationDate = currentDate
result = true result = true
# - Procs dealing directly with the database # - Procs dealing directly with the database
#
proc addTodo*(conn: DbConn; priority: int; text: string): TTodo = proc addTodo*(conn: DbConn; priority: int; text: string): Todo =
## Inserts a new todo into the database. ## Inserts a new todo into the database.
## ##
## Returns the generated todo object. If there is an error EDb will be raised. ## Returns the generated todo object. If there is an error EDb will be raised.
@ -145,10 +133,8 @@ proc addTodo*(conn: DbConn; priority: int; text: string): TTodo =
(priority, is_done, desc, modification_date) (priority, is_done, desc, modification_date)
VALUES (?, 'false', ?, ?)""" VALUES (?, 'false', ?, ?)"""
todoId = conn.insertId(query, priority, text, $int(currentDate)) todoId = conn.insertId(query, priority, text, $int(currentDate))
result = initFromDB(todoId, text, priority, false, currentDate) result = initFromDB(todoId, text, priority, false, currentDate)
proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} = proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} =
## Deletes the specified todo identifier. ## Deletes the specified todo identifier.
## ##
@ -156,7 +142,6 @@ proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} =
let query = sql"""DELETE FROM Todos WHERE id = ?""" let query = sql"""DELETE FROM Todos WHERE id = ?"""
result = conn.execAffectedRows(query, $todoId) result = conn.execAffectedRows(query, $todoId)
proc getNumEntries*(conn: DbConn): int = proc getNumEntries*(conn: DbConn): int =
## Returns the number of entries in the Todos table. ## Returns the number of entries in the Todos table.
## ##
@ -170,38 +155,30 @@ proc getNumEntries*(conn: DbConn): int =
echo("Something went wrong retrieving number of Todos entries") echo("Something went wrong retrieving number of Todos entries")
result = -1 result = -1
proc getPagedTodos*(conn: DbConn; params: PagedParams; page = 0'i64): seq[Todo] =
proc getPagedTodos*(conn: DbConn; params: TPagedParams;
page = 0'i64): seq[TTodo] =
## Returns the todo entries for a specific page. ## Returns the todo entries for a specific page.
## ##
## Pages are calculated based on the params.pageSize parameter, which can be ## Pages are calculated based on the params.pageSize parameter, which can be
## set to a negative value to specify no limit at all. The query will be ## set to a negative value to specify no limit at all. The query will be
## affected by the TPagedParams, which should have sane values (call ## affected by the PagedParams, which should have sane values (call
## initDefaults). ## initDefaults).
assert(page >= 0, "You should request a page zero or bigger than zero") assert(page >= 0, "You should request a page zero or bigger than zero")
result = @[] result = @[]
# Well, if you don't want to see anything, there's no point in asking the db. # Well, if you don't want to see anything, there's no point in asking the db.
if not params.showUnchecked and not params.showChecked: return if not params.showUnchecked and not params.showChecked: return
let let
order_by = [ order_by = [
if params.priorityAscending: "ASC" else: "DESC", if params.priorityAscending: "ASC" else: "DESC",
if params.dateAscending: "ASC" else: "DESC"] if params.dateAscending: "ASC" else: "DESC"]
query = sql("""SELECT id, desc, priority, is_done, modification_date query = sql("""SELECT id, desc, priority, is_done, modification_date
FROM Todos FROM Todos
WHERE is_done = ? OR is_done = ? WHERE is_done = ? OR is_done = ?
ORDER BY priority $1, modification_date $2, id DESC ORDER BY priority $1, modification_date $2, id DESC
LIMIT ? * ?,?""" % order_by) LIMIT ? * ?,?""" % order_by)
args = @[$params.showChecked, $(not params.showUnchecked), args = @[$params.showChecked, $(not params.showUnchecked),
$params.pageSize, $page, $params.pageSize] $params.pageSize, $page, $params.pageSize]
#echo("Query " & string(query)) #echo("Query " & string(query))
#echo("args: " & args.join(", ")) #echo("args: " & args.join(", "))
var newId: BiggestInt var newId: BiggestInt
for row in conn.fastRows(query, args): for row in conn.fastRows(query, args):
let numChars = row[0].parseBiggestInt(newId) let numChars = row[0].parseBiggestInt(newId)
@ -209,10 +186,9 @@ proc getPagedTodos*(conn: DbConn; params: TPagedParams;
result.add(initFromDB(int64(newId), row[1], row[2].parseInt, result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
row[3].parseBool, Time(row[4].parseInt))) row[3].parseBool, Time(row[4].parseInt)))
proc getTodo*(conn: DbConn; todoId: int64): ref Todo =
proc getTodo*(conn: DbConn; todoId: int64): ref TTodo = ## Returns a reference to a Todo or nil if the todo could not be found.
## Returns a reference to a TTodo or nil if the todo could not be found. var tempTodo: Todo
var tempTodo: TTodo
tempTodo.id = todoId tempTodo.id = todoId
if tempTodo.update(conn): if tempTodo.update(conn):
new(result) new(result)

View file

@ -2,8 +2,7 @@
import backend, db_sqlite, strutils, times import backend, db_sqlite, strutils, times
proc showPagedResults(conn: DbConn; params: PagedParams) =
proc showPagedResults(conn: DbConn; params: TPagedParams) =
## Shows the contents of the database in pages of specified size. ## Shows the contents of the database in pages of specified size.
## ##
## Hmm... I guess this is more of a debug proc which should be moved outside, ## Hmm... I guess this is more of a debug proc which should be moved outside,
@ -11,7 +10,6 @@ proc showPagedResults(conn: DbConn; params: TPagedParams) =
var var
page = 0'i64 page = 0'i64
rows = conn.getPagedTodos(params) rows = conn.getPagedTodos(params)
while rows.len > 0: while rows.len > 0:
echo("page " & $page) echo("page " & $page)
for row in rows: for row in rows:
@ -25,7 +23,6 @@ proc showPagedResults(conn: DbConn; params: TPagedParams) =
else: else:
break break
proc dumTest() = proc dumTest() =
let conn = openDatabase("todo.sqlite3") let conn = openDatabase("todo.sqlite3")
try: try:
@ -35,10 +32,8 @@ proc dumTest() =
# Fill some dummy rows if there are not many entries yet. # Fill some dummy rows if there are not many entries yet.
discard conn.addTodo(3, "Filler1") discard conn.addTodo(3, "Filler1")
discard conn.addTodo(4, "Filler2") discard conn.addTodo(4, "Filler2")
var todo = conn.addTodo(2, "Testing") var todo = conn.addTodo(2, "Testing")
echo("New todo added with id " & $todo.getId) echo("New todo added with id " & $todo.getId)
# Try changing it and updating the database. # Try changing it and updating the database.
var clonedTodo = conn.getTodo(todo.getId)[] var clonedTodo = conn.getTodo(todo.getId)[]
assert(clonedTodo.text == todo.text, "Should be equal") assert(clonedTodo.text == todo.text, "Should be equal")
@ -49,13 +44,11 @@ proc dumTest() =
echo("Updated priority $1, done $2" % [$todo.priority, $todo.isDone]) echo("Updated priority $1, done $2" % [$todo.priority, $todo.isDone])
else: else:
assert(false, "Uh oh, I wasn't expecting that!") assert(false, "Uh oh, I wasn't expecting that!")
# Verify our cloned copy is different but can be updated. # Verify our cloned copy is different but can be updated.
assert(clonedTodo.text != todo.text, "Should be different") assert(clonedTodo.text != todo.text, "Should be different")
discard clonedTodo.update(conn) discard clonedTodo.update(conn)
assert(clonedTodo.text == todo.text, "Should be equal") assert(clonedTodo.text == todo.text, "Should be equal")
var params: PagedParams
var params: TPagedParams
params.initDefaults params.initDefaults
conn.showPagedResults(params) conn.showPagedResults(params)
conn.deleteTodo(todo.getId) conn.deleteTodo(todo.getId)
@ -66,7 +59,6 @@ proc dumTest() =
echo("Later priority $1, done $2" % [$todo.priority, $todo.isDone]) echo("Later priority $1, done $2" % [$todo.priority, $todo.isDone])
else: else:
echo("Can't update object $1 from db!" % $todo.getId) echo("Can't update object $1 from db!" % $todo.getId)
# Try to list content in a different way. # Try to list content in a different way.
params.pageSize = 5 params.pageSize = 5
params.priorityAscending = true params.priorityAscending = true
@ -77,7 +69,6 @@ proc dumTest() =
conn.close conn.close
echo("Database closed") echo("Database closed")
# Code that will be run only on the commandline. # Code that will be run only on the commandline.
when isMainModule: when isMainModule:
dumTest() dumTest()

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nim configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nim_backend" path="../nim_backend"

View file

@ -18,8 +18,8 @@ Commands:
-h, --help shows this help -h, --help shows this help
List options (optional): List options (optional):
-p=+|- Sorts list by ascending|desdencing priority. Default:desdencing. -p=+|- Sorts list by ascending|descending priority. Default:descending.
-m=+|- Sorts list by ascending|desdencing date. Default:desdencing. -m=+|- Sorts list by ascending|descending date. Default:descending.
-t Show checked entries. By default they are not shown. -t Show checked entries. By default they are not shown.
-z Hide unchecked entries. By default they are shown. -z Hide unchecked entries. By default they are shown.
@ -33,7 +33,7 @@ Examples:
""" """
type type
TCommand = enum # The possible types of commands Command = enum # The possible types of commands
cmdAdd # The user wants to add a new todo entry. cmdAdd # The user wants to add a new todo entry.
cmdCheck # User wants to check a todo entry. cmdCheck # User wants to check a todo entry.
cmdUncheck # User wants to uncheck a todo entry. cmdUncheck # User wants to uncheck a todo entry.
@ -42,30 +42,27 @@ type
cmdGenerate # Add random rows to the database, for testing. cmdGenerate # Add random rows to the database, for testing.
cmdList # User wants to list contents. cmdList # User wants to list contents.
TParamConfig = object ParamConfig = object
# Structure containing the parsed options from the commandline. # Structure containing the parsed options from the commandline.
command: TCommand # Store the type of operation command: Command # Store the type of operation
addPriority: int # Only valid with cmdAdd, stores priority. addPriority: int # Only valid with cmdAdd, stores priority.
addText: seq[string] # Only valid with cmdAdd, stores todo text. addText: seq[string] # Only valid with cmdAdd, stores todo text.
todoId: int64 # The todo id for operations like check or delete. todoId: int64 # The todo id for operations like check or delete.
listParams: TPagedParams # Uses the backend structure directly for params. listParams: PagedParams # Uses the backend structure directly for params.
proc initDefaults(params: var ParamConfig) =
proc initDefaults(params: var TParamConfig) =
## Initialises defaults value in the structure. ## Initialises defaults value in the structure.
## ##
## Most importantly we want to have an empty list for addText. ## Most importantly we want to have an empty list for addText.
params.listParams.initDefaults params.listParams.initDefaults
params.addText = @[] params.addText = @[]
proc abort(message: string, value: int) = proc abort(message: string, value: int) =
# Simple wrapper to abort also displaying the help to the user. # Simple wrapper to abort also displaying the help to the user.
stdout.write(USAGE) stdout.write(USAGE)
quit(message, value) quit(message, value)
template parseTodoIdAndSetCommand(newCommand: Command): untyped =
template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
## Helper to parse a big todo identifier into todoId and set command. ## Helper to parse a big todo identifier into todoId and set command.
try: try:
let numChars = val.parseBiggestInt(newId) let numChars = val.parseBiggestInt(newId)
@ -75,8 +72,7 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
except OverflowError: except OverflowError:
raise newException(ValueError, "Value $1 too big" % val) raise newException(ValueError, "Value $1 too big" % val)
template verifySingleCommand(actions: typed): typed =
template verifySingleCommand(actions: stmt): stmt =
## Helper to make sure only one command has been specified so far. ## Helper to make sure only one command has been specified so far.
if specifiedCommand: if specifiedCommand:
abort("Only one command can be specified at a time! (extra:$1)" % [key], 2) abort("Only one command can be specified at a time! (extra:$1)" % [key], 2)
@ -84,7 +80,6 @@ template verifySingleCommand(actions: stmt): stmt =
actions actions
specifiedCommand = true specifiedCommand = true
proc parsePlusMinus(val: string, debugText: string): bool = proc parsePlusMinus(val: string, debugText: string): bool =
## Helper to process a plus or minus character from the commandline. ## Helper to process a plus or minus character from the commandline.
## ##
@ -100,11 +95,10 @@ proc parsePlusMinus(val: string, debugText: string): bool =
else: else:
abort("$1 parameter should be + or - but was '$2'." % [debugText, val], 4) abort("$1 parameter should be + or - but was '$2'." % [debugText, val], 4)
proc parseCmdLine(): ParamConfig =
proc parseCmdLine(): TParamConfig =
## Parses the commandline. ## Parses the commandline.
## ##
## Returns a TParamConfig structure filled with the proper values or directly ## Returns a ParamConfig structure filled with the proper values or directly
## calls quit() with the appropriate error message. ## calls quit() with the appropriate error message.
var var
specifiedCommand = false specifiedCommand = false
@ -112,15 +106,12 @@ proc parseCmdLine(): TParamConfig =
p = initOptParser() p = initOptParser()
key, val: TaintedString key, val: TaintedString
newId: BiggestInt newId: BiggestInt
result.initDefaults result.initDefaults
try: try:
while true: while true:
next(p) next(p)
key = p.key key = p.key
val = p.val val = p.val
case p.kind case p.kind
of cmdArgument: of cmdArgument:
if specifiedCommand and cmdAdd == result.command: if specifiedCommand and cmdAdd == result.command:
@ -180,17 +171,13 @@ proc parseCmdLine(): TParamConfig =
break break
except ValueError: except ValueError:
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7) abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
if not specifiedCommand: if not specifiedCommand:
abort("Didn't specify any command.", 8) abort("Didn't specify any command.", 8)
if cmdAdd == result.command and result.addText.len < 1: if cmdAdd == result.command and result.addText.len < 1:
abort("Used the add command, but provided no text/description.", 9) abort("Used the add command, but provided no text/description.", 9)
if usesListParams and cmdList != result.command: if usesListParams and cmdList != result.command:
abort("Used list options, but didn't specify the list command.", 10) abort("Used list options, but didn't specify the list command.", 10)
proc generateDatabaseRows(conn: DbConn) = proc generateDatabaseRows(conn: DbConn) =
## Adds some rows to the database ignoring errors. ## Adds some rows to the database ignoring errors.
discard conn.addTodo(1, "Watch another random youtube video") discard conn.addTodo(1, "Watch another random youtube video")
@ -208,19 +195,16 @@ proc generateDatabaseRows(conn: DbConn) =
discard conn.addTodo(6, "Learn a functional programming language") discard conn.addTodo(6, "Learn a functional programming language")
echo("Generated some entries, they were added to your database.") echo("Generated some entries, they were added to your database.")
proc listDatabaseContents(conn: DbConn; listParams: PagedParams) =
proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
## Dumps the database contents formatted to the standard output. ## Dumps the database contents formatted to the standard output.
## ##
## Pass the list/filter parameters parsed from the commandline. ## Pass the list/filter parameters parsed from the commandline.
var params = listParams var params = listParams
params.pageSize = -1 params.pageSize = -1
let todos = conn.getPagedTodos(params) let todos = conn.getPagedTodos(params)
if todos.len < 1: if todos.len < 1:
echo("Database empty") echo("Database empty")
return return
echo("Todo id, is done, priority, last modification date, text:") echo("Todo id, is done, priority, last modification date, text:")
# First detect how long should be our columns for formatting. # First detect how long should be our columns for formatting.
var cols: array[0..2, int] var cols: array[0..2, int]
@ -228,7 +212,6 @@ proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
cols[0] = max(cols[0], ($todo.getId).len) cols[0] = max(cols[0], ($todo.getId).len)
cols[1] = max(cols[1], ($todo.priority).len) cols[1] = max(cols[1], ($todo.priority).len)
cols[2] = max(cols[2], ($todo.getModificationDate).len) cols[2] = max(cols[2], ($todo.getModificationDate).len)
# Now dump all the rows using the calculated alignment sizes. # Now dump all the rows using the calculated alignment sizes.
for todo in todos: for todo in todos:
echo("$1 $2 $3, $4, $5" % [ echo("$1 $2 $3, $4, $5" % [
@ -238,7 +221,6 @@ proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
($todo.getModificationDate).align(cols[2]), ($todo.getModificationDate).align(cols[2]),
todo.text]) todo.text])
proc deleteOneTodo(conn: DbConn; todoId: int64) = proc deleteOneTodo(conn: DbConn; todoId: int64) =
## Deletes a single todo entry from the database. ## Deletes a single todo entry from the database.
let numDeleted = conn.deleteTodo(todoId) let numDeleted = conn.deleteTodo(todoId)
@ -247,7 +229,6 @@ proc deleteOneTodo(conn: DbConn; todoId: int64) =
else: else:
quit("Couldn't delete todo id " & $todoId, 11) quit("Couldn't delete todo id " & $todoId, 11)
proc deleteAllTodos(conn: DbConn) = proc deleteAllTodos(conn: DbConn) =
## Deletes all the contents from the database. ## Deletes all the contents from the database.
## ##
@ -256,43 +237,35 @@ proc deleteAllTodos(conn: DbConn) =
## ourselfves to the API exported by backend. ## ourselfves to the API exported by backend.
var var
counter: int64 counter: int64
params: TPagedParams params: PagedParams
params.initDefaults params.initDefaults
params.pageSize = -1 params.pageSize = -1
params.showUnchecked = true params.showUnchecked = true
params.showChecked = true params.showChecked = true
let todos = conn.getPagedTodos(params) let todos = conn.getPagedTodos(params)
for todo in todos: for todo in todos:
if conn.deleteTodo(todo.getId) > 0: if conn.deleteTodo(todo.getId) > 0:
counter += 1 counter += 1
else: else:
quit("Couldn't delete todo id " & $todo.getId, 12) quit("Couldn't delete todo id " & $todo.getId, 12)
echo("Deleted $1 todo entries from database." % $counter) echo("Deleted $1 todo entries from database." % $counter)
proc setTodoCheck(conn: DbConn; todoId: int64; value: bool) = proc setTodoCheck(conn: DbConn; todoId: int64; value: bool) =
## Changes the check state of a todo entry to the specified value. ## Changes the check state of a todo entry to the specified value.
let let
newState = if value: "checked" else: "unchecked" newState = if value: "checked" else: "unchecked"
todo = conn.getTodo(todoId) todo = conn.getTodo(todoId)
if todo == nil: if todo == nil:
quit("Can't modify todo id $1, its not in the database." % $todoId, 13) quit("Can't modify todo id $1, its not in the database." % $todoId, 13)
if todo[].isDone == value: if todo[].isDone == value:
echo("Todo id $1 was already set to $2." % [$todoId, newState]) echo("Todo id $1 was already set to $2." % [$todoId, newState])
return return
todo[].isDone = value todo[].isDone = value
if todo[].save(conn): if todo[].save(conn):
echo("Todo id $1 set to $2." % [$todoId, newState]) echo("Todo id $1 set to $2." % [$todoId, newState])
else: else:
quit("Error updating todo id $1 to $2." % [$todoId, newState]) quit("Error updating todo id $1 to $2." % [$todoId, newState])
proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) = proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) =
## Adds to the database a todo with the specified priority. ## Adds to the database a todo with the specified priority.
## ##
@ -302,17 +275,14 @@ proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) =
echo("Created todo entry with id:$1 for priority $2 and text '$3'." % [ echo("Created todo entry with id:$1 for priority $2 and text '$3'." % [
$todo.getId, $todo.priority, todo.text]) $todo.getId, $todo.priority, todo.text])
when isMainModule: when isMainModule:
## Main entry point. ## Main entry point.
let let
opt = parseCmdLine() opt = parseCmdLine()
dbPath = getConfigDir() / "nimtodo.sqlite3" dbPath = getConfigDir() / "nimtodo.sqlite3"
if not dbPath.existsFile: if not dbPath.existsFile:
createDir(getConfigDir()) createDir(getConfigDir())
echo("No database found at $1, it will be created for you." % dbPath) echo("No database found at $1, it will be created for you." % dbPath)
let conn = openDatabase(dbPath) let conn = openDatabase(dbPath)
try: try:
case opt.command case opt.command

View file

@ -14,6 +14,6 @@ generation switch can be used to fill the database with some basic todo entries
you can play with. you can play with.
Compilation is fairly easy despite having the source split in different Compilation is fairly easy despite having the source split in different
directories. Thanks to the Nim.cfg file, which adds the ../Nim_backend directories. Thanks to the nim.cfg file, which adds the ../Nim_backend
directory as a search path, you can compile and run the example just fine from directory as a search path, you can compile and run the example just fine from
the command line with 'nim c -r nimtodo.nim'. the command line with 'nim c -r nimtodo.nim'.

View file

@ -1,4 +1,4 @@
The cross platform todo illustrates how to use Nim to create a backend This cross platform todo illustrates how to use Nim to create a backend
called by different native user interfaces. called by different native user interfaces.
This example builds on the knowledge learned from the cross_calculator example. This example builds on the knowledge learned from the cross_calculator example.

View file

@ -3,7 +3,6 @@ import re
for x in lines("myfile.txt"): for x in lines("myfile.txt"):
if x =~ re"(\w+)=(.*)": if x =~ re"(\w+)=(.*)":
echo "Key: ", matches[0], echo "Key: ", matches[0], " Value: ", matches[1]
" Value: ", matches[1]

View file

@ -1,4 +1,4 @@
In this directory you will find several examples for how to use the Nimrod In this directory you will find several examples for how to use the Nim
library. library.
Copyright (c) 2004-2012 Andreas Rumpf. Copyright (c) 2004-2012 Andreas Rumpf.

View file

@ -1,20 +1,20 @@
import strutils import strutils
template html(name: expr, matter: stmt) {.immediate.} = template html(name, matter: untyped) =
proc name(): string = proc name(): string =
result = "<html>" result = "<html>"
matter matter
result.add("</html>") result.add("</html>")
template nestedTag(tag: expr) {.immediate.} = template nestedTag(tag: untyped) =
template tag(matter: stmt) {.immediate.} = template tag(matter: typed) =
result.add("<" & astToStr(tag) & ">") result.add("<" & astToStr(tag) & ">")
matter matter
result.add("</" & astToStr(tag) & ">") result.add("</" & astToStr(tag) & ">")
template simpleTag(tag: expr) {.immediate.} = template simpleTag(tag: untyped) =
template tag(matter: expr) {.immediate.} = template tag(matter: untyped) =
result.add("<$1>$2</$1>" % [astToStr(tag), matter]) result.add("<$1>$2</$1>" % [astToStr(tag), matter])
nestedTag body nestedTag body

View file

@ -5,7 +5,7 @@ import macros
proc invalidFormatString() = proc invalidFormatString() =
echo "invalidFormatString" echo "invalidFormatString"
template formatImpl(handleChar: expr) = template formatImpl(handleChar: untyped) =
var i = 0 var i = 0
while i < f.len: while i < f.len:
if f[i] == '$': if f[i] == '$':
@ -24,11 +24,11 @@ template formatImpl(handleChar: expr) =
i += 1 i += 1
proc `%`*(f: string, a: openArray[string]): string = proc `%`*(f: string, a: openArray[string]): string =
template identity(x: expr): expr = x template identity(x: untyped): untyped = x
result = "" result = ""
formatImpl(identity) formatImpl(identity)
macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): expr = macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped =
result = newNimNode(nnkBracket) result = newNimNode(nnkBracket)
#newCall("&") #newCall("&")
let f = f.strVal let f = f.strVal

View file

@ -1,7 +1,7 @@
import macros import macros
macro check(ex: expr): stmt = macro check(ex: untyped): typed =
var info = ex.lineinfo var info = ex.lineinfo
var expString = ex.toStrLit var expString = ex.toStrLit
result = quote do: result = quote do:

View file

@ -1,8 +1,9 @@
template htmlTag(tag: expr) {.immediate.} = template htmlTag(tag: untyped) =
proc tag(): string = "<" & astToStr(tag) & ">" proc tag(): string = "<" & astToStr(tag) & ">"
htmlTag(br) htmlTag(br)
htmlTag(html) htmlTag(html)
echo br() echo br()
echo html()