# Borrowed from: github.com/juretta/uri-templates/blob/master/grammar/uri_template.treetop
grammar UriTemplate
include DataMetaCommonsRoot rule uri_template uri_element more_elements:(uri_element)* { def value(env={}) uri_element.value(env) << more_elements.elements.map{|el| el.value(env)}.join end } end rule uri_element expansion / uri_part end rule expansion '{' c:( var / operator ) '}' { def value(env = {}) c.value(env) end } end rule uri_part (unreserved / reserved / pct_encoded) { def value(env = {}) text_value end } end rule arg (reserved / unreserved / pct_encoded)* end rule op ( 'opt' { # If each variable is undefined or an empty list then substitute the # empty string, otherwise substitute the value of 'arg'. def exec lambda do |env, arg, vars| ret = '' vars.split(',').each do |var| if env[var] && (env[var].respond_to?(:length) ? env[var].length > 0 : true) ret = "#{arg}" break end end ret end end } / 'neg' { # If all of the variables are un-defined or empty then substitute the # value of arg, otherwise substitute the empty string. def exec lambda do |env, arg, vars| ret = "#{arg}" vars.split(',').each do |var| if !env[var].to_s.blank? ret = "" break end end ret end end } / 'prefix' { # The prefix operator MUST only have one variable in its expansion. If # the variable is defined and non-empty then substitute the value of # arg followed by the value of the variable, otherwise substitute the # empty string. def exec lambda do |env, prefix, vars| v = env[vars] if vars =~ /([^=]+)=([^=]+)/ var, default = $1.dup, $2.dup v = env[var] v = default if v.to_s.blank? end !v.blank? ? "#{prefix}#{UriTemplate::Encoder.encode(v)}" : "" end end } / 'suffix' { # The suffix operator MUST only have one variable in its expansion. If # the variable is defined and non-empty then substitute the value of # the variable followed by the value of arg, otherwise substitute the # empty string. def exec lambda do |env, append, vars| v = env[vars] if vars =~ /([^=]+)=([^=]+)/ var, default = $1.dup, $2.dup v = env[var] v = default if v.to_s.blank? end if v val = UriTemplate::Encoder.encode(v) !val.blank? ? "#{val}#{append}" : "" else '' end end end } / 'join' { # For each variable that is defined and non-empty create a keyvalue # string that is the concatenation of the variable name, "=", and the # variable value. Concatenate more than one keyvalue string with # intervening values of arg to create the substitution value. def exec lambda do |env, joinop, vars| vars.split(',').map do |var| v = env[var] if var =~ /([^=]+)=([^=]+)/ var, default = $1.dup, $2.dup v = env[var] v = default if v.to_s.blank? end "#{var}=#{UriTemplate::Encoder.encode(v)}" if v end.compact.join(joinop) end end } / 'list' { # The listjoin operator MUST have only one variable in its expansion # and that variable must be a list. More than one variable is an # error. If the list is non-empty then substitute the concatenation of # all the list members with intervening values of arg. If the list is # empty or the variable is undefined them substitute the empty string. def exec lambda do |env, joinop, vars| return "" unless env[vars].respond_to? :each env[vars].map do |v| "#{UriTemplate::Encoder.encode(v)}" if v end.compact.join(joinop) end end } ) end rule vars var ("," var)* end rule vardefault (unreserved / pct_encoded)* end rule var varname defaults:('=' vardefault)* { def value(env={} ) return UriTemplate::Encoder.encode(env[name]) unless env[name].nil? defaults.text_value.gsub(/=/, '') end def name varname.text_value end } end rule operator "-" op "|" arg "|" vars { def value(env={}) op.exec.call(env, arg.text_value, vars.text_value) # if op.respond_to?(:exec) end } end rule varname [a-zA-Z0-9] [a-zA-Z0-9_.-]* end rule alpha [A-Za-z_] end rule alphanumeric alpha / [0-9] end # see http://www.ietf.org/rfc/rfc3986.txt rule unreserved alphanumeric / "-" / "." / "_" / "~" end # see http://www.ietf.org/rfc/rfc3986.txt rule pct_encoded '%' hexdig hexdig end rule hexdig [a-fA-F0-9] end # see http://www.ietf.org/rfc/rfc3986.txt rule reserved gen_delims / sub_delims end rule gen_delims ":" / "/" / "?" / "#" / "[" / "]" / "@" end rule sub_delims "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" end
end