Remove deprecated stuff from stdlib (#14699)

* update to the latest Jester

* remove deprecated procs from some stdlib modules

* 'criterion' is not maintained anymore and relies on obsolete stuff
This commit is contained in:
Miran 2020-06-17 15:25:02 +02:00 • committed by GitHub
commit e7f280bd26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 155 additions and 519 deletions

View file

@ -367,7 +367,7 @@ A similar thing happens with C code invoking Nim code which returns a
.. code-block:: nim .. code-block:: nim
proc gimme(): cstring {.exportc.} = proc gimme(): cstring {.exportc.} =
result = "Hey there C code! " & $random(100) result = "Hey there C code! " & $rand(100)
Since Nim's garbage collector is not aware of the C code, once the Since Nim's garbage collector is not aware of the C code, once the
``gimme`` proc has finished it can reclaim the memory of the ``cstring``. ``gimme`` proc has finished it can reclaim the memory of the ``cstring``.

View file

@ -996,12 +996,6 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr
## ##
## Also see ``dumpTree`` and ``dumpLisp``. ## Also see ``dumpTree`` and ``dumpLisp``.
macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
## Deprecated. Use `dumpTree` instead.
macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
## Deprecated. Use `dumpLisp` instead.
proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} = proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
## Create a new empty node. ## Create a new empty node.
result = newNimNode(nnkEmpty) result = newNimNode(nnkEmpty)

View file

@ -483,13 +483,6 @@ proc multiReplace*(s: string, subs: openArray[
# copy the rest: # copy the rest:
add(result, substr(s, i)) add(result, substr(s, i))
proc parallelReplace*(s: string, subs: openArray[
tuple[pattern: Regex, repl: string]]): string {.deprecated:
"Deprecated since v0.18.0: Use ``multiReplace`` instead.".} =
## Returns a modified copy of ``s`` with the substitutions in ``subs``
## applied in parallel.
result = multiReplace(s, subs)
proc transformFile*(infile, outfile: string, proc transformFile*(infile, outfile: string,
subs: openArray[tuple[pattern: Regex, repl: string]]) = subs: openArray[tuple[pattern: Regex, repl: string]]) =
## reads in the file ``infile``, performs a parallel replacement (calls ## reads in the file ``infile``, performs a parallel replacement (calls

View file

@ -223,10 +223,6 @@ proc binarySearch*[T](a: openArray[T], key: T): int =
assert binarySearch([0, 1, 4, 2, 3], 4) == 2 assert binarySearch([0, 1, 4, 2, 3], 4) == 2
binarySearch(a, key, cmp[T]) binarySearch(a, key, cmp[T])
proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated:
"Deprecated since v0.18.1; Use 'binarySearch'".} =
binarySearch(a, key, cmp[T])
const const
onlySafeCode = true onlySafeCode = true

View file

@ -285,7 +285,7 @@ when defined(windows) or defined(nimdoc):
new result new result
result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
result.handles = initHashSet[AsyncFD]() result.handles = initHashSet[AsyncFD]()
result.timers.newHeapQueue() result.timers.clear()
result.callbacks = initDeque[proc () {.closure, gcsafe.}](64) result.callbacks = initDeque[proc () {.closure, gcsafe.}](64)
var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher

View file

@ -183,14 +183,6 @@ proc `$`*[T](heap: HeapQueue[T]): string =
result.addQuoted(x) result.addQuoted(x)
result.add("]") result.add("]")
proc newHeapQueue*[T](): HeapQueue[T] {.deprecated:
"Deprecated since v0.20.0: use 'initHeapQueue' instead.".} =
initHeapQueue[T]()
proc newHeapQueue*[T](heap: var HeapQueue[T]) {.deprecated:
"Deprecated since v0.20.0: use 'clear' instead.".} =
heap.clear()
when isMainModule: when isMainModule:
proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = proc toSortedSeq[T](h: HeapQueue[T]): seq[T] =
var tmp = h var tmp = h

View file

@ -111,9 +111,7 @@ proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) =
## * `toHashSet proc <#toHashSet,openArray[A]>`_ ## * `toHashSet proc <#toHashSet,openArray[A]>`_
runnableExamples: runnableExamples:
var a: HashSet[int] var a: HashSet[int]
assert(not a.isValid)
init(a) init(a)
assert a.isValid
initImpl(s, initialSize) initImpl(s, initialSize)
@ -647,9 +645,7 @@ proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) =
## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_ ## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_
runnableExamples: runnableExamples:
var a: OrderedSet[int] var a: OrderedSet[int]
assert(not a.isValid)
init(a) init(a)
assert a.isValid
initImpl(s, initialSize) initImpl(s, initialSize)
@ -923,21 +919,6 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
proc isValid*[A](s: OrderedSet[A]): bool {.deprecated:
"Deprecated since v0.20; sets are initialized by default".} =
##
## Returns `true` if the set has been initialized (with `initHashSet proc
## <#initOrderedSet,int>`_ or `init proc <#init,OrderedSet[A],int>`_).
##
## **Examples:**
##
## .. code-block ::
## proc savePreferences(options: OrderedSet[string]) =
## assert options.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = s.data.len > 0
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -945,16 +926,8 @@ proc isValid*[A](s: OrderedSet[A]): bool {.deprecated:
when isMainModule and not defined(release): when isMainModule and not defined(release):
proc testModule() = proc testModule() =
## Internal micro test to validate docstrings and such. ## Internal micro test to validate docstrings and such.
block isValidTest: # isValid is deprecated
var options: HashSet[string]
proc savePreferences(options: HashSet[string]) =
assert options.isValid, "Pass an initialized set!"
options = initHashSet[string]()
options.savePreferences
block lenTest: block lenTest:
var values: HashSet[int] var values: HashSet[int]
assert(not values.isValid)
assert values.len == 0 assert values.len == 0
assert values.card == 0 assert values.card == 0
@ -1046,16 +1019,8 @@ when isMainModule and not defined(release):
var b = a.map(proc (x: int): string = $x) var b = a.map(proc (x: int): string = $x)
assert b == toHashSet(["1", "2", "3"]) assert b == toHashSet(["1", "2", "3"])
block isValidTest: # isValid is deprecated
var cards: OrderedSet[string]
proc saveTarotCards(cards: OrderedSet[string]) =
assert cards.isValid, "Pass an initialized set!"
cards = initOrderedSet[string]()
cards.saveTarotCards
block lenTest: block lenTest:
var values: OrderedSet[int] var values: OrderedSet[int]
assert(not values.isValid)
assert values.len == 0 assert values.len == 0
assert values.card == 0 assert values.card == 0
@ -1119,7 +1084,7 @@ when isMainModule and not defined(release):
a.init(4) a.init(4)
a.incl(2) a.incl(2)
a.init a.init
assert a.len == 0 and a.isValid assert a.len == 0
a = initOrderedSet[int](4) a = initOrderedSet[int](4)
a.incl(2) a.incl(2)
assert a.len == 1 assert a.len == 1
@ -1128,7 +1093,7 @@ when isMainModule and not defined(release):
b.init(4) b.init(4)
b.incl(2) b.incl(2)
b.init b.init
assert b.len == 0 and b.isValid assert b.len == 0
b = initHashSet[int](4) b = initHashSet[int](4)
b.incl(2) b.incl(2)
assert b.len == 1 assert b.len == 1

View file

@ -88,7 +88,7 @@ when not defined(testing) and isMainModule and not defined(nimdoc):
proc busyLoop() = proc busyLoop() =
while true: while true:
discard random(80) discard rand(80)
os.sleep(100) os.sleep(100)
spawn busyLoop() spawn busyLoop()

View file

@ -435,7 +435,7 @@ proc `[]=`*(p: MultipartData, name: string,
proc getBoundary(p: MultipartData): string = proc getBoundary(p: MultipartData): string =
if p == nil or p.content.len == 0: return if p == nil or p.content.len == 0: return
while true: while true:
result = $random(int.high) result = $rand(int.high)
for i, entry in p.content: for i, entry in p.content:
if result in entry.content: break if result in entry.content: break
elif i == p.content.high: return elif i == p.content.high: return

View file

@ -196,17 +196,6 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
result = result or (result shr 1) result = result or (result shr 1)
result += 1 + ord(x <= 0) result += 1 + ord(x <= 0)
proc countBits32*(n: int32): int {.noSideEffect, deprecated:
"Deprecated since v0.20.0; use 'bitops.countSetBits' instead".} =
runnableExamples:
doAssert countBits32(7) == 3
doAssert countBits32(8) == 1
doAssert countBits32(15) == 4
doAssert countBits32(16) == 1
doAssert countBits32(17) == 2
bitops.countSetBits(n)
proc sum*[T](x: openArray[T]): T {.noSideEffect.} = proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
## Computes the sum of the elements in ``x``. ## Computes the sum of the elements in ``x``.
## ##
@ -611,13 +600,6 @@ when not defined(js): # C
## echo gamma(4.0) # 6.0 ## echo gamma(4.0) # 6.0
## echo gamma(11.0) # 3628800.0 ## echo gamma(11.0) # 3628800.0
## echo gamma(-1.0) # nan ## echo gamma(-1.0) # nan
proc tgamma*(x: float32): float32
{.deprecated: "Deprecated since v0.19.0; use 'gamma' instead",
importc: "tgammaf", header: "<math.h>".}
proc tgamma*(x: float64): float64
{.deprecated: "Deprecated since v0.19.0; use 'gamma' instead",
importc: "tgamma", header: "<math.h>".}
## The gamma function
proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".} proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".}
proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".} proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".}
## Computes the natural log of the gamma function for ``x``. ## Computes the natural log of the gamma function for ``x``.
@ -750,12 +732,6 @@ when not defined(js): # C
## echo trunc(PI) # 3.0 ## echo trunc(PI) # 3.0
## echo trunc(-1.85) # -1.0 ## echo trunc(-1.85) # -1.0
proc fmod*(x, y: float32): float32 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead",
importc: "fmodf", header: "<math.h>".}
proc fmod*(x, y: float64): float64 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead",
importc: "fmod", header: "<math.h>".}
## Computes the remainder of ``x`` divided by ``y``.
proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".} proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".}
proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".} proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".}
## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
@ -1111,7 +1087,6 @@ when isMainModule and not defined(js) and not windowsCC89:
# check gamma function # check gamma function
assert(gamma(5.0) == 24.0) # 4! assert(gamma(5.0) == 24.0) # 4!
assert($tgamma(5.0) == $24.0) # 4!
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
assert(erf(6.0) > erf(5.0)) assert(erf(6.0) > erf(5.0))
assert(erfc(6.0) < erfc(5.0)) assert(erfc(6.0) < erfc(5.0))
@ -1133,20 +1108,6 @@ when isMainModule:
doAssert round(-54.652) ==~ -55.0 doAssert round(-54.652) ==~ -55.0
doAssert round(-54.352) ==~ -54.0 doAssert round(-54.352) ==~ -54.0
doAssert round(0.0) ==~ 0.0 doAssert round(0.0) ==~ 0.0
# Round to positive decimal places
doAssert round(-547.652, 1) ==~ -547.7
doAssert round(547.652, 1) ==~ 547.7
doAssert round(-547.652, 2) ==~ -547.65
doAssert round(547.652, 2) ==~ 547.65
# Round to negative decimal places
doAssert round(547.652, -1) ==~ 550.0
doAssert round(547.652, -2) ==~ 500.0
doAssert round(547.652, -3) ==~ 1000.0
doAssert round(547.652, -4) ==~ 0.0
doAssert round(-547.652, -1) ==~ -550.0
doAssert round(-547.652, -2) ==~ -500.0
doAssert round(-547.652, -3) ==~ -1000.0
doAssert round(-547.652, -4) ==~ 0.0
block: # splitDecimal() tests block: # splitDecimal() tests
doAssert splitDecimal(54.674).intpart ==~ 54.0 doAssert splitDecimal(54.674).intpart ==~ 54.0

View file

@ -233,22 +233,6 @@ proc createNativeSocket*(domain: Domain = AF_INET,
## by child processes. ## by child processes.
createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol), inheritable) createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol), inheritable)
proc newNativeSocket*(domain: Domain = AF_INET,
sockType: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): SocketHandle
{.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} =
## Creates a new socket; returns `osInvalidSocket` if an error occurs.
createNativeSocket(domain, sockType, protocol)
proc newNativeSocket*(domain: cint, sockType: cint,
protocol: cint): SocketHandle
{.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} =
## Creates a new socket; returns `osInvalidSocket` if an error occurs.
##
## Use this overload if one of the enums specified above does
## not contain what you need.
createNativeSocket(domain, sockType, protocol)
proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, proc bindAddr*(socket: SocketHandle, name: ptr SockAddr,
namelen: SockLen): cint = namelen: SockLen): cint =
result = bindSocket(socket, name, namelen) result = bindSocket(socket, name, namelen)

View file

@ -206,30 +206,6 @@ proc skipRandomNumbers*(s: var Rand) =
s.a0 = s0 s.a0 = s0
s.a1 = s1 s.a1 = s1
proc random*(max: int): int {.benign, deprecated:
"Deprecated since v0.18.0; use 'rand' instead".} =
while true:
let x = next(state)
if x < randMax - (randMax mod Ui(max)):
return int(x mod uint64(max))
proc random*(max: float): float {.benign, deprecated:
"Deprecated since v0.18.0; use 'rand' instead".} =
let x = next(state)
when defined(js):
result = (float(x) / float(high(uint32))) * max
else:
let u = (0x3FFu64 shl 52u64) or (x shr 12u64)
result = (cast[float](u) - 1.0) * max
proc random*[T](x: HSlice[T, T]): T {.deprecated:
"Deprecated since v0.18.0; use 'rand' instead".} =
result = T(random(x.b - x.a)) + x.a
proc random*[T](a: openArray[T]): T {.deprecated:
"Deprecated since v0.18.0; use 'sample' instead".} =
result = a[random(a.low..a.len)]
proc rand*(r: var Rand; max: Natural): int {.benign.} = proc rand*(r: var Rand; max: Natural): int {.benign.} =
## Returns a random integer in the range `0..max` using the given state. ## Returns a random integer in the range `0..max` using the given state.
## ##
@ -362,10 +338,6 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T =
doAssert rand(1..6) == 6 doAssert rand(1..6) == 6
result = rand(state, x) result = rand(state, x)
proc rand*[T](r: var Rand; a: openArray[T]): T {.deprecated:
"Deprecated since v0.20.0; use 'sample' instead".} =
result = a[rand(r, a.low..a.high)]
proc rand*[T: SomeInteger](t: typedesc[T]): T = proc rand*[T: SomeInteger](t: typedesc[T]): T =
## Returns a random integer in the range `low(T)..high(T)`. ## Returns a random integer in the range `low(T)..high(T)`.
## ##
@ -395,10 +367,6 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T =
else: else:
result = cast[T](state.next) result = cast[T](state.next)
proc rand*[T](a: openArray[T]): T {.deprecated:
"Deprecated since v0.20.0; use 'sample' instead".} =
result = a[rand(a.low..a.high)]
proc sample*[T](r: var Rand; s: set[T]): T = proc sample*[T](r: var Rand; s: set[T]): T =
## Returns a random element from the set ``s`` using the given state. ## Returns a random element from the set ``s`` using the given state.
## ##
@ -687,6 +655,6 @@ when isMainModule:
# don't use causes integer overflow # don't use causes integer overflow
doAssert compiles(random[int](low(int) .. high(int))) doAssert compiles(rand[int](low(int) .. high(int)))
main() main()

View file

@ -334,22 +334,3 @@ else:
include ioselects/ioselectors_select include ioselects/ioselectors_select
else: else:
include ioselects/ioselectors_poll include ioselects/ioselectors_poll
proc register*[T](s: Selector[T], fd: int | SocketHandle,
events: set[Event], data: T) {.deprecated: "use registerHandle instead".} =
## **Deprecated since v0.18.0:** Use ``registerHandle`` instead.
s.registerHandle(fd, events, data)
proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} =
## Trigger event ``ev``.
##
## **Deprecated since v0.18.0:** Use ``trigger`` instead.
ev.trigger()
proc update*[T](s: Selector[T], fd: int | SocketHandle,
events: set[Event]) {.deprecated: "use updateHandle instead".} =
## Update file/socket descriptor ``fd``, registered in selector
## ``s`` with new events set ``event``.
##
## **Deprecated since v0.18.0:** Use ``updateHandle`` instead.
s.updateHandle()

View file

@ -581,8 +581,8 @@ proc initDuration*(nanoseconds, microseconds, milliseconds,
## Create a new `Duration <#Duration>`_. ## Create a new `Duration <#Duration>`_.
runnableExamples: runnableExamples:
let dur = initDuration(seconds = 1, milliseconds = 1) let dur = initDuration(seconds = 1, milliseconds = 1)
doAssert dur.milliseconds == 1 doAssert dur.inMilliseconds == 1001
doAssert dur.seconds == 1 doAssert dur.inSeconds == 1
let seconds = convert(Weeks, Seconds, weeks) + let seconds = convert(Weeks, Seconds, weeks) +
convert(Days, Seconds, days) + convert(Days, Seconds, days) +
@ -1464,7 +1464,7 @@ type
s, ss s, ss
fff, ffffff, fffffffff fff, ffffff, fffffffff
t, tt t, tt
y, yy, yyy, yyyy, yyyyy yy, yyyy
YYYY YYYY
uuuu uuuu
UUUU UUUU
@ -1612,11 +1612,8 @@ proc stringToPattern(str: string): FormatPattern =
of "fffffffff": result = fffffffff of "fffffffff": result = fffffffff
of "t": result = t of "t": result = t
of "tt": result = tt of "tt": result = tt
of "y": result = y
of "yy": result = yy of "yy": result = yy
of "yyy": result = yyy
of "yyyy": result = yyyy of "yyyy": result = yyyy
of "yyyyy": result = yyyyy
of "YYYY": result = YYYY of "YYYY": result = YYYY
of "uuuu": result = uuuu of "uuuu": result = uuuu
of "UUUU": result = UUUU of "UUUU": result = UUUU
@ -1709,20 +1706,14 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string,
result.add if dt.hour >= 12: "P" else: "A" result.add if dt.hour >= 12: "P" else: "A"
of tt: of tt:
result.add if dt.hour >= 12: "PM" else: "AM" result.add if dt.hour >= 12: "PM" else: "AM"
of y: # Deprecated
result.add $(dt.yearOfEra mod 10)
of yy: of yy:
result.add (dt.yearOfEra mod 100).intToStr(2) result.add (dt.yearOfEra mod 100).intToStr(2)
of yyy: # Deprecated
result.add (dt.yearOfEra mod 1000).intToStr(3)
of yyyy: of yyyy:
let year = dt.yearOfEra let year = dt.yearOfEra
if year < 10000: if year < 10000:
result.add year.intToStr(4) result.add year.intToStr(4)
else: else:
result.add '+' & $year result.add '+' & $year
of yyyyy: # Deprecated
result.add (dt.yearOfEra mod 100_000).intToStr(5)
of YYYY: of YYYY:
if dt.year < 1: if dt.year < 1:
result.add $(abs(dt.year) + 1) result.add $(abs(dt.year) + 1)
@ -1933,8 +1924,6 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
i.inc 2 i.inc 2
else: else:
result = false result = false
of y, yyy, yyyyy:
raiseAssert "Pattern is invalid for parsing: " & $pattern
of Lit: doAssert false, "Can't happen" of Lit: doAssert false, "Can't happen"
proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat,
@ -2631,167 +2620,11 @@ when not defined(js):
else: else:
result = toFloat(int(getClock())) / toFloat(clocksPerSec) result = toFloat(int(getClock())) / toFloat(clocksPerSec)
# #
# Deprecations # Deprecations
# #
proc countLeapYears*(yearSpan: int): int
{.deprecated.} =
## Returns the number of leap years spanned by a given number of years.
##
## **Note:** For leap years, start date is assumed to be 1 AD.
## counts the number of leap years up to January 1st of a given year.
## Keep in mind that if specified year is a leap year, the leap day
## has not happened before January 1st of that year.
# Deprecated since v0.20.0
(yearSpan - 1) div 4 - (yearSpan - 1) div 100 + (yearSpan - 1) div 400
proc countDays*(yearSpan: int): int
{.deprecated.} =
## Returns the number of days spanned by a given number of years.
# Deprecated since v0.20.0
(yearSpan - 1) * 365 + countLeapYears(yearSpan)
proc countYears*(daySpan: int): int
{.deprecated.} =
## Returns the number of years spanned by a given number of days.
# Deprecated since v0.20.0
((daySpan - countLeapYears(daySpan div 365)) div 365)
proc countYearsAndDays*(daySpan: int): tuple[years: int, days: int]
{.deprecated.} =
## Returns the number of years spanned by a given number of days and the
## remainder as days.
# Deprecated since v0.20.0
let days = daySpan - countLeapYears(daySpan div 365)
result.years = days div 365
result.days = days mod 365
proc toTimeInterval*(time: Time): TimeInterval
{.deprecated: "Use 'between' instead".} =
## Converts a Time to a TimeInterval. To be used when diffing times.
# Deprecated since version 0.20.0
runnableExamples:
let a = fromUnix(10)
let b = fromUnix(1_500_000_000)
let ti = b.toTimeInterval() - a.toTimeInterval()
doAssert a + ti == b
var dt = time.local
initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour,
dt.monthday, 0, dt.month.ord - 1, dt.year)
proc weeks*(dur: Duration): int64
{.inline, deprecated: "Use 'inWeeks' instead".} =
## Number of whole weeks represented by the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4)
doAssert dur.weeks == 1
dur.inWeeks
proc days*(dur: Duration): int64
{.inline, deprecated: "Use 'inDays' instead".} =
## Number of whole days represented by the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4)
doAssert dur.days == 9
dur.inDays
proc hours*(dur: Duration): int64
{.inline, deprecated: "Use 'inHours' instead".} =
## Number of whole hours represented by the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(days = 1, hours = 2, minutes = 3)
doAssert dur.hours == 26
dur.inHours
proc minutes*(dur: Duration): int64
{.inline, deprecated: "Use 'inMinutes' instead".} =
## Number of whole minutes represented by the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(days = 1, hours = 2, minutes = 3)
doAssert dur.minutes == 1563
dur.inMinutes
proc seconds*(dur: Duration): int64
{.inline, deprecated: "Use 'inSeconds' instead".} =
## Number of whole seconds represented by the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(minutes = 10, seconds = 30)
doAssert dur.seconds == 630
dur.inSeconds
proc milliseconds*(dur: Duration): int {.inline, deprecated.} =
## Number of whole milliseconds represented by the **fractional**
## part of the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
microseconds = 8, nanoseconds = 9)
doAssert dur.milliseconds == 7
result = convert(Nanoseconds, Milliseconds, dur.nanosecond)
proc microseconds*(dur: Duration): int {.inline, deprecated.} =
## Number of whole microseconds represented by the **fractional**
## part of the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
microseconds = 8, nanoseconds = 9)
doAssert dur.microseconds == 7008
result = convert(Nanoseconds, Microseconds, dur.nanosecond)
proc nanoseconds*(dur: Duration): NanosecondRange {.inline, deprecated.} =
## Number of whole microseconds represented by the **fractional**
## part of the duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
microseconds = 8, nanoseconds = 9)
doAssert dur.nanoseconds == 7008009
dur.nanosecond
proc fractional*(dur: Duration): Duration {.inline, deprecated.} =
## The fractional part of `dur`, as a duration.
# Deprecated since version v0.20.0
runnableExamples:
let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7,
microseconds = 8, nanoseconds = 9)
doAssert dur.fractional == initDuration(milliseconds = 7, microseconds = 8,
nanoseconds = 9)
initDuration(nanoseconds = dur.nanosecond)
proc fromSeconds*(since1970: float): Time
{.tags: [], raises: [], benign, deprecated: "Use `fromUnixFloat or 'fromUnix' instead".} =
## Takes a float which contains the number of seconds since the unix epoch and
## returns a time object.
# Deprecated since v0.18.0
fromUnixFloat(since1970)
proc fromSeconds*(since1970: int64): Time
{.tags: [], raises: [], benign, deprecated: "Use 'fromUnix' instead".} =
## Takes an int which contains the number of seconds since the unix epoch and
## returns a time object.
# Deprecated since v0.18.0
fromUnix(since1970)
proc toSeconds*(time: Time): float
{.tags: [], raises: [], benign, deprecated: "Use 'toUnixFloat' or 'toUnix' instead".} =
## Returns the time in seconds since the unix epoch, with subsecond resolution.
# Deprecated since v0.18.0
toUnixFloat(time)
proc getGMTime*(time: Time): DateTime
{.tags: [], raises: [], benign, deprecated: "Use 'utc' instead".} =
## Converts the calendar time `time` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
# Deprecated since v0.18.0
time.utc
proc `nanosecond=`*(dt: var DateTime, value: NanosecondRange) {.deprecated: "Deprecated since v1.3.1".} = proc `nanosecond=`*(dt: var DateTime, value: NanosecondRange) {.deprecated: "Deprecated since v1.3.1".} =
dt.nanosecond = value dt.nanosecond = value

View file

@ -1169,88 +1169,6 @@ proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {.
else: else:
result = s result = s
# -----------------------------------------------------------------------------
# deprecated
template runeCaseCheck(s, runeProc, skipNonAlpha) =
## Common code for rune.isLower and rune.isUpper.
if len(s) == 0: return false
var
i = 0
rune: Rune
hasAtleastOneAlphaRune = false
while i < len(s):
fastRuneAt(s, i, rune, doInc = true)
if skipNonAlpha:
var runeIsAlpha = isAlpha(rune)
if not hasAtleastOneAlphaRune:
hasAtleastOneAlphaRune = runeIsAlpha
if runeIsAlpha and (not runeProc(rune)):
return false
else:
if not runeProc(rune):
return false
return if skipNonAlpha: hasAtleastOneAlphaRune else: true
proc isLower*(s: string, skipNonAlpha: bool): bool {.
deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
## **Deprecated since version 0.20 since its semantics are unclear**
##
## Checks whether ``s`` is lower case.
##
## If ``skipNonAlpha`` is true, returns true if all alphabetical
## runes in ``s`` are lower case. Returns false if none of the
## runes in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all runes in
## ``s`` are alphabetical and lower case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
runeCaseCheck(s, isLower, skipNonAlpha)
proc isUpper*(s: string, skipNonAlpha: bool): bool {.
deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
## **Deprecated since version 0.20 since its semantics are unclear**
##
## Checks whether ``s`` is upper case.
##
## If ``skipNonAlpha`` is true, returns true if all alphabetical
## runes in ``s`` are upper case. Returns false if none of the
## runes in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all runes in
## ``s`` are alphabetical and upper case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
runeCaseCheck(s, isUpper, skipNonAlpha)
proc isTitle*(s: string): bool {.noSideEffect, rtl, extern: "nuc$1Str",
deprecated: "Deprecated since version 0.20 since its semantics are unclear".} =
## **Deprecated since version 0.20 since its semantics are unclear**
##
## Checks whether or not ``s`` is a unicode title.
##
## Returns true if the first character in each word inside ``s``
## are upper case and there is at least one character in ``s``.
if s.len == 0:
return false
result = true
var
i = 0
rune: Rune
var firstRune = true
while i < len(s) and result:
fastRuneAt(s, i, rune, doInc = true)
if not rune.isWhiteSpace() and firstRune:
result = rune.isUpper() and result
firstRune = false
elif rune.isWhiteSpace():
firstRune = true
when isMainModule: when isMainModule:

View file

@ -416,8 +416,7 @@ proc ensureInitialized() =
if formatters.len == 0: if formatters.len == 0:
formatters = @[OutputFormatter(defaultConsoleFormatter())] formatters = @[OutputFormatter(defaultConsoleFormatter())]
if not disabledParamFiltering and not testsFilters.isValid: if not disabledParamFiltering:
testsFilters.init()
when declared(paramCount): when declared(paramCount):
# Read tests to run from the command line. # Read tests to run from the command line.
for i in 1 .. paramCount(): for i in 1 .. paramCount():
@ -712,7 +711,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped =
## import math, random ## import math, random
## proc defectiveRobot() = ## proc defectiveRobot() =
## randomize() ## randomize()
## case random(1..4) ## case rand(1..4)
## of 1: raise newException(OSError, "CANNOT COMPUTE!") ## of 1: raise newException(OSError, "CANNOT COMPUTE!")
## of 2: discard parseInt("Hello World!") ## of 2: discard parseInt("Hello World!")
## of 3: raise newException(IOError, "I can't do that Dave.") ## of 3: raise newException(IOError, "I can't do that Dave.")

View file

@ -481,18 +481,10 @@ proc `+=`*[T: SomeInteger](x: var T, y: T) {.
magic: "Inc", noSideEffect.} magic: "Inc", noSideEffect.}
## Increments an integer. ## Increments an integer.
proc `+=`*[T: enum|bool](x: var T, y: T) {.
magic: "Inc", noSideEffect, deprecated: "use `inc` instead".}
## **Deprecated since v0.20**: use `inc` instead.
proc `-=`*[T: SomeInteger](x: var T, y: T) {. proc `-=`*[T: SomeInteger](x: var T, y: T) {.
magic: "Dec", noSideEffect.} magic: "Dec", noSideEffect.}
## Decrements an integer. ## Decrements an integer.
proc `-=`*[T: enum|bool](x: var T, y: T) {.
magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".}
## **Deprecated since v0.20**: use `dec` instead.
proc `*=`*[T: SomeInteger](x: var T, y: T) {. proc `*=`*[T: SomeInteger](x: var T, y: T) {.
inline, noSideEffect.} = inline, noSideEffect.} =
## Binary `*=` operator for integers. ## Binary `*=` operator for integers.

View file

@ -34,7 +34,6 @@ pkg1 "coco", true
pkg1 "combparser" pkg1 "combparser"
pkg1 "compactdict" pkg1 "compactdict"
pkg1 "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" pkg1 "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension"
pkg1 "criterion"
pkg1 "dashing", false, "nim c tests/functional.nim" pkg1 "dashing", false, "nim c tests/functional.nim"
pkg1 "delaunay" pkg1 "delaunay"
pkg1 "docopt" pkg1 "docopt"

View file

@ -0,0 +1,27 @@
discard """
output: '''a
long
list
of
words'''
cmd: r"nim c --hints:on $options -d:release $file"
ccodecheck: "! @'genericSeqAssign'"
target: "c"
"""
# bug #4354
import tables
import sets
import strutils
#const FRUITS = ["banana", "apple", "grapes"]
#let FRUITS = ["banana", "apple", "grapes"].toHashSet
const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable
proc main() =
let L = "a long list of words".split()
for word in L:
if word notin FRUITS:
echo(word)
main()

View file

@ -79,9 +79,8 @@ block hashForHashedSet:
let let
seq1 = "This is the test." seq1 = "This is the test."
seq2 = "the test is This." seq2 = "the test is This."
s1 = seq1.toSet() s1 = seq1.toHashSet()
s2 = seq2.toSet() s2 = seq2.toHashSet()
var hashSeq: seq[Hash] = @[]
doAssert s1 == s2 doAssert s1 == s2
doAssert hash(s1) == hash(s2) doAssert hash(s1) == hash(s2)

View file

@ -1,6 +1,6 @@
# Copyright (C) 2015 Dominik Picheta # Copyright (C) 2015 Dominik Picheta
# MIT License - Look at license.txt for details. # MIT License - Look at license.txt for details.
import net, strtabs, re, tables, parseutils, os, strutils, uri, import net, strtabs, re, tables, os, strutils, uri,
times, mimetypes, asyncnet, asyncdispatch, macros, md5, times, mimetypes, asyncnet, asyncdispatch, macros, md5,
logging, httpcore, asyncfile, macrocache, json, options, logging, httpcore, asyncfile, macrocache, json, options,
strformat strformat
@ -23,6 +23,7 @@ export SameSite
when useHttpBeast: when useHttpBeast:
import httpbeast except Settings, Request import httpbeast except Settings, Request
import options import options
from nativesockets import close
else: else:
import asynchttpserver except Request import asynchttpserver except Request
@ -72,14 +73,14 @@ type
of RouteCode: of RouteCode:
data: ResponseData data: ResponseData
const jesterVer = "0.4.0" const jesterVer = "0.4.3"
proc toStr(headers: Option[RawHeaders]): string = proc toStr(headers: Option[RawHeaders]): string =
return $newHttpHeaders(headers.get(@({:}))) return $newHttpHeaders(headers.get(@({:})))
proc createHeaders(headers: RawHeaders): string = proc createHeaders(headers: RawHeaders): string =
result = "" result = ""
if headers != nil: if headers.len > 0:
for header in headers: for header in headers:
let (key, value) = header let (key, value) = header
result.add(key & ": " & value & "\c\L") result.add(key & ": " & value & "\c\L")
@ -98,22 +99,24 @@ proc unsafeSend(request: Request, content: string) =
proc send( proc send(
request: Request, code: HttpCode, headers: Option[RawHeaders], body: string request: Request, code: HttpCode, headers: Option[RawHeaders], body: string
) = ): Future[void] =
when useHttpBeast: when useHttpBeast:
let h = let h =
if headers.isNone: "" if headers.isNone: ""
else: headers.get().createHeaders else: headers.get().createHeaders
request.getNativeReq.send(code, body, h) request.getNativeReq.send(code, body, h)
var fut = newFuture[void]()
complete(fut)
return fut
else: else:
# TODO: This may cause issues if we send too fast. return request.getNativeReq.respond(
asyncCheck request.getNativeReq.respond(
code, body, newHttpHeaders(headers.get(@({:}))) code, body, newHttpHeaders(headers.get(@({:})))
) )
proc statusContent(request: Request, status: HttpCode, content: string, proc statusContent(request: Request, status: HttpCode, content: string,
headers: Option[RawHeaders]) = headers: Option[RawHeaders]): Future[void] =
try: try:
send(request, status, headers, content) result = send(request, status, headers, content)
when not defined(release): when not defined(release):
logging.debug(" $1 $2" % [$status, toStr(headers)]) logging.debug(" $1 $2" % [$status, toStr(headers)])
except: except:
@ -174,7 +177,11 @@ proc sendStaticIfExists(
return Http403 return Http403
let fileSize = getFileSize(p) let fileSize = getFileSize(p)
let mimetype = req.settings.mimes.getMimetype(p.splitFile.ext[1 .. ^1]) let ext = p.splitFile.ext
let mimetype = req.settings.mimes.getMimetype(
if ext.len > 0: ext[1 .. ^1]
else: ""
)
if fileSize < 10_000_000: # 10 mb if fileSize < 10_000_000: # 10 mb
var file = readFile(p) var file = readFile(p)
@ -183,18 +190,18 @@ proc sendStaticIfExists(
# If the user has a cached version of this file and it matches our # If the user has a cached version of this file and it matches our
# version, let them use it # version, let them use it
if req.headers.hasKey("If-None-Match") and req.headers["If-None-Match"] == hashed: if req.headers.hasKey("If-None-Match") and req.headers["If-None-Match"] == hashed:
req.statusContent(Http304, "", none[RawHeaders]()) await req.statusContent(Http304, "", none[RawHeaders]())
else: else:
req.statusContent(Http200, file, some(@({ await req.statusContent(Http200, file, some(@({
"Content-Type": mimetype, "Content-Type": mimetype,
"ETag": hashed "ETag": hashed
}))) })))
else: else:
let headers = @({ let headers = @({
"Content-Type": mimetype, "Content-Type": mimetype,
"Content-Length": $fileSize "Content-Length": $fileSize
}) })
req.statusContent(Http200, "", some(headers)) await req.statusContent(Http200, "", some(headers))
var fileStream = newFutureStream[string]("sendStaticIfExists") var fileStream = newFutureStream[string]("sendStaticIfExists")
var file = openAsync(p, fmRead) var file = openAsync(p, fmRead)
@ -216,13 +223,22 @@ proc sendStaticIfExists(
# If we get to here then no match could be found. # If we get to here then no match could be found.
return Http404 return Http404
proc close*(request: Request) =
## Closes client socket connection.
##
## Routes using this procedure must enable raw mode.
let nativeReq = request.getNativeReq()
when useHttpBeast:
nativeReq.forget()
nativeReq.client.close()
proc defaultErrorFilter(error: RouteError): ResponseData = proc defaultErrorFilter(error: RouteError): ResponseData =
case error.kind case error.kind
of RouteException: of RouteException:
let e = error.exc let e = error.exc
let traceback = getStackTrace(e) let traceback = getStackTrace(e)
var errorMsg = e.msg var errorMsg = e.msg
if errorMsg.isNil: errorMsg = "(nil)" if errorMsg.len == 0: errorMsg = "(empty)"
let error = traceback & errorMsg let error = traceback & errorMsg
logging.error(error) logging.error(error)
@ -295,9 +311,11 @@ proc handleFileRequest(
jes.settings.staticDir / cgi.decodeUrl(req.pathInfo) jes.settings.staticDir / cgi.decodeUrl(req.pathInfo)
) )
# Verify that this isn't outside our static` dir. # Verify that this isn't outside our static dir.
var status = Http400 var status = Http400
if path.splitFile.dir.startsWith(jes.settings.staticDir): let pathDir = path.splitFile.dir / ""
let staticDir = jes.settings.staticDir / ""
if pathDir.startsWith(staticDir):
if existsDir(path): if existsDir(path):
status = await sendStaticIfExists( status = await sendStaticIfExists(
req, req,
@ -347,7 +365,7 @@ proc handleRequestSlow(
not dispatchedError and respData.content.len == 0: not dispatchedError and respData.content.len == 0:
respData = await dispatchError(jes, req, initRouteError(respData)) respData = await dispatchError(jes, req, initRouteError(respData))
statusContent( await statusContent(
req, req,
respData.code, respData.code,
respData.content, respData.content,
@ -368,7 +386,7 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] =
if likely(jes.matchers.len == 1 and not jes.matchers[0].async): if likely(jes.matchers.len == 1 and not jes.matchers[0].async):
let respData = jes.matchers[0].syncProc(req) let respData = jes.matchers[0].syncProc(req)
if likely(respData.matched): if likely(respData.matched):
statusContent( return statusContent(
req, req,
respData.code, respData.code,
respData.content, respData.content,
@ -383,6 +401,8 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] =
let respDataFut = dispatchError(jes, req, initRouteError(exc)) let respDataFut = dispatchError(jes, req, initRouteError(exc))
return handleRequestSlow(jes, req, respDataFut, true) return handleRequestSlow(jes, req, respDataFut, true)
assert(not result.isNil, "Expected handleRequest to return a valid future.")
proc newSettings*( proc newSettings*(
port = Port(5000), staticDir = getCurrentDir() / "public", port = Port(5000), staticDir = getCurrentDir() / "public",
appName = "", bindAddr = "", reusePort = false, appName = "", bindAddr = "", reusePort = false,
@ -461,14 +481,19 @@ proc serve*(
] ]
) )
else: else:
logging.info("Jester is making jokes at http://0.0.0.0:$1$2" % when defined(windows):
[$self.settings.port, self.settings.appName]) logging.info("Jester is making jokes at http://127.0.0.1:$1$2 (all interfaces)" %
[$self.settings.port, self.settings.appName])
else:
logging.info("Jester is making jokes at http://0.0.0.0:$1$2" %
[$self.settings.port, self.settings.appName])
var jes = self var jes = self
when useHttpBeast: when useHttpBeast:
run( run(
proc (req: httpbeast.Request): Future[void] = proc (req: httpbeast.Request): Future[void] =
result = handleRequest(jes, req), {.gcsafe.}:
result = handleRequest(jes, req),
httpbeast.initSettings(self.settings.port, self.settings.bindAddr) httpbeast.initSettings(self.settings.port, self.settings.bindAddr)
) )
else: else:
@ -484,14 +509,6 @@ proc serve*(
asyncCheck serveFut asyncCheck serveFut
runForever() runForever()
template resp*(code: HttpCode,
headers: openarray[tuple[key, value: string]],
content: string): typed =
## Sets ``(code, headers, content)`` as the response.
bind TCActionSend, newHttpHeaders
result = (TCActionSend, code, headers.newHttpHeaders.some(), content, true)
break route
template setHeader(headers: var Option[RawHeaders], key, value: string): typed = template setHeader(headers: var Option[RawHeaders], key, value: string): typed =
bind isNone bind isNone
if isNone(headers): if isNone(headers):
@ -509,6 +526,17 @@ template setHeader(headers: var Option[RawHeaders], key, value: string): typed =
# Add key if it doesn't exist. # Add key if it doesn't exist.
headers = some(h & @({key: value})) headers = some(h & @({key: value}))
template resp*(code: HttpCode,
headers: openarray[tuple[key, val: string]],
content: string): typed =
## Sets ``(code, headers, content)`` as the response.
bind TCActionSend
result = (TCActionSend, code, none[RawHeaders](), content, true)
for header in headers:
setHeader(result[2], header[0], header[1])
break route
template resp*(content: string, contentType = "text/html;charset=utf-8"): typed = template resp*(content: string, contentType = "text/html;charset=utf-8"): typed =
## Sets ``content`` as the response; ``Http200`` as the status code ## Sets ``content`` as the response; ``Http200`` as the status code
## and ``contentType`` as the Content-Type. ## and ``contentType`` as the Content-Type.
@ -687,7 +715,8 @@ proc daysForward*(days: int): DateTime =
return getTime().utc + initTimeInterval(days = days) return getTime().utc + initTimeInterval(days = days)
template setCookie*(name, value: string, expires="", template setCookie*(name, value: string, expires="",
sameSite: SameSite=Lax): typed = sameSite: SameSite=Lax, secure = false,
httpOnly = false, domain = "", path = "") =
## Creates a cookie which stores ``value`` under ``name``. ## Creates a cookie which stores ``value`` under ``name``.
## ##
## The SameSite argument determines the level of CSRF protection that ## The SameSite argument determines the level of CSRF protection that
@ -695,7 +724,7 @@ template setCookie*(name, value: string, expires="",
## should protect you from most vulnerabilities. Note that this is only ## should protect you from most vulnerabilities. Note that this is only
## supported by some browsers: ## supported by some browsers:
## https://caniuse.com/#feat=same-site-cookie-attribute ## https://caniuse.com/#feat=same-site-cookie-attribute
let newCookie = makeCookie(name, value, expires) let newCookie = makeCookie(name, value, expires, domain, path, secure, httpOnly, sameSite)
if isSome(result[2]) and if isSome(result[2]) and
(let headers = result[2].get(); headers.toTable.hasKey("Set-Cookie")): (let headers = result[2].get(); headers.toTable.hasKey("Set-Cookie")):
result[2] = some(headers & @({"Set-Cookie": newCookie})) result[2] = some(headers & @({"Set-Cookie": newCookie}))
@ -703,9 +732,12 @@ template setCookie*(name, value: string, expires="",
setHeader(result[2], "Set-Cookie", newCookie) setHeader(result[2], "Set-Cookie", newCookie)
template setCookie*(name, value: string, expires: DateTime, template setCookie*(name, value: string, expires: DateTime,
sameSite: SameSite=Lax): typed = sameSite: SameSite=Lax, secure = false,
httpOnly = false, domain = "", path = "") =
## Creates a cookie which stores ``value`` under ``name``. ## Creates a cookie which stores ``value`` under ``name``.
setCookie(name, value, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'")) setCookie(name, value,
format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
sameSite, secure, httpOnly, domain, path)
proc normalizeUri*(uri: string): string = proc normalizeUri*(uri: string): string =
## Remove any trailing ``/``. ## Remove any trailing ``/``.
@ -721,7 +753,10 @@ proc checkAction*(respData: var ResponseData): bool =
of TCActionPass: of TCActionPass:
result = false result = false
of TCActionNothing: of TCActionNothing:
assert(false) raise newException(
ValueError,
"Missing route action, did you forget to use `resp` in your route?"
)
proc skipDo(node: NimNode): NimNode {.compiletime.} = proc skipDo(node: NimNode): NimNode {.compiletime.} =
if node.kind == nnkDo: if node.kind == nnkDo:
@ -764,14 +799,14 @@ proc ctParsePattern(pattern, pathPrefix: string): NimNode {.compiletime.} =
newStrLitNode(node.text), newStrLitNode(node.text),
newIdentNode(if node.optional: "true" else: "false")) newIdentNode(if node.optional: "true" else: "false"))
template setDefaultResp*(): typed = template setDefaultResp*() =
# TODO: bindSym this in the 'routes' macro and put it in each route # TODO: bindSym this in the 'routes' macro and put it in each route
bind TCActionNothing, newHttpHeaders bind TCActionNothing, newHttpHeaders
result.action = TCActionNothing result.action = TCActionNothing
result.code = Http200 result.code = Http200
result.content = "" result.content = ""
template declareSettings(): typed {.dirty.} = template declareSettings() {.dirty.} =
when not declaredInScope(settings): when not declaredInScope(settings):
var settings = newSettings() var settings = newSettings()
@ -1299,7 +1334,7 @@ proc routesEx(name: string, body: NimNode): NimNode =
for branch in exceptionBranches: for branch in exceptionBranches:
stmts.add(newIfStmt(branch)) stmts.add(newIfStmt(branch))
errorHandlerProc[6][0][1][^1][1][1][0] = stmts errorHandlerProc[6][0][1][^1][1][1][0] = stmts
if httpCodeBranches.len > 1: if httpCodeBranches.len != 0:
var stmts = newStmtList() var stmts = newStmtList()
for branch in httpCodeBranches: for branch in httpCodeBranches:
stmts.add(newIfStmt(branch)) stmts.add(newIfStmt(branch))
@ -1313,7 +1348,7 @@ proc routesEx(name: string, body: NimNode): NimNode =
# echo toStrLit(result) # echo toStrLit(result)
# echo treeRepr(result) # echo treeRepr(result)
macro routes*(body: untyped): typed = macro routes*(body: untyped) =
result = routesEx("match", body) result = routesEx("match", body)
let jesIdent = genSym(nskVar, "jes") let jesIdent = genSym(nskVar, "jes")
let matchIdent = newIdentNode("match") let matchIdent = newIdentNode("match")
@ -1329,13 +1364,13 @@ macro routes*(body: untyped): typed =
serve(`jesIdent`) serve(`jesIdent`)
) )
macro router*(name: untyped, body: untyped): typed = macro router*(name: untyped, body: untyped) =
if name.kind != nnkIdent: if name.kind != nnkIdent:
error("Need an ident.", name) error("Need an ident.", name)
routesEx($name.ident, body) routesEx(strVal(name), body)
macro settings*(body: untyped): typed = macro settings*(body: untyped) =
#echo(treeRepr(body)) #echo(treeRepr(body))
expectKind(body, nnkStmtList) expectKind(body, nnkStmtList)

View file

@ -1,6 +1,6 @@
# Package # Package
version = "0.4.0" # Be sure to update jester.jesterVer too! version = "0.4.3" # Be sure to update jester.jesterVer too!
author = "Dominik Picheta" author = "Dominik Picheta"
description = "A sinatra-like web framework for Nim." description = "A sinatra-like web framework for Nim."
license = "MIT" license = "MIT"
@ -13,10 +13,10 @@ skipDirs = @["tests"]
requires "nim >= 0.18.1" requires "nim >= 0.18.1"
when not defined(windows): when not defined(windows):
requires "httpbeast >= 0.2.0" requires "httpbeast >= 0.2.2"
# For tests # For tests
requires "asynctools" requires "https://github.com/timotheecour/asynctools#pr_fix_compilation"
task test, "Runs the test suite.": task test, "Runs the test suite.":
exec "nimble c -y -r tests/tester" exec "nimble c -y -r tests/tester"

View file

@ -15,7 +15,7 @@ type
proc parsePattern*(pattern: string): Pattern = proc parsePattern*(pattern: string): Pattern =
result = @[] result = @[]
template addNode(result: var Pattern, theT: NodeType, theText: string, template addNode(result: var Pattern, theT: NodeType, theText: string,
isOptional: bool): typed = isOptional: bool) =
block: block:
var newNode: Node var newNode: Node
newNode.typ = theT newNode.typ = theT
@ -120,7 +120,7 @@ proc match*(pattern: Pattern, s: string):
if s.len != i: if s.len != i:
result.matched = false result.matched = false
when true: when isMainModule:
let f = parsePattern("/show/@id/test/@show?/?") let f = parsePattern("/show/@id/test/@show?/?")
doAssert match(f, "/show/12/test/hallo/").matched doAssert match(f, "/show/12/test/hallo/").matched
doAssert match(f, "/show/2131726/test/jjjuuwąąss").matched doAssert match(f, "/show/2131726/test/jjjuuwąąss").matched

View file

@ -21,7 +21,7 @@ type
JesterError* = object of Exception JesterError* = object of Exception
proc parseUrlQuery*(query: string, result: var Table[string, string]) proc parseUrlQuery*(query: string, result: var Table[string, string])
{.deprecated: "use stdlib".} = {.deprecated: "use stdlib cgi/decodeData".} =
var i = 0 var i = 0
i = query.skip("?") i = query.skip("?")
while i < query.len()-1: while i < query.len()-1:
@ -192,4 +192,3 @@ when false:
var r = {:}.newStringTable var r = {:}.newStringTable
parseUrlQuery("FirstName=Mickey", r) parseUrlQuery("FirstName=Mickey", r)
echo r echo r

View file

@ -61,6 +61,7 @@ proc reqMethod*(req: Request): HttpMethod =
req.req.httpMethod.get() req.req.httpMethod.get()
else: else:
req.req.reqMethod req.req.reqMethod
proc reqMeth*(req: Request): HttpMethod {.deprecated.} = proc reqMeth*(req: Request): HttpMethod {.deprecated.} =
req.reqMethod req.reqMethod

View file

@ -9,7 +9,7 @@ proc main =
for ii in 0..50_000: for ii in 0..50_000:
#while true: #while true:
var t = getTime() var t = getTime()
var g = t.getGMTime() var g = t.utc()
#echo isOnStack(addr g) #echo isOnStack(addr g)
if i mod 100 == 0: if i mod 100 == 0:

View file

@ -447,7 +447,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[],
# First generate the joined version of input parameters in a list. # First generate the joined version of input parameters in a list.
var var
seen = initSet[string]() seen = initHashSet[string]()
prefixes: seq[string] = @[] prefixes: seq[string] = @[]
helps: seq[string] = @[] helps: seq[string] = @[]
for key in keys: for key in keys:

View file

@ -486,7 +486,7 @@ when defined(DebugKeys):
activeVehicle.body.setPos mouseToSpace()) activeVehicle.body.setPos mouseToSpace())
ingameClient.registerHandler(KeyY, down, proc() = ingameClient.registerHandler(KeyY, down, proc() =
const looloo = ["Asteroid1", "Asteroid2"] const looloo = ["Asteroid1", "Asteroid2"]
addObject(looloo[random(looloo.len)])) addObject(looloo[rand(looloo.len)]))
ingameClient.registerHandler(KeyO, down, proc() = ingameClient.registerHandler(KeyO, down, proc() =
if objects.len == 0: if objects.len == 0:
echo "Objects is empty" echo "Objects is empty"

View file

@ -63,7 +63,7 @@ task "release", "release build":
## zip up all the files and such or something useful here ## zip up all the files and such or something useful here
task "testskel", "create skeleton test dir for testing": task "testskel", "create skeleton test dir for testing":
let dirname = "test-" & $random(5000) let dirname = "test-" & $rand(5000)
removeDir dirName removeDir dirName
createDir dirName/"data/fnt" createDir dirName/"data/fnt"
copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf" copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf"
@ -133,7 +133,7 @@ task "download", "download game assets":
else: ## this crashes, dunno why else: ## this crashes, dunno why
var var
z: TZipArchive z: TZipArchive
destDir = getCurrentDir()/("unzip" & $random(5000)) destDir = getCurrentDir()/("unzip" & $rand(5000))
if not z.open(path, fmRead): if not z.open(path, fmRead):
echo "Could not open zip, bad download?" echo "Could not open zip, bad download?"
return return

View file

@ -50,7 +50,7 @@ proc post*(database: Database, message: Message) =
raise newException(ValueError, "Message has to be less than 140 characters.") raise newException(ValueError, "Message has to be less than 140 characters.")
database.db.exec(sql"INSERT INTO Message VALUES (?, ?, ?);", #<2> database.db.exec(sql"INSERT INTO Message VALUES (?, ?, ?);", #<2>
message.username, $message.time.toSeconds().int, message.msg) #<3> message.username, $message.time.toUnix().int, message.msg) #<3>
proc follow*(database: Database, follower: User, user: User) = proc follow*(database: Database, follower: User, user: User) =
database.db.exec(sql"INSERT INTO Following VALUES (?, ?);",#<2> database.db.exec(sql"INSERT INTO Following VALUES (?, ?);",#<2>
@ -90,4 +90,4 @@ proc findMessages*(database: Database, usernames: seq[string],
"ORDER BY time DESC LIMIT " & $limit), "ORDER BY time DESC LIMIT " & $limit),
usernames) usernames)
for row in messages: for row in messages:
result.add(Message(username: row[0], time: fromSeconds(row[1].parseInt), msg: row[2])) result.add(Message(username: row[0], time: fromUnix(row[1].parseInt), msg: row[2]))

View file

@ -51,7 +51,7 @@ routes:
redirect(uri("/" & @"target")) redirect(uri("/" & @"target"))
post "/login": post "/login":
setCookie("username", @"username", getTime().getGMTime() + 2.hours) setCookie("username", @"username", getTime().utc() + 2.hours)
redirect("/") redirect("/")
post "/createMessage": post "/createMessage":

View file

@ -33,7 +33,7 @@
#for message in messages: #for message in messages:
<div> <div>
<a href="/${message.username}">${message.username}</a> <a href="/${message.username}">${message.username}</a>
<span>${message.time.getGMTime().format("HH:mm MMMM d',' yyyy")}</span> <span>${message.time.utc().format("HH:mm MMMM d',' yyyy")}</span>
<h3>${message.msg}</h3> <h3>${message.msg}</h3>
</div> </div>
#end for #end for

View file

@ -60,15 +60,15 @@ block tcritbits:
block testequivalence: block testequivalence:
doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset") doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset") doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset") doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset") doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset") doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset") doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==") doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==") doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==") doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")

View file

@ -47,10 +47,10 @@ test "unittest multiple requires":
require(true) require(true)
import math, random import random
from strutils import parseInt from strutils import parseInt
proc defectiveRobot() = proc defectiveRobot() =
case random(1..4) case rand(1..4)
of 1: raise newException(OSError, "CANNOT COMPUTE!") of 1: raise newException(OSError, "CANNOT COMPUTE!")
of 2: discard parseInt("Hello World!") of 2: discard parseInt("Hello World!")
of 3: raise newException(IOError, "I can't do that Dave.") of 3: raise newException(IOError, "I can't do that Dave.")

View file

@ -107,7 +107,7 @@ block tgetast_typeliar:
error("Assertion failed: " & $(`message`) & "\n" & `line`) error("Assertion failed: " & $(`message`) & "\n" & `line`)
return return
macro assertOrReturn(condition: bool): typed = macro assertOrReturn(condition: bool) =
var message : NimNode = newLit(condition.repr) var message : NimNode = newLit(condition.repr)
# echo message # echo message
result = getAst assertOrReturn2(condition, message) result = getAst assertOrReturn2(condition, message)

View file

@ -57,7 +57,7 @@ converter int2string(x: int): string = $x
template wrap(body: typed): untyped = template wrap(body: typed): untyped =
body body
macro makeProc(): typed = macro makeProc() =
# Make a template tree # Make a template tree
result = quote do: result = quote do:
proc someProc* = proc someProc* =

View file

@ -10,4 +10,4 @@ const EXTENSIONMAP = {
"c": @["*.c", "*.h"], "c": @["*.c", "*.h"],
}.toTable() }.toTable()
const EXTENSIONS = toSet(concat(toSeq(EXTENSIONMAP.values()))) const EXTENSIONS = toHashSet(concat(toSeq(EXTENSIONMAP.values())))

View file

@ -5,7 +5,7 @@ line: 11
import sets import sets
let BUILTIN_NAMES = toSet(["int8", "int16", "int32", "int64"]) let BUILTIN_NAMES = toHashSet(["int8", "int16", "int32", "int64"])
macro test*(): bool = macro test*(): bool =
echo "int64" notin BUILTIN_NAMES echo "int64" notin BUILTIN_NAMES

View file

@ -101,7 +101,7 @@ proc createChangelog(pkgName, version, maintainer: string): string =
addN(" * Initial release.") addN(" * Initial release.")
addN("") addN("")
addN(" -- " & maintainer & " " & addN(" -- " & maintainer & " " &
formatDateTime(getGMTime(getTime()), "+0000")) formatDateTime(utc(getTime()), "+0000"))
proc createRules(): string = proc createRules(): string =
## Creates a nim application-agnostic rules file for building deb packages. ## Creates a nim application-agnostic rules file for building deb packages.

View file

@ -421,7 +421,7 @@ proc generateRss(outputFilename: string, news: seq[TRssItem]) =
output.write(link(href = rssNewsUrl)) output.write(link(href = rssNewsUrl))
output.write(id(rssNewsUrl)) output.write(id(rssNewsUrl))
let now = getGMTime(getTime()) let now = utc(getTime())
output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday)) output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday))
for rss in news: for rss in news:

View file

@ -250,7 +250,7 @@ runForever()
<p>This section lists the companies and individuals that are, very kindly, contributing a <p>This section lists the companies and individuals that are, very kindly, contributing a
monthly amount to help sustain Nim's development. For more details take a monthly amount to help sustain Nim's development. For more details take a
look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p> look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p>
<p class="lastUpdate">Last updated: ${getTime().getGMTime().format("dd/MM/yyyy")}</p> <p class="lastUpdate">Last updated: ${getTime().utc().format("dd/MM/yyyy")}</p>
<dl> <dl>
${generateSponsors(activeSponsors)} ${generateSponsors(activeSponsors)}
</dl> </dl>