Permalink
Browse files

Readme updates, fix for bogus values

  • Loading branch information...
1 parent 1f77da2 commit 242f326431ace1b409a48de3b6a0722ecff5fc2e @therabidbanana therabidbanana committed May 18, 2012
Showing with 81 additions and 11 deletions.
  1. +5 −0 README.md
  2. +51 −7 lib/addressable/uri_template.rb
  3. +25 −4 spec/addressable/uri_template_spec.rb
View
@@ -21,6 +21,7 @@ support for URI templates.
- {Addressable::URI}
- {Addressable::Template}
+- {Addressable::UriTemplate}
# Example usage
@@ -55,10 +56,14 @@ support for URI templates.
template = Addressable::Template.new(
"http://{host}/{-suffix|/|segments}?{-join|&|one,two,bogus}\#{fragment}"
)
+ template2 = Addressable::UriTemplate.new(
+ "http://{host}{/segments}/{?one,two,bogus}{#fragment}"
+ )
uri = Addressable::URI.parse(
"http://example.com/a/b/c/?one=1&two=2#foo"
)
template.extract(uri)
+ template2.extract(uri)
#=>
# {
# "host" => "example.com",
@@ -151,7 +151,7 @@ def match(uri, processor=nil)
unparsed_value = unparsed_values[index]
name = varspec[VARSPEC, 1]
value = unparsed_value
- value = value.split(JOINERS[operator]) if modifier == ?*
+ value = value.split(JOINERS[operator]) if value && modifier == ?*
when ?;, ??, ?&
if modifier == ?*
value = unparsed_values[index].split(JOINERS[operator])
@@ -162,8 +162,10 @@ def match(uri, processor=nil)
acc
end
else
- name, value = unparsed_values[index].split('=')
- value = "" if value.nil?
+ if (unparsed_values[index])
+ name, value = unparsed_values[index].split('=')
+ value = "" if value.nil?
+ end
end
end
if processor != nil && processor.respond_to?(:restore)
@@ -320,6 +322,29 @@ def ordered_variable_defaults
end
+ ##
+ # Loops through each capture and expands any values available in mapping
+ #
+ # @param [Hash] mapping
+ # Set of keys to expand
+ # @param [String] capture
+ # The expression to expand
+ # @param [#validate, #transform] processor
+ # An optional processor object may be supplied.
+ #
+ # The object should respond to either the <tt>validate</tt> or
+ # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
+ # <tt>transform</tt> methods should take two parameters: <tt>name</tt> and
+ # <tt>value</tt>. The <tt>validate</tt> method should return <tt>true</tt>
+ # or <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
+ # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt> exception
+ # will be raised if the value is invalid. The <tt>transform</tt> method
+ # should return the transformed variable value as a <tt>String</tt>. If a
+ # <tt>transform</tt> method is used, the value will not be percent encoded
+ # automatically. Unicode normalization will be performed both before and
+ # after sending the value to the transform method.
+ #
+ # @return [String] The expanded expression
def transform_partial_capture(mapping, capture, processor = nil)
_, operator, varlist = *capture.match(EXPRESSION)
is_first = true
@@ -360,7 +385,7 @@ def transform_partial_capture(mapping, capture, processor = nil)
# automatically. Unicode normalization will be performed both before and
# after sending the value to the transform method.
#
- # @return [Object] The transformed mapped value
+ # @return [String] The expanded expression
def transform_capture(mapping, capture, processor=nil)
_, operator, varlist = *capture.match(EXPRESSION)
return_value = varlist.split(',').inject([]) do |acc, varspec|
@@ -451,6 +476,17 @@ def transform_capture(mapping, capture, processor=nil)
join_values(operator, return_value)
end
+ ##
+ # Takes a set of values, and joins them together based on the
+ # operator.
+ #
+ # @param [String, Nil] operator One of the operators from the set
+ # (?,&,+,#,;,/,.), or nil if there wasn't one.
+ # @param [Array] return_value
+ # The set of return values (as [variable_name, value] tuples) that will
+ # be joined together.
+ #
+ # @return [String] The transformed mapped value
def join_values(operator, return_value)
leader = LEADERS.fetch(operator, '')
joiner = JOINERS.fetch(operator, ',')
@@ -480,6 +516,14 @@ def join_values(operator, return_value)
end
end
+ ##
+ # Takes a set of values, and joins them together based on the
+ # operator.
+ #
+ # @param [Hash, Array, String] value
+ # Normalizes keys and values with IDNA#unicode_normalize_kc
+ #
+ # @return [Hash, Array, String] The normalized values
def normalize_value(value)
unless value.is_a?(Hash)
value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str
@@ -575,12 +619,12 @@ def parse_template_pattern(pattern, processor=nil)
"#{ UNRESERVED }*?"
end
if modifier == ?*
- "(#{group}(?:#{joiner}?#{group})*)"
+ "(#{group}(?:#{joiner}?#{group})*)?"
else
- "(#{group})"
+ "(#{group})?"
end
end
- end.join(joiner)
+ end.join("#{joiner}?")
end
# Ensure that the regular expression matches the whole URI.
@@ -436,6 +436,7 @@ def self.transform(name, value)
its(:variables){ should == ["query"]}
its(:captures){ should == ["an example search query"]}
end
+
context "second uri with ExampleTwoProcessor" do
subject{
match = Addressable::UriTemplate.new(
@@ -461,7 +462,8 @@ def self.transform(name, value)
).match(uri3)
}
its(:variables){ should == ["hash", "first"]}
- its(:captures){ should == [{"a" => "1", "b" => "2", "c" => "3"}, "foo"] }
+ its(:captures){ should == [
+ {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
end
context "fourth uri" do
subject{
@@ -470,7 +472,26 @@ def self.transform(name, value)
).match(uri4)
}
its(:variables){ should == ["hash", "first"]}
- its(:captures){ should == [{"a" => "1", "b" => "2", "c" => "3"}, "foo"] }
+ its(:captures){ should == [
+ {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
+ end
+ end
+ describe "extract" do
+ let(:template) {
+ Addressable::UriTemplate.new(
+ "http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
+ )
+ }
+ let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
+ it "should be able to extract" do
+ template.extract(uri).should == {
+ "host" => "example.com",
+ "segments" => %w(a b c),
+ "one" => "1",
+ "bogus" => nil,
+ "two" => "2",
+ "fragment" => "foo"
+ }
end
end
describe "Partial expand" do
@@ -597,8 +618,8 @@ def self.transform(name, value)
subject { Addressable::UriTemplate.new("foo{+foo,bar}baz") }
it "can match" do
data = subject.match("foofoo/bar,barbaz")
- data.mapping["foo"].should == "foo/bar"
- data.mapping["bar"].should == "bar"
+ data.mapping["bar"].should == "foo/bar,bar"
+ data.mapping["foo"].should == ""
end
it "lists vars" do
subject.variables.should == ["foo", "bar"]

0 comments on commit 242f326

Please sign in to comment.