From ca6de90fc53a41946df48064530c395033c27f22 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Tue, 2 Sep 2014 20:04:35 +0900 Subject: [PATCH] Add a new filter `to_uri`. --- app/concerns/liquid_droppable.rb | 16 +++++++++ app/concerns/liquid_interpolatable.rb | 16 +++++++++ spec/concerns/liquid_interpolatable_spec.rb | 37 +++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/app/concerns/liquid_droppable.rb b/app/concerns/liquid_droppable.rb index ca9a0051..5f3edf09 100644 --- a/app/concerns/liquid_droppable.rb +++ b/app/concerns/liquid_droppable.rb @@ -27,4 +27,20 @@ module LiquidDroppable def to_liquid self.class::Drop.new(self) end + + require 'uri' + + class URIDrop < Drop + URI::Generic::COMPONENT.each { |attr| + define_method(attr) { + @object.__send__(attr) + } + } + end + + class ::URI::Generic + def to_liquid + URIDrop.new(self) + end + end end diff --git a/app/concerns/liquid_interpolatable.rb b/app/concerns/liquid_interpolatable.rb index 23b375ad..a1ea866a 100644 --- a/app/concerns/liquid_interpolatable.rb +++ b/app/concerns/liquid_interpolatable.rb @@ -116,6 +116,22 @@ module LiquidInterpolatable CGI.escape(string) rescue string end + # Parse an input into a URI object, optionally resolving it + # against a base URI if given. + # + # A URI object will have the following properties: scheme, + # userinfo, host, port, registry, path, opaque, query, and + # fragment. + def to_uri(uri, base_uri = nil) + if base_uri + URI(base_uri) + uri.to_s + else + URI(uri.to_s) + end + rescue URI::Error + nil + end + # Escape a string for use in XPath expression def to_xpath(string) subs = string.to_s.scan(/\G(?:\A\z|[^"]+|[^']+)/).map { |x| diff --git a/spec/concerns/liquid_interpolatable_spec.rb b/spec/concerns/liquid_interpolatable_spec.rb index 338dff32..320f14f5 100644 --- a/spec/concerns/liquid_interpolatable_spec.rb +++ b/spec/concerns/liquid_interpolatable_spec.rb @@ -59,4 +59,41 @@ describe LiquidInterpolatable::Filters do @filter.to_xpath_roundtrip(1).should == '1' end end + + describe 'to_uri' do + before do + @agent = Agents::InterpolatableAgent.new(name: "test", options: { 'foo' => '{% assign u = s | to_uri %}{{ u.path }}' }) + @agent.interpolation_context['s'] = 'http://example.com/dir/1?q=test' + end + + it 'should parse an abosule URI' do + @filter.to_uri('http://example.net/index.html', 'http://example.com/dir/1').should == URI('http://example.net/index.html') + end + + it 'should parse an abosule URI with a base URI specified' do + @filter.to_uri('http://example.net/index.html', 'http://example.com/dir/1').should == URI('http://example.net/index.html') + end + + it 'should parse a relative URI with a base URI specified' do + @filter.to_uri('foo/index.html', 'http://example.com/dir/1').should == URI('http://example.com/dir/foo/index.html') + end + + it 'should parse an abosule URI with a base URI specified' do + @filter.to_uri('http://example.net/index.html', 'http://example.com/dir/1').should == URI('http://example.net/index.html') + end + + it 'should stringify a non-string operand' do + @filter.to_uri(123, 'http://example.com/dir/1').should == URI('http://example.com/dir/123') + end + + it 'should return a URI value in interpolation' do + @agent.interpolated['foo'].should == '/dir/1' + end + + it 'should return a URI value resolved against a base URI in interpolation' do + @agent.options['foo'] = '{% assign u = s | to_uri:"http://example.com/dir/1" %}{{ u.path }}' + @agent.interpolation_context['s'] = 'foo/index.html' + @agent.interpolated['foo'].should == '/dir/foo/index.html' + end + end end