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
|
require 'mustermann/ast/pattern'
module Mustermann
# URI template pattern implementation.
#
# @example
# Mustermann.new('/{foo}') === '/bar' # => true
#
# @see Mustermann::Pattern
# @see file:README.md#template Syntax description in the README
# @see http://tools.ietf.org/html/rfc6570 RFC 6570
class Template < AST::Pattern
register :template, :uri_template
on ?{ do |char|
variable = proc do
start = pos
match = expect(/(?<name>\w+)(?:\:(?<prefix>\d{1,4})|(?<explode>\*))?/)
node(:variable, match[:name], prefix: match[:prefix], explode: match[:explode], start: start)
end
operator = buffer.scan(/[\+\#\.\/;\?\&\=\,\!\@\|]/)
expression = node(:expression, [variable[]], operator: operator) { variable[] if scan(?,) }
expression if expect(?})
end
on(?}) { |c| unexpected(c) }
# @!visibility private
def compile(*args)
options = args.last.is_a?(Hash) ? args.pop : {}
@split_params = {}
super(*args, options.merge(:split_params => @split_params))
end
# @!visibility private
def map_param(key, value)
return super unless variable = @split_params[key]
value = value.split variable[:separator]
value.map! { |e| e.sub(/\A#{key}=/, '') } if variable[:parametric]
value.map! { |e| super(key, e) }
end
# @!visibility private
def always_array?(key)
@split_params.include? key
end
# Identity patterns support generating templates (the logic is quite complex, though).
#
# @example (see Mustermann::Pattern#to_templates)
# @param (see Mustermann::Pattern#to_templates)
# @return (see Mustermann::Pattern#to_templates)
# @see Mustermann::Pattern#to_templates
def to_templates
[to_s]
end
private :compile, :map_param, :always_array?
end
end
|