Skip to content

Commit

Permalink
Readme updates, fix for bogus values
Browse files Browse the repository at this point in the history
  • Loading branch information
therabidbanana committed May 18, 2012
1 parent 1f77da2 commit 242f326
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 11 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ support for URI templates.

- {Addressable::URI}
- {Addressable::Template}
- {Addressable::UriTemplate}

# Example usage

Expand Down Expand Up @@ -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",
Expand Down
58 changes: 51 additions & 7 deletions lib/addressable/uri_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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|
Expand Down Expand Up @@ -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, ',')
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
29 changes: 25 additions & 4 deletions spec/addressable/uri_template_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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{
Expand All @@ -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
Expand Down Expand Up @@ -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"]
Expand Down

0 comments on commit 242f326

Please sign in to comment.