Experiment with non-rack rewriters
This commit is contained in:
parent
0f2bc1e0ea
commit
13d62cb276
6 changed files with 184 additions and 34 deletions
123
middleman-core/features/relative_assets_helpers_only.feature
Normal file
123
middleman-core/features/relative_assets_helpers_only.feature
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
Feature: Relative Assets (Helpers Only)
|
||||||
|
|
||||||
|
Scenario: Rendering css with the feature enabled
|
||||||
|
Given a fixture app "relative-assets-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :relative_assets, helpers_only: true
|
||||||
|
"""
|
||||||
|
And a file named "source/stylesheets/relative_assets.css.sass.erb" with:
|
||||||
|
"""
|
||||||
|
h1
|
||||||
|
background: url("<%= asset_url('images/blank.gif') %>")
|
||||||
|
h2
|
||||||
|
background: url("<%= asset_url('/images/blank2.gif') %>")
|
||||||
|
"""
|
||||||
|
And a file named "source/javascripts/application.js.erb" with:
|
||||||
|
"""
|
||||||
|
function foo() {
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = '<%= asset_url("images/100px.jpg") %>';
|
||||||
|
var body = document.getElementsByTagName('body')[0];
|
||||||
|
body.insertBefore(img, body.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = foo;
|
||||||
|
"""
|
||||||
|
And a file named "source/stylesheets/fonts3.css.erb" with:
|
||||||
|
"""
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto2';
|
||||||
|
src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>);
|
||||||
|
src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And the Server is running at "relative-assets-app"
|
||||||
|
When I go to "/stylesheets/relative_assets.css"
|
||||||
|
Then I should see 'url("../images/blank.gif'
|
||||||
|
And I should see 'url("../images/blank2.gif'
|
||||||
|
When I go to "/javascripts/application.js"
|
||||||
|
Then I should not see "../"
|
||||||
|
When I go to "/stylesheets/fonts3.css"
|
||||||
|
Then I should see 'url(../fonts/roboto/roboto-regular-webfont.eot'
|
||||||
|
And I should see 'url(../fonts/roboto/roboto-regular-webfont.woff'
|
||||||
|
And I should see 'url(../fonts/roboto/roboto-regular-webfont.ttf'
|
||||||
|
And I should see 'url(../fonts/roboto/roboto-regular-webfont.svg'
|
||||||
|
|
||||||
|
Scenario: Relative css reference with directory indexes
|
||||||
|
Given a fixture app "relative-assets-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :directory_indexes
|
||||||
|
activate :relative_assets, helpers_only: true
|
||||||
|
"""
|
||||||
|
And the Server is running at "relative-assets-app"
|
||||||
|
When I go to "/relative_image/index.html"
|
||||||
|
Then I should see "../stylesheets/relative_assets.css"
|
||||||
|
|
||||||
|
Scenario: Relative assets via image_tag
|
||||||
|
Given a fixture app "relative-assets-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :relative_assets, helpers_only: true
|
||||||
|
"""
|
||||||
|
And a file named "source/sub/image_tag.html.erb" with:
|
||||||
|
"""
|
||||||
|
<%= image_tag '/img/blank.gif' %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "relative-assets-app"
|
||||||
|
When I go to "/sub/image_tag.html"
|
||||||
|
Then I should see '<img src="../img/blank.gif" />'
|
||||||
|
|
||||||
|
Scenario: Relative assets should not break data URIs in image_tag
|
||||||
|
Given a fixture app "relative-assets-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :relative_assets, helpers_only: true
|
||||||
|
"""
|
||||||
|
And a file named "source/sub/image_tag.html.erb" with:
|
||||||
|
"""
|
||||||
|
<%= image_tag "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "relative-assets-app"
|
||||||
|
When I go to "/sub/image_tag.html"
|
||||||
|
Then I should see '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />'
|
||||||
|
|
||||||
|
Scenario: URLs are not rewritten for rewrite ignored paths
|
||||||
|
Given a fixture app "relative-assets-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :relative_assets, rewrite_ignore: [
|
||||||
|
'/stylesheets/fonts3.css',
|
||||||
|
], helpers_only: true
|
||||||
|
"""
|
||||||
|
And a file named "source/stylesheets/relative_assets.css.sass.erb" with:
|
||||||
|
"""
|
||||||
|
h1
|
||||||
|
background: url("<%= asset_url('images/blank.gif') %>")
|
||||||
|
h2
|
||||||
|
background: url("<%= asset_url('/images/blank2.gif') %>")
|
||||||
|
"""
|
||||||
|
And a file named "source/stylesheets/fonts3.css.erb" with:
|
||||||
|
"""
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto2';
|
||||||
|
src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>);
|
||||||
|
src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'),
|
||||||
|
url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And the Server is running at "relative-assets-app"
|
||||||
|
When I go to "/stylesheets/relative_assets.css"
|
||||||
|
Then I should see 'url("../images/blank.gif'
|
||||||
|
When I go to "/stylesheets/fonts3.css"
|
||||||
|
Then I should see 'url(/fonts/roboto/roboto-regular-webfont.eot'
|
|
@ -1,4 +1,5 @@
|
||||||
require 'padrino-helpers'
|
require 'padrino-helpers'
|
||||||
|
require 'middleman-core/contracts'
|
||||||
|
|
||||||
# Don't fail on invalid locale, that's not what our current
|
# Don't fail on invalid locale, that's not what our current
|
||||||
# users expect.
|
# users expect.
|
||||||
|
|
|
@ -11,13 +11,12 @@ module Middleman
|
||||||
|
|
||||||
expose_to_application rewrite_inline_urls: :add
|
expose_to_application rewrite_inline_urls: :add
|
||||||
|
|
||||||
IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
|
|
||||||
REWRITER_DESCRIPTOR = {
|
REWRITER_DESCRIPTOR = {
|
||||||
id: Symbol,
|
id: Symbol,
|
||||||
proc: Or[Proc, Method],
|
proc: Or[Proc, Method],
|
||||||
url_extensions: ArrayOf[String],
|
url_extensions: ArrayOf[String],
|
||||||
source_extensions: ArrayOf[String],
|
source_extensions: ArrayOf[String],
|
||||||
ignore: ArrayOf[IGNORE_DESCRIPTOR],
|
ignore: ArrayOf[::Middleman::Util::IGNORE_DESCRIPTOR],
|
||||||
after: Maybe[Symbol]
|
after: Maybe[Symbol]
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
@ -109,7 +108,7 @@ module Middleman
|
||||||
next unless source_exts.include?(::File.extname(path))
|
next unless source_exts.include?(::File.extname(path))
|
||||||
|
|
||||||
ignore = rewriter.fetch(:ignore)
|
ignore = rewriter.fetch(:ignore)
|
||||||
next if ignore.any? { |r| should_ignore?(r, full_asset_path) }
|
next if ignore.any? { |r| ::Middleman::Util.should_ignore?(r, full_asset_path) }
|
||||||
|
|
||||||
rewrite_ignore = Array(rewriter[:rewrite_ignore] || [])
|
rewrite_ignore = Array(rewriter[:rewrite_ignore] || [])
|
||||||
next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) }
|
next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) }
|
||||||
|
@ -130,24 +129,6 @@ module Middleman
|
||||||
headers
|
headers
|
||||||
).finish
|
).finish
|
||||||
end
|
end
|
||||||
|
|
||||||
Contract IGNORE_DESCRIPTOR, String => Bool
|
|
||||||
def should_ignore?(validator, value)
|
|
||||||
if validator.is_a? Regexp
|
|
||||||
# Treat as Regexp
|
|
||||||
!!(value =~ validator)
|
|
||||||
elsif validator.respond_to? :call
|
|
||||||
# Treat as proc
|
|
||||||
validator.call(value)
|
|
||||||
elsif validator.is_a? String
|
|
||||||
# Treat as glob
|
|
||||||
File.fnmatch(value, validator)
|
|
||||||
else
|
|
||||||
# If some unknown thing, don't ignore
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
memoize :should_ignore?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,15 +2,20 @@ require 'addressable/uri'
|
||||||
|
|
||||||
# Relative Assets extension
|
# Relative Assets extension
|
||||||
class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
||||||
option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
|
option :exts, nil, 'List of extensions that get converted to relative paths.'
|
||||||
option :sources, %w(.css .htm .html .xhtml), 'List of extensions that are searched for relative assets.'
|
option :sources, %w(.css .htm .html .xhtml), 'List of extensions that are searched for relative assets.'
|
||||||
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
|
option :ignore, [], 'Regexes of filenames to skip converting to relative paths.'
|
||||||
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
|
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites.'
|
||||||
|
option :helpers_only, false, 'Allow only Ruby helpers to change paths.'
|
||||||
|
|
||||||
def initialize(app, options_hash={}, &block)
|
def initialize(app, options_hash={}, &block)
|
||||||
super
|
super
|
||||||
|
|
||||||
app.rewrite_inline_urls id: :asset_hash,
|
if options[:helpers_only]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
app.rewrite_inline_urls id: :relative_assets,
|
||||||
url_extensions: options.exts || app.config[:asset_extensions],
|
url_extensions: options.exts || app.config[:asset_extensions],
|
||||||
source_extensions: options.sources,
|
source_extensions: options.sources,
|
||||||
ignore: options.ignore,
|
ignore: options.ignore,
|
||||||
|
@ -18,16 +23,37 @@ class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
||||||
proc: method(:rewrite_url)
|
proc: method(:rewrite_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers do
|
def mark_as_relative(file_path, opts, current_resource)
|
||||||
# asset_url override for relative assets
|
result = opts.dup
|
||||||
# @param [String] path
|
|
||||||
# @param [String] prefix
|
|
||||||
# @param [Hash] options Additional options.
|
|
||||||
# @return [String]
|
|
||||||
def asset_url(path, prefix='', options={})
|
|
||||||
options[:relative] = true unless options.key?(:relative)
|
|
||||||
|
|
||||||
super(path, prefix, options)
|
valid_exts = options.sources
|
||||||
|
|
||||||
|
return result unless current_resource
|
||||||
|
return result unless valid_exts.include?(current_resource.ext)
|
||||||
|
|
||||||
|
rewrite_ignores = Array(options.rewrite_ignore || [])
|
||||||
|
|
||||||
|
path = current_resource.destination_path
|
||||||
|
return result if rewrite_ignores.any? do |i|
|
||||||
|
::Middleman::Util.path_match(i, path) || ::Middleman::Util.path_match(i, "/#{path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
return result if Array(options.ignore || []).any? do |r|
|
||||||
|
::Middleman::Util.should_ignore?(r, file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
result[:relative] = true unless result.key?(:relative)
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
helpers do
|
||||||
|
def asset_url(path, prefix='', options={})
|
||||||
|
super(path, prefix, app.extensions[:relative_assets].mark_as_relative(super, options, current_resource))
|
||||||
|
end
|
||||||
|
|
||||||
|
def asset_path(kind, source, options={})
|
||||||
|
super(kind, source, app.extensions[:relative_assets].mark_as_relative(super, options, current_resource))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,25 @@ module Middleman
|
||||||
end
|
end
|
||||||
memoize :strip_leading_slash
|
memoize :strip_leading_slash
|
||||||
|
|
||||||
|
IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
|
||||||
|
Contract IGNORE_DESCRIPTOR, String => Bool
|
||||||
|
def should_ignore?(validator, value)
|
||||||
|
if validator.is_a? Regexp
|
||||||
|
# Treat as Regexp
|
||||||
|
!!(value =~ validator)
|
||||||
|
elsif validator.respond_to? :call
|
||||||
|
# Treat as proc
|
||||||
|
validator.call(value)
|
||||||
|
elsif validator.is_a? String
|
||||||
|
# Treat as glob
|
||||||
|
File.fnmatch(value, validator)
|
||||||
|
else
|
||||||
|
# If some unknown thing, don't ignore
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
memoize :should_ignore?
|
||||||
|
|
||||||
# Get the path of a file of a given type
|
# Get the path of a file of a given type
|
||||||
#
|
#
|
||||||
# @param [Middleman::Application] app The app.
|
# @param [Middleman::Application] app The app.
|
||||||
|
|
Loading…
Add table
Reference in a new issue