Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add absolute_url and relative_url filters. #5399

Merged
merged 3 commits into from
Sep 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/jekyll/filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
require "date"
require "liquid"

require_all "jekyll/filters"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️


module Jekyll
module Filters
include URLFilters
# Convert a Markdown string into HTML output.
#
# input - The Markdown String to convert.
Expand Down
38 changes: 38 additions & 0 deletions lib/jekyll/filters/url_filters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Jekyll
module Filters
module URLFilters
# Produces an absolute URL based on site.url and site.baseurl.
#
# input - the URL to make absolute.
#
# Returns the absolute URL as a String.
def absolute_url(input)
return if input.nil?
site = @context.registers[:site]
return relative_url(input).to_s if site.config["url"].nil?
URI(site.config["url"] + relative_url(input)).to_s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be URI.join here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URI.join causes more problems than it solves. relative_url will always start with a / so this is safe. An example of what it breaks is if site.url = "example.com":

Error:
TestFilters#test_: filters absolute_url filter should be ok with a blank but present 'url'. :
URI::BadURIError: both URI are relative
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/generic.rb:1102:in `rescue in merge'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/generic.rb:1099:in `merge'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/rfc3986_parser.rb:89:in `each'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/rfc3986_parser.rb:89:in `inject'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/rfc3986_parser.rb:89:in `join'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/2.3.0/uri/common.rb:265:in `join'
    /Users/parkr/jekyll/jekyll/lib/jekyll/filters/url_filters.rb:13:in `absolute_url'
    /Users/parkr/jekyll/jekyll/test/test_filters.rb:341:in `block (3 levels) in <class:TestFilters>'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/shoulda-context-1.2.1/lib/shoulda/context/context.rb:413:in `instance_exec'
    /Users/parkr/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/shoulda-context-1.2.1/lib/shoulda/context/context.rb:413:in `block in create_test_from_should_hash'

end

# Produces a URL relative to the domain root based on site.baseurl.
#
# input - the URL to make relative to the domain root
#
# Returns a URL relative to the domain root as a String.
def relative_url(input)
return if input.nil?
site = @context.registers[:site]
return ensure_leading_slash(input.to_s) if site.config["baseurl"].nil?
URI(
ensure_leading_slash(site.config["baseurl"]) + ensure_leading_slash(input.to_s)
).to_s
end

private
def ensure_leading_slash(input)
return input if input.nil? || input.empty? || input.start_with?("/")
"/#{input}"
end

end
end
end
7 changes: 2 additions & 5 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,9 @@ def site_configuration(overrides = {})
"destination" => dest_dir,
"incremental" => false
}))
build_configs({
Configuration.from(full_overrides.merge({
"source" => source_dir
}, full_overrides)
.fix_common_issues
.backwards_compatibilize
.add_default_collections
}))
end

def clear_dest
Expand Down
114 changes: 106 additions & 8 deletions test/test_filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,28 @@ class JekyllFilter
attr_accessor :site, :context

def initialize(opts = {})
@site = Jekyll::Site.new(
Jekyll.configuration(opts.merge("skip_config_files" => true))
)
@site = Jekyll::Site.new(opts.merge("skip_config_files" => true))
@context = Liquid::Context.new({}, {}, { :site => @site })
end
end

def make_filter_mock(opts = {})
JekyllFilter.new(site_configuration(opts)).tap do |f|
tz = f.site.config["timezone"]
Jekyll.set_timezone(tz) if tz
end
end

class SelectDummy
def select; end
end

context "filters" do
setup do
@filter = JekyllFilter.new({
"source" => source_dir,
"destination" => dest_dir,
"timezone" => "UTC"
@filter = make_filter_mock({
"timezone" => "UTC",
"url" => "http://example.com",
"baseurl" => "/base"
})
@sample_time = Time.utc(2013, 3, 27, 11, 22, 33)
@sample_date = Date.parse("2013-03-27")
Expand Down Expand Up @@ -65,7 +70,7 @@ def select; end
end

should "escapes special characters when configured to do so" do
kramdown = JekyllFilter.new({ :kramdown => { :entity_output => :symbolic } })
kramdown = make_filter_mock({ :kramdown => { :entity_output => :symbolic } })
assert_equal(
"&ldquo;This filter&rsquo;s test&hellip;&rdquo;",
kramdown.smartify(%q{"This filter's test..."})
Expand Down Expand Up @@ -307,6 +312,99 @@ def select; end
assert_equal "my%20things", @filter.uri_escape("my things")
end

context "absolute_url filter" do
should "produce an absolute URL from a page URL" do
page_url = "/about/my_favorite_page/"
assert_equal "http://example.com/base#{page_url}", @filter.absolute_url(page_url)
end

should "ensure the leading slash" do
page_url = "about/my_favorite_page/"
assert_equal "http://example.com/base/#{page_url}", @filter.absolute_url(page_url)
end

should "ensure the leading slash for the baseurl" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({
"url" => "http://example.com",
"baseurl" => "base"
})
assert_equal "http://example.com/base/#{page_url}", filter.absolute_url(page_url)
end

should "be ok with a blank but present 'url'" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({
"url" => "",
"baseurl" => "base"
})
assert_equal "/base/#{page_url}", filter.absolute_url(page_url)
end

should "be ok with a nil 'url'" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({
"url" => nil,
"baseurl" => "base"
})
assert_equal "/base/#{page_url}", filter.absolute_url(page_url)
end

should "be ok with a nil 'baseurl'" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({
"url" => "http://example.com",
"baseurl" => nil
})
assert_equal "http://example.com/#{page_url}", filter.absolute_url(page_url)
end

should "not prepend a forward slash if input is empty" do
page_url = ""
filter = make_filter_mock({
"url" => "http://example.com",
"baseurl" => "/base"
})
assert_equal "http://example.com/base", filter.absolute_url(page_url)
end
end

context "relative_url filter" do
should "produce a relative URL from a page URL" do
page_url = "/about/my_favorite_page/"
assert_equal "/base#{page_url}", @filter.relative_url(page_url)
end

should "ensure the leading slash between baseurl and input" do
page_url = "about/my_favorite_page/"
assert_equal "/base/#{page_url}", @filter.relative_url(page_url)
end

should "ensure the leading slash for the baseurl" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({ "baseurl" => "base" })
assert_equal "/base/#{page_url}", filter.relative_url(page_url)
end

should "be ok with a nil 'baseurl'" do
page_url = "about/my_favorite_page/"
filter = make_filter_mock({
"url" => "http://example.com",
"baseurl" => nil
})
assert_equal "/#{page_url}", filter.relative_url(page_url)
end

should "not prepend a forward slash if input is empty" do
page_url = ""
filter = make_filter_mock({
"url" => "http://example.com",
"baseurl" => "/base"
})
assert_equal "/base", filter.relative_url(page_url)
end
end

context "jsonify filter" do
should "convert hash to json" do
assert_equal "{\"age\":18}", @filter.jsonify({ :age => 18 })
Expand Down