all repos — hastysite @ 1e77065565a49f578429f3abf9dd58a44f5052a4

A high-performance static site generator.

vendor/moustachupkg/context.nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
import json
import sequtils
import strutils
import tables


type
  ContextKind* = enum ## possible Context types
    CArray,
    CObject,
    CValue

  ## Context used to render a mustache template
  Context* = ref ContextObj
  ContextObj = object
    case kind*: ContextKind
    of CValue:
      val: JsonNode
    of CArray:
      elems: seq[Context]
    of CObject:
      fields: Table[string, Context]

## Builders

proc newContext*(j : JsonNode = nil): Context =
  ## Create a new Context based on a JsonNode object
  new(result)
  if j == nil:
    result.kind = CObject
    result.fields = initTable[string, Context](4)
  else:
    case j.kind
    of JObject:
      result.kind = CObject
      result.fields = initTable[string, Context](4)
      for key, val in pairs(j.fields):
        result.fields[key] = newContext(val)
    of JArray:
      result.kind = CArray
      result.elems = @[]
      for val in j.elems:
        result.elems.add(newContext(val))
    else:
      result.kind = CValue
      result.val = j

proc newArrayContext*(): Context =
  ## Create a new Context of kind CArray
  new(result)
  result.kind = CArray
  result.elems = @[]

## Getters

proc `[]`*(c: Context, key: string): Context =
  ## Return the Context associated with `key`.
  ## If the Context at `key` does not exist, return nil.
  assert(c != nil)
  if c.kind != CObject: return nil
  if c.fields.hasKey(key): return c.fields[key] else: return nil

proc `[]`*(c: Context, index: int): Context =
  assert(c != nil)
  if c.kind != CArray: return nil else: return c.elems[index]

## Setters

proc `[]=`*(c: var Context, key: string, value: Context) =
  ## Assign a context `value` to `key` in context `c`
  assert(c.kind == CObject)
  c.fields[key] = value

proc `[]=`*(c: var Context, key: string, value: JsonNode) =
  ## Convert and assign `value` to `key` in `c`
  assert(c.kind == CObject)
  c[key] = newContext(value)

proc `[]=`*(c: var Context; key: string, value: BiggestInt) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = newContext(newJInt(value))

proc `[]=`*(c: var Context; key: string, value: string) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = newContext(newJString(value))

proc `[]=`*(c: var Context; key: string, value: float) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = newContext(newJFloat(value))

proc `[]=`*(c: var Context; key: string, value: bool) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = newContext(newJBool(value))

proc `[]=`*(c: var Context, key: string, value: openarray[Context]) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  var contextList = newArrayContext()
  for v in value:
    contextList.elems.add(v)
  c[key] = contextList

proc `[]=`*(c: var Context, key: string, value: openarray[string]) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = map(value, proc(x: string): Context = newContext(newJString(x)))

proc `[]=`*(c: var Context, key: string, value: openarray[int]) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = map(value, proc(x: int): Context = newContext(newJInt(x)))

proc `[]=`*(c: var Context, key: string, value: openarray[float]) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = map(value, proc(x: float): Context = newContext(newJFloat(x)))

proc `[]=`*(c: var Context, key: string, value: openarray[bool]) =
  ## Assign `value` to `key` in Context `c`
  assert(c.kind == CObject)
  c[key] = map(value, proc(x: bool): Context = newContext(newJBool(x)))

## Printers

proc `$`*(c: Context): string =
  ## Return a string representing the context. Useful for debugging
  result = "Context->[kind: " & $c.kind
  case c.kind
  of CValue: result &= "\nval: " & $c.val
  of CArray:
    var strArray = map(c.elems, proc(c: Context): string = $c)
    result &= "\nelems: [" & join(strArray, ", ") & "]"
  of CObject:
    var strArray : seq[string] = @[]
    for key, val in pairs(c.fields):
      strArray.add(key & ": " & $val)
    result &= "\nfields: {" & join(strArray, ", ") & "}"
  result &= "\n]"

proc toString*(c: Context): string =
  ## Return string representation of `c` relevant to mustache
  if c != nil:
    if c.kind == CValue:
      case c.val.kind
      of JString:
       return c.val.str
      of JFloat:
       return c.val.fnum.formatFloat(ffDefault, 0)
      of JInt:
       return $c.val.num
      of JNull:
       return ""
      of JBool:
       return if c.val.bval: "true" else: ""
      else:
       return $c.val
    else:
      return $c
  else:
    return ""

proc len*(c: Context): int =
  if c.kind == CArray: 
    result = c.elems.len
  elif c.kind == CObject:
    result = c.fields.len
  else: discard

converter toBool*(c: Context): bool =
  assert(c.kind == CValue)
  case c.val.kind
  of JBool: result = c.val.bval
  of JNull: result = false
  of JString: result = c.val.str != ""
  else: result = true