Skip to content

Instantly share code, notes, and snippets.

@cyisfor
Created May 8, 2019 04:13
Show Gist options
  • Save cyisfor/18b976fbbad530a883f15d3bf8f70ebb to your computer and use it in GitHub Desktop.
Save cyisfor/18b976fbbad530a883f15d3bf8f70ebb to your computer and use it in GitHub Desktop.
from times import Time, `$`, DateTime, toTime
from sequtils import toSeq, mapIt
from strutils import replace
################
# This is just some stuff to establish a few interestingly named and varying types
type Ident = int
type Actor = object
name: string
type Tag = int
func `$`(actor: Actor): string =
return "Actor " & actor.name
func urlencode(s: string): string =
return s.replace(" ", "+")
#################################
# Begin what SHOULD be the output of a macro.
# Note all the copy and paste code duplication.
# As well as the many different locations that must be kept in sync to add or remove anything
type ParameterKind = enum
local_only_kind = "local_only"
only_media_kind = "only_media"
since_kind = "since"
until_kind = "until"
poster_kind = "poster"
signer_kind = "signer"
tags_kind = "tags"
tags_excluded_kind = "tags_excluded"
type TypeKind = enum
Time_type
Actor_type
Tag_type
type Behavior = enum
flag_behavior
value_behavior
seq_behavior
type Parameter = object
case kind: ParameterKind:
of local_only_kind, only_media_kind:
discard
of since_kind, until_kind:
Time_value: Time
of poster_kind, signer_kind:
Actor_value: Actor
of tags_kind, tags_excluded_kind:
Tag_value: seq[Tag]
func doc(p: Parameter): string =
case p.kind:
of local_only_kind: return "Only local posts"
of only_media_kind: return "Only posts with media in them"
of since_kind: return "Only posts after this time"
of until_kind: return "Only posts before this time"
of poster_kind: return "Only posts posted by this guy"
of signer_kind: return "Only posts signed by this guy"
of tags_kind: return "Only posts with these tags"
of tags_excluded_kind: return "Only posts without these tags"
func behavior(p: Parameter): Behavior =
case p.kind:
of local_only_kind, only_media_kind:
flag_behavior
of since_kind, until_kind:
value_behavior
of poster_kind, signer_kind:
value_behavior
of tags_kind, tags_excluded_kind:
seq_behavior
func typeKind(p: Parameter): TypeKind =
case p.kind:
of local_only_kind, only_media_kind:
assert(false)
of since_kind, until_kind:
return Time_type
of poster_kind, signer_kind:
return Actor_type
of tags_kind, tags_excluded_kind:
return Tag_type
proc convert_flag(p: Parameter): seq[tuple[name: string, value: string]] =
result.add(($p.kind, "1"))
proc convert_value[T](p: Parameter, value: T): seq[tuple[name: string, value: string]] =
result.add(($p.kind, urlencode($value)))
proc convert_seq[T](p: Parameter, value: seq[T]): seq[tuple[name: string, value: string]] =
# I want to shoot whoevexr started this trend in the elbow
let arrayname = $p.kind & "[]"
for item in value:
result.add((arrayname, urlencode($item)))
proc toQueryParams*(p: Parameter): seq[tuple[name: string,value: string]] =
if p.behavior == flag_behavior: return convert_flag(p)
case p.typeKind:
of Time_type: return convert_value(p, p.Time_value)
of Actor_type: return convert_value(p, p.Actor_value)
of Tag_type: return convert_seq(p, p.Tag_value)
let local_only* = Parameter(kind: local_only_kind)
let only_media* = Parameter(kind: only_media_kind)
proc since*(value: DateTime): Parameter =
Parameter(kind: since_kind, Time_value: value.toTime())
proc until*(value: DateTime): Parameter =
Parameter(kind: until_kind, Time_value: value.toTime())
proc poster*(value: Actor): Parameter =
Parameter(kind: poster_kind, Actor_value: value)
proc signer*(value: Actor): Parameter =
Parameter(kind: signer_kind, Actor_value: value)
proc tags*(value: varargs[string]): Parameter =
Parameter(kind: tags_kind, Tag_value: value.mapIt(it.len))
proc tagsExcluded*(value: varargs[string]): Parameter =
Parameter(kind: tags_excluded_kind, Tag_value: value.mapIt(it[0].ord))
# end hypothetical macro output
#############################################3
# this is what I would LIKE to write instead of the above code
when false:
flags:
local_only = "Only local posts"
only_media = "Only posts with media in them"
Time:
since = "Only posts after this time"
until = "Only posts before this time"
Actor:
poster = "Only posts posted by this guy"
signer = "Only posts signed by this guy"
seq[Tag]:
tags = "Only posts with these tags"
tags_excluded = "Only posts without these tags"
#################################
# Then just something to prove that it actually works
when isMainModule:
import times
from strutils import join
from sequtils import mapIt
proc showPosts(parameters: varargs[Parameter]) =
var query_params: seq[tuple[name: string,value: string]]
for parameter in parameters:
query_params.add(parameter.toQuery_params)
echo(query_params.mapIt(it[0] & "=" & it[1]).join("&"))
let Alice: Actor = Actor(name: "Alice")
let Joe: Actor = Actor(name: "Giuseppi Verdi")
show_posts(
since(now() - 30.days),
until(now() - 15.days),
poster(Alice),
local_only,
signer(Joe),
tags("ponies", "art", "beautiful"),
tagsExcluded("nyx"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment