merge in fixes from stable
This commit is contained in:
commit
fdabd87957
|
@ -29,8 +29,6 @@ HashSyntax:
|
||||||
EnforcedStyle: ruby19
|
EnforcedStyle: ruby19
|
||||||
SpaceAroundEqualsInParameterDefault:
|
SpaceAroundEqualsInParameterDefault:
|
||||||
EnforcedStyle: no_space
|
EnforcedStyle: no_space
|
||||||
BlockDelimiters:
|
|
||||||
Enabled: false
|
|
||||||
PerlBackrefs:
|
PerlBackrefs:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
ClassAndModuleChildren:
|
ClassAndModuleChildren:
|
||||||
|
|
|
@ -5,8 +5,6 @@ before_script:
|
||||||
- bundle update
|
- bundle update
|
||||||
rvm:
|
rvm:
|
||||||
- ruby-head
|
- ruby-head
|
||||||
- jruby-head
|
|
||||||
- jruby-19mode
|
|
||||||
- 2.2.2
|
- 2.2.2
|
||||||
- 2.1
|
- 2.1
|
||||||
- 2.0
|
- 2.0
|
||||||
|
@ -17,13 +15,10 @@ matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- rvm: ruby-head
|
- rvm: ruby-head
|
||||||
- rvm: jruby-19mode
|
|
||||||
- rvm: jruby-head
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- JRUBY_OPTS='-J-Xmx1024M'
|
|
||||||
- TEST=true
|
- TEST=true
|
||||||
- CODECLIMATE_REPO_TOKEN=81787f7b1c3bfa937edadcafbc94f807bf5af5c1142c7b793f2d9969a271de1f
|
- CODECLIMATE_REPO_TOKEN=81787f7b1c3bfa937edadcafbc94f807bf5af5c1142c7b793f2d9969a271de1f
|
||||||
script: bundle exec rake test
|
script: bundle exec rake test
|
||||||
notifications:
|
notifications:
|
||||||
slack: middleman:JW9OvXmn1m3XrSERe8866nBR
|
slack: middleman:JW9OvXmn1m3XrSERe8866nBR
|
||||||
|
|
10
Gemfile
10
Gemfile
|
@ -6,6 +6,7 @@ gem 'yard', '~> 0.8', require: false
|
||||||
|
|
||||||
# Test tools
|
# Test tools
|
||||||
gem 'pry', '~> 0.10', group: :development, require: false
|
gem 'pry', '~> 0.10', group: :development, require: false
|
||||||
|
gem 'pry-byebug'
|
||||||
gem 'aruba', '~> 0.7.4', require: false
|
gem 'aruba', '~> 0.7.4', require: false
|
||||||
gem 'rspec', '~> 3.0', require: false
|
gem 'rspec', '~> 3.0', require: false
|
||||||
gem 'cucumber', '~> 2.0', require: false
|
gem 'cucumber', '~> 2.0', require: false
|
||||||
|
@ -22,18 +23,25 @@ gem 'sinatra', '>= 1.4', require: false
|
||||||
gem 'redcarpet', '>= 3.1', require: false unless RUBY_ENGINE == 'jruby'
|
gem 'redcarpet', '>= 3.1', require: false unless RUBY_ENGINE == 'jruby'
|
||||||
gem 'asciidoctor', '~> 0.1', require: false
|
gem 'asciidoctor', '~> 0.1', require: false
|
||||||
|
|
||||||
|
# Dns server to test preview server
|
||||||
|
gem 'rubydns', '~> 1.0.1', require: false
|
||||||
|
|
||||||
|
# To test javascript
|
||||||
|
gem 'poltergeist', '~> 1.6.0', require: false
|
||||||
|
|
||||||
# For less, note there is no compatible JS runtime for windows
|
# For less, note there is no compatible JS runtime for windows
|
||||||
gem 'therubyrhino', '>= 2.0', platforms: :jruby
|
gem 'therubyrhino', '>= 2.0', platforms: :jruby
|
||||||
gem 'therubyracer', '>= 0.12', platforms: :ruby
|
gem 'therubyracer', '>= 0.12', platforms: :ruby
|
||||||
|
|
||||||
# Code Quality
|
# Code Quality
|
||||||
gem 'rubocop', '~> 0.24', require: false
|
gem 'rubocop', '~> 0.24', require: false
|
||||||
gem 'simplecov', '~> 0.9', require: false
|
gem 'simplecov', '~> 0.10', require: false
|
||||||
gem 'coveralls', '~> 0.8', require: false
|
gem 'coveralls', '~> 0.8', require: false
|
||||||
gem 'codeclimate-test-reporter', '~> 0.3', require: false, group: :test
|
gem 'codeclimate-test-reporter', '~> 0.3', require: false, group: :test
|
||||||
|
|
||||||
# Middleman itself
|
# Middleman itself
|
||||||
gem 'middleman-cli', path: 'middleman-cli'
|
gem 'middleman-cli', path: 'middleman-cli'
|
||||||
gem 'middleman-core', path: 'middleman-core'
|
gem 'middleman-core', path: 'middleman-core'
|
||||||
|
|
||||||
# gem 'middleman-compass', github: 'middleman/middleman-compass', require: false
|
# gem 'middleman-compass', github: 'middleman/middleman-compass', require: false
|
||||||
# gem 'middleman-sprockets', github: 'middleman/middleman-sprockets', require: false
|
# gem 'middleman-sprockets', github: 'middleman/middleman-sprockets', require: false
|
||||||
|
|
|
@ -21,16 +21,14 @@ Cucumber::Rake::Task.new do |t|
|
||||||
exempt_tags << '--tags ~@encoding' unless Object.const_defined?(:Encoding)
|
exempt_tags << '--tags ~@encoding' unless Object.const_defined?(:Encoding)
|
||||||
exempt_tags << '--tags ~@nowindows' if Gem.win_platform?
|
exempt_tags << '--tags ~@nowindows' if Gem.win_platform?
|
||||||
exempt_tags << '--tags ~@travishatesme' if ENV['TRAVIS'] == 'true'
|
exempt_tags << '--tags ~@travishatesme' if ENV['TRAVIS'] == 'true'
|
||||||
t.cucumber_opts = "--require features --color #{exempt_tags.join(' ')} --strict"
|
t.cucumber_opts = "--require features --color #{exempt_tags.join(' ')} --strict" # --format #{ENV['CUCUMBER_FORMAT'] || 'Fivemat'}"
|
||||||
end
|
end
|
||||||
|
|
||||||
Cucumber::Rake::Task.new(:cucumber_wip) do |t|
|
Cucumber::Rake::Task.new(:cucumber_wip) do |t|
|
||||||
exempt_tags = ['--tags @wip']
|
exempt_tags = ['--tags @wip']
|
||||||
exempt_tags << '--tags ~@nojava' if RUBY_PLATFORM == 'java'
|
|
||||||
exempt_tags << '--tags ~@encoding' unless Object.const_defined?(:Encoding)
|
exempt_tags << '--tags ~@encoding' unless Object.const_defined?(:Encoding)
|
||||||
exempt_tags << '--tags ~@nowindows' if Gem.win_platform?
|
exempt_tags << '--tags ~@nowindows' if Gem.win_platform?
|
||||||
exempt_tags << '--tags ~@travishatesme' if ENV['TRAVIS'] == 'true'
|
t.cucumber_opts = "--require features --color #{exempt_tags.join(' ')} --strict" # --format #{ENV['CUCUMBER_FORMAT'] || 'Fivemat'}"
|
||||||
t.cucumber_opts = "--require features --color #{exempt_tags.join(' ')} --strict"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'rspec/core/rake_task'
|
require 'rspec/core/rake_task'
|
||||||
|
|
|
@ -8,13 +8,22 @@ module Middleman::Cli
|
||||||
aliases: '-e',
|
aliases: '-e',
|
||||||
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
|
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
|
||||||
desc: 'The environment Middleman will run under'
|
desc: 'The environment Middleman will run under'
|
||||||
class_option :host,
|
|
||||||
type: :string,
|
|
||||||
aliases: '-h',
|
|
||||||
desc: 'Bind to HOST address'
|
|
||||||
class_option :port,
|
class_option :port,
|
||||||
aliases: '-p',
|
aliases: '-p',
|
||||||
desc: 'The port Middleman will listen on'
|
desc: 'The port Middleman will listen on'
|
||||||
|
class_option :server_name,
|
||||||
|
aliases: '-s',
|
||||||
|
desc: 'The server name Middleman will use'
|
||||||
|
class_option :bind_address,
|
||||||
|
aliases: '-b',
|
||||||
|
desc: 'The bind address Middleman will listen on'
|
||||||
|
class_option :https,
|
||||||
|
type: :boolean,
|
||||||
|
desc: 'Serve the preview server over SSL/TLS'
|
||||||
|
class_option :ssl_certificate,
|
||||||
|
desc: 'Path to an X.509 certificate to use for the preview server'
|
||||||
|
class_option :ssl_private_key,
|
||||||
|
desc: "Path to an RSA private key for the preview server's certificate"
|
||||||
class_option :verbose,
|
class_option :verbose,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -53,7 +62,11 @@ module Middleman::Cli
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
port: options['port'],
|
port: options['port'],
|
||||||
host: options['host'],
|
bind_address: options['bind_address'],
|
||||||
|
https: options['https'],
|
||||||
|
server_name: options['server_name'],
|
||||||
|
ssl_certificate: options['ssl_certificate'],
|
||||||
|
ssl_private_key: options['ssl_private_key'],
|
||||||
environment: options['environment'],
|
environment: options['environment'],
|
||||||
debug: options['verbose'],
|
debug: options['verbose'],
|
||||||
instrumenting: options['instrument'],
|
instrumenting: options['instrument'],
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
--color
|
--color
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
default: --require features --tags ~@wip
|
default: --require features --tags ~@wip
|
||||||
wip: --require features --tags @wip
|
wip: --require features --tags @wip
|
||||||
|
|
|
@ -12,7 +12,7 @@ Feature: Assets get file hashes appended to them and references to them are upda
|
||||||
| images/300px-59adce76.jpg |
|
| images/300px-59adce76.jpg |
|
||||||
| images/100px-5fd6fb90.gif |
|
| images/100px-5fd6fb90.gif |
|
||||||
| javascripts/application-1d8d5276.js |
|
| javascripts/application-1d8d5276.js |
|
||||||
| stylesheets/site-7474cadd.css |
|
| stylesheets/site-8bc55985.css |
|
||||||
| index.html |
|
| index.html |
|
||||||
| subdir/index.html |
|
| subdir/index.html |
|
||||||
| other/index.html |
|
| other/index.html |
|
||||||
|
@ -26,21 +26,21 @@ Feature: Assets get file hashes appended to them and references to them are upda
|
||||||
| stylesheets/site.css |
|
| stylesheets/site.css |
|
||||||
|
|
||||||
And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'"
|
And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'"
|
||||||
And the file "stylesheets/site-7474cadd.css" should contain:
|
And the file "stylesheets/site-8bc55985.css" should contain:
|
||||||
"""
|
"""
|
||||||
background-image: url("../images/100px-5fd6fb90.jpg")
|
background-image: url("../images/100px-5fd6fb90.jpg")
|
||||||
"""
|
"""
|
||||||
And the file "index.html" should contain 'href="apple-touch-icon.png"'
|
And the file "index.html" should contain 'href="apple-touch-icon.png"'
|
||||||
And the file "index.html" should contain 'href="stylesheets/site-7474cadd.css"'
|
And the file "index.html" should contain 'href="stylesheets/site-8bc55985.css"'
|
||||||
And the file "index.html" should contain 'src="javascripts/application-1d8d5276.js"'
|
And the file "index.html" should contain 'src="javascripts/application-1d8d5276.js"'
|
||||||
And the file "index.html" should contain 'src="images/100px-5fd6fb90.jpg"'
|
And the file "index.html" should contain 'src="images/100px-5fd6fb90.jpg"'
|
||||||
And the file "subdir/index.html" should contain 'href="../stylesheets/site-7474cadd.css"'
|
And the file "subdir/index.html" should contain 'href="../stylesheets/site-8bc55985.css"'
|
||||||
And the file "index.html" should contain 'srcset="images/100px-5fd6fb90.jpg 1x, images/200px-c11eb203.jpg 2x, images/300px-59adce76.jpg 3x"'
|
And the file "index.html" should contain 'srcset="images/100px-5fd6fb90.jpg 1x, images/200px-c11eb203.jpg 2x, images/300px-59adce76.jpg 3x"'
|
||||||
And the file "index.html" should contain 'src="images/100px-5fd6fb90.gif"'
|
And the file "index.html" should contain 'src="images/100px-5fd6fb90.gif"'
|
||||||
And the file "index.html" should contain 'src="images/100px-1242c368.png"'
|
And the file "index.html" should contain 'src="images/100px-1242c368.png"'
|
||||||
And the file "subdir/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
|
And the file "subdir/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
|
||||||
And the file "subdir/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
|
And the file "subdir/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
|
||||||
And the file "other/index.html" should contain 'href="../stylesheets/site-7474cadd.css"'
|
And the file "other/index.html" should contain 'href="../stylesheets/site-8bc55985.css"'
|
||||||
And the file "other/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
|
And the file "other/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
|
||||||
And the file "other/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
|
And the file "other/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
|
||||||
And the file "api.json" should contain 'images/100px-5fd6fb90.gif'
|
And the file "api.json" should contain 'images/100px-5fd6fb90.gif'
|
||||||
|
@ -50,6 +50,15 @@ Feature: Assets get file hashes appended to them and references to them are upda
|
||||||
And the file "subdir/api.json" should contain 'images/100px-5fd6fb90.jpg'
|
And the file "subdir/api.json" should contain 'images/100px-5fd6fb90.jpg'
|
||||||
And the file "subdir/api.json" should contain 'images/100px-1242c368.png'
|
And the file "subdir/api.json" should contain 'images/100px-1242c368.png'
|
||||||
|
|
||||||
|
Scenario: Hashed fonts assets work with woff and woff2 extension
|
||||||
|
Given a successfully built app at "asset-hash-app"
|
||||||
|
When I cd to "build"
|
||||||
|
Then the following files should exist:
|
||||||
|
| fonts/fontawesome-webfont-56ce13e7.woff |
|
||||||
|
| fonts/fontawesome-webfont-10752316.woff2 |
|
||||||
|
And the file "stylesheets/uses_fonts-88aa3e2b.css" should contain "src: url('../fonts/fontawesome-webfont-10752316.woff2')"
|
||||||
|
And the file "stylesheets/uses_fonts-88aa3e2b.css" should contain "url('../fonts/fontawesome-webfont-56ce13e7.woff')"
|
||||||
|
|
||||||
Scenario: Hashed assets work in preview server
|
Scenario: Hashed assets work in preview server
|
||||||
Given the Server is running at "asset-hash-app"
|
Given the Server is running at "asset-hash-app"
|
||||||
When I go to "/"
|
When I go to "/"
|
||||||
|
|
532
middleman-core/features/cli/preview_server.feature
Normal file
532
middleman-core/features/cli/preview_server.feature
Normal file
|
@ -0,0 +1,532 @@
|
||||||
|
Feature: Run the preview server
|
||||||
|
|
||||||
|
As a software developer
|
||||||
|
I want to start the preview server
|
||||||
|
In order to view my changes immediately in the browser
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a fixture app "preview-server-app"
|
||||||
|
And the default aruba timeout is 30 seconds
|
||||||
|
|
||||||
|
Scenario: Start the server with defaults
|
||||||
|
When I run `middleman server` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with defaults in verbose mode
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::4567", "0.0.0.0:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://
|
||||||
|
"""
|
||||||
|
|
||||||
|
@ruby-2.1
|
||||||
|
Scenario: Start the server with defaults in verbose mode, when a local mdns server resolves the local hostname
|
||||||
|
Given I start a mdns server for the local hostname
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::4567", "0.0.0.0:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address 127.0.0.1
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
127.0.0.1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --bind-address 127.0.0.1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address 127.0.0.1 configured via config.rb
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
127.0.0.1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :bind_address, '127.0.0.1'
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address 127.0.0.5
|
||||||
|
|
||||||
|
This will have no hostname attached because the hosts file, the DNS server
|
||||||
|
and the MDNS-server do not know anything about 127.0.0.5
|
||||||
|
|
||||||
|
When I run `middleman server --verbose --bind-address 127.0.0.5` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.5:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://127.0.0.5:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://127.0.0.5:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address ::1
|
||||||
|
Given a file named ".hosts" with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
::1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --bind-address ::1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "::1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://[::1]:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://[::1]:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address 0.0.0.0
|
||||||
|
When I run `middleman server --verbose --bind-address 0.0.0.0` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "0.0.0.0:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address ::
|
||||||
|
When I run `middleman server --verbose --bind-address ::` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "localhost"
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
127.0.0.1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name localhost` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://localhost:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://localhost:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "localhost" configured via config.rb
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
127.0.0.1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :server_name, 'localhost'
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://localhost:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://localhost:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "localhost" and bind address "127.0.0.1"
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# <ip-address> <hostname.domain.org> <hostname>
|
||||||
|
127.0.0.1 localhost.localdomain localhost
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name localhost --bind-address 127.0.0.1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://localhost:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://localhost:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "127.0.0.1"
|
||||||
|
When I run `middleman server --verbose --server-name 127.0.0.1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "::1"
|
||||||
|
When I run `middleman server --verbose --server-name ::1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "::1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://[::1]:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://[::1]:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with https
|
||||||
|
When I run `middleman server --verbose --https` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::4567", "0.0.0.0:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "https://
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "https://
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with port 65432
|
||||||
|
When I run `middleman server --verbose --port 65432` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::65432", "0.0.0.0:65432"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with port 65432 configured via config.rb
|
||||||
|
Given a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :port, 65432
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to ":::65432", "0.0.0.0:65432"
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server when port is blocked by other middleman instance
|
||||||
|
Given `middleman server` is running in background
|
||||||
|
When I run `middleman server --verbose` interactively
|
||||||
|
And I stop all commands if the output of the last command contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman uses a different port
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with bind address 1.1.1.1
|
||||||
|
|
||||||
|
This should fail, because "1.1.1.1" is not an interface available on this computer.
|
||||||
|
|
||||||
|
Given a file named ".hosts" with:
|
||||||
|
"""
|
||||||
|
1.1.1.1 www.example.com www
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --bind-address 1.1.1.1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Running Middleman failed:
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
Bind address "1.1.1.1" is not available on your system
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name www.example.com and bind address 0.0.0.0
|
||||||
|
|
||||||
|
This should fail, because the user can just use `--server-name`. It does
|
||||||
|
not make sense for `middleman` to only listen on `0.0.0.0` (IPv4 all
|
||||||
|
interfaces), but not on `::` (IPv6 all interfaces). There are other tools
|
||||||
|
like `iptables` (Linux-only) or better some `kernel`-configurations to make
|
||||||
|
this possible.
|
||||||
|
|
||||||
|
When I run `middleman server --verbose --server-name www.example.com --bind-address 0.0.0.0` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Running Middleman failed:
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
Undefined combination of options "--server-name" and "--bind-address".
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "www.example.com" and bind address "127.0.0.1"
|
||||||
|
|
||||||
|
This should fail because the server name does not resolve to the ip address.
|
||||||
|
|
||||||
|
Given a file named ".hosts" with:
|
||||||
|
"""
|
||||||
|
1.1.1.1 www.example.com www
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name www.example.com --bind-address 127.0.0.1` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Running Middleman failed:
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
Server name "www.example.com" does not resolve to bind address "127.0.0.1". Please fix that and try again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "garbage.example.com"
|
||||||
|
When I run `middleman server --verbose --server-name garbage.example.com` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Running Middleman failed:
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
Server name "garbage.example.com" does not resolve to an ip address. Please fix that and try again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Start the server with server name "www.example.com" and the network name server is used to resolve the server name
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# empty
|
||||||
|
"""
|
||||||
|
And I start a mdns server with:
|
||||||
|
"""
|
||||||
|
# empty
|
||||||
|
"""
|
||||||
|
And I start a dns server with:
|
||||||
|
"""
|
||||||
|
www.example.com: 127.0.0.1
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name www.example.com` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://www.example.com:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://www.example.com:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
@ruby-2.1
|
||||||
|
Scenario: Start the server with server name "host.local" and the link local name server is used to resolve the server name
|
||||||
|
|
||||||
|
To make the mdns resolver resolve a name, it needs to end with ".local".
|
||||||
|
Otherwise the resolver returns [].
|
||||||
|
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# empty
|
||||||
|
"""
|
||||||
|
And I start a mdns server with:
|
||||||
|
"""
|
||||||
|
host.local: 127.0.0.1
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name host.local` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://host.local:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://host.local:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
||||||
|
|
||||||
|
@ruby-2.1
|
||||||
|
Scenario: Start the server with server name "host" and the link local name server is used to resolve the server name
|
||||||
|
|
||||||
|
To make the mdns resolver resolve a name, it needs to end with ".local". If
|
||||||
|
a plain hostname is given `middleman` appends ".local" automatically.
|
||||||
|
|
||||||
|
Given I have a local hosts file with:
|
||||||
|
"""
|
||||||
|
# empty
|
||||||
|
"""
|
||||||
|
And I start a mdns server with:
|
||||||
|
"""
|
||||||
|
host.local: 127.0.0.1
|
||||||
|
"""
|
||||||
|
When I run `middleman server --verbose --server-name host` interactively
|
||||||
|
And I stop middleman if the output contains:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration
|
||||||
|
"""
|
||||||
|
Then the output should contain:
|
||||||
|
"""
|
||||||
|
The Middleman preview server is bound to "127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
View your site at "http://host.local:4567", "http://127.0.0.1:4567"
|
||||||
|
"""
|
||||||
|
And the output should contain:
|
||||||
|
"""
|
||||||
|
Inspect your site configuration at "http://host.local:4567/__middleman", "http://127.0.0.1:4567/__middleman"
|
||||||
|
"""
|
|
@ -12,6 +12,8 @@ Feature: Setting the right content type for files
|
||||||
Then the content type should be "text/css"
|
Then the content type should be "text/css"
|
||||||
When I go to "/README"
|
When I go to "/README"
|
||||||
Then the content type should be "text/plain"
|
Then the content type should be "text/plain"
|
||||||
|
When I go to "/index.php"
|
||||||
|
Then the content type should be "text/php"
|
||||||
|
|
||||||
Scenario: Content type can be set explicitly via page or proxy or frontmatter
|
Scenario: Content type can be set explicitly via page or proxy or frontmatter
|
||||||
Given a fixture app "content-type-app"
|
Given a fixture app "content-type-app"
|
||||||
|
@ -31,6 +33,7 @@ Feature: Setting the right content type for files
|
||||||
When I go to "/override.html"
|
When I go to "/override.html"
|
||||||
Then the content type should be "text/neato"
|
Then the content type should be "text/neato"
|
||||||
|
|
||||||
|
@preserve_mime_types
|
||||||
Scenario: Content types can be overridden with mime_type
|
Scenario: Content types can be overridden with mime_type
|
||||||
Given a fixture app "content-type-app"
|
Given a fixture app "content-type-app"
|
||||||
And a file named "config.rb" with:
|
And a file named "config.rb" with:
|
||||||
|
|
209
middleman-core/features/i18n_link_to.feature
Normal file
209
middleman-core/features/i18n_link_to.feature
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
Feature: i18n Paths
|
||||||
|
|
||||||
|
Scenario: link_to is i18n aware
|
||||||
|
Given a fixture app "empty-app"
|
||||||
|
And a file named "data/pages.yml" with:
|
||||||
|
"""
|
||||||
|
- hello.html
|
||||||
|
"""
|
||||||
|
And a file named "locales/en.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
msg: Hello
|
||||||
|
home: Home
|
||||||
|
"""
|
||||||
|
And a file named "locales/es.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
es:
|
||||||
|
paths:
|
||||||
|
hello: "hola"
|
||||||
|
msg: Hola
|
||||||
|
home: Casa
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/index.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page: <%= t(:hom) %>
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/hello.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page: <%= t(:msg) %>
|
||||||
|
|
||||||
|
<%= link_to "Current Home", "/index.html", class: 'current' %>
|
||||||
|
<%= link_to "Other Home", "/index.html", title: "Other Home", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
<% link_to "/index.html", class: 'current' do %><span>Home: Current Block</span><% end %>
|
||||||
|
<% link_to "/index.html", title: "Other Home", locale: ::I18n.locale == :en ? :es : :en do %><span>Home: Other Block</span><% end %>
|
||||||
|
|
||||||
|
<% data.pages.each_with_index do |p, i| %>
|
||||||
|
<%= link_to "Current #{p}", "/#{p}", class: 'current' %>
|
||||||
|
<%= link_to "Other #{p}", "/#{p}", title: "Other #{p}", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
<% link_to "/#{p}", class: 'current' do %><span>Current Block</span><% end %>
|
||||||
|
<% link_to "/#{p}", title: "Other #{p}", locale: ::I18n.locale == :en ? :es : :en do %><span>Other Block</span><% end %>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :strip_index_file, false
|
||||||
|
activate :i18n, mount_at_root: :en
|
||||||
|
"""
|
||||||
|
Given the Server is running at "empty-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see "Page: Hello"
|
||||||
|
Then I should see '<a class="current" href="/index.html">Current Home</a>'
|
||||||
|
Then I should see '<a title="Other Home" href="/es/index.html">Other Home</a>'
|
||||||
|
Then I should see '<a class="current" href="/index.html"><span>Home: Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other Home" href="/es/index.html"><span>Home: Other Block</span></a>'
|
||||||
|
Then I should see '<a class="current" href="/hello.html">Current hello.html</a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="/es/hola.html">Other hello.html</a>'
|
||||||
|
Then I should see '<a class="current" href="/hello.html"><span>Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="/es/hola.html"><span>Other Block</span></a>'
|
||||||
|
When I go to "/es/hola.html"
|
||||||
|
Then I should see "Page: Hola"
|
||||||
|
Then I should see '<a class="current" href="/es/index.html">Current Home</a>'
|
||||||
|
Then I should see '<a title="Other Home" href="/index.html">Other Home</a>'
|
||||||
|
Then I should see '<a class="current" href="/es/index.html"><span>Home: Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other Home" href="/index.html"><span>Home: Other Block</span></a>'
|
||||||
|
Then I should see '<a class="current" href="/es/hola.html">Current hello.html</a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="/hello.html">Other hello.html</a>'
|
||||||
|
Then I should see '<a class="current" href="/es/hola.html"><span>Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="/hello.html"><span>Other Block</span></a>'
|
||||||
|
|
||||||
|
Scenario: link_to is i18n aware and supports relative_links
|
||||||
|
Given a fixture app "empty-app"
|
||||||
|
And a file named "locales/en.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
msg: Hello
|
||||||
|
home: Home
|
||||||
|
"""
|
||||||
|
And a file named "locales/es.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
es:
|
||||||
|
paths:
|
||||||
|
hello: "hola"
|
||||||
|
msg: Hola
|
||||||
|
home: Casa
|
||||||
|
"""
|
||||||
|
And a file named "source/assets/css/main.css.scss" with:
|
||||||
|
"""
|
||||||
|
$color: red;
|
||||||
|
body { background: $color; }
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/index.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page: <%= t(:home) %>
|
||||||
|
<%= stylesheet_link_tag :main %>
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/hello.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page: <%= t(:msg) %>
|
||||||
|
|
||||||
|
<%= link_to "Current Home", "/index.html", class: 'current' %>
|
||||||
|
<%= link_to "Other Home", "/index.html", title: "Other Home", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
<% link_to "/index.html", class: 'current' do %><span>Home: Current Block</span><% end %>
|
||||||
|
<% link_to "/index.html", title: "Other Home", locale: ::I18n.locale == :en ? :es : :en do %><span>Home: Other Block</span><% end %>
|
||||||
|
|
||||||
|
<%= link_to "Current hello.html", "/hello.html", class: 'current' %>
|
||||||
|
<%= link_to "Other hello.html", "/hello.html", title: "Other hello.html", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
<% link_to "/hello.html", class: 'current' do %><span>Current Block</span><% end %>
|
||||||
|
<% link_to "/hello.html", title: "Other hello.html", locale: ::I18n.locale == :en ? :es : :en do %><span>Other Block</span><% end %>
|
||||||
|
"""
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
set :css_dir, 'assets/css'
|
||||||
|
set :relative_links, true
|
||||||
|
set :strip_index_file, false
|
||||||
|
activate :i18n, mount_at_root: :en
|
||||||
|
activate :relative_assets
|
||||||
|
"""
|
||||||
|
Given the Server is running at "empty-app"
|
||||||
|
When I go to "/index.html"
|
||||||
|
Then I should see "assets/css/main.css"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see "Page: Hello"
|
||||||
|
Then I should see '<a class="current" href="index.html">Current Home</a>'
|
||||||
|
Then I should see '<a title="Other Home" href="es/index.html">Other Home</a>'
|
||||||
|
Then I should see '<a class="current" href="index.html"><span>Home: Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other Home" href="es/index.html"><span>Home: Other Block</span></a>'
|
||||||
|
Then I should see '<a class="current" href="hello.html">Current hello.html</a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="es/hola.html">Other hello.html</a>'
|
||||||
|
Then I should see '<a class="current" href="hello.html"><span>Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="es/hola.html"><span>Other Block</span></a>'
|
||||||
|
When I go to "/es/hola.html"
|
||||||
|
Then I should see "Page: Hola"
|
||||||
|
Then I should see '<a class="current" href="index.html">Current Home</a>'
|
||||||
|
Then I should see '<a title="Other Home" href="../index.html">Other Home</a>'
|
||||||
|
Then I should see '<a class="current" href="index.html"><span>Home: Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other Home" href="../index.html"><span>Home: Other Block</span></a>'
|
||||||
|
Then I should see '<a class="current" href="hola.html">Current hello.html</a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="../hello.html">Other hello.html</a>'
|
||||||
|
Then I should see '<a class="current" href="hola.html"><span>Current Block</span></a>'
|
||||||
|
Then I should see '<a title="Other hello.html" href="../hello.html"><span>Other Block</span></a>'
|
||||||
|
|
||||||
|
Scenario: url_for is i18n aware
|
||||||
|
Given a fixture app "empty-app"
|
||||||
|
And a file named "data/pages.yml" with:
|
||||||
|
"""
|
||||||
|
- hello.html
|
||||||
|
- article.html
|
||||||
|
"""
|
||||||
|
And a file named "locales/en.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
msg: Hello
|
||||||
|
"""
|
||||||
|
And a file named "locales/es.yml" with:
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
es:
|
||||||
|
paths:
|
||||||
|
hello: "hola"
|
||||||
|
msg: Hola
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/hello.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page: <%= t(:msg) %>
|
||||||
|
<% data.pages.each_with_index do |p, i| %>
|
||||||
|
Current: <%= url_for "/#{p}" %>
|
||||||
|
Other: <%= url_for "/#{p}", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/article.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page Lang: Default
|
||||||
|
|
||||||
|
Current: <%= url_for "/article.html" %>
|
||||||
|
Other: <%= url_for "/article.html", locale: ::I18n.locale == :en ? :es : :en %>
|
||||||
|
"""
|
||||||
|
And a file named "source/localizable/article.es.html.erb" with:
|
||||||
|
"""
|
||||||
|
Page Lang: Spanish
|
||||||
|
|
||||||
|
Current: <%= url_for "/article.html" %>
|
||||||
|
Other: <%= url_for "/article.html", locale: :en %>
|
||||||
|
"""
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :i18n, mount_at_root: :en
|
||||||
|
"""
|
||||||
|
Given the Server is running at "empty-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see "Page: Hello"
|
||||||
|
Then I should see 'Current: /hello.html'
|
||||||
|
Then I should see 'Other: /es/hola.html'
|
||||||
|
When I go to "/es/hola.html"
|
||||||
|
Then I should see "Page: Hola"
|
||||||
|
Then I should see 'Current: /es/hola.html'
|
||||||
|
Then I should see 'Other: /hello.html'
|
||||||
|
When I go to "/article.html"
|
||||||
|
Then I should see "Page Lang: Default"
|
||||||
|
Then I should see 'Current: /article.html'
|
||||||
|
Then I should see 'Other: /es/article.html'
|
||||||
|
When I go to "/es/article.html"
|
||||||
|
Then I should see "Page Lang: Spanish"
|
||||||
|
Then I should see 'Current: /es/article.html'
|
||||||
|
Then I should see 'Other: /article.html'
|
18
middleman-core/features/javascript-testing.feature
Normal file
18
middleman-core/features/javascript-testing.feature
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Feature: Test a site with javascript included
|
||||||
|
|
||||||
|
As a software developer
|
||||||
|
I want to develop a site using javascript
|
||||||
|
I would like to have a server step rendering javascript correctly in order to test it
|
||||||
|
|
||||||
|
@javascript
|
||||||
|
Scenario: Existing app with javascript
|
||||||
|
Given the Server is running at "javascript-app"
|
||||||
|
When I go to "/index.html"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
Local Hour
|
||||||
|
"""
|
||||||
|
And I should see:
|
||||||
|
"""
|
||||||
|
Local Minutes
|
||||||
|
"""
|
|
@ -1,4 +1,3 @@
|
||||||
@nojava
|
|
||||||
Feature: Markdown (Redcarpet) support
|
Feature: Markdown (Redcarpet) support
|
||||||
In order to test included Redcarpet support
|
In order to test included Redcarpet support
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@nojava
|
|
||||||
Feature: Markdown support in Haml
|
Feature: Markdown support in Haml
|
||||||
In order to test support of the Haml markdown filter
|
In order to test support of the Haml markdown filter
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,18 @@ Feature: Minify CSS
|
||||||
When I go to "/stylesheets/report.css"
|
When I go to "/stylesheets/report.css"
|
||||||
Then I should see "p{border:1px solid #ff6600}"
|
Then I should see "p{border:1px solid #ff6600}"
|
||||||
|
|
||||||
|
Scenario: Rendering external css in a proxied resource
|
||||||
|
Given a fixture app "minify-css-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_css
|
||||||
|
proxy '/css-proxy', '/stylesheets/site.css', ignore: true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-css-app"
|
||||||
|
When I go to "/css-proxy"
|
||||||
|
Then I should see "1" lines
|
||||||
|
And I should see "only screen and (device-width"
|
||||||
|
|
||||||
Scenario: Rendering external css with passthrough compressor
|
Scenario: Rendering external css with passthrough compressor
|
||||||
Given a fixture app "passthrough-app"
|
Given a fixture app "passthrough-app"
|
||||||
And a file named "config.rb" with:
|
And a file named "config.rb" with:
|
||||||
|
@ -120,4 +132,54 @@ Feature: Minify CSS
|
||||||
<style>
|
<style>
|
||||||
body{test:style;good:deal}
|
body{test:style;good:deal}
|
||||||
</style>
|
</style>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Rendering inline css in a PHP document
|
||||||
|
Given a fixture app "minify-css-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_css, :inline => true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-css-app"
|
||||||
|
When I go to "/inline-css.php"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
<?='Hello'?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body{test:style;good:deal}
|
||||||
|
</style>
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Rendering inline css in a proxied resource
|
||||||
|
Given a fixture app "minify-css-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_css, :inline => true
|
||||||
|
proxy '/inline-css-proxy', '/inline-css.html', ignore: true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-css-app"
|
||||||
|
When I go to "/inline-css-proxy"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
<style>
|
||||||
|
body{test:style;good:deal}
|
||||||
|
</style>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@preserve_mime_types
|
||||||
|
Scenario: Configuring content types of resources to be minified
|
||||||
|
Given a fixture app "minify-css-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
mime_type('.xcss', 'text/x-css')
|
||||||
|
activate :minify_css, content_types: ['text/x-css'],
|
||||||
|
inline: true,
|
||||||
|
inline_content_types: ['text/html']
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-css-app"
|
||||||
|
When I go to "/stylesheets/site.xcss"
|
||||||
|
Then I should see "1" lines
|
||||||
|
And I should see "only screen and (device-width"
|
||||||
|
When I go to "/inline-css.php"
|
||||||
|
Then I should see "8" lines
|
||||||
|
|
|
@ -86,7 +86,7 @@ Feature: Minify Javascript
|
||||||
</script>
|
</script>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Scenario: Rendering inline css with a passthrough minifier using activate-style compressor
|
Scenario: Rendering inline JS with a passthrough minifier using activate-style compressor
|
||||||
Given a fixture app "passthrough-app"
|
Given a fixture app "passthrough-app"
|
||||||
And a file named "config.rb" with:
|
And a file named "config.rb" with:
|
||||||
"""
|
"""
|
||||||
|
@ -146,6 +146,42 @@ Feature: Minify Javascript
|
||||||
</script>
|
</script>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Rendering inline js in a PHP document
|
||||||
|
Given a fixture app "minify-js-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_javascript, :inline => true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-js-app"
|
||||||
|
When I go to "/inline-js.php"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
<?='Hello'?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
!function(){should(),all.be(),on={one:line}}();
|
||||||
|
</script>
|
||||||
|
<script type='text/javascript'>
|
||||||
|
//<!--
|
||||||
|
!function(){one,line(),here()}();
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
<script type='text/html'>
|
||||||
|
I'm a jQuery {{template}}.
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Rendering inline js in a proxied resource
|
||||||
|
Given a fixture app "minify-js-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_javascript, :inline => true
|
||||||
|
proxy '/inline-js-proxy', '/inline-js.html', ignore: true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-js-app"
|
||||||
|
When I go to "/inline-js-proxy"
|
||||||
|
Then I should see "14" lines
|
||||||
|
|
||||||
Scenario: Rendering external js with the feature enabled
|
Scenario: Rendering external js with the feature enabled
|
||||||
Given a fixture app "minify-js-app"
|
Given a fixture app "minify-js-app"
|
||||||
And a file named "config.rb" with:
|
And a file named "config.rb" with:
|
||||||
|
@ -158,6 +194,17 @@ Feature: Minify Javascript
|
||||||
When I go to "/more-js/other.js"
|
When I go to "/more-js/other.js"
|
||||||
Then I should see "1" lines
|
Then I should see "1" lines
|
||||||
|
|
||||||
|
Scenario: Rendering external js in a proxied resource
|
||||||
|
Given a fixture app "minify-js-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :minify_javascript
|
||||||
|
proxy '/js-proxy', '/javascripts/js_test.js', ignore: true
|
||||||
|
"""
|
||||||
|
And the Server is running at "minify-js-app"
|
||||||
|
When I go to "/js-proxy"
|
||||||
|
Then I should see "1" lines
|
||||||
|
|
||||||
Scenario: Rendering external js with a passthrough minifier
|
Scenario: Rendering external js with a passthrough minifier
|
||||||
And the Server is running at "passthrough-app"
|
And the Server is running at "passthrough-app"
|
||||||
When I go to "/javascripts/js_test.js"
|
When I go to "/javascripts/js_test.js"
|
||||||
|
|
|
@ -8,6 +8,7 @@ Feature: Meta redirects
|
||||||
"""
|
"""
|
||||||
And the Server is running at "large-build-app"
|
And the Server is running at "large-build-app"
|
||||||
When I go to "/hello.html"
|
When I go to "/hello.html"
|
||||||
|
Then I should see '<link rel="canonical" href="world.html"'
|
||||||
Then I should see '<meta http-equiv=refresh content="0; url=world.html"'
|
Then I should see '<meta http-equiv=refresh content="0; url=world.html"'
|
||||||
|
|
||||||
Scenario: Redirect to external site
|
Scenario: Redirect to external site
|
||||||
|
|
|
@ -21,6 +21,12 @@ Feature: Relative Assets
|
||||||
Given "relative_assets" feature is "disabled"
|
Given "relative_assets" feature is "disabled"
|
||||||
And the Server is running at "relative-assets-app"
|
And the Server is running at "relative-assets-app"
|
||||||
When I go to "/relative_image.html"
|
When I go to "/relative_image.html"
|
||||||
|
Then I should see '"/stylesheets/relative_assets.css"'
|
||||||
|
Then I should see '"/javascripts/app.js"'
|
||||||
|
Then I should see "/images/blank.gif"
|
||||||
|
When I go to "/absolute_image_relative_css.html"
|
||||||
|
Then I should see '"stylesheets/relative_assets.css"'
|
||||||
|
Then I should see '"javascripts/app.js"'
|
||||||
Then I should see "/images/blank.gif"
|
Then I should see "/images/blank.gif"
|
||||||
|
|
||||||
Scenario: Rendering css with the feature enabled
|
Scenario: Rendering css with the feature enabled
|
||||||
|
@ -57,6 +63,11 @@ Feature: Relative Assets
|
||||||
Given "relative_assets" feature is "enabled"
|
Given "relative_assets" feature is "enabled"
|
||||||
And the Server is running at "relative-assets-app"
|
And the Server is running at "relative-assets-app"
|
||||||
When I go to "/relative_image.html"
|
When I go to "/relative_image.html"
|
||||||
|
Then I should see '"stylesheets/relative_assets.css"'
|
||||||
|
Then I should see '"javascripts/app.js"'
|
||||||
|
When I go to "/relative_image_absolute_css.html"
|
||||||
|
Then I should see '"/stylesheets/relative_assets.css"'
|
||||||
|
Then I should see '"/javascripts/app.js"'
|
||||||
Then I should not see "/images/blank.gif"
|
Then I should not see "/images/blank.gif"
|
||||||
And I should see "images/blank.gif"
|
And I should see "images/blank.gif"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@nojava
|
|
||||||
Feature: Stylus Updates and Partials
|
Feature: Stylus Updates and Partials
|
||||||
Scenario: The preview server should update stylesheets when Stylus changes
|
Scenario: The preview server should update stylesheets when Stylus changes
|
||||||
Given the Server is running at "stylus-preview-app"
|
Given the Server is running at "stylus-preview-app"
|
||||||
|
|
|
@ -4,6 +4,9 @@ ENV["AUTOLOAD_SPROCKETS"] ||= "false"
|
||||||
require 'simplecov'
|
require 'simplecov'
|
||||||
SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/../..'))
|
SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/../..'))
|
||||||
|
|
||||||
|
require 'capybara/poltergeist'
|
||||||
|
Capybara.javascript_driver = :poltergeist
|
||||||
|
|
||||||
require 'coveralls'
|
require 'coveralls'
|
||||||
Coveralls.wear!
|
Coveralls.wear!
|
||||||
|
|
||||||
|
|
7
middleman-core/features/support/preserve_mime_types.rb
Normal file
7
middleman-core/features/support/preserve_mime_types.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Around('@preserve_mime_types') do |_scenario, block|
|
||||||
|
mime_types = ::Rack::Mime::MIME_TYPES.clone
|
||||||
|
|
||||||
|
block.call
|
||||||
|
|
||||||
|
::Rack::Mime::MIME_TYPES.replace mime_types
|
||||||
|
end
|
|
@ -1,4 +1,4 @@
|
||||||
@nojava @nowindows
|
@nowindows
|
||||||
Feature: Compile a complicated Twitter bootstrap app
|
Feature: Compile a complicated Twitter bootstrap app
|
||||||
|
|
||||||
Scenario: User drops Twitter Bootstrap source into an app
|
Scenario: User drops Twitter Bootstrap source into an app
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
#main {
|
#main {
|
||||||
padding: 50px;
|
padding: 50px;
|
||||||
background-image: image-url('100px.jpg');
|
background-image: url('/images/100px.jpg');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
src: url('../fonts/fontawesome-webfont.woff2') format('woff2'), url('../fonts/fontawesome-webfont.woff') format('woff');
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
<?="I'm a PHP file!"?>
|
0
middleman-core/fixtures/javascript-app/config.rb
Normal file
0
middleman-core/fixtures/javascript-app/config.rb
Normal file
17
middleman-core/fixtures/javascript-app/source/index.html
Normal file
17
middleman-core/fixtures/javascript-app/source/index.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
Title
|
||||||
|
</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" language="JavaScript">
|
||||||
|
<!--
|
||||||
|
current_date = new Date();
|
||||||
|
document.write('Now: ');
|
||||||
|
document.write(current_date.getHours() + " Local H" + "our");
|
||||||
|
document.write(current_date.getMinutes() + " Local M" + "inutes");
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?='Hello'?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
test: style;
|
||||||
|
good: deal;
|
||||||
|
}
|
||||||
|
</style>
|
5
middleman-core/fixtures/minify-css-app/source/stylesheets/site.xcss.sass
Executable file
5
middleman-core/fixtures/minify-css-app/source/stylesheets/site.xcss.sass
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
@import "compass/reset"
|
||||||
|
|
||||||
|
@media handheld, only screen and (device-width: 768px)
|
||||||
|
body
|
||||||
|
display: block
|
22
middleman-core/fixtures/minify-js-app/source/inline-js.php
Executable file
22
middleman-core/fixtures/minify-js-app/source/inline-js.php
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
<?='Hello'?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
;(function() {
|
||||||
|
this;
|
||||||
|
should();
|
||||||
|
all.be();
|
||||||
|
on = { one: line };
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<script type='text/javascript'>
|
||||||
|
//<!--
|
||||||
|
;(function() {
|
||||||
|
one;
|
||||||
|
line();
|
||||||
|
here();
|
||||||
|
})();
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
<script type='text/html'>
|
||||||
|
I'm a jQuery {{template}}.
|
||||||
|
</script>
|
|
@ -0,0 +1,8 @@
|
||||||
|
var race;
|
||||||
|
var __slice = Array.prototype.slice;
|
||||||
|
|
||||||
|
race = function() {
|
||||||
|
var runners, winner;
|
||||||
|
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
||||||
|
return print(winner, runners);
|
||||||
|
};
|
33
middleman-core/fixtures/preview-server-app/bin/dns_server.rb
Executable file
33
middleman-core/fixtures/preview-server-app/bin/dns_server.rb
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require 'rubydns'
|
||||||
|
require 'psych'
|
||||||
|
|
||||||
|
db_file = ARGV[0]
|
||||||
|
port = ARGV[1] || 5300
|
||||||
|
|
||||||
|
db = if File.file? db_file
|
||||||
|
$stderr.puts 'Found dns db'
|
||||||
|
Psych.load_file(db_file)
|
||||||
|
else
|
||||||
|
$stderr.puts 'Found no dns db. Use default db.'
|
||||||
|
|
||||||
|
{
|
||||||
|
/www\.example\.org/ => '1.1.1.1'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
interfaces = [
|
||||||
|
[:udp, "127.0.0.1", port],
|
||||||
|
[:tcp, "127.0.0.1", port]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Start the RubyDNS server
|
||||||
|
RubyDNS::run_server(:listen => interfaces) do
|
||||||
|
db.each do |matcher, result|
|
||||||
|
match(matcher, Resolv::DNS::Resource::IN::A) do |transaction|
|
||||||
|
transaction.respond!(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
1
middleman-core/fixtures/preview-server-app/source/index.html.erb
Executable file
1
middleman-core/fixtures/preview-server-app/source/index.html.erb
Executable file
|
@ -0,0 +1 @@
|
||||||
|
<h1>Welcome</h1>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>My Sample Site</title>
|
||||||
|
<!-- Comment in layout -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%= yield %>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
middleman-core/fixtures/preview-server-app/source/layouts/custom.erb
Executable file
8
middleman-core/fixtures/preview-server-app/source/layouts/custom.erb
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Custom Layout</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%= yield %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
I am real
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
layout: false
|
||||||
|
---
|
||||||
|
|
||||||
|
I am real: <%= @num %>
|
|
@ -0,0 +1 @@
|
||||||
|
<h1>Ignore me!</h1>
|
|
@ -0,0 +1 @@
|
||||||
|
<h1>Ignore me! 2</h1>
|
|
@ -0,0 +1 @@
|
||||||
|
<h1>Ignore me! 3</h1>
|
1
middleman-core/fixtures/preview-server-app/source/static.html
Executable file
1
middleman-core/fixtures/preview-server-app/source/static.html
Executable file
|
@ -0,0 +1 @@
|
||||||
|
Static, no code!
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<%= stylesheet_link_tag :relative_assets, relative: true %>
|
||||||
|
<%= javascript_include_tag :app, relative: true %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%= image_tag "blank.gif" %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,3 @@
|
||||||
|
function hello() {
|
||||||
|
console.log('world');
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<%= stylesheet_link_tag :relative_assets %>
|
<%= stylesheet_link_tag :relative_assets %>
|
||||||
|
<%= javascript_include_tag :app %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%= image_tag "blank.gif" %>
|
<%= image_tag "blank.gif" %>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<%= stylesheet_link_tag :relative_assets, relative: false %>
|
||||||
|
<%= javascript_include_tag :app, relative: false %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%= image_tag "blank.gif" %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -33,7 +33,9 @@ module Middleman
|
||||||
# Root project directory (overwritten in middleman build/server)
|
# Root project directory (overwritten in middleman build/server)
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def root
|
def root
|
||||||
ENV['MM_ROOT'] || Dir.pwd
|
r = ENV['MM_ROOT'] ? ENV['MM_ROOT'].dup : ::Middleman::Util.current_directory
|
||||||
|
r.encode!('UTF-8', 'UTF-8-MAC') if RUBY_PLATFORM =~ /darwin/
|
||||||
|
r
|
||||||
end
|
end
|
||||||
|
|
||||||
# Pathname-addressed root
|
# Pathname-addressed root
|
||||||
|
@ -66,13 +68,17 @@ module Middleman
|
||||||
Contract SetOf[MapDescriptor]
|
Contract SetOf[MapDescriptor]
|
||||||
attr_reader :mappings
|
attr_reader :mappings
|
||||||
|
|
||||||
# Which host preview should start on.
|
|
||||||
# @return [Fixnum]
|
|
||||||
define_setting :host, '0.0.0.0', 'The preview server host'
|
|
||||||
|
|
||||||
# Which port preview should start on.
|
# Which port preview should start on.
|
||||||
# @return [Fixnum]
|
# @return [Fixnum]
|
||||||
define_setting :port, 4567, 'The preview server port'
|
config.define_setting :port, 4567, 'The preview server port'
|
||||||
|
|
||||||
|
# Which server name should be used
|
||||||
|
# @return [NilClass, String]
|
||||||
|
config.define_setting :server_name, nil, 'The server name of preview server'
|
||||||
|
|
||||||
|
# Which bind address the preview server should use
|
||||||
|
# @return [NilClass, String]
|
||||||
|
config.define_setting :bind_address, nil, 'The bind address of the preview server'
|
||||||
|
|
||||||
# Whether to serve the preview server over HTTPS.
|
# Whether to serve the preview server over HTTPS.
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
|
@ -160,7 +166,7 @@ module Middleman
|
||||||
# Setup callbacks which can exclude paths from the sitemap
|
# Setup callbacks which can exclude paths from the sitemap
|
||||||
define_setting :ignored_sitemap_matchers, {
|
define_setting :ignored_sitemap_matchers, {
|
||||||
# Files starting with an underscore, but not a double-underscore
|
# Files starting with an underscore, but not a double-underscore
|
||||||
partials: proc { |file|
|
partials: proc do |file|
|
||||||
ignored = false
|
ignored = false
|
||||||
|
|
||||||
file[:relative_path].ascend do |f|
|
file[:relative_path].ascend do |f|
|
||||||
|
@ -171,12 +177,12 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
ignored
|
ignored
|
||||||
},
|
end,
|
||||||
|
|
||||||
layout: proc { |file, _sitemap_app|
|
layout: proc do |file, _sitemap_app|
|
||||||
file[:relative_path].to_s.start_with?('layout.') ||
|
file[:relative_path].to_s.start_with?('layout.') ||
|
||||||
file[:relative_path].to_s.start_with?('layouts/')
|
file[:relative_path].to_s.start_with?('layouts/')
|
||||||
}
|
end
|
||||||
}, 'Callbacks that can exclude paths from the sitemap'
|
}, 'Callbacks that can exclude paths from the sitemap'
|
||||||
|
|
||||||
define_setting :watcher_disable, false, 'If the Listen watcher should not run'
|
define_setting :watcher_disable, false, 'If the Listen watcher should not run'
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
# CLI Module
|
|
||||||
module Middleman::Cli
|
|
||||||
# Server thor task
|
|
||||||
class Server < Thor
|
|
||||||
check_unknown_options!
|
|
||||||
|
|
||||||
namespace :server
|
|
||||||
|
|
||||||
desc 'server [options]', 'Start the preview server'
|
|
||||||
method_option :environment,
|
|
||||||
aliases: '-e',
|
|
||||||
default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development',
|
|
||||||
desc: 'The environment Middleman will run under'
|
|
||||||
method_option :host,
|
|
||||||
type: :string,
|
|
||||||
aliases: '-h',
|
|
||||||
desc: 'Bind to HOST address'
|
|
||||||
method_option :port,
|
|
||||||
aliases: '-p',
|
|
||||||
desc: 'The port Middleman will listen on'
|
|
||||||
method_option :https,
|
|
||||||
type: :boolean,
|
|
||||||
desc: 'Serve the preview server over SSL/TLS'
|
|
||||||
method_option :ssl_certificate,
|
|
||||||
desc: 'Path to an X.509 certificate to use for the preview server'
|
|
||||||
method_option :ssl_private_key,
|
|
||||||
desc: "Path to an RSA private key for the preview server's certificate"
|
|
||||||
method_option :verbose,
|
|
||||||
type: :boolean,
|
|
||||||
default: false,
|
|
||||||
desc: 'Print debug messages'
|
|
||||||
method_option :instrument,
|
|
||||||
type: :string,
|
|
||||||
default: false,
|
|
||||||
desc: 'Print instrument messages'
|
|
||||||
method_option :disable_watcher,
|
|
||||||
type: :boolean,
|
|
||||||
default: false,
|
|
||||||
desc: 'Disable the file change and delete watcher process'
|
|
||||||
method_option :profile,
|
|
||||||
type: :boolean,
|
|
||||||
default: false,
|
|
||||||
desc: 'Generate profiling report for server startup'
|
|
||||||
method_option :reload_paths,
|
|
||||||
type: :string,
|
|
||||||
default: false,
|
|
||||||
desc: 'Additional paths to auto-reload when files change'
|
|
||||||
method_option :force_polling,
|
|
||||||
type: :boolean,
|
|
||||||
default: false,
|
|
||||||
desc: 'Force file watcher into polling mode'
|
|
||||||
method_option :latency,
|
|
||||||
type: :numeric,
|
|
||||||
aliases: '-l',
|
|
||||||
default: 0.25,
|
|
||||||
desc: 'Set file watcher latency, in seconds'
|
|
||||||
|
|
||||||
# Start the server
|
|
||||||
def server
|
|
||||||
require 'middleman-core'
|
|
||||||
require 'middleman-core/preview_server'
|
|
||||||
|
|
||||||
unless ENV['MM_ROOT']
|
|
||||||
puts '== Could not find a Middleman project config.rb'
|
|
||||||
puts '== Treating directory as a static site to be served'
|
|
||||||
ENV['MM_ROOT'] = Dir.pwd
|
|
||||||
ENV['MM_SOURCE'] = ''
|
|
||||||
end
|
|
||||||
|
|
||||||
params = {
|
|
||||||
port: options['port'],
|
|
||||||
host: options['host'],
|
|
||||||
https: options['https'],
|
|
||||||
ssl_certificate: options['ssl_certificate'],
|
|
||||||
ssl_private_key: options['ssl_private_key'],
|
|
||||||
environment: options['environment'],
|
|
||||||
debug: options['verbose'],
|
|
||||||
instrumenting: options['instrument'],
|
|
||||||
disable_watcher: options['disable_watcher'],
|
|
||||||
reload_paths: options['reload_paths'],
|
|
||||||
force_polling: options['force_polling'],
|
|
||||||
latency: options['latency']
|
|
||||||
}
|
|
||||||
|
|
||||||
puts '== The Middleman is loading'
|
|
||||||
::Middleman::PreviewServer.start(params)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.exit_on_failure?
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Map "s" to "server"
|
|
||||||
Base.map('s' => 'server')
|
|
||||||
end
|
|
|
@ -150,7 +150,7 @@ module Middleman
|
||||||
|
|
||||||
# Whether or not there has been a value set beyond the default
|
# Whether or not there has been a value set beyond the default
|
||||||
def value_set?
|
def value_set?
|
||||||
@value_set
|
@value_set == true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,36 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Override helper to add `relative` opt-out.
|
||||||
|
def stylesheet_link_tag(*sources)
|
||||||
|
options = {
|
||||||
|
rel: 'stylesheet'
|
||||||
|
}.update(sources.extract_options!.symbolize_keys)
|
||||||
|
|
||||||
|
path_options = {}
|
||||||
|
path_options[:relative] = options.delete(:relative) if options.key?(:relative)
|
||||||
|
|
||||||
|
sources.flatten.inject(::ActiveSupport::SafeBuffer.new) do |all, source|
|
||||||
|
all << tag(:link, {
|
||||||
|
href: asset_path(:css, source, path_options)
|
||||||
|
}.update(options))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Override helper to add `relative` opt-out.
|
||||||
|
def javascript_include_tag(*sources)
|
||||||
|
options = sources.extract_options!.symbolize_keys
|
||||||
|
|
||||||
|
path_options = {}
|
||||||
|
path_options[:relative] = options.delete(:relative) if options.key?(:relative)
|
||||||
|
|
||||||
|
sources.flatten.inject(::ActiveSupport::SafeBuffer.new) do |all, source|
|
||||||
|
all << content_tag(:script, nil, {
|
||||||
|
src: asset_path(:js, source, path_options)
|
||||||
|
}.update(options))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Output a stylesheet link tag based on the current path
|
# Output a stylesheet link tag based on the current path
|
||||||
#
|
#
|
||||||
# @param [Symbol] asset_ext The type of asset
|
# @param [Symbol] asset_ext The type of asset
|
||||||
|
@ -161,16 +191,19 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
# @param [Hash] options Data to pass through.
|
# @param [Hash] options Data to pass through.
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def asset_path(kind, source, options={})
|
def asset_path(kind, source, options={})
|
||||||
::Middleman::Util.asset_path(app, kind, source, options)
|
options_with_resource = options.merge(current_resource: current_resource)
|
||||||
|
::Middleman::Util.asset_path(app, kind, source, options_with_resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the URL of an asset given a type/prefix
|
# Get the URL of an asset given a type/prefix
|
||||||
#
|
#
|
||||||
# @param [String] path The path (such as "photo.jpg")
|
# @param [String] path The path (such as "photo.jpg")
|
||||||
# @param [String] prefix The type prefix (such as "images")
|
# @param [String] prefix The type prefix (such as "images")
|
||||||
|
# @param [Hash] options Additional options.
|
||||||
# @return [String] The fully qualified asset url
|
# @return [String] The fully qualified asset url
|
||||||
def asset_url(_path, prefix='', options={})
|
def asset_url(_path, prefix='', options={})
|
||||||
::Middleman::Util.asset_url(app, prefix, options)
|
options_with_resource = options.merge(current_resource: current_resource)
|
||||||
|
::Middleman::Util.asset_url(app, prefix, options_with_resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Given a source path (referenced either absolutely or relatively)
|
# Given a source path (referenced either absolutely or relatively)
|
||||||
|
|
|
@ -19,7 +19,8 @@ module Middleman
|
||||||
|
|
||||||
return unless File.exist?(helpers_path)
|
return unless File.exist?(helpers_path)
|
||||||
|
|
||||||
Dir[File.join(helpers_path, app.config[:helpers_filename_glob])].each do |filename|
|
glob = File.join(helpers_path, app.config[:helpers_filename_glob])
|
||||||
|
::Middleman::Util.glob_directory(glob).each do |filename|
|
||||||
module_name = app.config[:helpers_filename_to_module_name_proc].call(filename)
|
module_name = app.config[:helpers_filename_to_module_name_proc].call(filename)
|
||||||
next unless module_name
|
next unless module_name
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,33 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
::I18n.t(*args)
|
::I18n.t(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def url_for(path_or_resource, options={})
|
||||||
|
locale = options.delete(:locale) || ::I18n.locale
|
||||||
|
|
||||||
|
opts = options.dup
|
||||||
|
|
||||||
|
should_relativize = opts.key?(:relative) ? opts[:relative] : config[:relative_links]
|
||||||
|
|
||||||
|
opts[:relative] = false
|
||||||
|
|
||||||
|
href = super(path_or_resource, opts)
|
||||||
|
|
||||||
|
final_path = if result = extensions[:i18n].localized_path(href, locale)
|
||||||
|
result
|
||||||
|
else
|
||||||
|
# Should we log the missing file?
|
||||||
|
href
|
||||||
|
end
|
||||||
|
|
||||||
|
opts[:relative] = should_relativize
|
||||||
|
|
||||||
|
begin
|
||||||
|
super(final_path, opts)
|
||||||
|
rescue RuntimeError
|
||||||
|
super(path_or_resource, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def locate_partial(partial_name, try_static=false)
|
def locate_partial(partial_name, try_static=false)
|
||||||
locals_dir = extensions[:i18n].options[:templates_dir]
|
locals_dir = extensions[:i18n].options[:templates_dir]
|
||||||
|
|
||||||
|
@ -102,19 +129,21 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
def manipulate_resource_list(resources)
|
def manipulate_resource_list(resources)
|
||||||
new_resources = []
|
new_resources = []
|
||||||
|
|
||||||
resources.each do |resource|
|
file_extension_resources = resources.select do |resource|
|
||||||
# If it uses file extension localization
|
parse_locale_extension(resource.path)
|
||||||
if result = parse_locale_extension(resource.path)
|
end
|
||||||
ext_lang, path, page_id = result
|
|
||||||
new_resources << build_resource(path, resource.path, page_id, ext_lang)
|
localizable_folder_resources = resources.select do |resource|
|
||||||
# If it's a "localizable template"
|
!file_extension_resources.include?(resource) && File.fnmatch?(File.join(options[:templates_dir], '**'), resource.path)
|
||||||
elsif File.fnmatch?(File.join(options[:templates_dir], '**'), resource.path)
|
end
|
||||||
page_id = File.basename(resource.path, File.extname(resource.path))
|
|
||||||
langs.each do |lang|
|
# If it's a "localizable template"
|
||||||
# Remove folder name
|
localizable_folder_resources.map do |resource|
|
||||||
path = resource.path.sub(options[:templates_dir], '')
|
page_id = File.basename(resource.path, File.extname(resource.path))
|
||||||
new_resources << build_resource(path, resource.path, page_id, lang)
|
langs.each do |lang|
|
||||||
end
|
# Remove folder name
|
||||||
|
path = resource.path.sub(options[:templates_dir], '')
|
||||||
|
new_resources << build_resource(path, resource.path, page_id, lang)
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is for backwards compatibility with the old provides_metadata-based code
|
# This is for backwards compatibility with the old provides_metadata-based code
|
||||||
|
@ -124,7 +153,27 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
resource.add_metadata options: { lang: @mount_at_root }, locals: { lang: @mount_at_root }
|
resource.add_metadata options: { lang: @mount_at_root }, locals: { lang: @mount_at_root }
|
||||||
end
|
end
|
||||||
|
|
||||||
resources + new_resources
|
# If it uses file extension localization
|
||||||
|
file_extension_resources.map do |resource|
|
||||||
|
result = parse_locale_extension(resource.path)
|
||||||
|
ext_lang, path, page_id = result
|
||||||
|
new_resources << build_resource(path, resource.path, page_id, ext_lang)
|
||||||
|
end
|
||||||
|
|
||||||
|
@lookup = new_resources.each_with_object({}) do |desc, sum|
|
||||||
|
abs_path = desc.source_path.sub(options[:templates_dir], '')
|
||||||
|
sum[abs_path] ||= {}
|
||||||
|
sum[abs_path][desc.lang] = '/' + desc.path
|
||||||
|
end
|
||||||
|
|
||||||
|
resources + new_resources.map { |r| r.to_resource(app) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def localized_path(path, lang)
|
||||||
|
lookup_path = path.dup
|
||||||
|
lookup_path << app.config[:index_file] if lookup_path.end_with?('/')
|
||||||
|
|
||||||
|
@lookup[lookup_path] && @lookup[lookup_path][lang]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -155,9 +204,9 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
p[:relative_path].to_s.split(File::SEPARATOR).length == 1
|
p[:relative_path].to_s.split(File::SEPARATOR).length == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
known_langs.map { |p|
|
known_langs.map do |p|
|
||||||
File.basename(p[:relative_path].to_s).sub(/\.ya?ml$/, '').sub(/\.rb$/, '')
|
File.basename(p[:relative_path].to_s).sub(/\.ya?ml$/, '').sub(/\.rb$/, '')
|
||||||
}.sort.map(&:to_sym)
|
end.sort.map(&:to_sym)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -177,12 +226,29 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
[lang, path, basename]
|
[lang, path, basename]
|
||||||
end
|
end
|
||||||
|
|
||||||
Contract String, String, String, Symbol => IsA['Middleman::Sitemap::Resource']
|
LocalizedPageDescriptor = Struct.new(:path, :source_path, :lang) do
|
||||||
|
def to_resource(app)
|
||||||
|
r = ::Middleman::Sitemap::ProxyResource.new(app.sitemap, path, source_path)
|
||||||
|
r.add_metadata options: { lang: lang }
|
||||||
|
r
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Contract String, String, String, Symbol => LocalizedPageDescriptor
|
||||||
def build_resource(path, source_path, page_id, lang)
|
def build_resource(path, source_path, page_id, lang)
|
||||||
old_locale = ::I18n.locale
|
old_locale = ::I18n.locale
|
||||||
::I18n.locale = lang
|
::I18n.locale = lang
|
||||||
localized_page_id = ::I18n.t("paths.#{page_id}", default: page_id, fallback: [])
|
localized_page_id = ::I18n.t("paths.#{page_id}", default: page_id, fallback: [])
|
||||||
|
|
||||||
|
partially_localized_path = ''
|
||||||
|
|
||||||
|
File.dirname(path).split('/').each do |path_sub|
|
||||||
|
next if path_sub == ''
|
||||||
|
partially_localized_path = "#{partially_localized_path}/#{(::I18n.t("paths.#{path_sub}", default: path_sub).to_s)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
path = "#{partially_localized_path}/#{File.basename(path)}"
|
||||||
|
|
||||||
prefix = if (options[:mount_at_root] == lang) || (options[:mount_at_root].nil? && langs[0] == lang)
|
prefix = if (options[:mount_at_root] == lang) || (options[:mount_at_root].nil? && langs[0] == lang)
|
||||||
'/'
|
'/'
|
||||||
else
|
else
|
||||||
|
@ -197,10 +263,8 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
||||||
|
|
||||||
path = path.sub(options[:templates_dir] + '/', '')
|
path = path.sub(options[:templates_dir] + '/', '')
|
||||||
|
|
||||||
p = ::Middleman::Sitemap::ProxyResource.new(app.sitemap, path, source_path)
|
|
||||||
p.add_metadata locals: { lang: lang, page_id: path }, options: { lang: lang }
|
|
||||||
|
|
||||||
::I18n.locale = old_locale
|
::I18n.locale = old_locale
|
||||||
p
|
|
||||||
|
LocalizedPageDescriptor.new(path, source_path, lang)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
73
middleman-core/lib/middleman-core/dns_resolver.rb
Normal file
73
middleman-core/lib/middleman-core/dns_resolver.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
require 'resolv'
|
||||||
|
require 'middleman-core/dns_resolver/network_resolver'
|
||||||
|
require 'middleman-core/dns_resolver/hosts_resolver'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
# This resolves IP address to names and vice versa
|
||||||
|
class DnsResolver
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :resolvers
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
# Create resolver
|
||||||
|
#
|
||||||
|
# First the local resolver is used. If environment variable HOSTSRC is
|
||||||
|
# given this file is used for local name lookup.
|
||||||
|
#
|
||||||
|
# @param [#getnames, #getaddresses] network_resolver
|
||||||
|
# The resolver which uses a network name server to resolve ip addresses
|
||||||
|
# and names.
|
||||||
|
#
|
||||||
|
# @param [#getnames, #getaddresses] local_resolver
|
||||||
|
# The resolver uses /etc/hosts on POSIX-systems and
|
||||||
|
# C:\Windows\System32\drivers\etc\hosts on Windows-operating systems to
|
||||||
|
# resolve ip addresses and names.
|
||||||
|
#
|
||||||
|
# First the local resolver is queried. If this raises an error or returns
|
||||||
|
# nil or [] the network resolver is queried.
|
||||||
|
def initialize(opts={})
|
||||||
|
@resolvers = []
|
||||||
|
@resolvers << opts.fetch(:hosts_resolver, HostsResolver.new)
|
||||||
|
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
require 'middleman-core/dns_resolver/local_link_resolver'
|
||||||
|
@resolvers << opts.fetch(:local_link_resolver, LocalLinkResolver.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
@resolvers << opts.fetch(:network_resolver, NetworkResolver.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get names for given ip
|
||||||
|
#
|
||||||
|
# @param [String] ip
|
||||||
|
# The ip which should be resolved.
|
||||||
|
def names_for(ip)
|
||||||
|
resolvers.each do |r|
|
||||||
|
names = r.getnames(ip)
|
||||||
|
|
||||||
|
return names unless names.nil? || names.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get ips for given name
|
||||||
|
#
|
||||||
|
# First the local resolver is used. On POSIX-systems /etc/hosts is used. On
|
||||||
|
# Windows C:\Windows\System32\drivers\etc\hosts is used.
|
||||||
|
#
|
||||||
|
# @param [String] name
|
||||||
|
# The name which should be resolved.
|
||||||
|
def ips_for(name)
|
||||||
|
resolvers.each do |r|
|
||||||
|
ips = r.getaddresses(name)
|
||||||
|
|
||||||
|
return ips unless ips.nil? || ips.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,52 @@
|
||||||
|
module Middleman
|
||||||
|
class DnsResolver
|
||||||
|
# Use network name server to resolve ips and names
|
||||||
|
class BasicNetworkResolver
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :resolver, :timeouts
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize(opts={})
|
||||||
|
@timeouts = opts.fetch(:timeouts, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get names for ip
|
||||||
|
#
|
||||||
|
# @param [#to_s] ip
|
||||||
|
# The ip to resolve into names
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# Array of Names
|
||||||
|
def getnames(ip)
|
||||||
|
resolver.getnames(ip.to_s).map(&:to_s)
|
||||||
|
rescue Resolv::ResolvError, Errno::EADDRNOTAVAIL
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get ips for name
|
||||||
|
#
|
||||||
|
# @param [#to_s] name
|
||||||
|
# The name to resolve into ips
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# Array of ipaddresses
|
||||||
|
def getaddresses(name)
|
||||||
|
resolver.getaddresses(name.to_s).map(&:to_s)
|
||||||
|
rescue Resolv::ResolvError, Errno::EADDRNOTAVAIL
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set timeout for lookup
|
||||||
|
#
|
||||||
|
# @param [Integer] value
|
||||||
|
# The timeout value
|
||||||
|
def timeouts=(timeouts)
|
||||||
|
return if RUBY_VERSION < '2'
|
||||||
|
|
||||||
|
resolver.timeouts = timeouts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,63 @@
|
||||||
|
module Middleman
|
||||||
|
class DnsResolver
|
||||||
|
# Use network name server to resolve ips and names
|
||||||
|
class HostsResolver
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :resolver
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize(opts={})
|
||||||
|
# using the splat operator works around a non-existing HOSTSRC variable
|
||||||
|
# using nil as input does not work, but `*[]` does and then Resolv::Hosts
|
||||||
|
# uses its defaults
|
||||||
|
@resolver = opts.fetch(:resolver, Resolv::Hosts.new(*hosts_file))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get names for ip
|
||||||
|
#
|
||||||
|
# @param [#to_s] ip
|
||||||
|
# The ip to resolve into names
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# Array of Names
|
||||||
|
def getnames(ip)
|
||||||
|
resolver.getnames(ip.to_s).map(&:to_s)
|
||||||
|
rescue Resolv::ResolvError
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get ips for name
|
||||||
|
#
|
||||||
|
# @param [#to_s] name
|
||||||
|
# The name to resolve into ips
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# Array of ipaddresses
|
||||||
|
def getaddresses(name)
|
||||||
|
resolver.getaddresses(name.to_s).map(&:to_s)
|
||||||
|
rescue Resolv::ResolvError
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Path to hosts file
|
||||||
|
#
|
||||||
|
# This looks for MM_HOSTSRC in your environment
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# This needs to be an array, to make the splat operator work
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# # <ip> <hostname>
|
||||||
|
# 127.0.0.1 localhost.localhost localhost
|
||||||
|
def hosts_file
|
||||||
|
return [ENV['MM_HOSTSRC']] if ENV.key?('MM_HOSTSRC') && File.file?(ENV['MM_HOSTSRC'])
|
||||||
|
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,44 @@
|
||||||
|
require 'middleman-core/dns_resolver/basic_network_resolver'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class DnsResolver
|
||||||
|
# Use network name server to resolve ips and names
|
||||||
|
class LocalLinkResolver < BasicNetworkResolver
|
||||||
|
def initialize(opts={})
|
||||||
|
super
|
||||||
|
|
||||||
|
@timeouts = opts.fetch(:timeouts, 1)
|
||||||
|
@resolver = opts.fetch(:resolver, Resolv::MDNS.new(nameserver_config))
|
||||||
|
|
||||||
|
self.timeouts = timeouts
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Hosts + Ports for MDNS resolver
|
||||||
|
#
|
||||||
|
# This looks for MM_MDNSRC in your environment. If you are going to use
|
||||||
|
# IPv6-addresses: Make sure you do not forget to add the port at the end.
|
||||||
|
#
|
||||||
|
# MM_MDNSRC=ip:port ip:port
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
# Returns the configuration for the nameserver
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# export MM_MDNSRC="224.0.0.251:5353 ff02::fb:5353"
|
||||||
|
#
|
||||||
|
def nameserver_config
|
||||||
|
return unless ENV.key?('MM_MDNSRC') && ENV['MM_MDNSRC']
|
||||||
|
|
||||||
|
address, port = ENV['MM_MDNSRC'].split(/:/)
|
||||||
|
|
||||||
|
{
|
||||||
|
nameserver_port: [[address, port.to_i]]
|
||||||
|
}
|
||||||
|
rescue StandardError
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,42 @@
|
||||||
|
require 'middleman-core/dns_resolver/basic_network_resolver'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class DnsResolver
|
||||||
|
# Use network name server to resolve ips and names
|
||||||
|
class NetworkResolver < BasicNetworkResolver
|
||||||
|
def initialize(opts={})
|
||||||
|
super
|
||||||
|
|
||||||
|
@resolver = opts.fetch(:resolver, Resolv::DNS.new(nameserver_config))
|
||||||
|
self.timeouts = timeouts
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Hosts + Ports for MDNS resolver
|
||||||
|
#
|
||||||
|
# This looks for MM_MDNSRC in your environment. If you are going to use
|
||||||
|
# IPv6-addresses: Make sure you do not forget to add the port at the end.
|
||||||
|
#
|
||||||
|
# MM_MDNSRC=ip:port ip:port
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
# Returns the configuration for the nameserver
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# export MM_MDNSRC="224.0.0.251:5353 ff02::fb:5353"
|
||||||
|
#
|
||||||
|
def nameserver_config
|
||||||
|
return unless ENV.key?('MM_DNSRC') && ENV['MM_DNSRC']
|
||||||
|
|
||||||
|
address, port = ENV['MM_DNSRC'].split(/:/)
|
||||||
|
|
||||||
|
{
|
||||||
|
nameserver_port: [[address, port.to_i]]
|
||||||
|
}
|
||||||
|
rescue StandardError
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,7 +3,7 @@ require 'middleman-core/util'
|
||||||
require 'middleman-core/rack'
|
require 'middleman-core/rack'
|
||||||
|
|
||||||
class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
||||||
option :exts, %w(.jpg .jpeg .png .gif .webp .js .css .otf .woff .woff2 .eot .ttf .svg), 'List of extensions that get asset hashes appended to them.'
|
option :exts, %w(.jpg .jpeg .png .gif .webp .js .css .otf .woff .woff2 .eot .ttf .svg .svgz), 'List of extensions that get asset hashes appended to them.'
|
||||||
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
|
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
|
||||||
|
|
||||||
def initialize(app, options_hash={}, &block)
|
def initialize(app, options_hash={}, &block)
|
||||||
|
@ -20,7 +20,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
||||||
|
|
||||||
app.use ::Middleman::Middleware::InlineURLRewriter,
|
app.use ::Middleman::Middleware::InlineURLRewriter,
|
||||||
id: :asset_hash,
|
id: :asset_hash,
|
||||||
url_extensions: options.exts,
|
url_extensions: options.exts.sort.reverse,
|
||||||
source_extensions: %w(.htm .html .php .css .js),
|
source_extensions: %w(.htm .html .php .css .js),
|
||||||
ignore: @ignore,
|
ignore: @ignore,
|
||||||
middleman_app: app,
|
middleman_app: app,
|
||||||
|
|
|
@ -24,6 +24,13 @@ class Middleman::Extensions::AutomaticImageSizes < ::Middleman::Extension
|
||||||
if file && file[:full_path].exist?
|
if file && file[:full_path].exist?
|
||||||
begin
|
begin
|
||||||
width, height = ::FastImage.size(file[:full_path].to_s, raise_on_failure: true)
|
width, height = ::FastImage.size(file[:full_path].to_s, raise_on_failure: true)
|
||||||
|
# Check for @2x and @3x image
|
||||||
|
retina = full_path.match(/@(\d)x\.[a-zA-Z]{3,4}$/)
|
||||||
|
if retina
|
||||||
|
factor = retina[1].to_i
|
||||||
|
width /= factor
|
||||||
|
height /= factor
|
||||||
|
end
|
||||||
params[:width] = width
|
params[:width] = width
|
||||||
params[:height] = height
|
params[:height] = height
|
||||||
rescue FastImage::UnknownImageType
|
rescue FastImage::UnknownImageType
|
||||||
|
|
|
@ -8,12 +8,16 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension
|
||||||
require 'sass'
|
require 'sass'
|
||||||
SassCompressor
|
SassCompressor
|
||||||
}, 'Set the CSS compressor to use.'
|
}, 'Set the CSS compressor to use.'
|
||||||
|
option :content_types, %w(text/css), 'Content types of resources that contain CSS'
|
||||||
|
option :inline_content_types, %w(text/html text/php), 'Content types of resources that contain inline CSS'
|
||||||
|
|
||||||
def ready
|
def ready
|
||||||
# Setup Rack middleware to minify CSS
|
# Setup Rack middleware to minify CSS
|
||||||
app.use Rack, compressor: options[:compressor],
|
app.use Rack, compressor: options[:compressor],
|
||||||
ignore: Array(options[:ignore]) + [/\.min\./],
|
ignore: Array(options[:ignore]) + [/\.min\./],
|
||||||
inline: options[:inline]
|
inline: options[:inline],
|
||||||
|
content_types: options[:content_types],
|
||||||
|
inline_content_types: options[:inline_content_types]
|
||||||
end
|
end
|
||||||
|
|
||||||
class SassCompressor
|
class SassCompressor
|
||||||
|
@ -45,6 +49,8 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension
|
||||||
@compressor = options.fetch(:compressor)
|
@compressor = options.fetch(:compressor)
|
||||||
@compressor = @compressor.to_proc if @compressor.respond_to? :to_proc
|
@compressor = @compressor.to_proc if @compressor.respond_to? :to_proc
|
||||||
@compressor = @compressor.call if @compressor.is_a? Proc
|
@compressor = @compressor.call if @compressor.is_a? Proc
|
||||||
|
@content_types = options[:content_types]
|
||||||
|
@inline_content_types = options[:inline_content_types]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rack interface
|
# Rack interface
|
||||||
|
@ -53,19 +59,18 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension
|
||||||
def call(env)
|
def call(env)
|
||||||
status, headers, response = @app.call(env)
|
status, headers, response = @app.call(env)
|
||||||
|
|
||||||
if inline_html_content?(env['PATH_INFO'])
|
content_type = headers['Content-Type'].try(:slice, /^[^;]*/)
|
||||||
minified = ::Middleman::Util.extract_response_text(response)
|
path = env['PATH_INFO']
|
||||||
minified.gsub!(INLINE_CSS_REGEX) do
|
|
||||||
$1 << @compressor.compress($2) << $3
|
|
||||||
end
|
|
||||||
|
|
||||||
|
minified = if @inline && minifiable_inline?(content_type)
|
||||||
|
minify_inline(::Middleman::Util.extract_response_text(response))
|
||||||
|
elsif minifiable?(content_type) && !ignore?(path)
|
||||||
|
minify(::Middleman::Util.extract_response_text(response))
|
||||||
|
end
|
||||||
|
|
||||||
|
if minified
|
||||||
headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s
|
headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s
|
||||||
response = [minified]
|
response = [minified]
|
||||||
elsif standalone_css_content?(env['PATH_INFO'])
|
|
||||||
minified_css = @compressor.compress(::Middleman::Util.extract_response_text(response))
|
|
||||||
|
|
||||||
headers['Content-Length'] = ::Rack::Utils.bytesize(minified_css).to_s
|
|
||||||
response = [minified_css]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
[status, headers, response]
|
[status, headers, response]
|
||||||
|
@ -73,14 +78,41 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
Contract String => Bool
|
# Whether the path should be ignored
|
||||||
def inline_html_content?(path)
|
# @param [String] path
|
||||||
(path.end_with?('.html') || path.end_with?('.php')) && @inline
|
# @return [Boolean]
|
||||||
|
def ignore?(path)
|
||||||
|
@ignore.any? { |ignore| Middleman::Util.path_match(ignore, path) }
|
||||||
end
|
end
|
||||||
|
|
||||||
Contract String => Bool
|
# Whether this type of content can be minified
|
||||||
def standalone_css_content?(path)
|
# @param [String, nil] content_type
|
||||||
path.end_with?('.css') && @ignore.none? { |ignore| Middleman::Util.path_match(ignore, path) }
|
# @return [Boolean]
|
||||||
|
def minifiable?(content_type)
|
||||||
|
@content_types.include?(content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this type of content contains inline content that can be minified
|
||||||
|
# @param [String, nil] content_type
|
||||||
|
# @return [Boolean]
|
||||||
|
def minifiable_inline?(content_type)
|
||||||
|
@inline_content_types.include?(content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Minify the content
|
||||||
|
# @param [String] content
|
||||||
|
# @return [String]
|
||||||
|
def minify(content)
|
||||||
|
@compressor.compress(content)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detect and minify inline content
|
||||||
|
# @param [String] content
|
||||||
|
# @return [String]
|
||||||
|
def minify_inline(content)
|
||||||
|
content.gsub(INLINE_CSS_REGEX) do
|
||||||
|
$1 + minify($2) + $3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,17 +8,22 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
||||||
require 'uglifier'
|
require 'uglifier'
|
||||||
::Uglifier.new
|
::Uglifier.new
|
||||||
}, 'Set the JS compressor to use.'
|
}, 'Set the JS compressor to use.'
|
||||||
|
option :content_types, %w(application/javascript), 'Content types of resources that contain JS'
|
||||||
|
option :inline_content_types, %w(text/html text/php), 'Content types of resources that contain inline JS'
|
||||||
|
|
||||||
def ready
|
def ready
|
||||||
# Setup Rack middleware to minify CSS
|
# Setup Rack middleware to minify JS
|
||||||
app.use Rack, compressor: options[:compressor],
|
app.use Rack, compressor: chosen_compressor,
|
||||||
ignore: Array(options[:ignore]) + [/\.min\./],
|
ignore: Array(options[:ignore]) + [/\.min\./],
|
||||||
inline: options[:inline]
|
inline: options[:inline],
|
||||||
|
content_types: options[:content_types],
|
||||||
|
inline_content_types: options[:inline_content_types]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rack middleware to look for JS and compress it
|
# Rack middleware to look for JS and compress it
|
||||||
class Rack
|
class Rack
|
||||||
include Contracts
|
include Contracts
|
||||||
|
INLINE_JS_REGEX = /(<script[^>]*>\s*(?:\/\/(?:(?:<!--)|(?:<!\[CDATA\[))\n)?)(.*?)((?:(?:\n\s*)?\/\/(?:(?:-->)|(?:\]\]>)))?\s*<\/script>)/m
|
||||||
|
|
||||||
# Init
|
# Init
|
||||||
# @param [Class] app
|
# @param [Class] app
|
||||||
|
@ -36,6 +41,8 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
||||||
@compressor = options.fetch(:compressor)
|
@compressor = options.fetch(:compressor)
|
||||||
@compressor = @compressor.to_proc if @compressor.respond_to? :to_proc
|
@compressor = @compressor.to_proc if @compressor.respond_to? :to_proc
|
||||||
@compressor = @compressor.call if @compressor.is_a? Proc
|
@compressor = @compressor.call if @compressor.is_a? Proc
|
||||||
|
@content_types = options[:content_types]
|
||||||
|
@inline_content_types = options[:inline_content_types]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rack interface
|
# Rack interface
|
||||||
|
@ -44,25 +51,18 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
||||||
def call(env)
|
def call(env)
|
||||||
status, headers, response = @app.call(env)
|
status, headers, response = @app.call(env)
|
||||||
|
|
||||||
path = env['PATH_INFO']
|
type = headers['Content-Type'].try(:slice, /^[^;]*/)
|
||||||
|
@path = env['PATH_INFO']
|
||||||
|
|
||||||
begin
|
minified = if @inline && minifiable_inline?(type)
|
||||||
if @inline && (path.end_with?('.html') || path.end_with?('.php'))
|
minify_inline(::Middleman::Util.extract_response_text(response))
|
||||||
uncompressed_source = ::Middleman::Util.extract_response_text(response)
|
elsif minifiable?(type) && !ignore?(@path)
|
||||||
|
minify(::Middleman::Util.extract_response_text(response))
|
||||||
|
end
|
||||||
|
|
||||||
minified = minify_inline_content(uncompressed_source)
|
if minified
|
||||||
|
headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s
|
||||||
headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s
|
response = [minified]
|
||||||
response = [minified]
|
|
||||||
elsif path.end_with?('.js') && @ignore.none? { |ignore| Middleman::Util.path_match(ignore, path) }
|
|
||||||
uncompressed_source = ::Middleman::Util.extract_response_text(response)
|
|
||||||
minified = @compressor.compress(uncompressed_source)
|
|
||||||
|
|
||||||
headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s
|
|
||||||
response = [minified]
|
|
||||||
end
|
|
||||||
rescue ExecJS::ProgramError => e
|
|
||||||
warn "WARNING: Couldn't compress JavaScript in #{path}: #{e.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
[status, headers, response]
|
[status, headers, response]
|
||||||
|
@ -70,20 +70,50 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
Contract String => String
|
# Whether the path should be ignored
|
||||||
def minify_inline_content(uncompressed_source)
|
# @param [String] path
|
||||||
uncompressed_source.gsub(/(<script[^>]*>\s*(?:\/\/(?:(?:<!--)|(?:<!\[CDATA\[))\n)?)(.*?)((?:(?:\n\s*)?\/\/(?:(?:-->)|(?:\]\]>)))?\s*<\/script>)/m) do |match|
|
# @return [Boolean]
|
||||||
|
def ignore?(path)
|
||||||
|
@ignore.any? { |ignore| Middleman::Util.path_match(ignore, path) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this type of content can be minified
|
||||||
|
# @param [String, nil] content_type
|
||||||
|
# @return [Boolean]
|
||||||
|
def minifiable?(content_type)
|
||||||
|
@content_types.include?(content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this type of content contains inline content that can be minified
|
||||||
|
# @param [String, nil] content_type
|
||||||
|
# @return [Boolean]
|
||||||
|
def minifiable_inline?(content_type)
|
||||||
|
@inline_content_types.include?(content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Minify the content
|
||||||
|
# @param [String] content
|
||||||
|
# @return [String]
|
||||||
|
def minify(content)
|
||||||
|
@compressor.compress(content)
|
||||||
|
rescue ExecJS::ProgramError => e
|
||||||
|
warn "WARNING: Couldn't compress JavaScript in #{@path}: #{e.message}"
|
||||||
|
content
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detect and minify inline content
|
||||||
|
# @param [String] content
|
||||||
|
# @return [String]
|
||||||
|
def minify_inline(content)
|
||||||
|
content.gsub(INLINE_JS_REGEX) do |match|
|
||||||
first = $1
|
first = $1
|
||||||
javascript = $2
|
inline_content = $2
|
||||||
last = $3
|
last = $3
|
||||||
|
|
||||||
# Only compress script tags that contain JavaScript (as opposed
|
# Only compress script tags that contain JavaScript (as opposed to
|
||||||
# to something like jQuery templates, identified with a "text/html"
|
# something like jQuery templates, identified with a "text/html" type).
|
||||||
# type.
|
if first.include?('<script>') || first.include?('text/javascript')
|
||||||
if first =~ /<script>/ || first.include?('text/javascript')
|
first + minify(inline_content) + last
|
||||||
minified_js = @compressor.compress(javascript)
|
|
||||||
|
|
||||||
first << minified_js << last
|
|
||||||
else
|
else
|
||||||
match
|
match
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,19 @@ class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
||||||
proc: method(:rewrite_url)
|
proc: method(:rewrite_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
helpers do
|
||||||
|
# asset_url override for relative assets
|
||||||
|
# @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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Contract String, Or[String, Pathname], Any => Maybe[String]
|
Contract String, Or[String, Pathname], Any => Maybe[String]
|
||||||
def rewrite_url(asset_path, dirpath, request_path)
|
def rewrite_url(asset_path, dirpath, request_path)
|
||||||
uri = ::Addressable::URI.parse(asset_path)
|
uri = ::Addressable::URI.parse(asset_path)
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Middleman
|
||||||
# @param [Class] context
|
# @param [Class] context
|
||||||
# @return [String]
|
# @return [String]
|
||||||
Contract Hash, Hash, Any, Maybe[Proc] => String
|
Contract Hash, Hash, Any, Maybe[Proc] => String
|
||||||
def render(locs={}, opts={}, context, &block)
|
def render(locs, opts, context, &block)
|
||||||
path = @path.dup
|
path = @path.dup
|
||||||
|
|
||||||
# Detect the remdering engine from the extension
|
# Detect the remdering engine from the extension
|
||||||
|
|
|
@ -95,7 +95,7 @@ module Middleman
|
||||||
# Render a template with the given name and locals
|
# Render a template with the given name and locals
|
||||||
def template(template_name, locals={})
|
def template(template_name, locals={})
|
||||||
template_path = File.join(File.dirname(__FILE__), 'meta_pages', 'templates', template_name)
|
template_path = File.join(File.dirname(__FILE__), 'meta_pages', 'templates', template_name)
|
||||||
content = Tilt.new(template_path).render(nil, locals)
|
content = Tilt.new(template_path).render(::Object.new, locals)
|
||||||
response(content)
|
response(content)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,53 @@
|
||||||
require 'webrick'
|
require 'webrick'
|
||||||
require 'webrick/https'
|
require 'webrick/https'
|
||||||
require 'openssl'
|
require 'openssl'
|
||||||
require 'socket'
|
|
||||||
require 'middleman-core/meta_pages'
|
require 'middleman-core/meta_pages'
|
||||||
require 'middleman-core/logger'
|
require 'middleman-core/logger'
|
||||||
require 'middleman-core/rack'
|
require 'middleman-core/rack'
|
||||||
|
require 'middleman-core/preview_server/server_information'
|
||||||
|
require 'middleman-core/preview_server/server_url'
|
||||||
|
|
||||||
# rubocop:disable GlobalVars
|
# rubocop:disable GlobalVars
|
||||||
module Middleman
|
module Middleman
|
||||||
module PreviewServer
|
class PreviewServer
|
||||||
class << self
|
class << self
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
|
|
||||||
attr_reader :app, :host, :port, :ssl_certificate, :ssl_private_key
|
attr_reader :app, :ssl_certificate, :ssl_private_key, :environment, :server_information
|
||||||
def_delegator :app, :logger
|
def_delegator :app, :logger
|
||||||
|
|
||||||
def https?
|
def https?
|
||||||
@https
|
@https == true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Start an instance of Middleman::Application
|
# Start an instance of Middleman::Application
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def start(opts={})
|
def start(opts={})
|
||||||
@options = opts
|
# Do not buffer output, otherwise testing of output does not work
|
||||||
|
$stdout.sync = true
|
||||||
|
$stderr.sync = true
|
||||||
|
|
||||||
mount_instance(new_app)
|
@options = opts
|
||||||
logger.info "== The Middleman is standing watch at #{uri}"
|
@server_information = ServerInformation.new
|
||||||
logger.info "== Inspect your site configuration at #{uri + '__middleman'}"
|
|
||||||
|
# New app evaluates the middleman configuration. Since this can be
|
||||||
|
# invalid as well, we need to evaluate the configuration BEFORE
|
||||||
|
# checking for validity
|
||||||
|
the_app = initialize_new_app
|
||||||
|
|
||||||
|
# And now comes the check
|
||||||
|
unless server_information.valid?
|
||||||
|
$stderr.puts %(== Running Middleman failed: #{server_information.reason}. Please fix that and try again.)
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
mount_instance(the_app)
|
||||||
|
|
||||||
|
logger.debug %(== Server information is provided by #{server_information.handler})
|
||||||
|
logger.debug %(== The Middleman is running in "#{environment}" environment)
|
||||||
|
logger.debug format('== The Middleman preview server is bound to %s', ServerUrl.new(hosts: server_information.listeners, port: server_information.port, https: https?).to_bind_addresses.join(', '))
|
||||||
|
logger.info format('== View your site at %s', ServerUrl.new(hosts: server_information.site_addresses, port: server_information.port, https: https?).to_urls.join(', '))
|
||||||
|
logger.info format('== Inspect your site configuration at %s', ServerUrl.new(hosts: server_information.site_addresses, port: server_information.port, https: https?).to_config_urls.join(', '))
|
||||||
|
|
||||||
@initialized ||= false
|
@initialized ||= false
|
||||||
return if @initialized
|
return if @initialized
|
||||||
|
@ -70,7 +91,7 @@ module Middleman
|
||||||
logger.info '== The Middleman is reloading'
|
logger.info '== The Middleman is reloading'
|
||||||
|
|
||||||
begin
|
begin
|
||||||
app = new_app
|
app = initialize_new_app
|
||||||
rescue => e
|
rescue => e
|
||||||
logger.error "Error reloading Middleman: #{e}\n#{e.backtrace.join("\n")}"
|
logger.error "Error reloading Middleman: #{e}\n#{e.backtrace.join("\n")}"
|
||||||
logger.info '== The Middleman is still running the application from before the error'
|
logger.info '== The Middleman is still running the application from before the error'
|
||||||
|
@ -96,7 +117,7 @@ module Middleman
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def new_app
|
def initialize_new_app
|
||||||
opts = @options.dup
|
opts = @options.dup
|
||||||
|
|
||||||
::Middleman::Logger.singleton(
|
::Middleman::Logger.singleton(
|
||||||
|
@ -110,8 +131,10 @@ module Middleman
|
||||||
config[:watcher_force_polling] = opts[:force_polling]
|
config[:watcher_force_polling] = opts[:force_polling]
|
||||||
config[:watcher_latency] = opts[:latency]
|
config[:watcher_latency] = opts[:latency]
|
||||||
|
|
||||||
config[:host] = opts[:host] if opts[:host]
|
|
||||||
config[:port] = opts[:port] if opts[:port]
|
config[:port] = opts[:port] if opts[:port]
|
||||||
|
config[:bind_address] = opts[:bind_address]
|
||||||
|
config[:server_name] = opts[:server_name]
|
||||||
|
config[:https] = opts[:https] unless opts[:https].nil?
|
||||||
config[:ssl_certificate] = opts[:ssl_certificate] if opts[:ssl_certificate]
|
config[:ssl_certificate] = opts[:ssl_certificate] if opts[:ssl_certificate]
|
||||||
config[:ssl_private_key] = opts[:ssl_private_key] if opts[:ssl_private_key]
|
config[:ssl_private_key] = opts[:ssl_private_key] if opts[:ssl_private_key]
|
||||||
|
|
||||||
|
@ -139,9 +162,17 @@ module Middleman
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@host = app.config[:host]
|
# store configured port to make a check later on possible
|
||||||
@port = app.config[:port]
|
configured_port = app.config[:port]
|
||||||
@https = app.config[:https]
|
|
||||||
|
# Use configuration values to set `bind_address` etc. in
|
||||||
|
# `server_information`
|
||||||
|
server_information.use app.config
|
||||||
|
|
||||||
|
logger.warn format('== The Middleman uses a different port "%s" then the configured one "%s" because some other server is listening on that port.', server_information.port, configured_port) unless app.config[:port] == configured_port
|
||||||
|
|
||||||
|
@https = app.config[:https]
|
||||||
|
@environment = app.config[:environment]
|
||||||
|
|
||||||
@ssl_certificate = app.config[:ssl_certificate]
|
@ssl_certificate = app.config[:ssl_certificate]
|
||||||
@ssl_private_key = app.config[:ssl_private_key]
|
@ssl_private_key = app.config[:ssl_private_key]
|
||||||
|
@ -179,9 +210,10 @@ module Middleman
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def setup_webrick(is_logging)
|
def setup_webrick(is_logging)
|
||||||
http_opts = {
|
http_opts = {
|
||||||
BindAddress: host,
|
Port: server_information.port,
|
||||||
Port: port,
|
|
||||||
AccessLog: [],
|
AccessLog: [],
|
||||||
|
ServerName: server_information.server_name,
|
||||||
|
BindAddress: server_information.bind_address.to_s,
|
||||||
DoNotReverseLookup: true
|
DoNotReverseLookup: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +230,9 @@ module Middleman
|
||||||
%w(CN localhost),
|
%w(CN localhost),
|
||||||
%w(CN #{host})
|
%w(CN #{host})
|
||||||
].uniq
|
].uniq
|
||||||
|
cert, key = create_self_signed_cert(1024, [['CN', server_information.server_name]], server_information.site_addresses, 'Middleman Preview Server')
|
||||||
|
http_opts[:SSLCertificate] = cert
|
||||||
|
http_opts[:SSLPrivateKey] = key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -210,11 +245,44 @@ module Middleman
|
||||||
begin
|
begin
|
||||||
::WEBrick::HTTPServer.new(http_opts)
|
::WEBrick::HTTPServer.new(http_opts)
|
||||||
rescue Errno::EADDRINUSE
|
rescue Errno::EADDRINUSE
|
||||||
logger.error "== Port #{port} is unavailable. Either close the instance of Middleman already running on #{port} or start this Middleman on a new port with: --port=#{unused_tcp_port}"
|
logger.error %(== Port "#{http_opts[:Port]}" is in use. This should not have happened. Please start "middleman server" again.)
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Copy of https://github.com/nahi/ruby/blob/webrick_trunk/lib/webrick/ssl.rb#L39
|
||||||
|
# that uses a different serial number each time the cert is generated in order to
|
||||||
|
# avoid errors in Firefox. Also doesn't print out stuff to $stderr unnecessarily.
|
||||||
|
def create_self_signed_cert(bits, cn, aliases, comment)
|
||||||
|
rsa = OpenSSL::PKey::RSA.new(bits)
|
||||||
|
cert = OpenSSL::X509::Certificate.new
|
||||||
|
cert.version = 2
|
||||||
|
cert.serial = Time.now.to_i % (1 << 20)
|
||||||
|
name = OpenSSL::X509::Name.new(cn)
|
||||||
|
cert.subject = name
|
||||||
|
cert.issuer = name
|
||||||
|
cert.not_before = Time.now
|
||||||
|
cert.not_after = Time.now + (365 * 24 * 60 * 60)
|
||||||
|
cert.public_key = rsa.public_key
|
||||||
|
|
||||||
|
ef = OpenSSL::X509::ExtensionFactory.new(nil, cert)
|
||||||
|
ef.issuer_certificate = cert
|
||||||
|
cert.extensions = [
|
||||||
|
ef.create_extension('basicConstraints', 'CA:FALSE'),
|
||||||
|
ef.create_extension('keyUsage', 'keyEncipherment'),
|
||||||
|
ef.create_extension('subjectKeyIdentifier', 'hash'),
|
||||||
|
ef.create_extension('extendedKeyUsage', 'serverAuth'),
|
||||||
|
ef.create_extension('nsComment', comment)
|
||||||
|
]
|
||||||
|
aki = ef.create_extension('authorityKeyIdentifier',
|
||||||
|
'keyid:always,issuer:always')
|
||||||
|
cert.add_extension(aki)
|
||||||
|
cert.add_extension ef.create_extension('subjectAltName', aliases.map { |d| "DNS: #{d}" }.join(','))
|
||||||
|
|
||||||
|
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
||||||
|
|
||||||
|
[cert, rsa]
|
||||||
|
end
|
||||||
|
|
||||||
# Attach a new Middleman::Application instance
|
# Attach a new Middleman::Application instance
|
||||||
# @param [Middleman::Application] app
|
# @param [Middleman::Application] app
|
||||||
# @return [void]
|
# @return [void]
|
||||||
|
@ -236,23 +304,6 @@ module Middleman
|
||||||
|
|
||||||
@app = nil
|
@app = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the URI the preview server will run on
|
|
||||||
# @return [URI]
|
|
||||||
def uri
|
|
||||||
host = (@host == '0.0.0.0') ? 'localhost' : @host
|
|
||||||
scheme = https? ? 'https' : 'http'
|
|
||||||
URI("#{scheme}://#{host}:#{@port}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns unused TCP port
|
|
||||||
# @return [Fixnum]
|
|
||||||
def unused_tcp_port
|
|
||||||
server = TCPServer.open(0)
|
|
||||||
port = server.addr[1]
|
|
||||||
server.close
|
|
||||||
port
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class FilteredWebrickLog < ::WEBrick::Log
|
class FilteredWebrickLog < ::WEBrick::Log
|
||||||
|
|
81
middleman-core/lib/middleman-core/preview_server/checks.rb
Normal file
81
middleman-core/lib/middleman-core/preview_server/checks.rb
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
require 'ipaddr'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# Checks for input of preview server
|
||||||
|
module Checks
|
||||||
|
# This one will get all default setup
|
||||||
|
class BasicCheck; end
|
||||||
|
|
||||||
|
# This checks if the server name resolves to the bind_address
|
||||||
|
#
|
||||||
|
# If the users enters:
|
||||||
|
#
|
||||||
|
# 1. server_name: www.example.com (10.0.0.1)
|
||||||
|
# 2. bind_address: 127.0.0.01
|
||||||
|
#
|
||||||
|
# This validation will fail
|
||||||
|
class ServerNameResolvesToBindAddress < BasicCheck
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :resolver
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@resolver = DnsResolver.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate
|
||||||
|
#
|
||||||
|
# @param [Information] information
|
||||||
|
# The information to be validated
|
||||||
|
def validate(information)
|
||||||
|
return if resolver.ips_for(information.server_name).include? information.bind_address
|
||||||
|
|
||||||
|
information.valid = false
|
||||||
|
information.reason = format('Server name "%s" does not resolve to bind address "%s"', information.server_name, information.bind_address)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This validation fails if the user chooses to use an ip address which is
|
||||||
|
# not available on his/her system
|
||||||
|
class InterfaceIsAvailableOnSystem < BasicCheck
|
||||||
|
# Validate
|
||||||
|
#
|
||||||
|
# @param [Information] information
|
||||||
|
# The information to be validated
|
||||||
|
def validate(information)
|
||||||
|
return if information.bind_address.blank? || information.local_network_interfaces.include?(information.bind_address.to_s) || %w(0.0.0.0 ::).any? { |b| information.bind_address == b } || IPAddr.new('127.0.0.0/8').include?(information.bind_address.to_s)
|
||||||
|
|
||||||
|
information.valid = false
|
||||||
|
information.reason = format('Bind address "%s" is not available on your system. Please use one of %s', information.bind_address, information.local_network_interfaces.map { |i| %("#{i}") }.join(', '))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This one requires a bind address if the user entered a server name
|
||||||
|
#
|
||||||
|
# If the `bind_address` is blank this check will fail
|
||||||
|
class RequiresBindAddressIfServerNameIsGiven < BasicCheck
|
||||||
|
def validate(information)
|
||||||
|
return unless information.bind_address.blank?
|
||||||
|
|
||||||
|
information.valid = false
|
||||||
|
information.reason = format('Server name "%s" does not resolve to an ip address', information.server_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This validation always fails
|
||||||
|
class DenyAnyAny < BasicCheck
|
||||||
|
# Validate
|
||||||
|
#
|
||||||
|
# @param [Information] information
|
||||||
|
# The information to be validated
|
||||||
|
def validate(information)
|
||||||
|
information.valid = false
|
||||||
|
information.reason = 'Undefined combination of options "--server-name" and "--bind-address". If you think this is wrong, please file a bug at "https://github.com/middleman/middleman"'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
273
middleman-core/lib/middleman-core/preview_server/information.rb
Normal file
273
middleman-core/lib/middleman-core/preview_server/information.rb
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
require 'ipaddr'
|
||||||
|
require 'active_support/core_ext/object/blank'
|
||||||
|
require 'middleman-core/preview_server/checks'
|
||||||
|
require 'middleman-core/preview_server/server_hostname'
|
||||||
|
require 'middleman-core/preview_server/server_ip_address'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# Basic information class to wrap common behaviour
|
||||||
|
class BasicInformation
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :checks, :network_interfaces_inventory
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
attr_accessor :bind_address, :server_name, :port, :reason, :valid
|
||||||
|
attr_reader :listeners, :site_addresses
|
||||||
|
|
||||||
|
# Create instance
|
||||||
|
#
|
||||||
|
# @param [String] bind_address
|
||||||
|
# The bind address of the server
|
||||||
|
#
|
||||||
|
# @param [String] server_name
|
||||||
|
# The name of the server
|
||||||
|
#
|
||||||
|
# @param [Integer] port
|
||||||
|
# The port to listen on
|
||||||
|
def initialize(opts={})
|
||||||
|
@bind_address = ServerIpAddress.new(opts[:bind_address])
|
||||||
|
@server_name = ServerHostname.new(opts[:server_name])
|
||||||
|
@port = opts[:port]
|
||||||
|
@valid = true
|
||||||
|
|
||||||
|
@site_addresses = []
|
||||||
|
@listeners = []
|
||||||
|
@checks = []
|
||||||
|
|
||||||
|
# This needs to be check for each use case. Otherwise `Webrick` will
|
||||||
|
# complain about that.
|
||||||
|
@checks << Checks::InterfaceIsAvailableOnSystem.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# Is the given information valid?
|
||||||
|
def valid?
|
||||||
|
valid == true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Pass "self" to validator
|
||||||
|
#
|
||||||
|
# @param [#validate] validator
|
||||||
|
# The validator
|
||||||
|
def validate_me(validator)
|
||||||
|
validator.validate self, checks
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_me(*)
|
||||||
|
fail NoMethodError
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get network information
|
||||||
|
#
|
||||||
|
# @param [#network_interfaces] inventory
|
||||||
|
# Get list of available network interfaces
|
||||||
|
def show_me_network_interfaces(inventory)
|
||||||
|
@network_interfaces_inventory = inventory
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default is to get all network interfaces
|
||||||
|
def local_network_interfaces
|
||||||
|
network_interfaces_inventory.nil? ? [] : network_interfaces_inventory.network_interfaces(:all)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This only is used if no other parser is available
|
||||||
|
#
|
||||||
|
# The "default" behaviour is to fail because of "Checks::DenyAnyAny"
|
||||||
|
class DefaultInformation < BasicInformation
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
# Make this fail
|
||||||
|
@checks << Checks::DenyAnyAny.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_me(*); end
|
||||||
|
|
||||||
|
# Always true
|
||||||
|
def self.matches?(*)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This one is used if no bind address and no server name is given
|
||||||
|
class AllInterfaces < BasicInformation
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
after_init
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.matches?(opts={})
|
||||||
|
opts[:bind_address].blank? && opts[:server_name].blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Resolve ips
|
||||||
|
def resolve_me(resolver)
|
||||||
|
hostname = ServerHostname.new(Socket.gethostname)
|
||||||
|
hostname_ips = resolver.ips_for(hostname)
|
||||||
|
network_interface = ServerIpAddress.new(Array(local_network_interfaces).first)
|
||||||
|
resolved_name = ServerHostname.new(resolver.names_for(network_interface).first)
|
||||||
|
|
||||||
|
if includes_array? local_network_interfaces, hostname_ips
|
||||||
|
@server_name = hostname
|
||||||
|
@site_addresses << hostname
|
||||||
|
|
||||||
|
network_interface = ServerIpAddress.new((local_network_interfaces & hostname_ips).first)
|
||||||
|
elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
||||||
|
@server_name = hostname
|
||||||
|
@site_addresses << hostname
|
||||||
|
elsif !resolved_name.blank?
|
||||||
|
@server_name = resolved_name
|
||||||
|
@site_addresses << resolved_name
|
||||||
|
else
|
||||||
|
@server_name = network_interface
|
||||||
|
end
|
||||||
|
|
||||||
|
@site_addresses << network_interface
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def includes_array?(a, b)
|
||||||
|
!(a & b).empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_init
|
||||||
|
@listeners << ServerIpAddress.new('::')
|
||||||
|
@listeners << ServerIpAddress.new('0.0.0.0')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is used if bind address is 0.0.0.0, the server name needs to be
|
||||||
|
# blank
|
||||||
|
class AllIpv4Interfaces < AllInterfaces
|
||||||
|
def self.matches?(opts={})
|
||||||
|
opts[:bind_address] == '0.0.0.0' && opts[:server_name].blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use only ipv4 interfaces
|
||||||
|
def local_network_interfaces
|
||||||
|
network_interfaces_inventory.nil? ? [] : network_interfaces_inventory.network_interfaces(:ipv4)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def after_init
|
||||||
|
@listeners << ServerIpAddress.new('0.0.0.0')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is used if bind address is ::, the server name needs to be blank
|
||||||
|
class AllIpv6Interfaces < AllInterfaces
|
||||||
|
def self.matches?(opts={})
|
||||||
|
opts[:bind_address] == '::' && opts[:server_name].blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use only ipv6 interfaces
|
||||||
|
def local_network_interfaces
|
||||||
|
network_interfaces_inventory.nil? ? [] : network_interfaces_inventory.network_interfaces(:ipv6)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def after_init
|
||||||
|
@listeners << ServerIpAddress.new('::')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used if a bind address is given and the server name is blank
|
||||||
|
class BindAddressInformation < BasicInformation
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
@listeners << bind_address
|
||||||
|
@site_addresses << bind_address
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.matches?(opts={})
|
||||||
|
!opts[:bind_address].blank? && opts[:server_name].blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Resolv
|
||||||
|
def resolve_me(resolver)
|
||||||
|
@server_name = ServerHostname.new(resolver.names_for(bind_address).first)
|
||||||
|
@site_addresses << @server_name unless @server_name.blank?
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use if server name is given and bind address is blank
|
||||||
|
class ServerNameInformation < BasicInformation
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
@checks << Checks::RequiresBindAddressIfServerNameIsGiven.new
|
||||||
|
@site_addresses << server_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_me(resolver)
|
||||||
|
@bind_address = ServerIpAddress.new(resolver.ips_for(server_name).first)
|
||||||
|
|
||||||
|
unless bind_address.blank?
|
||||||
|
@listeners << bind_address
|
||||||
|
@site_addresses << bind_address
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.matches?(opts={})
|
||||||
|
opts[:bind_address].blank? && !opts[:server_name].blank?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Only used if bind address and server name are given and bind address is
|
||||||
|
# not :: or 0.0.0.0
|
||||||
|
class BindAddressAndServerNameInformation < BasicInformation
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
@listeners << bind_address
|
||||||
|
@site_addresses << server_name
|
||||||
|
@site_addresses << bind_address
|
||||||
|
|
||||||
|
@checks << Checks::ServerNameResolvesToBindAddress.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.matches?(opts={})
|
||||||
|
!opts[:bind_address].blank? && !opts[:server_name].blank? && !%w(:: 0.0.0.0).include?(opts[:bind_address])
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_me(*); end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the server name is either an ipv4 or ipv6 address, e.g. 127.0.0.1 or
|
||||||
|
# ::1, use this one
|
||||||
|
class ServerNameIsIpInformation < BasicInformation
|
||||||
|
def initialize(opts={})
|
||||||
|
super
|
||||||
|
|
||||||
|
ip = ServerIpAddress.new(server_name.to_s)
|
||||||
|
|
||||||
|
@listeners << ip
|
||||||
|
@site_addresses << ip
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_me(*); end
|
||||||
|
|
||||||
|
def self.matches?(opts={})
|
||||||
|
ip = IPAddr.new(opts[:server_name])
|
||||||
|
|
||||||
|
ip.ipv4? || ip.ipv6?
|
||||||
|
rescue
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,65 @@
|
||||||
|
require 'middleman-core/preview_server/server_ip_address'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# This holds information about local network interfaces on the user systemd
|
||||||
|
class NetworkInterfaceInventory
|
||||||
|
# Return all ip interfaces
|
||||||
|
class All
|
||||||
|
def network_interfaces
|
||||||
|
ipv4_addresses = Socket.ip_address_list.select(&:ipv4?).map { |ai| ServerIpv4Address.new(ai.ip_address) }
|
||||||
|
ipv6_addresses = Socket.ip_address_list.select(&:ipv6?).map { |ai| ServerIpv6Address.new(ai.ip_address) }
|
||||||
|
|
||||||
|
ipv4_addresses + ipv6_addresses
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(*)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return all ipv4 interfaces
|
||||||
|
class Ipv4
|
||||||
|
def network_interfaces
|
||||||
|
Socket.ip_address_list.select { |ai| ai.ipv4? && !ai.ipv4_loopback? }.map { |ai| ServerIpv4Address.new(ai.ip_address) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(type)
|
||||||
|
:ipv4 == type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return all ipv6 interfaces
|
||||||
|
class Ipv6
|
||||||
|
def network_interfaces
|
||||||
|
Socket.ip_address_list.select { |ai| ai.ipv6? && !ai.ipv6_loopback? }.map { |ai| ServerIpv6Address.new(ai.ip_address) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(type)
|
||||||
|
:ipv6 == type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :types
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@types = []
|
||||||
|
@types << Ipv4
|
||||||
|
@types << Ipv6
|
||||||
|
@types << All
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return ip interfaces
|
||||||
|
#
|
||||||
|
# @param [Symbol] type
|
||||||
|
# The type of interface which should be returned
|
||||||
|
def network_interfaces(type=:all)
|
||||||
|
types.find { |t| t.match? type.to_sym }.new.network_interfaces
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,39 @@
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
class ServerHostname
|
||||||
|
class ServerFullHostname < SimpleDelegator
|
||||||
|
def to_s
|
||||||
|
__getobj__.gsub(/\s/, '+')
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(*)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :to_browser, :to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
class ServerPlainHostname < SimpleDelegator
|
||||||
|
def to_s
|
||||||
|
__getobj__.gsub(/\s/, '+') + '.local'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(name)
|
||||||
|
# rubocop:disable Style/CaseEquality
|
||||||
|
name != 'localhost' && /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?\.?$/ === name
|
||||||
|
# rubocop:enable Style/CaseEquality
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :to_browser, :to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new(string)
|
||||||
|
@names = []
|
||||||
|
@names << ServerPlainHostname
|
||||||
|
@names << ServerFullHostname
|
||||||
|
|
||||||
|
@names.find { |n| n.match? string }.new(string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,144 @@
|
||||||
|
require 'middleman-core/dns_resolver'
|
||||||
|
require 'middleman-core/preview_server/information'
|
||||||
|
require 'middleman-core/preview_server/network_interface_inventory'
|
||||||
|
require 'middleman-core/preview_server/tcp_port_prober'
|
||||||
|
require 'middleman-core/preview_server/server_information_validator'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# This class holds all information which the preview server needs to setup a listener
|
||||||
|
#
|
||||||
|
# * server name
|
||||||
|
# * bind address
|
||||||
|
# * port
|
||||||
|
#
|
||||||
|
# Furthermore it probes for a free tcp port, if the default one 4567 is not available.
|
||||||
|
class ServerInformation
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :resolver, :validator, :network_interface_inventory, :informations, :tcp_port_prober
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize(opts={})
|
||||||
|
@resolver = opts.fetch(:resolver, DnsResolver.new)
|
||||||
|
@validator = opts.fetch(:validator, ServerInformationValidator.new)
|
||||||
|
@network_interface_inventory = opts.fetch(:network_interface_inventory, NetworkInterfaceInventory.new)
|
||||||
|
@tcp_port_prober = opts.fetch(:tcp_port_prober, TcpPortProber.new)
|
||||||
|
|
||||||
|
@informations = []
|
||||||
|
@informations << AllInterfaces
|
||||||
|
@informations << AllIpv4Interfaces
|
||||||
|
@informations << AllIpv6Interfaces
|
||||||
|
@informations << ServerNameIsIpInformation
|
||||||
|
@informations << ServerNameInformation
|
||||||
|
@informations << BindAddressInformation
|
||||||
|
@informations << BindAddressAndServerNameInformation
|
||||||
|
@informations << DefaultInformation
|
||||||
|
end
|
||||||
|
|
||||||
|
# The information
|
||||||
|
#
|
||||||
|
# Is cached
|
||||||
|
def information
|
||||||
|
return @information if @information
|
||||||
|
|
||||||
|
# The `DefaultInformation`-class always returns `true`, so there's
|
||||||
|
# always a klass available and find will never return nil
|
||||||
|
listener_klass = informations.find { |l| l.matches? bind_address: @bind_address, server_name: @server_name }
|
||||||
|
@information = listener_klass.new(bind_address: @bind_address, server_name: @server_name)
|
||||||
|
|
||||||
|
@information.show_me_network_interfaces(network_interface_inventory)
|
||||||
|
@information.resolve_me(resolver)
|
||||||
|
@information.port = tcp_port_prober.port(@port)
|
||||||
|
@information.validate_me(validator)
|
||||||
|
|
||||||
|
@information
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use a middleman configuration to get information
|
||||||
|
#
|
||||||
|
# @param [#[]] config
|
||||||
|
# The middleman config
|
||||||
|
def use(config)
|
||||||
|
@bind_address = config[:bind_address]
|
||||||
|
@port = config[:port]
|
||||||
|
@server_name = config[:server_name]
|
||||||
|
|
||||||
|
config[:bind_address] = bind_address
|
||||||
|
config[:port] = port
|
||||||
|
config[:server_name] = server_name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Make information of internal server class avaible to make debugging
|
||||||
|
# easier. This can be used to log the class which was used to determine
|
||||||
|
# the preview server settings
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# The name of the class
|
||||||
|
def handler
|
||||||
|
information.class.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Is the server information valid?
|
||||||
|
#
|
||||||
|
# This is used to output a helpful error message, which can be stored in
|
||||||
|
# `#reason`.
|
||||||
|
#
|
||||||
|
# @return [TrueClass, FalseClass]
|
||||||
|
# The result
|
||||||
|
def valid?
|
||||||
|
information.valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
# The reason why the information is NOT valid
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# The reason why the information is not valid
|
||||||
|
def reason
|
||||||
|
information.reason
|
||||||
|
end
|
||||||
|
|
||||||
|
# The server name
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# The name of the server
|
||||||
|
def server_name
|
||||||
|
information.server_name
|
||||||
|
end
|
||||||
|
|
||||||
|
# The bind address of server
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# The bind address of the server
|
||||||
|
def bind_address
|
||||||
|
information.bind_address
|
||||||
|
end
|
||||||
|
|
||||||
|
# The port on which the server should listen
|
||||||
|
#
|
||||||
|
# @return [Integer]
|
||||||
|
# The port number
|
||||||
|
def port
|
||||||
|
information.port
|
||||||
|
end
|
||||||
|
|
||||||
|
# A list of site addresses
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# A list of addresses which can be used to access the middleman preview
|
||||||
|
# server
|
||||||
|
def site_addresses
|
||||||
|
information.site_addresses
|
||||||
|
end
|
||||||
|
|
||||||
|
# A list of listeners
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# A list of bind address where the
|
||||||
|
def listeners
|
||||||
|
information.listeners
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# Validate user input
|
||||||
|
class ServerInformationValidator
|
||||||
|
# Validate the input
|
||||||
|
#
|
||||||
|
# @param [ServerInformation] information
|
||||||
|
# The information instance which holds information about the preview
|
||||||
|
# server settings
|
||||||
|
#
|
||||||
|
# @param [Array] checks
|
||||||
|
# A list of checks which should be evaluated
|
||||||
|
def validate(information, checks)
|
||||||
|
checks.each { |c| c.validate information }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,55 @@
|
||||||
|
require 'ipaddr'
|
||||||
|
require 'forwardable'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
class ServerIpAddress
|
||||||
|
def self.new(ip_address)
|
||||||
|
@parser = []
|
||||||
|
@parser << ServerIpv6Address
|
||||||
|
@parser << ServerIpv4Address
|
||||||
|
|
||||||
|
@parser.find { |p| p.match? ip_address }.new(ip_address)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class BasicServerIpAddress < SimpleDelegator
|
||||||
|
end
|
||||||
|
|
||||||
|
class ServerIpv4Address < BasicServerIpAddress
|
||||||
|
def to_browser
|
||||||
|
__getobj__.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.match?(*)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ServerIpv6Address < BasicServerIpAddress
|
||||||
|
def to_s
|
||||||
|
__getobj__.sub(/%.*$/, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_browser
|
||||||
|
format('[%s]', to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
if RUBY_VERSION < '2'
|
||||||
|
def self.match?(str)
|
||||||
|
str = str.to_s.sub(/%.*$/, '')
|
||||||
|
IPAddr.new(str).ipv6?
|
||||||
|
rescue StandardError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
def self.match?(str)
|
||||||
|
str = str.to_s.sub(/%.*$/, '')
|
||||||
|
IPAddr.new(str).ipv6?
|
||||||
|
rescue IPAddr::InvalidAddressError, IPAddr::AddressFamilyError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
require 'ipaddr'
|
||||||
|
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# This builds the server urls for the preview server
|
||||||
|
class ServerUrl
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_reader :hosts, :port, :https
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
def initialize(opts={})
|
||||||
|
@hosts = opts.fetch(:hosts)
|
||||||
|
@port = opts.fetch(:port)
|
||||||
|
@https = opts.fetch(:https, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return bind addresses
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# List of bind addresses of format host:port
|
||||||
|
def to_bind_addresses
|
||||||
|
hosts.map { |l| format('"%s:%s"', l.to_s, port) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return server urls
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# List of urls of format http://host:port
|
||||||
|
def to_urls
|
||||||
|
hosts.map { |l| format('"%s://%s:%s"', https? ? 'https' : 'http', l.to_browser, port) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return server config urls
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
# List of urls of format http://host:port/__middleman
|
||||||
|
def to_config_urls
|
||||||
|
hosts.map { |l| format('"%s://%s:%s/__middleman"', https? ? 'https' : 'http', l.to_browser, port) }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def https?
|
||||||
|
https == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
module Middleman
|
||||||
|
class PreviewServer
|
||||||
|
# Probe for tcp ports
|
||||||
|
#
|
||||||
|
# This one first tries `try_port` if this is not available use the free
|
||||||
|
# port returned by TCPServer.
|
||||||
|
class TcpPortProber
|
||||||
|
# Check for port
|
||||||
|
#
|
||||||
|
# @param [Integer] try_port
|
||||||
|
# The port to be checked
|
||||||
|
#
|
||||||
|
# @return [Integer]
|
||||||
|
# The port
|
||||||
|
def port(try_port)
|
||||||
|
server = TCPServer.open(try_port)
|
||||||
|
server.close
|
||||||
|
|
||||||
|
try_port
|
||||||
|
rescue
|
||||||
|
server = TCPServer.open(0)
|
||||||
|
port = server.addr[1]
|
||||||
|
server.close
|
||||||
|
|
||||||
|
port
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -30,7 +30,11 @@ module Middleman
|
||||||
elsif path.is_a? String
|
elsif path.is_a? String
|
||||||
path_clean = ::Middleman::Util.normalize_path(path)
|
path_clean = ::Middleman::Util.normalize_path(path)
|
||||||
if path_clean.include?('*') # It's a glob
|
if path_clean.include?('*') # It's a glob
|
||||||
@ignored_callbacks << proc { |p| File.fnmatch(path_clean, p) }
|
if defined? File::FNM_EXTGLOB
|
||||||
|
@ignored_callbacks << proc { |p| File.fnmatch(path_clean, p, File::FNM_EXTGLOB) }
|
||||||
|
else
|
||||||
|
@ignored_callbacks << proc { |p| File.fnmatch(path_clean, p) }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
# Add a specific-path ignore unless that path is already covered
|
# Add a specific-path ignore unless that path is already covered
|
||||||
return if ignored?(path_clean)
|
return if ignored?(path_clean)
|
||||||
|
|
|
@ -74,6 +74,7 @@ module Middleman
|
||||||
<<-END
|
<<-END
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<link rel="canonical" href="#{url}" />
|
||||||
<meta http-equiv=refresh content="0; url=#{url}" />
|
<meta http-equiv=refresh content="0; url=#{url}" />
|
||||||
<meta name="robots" content="noindex,follow" />
|
<meta name="robots" content="noindex,follow" />
|
||||||
<meta http-equiv="cache-control" content="no-cache" />
|
<meta http-equiv="cache-control" content="no-cache" />
|
||||||
|
|
|
@ -212,10 +212,10 @@ module Middleman
|
||||||
private
|
private
|
||||||
|
|
||||||
def reset_lookup_cache!
|
def reset_lookup_cache!
|
||||||
@lock.synchronize {
|
@lock.synchronize do
|
||||||
@_lookup_by_path = {}
|
@_lookup_by_path = {}
|
||||||
@_lookup_by_destination_path = {}
|
@_lookup_by_destination_path = {}
|
||||||
}
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Removes the templating extensions, while keeping the others
|
# Removes the templating extensions, while keeping the others
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
require 'hamster'
|
require 'hamster'
|
||||||
require 'middleman-core/contracts'
|
require 'middleman-core/contracts'
|
||||||
require 'backports/2.0.0/enumerable/lazy'
|
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
# The standard "record" that contains information about a file on disk.
|
# The standard "record" that contains information about a file on disk.
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# Watcher Library
|
# Watcher Library
|
||||||
require 'listen'
|
require 'listen'
|
||||||
require 'middleman-core/contracts'
|
require 'middleman-core/contracts'
|
||||||
require 'middleman-core/contracts'
|
|
||||||
require 'backports/2.0.0/enumerable/lazy'
|
|
||||||
|
|
||||||
# Monkey patch Listen silencer so `only` works on directories too
|
# Monkey patch Listen silencer so `only` works on directories too
|
||||||
module Listen
|
module Listen
|
||||||
|
@ -123,6 +121,8 @@ module Middleman
|
||||||
# @return [Middleman::SourceFile, nil]
|
# @return [Middleman::SourceFile, nil]
|
||||||
Contract Or[String, Pathname], Maybe[Bool] => Maybe[IsA['Middleman::SourceFile']]
|
Contract Or[String, Pathname], Maybe[Bool] => Maybe[IsA['Middleman::SourceFile']]
|
||||||
def find(path, glob=false)
|
def find(path, glob=false)
|
||||||
|
path = path.to_s.encode!('UTF-8', 'UTF-8-MAC') if RUBY_PLATFORM =~ /darwin/
|
||||||
|
|
||||||
p = Pathname(path)
|
p = Pathname(path)
|
||||||
|
|
||||||
return nil if p.absolute? && !p.to_s.start_with?(@directory.to_s)
|
return nil if p.absolute? && !p.to_s.start_with?(@directory.to_s)
|
||||||
|
|
|
@ -2,6 +2,7 @@ require 'aruba/cucumber'
|
||||||
require 'middleman-core/step_definitions/middleman_steps'
|
require 'middleman-core/step_definitions/middleman_steps'
|
||||||
require 'middleman-core/step_definitions/builder_steps'
|
require 'middleman-core/step_definitions/builder_steps'
|
||||||
require 'middleman-core/step_definitions/server_steps'
|
require 'middleman-core/step_definitions/server_steps'
|
||||||
|
require 'middleman-core/step_definitions/commandline_steps'
|
||||||
|
|
||||||
# Monkeypatch for windows support
|
# Monkeypatch for windows support
|
||||||
module ArubaMonkeypatch
|
module ArubaMonkeypatch
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
When /^I stop (?:middleman|all commands) if the output( of the last command)? contains:$/ do |last_command, expected|
|
||||||
|
begin
|
||||||
|
Timeout.timeout(exit_timeout) do
|
||||||
|
loop do
|
||||||
|
fail "You need to start middleman interactively first." unless @interactive
|
||||||
|
|
||||||
|
if unescape(@interactive.output) =~ Regexp.new(unescape(expected))
|
||||||
|
only_processes.each { |p| p.terminate }
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue ChildProcess::TimeoutError, TimeoutError
|
||||||
|
@interactive.terminate
|
||||||
|
ensure
|
||||||
|
announcer.stdout @interactive.stdout
|
||||||
|
announcer.stderr @interactive.stderr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Make it just a long running process
|
||||||
|
Given /`(.*?)` is running in background/ do |cmd|
|
||||||
|
run(cmd, 120)
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /I have a local hosts file with:/ do |string|
|
||||||
|
step 'I set the environment variables to:', table(
|
||||||
|
%(
|
||||||
|
| variable | value |
|
||||||
|
| MM_HOSTSRC | .hosts |
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
step 'a file named ".hosts" with:', string
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /I start a dns server with:/ do |string|
|
||||||
|
@dns_server.terminate if defined? @dns_server
|
||||||
|
|
||||||
|
port = 5300
|
||||||
|
db_file = 'dns.db'
|
||||||
|
|
||||||
|
step 'I set the environment variables to:', table(
|
||||||
|
%(
|
||||||
|
| variable | value |
|
||||||
|
| MM_DNSRC | 127.0.0.1:#{port}|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
set_env 'PATH', File.expand_path(File.join(current_dir, 'bin')) + ':' + ENV['PATH']
|
||||||
|
write_file db_file, string
|
||||||
|
|
||||||
|
@dns_server = run("dns_server.rb #{db_file} #{port}", 120)
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /I start a mdns server with:/ do |string|
|
||||||
|
@mdns_server.terminate if defined? @mdns_server
|
||||||
|
|
||||||
|
port = 5301
|
||||||
|
db_file = 'mdns.db'
|
||||||
|
|
||||||
|
step 'I set the environment variables to:', table(
|
||||||
|
%(
|
||||||
|
| variable | value |
|
||||||
|
| MM_MDNSRC | 127.0.0.1:#{port}|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
set_env 'PATH', File.expand_path(File.join(current_dir, 'bin')) + ':' + ENV['PATH']
|
||||||
|
write_file db_file, string
|
||||||
|
|
||||||
|
@mdns_server = run("dns_server.rb #{db_file} #{port}", 120)
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /I start a mdns server for the local hostname/ do
|
||||||
|
step %(I start a mdns server with:), "#{Socket.gethostname}: 127.0.0.1"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Make sure each and every process is really dead
|
||||||
|
After do
|
||||||
|
only_processes.each { |p| p.terminate }
|
||||||
|
end
|
||||||
|
|
||||||
|
Before '@ruby-2.1' do
|
||||||
|
skip_this_scenario if RUBY_VERSION < '2.1'
|
||||||
|
end
|
|
@ -1,7 +1,5 @@
|
||||||
# encoding: UTF-8
|
require 'rspec/expectations'
|
||||||
|
require 'capybara/cucumber'
|
||||||
require 'rack/mock'
|
|
||||||
require 'middleman-core/rack'
|
|
||||||
|
|
||||||
Given /^a clean server$/ do
|
Given /^a clean server$/ do
|
||||||
@initialize_commands = []
|
@initialize_commands = []
|
||||||
|
@ -54,7 +52,7 @@ Given /^the Server is running$/ do
|
||||||
end
|
end
|
||||||
|
|
||||||
rack = ::Middleman::Rack.new(@server_inst)
|
rack = ::Middleman::Rack.new(@server_inst)
|
||||||
@browser = ::Rack::MockRequest.new(rack.to_app)
|
Capybara.app = rack.to_app
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,76 +67,72 @@ end
|
||||||
|
|
||||||
When /^I go to "([^\"]*)"$/ do |url|
|
When /^I go to "([^\"]*)"$/ do |url|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
@last_response = @browser.get(URI.encode(url))
|
visit(URI.encode(url).to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^going to "([^\"]*)" should not raise an exception$/ do |url|
|
Then /^going to "([^\"]*)" should not raise an exception$/ do |url|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
last_response = nil
|
expect{ visit(URI.encode(url).to_s) }.to_not raise_exception
|
||||||
expect {
|
|
||||||
last_response = @browser.get(URI.encode(url))
|
|
||||||
}.to_not raise_exception
|
|
||||||
@last_response = last_response
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^the content type should be "([^\"]*)"$/ do |expected|
|
Then /^the content type should be "([^\"]*)"$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.content_type).to start_with(expected)
|
expect(page.response_headers['Content-Type']).to start_with expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should see "([^\"]*)"$/ do |expected|
|
Then /^I should see "([^\"]*)"$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to include(expected)
|
expect(page.body).to include expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should see '([^\']*)'$/ do |expected|
|
Then /^I should see '([^\']*)'$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to include(expected)
|
expect(page.body).to include expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should see:$/ do |expected|
|
Then /^I should see:$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to include(expected)
|
expect(page.body).to include expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should not see "([^\"]*)"$/ do |expected|
|
Then /^I should not see "([^\"]*)"$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to_not include(expected)
|
expect(page.body).not_to include expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should see content matching %r{(.*)}$/ do |expected|
|
Then /^I should see content matching %r{(.*)}$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to match(expected)
|
expect(page.body).to match(expected)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should not see content matching %r{(.*)}$/ do |expected|
|
Then /^I should not see content matching %r{(.*)}$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body).to_not match(expected)
|
expect(page.body).to_not match(expected)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should not see:$/ do |expected|
|
Then /^I should not see:$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@browser.last_response.body).to_not include(expected.chomp)
|
expect(page.body).not_to include expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^the status code should be "([^\"]*)"$/ do |expected|
|
Then /^the status code should be "([^\"]*)"$/ do |expected|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@browser.last_response.status).to eq expected.to_i
|
expect(page.status_code).to eq expected.to_i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should see "([^\"]*)" lines$/ do |lines|
|
Then /^I should see "([^\"]*)" lines$/ do |lines|
|
||||||
cd(".") do
|
cd(".") do
|
||||||
expect(@last_response.body.chomp.split($/).length).to eq(lines.to_i)
|
expect(page.body.chomp.split($/).length).to eq lines.to_i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -199,12 +199,12 @@ module Middleman
|
||||||
# @param [Hash] options Data to pass through.
|
# @param [Hash] options Data to pass through.
|
||||||
# @return [String] The fully qualified asset url
|
# @return [String] The fully qualified asset url
|
||||||
Contract IsA['Middleman::Application'], String, String, Hash => String
|
Contract IsA['Middleman::Application'], String, String, Hash => String
|
||||||
def asset_url(app, path, prefix='', _options={})
|
def asset_url(app, path, prefix='', options={})
|
||||||
# Don't touch assets which already have a full path
|
# Don't touch assets which already have a full path
|
||||||
if path.include?('//') || path.start_with?('data:')
|
if path.include?('//') || path.start_with?('data:') || !options[:current_resource]
|
||||||
path
|
path
|
||||||
else # rewrite paths to use their destination path
|
else # rewrite paths to use their destination path
|
||||||
if resource = app.sitemap.find_resource_by_destination_path(url_for(app, path))
|
result = if resource = app.sitemap.find_resource_by_destination_path(url_for(app, path))
|
||||||
resource.url
|
resource.url
|
||||||
else
|
else
|
||||||
path = File.join(prefix, path)
|
path = File.join(prefix, path)
|
||||||
|
@ -214,6 +214,13 @@ module Middleman
|
||||||
File.join(app.config[:http_prefix], path)
|
File.join(app.config[:http_prefix], path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if options[:relative] != true
|
||||||
|
result
|
||||||
|
else
|
||||||
|
current_dir = Pathname('/' + options[:current_resource].destination_path)
|
||||||
|
Pathname(result).relative_path_from(current_dir.dirname).to_s
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -369,6 +376,30 @@ module Middleman
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Glob a directory and try to keep path encoding consistent.
|
||||||
|
#
|
||||||
|
# @param [String] path The glob path.
|
||||||
|
# @return [Array<String>]
|
||||||
|
def glob_directory(path)
|
||||||
|
results = ::Dir[path]
|
||||||
|
|
||||||
|
return results unless RUBY_PLATFORM =~ /darwin/
|
||||||
|
|
||||||
|
results.map { |r| r.encode('UTF-8', 'UTF-8-MAC') }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the PWD and try to keep path encoding consistent.
|
||||||
|
#
|
||||||
|
# @param [String] path The glob path.
|
||||||
|
# @return [Array<String>]
|
||||||
|
def current_directory
|
||||||
|
result = ::Dir.pwd
|
||||||
|
|
||||||
|
return result unless RUBY_PLATFORM =~ /darwin/
|
||||||
|
|
||||||
|
result.encode('UTF-8', 'UTF-8-MAC')
|
||||||
|
end
|
||||||
|
|
||||||
# Get a relative path to a resource.
|
# Get a relative path to a resource.
|
||||||
#
|
#
|
||||||
# @param [Middleman::Sitemap::Resource] curr_resource The resource.
|
# @param [Middleman::Sitemap::Resource] curr_resource The resource.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module Middleman
|
module Middleman
|
||||||
# Current Version
|
# Current Version
|
||||||
# @return [String]
|
# @return [String]
|
||||||
VERSION = '4.0.0.rc.1' unless const_defined?(:VERSION)
|
VERSION = '4.0.0.rc.2' unless const_defined?(:VERSION)
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,11 +16,10 @@ Gem::Specification.new do |s|
|
||||||
s.files = `git ls-files -z`.split("\0")
|
s.files = `git ls-files -z`.split("\0")
|
||||||
s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
|
s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
|
||||||
s.require_path = 'lib'
|
s.require_path = 'lib'
|
||||||
s.required_ruby_version = '>= 1.9.3'
|
s.required_ruby_version = '>= 2.0.0'
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
s.add_dependency('bundler', ['~> 1.1'])
|
s.add_dependency('bundler', ['~> 1.1'])
|
||||||
s.add_dependency('backports', ['~> 3.6'])
|
|
||||||
s.add_dependency('rack', ['>= 1.4.5', '< 2.0'])
|
s.add_dependency('rack', ['>= 1.4.5', '< 2.0'])
|
||||||
s.add_dependency('tilt', ['~> 1.4.1'])
|
s.add_dependency('tilt', ['~> 1.4.1'])
|
||||||
s.add_dependency('erubis')
|
s.add_dependency('erubis')
|
||||||
|
@ -33,6 +32,9 @@ Gem::Specification.new do |s|
|
||||||
# Watcher
|
# Watcher
|
||||||
s.add_dependency('listen', ['~> 3.0'])
|
s.add_dependency('listen', ['~> 3.0'])
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
s.add_dependency("capybara", ["~> 2.4.4"])
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
s.add_dependency('i18n', ['~> 0.7.0'])
|
s.add_dependency('i18n', ['~> 0.7.0'])
|
||||||
|
|
||||||
|
|
118
middleman-core/spec/middleman-core/dns_resolver_spec.rb
Normal file
118
middleman-core/spec/middleman-core/dns_resolver_spec.rb
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'middleman-core/dns_resolver'
|
||||||
|
|
||||||
|
RSpec.describe Middleman::DnsResolver do
|
||||||
|
subject(:resolver) do
|
||||||
|
described_class.new(
|
||||||
|
hosts_resolver: hosts_resolver,
|
||||||
|
local_link_resolver: local_link_resolver,
|
||||||
|
network_resolver: network_resolver
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:hosts_resolver) { instance_double('Middleman::DnsResolver::HostsResolver') }
|
||||||
|
let(:local_link_resolver) { instance_double('Middleman::DnsResolver::LocalLinkResolver') }
|
||||||
|
let(:network_resolver) { instance_double('Middleman::DnsResolver::NetworkResolver') }
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
allow(network_resolver).to receive(:timeouts=)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#names_for' do
|
||||||
|
context 'when hosts resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getnames).with(unresolved_ip).and_return(resolved_names)
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).not_to receive(:getnames)
|
||||||
|
end
|
||||||
|
expect(network_resolver).not_to receive(:getnames)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ip) { '127.0.0.1' }
|
||||||
|
let(:resolved_names) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.names_for(unresolved_ip)).to eq resolved_names }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when local link resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getnames).with(unresolved_ip).and_return([])
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).to receive(:getnames).with(unresolved_ip).and_return(resolved_names)
|
||||||
|
expect(network_resolver).not_to receive(:getnames)
|
||||||
|
else
|
||||||
|
expect(network_resolver).to receive(:getnames).with(unresolved_ip).and_return(resolved_names)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ip) { '127.0.0.1' }
|
||||||
|
let(:resolved_names) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.names_for(unresolved_ip)).to eq resolved_names }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when network resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getnames).with(unresolved_ip).and_return([])
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).to receive(:getnames).with(unresolved_ip).and_return([])
|
||||||
|
end
|
||||||
|
expect(network_resolver).to receive(:getnames).with(unresolved_ip).and_return(resolved_names)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ip) { '127.0.0.1' }
|
||||||
|
let(:resolved_names) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.names_for(unresolved_ip)).to eq resolved_names }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#ips_for' do
|
||||||
|
context 'when hosts resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getaddresses).with(unresolved_ips).and_return(resolved_name)
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).not_to receive(:getaddresses)
|
||||||
|
end
|
||||||
|
expect(network_resolver).not_to receive(:getaddresses)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ips) { '127.0.0.1' }
|
||||||
|
let(:resolved_name) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.ips_for(unresolved_ips)).to eq resolved_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when local link resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getaddresses).with(unresolved_ips).and_return([])
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).to receive(:getaddresses).with(unresolved_ips).and_return(resolved_name)
|
||||||
|
expect(network_resolver).not_to receive(:getaddresses)
|
||||||
|
else
|
||||||
|
expect(network_resolver).to receive(:getaddresses).with(unresolved_ips).and_return(resolved_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ips) { '127.0.0.1' }
|
||||||
|
let(:resolved_name) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.ips_for(unresolved_ips)).to eq resolved_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when network resolver can resolve name' do
|
||||||
|
before :each do
|
||||||
|
expect(hosts_resolver).to receive(:getaddresses).with(unresolved_ips).and_return([])
|
||||||
|
if RUBY_VERSION >= '2.1'
|
||||||
|
expect(local_link_resolver).to receive(:getaddresses).with(unresolved_ips).and_return([])
|
||||||
|
end
|
||||||
|
expect(network_resolver).to receive(:getaddresses).with(unresolved_ips).and_return(resolved_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:unresolved_ips) { '127.0.0.1' }
|
||||||
|
let(:resolved_name) { %w(localhost) }
|
||||||
|
|
||||||
|
it { expect(resolver.ips_for(unresolved_ips)).to eq resolved_name }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,39 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'middleman-core/preview_server/server_hostname'
|
||||||
|
|
||||||
|
RSpec.describe Middleman::PreviewServer::ServerHostname do
|
||||||
|
subject(:hostname) { described_class.new(string) }
|
||||||
|
let(:string) { 'www.example.com' }
|
||||||
|
|
||||||
|
describe '#to_s' do
|
||||||
|
context 'when hostname' do
|
||||||
|
it { expect(hostname.to_s).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv4' do
|
||||||
|
let(:string) { '127.0.0.1' }
|
||||||
|
it { expect(hostname.to_s).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv6' do
|
||||||
|
let(:string) { '2607:f700:8000:12e:b3d9:1cba:b52:aa1b' }
|
||||||
|
it { expect(hostname.to_s).to eq string }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_browser' do
|
||||||
|
context 'when hostname' do
|
||||||
|
it { expect(hostname.to_browser).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv4' do
|
||||||
|
let(:string) { '127.0.0.1' }
|
||||||
|
it { expect(hostname.to_browser).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv6' do
|
||||||
|
let(:string) { '::1' }
|
||||||
|
it { expect(hostname.to_browser).to eq string }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,43 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'middleman-core/preview_server/server_ip_address'
|
||||||
|
|
||||||
|
RSpec.describe Middleman::PreviewServer::ServerIpAddress do
|
||||||
|
subject(:ip_address) { described_class.new(string) }
|
||||||
|
let(:string) { '127.0.0.1' }
|
||||||
|
|
||||||
|
describe '#to_s' do
|
||||||
|
context 'when ipv4' do
|
||||||
|
let(:string) { '127.0.0.1' }
|
||||||
|
it { expect(ip_address.to_s).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv6' do
|
||||||
|
context 'without suffix' do
|
||||||
|
let(:string) { '2607:f700:8000:12e:b3d9:1cba:b52:aa1b' }
|
||||||
|
it { expect(ip_address.to_s).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with suffix' do
|
||||||
|
let(:string) { '2607:f700:8000:12e:b3d9:1cba:b52:aa1b%wlp1s0' }
|
||||||
|
let(:result) { '2607:f700:8000:12e:b3d9:1cba:b52:aa1b' }
|
||||||
|
it { expect(ip_address.to_s).to eq result }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_browser' do
|
||||||
|
context 'when ip_address' do
|
||||||
|
it { expect(ip_address.to_browser).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv4' do
|
||||||
|
let(:string) { '127.0.0.1' }
|
||||||
|
it { expect(ip_address.to_browser).to eq string }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ipv6' do
|
||||||
|
let(:string) { '2607:f700:8000:12e:b3d9:1cba:b52:aa1b' }
|
||||||
|
it { expect(ip_address.to_browser).to eq "[#{string}]" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,4 +5,30 @@ require 'coveralls'
|
||||||
Coveralls.wear!
|
Coveralls.wear!
|
||||||
|
|
||||||
require 'codeclimate-test-reporter'
|
require 'codeclimate-test-reporter'
|
||||||
CodeClimate::TestReporter.start
|
CodeClimate::TestReporter.start
|
||||||
|
|
||||||
|
require 'aruba/api'
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.include Aruba::Api
|
||||||
|
end
|
||||||
|
|
||||||
|
# encoding: utf-8
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.filter_run :focus
|
||||||
|
config.run_all_when_everything_filtered = true
|
||||||
|
|
||||||
|
config.default_formatter = 'doc' if config.files_to_run.one?
|
||||||
|
|
||||||
|
# config.profile_examples = 10
|
||||||
|
config.order = :random
|
||||||
|
Kernel.srand config.seed
|
||||||
|
|
||||||
|
config.expect_with :rspec do |expectations|
|
||||||
|
expectations.syntax = :expect
|
||||||
|
end
|
||||||
|
|
||||||
|
config.mock_with :rspec do |mocks|
|
||||||
|
mocks.syntax = :expect
|
||||||
|
mocks.verify_partial_doubles = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue