Merge remote-tracking branch 'origin/3.0-stable'
Conflicts: middleman-core/lib/middleman-core/core_extensions/data.rb middleman-core/lib/middleman-core/core_extensions/front_matter.rb middleman-core/lib/middleman-core/util.rb middleman-core/middleman-core-x86-mingw32.gemspec middleman-more/lib/middleman-more/core_extensions/default_helpers.rb middleman-more/lib/middleman-more/core_extensions/i18n.rb
This commit is contained in:
commit
52c4677391
|
@ -48,11 +48,7 @@ A full set of in-depth instructional guides are available on the official websit
|
||||||
|
|
||||||
http://middlemanapp.com/
|
http://middlemanapp.com/
|
||||||
|
|
||||||
The community maintains its own collection of tips and tricks in the GitHub wiki:
|
Additionally, up-to-date generated code documentation is available on RubyDoc:
|
||||||
|
|
||||||
https://github.com/middleman/middleman/wiki
|
|
||||||
|
|
||||||
Finally, up-to-date generated code documentation is available on RubyDoc:
|
|
||||||
http://rubydoc.info/github/middleman/middleman
|
http://rubydoc.info/github/middleman/middleman
|
||||||
|
|
||||||
# Community
|
# Community
|
||||||
|
|
7
Rakefile
7
Rakefile
|
@ -87,6 +87,13 @@ task :test do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Run specs for all middleman gems"
|
||||||
|
task :spec do
|
||||||
|
GEM_PATHS.each do |g|
|
||||||
|
sh "cd #{File.join(ROOT, g)} && #{Gem.ruby} -S rake spec"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# desc "Rune cane for all middleman gems"
|
# desc "Rune cane for all middleman gems"
|
||||||
# task :cane do
|
# task :cane do
|
||||||
# GEM_PATHS.each do |g|
|
# GEM_PATHS.each do |g|
|
||||||
|
|
|
@ -233,7 +233,7 @@ module Middleman::Cli
|
||||||
|
|
||||||
paths = ::Middleman::Util.all_files_under(@destination)
|
paths = ::Middleman::Util.all_files_under(@destination)
|
||||||
@cleaning_queue += paths.select do |path|
|
@cleaning_queue += paths.select do |path|
|
||||||
!path.to_s.match(/\/\./) || path.to_s.match(/\.htaccess|\.htpasswd/)
|
path.to_s !~ /\/\./ || path.to_s =~ /\.(htaccess|htpasswd)/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,12 @@ module Middleman
|
||||||
# Setup data files before anything else so they are available when
|
# Setup data files before anything else so they are available when
|
||||||
# parsing config.rb
|
# parsing config.rb
|
||||||
def initialize
|
def initialize
|
||||||
files.changed DataStore.matcher do |file|
|
self.files.changed DataStore.matcher do |file|
|
||||||
data.touch_file(file) if file.match(%r{^#{config[:data_dir]}\/})
|
self.data.touch_file(file) if file.start_with?("#{config[data_dir]}/")
|
||||||
end
|
end
|
||||||
|
|
||||||
files.deleted DataStore.matcher do |file|
|
self.files.deleted DataStore.matcher do |file|
|
||||||
data.remove_file(file) if file.match(%r{^#{config[data_dir]}\/})
|
self.data.remove_file(file) if file.start_with?("#{config[data_dir]}/")
|
||||||
end
|
end
|
||||||
|
|
||||||
super
|
super
|
||||||
|
|
|
@ -145,7 +145,8 @@ module Middleman
|
||||||
# @param [Pathname] path
|
# @param [Pathname] path
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def ignored?(path)
|
def ignored?(path)
|
||||||
IGNORE_LIST.any? { |r| path.to_s.match(r) }
|
path = path.to_s
|
||||||
|
IGNORE_LIST.any? { |r| path =~ r }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Notify callbacks for a file given an array of callbacks
|
# Notify callbacks for a file given an array of callbacks
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require "active_support/core_ext/hash/keys"
|
require "active_support/core_ext/hash/keys"
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
# Extensions namespace
|
# Extensions namespace
|
||||||
module Middleman::CoreExtensions
|
module Middleman::CoreExtensions
|
||||||
|
@ -130,7 +131,12 @@ module Middleman::CoreExtensions
|
||||||
# @param [String] path
|
# @param [String] path
|
||||||
# @return [Array<Thor::CoreExt::HashWithIndifferentAccess, String>]
|
# @return [Array<Thor::CoreExt::HashWithIndifferentAccess, String>]
|
||||||
def frontmatter_and_content(path)
|
def frontmatter_and_content(path)
|
||||||
full_path = File.expand_path(File.join(@app.source_dir, path))
|
full_path = if Pathname(path).relative?
|
||||||
|
File.join(@app.source_dir, path)
|
||||||
|
else
|
||||||
|
path
|
||||||
|
end
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
content = nil
|
content = nil
|
||||||
|
|
||||||
|
@ -158,7 +164,7 @@ module Middleman::CoreExtensions
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize_path(path)
|
def normalize_path(path)
|
||||||
path.sub(@app.source_dir, "").sub(/^\//, "")
|
path.sub(%r{^#{@app.source_dir}\/}, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update the main sitemap resource list
|
# Update the main sitemap resource list
|
||||||
|
|
|
@ -246,15 +246,26 @@ module Middleman
|
||||||
options = opts.merge(options_for_ext(extension))
|
options = opts.merge(options_for_ext(extension))
|
||||||
options[:outvar] ||= '@_out_buf'
|
options[:outvar] ||= '@_out_buf'
|
||||||
|
|
||||||
|
template_class = Tilt[path]
|
||||||
|
# Allow hooks to manipulate the template before render
|
||||||
|
self.class.callbacks_for_hook(:before_render).each do |callback|
|
||||||
|
newbody = callback.call(body, path, locs, template_class)
|
||||||
|
body = newbody if newbody # Allow the callback to return nil to skip it
|
||||||
|
end
|
||||||
|
|
||||||
# Read compiled template from disk or cache
|
# Read compiled template from disk or cache
|
||||||
template = cache.fetch(:compiled_template, options, body) do
|
template = cache.fetch(:compiled_template, options, body) do
|
||||||
::Tilt.new(path, 1, options) { body }
|
::Tilt.new(path, 1, options) { body }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Render using Tilt
|
# Render using Tilt
|
||||||
run_hook :before_render, template.data, template
|
content = template.render(context, path, locs, &block)
|
||||||
content = template.render(context, locs, &block)
|
|
||||||
run_hook :after_render, content, template
|
# Allow hooks to manipulate the result after render
|
||||||
|
self.class.callbacks_for_hook(:after_render).each do |callback|
|
||||||
|
content = callback.call(content, locs, template_class)
|
||||||
|
end
|
||||||
|
|
||||||
return content
|
return content
|
||||||
ensure
|
ensure
|
||||||
# Reset stored buffer
|
# Reset stored buffer
|
||||||
|
@ -408,7 +419,7 @@ module Middleman
|
||||||
# Find the path by searching or using the cache
|
# Find the path by searching or using the cache
|
||||||
request_path = request_path.to_s
|
request_path = request_path.to_s
|
||||||
cache.fetch(:resolve_template, request_path, options) do
|
cache.fetch(:resolve_template, request_path, options) do
|
||||||
relative_path = request_path.sub(%r{^/}, "")
|
relative_path = Util.strip_leading_slash(request_path)
|
||||||
on_disk_path = File.expand_path(relative_path, self.source_dir)
|
on_disk_path = File.expand_path(relative_path, self.source_dir)
|
||||||
|
|
||||||
# By default, any engine will do
|
# By default, any engine will do
|
||||||
|
|
|
@ -194,7 +194,7 @@ module Middleman
|
||||||
|
|
||||||
paths.any? do |path|
|
paths.any? do |path|
|
||||||
match_against.any? do |matcher|
|
match_against.any? do |matcher|
|
||||||
path.match(matcher)
|
path =~ matcher
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,18 +25,18 @@ module Middleman
|
||||||
# Setup callbacks which can exclude paths from the sitemap
|
# Setup callbacks which can exclude paths from the sitemap
|
||||||
app.config.define_setting :ignored_sitemap_matchers, {
|
app.config.define_setting :ignored_sitemap_matchers, {
|
||||||
# dotfiles and folders in the root
|
# dotfiles and folders in the root
|
||||||
:root_dotfiles => proc { |file| file.match(%r{^\.}) },
|
:root_dotfiles => proc { |file| file.start_with?('.') },
|
||||||
|
|
||||||
# Files starting with an dot, but not .htaccess
|
# Files starting with an dot, but not .htaccess
|
||||||
:source_dotfiles => proc { |file|
|
:source_dotfiles => proc { |file|
|
||||||
file.match(%r{/\.}) && !file.match(%r{/\.htaccess|\.htpasswd})
|
file =~ %r{/\.} && file !~ %r{/\.(htaccess|htpasswd)}
|
||||||
},
|
},
|
||||||
|
|
||||||
# Files starting with an underscore, but not a double-underscore
|
# Files starting with an underscore, but not a double-underscore
|
||||||
:partials => proc { |file| file.match(%r{/_}) && !file.match(%r{/__}) },
|
:partials => proc { |file| file =~ %r{/_} && file !~ %r{/__} },
|
||||||
|
|
||||||
:layout => proc { |file|
|
:layout => proc { |file|
|
||||||
file.match(%r{^source/layout\.}) || file.match(%r{^source/layouts/})
|
file.start_with?('source/layout.') || file.start_with?('source/layouts/')
|
||||||
}
|
}
|
||||||
}, 'Callbacks that can exclude paths from the sitemap'
|
}, 'Callbacks that can exclude paths from the sitemap'
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ module Middleman
|
||||||
blank_metadata = { :options => {}, :locals => {}, :page => {}, :blocks => [] }
|
blank_metadata = { :options => {}, :locals => {}, :page => {}, :blocks => [] }
|
||||||
|
|
||||||
provides_metadata.inject(blank_metadata) do |result, (callback, matcher)|
|
provides_metadata.inject(blank_metadata) do |result, (callback, matcher)|
|
||||||
next result if !matcher.nil? && !source_file.match(matcher)
|
next result if matcher && !source_file.match(matcher)
|
||||||
|
|
||||||
metadata = callback.call(source_file)
|
metadata = callback.call(source_file)
|
||||||
|
|
||||||
|
@ -149,9 +149,9 @@ module Middleman
|
||||||
@_cached_metadata[request_path] = provides_metadata_for_path.inject(blank_metadata) do |result, (callback, matcher)|
|
@_cached_metadata[request_path] = provides_metadata_for_path.inject(blank_metadata) do |result, (callback, matcher)|
|
||||||
case matcher
|
case matcher
|
||||||
when Regexp
|
when Regexp
|
||||||
next result unless request_path.match(matcher)
|
next result unless request_path =~ matcher
|
||||||
when String
|
when String
|
||||||
next result unless File.fnmatch("/" + matcher.sub(%r{^/}, ''), "/#{request_path}")
|
next result unless File.fnmatch("/" + Util.strip_leading_slash(matcher), "/#{request_path}")
|
||||||
end
|
end
|
||||||
|
|
||||||
metadata = callback.call(request_path)
|
metadata = callback.call(request_path)
|
||||||
|
|
|
@ -10,7 +10,8 @@ require "thor"
|
||||||
# Core Pathname library used for traversal
|
# Core Pathname library used for traversal
|
||||||
require "pathname"
|
require "pathname"
|
||||||
|
|
||||||
require "rack"
|
require "tilt"
|
||||||
|
require "rack/mime"
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
|
||||||
|
@ -22,11 +23,19 @@ module Middleman
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def self.binary?(filename)
|
def self.binary?(filename)
|
||||||
ext = File.extname(filename)
|
ext = File.extname(filename)
|
||||||
|
return true if ext == '.svgz'
|
||||||
return false if Tilt.registered?(ext.sub('.',''))
|
return false if Tilt.registered?(ext.sub('.',''))
|
||||||
|
|
||||||
ext = ".#{ext}" unless ext.to_s[0] == ?.
|
ext = ".#{ext}" unless ext.to_s[0] == ?.
|
||||||
mime = ::Rack::Mime.mime_type(ext, nil)
|
mime = ::Rack::Mime.mime_type(ext, nil)
|
||||||
return false unless mime
|
unless mime
|
||||||
|
binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
|
||||||
|
s = File.read(filename, 4096) || ''
|
||||||
|
s.each_byte do |c|
|
||||||
|
return true if binary_bytes.include?(c)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
return false if mime.start_with?('text/')
|
return false if mime.start_with?('text/')
|
||||||
return false if mime.include?('xml')
|
return false if mime.include?('xml')
|
||||||
return false if mime.include?('json')
|
return false if mime.include?('json')
|
||||||
|
@ -78,7 +87,13 @@ module Middleman
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def self.normalize_path(path)
|
def self.normalize_path(path)
|
||||||
# The tr call works around a bug in Ruby's Unicode handling
|
# The tr call works around a bug in Ruby's Unicode handling
|
||||||
path.sub(/^\//, "").tr('','')
|
path.sub(%r{^/}, "").tr('','')
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is a separate method from normalize_path in case we
|
||||||
|
# change how we normalize paths
|
||||||
|
def self.strip_leading_slash(path)
|
||||||
|
path.sub(%r{^/}, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Extract the text of a Rack response as a string.
|
# Extract the text of a Rack response as a string.
|
||||||
|
|
|
@ -26,7 +26,7 @@ Gem::Specification.new do |s|
|
||||||
s.add_dependency("rack-test", ["~> 0.6.1"])
|
s.add_dependency("rack-test", ["~> 0.6.1"])
|
||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
s.add_dependency("thor", [">= 0.15.4", "~> 0.15"])
|
s.add_dependency("thor", ["~> 0.15.4"])
|
||||||
|
|
||||||
# Helpers
|
# Helpers
|
||||||
s.add_dependency("activesupport", ["~> 3.2.6"])
|
s.add_dependency("activesupport", ["~> 3.2.6"])
|
||||||
|
|
15
middleman-core/spec/middleman-core/binary_spec.rb
Normal file
15
middleman-core/spec/middleman-core/binary_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require 'middleman-core/util'
|
||||||
|
|
||||||
|
describe "Middleman::Util#binary?" do
|
||||||
|
%w(plain.txt unicode.txt unicode stars.svgz).each do |file|
|
||||||
|
it "recognizes #{file} as not binary" do
|
||||||
|
Middleman::Util.binary?(File.join(File.dirname(__FILE__), "binary_spec/#{file}")).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%w(middleman.png middleman).each do |file|
|
||||||
|
it "recognizes #{file} as binary" do
|
||||||
|
Middleman::Util.binary?(File.join(File.dirname(__FILE__), "binary_spec/#{file}")).should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
BIN
middleman-core/spec/middleman-core/binary_spec/middleman
Normal file
BIN
middleman-core/spec/middleman-core/binary_spec/middleman
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
middleman-core/spec/middleman-core/binary_spec/middleman.png
Normal file
BIN
middleman-core/spec/middleman-core/binary_spec/middleman.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
1
middleman-core/spec/middleman-core/binary_spec/plain.txt
Normal file
1
middleman-core/spec/middleman-core/binary_spec/plain.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Some plain text
|
BIN
middleman-core/spec/middleman-core/binary_spec/stars.svgz
Normal file
BIN
middleman-core/spec/middleman-core/binary_spec/stars.svgz
Normal file
Binary file not shown.
1
middleman-core/spec/middleman-core/binary_spec/unicode
Normal file
1
middleman-core/spec/middleman-core/binary_spec/unicode
Normal file
|
@ -0,0 +1 @@
|
||||||
|
明日がある。
|
|
@ -0,0 +1 @@
|
||||||
|
明日がある。
|
|
@ -25,3 +25,18 @@ Feature: Generate mtime-based query string for busting browser caches
|
||||||
When I go to "/cache-buster.html"
|
When I go to "/cache-buster.html"
|
||||||
Then I should see "site.css?"
|
Then I should see "site.css?"
|
||||||
Then I should see "blank.gif?"
|
Then I should see "blank.gif?"
|
||||||
|
|
||||||
|
Scenario: Rendering css with the feature and relative_assets enabled
|
||||||
|
Given "relative_assets" feature is "enabled"
|
||||||
|
Given "cache_buster" feature is "enabled"
|
||||||
|
And the Server is running at "cache-buster-app"
|
||||||
|
When I go to "/stylesheets/relative_assets.css"
|
||||||
|
Then I should see "blank.gif?"
|
||||||
|
|
||||||
|
Scenario: Rendering html with the feature and relative_assets enabled
|
||||||
|
Given "relative_assets" feature is "enabled"
|
||||||
|
Given "cache_buster" feature is "enabled"
|
||||||
|
And the Server is running at "cache-buster-app"
|
||||||
|
When I go to "/cache-buster.html"
|
||||||
|
Then I should see "site.css?"
|
||||||
|
Then I should see "blank.gif?"
|
26
middleman-more/features/helpers_form_tag.feature
Normal file
26
middleman-more/features/helpers_form_tag.feature
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Feature: form_tag helper
|
||||||
|
|
||||||
|
Scenario: form_tag produces relative links
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And an empty file named "config.rb"
|
||||||
|
And a file named "source/form_tag.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <% form_tag "/needs_index.html#absolute", :relative => true do %>
|
||||||
|
<% end %>
|
||||||
|
relative: <% form_tag "needs_index.html#relative", :relative => true do %>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And a file named "source/form_tag/sub.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <% form_tag "/needs_index.html#absolute", :relative => true do %>
|
||||||
|
<% end %>
|
||||||
|
relative: <% form_tag "../needs_index.html#relative", :relative => true do %>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/form_tag.html"
|
||||||
|
Then I should see 'action="needs_index.html#absolute"'
|
||||||
|
Then I should see 'action="needs_index.html#relative"'
|
||||||
|
When I go to "/form_tag/sub.html"
|
||||||
|
Then I should see 'action="../needs_index.html#absolute"'
|
||||||
|
Then I should see 'action="../needs_index.html#relative"'
|
152
middleman-more/features/helpers_url_for.feature
Normal file
152
middleman-more/features/helpers_url_for.feature
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
Feature: url_for helper
|
||||||
|
|
||||||
|
Scenario: url_for produces relative links
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And an empty file named "config.rb"
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html", :relative => true %>
|
||||||
|
relative: <%= url_for "needs_index.html", :relative => true %>
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for/sub.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html", :relative => true %>
|
||||||
|
relative: <%= url_for "../needs_index.html", :relative => true %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for.html"
|
||||||
|
Then I should see 'absolute: needs_index.html'
|
||||||
|
Then I should see 'relative: needs_index.html'
|
||||||
|
When I go to "/url_for/sub.html"
|
||||||
|
Then I should see 'absolute: ../needs_index.html'
|
||||||
|
Then I should see 'relative: ../needs_index.html'
|
||||||
|
|
||||||
|
Scenario: url_for relative works with strip_index_file
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :relative_links, true
|
||||||
|
set :strip_index_file, true
|
||||||
|
helpers do
|
||||||
|
def menu_items(path='url_for.html')
|
||||||
|
sitemap.find_resource_by_destination_path(path).children
|
||||||
|
end
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
<% menu_items.each do |item| %>
|
||||||
|
"<%= url_for(item.url) %>"
|
||||||
|
"<%= url_for(item) %>"
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for/sub.html.erb" with:
|
||||||
|
"""
|
||||||
|
<% menu_items.each do |item| %>
|
||||||
|
"<%= url_for(item.url) %>"
|
||||||
|
"<%= url_for(item) %>"
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for.html"
|
||||||
|
Then I should see '"url_for/sub.html"'
|
||||||
|
Then I should not see "/url_for/sub.html"
|
||||||
|
When I go to "/url_for/sub.html"
|
||||||
|
Then I should see '"sub.html"'
|
||||||
|
Then I should not see "/url_for/sub.html"
|
||||||
|
|
||||||
|
Scenario: url_for produces relative links when :relative_links is set to true
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :relative_links, true
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html" %>
|
||||||
|
relative: <%= url_for "needs_index.html", :relative => false %>
|
||||||
|
unknown: <%= url_for "foo.html" %>
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for/sub.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html" %>
|
||||||
|
relative: <%= url_for "../needs_index.html" %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for.html"
|
||||||
|
Then I should see 'absolute: needs_index.html'
|
||||||
|
Then I should see 'relative: /needs_index.html'
|
||||||
|
Then I should see 'unknown: foo.html'
|
||||||
|
When I go to "/url_for/sub.html"
|
||||||
|
Then I should see 'absolute: ../needs_index.html'
|
||||||
|
Then I should see 'relative: ../needs_index.html'
|
||||||
|
|
||||||
|
Scenario: url_for knows about directory indexes
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html", :relative => true %>
|
||||||
|
relative: <%= url_for "needs_index.html", :relative => true %>
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for/sub.html.erb" with:
|
||||||
|
"""
|
||||||
|
absolute: <%= url_for "/needs_index.html", :relative => true %>
|
||||||
|
relative: <%= url_for "../needs_index.html", :relative => true %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for/"
|
||||||
|
Then I should see 'absolute: ../needs_index/'
|
||||||
|
Then I should see 'relative: ../needs_index/'
|
||||||
|
When I go to "/url_for/sub/"
|
||||||
|
Then I should see 'absolute: ../../needs_index/'
|
||||||
|
Then I should see 'relative: ../../needs_index/'
|
||||||
|
|
||||||
|
Scenario: url_for can take a Resource
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
"<%= url_for sitemap.find_resource_by_path("/needs_index.html") %>"
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for/"
|
||||||
|
Then I should see '"/needs_index/"'
|
||||||
|
|
||||||
|
Scenario: Setting http_prefix
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :http_prefix, "/foo"
|
||||||
|
"""
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
<%= url_for "/needs_index.html" %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for.html"
|
||||||
|
Then I should see '/foo/needs_index.html'
|
||||||
|
|
||||||
|
Scenario: url_for preserves query string and anchor and isn't messed up by them
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
Needs Index Anchor <%= url_for "/needs_index.html#foo" %>
|
||||||
|
Needs Index Query <%= url_for "/needs_index.html?foo" %>
|
||||||
|
Needs Index Query and Anchor <%= url_for "/needs_index.html?foo#foo" %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for/"
|
||||||
|
Then I should see 'Needs Index Anchor /needs_index/#foo'
|
||||||
|
Then I should see 'Needs Index Query /needs_index/?foo'
|
||||||
|
Then I should see 'Needs Index Query and Anchor /needs_index/?foo#foo'
|
||||||
|
|
||||||
|
Scenario: url_for accepts a :query option that appends a query string
|
||||||
|
Given a fixture app "indexable-app"
|
||||||
|
And a file named "source/url_for.html.erb" with:
|
||||||
|
"""
|
||||||
|
Needs Index String <%= url_for "/needs_index.html", :query => "foo" %>
|
||||||
|
Needs Index Hash <%= url_for "/needs_index.html", :query => { :foo => :bar } %>
|
||||||
|
"""
|
||||||
|
And the Server is running at "indexable-app"
|
||||||
|
When I go to "/url_for/"
|
||||||
|
Then I should see 'Needs Index String /needs_index/?foo'
|
||||||
|
Then I should see 'Needs Index Hash /needs_index/?foo=bar'
|
|
@ -104,6 +104,51 @@ Feature: i18n Preview
|
||||||
When I go to "/spanish/hola.html"
|
When I go to "/spanish/hola.html"
|
||||||
Then I should see "Hola World"
|
Then I should see "Hola World"
|
||||||
|
|
||||||
|
Scenario: Running localize with a non-English mount config
|
||||||
|
Given a fixture app "i18n-test-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :i18n, :mount_at_root => :es
|
||||||
|
"""
|
||||||
|
Given the Server is running at "i18n-test-app"
|
||||||
|
When I go to "/en/index.html"
|
||||||
|
Then I should see "Howdy"
|
||||||
|
When I go to "/en/hello.html"
|
||||||
|
Then I should see "Hello World"
|
||||||
|
When I go to "/"
|
||||||
|
Then I should see "Como Esta?"
|
||||||
|
When I go to "/hola.html"
|
||||||
|
Then I should see "Hola World"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/es/index.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/es/hola.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
|
||||||
|
Scenario: Running localize with a non-English lang subset
|
||||||
|
Given a fixture app "i18n-test-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :i18n, :langs => :es
|
||||||
|
"""
|
||||||
|
Given the Server is running at "i18n-test-app"
|
||||||
|
When I go to "/en/index.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/en/hello.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/"
|
||||||
|
Then I should see "Como Esta?"
|
||||||
|
When I go to "/hola.html"
|
||||||
|
Then I should see "Hola World"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/es/index.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
When I go to "/es/hola.html"
|
||||||
|
Then I should see "File Not Found"
|
||||||
|
|
||||||
|
|
||||||
Scenario: Running localize with the no mount config
|
Scenario: Running localize with the no mount config
|
||||||
Given a fixture app "i18n-test-app"
|
Given a fixture app "i18n-test-app"
|
||||||
And a file named "config.rb" with:
|
And a file named "config.rb" with:
|
||||||
|
|
|
@ -64,7 +64,7 @@ module Middleman
|
||||||
# If the basename of the request as no extension, assume we are serving a
|
# If the basename of the request as no extension, assume we are serving a
|
||||||
# directory and join index_file to the path.
|
# directory and join index_file to the path.
|
||||||
path = File.join(asset_dir, current_path)
|
path = File.join(asset_dir, current_path)
|
||||||
path = path.gsub(File.extname(path), ".#{asset_ext}")
|
path = path.sub(/#{File.extname(path)}$/, ".#{asset_ext}")
|
||||||
|
|
||||||
yield path if sitemap.find_resource_by_path(path)
|
yield path if sitemap.find_resource_by_path(path)
|
||||||
end
|
end
|
||||||
|
@ -74,11 +74,11 @@ module Middleman
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def page_classes
|
def page_classes
|
||||||
path = current_path.dup
|
path = current_path.dup
|
||||||
path << index_file if path.match(%r{/$})
|
path << index_file if path.end_with?('/')
|
||||||
path = path.gsub(%r{^/}, '')
|
path = Util.strip_leading_slash(path)
|
||||||
|
|
||||||
classes = []
|
classes = []
|
||||||
parts = path.split('.')[0].split('/')
|
parts = path.split('.').first.split('/')
|
||||||
parts.each_with_index { |path, i| classes << parts.first(i+1).join('_') }
|
parts.each_with_index { |path, i| classes << parts.first(i+1).join('_') }
|
||||||
|
|
||||||
classes.join(' ')
|
classes.join(' ')
|
||||||
|
@ -90,22 +90,93 @@ module Middleman
|
||||||
# @param [String] source The path to the file
|
# @param [String] source The path to the file
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def asset_path(kind, source)
|
def asset_path(kind, source)
|
||||||
return source if source =~ /^http/
|
return source if source.to_s.include?('//')
|
||||||
asset_folder = case kind
|
asset_folder = case kind
|
||||||
when :css then css_dir
|
when :css then css_dir
|
||||||
when :js then js_dir
|
when :js then js_dir
|
||||||
when :images then images_dir
|
when :images then images_dir
|
||||||
else kind.to_s
|
else kind.to_s
|
||||||
end
|
end
|
||||||
source = source.to_s.gsub(/\s/, '')
|
source = source.to_s.tr(' ', '')
|
||||||
ignore_extension = (kind == :images) # don't append extension
|
ignore_extension = (kind == :images) # don't append extension
|
||||||
source << ".#{kind}" unless ignore_extension or source =~ /\.#{kind}/
|
source << ".#{kind}" unless ignore_extension || source.end_with?(".#{kind}")
|
||||||
if source =~ %r{^/} # absolute path
|
asset_folder = "" if source.start_with?('/') # absolute path
|
||||||
asset_folder = ""
|
|
||||||
end
|
|
||||||
asset_url(source, asset_folder)
|
asset_url(source, asset_folder)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Given a source path (referenced either absolutely or relatively)
|
||||||
|
# or a Resource, this will produce the nice URL configured for that
|
||||||
|
# path, respecting :relative_links, directory indexes, etc.
|
||||||
|
def url_for(path_or_resource, options={})
|
||||||
|
# Handle Resources and other things which define their own url method
|
||||||
|
url = path_or_resource.respond_to?(:url) ? path_or_resource.url : path_or_resource
|
||||||
|
|
||||||
|
begin
|
||||||
|
uri = URI(url)
|
||||||
|
rescue URI::InvalidURIError
|
||||||
|
# Nothing we can do with it, it's not really a URI
|
||||||
|
return url
|
||||||
|
end
|
||||||
|
|
||||||
|
relative = options.delete(:relative)
|
||||||
|
raise "Can't use the relative option with an external URL" if relative && uri.host
|
||||||
|
|
||||||
|
# Allow people to turn on relative paths for all links with
|
||||||
|
# set :relative_links, true
|
||||||
|
# but still override on a case by case basis with the :relative parameter.
|
||||||
|
effective_relative = relative || false
|
||||||
|
effective_relative = true if relative.nil? && config[:relative_links]
|
||||||
|
|
||||||
|
# Try to find a sitemap resource corresponding to the desired path
|
||||||
|
this_resource = current_resource # store in a local var to save work
|
||||||
|
if path_or_resource.is_a?(Sitemap::Resource)
|
||||||
|
resource = path_or_resource
|
||||||
|
resource_url = url
|
||||||
|
elsif this_resource && uri.path
|
||||||
|
# Handle relative urls
|
||||||
|
url_path = Pathname(uri.path)
|
||||||
|
current_source_dir = Pathname('/' + this_resource.path).dirname
|
||||||
|
url_path = current_source_dir.join(url_path) if url_path.relative?
|
||||||
|
resource = sitemap.find_resource_by_path(url_path.to_s)
|
||||||
|
resource_url = resource.url if resource
|
||||||
|
end
|
||||||
|
|
||||||
|
if resource
|
||||||
|
# Switch to the relative path between this_resource and the given resource
|
||||||
|
# if we've been asked to.
|
||||||
|
if effective_relative
|
||||||
|
# Output urls relative to the destination path, not the source path
|
||||||
|
current_dir = Pathname('/' + this_resource.destination_path).dirname
|
||||||
|
relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
|
||||||
|
|
||||||
|
# Put back the trailing slash to avoid unnecessary Apache redirects
|
||||||
|
if resource_url.end_with?('/') && !relative_path.end_with?('/')
|
||||||
|
relative_path << '/'
|
||||||
|
end
|
||||||
|
|
||||||
|
uri.path = relative_path
|
||||||
|
else
|
||||||
|
uri.path = resource_url
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# If they explicitly asked for relative links but we can't find a resource...
|
||||||
|
raise "No resource exists at #{url}" if relative
|
||||||
|
end
|
||||||
|
|
||||||
|
# Support a :query option that can be a string or hash
|
||||||
|
if query = options.delete(:query)
|
||||||
|
uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Support a :fragment or :anchor option just like Padrino
|
||||||
|
fragment = options.delete(:anchor) || options.delete(:fragment)
|
||||||
|
uri.fragment = fragment.to_s if fragment
|
||||||
|
|
||||||
|
# Finally make the URL back into a string
|
||||||
|
uri.to_s
|
||||||
|
end
|
||||||
|
|
||||||
# Overload the regular link_to to be sitemap-aware - if you
|
# Overload the regular link_to to be sitemap-aware - if you
|
||||||
# reference a source path, either absolutely or relatively,
|
# reference a source path, either absolutely or relatively,
|
||||||
# you'll get that resource's nice URL. Also, there is a
|
# you'll get that resource's nice URL. Also, there is a
|
||||||
|
@ -123,75 +194,27 @@ module Middleman
|
||||||
url_arg_index = block_given? ? 0 : 1
|
url_arg_index = block_given? ? 0 : 1
|
||||||
options_index = block_given? ? 1 : 2
|
options_index = block_given? ? 1 : 2
|
||||||
|
|
||||||
|
if block_given? && args.size > 2
|
||||||
|
raise ArgumentError.new("Too many arguments to link_to(url, options={}, &block)")
|
||||||
|
end
|
||||||
|
|
||||||
if url = args[url_arg_index]
|
if url = args[url_arg_index]
|
||||||
options = args[options_index] || {}
|
options = args[options_index] || {}
|
||||||
relative = options.delete(:relative)
|
raise ArgumentError.new("Options must be a hash") unless options.is_a?(Hash)
|
||||||
|
|
||||||
# Handle Resources, which define their own url method
|
# Transform the url through our magic url_for method
|
||||||
if url.respond_to? :url
|
args[url_arg_index] = url_for(url, options)
|
||||||
url = args[url_arg_index] = url.url
|
|
||||||
end
|
|
||||||
|
|
||||||
if url.include? '://'
|
|
||||||
raise "Can't use the relative option with an external URL" if relative
|
|
||||||
elsif current_resource
|
|
||||||
# Handle relative urls
|
|
||||||
current_source_dir = Pathname('/' + current_resource.path).dirname
|
|
||||||
|
|
||||||
begin
|
|
||||||
uri = URI(url)
|
|
||||||
url_path = uri.path
|
|
||||||
rescue
|
|
||||||
end
|
|
||||||
|
|
||||||
if url_path
|
|
||||||
path = Pathname(url_path)
|
|
||||||
url_path = current_source_dir.join(path).to_s if path.relative?
|
|
||||||
|
|
||||||
resource = sitemap.find_resource_by_path(url_path)
|
|
||||||
|
|
||||||
# Allow people to turn on relative paths for all links with config[:relative_links] = true
|
|
||||||
# but still override on a case by case basis with the :relative parameter.
|
|
||||||
effective_relative = relative || false
|
|
||||||
if relative.nil? && config[:relative_links]
|
|
||||||
effective_relative = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if resource
|
|
||||||
if effective_relative
|
|
||||||
resource_url = resource.url
|
|
||||||
|
|
||||||
# Output urls relative to the destination path, not the source path
|
|
||||||
current_dir = Pathname('/' + current_resource.destination_path).dirname
|
|
||||||
new_url = Pathname(resource_url).relative_path_from(current_dir).to_s
|
|
||||||
|
|
||||||
# Put back the trailing slash to avoid unnecessary Apache redirects
|
|
||||||
if resource_url.end_with?('/') && !new_url.end_with?('/')
|
|
||||||
new_url << '/'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
new_url = resource.url
|
|
||||||
end
|
|
||||||
|
|
||||||
uri.path = new_url
|
|
||||||
|
|
||||||
args[url_arg_index] = uri.to_s
|
|
||||||
else
|
|
||||||
raise "No resource exists at #{url}" if relative
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Support a :query option that can be a string or hash
|
|
||||||
if query = options.delete(:query)
|
|
||||||
uri = URI(args[url_arg_index])
|
|
||||||
uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
|
|
||||||
args[url_arg_index] = uri.to_s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
super(*args, &block)
|
super(*args, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Modified Padrino form_for that uses Middleman's url_for
|
||||||
|
# to transform the URL.
|
||||||
|
def form_tag(url, options={}, &block)
|
||||||
|
url = url_for(url, options)
|
||||||
|
super
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,6 +28,7 @@ module Middleman
|
||||||
@app = app
|
@app = app
|
||||||
@locales_glob = File.join(app.locales_dir, "**", "*.{rb,yml,yaml}")
|
@locales_glob = File.join(app.locales_dir, "**", "*.{rb,yml,yaml}")
|
||||||
|
|
||||||
|
# File.fnmatch doesn't support brackets: {rb,yml,yaml}
|
||||||
regex = @locales_glob.sub(/\./, '\.').sub(File.join("**", "*"), ".*").sub(/\//, '\/').sub("{rb,yml,yaml}", "rb|ya?ml")
|
regex = @locales_glob.sub(/\./, '\.').sub(File.join("**", "*"), ".*").sub(/\//, '\/').sub("{rb,yml,yaml}", "rb|ya?ml")
|
||||||
@locales_regex = %r{^#{regex}}
|
@locales_regex = %r{^#{regex}}
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ module Middleman
|
||||||
@mount_at_root = @options.has_key?(:mount_at_root) ? @options[:mount_at_root] : langs.first
|
@mount_at_root = @options.has_key?(:mount_at_root) ? @options[:mount_at_root] : langs.first
|
||||||
|
|
||||||
if !@app.build?
|
if !@app.build?
|
||||||
logger.info "== Locales: #{langs.join(", ")}"
|
logger.info "== Locales: #{langs.join(", ")} (Default #{@mount_at_root})"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Don't output localizable files
|
# Don't output localizable files
|
||||||
|
@ -52,15 +53,20 @@ module Middleman
|
||||||
@app.sitemap.provides_metadata_for_path do |url|
|
@app.sitemap.provides_metadata_for_path do |url|
|
||||||
if d = get_localization_data(url)
|
if d = get_localization_data(url)
|
||||||
lang, page_id = d
|
lang, page_id = d
|
||||||
instance_vars = Proc.new {
|
else
|
||||||
|
# Default to the @mount_at_root lang
|
||||||
|
page_id = nil
|
||||||
|
lang = @mount_at_root
|
||||||
|
end
|
||||||
|
|
||||||
|
instance_vars = Proc.new do
|
||||||
::I18n.locale = lang
|
::I18n.locale = lang
|
||||||
@lang = lang
|
@lang = lang
|
||||||
@page_id = page_id
|
@page_id = page_id
|
||||||
}
|
|
||||||
{ :blocks => [instance_vars] }
|
|
||||||
else
|
|
||||||
{}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
locals = { :lang => lang, :page_id => page_id }
|
||||||
|
{ :blocks => [instance_vars], :locals => locals }
|
||||||
end
|
end
|
||||||
|
|
||||||
@app.sitemap.register_resource_list_manipulator(
|
@app.sitemap.register_resource_list_manipulator(
|
||||||
|
@ -73,13 +79,15 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_file_changed(file)
|
def on_file_changed(file)
|
||||||
if @locales_regex.match(file)
|
if @locales_regex =~ file
|
||||||
::I18n.reload!
|
::I18n.reload!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def langs
|
def langs
|
||||||
@options[:langs] || begin
|
if @options[:langs]
|
||||||
|
Array(@options[:langs]).map(&:to_sym)
|
||||||
|
else
|
||||||
Dir[File.join(@app.root, @locales_glob)].map { |file|
|
Dir[File.join(@app.root, @locales_glob)].map { |file|
|
||||||
File.basename(file).sub(/\.ya?ml$/, "").sub(/\.rb$/, "")
|
File.basename(file).sub(/\.ya?ml$/, "").sub(/\.rb$/, "")
|
||||||
}.sort.map(&:to_sym)
|
}.sort.map(&:to_sym)
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Middleman
|
||||||
params[:alt] ||= ""
|
params[:alt] ||= ""
|
||||||
|
|
||||||
real_path = path
|
real_path = path
|
||||||
real_path = File.join(images_dir, real_path) unless real_path =~ %r{^/}
|
real_path = File.join(images_dir, real_path) unless real_path.start_with?('/')
|
||||||
full_path = File.join(source_dir, real_path)
|
full_path = File.join(source_dir, real_path)
|
||||||
|
|
||||||
if File.exists?(full_path)
|
if File.exists?(full_path)
|
||||||
|
|
|
@ -36,7 +36,7 @@ module Middleman
|
||||||
path
|
path
|
||||||
else
|
else
|
||||||
current_dir = Pathname('/' + current_resource.destination_path)
|
current_dir = Pathname('/' + current_resource.destination_path)
|
||||||
Pathname(path).relative_path_from(current_dir.dirname)
|
Pathname(path).relative_path_from(current_dir.dirname).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
2
vendor.yml
Normal file
2
vendor.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
- fixtures
|
||||||
|
- templates
|
Loading…
Reference in a new issue