From 23bdb7be7b6057abb462054551bc86a525877ab6 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Tue, 2 Sep 2014 20:04:07 +0900 Subject: [PATCH 1/2] Define a default #to_s in Drop. --- app/concerns/liquid_droppable.rb | 4 +++ spec/concerns/liquid_droppable_spec.rb | 34 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 spec/concerns/liquid_droppable_spec.rb diff --git a/app/concerns/liquid_droppable.rb b/app/concerns/liquid_droppable.rb index 5f11a6c665..ca9a005122 100644 --- a/app/concerns/liquid_droppable.rb +++ b/app/concerns/liquid_droppable.rb @@ -9,6 +9,10 @@ def initialize(object) @object = object end + def to_s + @object.to_s + end + def each (public_instance_methods - Drop.public_instance_methods).each { |name| yield [name, __send__(name)] diff --git a/spec/concerns/liquid_droppable_spec.rb b/spec/concerns/liquid_droppable_spec.rb new file mode 100644 index 0000000000..96d37aaf68 --- /dev/null +++ b/spec/concerns/liquid_droppable_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe LiquidDroppable do + before do + class DroppableTest + include LiquidDroppable + + def initialize(value) + @value = value + end + + attr_reader :value + + def to_s + "[value:#{value}]" + end + end + + class DroppableTestDrop + def value + @object.value + end + end + end + + describe 'test class' do + it 'should be droppable' do + five = DroppableTest.new(5) + five.to_liquid.class.should == DroppableTestDrop + Liquid::Template.parse('{{ x.value | plus:3 }}').render('x' => five).should == '8' + Liquid::Template.parse('{{ x }}').render('x' => five).should == '[value:5]' + end + end +end From ca6de90fc53a41946df48064530c395033c27f22 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Tue, 2 Sep 2014 20:04:35 +0900 Subject: [PATCH 2/2] 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 ca9a005122..5f3edf0995 100644 --- a/app/concerns/liquid_droppable.rb +++ b/app/concerns/liquid_droppable.rb @@ -27,4 +27,20 @@ def each 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 23b375ad50..a1ea866a0b 100644 --- a/app/concerns/liquid_interpolatable.rb +++ b/app/concerns/liquid_interpolatable.rb @@ -116,6 +116,22 @@ def uri_escape(string) 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 338dff3221..320f14f52d 100644 --- a/spec/concerns/liquid_interpolatable_spec.rb +++ b/spec/concerns/liquid_interpolatable_spec.rb @@ -59,4 +59,41 @@ def @filter.to_xpath_roundtrip(string) @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