Skip to content

Commit

Permalink
Add exclude: param to relativize_paths filter
Browse files Browse the repository at this point in the history
  • Loading branch information
denisdefreyne committed Jun 9, 2018
1 parent b41b1f5 commit 256cdbd
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 17 deletions.
46 changes: 35 additions & 11 deletions nanoc/lib/nanoc/filters/relativize_paths.rb
Expand Up @@ -8,6 +8,8 @@ class RelativizePaths < Nanoc::Filter
require 'nanoc/helpers/link_to'
include Nanoc::Helpers::LinkTo

DDMemoize.activate(self)

SELECTORS = ['*/@href', '*/@src', 'object/@data', 'param[@name="movie"]/@content', 'form/@action', 'comment()'].freeze

GCSE_SEARCH_WORKAROUND = 'nanoc__gcse_search__f7ac3462f628a053f86fe6563c0ec98f1fe45cee'
Expand Down Expand Up @@ -41,7 +43,7 @@ def run(content, params = {})
# Filter
case params[:type]
when :css
relativize_css(content)
relativize_css(content, params)
when :html, :html5, :xml, :xhtml
relativize_html_like(content, params)
else
Expand All @@ -53,15 +55,37 @@ def run(content, params = {})

protected

def relativize_css(content)
def relativize_css(content, params)
# FIXME: parse CSS the proper way using csspool or something
content.gsub(/url\((['"]?)(\/(?:[^\/].*?)?)\1\)/) do
quote = Regexp.last_match[1]
path = Regexp.last_match[2]
'url(' + quote + relative_path_to(path) + quote + ')'

if exclude?(path, params)
Regexp.last_match[0]
else
'url(' + quote + relative_path_to(path) + quote + ')'
end
end
end

memoized def excludes(params)
raw = [params.fetch(:exclude, [])].flatten
raw.map do |exclusion|
case exclusion
when Regexp
exclusion
when String
/\A#{exclusion}(\z|\/)/
end
end
end

def exclude?(path, params)
# TODO: Use #match? on newer Ruby versions
excludes(params).any? { |ex| path =~ ex }
end

def relativize_html_like(content, params)
selectors = params.fetch(:select, SELECTORS)
namespaces = params.fetch(:namespaces, {})
Expand All @@ -71,7 +95,7 @@ def relativize_html_like(content, params)
parser = parser_for(type)
content = fix_content(content, type)

nokogiri_process(content, selectors, namespaces, parser, type, nokogiri_save_options)
nokogiri_process(content, selectors, namespaces, parser, type, nokogiri_save_options, params)
end

def parser_for(type)
Expand Down Expand Up @@ -104,7 +128,7 @@ def fix_content(content, type)
end
end

def nokogiri_process(content, selectors, namespaces, klass, type, nokogiri_save_options = nil)
def nokogiri_process(content, selectors, namespaces, klass, type, nokogiri_save_options, params)
# Ensure that all prefixes are strings
namespaces = namespaces.reduce({}) { |new, (prefix, uri)| new.merge(prefix.to_s => uri) }

Expand All @@ -114,8 +138,8 @@ def nokogiri_process(content, selectors, namespaces, klass, type, nokogiri_save_
selector = selectors.map { |sel| "descendant-or-self::#{sel}" }.join('|')
doc.xpath(selector, namespaces).each do |node|
if node.name == 'comment'
nokogiri_process_comment(node, doc, selectors, namespaces, klass, type)
elsif path_is_relativizable?(node.content)
nokogiri_process_comment(node, doc, selectors, namespaces, klass, type, params)
elsif path_is_relativizable?(node.content, params)
node.content = relative_path_to(node.content)
end
end
Expand All @@ -139,20 +163,20 @@ def revert_gcse_search_workaround(content)
content.gsub(GCSE_SEARCH_WORKAROUND, 'gcse:search')
end

def nokogiri_process_comment(node, doc, selectors, namespaces, klass, type)
def nokogiri_process_comment(node, doc, selectors, namespaces, klass, type, params)
content = node.content.dup.sub(%r{^(\s*\[.+?\]>\s*)(.+?)(\s*<!\[endif\])}m) do |_m|
beginning = Regexp.last_match[1]
body = Regexp.last_match[2]
ending = Regexp.last_match[3]

beginning + nokogiri_process(body, selectors, namespaces, klass, type) + ending
beginning + nokogiri_process(body, selectors, namespaces, klass, type, nil, params) + ending
end

node.replace(Nokogiri::XML::Comment.new(doc, content))
end

def path_is_relativizable?(path)
path.start_with?('/')
def path_is_relativizable?(path, params)
path.start_with?('/') && !exclude?(path, params)
end
end
end
133 changes: 127 additions & 6 deletions nanoc/spec/nanoc/filters/relativize_paths_spec.rb
Expand Up @@ -21,7 +21,7 @@
subject { filter.setup_and_run(content, params) }

let(:content) do
'<a href="/foo">Foo</a>'
'<a href="/foo/bar">Foo</a>'
end

let(:params) do
Expand All @@ -30,26 +30,147 @@

context 'HTML' do
let(:params) { { type: :html } }
it { is_expected.to eq('<a href="../foo">Foo</a>') }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }

context 'full component excluded' do
let(:params) { { type: :html, exclude: '/foo' } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'full component excluded as list' do
let(:params) { { type: :html, exclude: ['/foo'] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'partial component excluded' do
let(:params) { { type: :html, exclude: ['/fo'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'non-root component excluded' do
let(:params) { { type: :html, exclude: ['/bar'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'excluded with regexp' do
let(:params) { { type: :html, exclude: /ar/ } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'excluded with regexp list' do
let(:params) { { type: :html, exclude: [/ar/] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end
end

context 'HTML5' do
let(:params) { { type: :html5 } }
it { is_expected.to eq('<a href="../foo">Foo</a>') }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }

context 'full component excluded' do
let(:params) { { type: :html5, exclude: '/foo' } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'full component excluded as list' do
let(:params) { { type: :html5, exclude: ['/foo'] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'partial component excluded' do
let(:params) { { type: :html5, exclude: ['/fo'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'non-root component excluded' do
let(:params) { { type: :html5, exclude: ['/bar'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'excluded with regexp' do
let(:params) { { type: :html5, exclude: /ar/ } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'excluded with regexp list' do
let(:params) { { type: :html5, exclude: [/ar/] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end
end

context 'XHTML' do
let(:params) { { type: :xhtml } }
it { is_expected.to eq('<a href="../foo">Foo</a>') }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }

context 'full component excluded' do
let(:params) { { type: :xhtml, exclude: '/foo' } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'full component excluded as list' do
let(:params) { { type: :xhtml, exclude: ['/foo'] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'partial component excluded' do
let(:params) { { type: :xhtml, exclude: ['/fo'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'non-root component excluded' do
let(:params) { { type: :xhtml, exclude: ['/bar'] } }
it { is_expected.to eq('<a href="../foo/bar">Foo</a>') }
end

context 'excluded with regexp' do
let(:params) { { type: :xhtml, exclude: /ar/ } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end

context 'excluded with regexp list' do
let(:params) { { type: :xhtml, exclude: [/ar/] } }
it { is_expected.to eq('<a href="/foo/bar">Foo</a>') }
end
end

context 'CSS' do
let(:params) { { type: :css } }

let(:content) do
'.oink { background: url(/foo.png) }'
'.oink { background: url(/foo/bar.png) }'
end

it { is_expected.to eq('.oink { background: url(../foo.png) }') }
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }

context 'full component excluded' do
let(:params) { { type: :css, exclude: '/foo' } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end

context 'full component excluded as list' do
let(:params) { { type: :css, exclude: ['/foo'] } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end

context 'partial component excluded' do
let(:params) { { type: :css, exclude: ['/fo'] } }
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }
end

context 'non-root component excluded' do
let(:params) { { type: :css, exclude: ['/bar'] } }
it { is_expected.to eq('.oink { background: url(../foo/bar.png) }') }
end

context 'excluded with regexp' do
let(:params) { { type: :css, exclude: /ar/ } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end

context 'excluded with regexp list' do
let(:params) { { type: :css, exclude: [/ar/] } }
it { is_expected.to eq('.oink { background: url(/foo/bar.png) }') }
end
end
end
end

0 comments on commit 256cdbd

Please sign in to comment.