uritemplate.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
  2. //
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of The BSD 3-Clause License
  5. // that can be found in the LICENSE file.
  6. package uritemplate
  7. import (
  8. "log"
  9. "regexp"
  10. "strings"
  11. "sync"
  12. )
  13. var (
  14. debug = debugT(false)
  15. )
  16. type debugT bool
  17. func (t debugT) Printf(format string, v ...interface{}) {
  18. if t {
  19. log.Printf(format, v...)
  20. }
  21. }
  22. // Template represents a URI Template.
  23. type Template struct {
  24. raw string
  25. exprs []template
  26. // protects the rest of fields
  27. mu sync.Mutex
  28. varnames []string
  29. re *regexp.Regexp
  30. prog *prog
  31. }
  32. // New parses and constructs a new Template instance based on the template.
  33. // New returns an error if the template cannot be recognized.
  34. func New(template string) (*Template, error) {
  35. return (&parser{r: template}).parseURITemplate()
  36. }
  37. // MustNew panics if the template cannot be recognized.
  38. func MustNew(template string) *Template {
  39. ret, err := New(template)
  40. if err != nil {
  41. panic(err)
  42. }
  43. return ret
  44. }
  45. // Raw returns a raw URI template passed to New in string.
  46. func (t *Template) Raw() string {
  47. return t.raw
  48. }
  49. // Varnames returns variable names used in the template.
  50. func (t *Template) Varnames() []string {
  51. t.mu.Lock()
  52. defer t.mu.Unlock()
  53. if t.varnames != nil {
  54. return t.varnames
  55. }
  56. reg := map[string]struct{}{}
  57. t.varnames = []string{}
  58. for i := range t.exprs {
  59. expr, ok := t.exprs[i].(*expression)
  60. if !ok {
  61. continue
  62. }
  63. for _, spec := range expr.vars {
  64. if _, ok := reg[spec.name]; ok {
  65. continue
  66. }
  67. reg[spec.name] = struct{}{}
  68. t.varnames = append(t.varnames, spec.name)
  69. }
  70. }
  71. return t.varnames
  72. }
  73. // Expand returns a URI reference corresponding to the template expanded using the passed variables.
  74. func (t *Template) Expand(vars Values) (string, error) {
  75. var w strings.Builder
  76. for i := range t.exprs {
  77. expr := t.exprs[i]
  78. if err := expr.expand(&w, vars); err != nil {
  79. return w.String(), err
  80. }
  81. }
  82. return w.String(), nil
  83. }
  84. // Regexp converts the template to regexp and returns compiled *regexp.Regexp.
  85. func (t *Template) Regexp() *regexp.Regexp {
  86. t.mu.Lock()
  87. defer t.mu.Unlock()
  88. if t.re != nil {
  89. return t.re
  90. }
  91. var b strings.Builder
  92. b.WriteByte('^')
  93. for _, expr := range t.exprs {
  94. expr.regexp(&b)
  95. }
  96. b.WriteByte('$')
  97. t.re = regexp.MustCompile(b.String())
  98. return t.re
  99. }