docs: def template2path(template, params, ranges=None):
      """Converts a template and a dict of parameters to a path fragment.
  
      Converts a template, such as /{name}/ and a dictionary of parameter
      values to a URL path (string).
  
      Parameter values that are used for buildig the path are converted to
      strings using `str()` and URI-escaped, then validated against the their
      range. Unused parameters are ignored.
  
      Any optional ([]) blocks in the template are skipped unless they contain at
      least one parameter and all parameters needed to fill the block (including
      nested blocks) are present in `params`.
  
      Example:
  
      >>> import rhino.mapper
      >>> rhino.mapper.template2path("/{name}", {'name': 'fred'})
      '/fred'
  
      """
      if len(template) and -1 < template.find('|') < len(template) - 1:
          raise InvalidTemplateError("'|' may only appear at the end, found at position %d in %s" % (template.find('|'), template))
      if ranges is None:
          ranges = DEFAULT_RANGES
  
      # Stack for path components. A new list is added for each '[]' block
      # encountered. When the closing ']' is reached, the last element is
      # removed and either merged into the previous one (we keep the
      # block) or discarded (we skip the block). At the end, this should
      # contain a flat list of strings as its single element.
      stack = [[]]
      pattern = "[^/]+"    # default range
      name = ""            # name of the current parameter
      bracketdepth = 0     # current level of nested brackets
      skip_to_depth = 0    # if > 1, skip until we're back at this bracket level
      state = S_PATH
      rangename = None     # range name for the current parameter
      seen_name = [False]  # have we seen a named param in bracket level (index)?
  
      for c in template_splitter.split(template):
          if state == S_PATH:
              if len(c) > 1:
                  stack[-1].append(c)
              elif c == '[':
                  bracketdepth += 1
                  stack.append([])
                  seen_name.append(False)
              elif c == ']':
                  bracketdepth -= 1
                  if bracketdepth < 0:
                      raise InvalidTemplateError("Mismatched brackets in %s" % template)
                  last_elem = stack.pop()
                  if seen_name.pop():
                      stack[-1].extend(last_elem)
                      seen_name[-1] = True
              elif c == '{':
                  name = ""
                  state = S_TEMPLATE
              elif c == '}':
                  raise InvalidTemplateError("Mismatched braces in %s" % template)
              elif c == '|':
                  pass
              else:
                  stack[-1].append(c)
          elif state == S_SKIP:
              if c == '[':
                  bracketdepth += 1
                  seen_name.append(False)
              elif c == ']':
                  if bracketdepth == skip_to_depth:
                      stack.pop()
                      skip_to_depth = 0
                      state = S_PATH
                  bracketdepth -= 1
                  seen_name.pop()
          else:  # state == S_TEMPLATE
              if c == '}':
                  if name not in params:
                      if bracketdepth:
                          # We're missing a parameter, but it's ok since
                          # we're inside a '[]' block. Skip everything
                          # until we reach the end of the current block.
                          skip_to_depth = bracketdepth
                          state = S_SKIP
                      else:
                          raise InvalidArgumentError("Missing parameter '%s' in %s" % (name, template))
                  else:
                      if rangename and rangename in ranges:
                          regex = ranges[rangename]
                      else:
                          regex = pattern
                      value_bytes = unicode(params[name]).encode('utf-8')
                      value = urllib.quote(value_bytes, safe='/:;')
                      if not re.match('^' + regex + '$', value):
                          raise InvalidArgumentError("Value '%s' for parameter '%s' does not match '^%s$' in %s" % (value, name, regex, template))
                      stack[-1].append(value)
                      state = S_PATH
                  rangename = None
              else:
                  name = c
                  if name.find(":") > -1:
                      name, rangename = name.split(":")
                  seen_name[bracketdepth] = True
  
      if bracketdepth != 0:
          raise InvalidTemplateError("Mismatched brackets in %s" % template)
      if state == S_TEMPLATE:
          raise InvalidTemplateError("Mismatched braces in %s" % template)
      # None of these Should Ever Happen [TM]
      if state == S_SKIP:     # pragma: no cover
          raise MapperException("Internal error: end state is S_SKIP")
      if len(stack) > 1:      # pragma: no cover
          raise MapperException("Internal error: stack not empty")
      if len(seen_name) != 1: # pragma: no cover
          raise MapperException("Internal error: seen_name not empty")
  
      return "".join(stack[0])