Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions dimscord/helpers/message.nim
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ template editMessage*(c: SomeChannel, m: Message;
components
)

proc edit*(m: Message;
template edit*(m: Message;
content = "";
embeds: seq[Embed] = @[];
attachments: seq[Attachment] = @[];
components: seq[MessageComponent] = @[];
files: seq[DiscordFile] = @[];
tts = false;
flags = none set[MessageFlags]): Future[Message] {.async.} =
flags = none set[MessageFlags]): Future[Message] =
## Edits a Message.

# getMessage(getClient.shards[0].cache.gchannel(m), "123")
Expand Down
285 changes: 141 additions & 144 deletions dimscord/objects/macros.nim
Original file line number Diff line number Diff line change
@@ -1,144 +1,141 @@
import std/[macros, macrocache], typedefs

#const clientCache = CacheSeq"dimscord.client"

macro keyCheckOptInt*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getInt

macro keyCheckOptBool*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getBool

macro keyCheckBool*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = `obj`[`fieldName`].getBool

macro keyCheckOptStr*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getStr

macro keyCheckStr*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = `obj`[`fieldName`].getStr

macro loadOpt*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome:
var value = %*get(`lit`)
when `lit` is Option[int]:
if `lit`.get == -1: value = newJNull()
when `lit` is Option[string]:
if `lit`.get == "": value = newJNull()
when `lit` is Option[enum]:
value = %*(ord get(`lit`))

`obj`[`fieldName`] = value

macro loadOpts*(res, parent: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `parent`.`lit`.isSome:
`res`[`fieldName`] = %*get(`parent`.`lit`)

macro loadNullableOptStr*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome and get(`lit`) == "":
`obj`[`fieldName`] = newJNull()

macro loadNullableOptInt*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome and get(`lit`) == -1:
`obj`[`fieldName`] = newJNull()

macro optionIf*(check: typed): untyped =
## Runs `check` to see if a variable is considered empty
## - if check is true, then it returns None[T]
## - if check is false, then it returns some(variable)
## not very robust but supports basics like calls, field access
expectKind check, nnkInfix
let symbol = case check[1].kind:
of nnkDotExpr: check[1][1]
else: check[1]
let
variable = check[1]
varType = ident $symbol.getType()

result = quote do:
if `check`: none `varType` else: some (`variable`)

macro mainClient*(x: typed) =
## Registers a DiscordClient for helper templates
## Usage: `let discord {.mainClient.} = newDiscordClient("TOKEN")`
let tname = ident("dimscordPrivateClient")
var vname: NimNode
if (x.kind == nnkLetSection) or (x.kind == nnkVarSection):
vname = x[0][0]
else:
# TODO: check for `newDiscordClient` presence
error("Invalid usage, macro expects a let or var statement")
result = newStmtList()
result.add(x)
result.add(quote do:
template `tname`*(): DiscordClient {.dirty.} =
`vname`
)

proc sCheck(): bool =
when declared(s): s is Shard

template getClient*: DiscordClient =
## Gets registered client or shard client
when declared(dimscordPrivateClient):
var dc {.cursor.} = dimscordPrivateClient() # note: is safe in async code ?
when defined(dimscordDebug):
if dc.isNil:
raise (ref AccessViolationDefect)(
msg: "Client is nil: Check client initialization"
)
dc
elif sCheck():
when defined(dimscordDebug):
if s.client.isNil:
raise (ref AccessViolationDefect)(
msg: "Client is nil: Check shard initialization"
)
s.client
else:
{.error: "No client found. Use `mainClient` or ensure 's' Shard exists".}
import std/[macros, macrocache], typedefs

#const clientCache = CacheSeq"dimscord.client"

macro keyCheckOptInt*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getInt

macro keyCheckOptBool*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getBool

macro keyCheckBool*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = `obj`[`fieldName`].getBool

macro keyCheckOptStr*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = some `obj`[`fieldName`].getStr

macro keyCheckStr*(obj: typed, obj2: typed,
lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `fieldName` in `obj` and `obj`[`fieldName`].kind != JNull:
`obj2`.`lit` = `obj`[`fieldName`].getStr

macro loadOpt*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome:
var value = %*get(`lit`)
when `lit` is Option[int]:
if `lit`.get == -1: value = newJNull()
when `lit` is Option[string]:
if `lit`.get == "": value = newJNull()
when `lit` is Option[enum]:
value = %*(ord get(`lit`))

`obj`[`fieldName`] = value

macro loadOpts*(res, parent: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `parent`.`lit`.isSome:
`res`[`fieldName`] = %*get(`parent`.`lit`)

macro loadNullableOptStr*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome and get(`lit`) == "":
`obj`[`fieldName`] = newJNull()

macro loadNullableOptInt*(obj: typed, lits: varargs[untyped]): untyped =
result = newStmtList()
for lit in lits:
let fieldName = lit.strVal
result.add quote do:
if `lit`.isSome and get(`lit`) == -1:
`obj`[`fieldName`] = newJNull()

macro optionIf*(check: typed): untyped =
## Runs `check` to see if a variable is considered empty
## - if check is true, then it returns None[T]
## - if check is false, then it returns some(variable)
## not very robust but supports basics like calls, field access
expectKind check, nnkInfix
let symbol = case check[1].kind:
of nnkDotExpr: check[1][1]
else: check[1]
let
variable = check[1]
varType = ident $symbol.getType()

result = quote do:
if `check`: none `varType` else: some (`variable`)

macro mainClient*(x: typed) =
## Registers a DiscordClient for helper templates
## Usage: `let discord {.mainClient.} = newDiscordClient("TOKEN")`
let tname = ident("dimscordPrivateClient")
var vname: NimNode
if (x.kind == nnkLetSection) or (x.kind == nnkVarSection):
vname = x[0][0]
else:
# TODO: check for `newDiscordClient` presence
error("Invalid usage, macro expects a let or var statement")
result = newStmtList()
result.add(x)
result.add(quote do:
template `tname`*(): DiscordClient {.dirty.} =
`vname`
)

template getClient*: DiscordClient =
## Gets registered client or shard client
when declared(dimscordPrivateClient):
var dc {.cursor.} = dimscordPrivateClient() # note: is safe in async code ?
when defined(dimscordDebug):
if dc.isNil:
raise (ref AccessViolationDefect)(
msg: "Client is nil: Check client initialization"
)
dc
elif declared(s) and (s is Shard):
when defined(dimscordDebug):
if s.client.isNil:
raise (ref AccessViolationDefect)(
msg: "Client is nil: Check shard initialization"
)
s.client
else:
{.error: "No client found. Use `mainClient` or ensure 's' Shard exists".}
3 changes: 2 additions & 1 deletion tests/testHelpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import unittest
import asyncdispatch
import options, tables
import json
import std/setutils
import ../dimscord/objects
import ../dimscord/constants
import ../dimscord/restapi
Expand All @@ -18,7 +19,7 @@ let mockSeqString = @["mock1", "mock2"]
let mockTableString = {"en-US": some("mock_value")}.toTable()
let mockEmbed = Embed(title: some("Test Embed"))
let mockAttachment = Attachment(id: "123", filename: "test.txt")
let mockComponent = MessageComponent(kind: MessageComponentType.Button, custom_id: some("mock_button"))
let mockComponent = MessageComponent(kind: MessageComponentType.mctButton, custom_id: some("mock_button"))
let mockFile = DiscordFile(name: "test.txt", body: "")
let mockAllowedMentions = AllowedMentions(parse: @[])
let mockPermObj = PermObj(allowed: {}, denied: {})
Expand Down
Loading