context.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package pongo2
  2. import (
  3. "regexp"
  4. "github.com/juju/errors"
  5. )
  6. var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
  7. // A Context type provides constants, variables, instances or functions to a template.
  8. //
  9. // pongo2 automatically provides meta-information or functions through the "pongo2"-key.
  10. // Currently, context["pongo2"] contains the following keys:
  11. // 1. version: returns the version string
  12. //
  13. // Template examples for accessing items from your context:
  14. // {{ myconstant }}
  15. // {{ myfunc("test", 42) }}
  16. // {{ user.name }}
  17. // {{ pongo2.version }}
  18. type Context map[string]interface{}
  19. func (c Context) checkForValidIdentifiers() *Error {
  20. for k, v := range c {
  21. if !reIdentifiers.MatchString(k) {
  22. return &Error{
  23. Sender: "checkForValidIdentifiers",
  24. OrigError: errors.Errorf("context-key '%s' (value: '%+v') is not a valid identifier", k, v),
  25. }
  26. }
  27. }
  28. return nil
  29. }
  30. // Update updates this context with the key/value-pairs from another context.
  31. func (c Context) Update(other Context) Context {
  32. for k, v := range other {
  33. c[k] = v
  34. }
  35. return c
  36. }
  37. // ExecutionContext contains all data important for the current rendering state.
  38. //
  39. // If you're writing a custom tag, your tag's Execute()-function will
  40. // have access to the ExecutionContext. This struct stores anything
  41. // about the current rendering process's Context including
  42. // the Context provided by the user (field Public).
  43. // You can safely use the Private context to provide data to the user's
  44. // template (like a 'forloop'-information). The Shared-context is used
  45. // to share data between tags. All ExecutionContexts share this context.
  46. //
  47. // Please be careful when accessing the Public data.
  48. // PLEASE DO NOT MODIFY THE PUBLIC CONTEXT (read-only).
  49. //
  50. // To create your own execution context within tags, use the
  51. // NewChildExecutionContext(parent) function.
  52. type ExecutionContext struct {
  53. template *Template
  54. Autoescape bool
  55. Public Context
  56. Private Context
  57. Shared Context
  58. }
  59. var pongo2MetaContext = Context{
  60. "version": Version,
  61. }
  62. func newExecutionContext(tpl *Template, ctx Context) *ExecutionContext {
  63. privateCtx := make(Context)
  64. // Make the pongo2-related funcs/vars available to the context
  65. privateCtx["pongo2"] = pongo2MetaContext
  66. return &ExecutionContext{
  67. template: tpl,
  68. Public: ctx,
  69. Private: privateCtx,
  70. Autoescape: true,
  71. }
  72. }
  73. func NewChildExecutionContext(parent *ExecutionContext) *ExecutionContext {
  74. newctx := &ExecutionContext{
  75. template: parent.template,
  76. Public: parent.Public,
  77. Private: make(Context),
  78. Autoescape: parent.Autoescape,
  79. }
  80. newctx.Shared = parent.Shared
  81. // Copy all existing private items
  82. newctx.Private.Update(parent.Private)
  83. return newctx
  84. }
  85. func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
  86. return ctx.OrigError(errors.New(msg), token)
  87. }
  88. func (ctx *ExecutionContext) OrigError(err error, token *Token) *Error {
  89. filename := ctx.template.name
  90. var line, col int
  91. if token != nil {
  92. // No tokens available
  93. // TODO: Add location (from where?)
  94. filename = token.Filename
  95. line = token.Line
  96. col = token.Col
  97. }
  98. return &Error{
  99. Template: ctx.template,
  100. Filename: filename,
  101. Line: line,
  102. Column: col,
  103. Token: token,
  104. Sender: "execution",
  105. OrigError: err,
  106. }
  107. }
  108. func (ctx *ExecutionContext) Logf(format string, args ...interface{}) {
  109. ctx.template.set.logf(format, args...)
  110. }