First version of URI Template library
as specified by http://tools.ietf.org/html/draft-gregorio-uritemplate-05 (it seems to contains some error in the spec .. or minor incoherences, to double check) The matcher is basic, it does not handle all the details of the string builder, but that seems ok for now.
This commit is contained in:
10
library/protocol/uri_template/license.lic
Normal file
10
library/protocol/uri_template/license.lic
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
332
library/protocol/uri_template/src/uri_template.e
Normal file
332
library/protocol/uri_template/src/uri_template.e
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Summary description for {URI_TEMPLATE}.
|
||||||
|
|
||||||
|
See http://tools.ietf.org/html/draft-gregorio-uritemplate-05
|
||||||
|
|
||||||
|
]"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (s: STRING)
|
||||||
|
do
|
||||||
|
template := s
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_handler (s: STRING; a_handler: detachable URI_TEMPLATE_HANDLER)
|
||||||
|
do
|
||||||
|
make (s)
|
||||||
|
analyze (a_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
template: STRING
|
||||||
|
-- URI string representation
|
||||||
|
|
||||||
|
path_variable_names: LIST [STRING]
|
||||||
|
do
|
||||||
|
analyze (Void)
|
||||||
|
if attached expansion_parts as l_x_parts then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (l_x_parts.count)
|
||||||
|
from
|
||||||
|
l_x_parts.start
|
||||||
|
until
|
||||||
|
l_x_parts.after
|
||||||
|
loop
|
||||||
|
if not l_x_parts.item.is_query then
|
||||||
|
Result.append (l_x_parts.item.variable_names)
|
||||||
|
end
|
||||||
|
l_x_parts.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
query_variable_names: LIST [STRING]
|
||||||
|
do
|
||||||
|
analyze (Void)
|
||||||
|
if attached expansion_parts as l_x_parts then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (l_x_parts.count)
|
||||||
|
from
|
||||||
|
l_x_parts.start
|
||||||
|
until
|
||||||
|
l_x_parts.after
|
||||||
|
loop
|
||||||
|
if l_x_parts.item.is_query then
|
||||||
|
Result.append (l_x_parts.item.variable_names)
|
||||||
|
end
|
||||||
|
l_x_parts.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Builder
|
||||||
|
|
||||||
|
string (a_ht: HASH_TABLE [detachable ANY, STRING]): STRING
|
||||||
|
local
|
||||||
|
tpl: like template
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
p,q: INTEGER
|
||||||
|
do
|
||||||
|
analyze (Void)
|
||||||
|
tpl := template
|
||||||
|
if attached expansion_parts as l_x_parts then
|
||||||
|
create Result.make (tpl.count)
|
||||||
|
from
|
||||||
|
l_x_parts.start
|
||||||
|
p := 1
|
||||||
|
until
|
||||||
|
l_x_parts.after
|
||||||
|
loop
|
||||||
|
q := l_x_parts.item.position
|
||||||
|
--| Added inter variable text
|
||||||
|
Result.append (tpl.substring (p, q - 1))
|
||||||
|
--| Expand variables ...
|
||||||
|
exp := l_x_parts.item
|
||||||
|
exp.append_to_string (a_ht, Result)
|
||||||
|
|
||||||
|
p := q + l_x_parts.item.expression.count + 2
|
||||||
|
|
||||||
|
l_x_parts.forth
|
||||||
|
end
|
||||||
|
Result.append (tpl.substring (p, tpl.count))
|
||||||
|
else
|
||||||
|
create Result.make_from_string (tpl)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
url_encoder: URL_ENCODER
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Analyze
|
||||||
|
|
||||||
|
match (a_uri: STRING): detachable TUPLE [path_variables: HASH_TABLE [STRING, STRING]; query_variables: HASH_TABLE [STRING, STRING]]
|
||||||
|
local
|
||||||
|
b: BOOLEAN
|
||||||
|
tpl: like template
|
||||||
|
l_offset: INTEGER
|
||||||
|
p,q: INTEGER
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
vn, s,t: STRING
|
||||||
|
vv: STRING
|
||||||
|
l_vars, l_path_vars, l_query_vars: HASH_TABLE [STRING, STRING]
|
||||||
|
do
|
||||||
|
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||||
|
analyze (Void)
|
||||||
|
if attached expansion_parts as l_x_parts then
|
||||||
|
create l_path_vars.make (l_x_parts.count)
|
||||||
|
create l_query_vars.make (l_x_parts.count)
|
||||||
|
l_vars := l_path_vars
|
||||||
|
tpl := template
|
||||||
|
b := True
|
||||||
|
from
|
||||||
|
l_x_parts.start
|
||||||
|
p := 1
|
||||||
|
l_offset := 0
|
||||||
|
until
|
||||||
|
l_x_parts.after or not b
|
||||||
|
loop
|
||||||
|
exp := l_x_parts.item
|
||||||
|
vn := exp.expression
|
||||||
|
q := exp.position
|
||||||
|
--| Check text between vars
|
||||||
|
if q > p then
|
||||||
|
t := tpl.substring (p, q - 1)
|
||||||
|
s := a_uri.substring (p + l_offset, q + l_offset - 1)
|
||||||
|
b := s.same_string (t)
|
||||||
|
p := q + vn.count + 2
|
||||||
|
end
|
||||||
|
--| Check related variable
|
||||||
|
if not vn.is_empty then
|
||||||
|
if exp.is_query then
|
||||||
|
l_vars := l_query_vars
|
||||||
|
else
|
||||||
|
l_vars := l_path_vars
|
||||||
|
end
|
||||||
|
|
||||||
|
inspect vn[1]
|
||||||
|
when '?' then
|
||||||
|
import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, a_uri.count), l_vars)
|
||||||
|
when ';' then
|
||||||
|
import_path_style_parameters_into (a_uri.substring (q + l_offset, a_uri.count), l_vars)
|
||||||
|
else
|
||||||
|
vv := next_path_variable_value (a_uri, q + l_offset)
|
||||||
|
l_vars.force (vv, vn)
|
||||||
|
l_offset := l_offset + vv.count - (vn.count + 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_x_parts.forth
|
||||||
|
end
|
||||||
|
if b then
|
||||||
|
Result := [l_path_vars, l_query_vars]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
analyze (a_handler: detachable URI_TEMPLATE_HANDLER)
|
||||||
|
local
|
||||||
|
l_x_parts: like expansion_parts
|
||||||
|
c: CHARACTER
|
||||||
|
i,p,n: INTEGER
|
||||||
|
tpl: like template
|
||||||
|
in_x: BOOLEAN
|
||||||
|
in_query: BOOLEAN
|
||||||
|
x: STRING
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
do
|
||||||
|
l_x_parts := expansion_parts
|
||||||
|
if l_x_parts = Void then
|
||||||
|
tpl := template
|
||||||
|
|
||||||
|
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||||
|
create {ARRAYED_LIST [like expansion_parts.item]} l_x_parts.make (tpl.occurrences ('{'))
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := tpl.count
|
||||||
|
create x.make_empty
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
c := tpl[i]
|
||||||
|
if in_x then
|
||||||
|
if c = '}' then
|
||||||
|
create exp.make (p, x.twin, in_query)
|
||||||
|
l_x_parts.force (exp)
|
||||||
|
x.wipe_out
|
||||||
|
in_x := False
|
||||||
|
else
|
||||||
|
x.extend (c)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inspect c
|
||||||
|
when '{' then
|
||||||
|
check x_is_empty: x.is_empty end
|
||||||
|
p := i
|
||||||
|
in_x := True
|
||||||
|
if not in_query then
|
||||||
|
in_query := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||||
|
end
|
||||||
|
when '?' then
|
||||||
|
in_query := True
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
expansion_parts := l_x_parts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
expansion_parts: detachable LIST [URI_TEMPLATE_EXPRESSION]
|
||||||
|
-- Expansion parts
|
||||||
|
|
||||||
|
import_path_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
do
|
||||||
|
import_custom_style_parameters_into (a_content, ';', res)
|
||||||
|
end
|
||||||
|
|
||||||
|
import_form_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
do
|
||||||
|
import_custom_style_parameters_into (a_content, '&', res)
|
||||||
|
end
|
||||||
|
|
||||||
|
import_custom_style_parameters_into (a_content: STRING; a_separator: CHARACTER; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
local
|
||||||
|
n, p, i, j: INTEGER
|
||||||
|
s: STRING
|
||||||
|
l_name,l_value: STRING
|
||||||
|
do
|
||||||
|
n := a_content.count
|
||||||
|
if n > 0 then
|
||||||
|
from
|
||||||
|
p := 1
|
||||||
|
until
|
||||||
|
p = 0
|
||||||
|
loop
|
||||||
|
i := a_content.index_of (a_separator, p)
|
||||||
|
if i = 0 then
|
||||||
|
s := a_content.substring (p, n)
|
||||||
|
p := 0
|
||||||
|
else
|
||||||
|
s := a_content.substring (p, i - 1)
|
||||||
|
p := i + 1
|
||||||
|
end
|
||||||
|
if not s.is_empty then
|
||||||
|
j := s.index_of ('=', 1)
|
||||||
|
if j > 0 then
|
||||||
|
l_name := s.substring (1, j - 1)
|
||||||
|
l_value := s.substring (j + 1, s.count)
|
||||||
|
res.force (l_value, l_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next_path_variable_value (a_uri: STRING; a_index: INTEGER): STRING
|
||||||
|
require
|
||||||
|
valid_index: a_index <= a_uri.count
|
||||||
|
local
|
||||||
|
i,n,p: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := a_index
|
||||||
|
n := a_uri.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
inspect a_uri[i]
|
||||||
|
when '/', '?' then
|
||||||
|
i := n
|
||||||
|
else
|
||||||
|
p := i
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
Result := a_uri.substring (a_index, p)
|
||||||
|
end
|
||||||
|
|
||||||
|
comma_separated_variable_names (s: STRING): LIST [STRING]
|
||||||
|
do
|
||||||
|
Result := s.split (',')
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
286
library/protocol/uri_template/src/uri_template_expression.e
Normal file
286
library/protocol/uri_template/src/uri_template_expression.e
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_EXPRESSION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_EXPRESSION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_position: INTEGER; a_expression: STRING; a_is_query: BOOLEAN)
|
||||||
|
do
|
||||||
|
position := a_position
|
||||||
|
expression := a_expression
|
||||||
|
is_query := a_is_query
|
||||||
|
operator := '%U'
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Processing
|
||||||
|
|
||||||
|
analyze
|
||||||
|
local
|
||||||
|
exp: like expression
|
||||||
|
s: detachable STRING
|
||||||
|
lst: LIST [STRING]
|
||||||
|
p: INTEGER
|
||||||
|
vars: like variables
|
||||||
|
vn: STRING
|
||||||
|
vmodifier: detachable STRING
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
if not is_analyzed then
|
||||||
|
exp := expression
|
||||||
|
if not exp.is_empty then
|
||||||
|
op_prefix := '%U'
|
||||||
|
op_delimiter := ','
|
||||||
|
inspect exp[1]
|
||||||
|
when '+' then
|
||||||
|
reserved := True
|
||||||
|
operator := '+'
|
||||||
|
when '.' then
|
||||||
|
operator := '.'
|
||||||
|
op_prefix := '.'
|
||||||
|
op_delimiter := '.'
|
||||||
|
when '/' then
|
||||||
|
operator := '/'
|
||||||
|
op_prefix := '/'
|
||||||
|
op_delimiter := '/'
|
||||||
|
when ';' then
|
||||||
|
operator := ';'
|
||||||
|
op_prefix := ';'
|
||||||
|
op_delimiter := ';'
|
||||||
|
when '?' then
|
||||||
|
operator := '?'
|
||||||
|
op_prefix := '?'
|
||||||
|
op_delimiter := '&'
|
||||||
|
when '|', '!', '@' then
|
||||||
|
operator := exp[1]
|
||||||
|
else
|
||||||
|
operator := '%U'
|
||||||
|
end
|
||||||
|
if operator /= '%U' then
|
||||||
|
s := exp.substring (2, exp.count)
|
||||||
|
else
|
||||||
|
s := exp
|
||||||
|
end
|
||||||
|
|
||||||
|
lst := s.split (',')
|
||||||
|
from
|
||||||
|
create {ARRAYED_LIST [like variables.item]} vars.make (lst.count)
|
||||||
|
lst.start
|
||||||
|
until
|
||||||
|
lst.after
|
||||||
|
loop
|
||||||
|
s := lst.item
|
||||||
|
vmodifier := Void
|
||||||
|
p := s.index_of ('|', 1)
|
||||||
|
if p > 0 then
|
||||||
|
vn := s.substring (1, p - 1)
|
||||||
|
s := s.substring (p + 1, s.count)
|
||||||
|
else
|
||||||
|
vn := s
|
||||||
|
s := Void
|
||||||
|
end
|
||||||
|
from
|
||||||
|
vmodifier := Void
|
||||||
|
i := 1
|
||||||
|
n := vn.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
inspect vn[i]
|
||||||
|
when '*', '+', ':', '^' then
|
||||||
|
vmodifier := vn.substring (i, n)
|
||||||
|
vn := vn.substring (1, i - 1)
|
||||||
|
i := n + 1 --| exit
|
||||||
|
else
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vars.force (create {URI_TEMPLATE_EXPRESSION_VARIABLE}.make (operator, vn, s, vmodifier))
|
||||||
|
lst.forth
|
||||||
|
end
|
||||||
|
variables := vars
|
||||||
|
end
|
||||||
|
is_analyzed := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
position: INTEGER
|
||||||
|
|
||||||
|
expression: STRING
|
||||||
|
|
||||||
|
is_query: BOOLEAN
|
||||||
|
|
||||||
|
feature -- Status
|
||||||
|
|
||||||
|
operator: CHARACTER
|
||||||
|
|
||||||
|
has_operator: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := operator /= '%U'
|
||||||
|
end
|
||||||
|
|
||||||
|
reserved: BOOLEAN
|
||||||
|
|
||||||
|
has_op_prefix: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := op_prefix /= '%U'
|
||||||
|
end
|
||||||
|
|
||||||
|
op_prefix: CHARACTER
|
||||||
|
|
||||||
|
op_delimiter: CHARACTER
|
||||||
|
|
||||||
|
variables: detachable LIST [URI_TEMPLATE_EXPRESSION_VARIABLE]
|
||||||
|
|
||||||
|
variable_names: LIST [STRING]
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached variables as vars then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (vars.count)
|
||||||
|
from
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
vars.after
|
||||||
|
loop
|
||||||
|
Result.force (vars.item.name)
|
||||||
|
vars.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
is_analyzed: BOOLEAN
|
||||||
|
|
||||||
|
feature -- Report
|
||||||
|
|
||||||
|
append_to_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_buffer: STRING)
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached variables as vars then
|
||||||
|
append_custom_variables_to_string (a_ht, vars, op_prefix, op_delimiter, True, a_buffer)
|
||||||
|
-- inspect operator
|
||||||
|
-- when '?' then
|
||||||
|
-- append_custom_variables_to_string (a_ht, vars, '?', '&', True, a_buffer)
|
||||||
|
-- when ';' then
|
||||||
|
-- append_custom_variables_to_string (a_ht, vars, ';', ';', False, a_buffer)
|
||||||
|
-- when '.' then
|
||||||
|
-- append_custom_variables_to_string (a_ht, vars, '.', ',', True, a_buffer)
|
||||||
|
-- when '/' then
|
||||||
|
-- append_custom_variables_to_string (a_ht, vars, '/', '/', True, a_buffer)
|
||||||
|
-- else
|
||||||
|
-- append_custom_variables_to_string (a_ht, vars, '%U', ',', False, a_buffer)
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
url_encoded_string (s: READABLE_STRING_GENERAL; a_encoded: BOOLEAN): STRING
|
||||||
|
do
|
||||||
|
if a_encoded then
|
||||||
|
Result := url_encoder.encoded_string (s.as_string_32)
|
||||||
|
else
|
||||||
|
Result := url_encoder.partial_encoded_string (s.as_string_32, <<
|
||||||
|
':', ',',
|
||||||
|
'+', '.', '/', ';', '?',
|
||||||
|
'|', '!', '@'
|
||||||
|
>>)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
url_encoder: URL_ENCODER
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
end
|
||||||
|
|
||||||
|
append_custom_variables_to_string (a_ht: HASH_TABLE [detachable ANY, STRING]; vars: like variables; prefix_char, delimiter_char: CHARACTER; a_include_name: BOOLEAN; a_buffer: STRING)
|
||||||
|
-- If `first_char' is '%U' do not print any first character
|
||||||
|
local
|
||||||
|
vi: like variables.item
|
||||||
|
l_is_first: BOOLEAN
|
||||||
|
vdata: detachable ANY
|
||||||
|
vstr: detachable STRING
|
||||||
|
l_use_default: BOOLEAN
|
||||||
|
do
|
||||||
|
if vars /= Void then
|
||||||
|
from
|
||||||
|
vars.start
|
||||||
|
l_is_first := True
|
||||||
|
until
|
||||||
|
vars.after
|
||||||
|
loop
|
||||||
|
vi := vars.item
|
||||||
|
vdata := a_ht.item (vi.name)
|
||||||
|
vstr := Void
|
||||||
|
if vdata /= Void then
|
||||||
|
vstr := vi.string (vdata)
|
||||||
|
if vstr = Void and vi.has_explode_modifier then
|
||||||
|
--| Missing or list empty
|
||||||
|
vstr := vi.default_value
|
||||||
|
l_use_default := True
|
||||||
|
else
|
||||||
|
l_use_default := False
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--| Missing
|
||||||
|
vstr := vi.default_value
|
||||||
|
l_use_default := True
|
||||||
|
end
|
||||||
|
if vstr /= Void then
|
||||||
|
if l_is_first then
|
||||||
|
if prefix_char /= '%U' then
|
||||||
|
a_buffer.append_character (prefix_char)
|
||||||
|
end
|
||||||
|
l_is_first := False
|
||||||
|
else
|
||||||
|
a_buffer.append_character (delimiter_char)
|
||||||
|
end
|
||||||
|
if l_use_default and (operator = '?') and not vi.has_explode_modifier_star then
|
||||||
|
a_buffer.append (vi.name)
|
||||||
|
if vi.has_explode_modifier_plus then
|
||||||
|
a_buffer.append_character ('.')
|
||||||
|
else
|
||||||
|
a_buffer.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
a_buffer.append (vstr)
|
||||||
|
end
|
||||||
|
vars.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
debug_output: STRING
|
||||||
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
|
do
|
||||||
|
Result := expression
|
||||||
|
end
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,398 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_EXPRESSION_VARIABLE}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_EXPRESSION_VARIABLE
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (op: like operator; n: like name; d: like default_value; m: like modifier)
|
||||||
|
do
|
||||||
|
operator := op
|
||||||
|
name := n
|
||||||
|
default_value := d
|
||||||
|
modifier := m
|
||||||
|
|
||||||
|
|
||||||
|
op_prefix := '%U'
|
||||||
|
op_separator := ','
|
||||||
|
|
||||||
|
inspect op
|
||||||
|
when '+' then
|
||||||
|
reserved := True
|
||||||
|
when '?' then
|
||||||
|
op_prefix := '?'
|
||||||
|
op_separator := '&'
|
||||||
|
when ';' then
|
||||||
|
op_prefix := ';'
|
||||||
|
op_separator := ';'
|
||||||
|
when '/' then
|
||||||
|
op_prefix := '/'
|
||||||
|
op_separator := '/'
|
||||||
|
when '.' then
|
||||||
|
op_prefix := '.'
|
||||||
|
op_separator := '.'
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
operator: CHARACTER
|
||||||
|
|
||||||
|
name: STRING
|
||||||
|
|
||||||
|
default_value: detachable STRING
|
||||||
|
|
||||||
|
reserved: BOOLEAN
|
||||||
|
|
||||||
|
op_prefix: CHARACTER
|
||||||
|
|
||||||
|
op_separator: CHARACTER
|
||||||
|
|
||||||
|
modifier: detachable STRING
|
||||||
|
|
||||||
|
has_modifier: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := modifier /= Void
|
||||||
|
end
|
||||||
|
|
||||||
|
modified (s: READABLE_STRING_GENERAL): READABLE_STRING_GENERAL
|
||||||
|
local
|
||||||
|
t: STRING
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
Result := s
|
||||||
|
if attached modifier as m and then m.count > 1 and then m[1] = ':' then
|
||||||
|
n := s.count
|
||||||
|
t := m.substring (2, m.count)
|
||||||
|
if t.is_integer then
|
||||||
|
i := t.to_integer
|
||||||
|
if i > 0 then
|
||||||
|
if i < n then
|
||||||
|
Result := s.substring (1, i)
|
||||||
|
end
|
||||||
|
elseif i < 0 then
|
||||||
|
Result := s.substring (n - i, n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode_modifier: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := attached modifier as m and then m.count = 1 and then (
|
||||||
|
m[1] = '+' or m[1] = '*'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode_modifier_plus: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := attached modifier as m and then m.count = 1 and then
|
||||||
|
m[1] = '+'
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode_modifier_star: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := attached modifier as m and then m.count = 1 and then
|
||||||
|
m[1] = '*'
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Report
|
||||||
|
|
||||||
|
string (d: detachable ANY): detachable STRING
|
||||||
|
local
|
||||||
|
l_delimiter: CHARACTER
|
||||||
|
v_enc: detachable STRING
|
||||||
|
k_enc: STRING
|
||||||
|
l_obj: detachable ANY
|
||||||
|
i,n: INTEGER
|
||||||
|
modifier_is_plus: BOOLEAN
|
||||||
|
modifier_is_star: BOOLEAN
|
||||||
|
modifier_has_explode: BOOLEAN
|
||||||
|
dft: detachable ANY
|
||||||
|
has_list_op: BOOLEAN
|
||||||
|
do
|
||||||
|
modifier_has_explode := has_explode_modifier
|
||||||
|
if modifier_has_explode then
|
||||||
|
modifier_is_plus := has_explode_modifier_plus
|
||||||
|
modifier_is_star := has_explode_modifier_star
|
||||||
|
end
|
||||||
|
has_list_op := operator /= '%U' and operator /= '+'
|
||||||
|
dft := default_value
|
||||||
|
create Result.make (20)
|
||||||
|
if attached {READABLE_STRING_GENERAL} d as l_string then
|
||||||
|
v_enc := url_encoded_string (modified (l_string), not reserved)
|
||||||
|
if operator = '?' then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
elseif operator = ';' then
|
||||||
|
Result.append (name)
|
||||||
|
if not v_enc.is_empty then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
elseif attached {ARRAY [detachable ANY]} d as l_array then
|
||||||
|
if l_array.is_empty then
|
||||||
|
if dft /= Void then
|
||||||
|
inspect operator
|
||||||
|
when '?',';' then
|
||||||
|
if not modifier_has_explode then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
Result.append (dft.out)
|
||||||
|
else
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
when '/' then
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
when '.' then
|
||||||
|
else
|
||||||
|
if modifier_has_explode then
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- nothing ...
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if modifier_has_explode then
|
||||||
|
l_delimiter := op_separator
|
||||||
|
else
|
||||||
|
l_delimiter := ','
|
||||||
|
inspect operator
|
||||||
|
when '?' then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
when ';' then
|
||||||
|
when '/' then
|
||||||
|
-- Result.append_character ('/')
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
from
|
||||||
|
i := l_array.lower
|
||||||
|
n := l_array.upper
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
l_obj := l_array[i]
|
||||||
|
if l_obj /= Void then
|
||||||
|
v_enc := url_encoded_string (l_obj.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := ""
|
||||||
|
end
|
||||||
|
if modifier_is_plus then
|
||||||
|
if
|
||||||
|
(operator = '?' and modifier_is_plus) or
|
||||||
|
(operator = ';' and modifier_has_explode)
|
||||||
|
then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
elseif modifier_is_star and operator = '?' then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
if i < n then
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Result.is_empty then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
elseif attached {HASH_TABLE [detachable ANY, STRING]} d as l_table then
|
||||||
|
-- if operator = '?' and not modifier_has_explode and l_table.is_empty and dft = Void then
|
||||||
|
-- elseif operator = '?' and not modifier_has_explode then
|
||||||
|
-- Result.append (name)
|
||||||
|
-- Result.append_character ('=')
|
||||||
|
-- if l_table.is_empty and dft /= Void then
|
||||||
|
-- Result.append (dft.out)
|
||||||
|
-- end
|
||||||
|
-- elseif l_table.is_empty and dft /= Void then
|
||||||
|
-- if modifier_has_explode then
|
||||||
|
-- if modifier_is_plus then
|
||||||
|
-- Result.append (name)
|
||||||
|
-- Result.append_character ('.')
|
||||||
|
-- end
|
||||||
|
-- Result.append (dft.out)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
if l_table.is_empty then
|
||||||
|
if dft /= Void then
|
||||||
|
inspect operator
|
||||||
|
when '?',';' then
|
||||||
|
if not modifier_has_explode then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
Result.append (dft.out)
|
||||||
|
else
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
when '/' then
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
when '.' then
|
||||||
|
else
|
||||||
|
if modifier_has_explode then
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- nothing ...
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if modifier_has_explode then
|
||||||
|
l_delimiter := op_separator
|
||||||
|
else
|
||||||
|
l_delimiter := ','
|
||||||
|
inspect operator
|
||||||
|
when '?' then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
when ';' then
|
||||||
|
when '/' then
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
from
|
||||||
|
l_table.start
|
||||||
|
until
|
||||||
|
l_table.after
|
||||||
|
loop
|
||||||
|
k_enc := url_encoded_string (l_table.key_for_iteration, not reserved)
|
||||||
|
l_obj := l_table.item_for_iteration
|
||||||
|
if l_obj /= Void then
|
||||||
|
v_enc := url_encoded_string (l_obj.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if modifier_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
if
|
||||||
|
modifier_has_explode and
|
||||||
|
(
|
||||||
|
operator = '%U' or
|
||||||
|
operator = '+' or
|
||||||
|
operator = '?' or
|
||||||
|
operator = '.' or
|
||||||
|
operator = ';' or
|
||||||
|
operator = '/'
|
||||||
|
)
|
||||||
|
then
|
||||||
|
Result.append (k_enc)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
Result.append (k_enc)
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
|
||||||
|
l_table.forth
|
||||||
|
if not l_table.after then
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Result.is_empty then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if d /= Void then
|
||||||
|
v_enc := url_encoded_string (d.out, not reserved)
|
||||||
|
elseif dft /= Void then
|
||||||
|
v_enc := url_encoded_string (dft.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := default_value
|
||||||
|
end
|
||||||
|
if operator = '?' then
|
||||||
|
Result.append (name)
|
||||||
|
if v_enc /= Void then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
elseif operator = ';' then
|
||||||
|
Result.append (name)
|
||||||
|
if v_enc /= Void and then not v_enc.is_empty then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if v_enc /= Void then
|
||||||
|
Result.append (v_enc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
url_encoded_string (s: READABLE_STRING_GENERAL; a_encoded: BOOLEAN): STRING
|
||||||
|
do
|
||||||
|
if a_encoded then
|
||||||
|
Result := url_encoder.encoded_string (s.as_string_32)
|
||||||
|
else
|
||||||
|
Result := url_encoder.partial_encoded_string (s.as_string_32, <<
|
||||||
|
':', ',',
|
||||||
|
'+', '.', '/', ';', '?',
|
||||||
|
'|', '!', '@'
|
||||||
|
>>)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
url_encoder: URL_ENCODER
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
end
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
25
library/protocol/uri_template/src/uri_template_handler.e
Normal file
25
library/protocol/uri_template/src/uri_template_handler.e
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
URI_TEMPLATE_HANDLER
|
||||||
|
|
||||||
|
feature -- Events
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
616
library/protocol/uri_template/tests/test_uri_template.e
Normal file
616
library/protocol/uri_template/tests/test_uri_template.e
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Eiffel tests that can be executed by testing tool.
|
||||||
|
]"
|
||||||
|
author: "EiffelStudio test wizard"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
testing: "type/manual"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_URI_TEMPLATE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
|
||||||
|
feature -- Test routines
|
||||||
|
|
||||||
|
test_uri_template_parser
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
do
|
||||||
|
uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>)
|
||||||
|
uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test_uri_template_matcher
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
do
|
||||||
|
create tpl.make ("api/foo/{foo_id}/{?id,extra}")
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>)
|
||||||
|
|
||||||
|
create tpl.make ("weather/{state}/{city}?forecast={day}")
|
||||||
|
uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string_errors: detachable LIST [STRING]
|
||||||
|
|
||||||
|
test_uri_template_string_builder
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
|
||||||
|
--| Simple string expansion
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "O{empty}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef}X", "OX")
|
||||||
|
|
||||||
|
--| String expansion with defaults
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "O{empty|default}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef|default}X", "OdefaultX")
|
||||||
|
|
||||||
|
--| Reserved expansion with defaults
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar")
|
||||||
|
uri_template_string (ht, "up{+path}{x}/here", "up/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "up{+empty|/1}/here", "up/here")
|
||||||
|
uri_template_string (ht, "up{+undef|/1}/here", "up/1/here")
|
||||||
|
|
||||||
|
--| String expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{x,hello,y}", "1024,Hello+World%%21,768")
|
||||||
|
uri_template_string (ht, "?{x,empty}", "?1024,")
|
||||||
|
uri_template_string (ht, "?{x,undef}", "?1024")
|
||||||
|
uri_template_string (ht, "?{undef,y}", "?768")
|
||||||
|
uri_template_string (ht, "?{x,undef|0}", "?1024,0")
|
||||||
|
|
||||||
|
--| Reserved expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{+x,hello,y}", "1024,Hello+World!,768")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
|
||||||
|
|
||||||
|
ht.force (colors, "list")
|
||||||
|
ht.force (semi_dot, "keys")
|
||||||
|
--| String expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{var:3}", "val")
|
||||||
|
uri_template_string (ht, "{var:30}", "value")
|
||||||
|
uri_template_string (ht, "{list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{keys}", "semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{keys*}", "semi=%%3B,dot=.,comma=%%2C")
|
||||||
|
--| Reserved expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{+path:6}/here", "/foo/b/here")
|
||||||
|
uri_template_string (ht, "{+list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+keys}", "semi,;,dot,.,comma,,")
|
||||||
|
uri_template_string (ht, "{+keys*}", "semi=;,dot=.,comma=,")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var:3}", "X.val")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.red,green,blue")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.red.green.blue")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.semi=%%3B.dot=..comma=%%2C")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var:1,var}", "/v/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/red,green,blue")
|
||||||
|
uri_template_string (ht, "{/list*}", "/red/green/blue")
|
||||||
|
uri_template_string (ht, "{/list*,path:4}", "/red/green/blue/%%2Ffoo")
|
||||||
|
uri_template_string (ht, "{/keys}", "/semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/semi=%%3B/dot=./comma=%%2C")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;hello:5}", ";hello=Hello")
|
||||||
|
uri_template_string (ht, "{;list}", ";red,green,blue")
|
||||||
|
uri_template_string (ht, "{;list*}", ";red;green;blue")
|
||||||
|
uri_template_string (ht, "{;keys}", ";semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";semi=%%3B;dot=.;comma=%%2C")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?var:3}", "?var=val")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=red,green,blue")
|
||||||
|
uri_template_string (ht, "{?list*}", "?list=red&list=green&list=blue")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?semi=%%3B&dot=.&comma=%%2C")
|
||||||
|
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_uri_template_string_builder_extra
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
--| Addition to the spec
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,empty,undef,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&empty=&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "weather/{state}/{city}?forecast={day}",
|
||||||
|
"weather/California/Goleta?forecast=today")
|
||||||
|
|
||||||
|
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "{undef|default}", "default")
|
||||||
|
uri_template_string (ht, "{undef:3|default}", "default")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef|_}y", "x_y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{.name|none}", "x.Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{.name*|none}", "x.Fred.Wilma.Pebbles")
|
||||||
|
uri_template_string (ht, "x{.empty}", "x.")
|
||||||
|
uri_template_string (ht, "x{.empty|none}", "x.")
|
||||||
|
uri_template_string (ht, "x{.undef}", "x")
|
||||||
|
uri_template_string (ht, "x{.undef|none}", "x.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty|none}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*|none}", "x/none")
|
||||||
|
|
||||||
|
-- uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
-- uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty|none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
uri_template_string (ht, "x{;undef|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;undef|foo=y}", "x;foo=y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?var|none}", "x?var=value")
|
||||||
|
uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty|foo=none}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
-- uri_template_string (ht, "x{?undef|foo=none}", "x?foo=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
-- uri_template_string (ht, "x{?empty_keys|none}", "x?none")
|
||||||
|
-- uri_template_string (ht, "x{?empty_keys|y=z}", "x?y=z")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*|y=z}", "x?y=z")
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_list}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*|_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_list+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list+|_}y", "xempty_list._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_keys}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*|_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_keys+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys+|_}y", "xempty_keys._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?name|none}", "x?name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?favs+|none}", "x?favs.color=red&favs.volume=high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
uri_template_string (ht, "x{?undef|none}", "x?undef=none")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty|none}", "x?empty=")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list|none}", "x?empty_list=none")
|
||||||
|
uri_template_string (ht, "x{?empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list*|none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list+|none}", "x?empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys|none}", "x?empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*|none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+|none}", "x?empty_keys.none")
|
||||||
|
|
||||||
|
-- uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
-- uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs|none}", "x;color,red,volume,high") -- DIFF
|
||||||
|
uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;favs+|none}", "x;favs.color=red;favs.volume=high")
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
-- uri_template_string (ht, "x{;undef|none}", "x;undef=none")
|
||||||
|
uri_template_string (ht, "x{;undef|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty|none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list|none}", "x;empty_list=none")
|
||||||
|
uri_template_string (ht, "x{;empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list*|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list+|none}", "x;empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys|none}", "x;empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+|none}", "x;empty_keys.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name+|none}", "x/name.Fred/name.Wilma/name.Pebbles")
|
||||||
|
uri_template_string (ht, "x{/favs|none}", "x/color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{/favs*|none}", "x/color/red/volume/high")
|
||||||
|
uri_template_string (ht, "x{/favs+|none}", "x/favs.color/red/favs.volume/high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty|none}", "x/")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list*|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list+|none}", "x/empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+|none}", "x/empty_keys.none")
|
||||||
|
|
||||||
|
--| Simple expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "{path}/here", "%%2Ffoo%%2Fbar/here")
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "{undef|default}", "default")
|
||||||
|
uri_template_string (ht, "{list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Reserved expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
uri_template_string (ht, "{+path}{x}/here", "/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "{+empty}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+undef}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{+keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
-- uri_template_string (ht, "{;list}", ";val1,val2,val3") -- DIFF
|
||||||
|
uri_template_string (ht, "{;list}", ";list=val1,val2,val3") -- DIFF
|
||||||
|
uri_template_string (ht, "{;list*}", ";val1;val2;val3")
|
||||||
|
uri_template_string (ht, "{;list+}", ";list=val1;list=val2;list=val3")
|
||||||
|
uri_template_string (ht, "{;keys}", ";key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";key1=val1;key2=val2")
|
||||||
|
uri_template_string (ht, "{;keys+}", ";keys.key1=val1;keys.key2=val2")
|
||||||
|
|
||||||
|
--| Form-style parameters, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{?list*}", "?val1&val2&val3")
|
||||||
|
uri_template_string (ht, "{?list+}", "?list=val1&list=val2&list=val3")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?key1=val1&key2=val2")
|
||||||
|
uri_template_string (ht, "{?keys+}", "?keys.key1=val1&keys.key2=val2")
|
||||||
|
|
||||||
|
--| Hierarchical path segments, slash-separated
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{/list*}", "/val1/val2/val3")
|
||||||
|
uri_template_string (ht, "{/list*,x}", "/val1/val2/val3/1024")
|
||||||
|
uri_template_string (ht, "{/list+}", "/list.val1/list.val2/list.val3")
|
||||||
|
uri_template_string (ht, "{/keys}", "/key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/key1/val1/key2/val2")
|
||||||
|
uri_template_string (ht, "{/keys+}", "/keys.key1/val1/keys.key2/val2")
|
||||||
|
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.val1,val2,val3")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.val1.val2.val3")
|
||||||
|
uri_template_string (ht, "X{.list*,x}", "X.val1.val2.val3.1024")
|
||||||
|
uri_template_string (ht, "X{.list+}", "X.list.val1.list.val2.list.val3")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.key1.val1.key2.val2")
|
||||||
|
uri_template_string (ht, "X{.keys+}", "X.keys.key1.val1.keys.key2.val2")
|
||||||
|
|
||||||
|
--| Simple Expansion
|
||||||
|
uri_template_string (ht, "{foo}", "fred")
|
||||||
|
uri_template_string (ht, "{foo,foo}", "fred,fred")
|
||||||
|
uri_template_string (ht, "{bar,foo}", "fred")
|
||||||
|
uri_template_string (ht, "{bar|wilma}", "wilma")
|
||||||
|
|
||||||
|
--| Reserved Expansion
|
||||||
|
uri_template_string (ht, "{foo2}", "That%%27s+right%%21")
|
||||||
|
uri_template_string (ht, "{+foo2}", "That%%27s+right!")
|
||||||
|
uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex")
|
||||||
|
uri_template_string (ht, "{+base}index", "http://example.com/home/index")
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: STRING)
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
s: STRING
|
||||||
|
m: STRING
|
||||||
|
do
|
||||||
|
create tpl.make (a_expression)
|
||||||
|
s := tpl.string (a_ht)
|
||||||
|
if not s.same_string (a_expected) then
|
||||||
|
m := "Expected string for %"" + a_expression + "%" expected=%""+ a_expected +"%" but got %"" + s + "%"%N"
|
||||||
|
if attached uri_template_string_errors as err then
|
||||||
|
print (m)
|
||||||
|
err.force (m)
|
||||||
|
else
|
||||||
|
assert (m, False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING])
|
||||||
|
local
|
||||||
|
u: URI_TEMPLATE
|
||||||
|
matched: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
do
|
||||||
|
create u.make (s)
|
||||||
|
if attached u.path_variable_names as vars then
|
||||||
|
matched := vars.count = path_vars.count
|
||||||
|
from
|
||||||
|
i := path_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > path_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (path_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := path_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("path variables matched", matched)
|
||||||
|
|
||||||
|
if attached u.query_variable_names as vars then
|
||||||
|
matched := vars.count = query_vars.count
|
||||||
|
from
|
||||||
|
i := query_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > query_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (query_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := query_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("query variables matched", matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]])
|
||||||
|
local
|
||||||
|
b: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
do
|
||||||
|
if attached a_uri_template.match (a_uri) as l_match then
|
||||||
|
if attached l_match.path_variables as path_ht then
|
||||||
|
b := path_ht.count = path_res.count
|
||||||
|
from
|
||||||
|
i := path_res.lower
|
||||||
|
until
|
||||||
|
not b or i > path_res.upper
|
||||||
|
loop
|
||||||
|
b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri matched path variables", b)
|
||||||
|
end
|
||||||
|
if attached l_match.query_variables as query_ht then
|
||||||
|
b := query_ht.count = query_res.count
|
||||||
|
from
|
||||||
|
i := query_res.lower
|
||||||
|
until
|
||||||
|
not b or i > query_res.upper
|
||||||
|
loop
|
||||||
|
b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri matched query variables", b)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
assert ("uri matched", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
32
library/protocol/uri_template/uri_template-safe.ecf
Normal file
32
library/protocol/uri_template/uri_template-safe.ecf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="uri_template" uuid="64B64199-7F12-4A33-A962-4AD314E9593D" library_target="uri_template">
|
||||||
|
<target name="uri_template">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="tests" extends="uri_template">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="console_application" value="false"/>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
|
<tests name="tests" location=".\tests\"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
18
library/protocol/uri_template/uri_template.ecf
Normal file
18
library/protocol/uri_template/uri_template.ecf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="uri_template" uuid="64B64199-7F12-4A33-A962-4AD314E9593D" library_target="uri_template">
|
||||||
|
<target name="uri_template">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
|
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {URL_ENCODER}."
|
description: "[
|
||||||
|
Summary description for {URL_ENCODER}.
|
||||||
|
|
||||||
|
See: http://www.faqs.org/rfcs/rfc3986.html
|
||||||
|
]"
|
||||||
legal: "See notice at end of class."
|
legal: "See notice at end of class."
|
||||||
status: "See notice at end of class."
|
status: "See notice at end of class."
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
@@ -59,6 +63,47 @@ feature -- Encoder
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
partial_encoded_string (s: STRING_32; a_ignore: ARRAY [CHARACTER]): STRING_8
|
||||||
|
-- URL-encoded value of `s'.
|
||||||
|
local
|
||||||
|
i, n: INTEGER
|
||||||
|
uc: CHARACTER_32
|
||||||
|
c: CHARACTER_8
|
||||||
|
do
|
||||||
|
has_error := False
|
||||||
|
create Result.make (s.count + s.count // 10)
|
||||||
|
n := s.count
|
||||||
|
from i := 1 until i > n loop
|
||||||
|
uc := s.item (i)
|
||||||
|
if uc.is_character_8 then
|
||||||
|
c := uc.to_character_8
|
||||||
|
inspect c
|
||||||
|
when
|
||||||
|
'A' .. 'Z',
|
||||||
|
'a' .. 'z', '0' .. '9',
|
||||||
|
'.', '-', '~', '_'
|
||||||
|
then
|
||||||
|
Result.extend (c)
|
||||||
|
when ' ' then
|
||||||
|
Result.extend ('+')
|
||||||
|
else
|
||||||
|
if a_ignore.has (c) then
|
||||||
|
Result.extend (c)
|
||||||
|
else
|
||||||
|
Result.append (url_encoded_char (uc))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if a_ignore.has (c) then
|
||||||
|
Result.extend (c)
|
||||||
|
else
|
||||||
|
Result.append (url_encoded_char (uc))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature {NONE} -- encoder character
|
feature {NONE} -- encoder character
|
||||||
|
|
||||||
url_encoded_char (uc: CHARACTER_32): STRING_8
|
url_encoded_char (uc: CHARACTER_32): STRING_8
|
||||||
@@ -309,7 +354,7 @@ feature {NONE} -- Hexadecimal and strings
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
Reference in New Issue
Block a user