diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.gitignore b/.gitignore index 591c32b0..aabe272b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +.byebug_history +npm-debug.log +manifest.yaml /.bundle .DS_Store coverage diff --git a/.rubocop.yml b/.rubocop.yml index c1b86127..c92b709f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,11 +10,13 @@ AllCops: - '**/tmp/**/*' - '**/bin/**/*' - 'middleman-core/lib/middleman-core/step_definitions/**/*' - - 'middleman-core/lib/vendored-middleman-deps/**/*' - - 'middleman-cli/lib/middleman-cli/templates/**/*' - 'middleman-core/fixtures/**/*' - 'middleman-core/features/**/*' - 'middleman-core/spec/**/*' + - 'middleman-cli/lib/middleman-cli/templates/**/*' + - 'middleman-cli/fixtures/**/*' + - 'middleman-cli/features/**/*' + - 'middleman-cli/spec/**/*' DoubleNegation: Enabled: false LineLength: @@ -37,8 +39,6 @@ AssignmentInCondition: Enabled: false CyclomaticComplexity: Enabled: false -AbcSize: - Enabled: false HandleExceptions: Enabled: false EndAlignment: @@ -52,7 +52,9 @@ FormatString: CaseIndentation: IndentWhenRelativeTo: end TrivialAccessors: - ExactNameMatch: true + Enabled: false +SingleLineBlockParams: + Enabled: false Metrics/AbcSize: Enabled: false Metrics/PerceivedComplexity: @@ -63,3 +65,7 @@ Style/BlockDelimiters: Enabled: false Style/MultilineBlockChain: Enabled: false +Style/SpecialGlobalVars: + Enabled: false +Style/FrozenStringLiteralComment: + Enabled: false diff --git a/.travis.yml b/.travis.yml index 42c2903d..ac5a7f06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,14 @@ before_script: - bundle update rvm: - ruby-head - - 2.3.0 + - 2.3.1 - 2.2.4 - - 2.1 - - 2.0 os: - linux # - osx matrix: fast_finish: true allow_failures: - - rvm: 2.3.0 - rvm: ruby-head env: global: diff --git a/CHANGELOG.md b/CHANGELOG.md index 370a5e81..148aa2e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,78 @@ master === +# 4.1.13 + +* Change how config options are passed to Thor. Removes new Thor warnings from #2017 + +# 4.1.12 + +* Fix broken `ignore { |p| true }` form. + +# 4.1.11 + +* Upgrade to Rack 2. + +# 4.1.10 + +* Fix unicode issues in URL deeplinks. +* Add prefix option to asset_hash (#1949) + +# 4.1.9 + +* Fix `--watcher-*` CLI flags. +* Allow spaces in paths to work with `link_to`. Fixes #1914 +* Add support for dotenv +* Fix asset_url with asset_hash (#1919) +* Allow partial lookups without a current_resource (#1912) + +# 4.1.8 + +* Expose `development?` and `production?` helpers to template context. +* require the `try` core extension (#1911) +* Fix contract for Sitemap::Store.register_resource_list_manipulator (#1907) +* Loosen contract on Resource#source_file to Maybe[String] (#1906) +* Let collection loops access ConfigContext for helpers. #1879 +* Use https:// to clone templates (#1901) +* Allow numbers to be unique page_ids (#1886) +* Prevent infinite loop when encountering files where base filename is a possible templating engine + +# 4.1.7 + +* Upgrade fastimage to 2.0 +* Fix shutdown of external_pipeline commands when config.rb is changed. #1877 +* Allow calls to `app.` to work as collections after initial config parse. #1876 + + +# 4.1.5-4.1.6 + +* Fix file recursion when looking for possible asset dependencies. Major preview server performance improvement. + +# 4.1.4 + +* Unify default extensions for all URL processing extensions. #1855 +* Fix URL regex for `content: ` context of CSS. #1853 +* Make sure CLI config over-rides `config.rb` order. +* Fix relative assets in some contexts. #1842 + +# 4.1.3 + +* Expose all top-level config options to CLI (flags now match config. latency -> watcher_latency, etc). +* Fix directory indexes with `.htm` and `.xhtml` files. #1821 + +# 4.1.2 + +* Add `page_id` concept. Using the `id` key in frontmatter, proxy or page will set an ID on a resource which can be referenced by `url_for` and `link_to`. +* Allow looking for `Gemfile` when setting up a project to fail gracefully. +* Send correct exit code when external_pipeline fails during build. +* Fix error when customizing `layouts_dir`. #1028 +* Fix collections (commands in loops) not being processed by `page` command. #1226 +* Correctly asset_hash sourcemap references. + +# 4.1.1 + +* Fix bad code that made `/__middleman/` break. + # 4.1.0 * Add rewrite_ignore option to asset_hash, asset_host, cache_buster & relative_assets. This proc let's you opt-out of the extension behavior on a per-path basis. @@ -13,6 +85,15 @@ master * Don't parse frontmatter on ignored files. * Fix displaying frontmatter on `/__middleman/sitemap` * Add `skip_build_clean` config which when set to a block, will avoid removing non-generated paths from build, like .git #1716 +* Minor performance improvements +* DRY-up config.rb-specific commands like `ignore` or `path`. +* Fix automatic images with absolute (or images dir missing) paths in markdown. Fixes #1755 +* Fix asset_host in combination with Google Analytics snippet. #1751 +* Show an error message when git CLI is not available. #1765 +* Correctly show file names of GZIP'ed assets. #1364 +* Build file output is now parallel-ized! Use `middleman build --no-parallel` to disable. +* Make template file extensions that get layouts by default configurable via `config[:extensions_with_layout]` +* Remove `=` from inline url matcher. This means paths in HTML attributes MUST be quoted. Fixes #1780 # 4.0.0 diff --git a/Gemfile b/Gemfile index b446cdcd..db4043a0 100644 --- a/Gemfile +++ b/Gemfile @@ -5,12 +5,16 @@ gem 'rake', '~> 10.3', require: false gem 'yard', '~> 0.8', require: false # Test tools -gem 'pry', '~> 0.10', group: :development, require: false -gem 'pry-byebug' -gem 'pry-stack_explorer' +gem 'byebug' gem 'aruba', '~> 0.7.4', require: false gem 'rspec', '~> 3.0', require: false gem 'cucumber', '~> 2.0', require: false +gem 'addressable', '~> 2.4.0', require: false + +# Pry tools +gem 'pry' +gem 'pry-stack_explorer' +gem 'pry-rescue' # Optional middleman dependencies, included for tests gem 'haml', '>= 4.0.5', require: false @@ -20,7 +24,7 @@ gem 'kramdown', '~> 1.2', require: false gem 'slim', '>= 2.0', require: false gem 'liquid', '>= 2.6', require: false gem 'stylus', '>= 1.0', require: false -gem 'sinatra', '>= 1.4', require: false +gem 'sinatra', '>= 2.0.0.beta2', require: false gem 'redcarpet', '>= 3.1', require: false # Dns server to test preview server @@ -28,7 +32,7 @@ gem 'rubydns', '~> 1.0.1', require: false # To test javascript gem 'poltergeist', '~> 1.8', require: false -gem 'phantomjs', '~> 1.9.8.0', require: false +gem 'phantomjs', '~> 2.1.1.0', require: false # For less, note there is no compatible JS runtime for windows gem 'therubyrhino', '>= 2.0', platforms: :jruby diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..6d2dc0e0 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,9 @@ +## Expected behavior and actual behavior + +## Steps to reproduce the problem (from a clean middleman installation) + +## Additional information + +- Ruby version: +- Middleman version: +- OS version: diff --git a/README.md b/README.md index b7203403..df4497f7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The last few years have seen an explosion in the amount and variety of tools dev * [Sass](http://sass-lang.com/) for DRY stylesheets * [CoffeeScript](http://coffeescript.org/) for safer and less verbose javascript -* Multiple asset management solutions, including [Sprockets](https://github.com/sstephenson/sprockets) +* Multiple asset management solutions, including [Sprockets](https://github.com/rails/sprockets) * [ERb](http://ruby-doc.org/stdlib-2.0.0/libdoc/erb/rdoc/ERB.html) & [Haml](http://haml.info/) for dynamic pages and simplified HTML syntax **Middleman** gives the stand-alone developer access to all these tools and many, many more. Why would you use a stand-alone framework instead of Ruby on Rails? @@ -91,7 +91,7 @@ The best way to get quick responses to your issues and swift fixes to your bugs ## Donate -[Click here to lend your support to Middleman](https://spacebox.io/s/4dXbHBorC3) +[Click here to lend your support to Middleman](https://plasso.co/s/4dXbHBorC3) ## Versioning @@ -121,6 +121,6 @@ Copyright (c) 2010-2015 Thomas Reynolds. MIT Licensed, see [LICENSE] for details [codeclimate]: https://codeclimate.com/github/middleman/middleman [gittip]: https://www.gittip.com/middleman/ [rubyinstaller]: http://rubyinstaller.org/ -[RubyInstaller-Devkit]: http:rubyinstaller.org/add-ons/devkit/ +[RubyInstaller-Devkit]: http://rubyinstaller.org/add-ons/devkit/ [rubydoc]: http://rubydoc.info/github/middleman/middleman [LICENSE]: https://github.com/middleman/middleman/blob/master/LICENSE.md diff --git a/Rakefile b/Rakefile index 236a2d83..508c3a1d 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,7 @@ require 'rake' require File.expand_path('../middleman-core/lib/middleman-core/version.rb', __FILE__) ROOT = File.expand_path(File.dirname(__FILE__)) -GEM_NAME = 'middleman' +GEM_NAME = 'middleman'.freeze middleman_gems = %w(middleman-core middleman-cli middleman) GEM_PATHS = middleman_gems.freeze @@ -36,7 +36,7 @@ end desc 'Generate documentation for all middleman gems' task :doc do GEM_PATHS.each do |g| - Dir.chdir("#{File.join(ROOT, g)}") { sh "#{Gem.ruby} -S rake yard" } + Dir.chdir(File.join(ROOT, g).to_s) { sh "#{Gem.ruby} -S rake yard" } end end @@ -45,14 +45,14 @@ task :test do Rake::Task['rubocop'].invoke GEM_PATHS.each do |g| - Dir.chdir("#{File.join(ROOT, g)}") { sh "#{Gem.ruby} -S rake test" } + Dir.chdir(File.join(ROOT, g).to_s) { sh "#{Gem.ruby} -S rake test" } end end desc 'Run specs for all middleman gems' task :spec do GEM_PATHS.each do |g| - Dir.chdir("#{File.join(ROOT, g)}") { sh "#{Gem.ruby} -S rake spec" } + Dir.chdir(File.join(ROOT, g).to_s) { sh "#{Gem.ruby} -S rake spec" } end end diff --git a/middleman-cli/Rakefile b/middleman-cli/Rakefile index a7cd6621..db0d1cb8 100644 --- a/middleman-cli/Rakefile +++ b/middleman-cli/Rakefile @@ -1,4 +1,4 @@ # coding:utf-8 -RAKE_ROOT = __FILE__ -GEM_NAME = 'middleman-cli' +RAKE_ROOT = __FILE__.freeze +GEM_NAME = 'middleman-cli'.freeze require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper') diff --git a/middleman-cli/bin/middleman b/middleman-cli/bin/middleman index 165b7bc9..8b381a08 100755 --- a/middleman-cli/bin/middleman +++ b/middleman-cli/bin/middleman @@ -4,11 +4,37 @@ require 'middleman-core/profiling' if ARGV.include? '--profile' Middleman::Profiling.profiler = Middleman::Profiling::RubyProfProfiler.new end -Middleman::Profiling.start +# Middleman::Profiling.start require "middleman-core/load_paths" Middleman.setup_load_paths +require 'dotenv' +::Dotenv.load + +require 'middleman-core' +require 'middleman-core/logger' + +module Middleman::Cli + class << self + attr_accessor :config + end + + def self.import_config(base) + ::Middleman::Cli.config.all_settings.each do |setting| + if setting.default.is_a?(String) || setting.default.is_a?(NilClass) + base.class_option setting.key, + type: :string, + desc: setting.description + elsif setting.default.is_a?(TrueClass) || setting.default.is_a?(FalseClass) + base.class_option setting.key, + type: :boolean, + desc: setting.description + end + end + end +end + require "middleman-cli" # Change directory to the root @@ -19,5 +45,26 @@ if ARGV[0] != 'help' && (ARGV.length < 1 || ARGV.first.include?('-')) ARGV.unshift('server') end +::Middleman::Logger.singleton(3) +::Middleman::Cli.config = ::Middleman::Application.new do + # + config[:environment] = (ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development').to_sym + config[:mode] = :config + config[:exit_before_ready] = true + config[:watcher_disable] = true + config[:disable_sitemap] = true +end.config + +# Require the Middleman version +require 'middleman-core/version' + +# Include the core CLI items +require 'middleman-cli/init' +require 'middleman-cli/extension' +require 'middleman-cli/server' +require 'middleman-cli/build' +require 'middleman-cli/console' +require 'middleman-cli/config' + # Start the CLI Middleman::Cli::Base.start(ARGV) diff --git a/middleman-core/features/cli_extension.feature b/middleman-cli/features/cli_extension.feature similarity index 100% rename from middleman-core/features/cli_extension.feature rename to middleman-cli/features/cli_extension.feature diff --git a/middleman-core/features/cli_init.feature b/middleman-cli/features/cli_init.feature similarity index 94% rename from middleman-core/features/cli_init.feature rename to middleman-cli/features/cli_init.feature index 52aa8f7b..96595422 100644 --- a/middleman-core/features/cli_init.feature +++ b/middleman-cli/features/cli_init.feature @@ -63,6 +63,10 @@ Feature: Middleman CLI And the file "Gemfile" should contain "middleman-blog" And the file ".gitignore" should exist + Scenario: Create an invalid project using Middleman directory + When I run `middleman init MY_PROJECT -T does-not-exist-for-reals` + Then the exit status should be 1 + Scenario: Create a new project using github(user/repository) When I run `middleman init MY_PROJECT -T middleman/middleman-templates-default` interactively And I type "y" diff --git a/middleman-core/features/cli/preview_server-hook.feature b/middleman-cli/features/preview_server-hook.feature similarity index 100% rename from middleman-core/features/cli/preview_server-hook.feature rename to middleman-cli/features/preview_server-hook.feature diff --git a/middleman-core/features/cli/preview_server.feature b/middleman-cli/features/preview_server.feature similarity index 100% rename from middleman-core/features/cli/preview_server.feature rename to middleman-cli/features/preview_server.feature diff --git a/middleman-cli/features/support/env.rb b/middleman-cli/features/support/env.rb new file mode 100644 index 00000000..8044deab --- /dev/null +++ b/middleman-cli/features/support/env.rb @@ -0,0 +1,19 @@ +ENV["TEST"] = "true" + +require 'sassc' + +require 'simplecov' +SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/../..')) + +require 'phantomjs/poltergeist' +Capybara.javascript_driver = :poltergeist + +require 'coveralls' +Coveralls.wear! + +require 'codeclimate-test-reporter' +CodeClimate::TestReporter.start + +PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__))) +require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-cli') +require File.join(File.dirname(PROJECT_ROOT_PATH), 'middleman-core', 'lib', 'middleman-core', 'step_definitions') diff --git a/middleman-core/fixtures/preview-server-app/bin/dns_server.rb b/middleman-cli/fixtures/preview-server-app/bin/dns_server.rb similarity index 100% rename from middleman-core/fixtures/preview-server-app/bin/dns_server.rb rename to middleman-cli/fixtures/preview-server-app/bin/dns_server.rb diff --git a/middleman-core/fixtures/preview-server-app/config.rb b/middleman-cli/fixtures/preview-server-app/config.rb similarity index 100% rename from middleman-core/fixtures/preview-server-app/config.rb rename to middleman-cli/fixtures/preview-server-app/config.rb diff --git a/middleman-core/fixtures/preview-server-app/source/index.html.erb b/middleman-cli/fixtures/preview-server-app/source/index.html.erb similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/index.html.erb rename to middleman-cli/fixtures/preview-server-app/source/index.html.erb diff --git a/middleman-core/fixtures/preview-server-app/source/layout.erb b/middleman-cli/fixtures/preview-server-app/source/layout.erb similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/layout.erb rename to middleman-cli/fixtures/preview-server-app/source/layout.erb diff --git a/middleman-core/fixtures/preview-server-app/source/layouts/custom.erb b/middleman-cli/fixtures/preview-server-app/source/layouts/custom.erb similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/layouts/custom.erb rename to middleman-cli/fixtures/preview-server-app/source/layouts/custom.erb diff --git a/middleman-core/fixtures/preview-server-app/source/real.html b/middleman-cli/fixtures/preview-server-app/source/real.html similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/real.html rename to middleman-cli/fixtures/preview-server-app/source/real.html diff --git a/middleman-core/fixtures/preview-server-app/source/real/index.html.erb b/middleman-cli/fixtures/preview-server-app/source/real/index.html.erb similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/real/index.html.erb rename to middleman-cli/fixtures/preview-server-app/source/real/index.html.erb diff --git a/middleman-core/fixtures/preview-server-app/source/should_be_ignored.html b/middleman-cli/fixtures/preview-server-app/source/should_be_ignored.html similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/should_be_ignored.html rename to middleman-cli/fixtures/preview-server-app/source/should_be_ignored.html diff --git a/middleman-core/fixtures/preview-server-app/source/should_be_ignored2.html b/middleman-cli/fixtures/preview-server-app/source/should_be_ignored2.html similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/should_be_ignored2.html rename to middleman-cli/fixtures/preview-server-app/source/should_be_ignored2.html diff --git a/middleman-core/fixtures/preview-server-app/source/should_be_ignored3.html b/middleman-cli/fixtures/preview-server-app/source/should_be_ignored3.html similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/should_be_ignored3.html rename to middleman-cli/fixtures/preview-server-app/source/should_be_ignored3.html diff --git a/middleman-core/fixtures/preview-server-app/source/static.html b/middleman-cli/fixtures/preview-server-app/source/static.html similarity index 100% rename from middleman-core/fixtures/preview-server-app/source/static.html rename to middleman-cli/fixtures/preview-server-app/source/static.html diff --git a/middleman-core/fixtures/preview-server-hook-app/config.rb b/middleman-cli/fixtures/preview-server-hook-app/config.rb similarity index 100% rename from middleman-core/fixtures/preview-server-hook-app/config.rb rename to middleman-cli/fixtures/preview-server-hook-app/config.rb diff --git a/middleman-core/fixtures/preview-server-hook-app/source/index.html.erb b/middleman-cli/fixtures/preview-server-hook-app/source/index.html.erb similarity index 100% rename from middleman-core/fixtures/preview-server-hook-app/source/index.html.erb rename to middleman-cli/fixtures/preview-server-hook-app/source/index.html.erb diff --git a/middleman-cli/lib/middleman-cli.rb b/middleman-cli/lib/middleman-cli.rb index 83b95d30..e17137e7 100644 --- a/middleman-cli/lib/middleman-cli.rb +++ b/middleman-cli/lib/middleman-cli.rb @@ -21,14 +21,3 @@ module Middleman::Cli end end end - -# Require the Middleman version -require 'middleman-core/version' - -# Include the core CLI items -require 'middleman-cli/init' -require 'middleman-cli/extension' -require 'middleman-cli/server' -require 'middleman-cli/build' -require 'middleman-cli/console' -require 'middleman-cli/config' diff --git a/middleman-cli/lib/middleman-cli/build.rb b/middleman-cli/lib/middleman-cli/build.rb index 3ff1d638..9e521dde 100644 --- a/middleman-cli/lib/middleman-cli/build.rb +++ b/middleman-cli/lib/middleman-cli/build.rb @@ -1,3 +1,5 @@ +require 'middleman-core/application' + # CLI Module module Middleman::Cli # The CLI Build class @@ -8,12 +10,15 @@ module Middleman::Cli class_option :environment, aliases: '-e', - default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'production', - desc: 'The environment Middleman will run under' + default: ENV['MM_ENV'] || ENV['RACK_ENV'] || :production class_option :clean, type: :boolean, default: true, desc: 'Remove orphaned files from build (--no-clean to disable)' + class_option :parallel, + type: :boolean, + default: true, + desc: 'Output files in parallel (--no-parallel to disable)' class_option :glob, type: :string, aliases: '-g', @@ -24,7 +29,7 @@ module Middleman::Cli default: false, desc: 'Print debug messages' class_option :instrument, - type: :string, + type: :boolean, default: false, desc: 'Print instrument messages' class_option :profile, @@ -32,6 +37,8 @@ module Middleman::Cli default: false, desc: 'Generate profiling report for the build' + Middleman::Cli.import_config(self) + # Core build Thor command # @return [void] def build @@ -44,19 +51,21 @@ module Middleman::Cli require 'middleman-core/builder' require 'fileutils' - env = options['environment'].to_sym verbose = options['verbose'] ? 0 : 1 instrument = options['instrument'] builder = nil + cli_options = options ::Middleman::Logger.singleton(verbose, instrument) - ::Middleman::Util.instrument "builder_setup" do + ::Middleman::Util.instrument 'builder.setup' do @app = ::Middleman::Application.new do config[:mode] = :build - config[:environment] = env config[:show_exceptions] = false + config[:cli_options] = cli_options.each_with_object({}) do |(k, v), sum| + sum[k] = v + end end builder = Middleman::Builder.new(@app, @@ -67,7 +76,7 @@ module Middleman::Cli builder.on_build_event(&method(:on_event)) end - ::Middleman::Util.instrument "builder_run" do + ::Middleman::Util.instrument 'builder.run' do if builder.run! clean_directories! if options['clean'] shell.say 'Project built successfully.' diff --git a/middleman-cli/lib/middleman-cli/config.rb b/middleman-cli/lib/middleman-cli/config.rb index 902ea216..add8730a 100644 --- a/middleman-cli/lib/middleman-cli/config.rb +++ b/middleman-cli/lib/middleman-cli/config.rb @@ -23,6 +23,9 @@ module Middleman::Cli ::Middleman::Logger.singleton(2, false) app = ::Middleman::Application.new do + config[:mode] = :config + config[:disable_sitemap] = true + config[:watcher_disable] = true config[:exit_before_ready] = true config[:environment] = opts[:environment].to_sym if opts[:environment] end diff --git a/middleman-cli/lib/middleman-cli/init.rb b/middleman-cli/lib/middleman-cli/init.rb index 469d9d4c..e8e5770c 100644 --- a/middleman-cli/lib/middleman-cli/init.rb +++ b/middleman-cli/lib/middleman-cli/init.rb @@ -4,6 +4,8 @@ module Middleman::Cli class Init < Thor::Group include Thor::Actions + GIT_CMD = 'git'.freeze + check_unknown_options! argument :target, type: :string, default: '.' @@ -25,6 +27,13 @@ module Middleman::Cli require 'fileutils' require 'tmpdir' + unless git_present? + msg = 'You need to install the git command line tool to initialize a new project. ' + msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" + say msg, :red + exit 1 + end + repo_path, repo_branch = if shortname?(options[:template]) require 'open-uri' require 'json' @@ -51,10 +60,11 @@ module Middleman::Cli begin branch_cmd = repo_branch ? "-b #{repo_branch} " : '' - run("git clone --depth 1 #{branch_cmd}#{repo_path} #{dir}") + git_path = "#{branch_cmd}#{repo_path}" + run("#{GIT_CMD} clone --depth 1 #{branch_cmd}#{repo_path} #{dir}") - unless File.directory?(dir) - say 'Git clone failed, maybe the url is invalid or you don\'t have the permissions?', :red + unless $?.success? + say "Git clone command failed. Make sure git repository exists: #{git_path}", :red exit 1 end @@ -79,12 +89,31 @@ module Middleman::Cli protected + # Copied from Bundler + def git_present? + return @git_present if defined?(@git_present) + @git_present = which(GIT_CMD) || which('git.exe') + end + + # Copied from Bundler + def which(executable) + if File.file?(executable) && File.executable?(executable) + executable + elsif ENV['PATH'] + path = ENV['PATH'].split(File::PATH_SEPARATOR).find do |p| + abs_path = File.join(p, executable) + File.file?(abs_path) && File.executable?(abs_path) + end + path && File.expand_path(executable, path) + end + end + def shortname?(repo) repo.split('/').length == 1 end def repository_path(repo) - repo.include?('://') || repo.include?('git@') ? repo : "git://github.com/#{repo}.git" + repo.include?('://') || repo.include?('git@') ? repo : "https://github.com/#{repo}.git" end # Add to CLI diff --git a/middleman-cli/lib/middleman-cli/server.rb b/middleman-cli/lib/middleman-cli/server.rb index ab387ee6..85e75a9f 100644 --- a/middleman-cli/lib/middleman-cli/server.rb +++ b/middleman-cli/lib/middleman-cli/server.rb @@ -5,56 +5,33 @@ module Middleman::Cli check_unknown_options! class_option :environment, - aliases: '-e', - default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development', - desc: 'The environment Middleman will run under' + aliases: '-e' class_option :port, - aliases: '-p', - desc: 'The port Middleman will listen on' + aliases: '-p' class_option :server_name, - aliases: '-s', - desc: 'The server name Middleman will use' + aliases: '-s' 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" + aliases: '-b' class_option :verbose, type: :boolean, default: false, desc: 'Print debug messages' class_option :instrument, - type: :string, - default: false, - desc: 'Print instrument messages' - class_option :disable_watcher, type: :boolean, default: false, - desc: 'Disable the file change and delete watcher process' + desc: 'Print instrument messages' class_option :profile, type: :boolean, default: false, desc: 'Generate profiling report for server startup' - class_option :force_polling, - type: :boolean, - default: false, - desc: 'Force file watcher into polling mode' - class_option :latency, - type: :numeric, - aliases: '-l', - default: 0.5, - desc: 'Set file watcher latency, in seconds' class_option :daemon, type: :boolean, aliases: '-d', default: false, desc: 'Daemonize preview server' + Middleman::Cli.import_config(self) + # Start the server def server require 'middleman-core' @@ -66,24 +43,14 @@ module Middleman::Cli end params = { - port: options['port'], - 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'], debug: options['verbose'], instrumenting: options['instrument'], - disable_watcher: options['disable_watcher'], reload_paths: options['reload_paths'], - force_polling: options['force_polling'], - latency: options['latency'], daemon: options['daemon'] } puts '== The Middleman is loading' - ::Middleman::PreviewServer.start(params) + ::Middleman::PreviewServer.start(params, options) end # Add to CLI diff --git a/middleman-cli/middleman-cli.gemspec b/middleman-cli/middleman-cli.gemspec index f2719efc..e9447a9c 100644 --- a/middleman-cli/middleman-cli.gemspec +++ b/middleman-cli/middleman-cli.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0") s.executable = 'middleman' s.require_path = 'lib' - s.required_ruby_version = '>= 2.0.0' + s.required_ruby_version = '>= 2.2.0' # CLI s.add_dependency('thor', ['>= 0.17.0', '< 2.0']) diff --git a/middleman-core/Rakefile b/middleman-core/Rakefile index 3efd63ea..198f09ee 100644 --- a/middleman-core/Rakefile +++ b/middleman-core/Rakefile @@ -1,4 +1,4 @@ # coding:utf-8 -RAKE_ROOT = __FILE__ +RAKE_ROOT = __FILE__.freeze GEM_NAME = ENV['NAME'] || 'middleman-core' require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper') diff --git a/middleman-core/features/asset_hash.feature b/middleman-core/features/asset_hash.feature index 751b9e30..7c173800 100644 --- a/middleman-core/features/asset_hash.feature +++ b/middleman-core/features/asset_hash.feature @@ -63,8 +63,8 @@ Feature: Assets get file hashes appended to them and references to them are upda Given the Server is running at "asset-hash-app" When I go to "/" Then I should see 'href="apple-touch-icon.png"' - And I should see 'href="stylesheets/site-d2959d87.css"' - And I should see 'href="stylesheets/fragment-a06f0dfc.css"' + And I should see 'href="stylesheets/site-d1a750ca.css"' + And I should see 'href="stylesheets/fragment-99b76247.css"' And I should see 'src="javascripts/application-1d8d5276.js"' And I should see 'src="images/100px-5fd6fb90.jpg"' And I should see 'srcset="images/100px-5fd6fb90.jpg 1x, images/200px-c11eb203.jpg 2x, images/300px-59adce76.jpg 3x"' @@ -72,11 +72,11 @@ Feature: Assets get file hashes appended to them and references to them are upda And I should see 'src="images/100px-5fd6fb90.jpg?#test"' And I should see 'src="images/100px-5fd6fb90.jpg#test"' When I go to "/subdir/" - Then I should see 'href="../stylesheets/site-d2959d87.css"' + Then I should see 'href="../stylesheets/site-d1a750ca.css"' And I should see 'src="../javascripts/application-1d8d5276.js"' And I should see 'src="../images/100px-5fd6fb90.jpg"' When I go to "/other/" - Then I should see 'href="../stylesheets/site-d2959d87.css"' + Then I should see 'href="../stylesheets/site-d1a750ca.css"' And I should see 'src="../javascripts/application-1d8d5276.js"' And I should see 'src="../images/100px-5fd6fb90.jpg"' And I should see 'src="../images/100px-5fd6fb90.jpg?test"' @@ -84,8 +84,8 @@ Feature: Assets get file hashes appended to them and references to them are upda And I should see 'src="../images/100px-5fd6fb90.jpg#test"' When I go to "/javascripts/application-1d8d5276.js" Then I should see "img.src = '/images/100px-5fd6fb90.jpg'" - When I go to "/stylesheets/site-d2959d87.css" - Then I should see 'background-image: url("../images/100px-5fd6fb90.jpg")' + When I go to "/stylesheets/site-d1a750ca.css" + Then I should see 'background-image: url("../images/100px-5fd6fb90.jpg");' When I go to "/api.json" Then I should see 'images/100px-5fd6fb90.gif' And I should see 'images/100px-5fd6fb90.jpg' @@ -94,11 +94,11 @@ Feature: Assets get file hashes appended to them and references to them are upda Then I should see 'images/100px-5fd6fb90.gif' And I should see 'images/100px-5fd6fb90.jpg' And I should see 'images/100px-1242c368.png' - When I go to "/stylesheets/fragment-a06f0dfc.css" - And I should see 'url("../images/100px-5fd6fb90.jpg")' - And I should see 'url("../images/100px-5fd6fb90.jpg?test")' - And I should see 'url("../images/100px-5fd6fb90.jpg?#test")' - And I should see 'url("../images/100px-5fd6fb90.jpg#test")' + When I go to "/stylesheets/fragment-99b76247.css" + And I should see 'url("../images/100px-5fd6fb90.jpg");' + And I should see 'url("../images/100px-5fd6fb90.jpg?test");' + And I should see 'url("../images/100px-5fd6fb90.jpg?#test");' + And I should see 'url("../images/100px-5fd6fb90.jpg#test");' Scenario: Hashed assets work with Slim Given the Server is running at "asset-hash-app" @@ -107,25 +107,65 @@ Feature: Assets get file hashes appended to them and references to them are upda And I should see 'src="images/100px-5fd6fb90.jpg"' And I should see 'srcset="images/100px-5fd6fb90.jpg 1x, images/200px-c11eb203.jpg 2x, images/300px-59adce76.jpg 3x"' - Scenario: Enabling an asset host still produces hashed files and references + Scenario: Enabling an asset host still produces hashed files and references (hash first) + Given a fixture app "asset-hash-host-app" + And a file named "config.rb" with: + """ + set :sass_source_maps, false + activate :asset_hash + activate :directory_indexes + activate :asset_host, host: 'http://middlemanapp.com' + """ Given the Server is running at "asset-hash-host-app" When I go to "/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"' - Then I should see 'href="http://middlemanapp.com/stylesheets/fragment-a772891f.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/fragment-2902933e.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"' When I go to "/subdir/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' When I go to "/other/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"' - When I go to "/stylesheets/fragment-a772891f.css" + When I go to "/stylesheets/fragment-2902933e.css" + And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg");' + And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?test");' + And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test");' + And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg#test");' + + Scenario: Enabling an asset host still produces hashed files and references (host first) + Given a fixture app "asset-hash-host-app" + And a file named "config.rb" with: + """ + set :sass_source_maps, false + activate :asset_host, host: 'http://middlemanapp.com' + activate :directory_indexes + activate :asset_hash + """ + Given the Server is running at "asset-hash-host-app" + When I go to "/" + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/fragment-2902933e.css"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"' + When I go to "/subdir/" + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' + When I go to "/other/" + Then I should see 'href="http://middlemanapp.com/stylesheets/site-7474cadd.css"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"' + And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"' + When I go to "/stylesheets/fragment-2902933e.css" And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg")' And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?test")' And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test")' @@ -139,14 +179,14 @@ Feature: Assets get file hashes appended to them and references to them are upda font-size: 14px """ When I go to "/partials/" - Then I should see 'href="../stylesheets/uses_partials-44fb2764.css' + Then I should see 'href="../stylesheets/uses_partials-4d4e34e6.css' And the file "source/stylesheets/_partial.sass" has the contents """ body font-size: 18px !important """ When I go to "/partials/" - Then I should see 'href="../stylesheets/uses_partials-10d8ae33.css' + Then I should see 'href="../stylesheets/uses_partials-ec347271.css' Scenario: The asset hash should change when a Rack-based filter changes Given a fixture app "asset-hash-app" @@ -160,12 +200,10 @@ Feature: Assets get file hashes appended to them and references to them are upda """ Given the Server is running at "asset-hash-app" When I go to "/" - Then I should see 'href="stylesheets/site-30784643.css' - When I go to "stylesheets/site-30784643.css" - Then I should see 'background-image' + Then I should see 'href="stylesheets/site-5ad7def0.css' + When I go to "stylesheets/site-5ad7def0.css" + Then I should see 'background-image: url("../images/100px-5fd6fb90.jpg")' Then I should see 'Added by Rack filter' - When I go to "stylesheets/site-7474cadd.css" - Then I should see 'Not Found' Scenario: Hashed-asset files are not produced for ignored paths Given a fixture app "asset-hash-app" @@ -247,5 +285,40 @@ Feature: Assets get file hashes appended to them and references to them are upda When I cd to "build" Then the following files should exist: | javascripts/jquery.min-276c87ff.js | + | stylesheets/test-7de2ad06.css | And the following files should not exist: | javascripts/jquery.min.js | + And the file "stylesheets/test-7de2ad06.css" should contain: + """ + .no-bug{background-image:url(/images/100px-5fd6fb90.jpg)} + .bug{content:"";background-image:url(/images/100px-5fd6fb90.jpg)} + .no-bug{content:""; background-image:url(/images/100px-5fd6fb90.jpg)} + """ + + Scenario: Source map paths include the hash + Given a successfully built app at "asset-hash-source-map" + When I cd to "build" + Then the following files should exist: + | index.html | + | javascripts/application-4553338c.js | + | javascripts/application.js-22cc2b5f.map | + | index.html | + And the following files should not exist: + | javascripts/application.js | + | javascripts/application.js.map | + + And the file "javascripts/application-4553338c.js" should contain "//# sourceMappingURL=application.js-22cc2b5f.map" + + Scenario: Hashes can contain a prefix + Given a successfully built app at "asset-hash-prefix" + When I cd to "build" + Then the following files should exist: + | index.html | + | javascripts/application-myprefix-4553338c.js | + | javascripts/application.js-myprefix-22cc2b5f.map | + | index.html | + And the following files should not exist: + | javascripts/application.js | + | javascripts/application.js.map | + + And the file "javascripts/application-myprefix-4553338c.js" should contain "//# sourceMappingURL=application.js-myprefix-22cc2b5f.map" diff --git a/middleman-core/features/asset_host.feature b/middleman-core/features/asset_host.feature index d223b997..0433b61b 100644 --- a/middleman-core/features/asset_host.feature +++ b/middleman-core/features/asset_host.feature @@ -8,6 +8,7 @@ Feature: Alternate between multiple asset hosts """ And the Server is running When I go to "/asset_host.html" + Then I should see "'.google-analytics.com/ga.js'" Then I should see 'src="https://code.jquery.com/jquery-2.1.3.min.js"' Then I should see content matching %r{http://assets1.example.com/} Then I should not see content matching %r{http://assets1.example.com//} @@ -16,13 +17,16 @@ Feature: Alternate between multiple asset hosts When I go to "/stylesheets/asset_host.css" Then I should see content matching %r{http://assets1.example.com/} Then I should not see content matching %r{http://assets1.example.com//} + When I go to "/javascripts/asset_host.js" + Then I should not see content matching %r{http://assets1.example.com/} Scenario: Set proc host with inline-option Given a fixture app "asset-host-app" And a file named "config.rb" with: """ activate :asset_host, host: Proc.new { |asset| - "http://assets%d.example.com" % (asset.hash % 4) + hash = Digest::MD5.digest(asset).bytes.map!(&:ord).reduce(&:+) + "http://assets%d.example.com" % (hash % 4) } """ And the Server is running diff --git a/middleman-core/features/automatic_image_sizes.feature b/middleman-core/features/automatic_image_sizes.feature index 89f9d7a5..50a0b02e 100644 --- a/middleman-core/features/automatic_image_sizes.feature +++ b/middleman-core/features/automatic_image_sizes.feature @@ -2,15 +2,28 @@ Feature: Automatically detect and insert image dimensions into tags In order to speed up development and appease YSlow Scenario: Rendering an image with the feature disabled - Given "automatic_image_sizes" feature is "disabled" + Given a fixture app "automatic-image-size-app" + And a file named "config.rb" with: + """ + """ And the Server is running at "automatic-image-size-app" When I go to "/auto-image-sizes.html" Then I should not see "width=" And I should not see "height=" - + When I go to "/markdown-sizes.html" + Then I should not see "width=" + And I should not see "height=" + Scenario: Rendering an image with the feature enabled - Given "automatic_image_sizes" feature is "enabled" + Given a fixture app "automatic-image-size-app" + And a file named "config.rb" with: + """ + activate :automatic_image_sizes + """ And the Server is running at "automatic-image-size-app" When I go to "/auto-image-sizes.html" - Then I should see "width=" - And I should see "height=" \ No newline at end of file + Then I should see 'width="1"' + And I should see 'height="1"' + When I go to "/markdown-sizes.html" + Then I should see 'width="1"' + And I should see 'height="1"' diff --git a/middleman-core/features/builder.feature b/middleman-core/features/builder.feature index b61f5cdc..d99c165c 100644 --- a/middleman-core/features/builder.feature +++ b/middleman-core/features/builder.feature @@ -20,13 +20,13 @@ Feature: Builder | layout | | layouts/custom | | layouts/content_for | - + And the file "index.html" should contain "Comment in layout" And the file "index.html" should contain "

Welcome

" And the file "static.html" should contain "Static, no code!" And the file "services/index.html" should contain "Services" And the file "stylesheets/static.css" should contain "body" - + Scenario: Build glob Given a successfully built app at "glob-app" with flags "--glob '*.css'" When I cd to "build" @@ -34,15 +34,19 @@ Feature: Builder | index.html | Then the following files should exist: | stylesheets/site.css | - + Scenario: Build with errors Given a built app at "build-with-errors-app" Then the exit status should be 1 - + Scenario: Build empty errors Given a built app at "empty-app" Then the exit status should be 1 + Scenario: Build external_pipeline errors + Given a built app at "external-pipeline-error" + Then the exit status should be 1 + Scenario: Build alias (b) Given a fixture app "large-build-app" When I run `middleman b` diff --git a/middleman-core/features/collections.feature b/middleman-core/features/collections.feature index e12ca0a5..2d313a3c 100644 --- a/middleman-core/features/collections.feature +++ b/middleman-core/features/collections.feature @@ -144,6 +144,33 @@ Feature: Collections And I should see 'Article: Blog3 Another Article' And I should see 'Article: Blog2 Yet Another Article' + Scenario: Work with local helpers + Given a fixture app "collections-app" + And a file named "config.rb" with: + """ + module TestHelper + def help_me + "ok" + end + end + + include TestHelper + + data.articles.each_with_index do |a, i| + proxy "/#{i}-#{help_me}.html", a + end + """ + And a file named "data/articles.yaml" with: + """ + --- + - "/blog1/2011-01-01-new-article.html" + - "/blog2/2011-01-02-another-article.html" + """ + Given the Server is running at "collections-app" + When I go to "0-ok.html" + Then I should see 'Newer Article Content' + When I go to "1-ok.html" + Then I should see 'Another Article Content' Scenario: Collected data update with file changes Given a fixture app "collections-app" diff --git a/middleman-core/features/custom_layouts.feature b/middleman-core/features/custom_layouts.feature index 27f7df08..dfe52344 100644 --- a/middleman-core/features/custom_layouts.feature +++ b/middleman-core/features/custom_layouts.feature @@ -11,6 +11,22 @@ Feature: Custom layouts When I go to "/custom-layout.html" Then I should see "Custom Layout" + Scenario: Using custom :layout attribute with proxy + Given a fixture app "custom-layout-app2" + And a file named "config.rb" with: + """ + page '/test/*', layout: :custom + proxy "/test/me.html", "/custom-layout.html" + live { %w(you) }.each do |who| + proxy "/test/#{who}.html", "/custom-layout.html" + end + """ + And the Server is running at "custom-layout-app2" + When I go to "/test/me.html" + Then I should see "Custom Layout" + When I go to "/test/you.html" + Then I should see "Custom Layout" + Scenario: Using custom :layout attribute with folders Given a fixture app "custom-layout-app2" And a file named "config.rb" with: @@ -65,4 +81,4 @@ Feature: Custom layouts When I go to "/path/index.html" Then I should see "Alt" And I should see "Monde" - And I should not see "Hello" \ No newline at end of file + And I should not see "Hello" diff --git a/middleman-core/features/dynamic_pages.feature b/middleman-core/features/dynamic_pages.feature index 6d1b59ac..fc886ffd 100644 --- a/middleman-core/features/dynamic_pages.feature +++ b/middleman-core/features/dynamic_pages.feature @@ -31,7 +31,8 @@ Feature: Dynamic Pages | should_be_ignored6.html | | should_be_ignored7.html | | should_be_ignored8.html | - + | should_be_ignored9.html | + Scenario: Preview basic proxy Given the Server is running at "dynamic-pages-app" When I go to "/fake.html" @@ -42,46 +43,46 @@ Feature: Dynamic Pages Then I should see "I am real" When I go to "/fake4.html" Then I should see "I am real" - + Scenario: Preview proxy with variable one Given the Server is running at "dynamic-pages-app" When I go to "/fake/one.html" Then I should see "I am real: one" Then I should see "Global: I am one glob" Then I should see "All: I am all glob" - + When I go to "/fake2/one.html" Then I should see "I am real: one" Then I should see "Global: I am two glob" Then I should see "All: I am all glob" - + When I go to "/fake3/one.html" Then I should see "I am real: one" Then I should see "Global: I am three glob" Then I should see "All: I am all glob" - + When I go to "/fake4/one.html" Then I should see "I am real: one" Then I should see "Global: I am four glob" Then I should see "All: I am all glob" - + Scenario: Preview proxy with variable two Given the Server is running at "dynamic-pages-app" When I go to "/fake/two.html" Then I should see "I am real: two" Then I should see "Global: I am one glob" Then I should see "All: I am all glob" - + When I go to "/fake2/two.html" Then I should see "I am real: two" Then I should see "Global: I am two glob" Then I should see "All: I am all glob" - + When I go to "/fake3/two.html" Then I should see "I am real: two" Then I should see "Global: I am three glob" Then I should see "All: I am all glob" - + When I go to "/fake4/two.html" Then I should see "I am real: two" Then I should see "Global: I am four glob" @@ -101,7 +102,7 @@ Feature: Dynamic Pages Then the file "fake3/one.html" should contain "I am real: one" Then the file "fake3/one.html" should contain "Global: I am three glob" Then the file "fake3/one.html" should contain "All: I am all glob" - + Scenario: Target ignore Given the Server is running at "dynamic-pages-app" When I go to "/target_ignore.html" @@ -112,7 +113,7 @@ Feature: Dynamic Pages Then I should see "Ignore me! 7" When I go to "/target_ignore4.html" Then I should see "Ignore me! 8" - + Scenario: Preview ignored paths Given the Server is running at "dynamic-pages-app" When I go to "/should_be_ignored.html" @@ -130,4 +131,6 @@ Feature: Dynamic Pages When I go to "/should_be_ignored7.html" Then I should see "File Not Found" When I go to "/should_be_ignored8.html" - Then I should see "File Not Found" \ No newline at end of file + Then I should see "File Not Found" + When I go to "/should_be_ignored9.html" + Then I should see "File Not Found" diff --git a/middleman-core/features/front-matter-neighbor.feature b/middleman-core/features/front-matter-neighbor.feature index e2e5cc69..9260ff41 100644 --- a/middleman-core/features/front-matter-neighbor.feature +++ b/middleman-core/features/front-matter-neighbor.feature @@ -22,7 +22,7 @@ Feature: Neighboring YAML Front Matter Then I should not see "---" When I go to "/raw-front-matter.php.frontmatter" Then I should see "File Not Found" - + Scenario: YAML not on first line, with encoding Given the Server is running at "frontmatter-neighbor-app" When I go to "/front-matter-encoding.html" @@ -35,7 +35,7 @@ Feature: Neighboring YAML Front Matter Given the Server is running at "frontmatter-neighbor-app" And the file "source/front-matter-change.html.erb" has the contents """ - <%= current_page.data.title %> + FileA <%= current_page.data.title %> """ And the file "source/front-matter-change.html.erb.frontmatter" has the contents """ @@ -43,6 +43,8 @@ Feature: Neighboring YAML Front Matter title: Hello World layout: false --- + + FileB """ When I go to "/front-matter-change.html" Then I should see "Hello World" @@ -52,6 +54,8 @@ Feature: Neighboring YAML Front Matter title: Hola Mundo layout: false --- + + FileC """ When I go to "/front-matter-change.html" Then I should see "Hola Mundo" diff --git a/middleman-core/features/gzip.feature b/middleman-core/features/gzip.feature index 2f74cc9a..643972bc 100644 --- a/middleman-core/features/gzip.feature +++ b/middleman-core/features/gzip.feature @@ -22,7 +22,7 @@ Feature: GZIP assets during build Given a fixture app "gzip-app" And a file named "config.rb" with: """ - activate :gzip, exts: %w(.js .html .htm) + activate :gzip, exts: %w(.htm .html .js .xhtml) """ And a successfully built app at "gzip-app" Then the following files should exist: diff --git a/middleman-core/features/helpers_link_to.feature b/middleman-core/features/helpers_link_to.feature index 90b6f08a..fe8e8530 100644 --- a/middleman-core/features/helpers_link_to.feature +++ b/middleman-core/features/helpers_link_to.feature @@ -40,19 +40,29 @@ Feature: link_to helper """ absolute: <%= link_to "Needs Index", "/needs_index.html", relative: true %> relative: <%= link_to "Relative", "needs_index.html", relative: true %> + + absolute spaces: <%= link_to "Spaces Index", "/evil spaces.html", relative: true %> + relative spaces: <%= link_to "Spaces Relative", "evil spaces.html", relative: true %> """ And a file named "source/link_to/sub.html.erb" with: """ absolute: <%= link_to "Needs Index", "/needs_index.html", relative: true %> relative: <%= link_to "Relative", "../needs_index.html", relative: true %> + + absolute spaces: <%= link_to "Spaces Index", "/evil spaces.html", relative: true %> + relative spaces: <%= link_to "Spaces Relative", "../evil spaces.html", relative: true %> """ And the Server is running at "indexable-app" When I go to "/link_to.html" Then I should see 'absolute: Needs Index' Then I should see 'relative: Relative' + Then I should see 'absolute spaces: Spaces Index' + Then I should see 'relative spaces: Spaces Relative' When I go to "/link_to/sub.html" Then I should see 'absolute: Needs Index' Then I should see 'relative: Relative' + Then I should see 'absolute spaces: Spaces Index' + Then I should see 'relative spaces: Spaces Relative' Scenario: link_to relative works with strip_index_file Given a fixture app "indexable-app" @@ -113,7 +123,7 @@ Feature: link_to helper When I go to "/link_to/sub.html" Then I should see 'absolute: Needs Index' Then I should see 'relative: Relative' - + Scenario: link_to knows about directory indexes Given a fixture app "indexable-app" And a file named "source/link_to.html.erb" with: diff --git a/middleman-core/features/i18n_link_to.feature b/middleman-core/features/i18n_link_to.feature index a10787c4..9d3f0682 100644 --- a/middleman-core/features/i18n_link_to.feature +++ b/middleman-core/features/i18n_link_to.feature @@ -4,7 +4,7 @@ Feature: i18n Paths Given a fixture app "empty-app" And a file named "data/pages.yml" with: """ - - hello.html + - hello.html """ And a file named "locales/en.yml" with: """ @@ -50,24 +50,24 @@ Feature: i18n Paths 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 Home' - Then I should see 'Other Home' - Then I should see 'Home: Current Block' - Then I should see 'Home: Other Block' - Then I should see 'Current hello.html' - Then I should see 'Other hello.html' - Then I should see 'Current Block' - Then I should see 'Other Block' + Then I should see 'Current Home' + Then I should see 'Other Home' + Then I should see 'Home: Current Block' + Then I should see 'Home: Other Block' + Then I should see 'Current hello.html' + Then I should see 'Other hello.html' + Then I should see 'Current Block' + Then I should see 'Other Block' When I go to "/es/hola.html" Then I should see "Page: Hola" - Then I should see 'Current Home' - Then I should see 'Other Home' - Then I should see 'Home: Current Block' - Then I should see 'Home: Other Block' - Then I should see 'Current hello.html' - Then I should see 'Other hello.html' - Then I should see 'Current Block' - Then I should see 'Other Block' + Then I should see 'Current Home' + Then I should see 'Other Home' + Then I should see 'Home: Current Block' + Then I should see 'Home: Other Block' + Then I should see 'Current hello.html' + Then I should see 'Other hello.html' + Then I should see 'Current Block' + Then I should see 'Other Block' Scenario: link_to is i18n aware and supports relative_links Given a fixture app "empty-app" @@ -124,30 +124,30 @@ Feature: i18n Paths Then I should see "assets/css/main.css" When I go to "/hello.html" Then I should see "Page: Hello" - Then I should see 'Current Home' - Then I should see 'Other Home' - Then I should see 'Home: Current Block' - Then I should see 'Home: Other Block' - Then I should see 'Current hello.html' - Then I should see 'Other hello.html' - Then I should see 'Current Block' - Then I should see 'Other Block' + Then I should see 'Current Home' + Then I should see 'Other Home' + Then I should see 'Home: Current Block' + Then I should see 'Home: Other Block' + Then I should see 'Current hello.html' + Then I should see 'Other hello.html' + Then I should see 'Current Block' + Then I should see 'Other Block' When I go to "/es/hola.html" Then I should see "Page: Hola" - Then I should see 'Current Home' - Then I should see 'Other Home' - Then I should see 'Home: Current Block' - Then I should see 'Home: Other Block' - Then I should see 'Current hello.html' - Then I should see 'Other hello.html' - Then I should see 'Current Block' - Then I should see 'Other Block' + Then I should see 'Current Home' + Then I should see 'Other Home' + Then I should see 'Home: Current Block' + Then I should see 'Home: Other Block' + Then I should see 'Current hello.html' + Then I should see 'Other hello.html' + Then I should see 'Current Block' + Then I should see 'Other Block' Scenario: url_for is i18n aware Given a fixture app "empty-app" And a file named "data/pages.yml" with: """ - - hello.html + - hello.html - article.html """ And a file named "locales/en.yml" with: diff --git a/middleman-core/features/import_files.feature b/middleman-core/features/import_files.feature index b45f1256..faaf2039 100644 --- a/middleman-core/features/import_files.feature +++ b/middleman-core/features/import_files.feature @@ -13,5 +13,3 @@ Feature: Import files Then I should see 'jQuery' When I go to "/bower_components2/jquery/dist/jquery.js" Then I should see 'jQuery' - - diff --git a/middleman-core/features/markdown_redcarpet_in_slim.feature b/middleman-core/features/markdown_redcarpet_in_slim.feature new file mode 100644 index 00000000..250c6857 --- /dev/null +++ b/middleman-core/features/markdown_redcarpet_in_slim.feature @@ -0,0 +1,41 @@ +Feature: Markdown support in Slim + In order to test support of the Slim markdown filter + + Scenario: Markdown filter in Slim works + Given a fixture app "markdown-in-slim-app" + And a file named "config.rb" with: + """ + set :markdown_engine, :redcarpet + activate :directory_indexes + """ + And a file named "source/markdown_filter.html.slim" with: + """ + markdown: + # H1 + + paragraph + """ + Given the Server is running at "markdown-in-slim-app" + When I go to "/markdown_filter/" + Then I should see ">H1" + Then I should see "

paragraph

" + + + Scenario: Markdown filter in Slim uses our link_to and image_tag helpers + Given a fixture app "markdown-in-slim-app" + And a file named "config.rb" with: + """ + set :markdown_engine, :redcarpet + activate :directory_indexes + """ + And a file named "source/link_and_image.html.slim" with: + """ + markdown: + [A link](/link_target.html) + + ![image](blank.gif) + """ + Given the Server is running at "markdown-in-slim-app" + When I go to "/link_and_image/" + Then I should see "/link_target/" + Then I should see 'src="/images/blank.gif"' diff --git a/middleman-core/features/nested_layouts.feature b/middleman-core/features/nested_layouts.feature index d70a7e23..f51831fb 100644 --- a/middleman-core/features/nested_layouts.feature +++ b/middleman-core/features/nested_layouts.feature @@ -5,37 +5,37 @@ Feature: Allow nesting of layouts When I go to "/index.html" Then I should see: """ - Master + Master Erb

Index Title

- Outer - Inner + I am Outer + I am Inner Template - + """ When I go to "/another.html" Then I should see: """ - Master + Master Erb

New Article Title

- Outer - Inner + I am Outer + I am Inner

The Article Content

""" - + Scenario: A page uses an inner layout when uses an outer layout (slim) Given the Server is running at "nested-layout-app" When I go to "/slim-test.html" - Then I should see "

Master

New Article Title

Outer

Inner

The Article Content

" - + Then I should see "

Master Slim

New Article Title

I am Outer

I am Inner

The Article Content

" + Scenario: A page uses an inner layout when uses an outer layout (haml) Given the Server is running at "nested-layout-app" When I go to "/haml-test.html" Then I should see: """ - Master + Master Haml

New Article Title

- Outer - Inner + I am Outer + I am Inner

The Article Content

""" @@ -43,13 +43,16 @@ Feature: Allow nesting of layouts Given the Server is running at "nested-layout-app" When I go to "/data-one.html" Then I should see "Page Number One" - And I should see "Inner" + And I should see "Page #1" + And I should see "I am Inner" + And I should see "I am Outer" + And I should see "Master Erb" When I go to "/data-two.html" Then I should see "Page Number Two" - And I should not see "Inner" + And I should not see "I am Inner" When I go to "/data-one.html" Then I should see "Page Number One" - And I should see "Inner" + And I should see "I am Inner" When I go to "/data-two.html" Then I should see "Page Number Two" - And I should not see "Inner" + And I should not see "I am Inner" diff --git a/middleman-core/features/page-id.feature b/middleman-core/features/page-id.feature new file mode 100644 index 00000000..74d08cb5 --- /dev/null +++ b/middleman-core/features/page-id.feature @@ -0,0 +1,72 @@ +Feature: Page IDs + + Scenario: link_to works with blocks (erb) + Given the Server is running at "page-id-app" + When I go to "/index.html" + Then I should see "I am: index" + And I should see "URL1: /fm.html" + And I should see "URL2: /2.html" + And I should see 'URL3: Hi' + And I should see 'URL4: Sym' + And I should see 'URL5: Imp' + And I should see 'URL6: Foldern' + And I should see 'URL7: Feed' + + When I go to "/fm.html" + Then I should see "I am: frontmatter" + When I go to "/implicit.html" + Then I should see "I am: implicit" + When I go to "/feed.xml" + Then I should see "I am: feed.xml" + When I go to "/folder/foldern.html" + Then I should see "I am: folder/foldern" + + When I go to "/1.html" + Then I should see "I am: page1" + When I go to "/2.html" + Then I should see "I am: page2" + When I go to "/3.html" + Then I should see "I am: page3" + + When I go to "/overwrites/from-default.html" + Then I should see "I am: something-else" + + When I go to "/overwrites/from-frontmatter.html" + Then I should see "I am: from_frontmatter" + + Scenario: Override page ID derivation with a proc + Given a fixture app "page-id-app" + And app "page-id-app" is using config "proc" + And the Server is running at "page-id-app" + + When I go to "/index.html" + Then I should see "I am: index.html-foo" + And I should see "URL1: /fm.html" + And I should see "URL2: /2.html" + And I should see 'URL3: Hi' + And I should see 'URL4: Sym' + And I should see 'URL8: Imp' + And I should see 'URL9: Foldern' + And I should see 'URL10: Feed' + + When I go to "/fm.html" + Then I should see "I am: frontmatter" + When I go to "/implicit.html" + Then I should see "I am: implicit.html-foo" + When I go to "/feed.xml" + Then I should see "I am: feed.xml-foo" + When I go to "/folder/foldern.html" + Then I should see "I am: folder/foldern.html-foo" + + When I go to "/1.html" + Then I should see "I am: page1" + When I go to "/2.html" + Then I should see "I am: page2" + When I go to "/3.html" + Then I should see "I am: page3" + + When I go to "/overwrites/from-default.html" + Then I should see "I am: something-else" + + When I go to "/overwrites/from-frontmatter.html" + Then I should see "I am: from_frontmatter" diff --git a/middleman-core/features/partials.feature b/middleman-core/features/partials.feature index 86509027..8a0154c2 100644 --- a/middleman-core/features/partials.feature +++ b/middleman-core/features/partials.feature @@ -5,25 +5,30 @@ Feature: Provide Sane Defaults for Partial Behavior When I go to "/index.html" Then I should see "Header" And I should see "Footer" - + Scenario: Finds shared partials relative to the root (sub) Given the Server is running at "partials-app" When I go to "/sub/index.html" Then I should see "Header" And I should see "Footer" - + + Scenario: Flags error when partial is not found + Given the Server is running at "partials-app" + When I go to "/index_missing.html" + Then I should see "Error: Could not locate partial" + Scenario: Prefers partials of the same engine type Given the Server is running at "partials-app" When I go to "/index.html" Then I should see "ERb Main" - + Scenario: Prefers partials of the same engine type Given the Server is running at "partials-app" When I go to "/second.html" Then I should see "Str Main" And I should see "Header" And I should see "Footer" - + Scenario: Finds partial relative to template Given the Server is running at "partials-app" When I go to "/sub/index.html" @@ -33,7 +38,7 @@ Feature: Provide Sane Defaults for Partial Behavior Given the Server is running at "partials-app" When I go to "/locals.html" Then I should see "Local var is bar" - + Scenario: Partial and Layout use different engines Given the Server is running at "different-engine-partial" When I go to "/index.html" @@ -50,3 +55,10 @@ Feature: Provide Sane Defaults for Partial Behavior Then I should see "File Not Found" When I go to "/_code_snippet.html" Then I should see "File Not Found" + +Scenario: Works with blocks + Given the Server is running at "partials-app" + When I go to "/block.html" + Then I should see "Start" + And I should see "Contents" + And I should see "End" diff --git a/middleman-core/features/relative_assets.feature b/middleman-core/features/relative_assets.feature index ea6cbff0..ba131396 100644 --- a/middleman-core/features/relative_assets.feature +++ b/middleman-core/features/relative_assets.feature @@ -120,7 +120,7 @@ Feature: Relative Assets """ And the Server is running at "relative-assets-app" When I go to "/sub/image_tag.html" - Then I should see '' + Then I should see '") + h2 + background: url("<%= asset_url('/images/blank2.gif') %>") + """ + And a file named "source/javascripts/application.js.erb" with: + """ + function foo() { + var img = document.createElement('img'); + img.src = '<%= asset_url("images/100px.jpg") %>'; + var body = document.getElementsByTagName('body')[0]; + body.insertBefore(img, body.firstChild); + } + + window.onload = foo; + """ + And a file named "source/stylesheets/fonts3.css.erb" with: + """ + @font-face { + font-family: 'Roboto2'; + src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>); + src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg'); + font-weight: normal; + font-style: normal; + } + """ + And the Server is running at "relative-assets-app" + When I go to "/stylesheets/relative_assets.css" + Then I should see 'url("../images/blank.gif' + And I should see 'url("../images/blank2.gif' + When I go to "/javascripts/application.js" + Then I should not see "../" + When I go to "/stylesheets/fonts3.css" + Then I should see 'url(../fonts/roboto/roboto-regular-webfont.eot' + And I should see 'url(../fonts/roboto/roboto-regular-webfont.woff' + And I should see 'url(../fonts/roboto/roboto-regular-webfont.ttf' + And I should see 'url(../fonts/roboto/roboto-regular-webfont.svg' + + Scenario: Relative css reference with directory indexes + Given a fixture app "relative-assets-app" + And a file named "config.rb" with: + """ + activate :directory_indexes + activate :relative_assets, helpers_only: true + """ + And the Server is running at "relative-assets-app" + When I go to "/relative_image/index.html" + Then I should see "../stylesheets/relative_assets.css" + + Scenario: Relative assets via image_tag + Given a fixture app "relative-assets-app" + And a file named "config.rb" with: + """ + activate :relative_assets, helpers_only: true + """ + And a file named "source/sub/image_tag.html.erb" with: + """ + <%= image_tag '/img/blank.gif' %> + """ + And the Server is running at "relative-assets-app" + When I go to "/sub/image_tag.html" + Then I should see ' + """ + And the Server is running at "relative-assets-app" + When I go to "/sub/image_tag.html" + Then I should see '' + + Scenario: URLs are not rewritten for rewrite ignored paths + Given a fixture app "relative-assets-app" + And a file named "config.rb" with: + """ + activate :relative_assets, rewrite_ignore: [ + '/stylesheets/fonts3.css', + ], helpers_only: true + """ + And a file named "source/stylesheets/relative_assets.css.sass.erb" with: + """ + h1 + background: url("<%= asset_url('images/blank.gif') %>") + h2 + background: url("<%= asset_url('/images/blank2.gif') %>") + """ + And a file named "source/stylesheets/fonts3.css.erb" with: + """ + @font-face { + font-family: 'Roboto2'; + src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot") %>); + src: url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.eot?#iefix") %>) format('embedded-opentype'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.woff") %>) format('woff'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.ttf") %>) format('truetype'), + url(<%= asset_url("/fonts/roboto/roboto-regular-webfont.svg#robotoregular") %>) format('svg'); + font-weight: normal; + font-style: normal; + } + """ + And the Server is running at "relative-assets-app" + When I go to "/stylesheets/relative_assets.css" + Then I should see 'url("../images/blank.gif' + When I go to "/stylesheets/fonts3.css" + Then I should see 'url(/fonts/roboto/roboto-regular-webfont.eot' diff --git a/middleman-core/features/sass_in_slim.feature b/middleman-core/features/sass_in_slim.feature new file mode 100644 index 00000000..d04055e4 --- /dev/null +++ b/middleman-core/features/sass_in_slim.feature @@ -0,0 +1,40 @@ +Feature: Sass/SCSS support in Slim + In order to test support of the Slim sass and scss filters + + Scenario: Sass filter in Slim works + Given a fixture app "sass-in-slim-app" + And a file named "config.rb" with: + """ + activate :directory_indexes + """ + And a file named "source/sass_filter.html.slim" with: + """ + sass: + .sass + margin: 0 + """ + Given the Server is running at "sass-in-slim-app" + When I go to "/sass_filter/" + Then I should see "text/css" + Then I should see ".sass" + Then I should see "margin:0" + + + Scenario: SCSS filter in Slim works + Given a fixture app "sass-in-slim-app" + And a file named "config.rb" with: + """ + activate :directory_indexes + """ + And a file named "source/scss_filter.html.slim" with: + """ + scss: + .scss { + margin: 0; + } + """ + Given the Server is running at "sass-in-slim-app" + When I go to "/scss_filter/" + Then I should see "text/css" + Then I should see ".scss" + Then I should see "margin:0" diff --git a/middleman-core/features/template-key-collision.feature b/middleman-core/features/template-key-collision.feature new file mode 100644 index 00000000..9e530dc1 --- /dev/null +++ b/middleman-core/features/template-key-collision.feature @@ -0,0 +1,26 @@ +Feature: Don't allow template locals to overwrite template helpers + + Scenario: Normal Template + Given an empty app + And a file named "config.rb" with: + """ + class TestExt < ::Middleman::Extension + expose_to_template foo: :foo + + def foo + "bar" + end + end + + ::Middleman::Extensions.register :test, TestExt + + activate :test + + page "/index.html", locals: { foo: false } + """ + And a file named "source/index.html.erb" with: + """ + <%= foo %> + """ + Given a built app at "empty_app" + Then the exit status should be 1 diff --git a/middleman-core/fixtures/asset-hash-host-app/config.rb b/middleman-core/fixtures/asset-hash-host-app/config.rb deleted file mode 100644 index 085caeb7..00000000 --- a/middleman-core/fixtures/asset-hash-host-app/config.rb +++ /dev/null @@ -1,4 +0,0 @@ - -activate :asset_hash -activate :directory_indexes -activate :asset_host, host: 'http://middlemanapp.com' diff --git a/middleman-core/fixtures/asset-hash-host-app/source/index.html.erb b/middleman-core/fixtures/asset-hash-host-app/source/index.html.erb index ea81c790..c9fefc2a 100644 --- a/middleman-core/fixtures/asset-hash-host-app/source/index.html.erb +++ b/middleman-core/fixtures/asset-hash-host-app/source/index.html.erb @@ -3,7 +3,7 @@ <% end %>

Image url:

-<%= image_tag('100px.jpg') %> + <%= image_tag('100px.jpg?test') %> <%= image_tag('100px.jpg?#test') %> <%= image_tag('100px.jpg#test') %> diff --git a/middleman-core/fixtures/asset-hash-minified-app/source/images/100px.jpg b/middleman-core/fixtures/asset-hash-minified-app/source/images/100px.jpg new file mode 100644 index 00000000..557d0278 Binary files /dev/null and b/middleman-core/fixtures/asset-hash-minified-app/source/images/100px.jpg differ diff --git a/middleman-core/fixtures/asset-hash-minified-app/source/stylesheets/test.css b/middleman-core/fixtures/asset-hash-minified-app/source/stylesheets/test.css new file mode 100644 index 00000000..059fce9a --- /dev/null +++ b/middleman-core/fixtures/asset-hash-minified-app/source/stylesheets/test.css @@ -0,0 +1,3 @@ +.no-bug{background-image:url(/images/100px.jpg)} +.bug{content:"";background-image:url(/images/100px.jpg)} +.no-bug{content:""; background-image:url(/images/100px.jpg)} diff --git a/middleman-core/fixtures/asset-hash-prefix/config.rb b/middleman-core/fixtures/asset-hash-prefix/config.rb new file mode 100644 index 00000000..449a2e98 --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/config.rb @@ -0,0 +1,7 @@ + +activate :asset_hash, + prefix: "myprefix-" + +activate :relative_assets + +activate :directory_indexes diff --git a/middleman-core/fixtures/asset-hash-prefix/lib/middleware.rb b/middleman-core/fixtures/asset-hash-prefix/lib/middleware.rb new file mode 100644 index 00000000..8ee825fd --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/lib/middleware.rb @@ -0,0 +1,16 @@ +class Middleware + def initialize(app) + @app = app + end + + def call(env) + status, headers, response = @app.call(env) + body = '' + response.each {|part| body += part } + if (env["PATH_INFO"] =~ /css$/) + body += "\n/* Added by Rack filter */" + status, headers, response = Rack::Response.new(body, status, headers).finish + end + [status, headers, response] + end +end diff --git a/middleman-core/fixtures/asset-hash-prefix/source/index.html.erb b/middleman-core/fixtures/asset-hash-prefix/source/index.html.erb new file mode 100644 index 00000000..a88cc13f --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/source/index.html.erb @@ -0,0 +1,6 @@ +<% content_for :head do %> + The Middleman! +<% end %> + +

Testing the sitemap hashing

+


diff --git a/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js b/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js new file mode 100644 index 00000000..c72f8572 --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js @@ -0,0 +1,2 @@ +function foo(){var message="HEY THERE FRIEND!";var para=document.createElement("p");para.innerHTML=message;var body=document.getElementsByTagName("body")[0];body.insertBefore(para,body.firstChild)}window.onload=foo; +//# sourceMappingURL=application.js.map diff --git a/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js.map b/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js.map new file mode 100644 index 00000000..6a5acd5c --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/source/javascripts/application.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["source/javascripts/application.js"],"names":["foo","message","para","document","createElement","innerHTML","body","getElementsByTagName","insertBefore","firstChild","window","onload"],"mappings":"AAAA,QAASA,OACP,GAAIC,SAAU,mBACd,IAAIC,MAAOC,SAASC,cAAc,IAClCF,MAAKG,UAAYJ,OACb,IAAIK,MAAOH,SAASI,qBAAqB,QAAQ,EAC/CD,MAAKE,aAAaN,KAAMI,KAAKG,YAGpCC,OAAOC,OAASX"} \ No newline at end of file diff --git a/middleman-core/fixtures/asset-hash-prefix/source/layout.erb b/middleman-core/fixtures/asset-hash-prefix/source/layout.erb new file mode 100644 index 00000000..c8aacecf --- /dev/null +++ b/middleman-core/fixtures/asset-hash-prefix/source/layout.erb @@ -0,0 +1,17 @@ + + + + + + <%= javascript_include_tag "application" %> + <%= yield_content :head %> + + + + +
+ <%= yield %> +
+ + + diff --git a/middleman-core/fixtures/asset-hash-source-map/config.rb b/middleman-core/fixtures/asset-hash-source-map/config.rb new file mode 100644 index 00000000..1327d8f0 --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/config.rb @@ -0,0 +1,6 @@ + +activate :asset_hash + +activate :relative_assets + +activate :directory_indexes diff --git a/middleman-core/fixtures/asset-hash-source-map/lib/middleware.rb b/middleman-core/fixtures/asset-hash-source-map/lib/middleware.rb new file mode 100644 index 00000000..8ee825fd --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/lib/middleware.rb @@ -0,0 +1,16 @@ +class Middleware + def initialize(app) + @app = app + end + + def call(env) + status, headers, response = @app.call(env) + body = '' + response.each {|part| body += part } + if (env["PATH_INFO"] =~ /css$/) + body += "\n/* Added by Rack filter */" + status, headers, response = Rack::Response.new(body, status, headers).finish + end + [status, headers, response] + end +end diff --git a/middleman-core/fixtures/asset-hash-source-map/source/index.html.erb b/middleman-core/fixtures/asset-hash-source-map/source/index.html.erb new file mode 100644 index 00000000..a88cc13f --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/source/index.html.erb @@ -0,0 +1,6 @@ +<% content_for :head do %> + The Middleman! +<% end %> + +

Testing the sitemap hashing

+


diff --git a/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js b/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js new file mode 100644 index 00000000..c72f8572 --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js @@ -0,0 +1,2 @@ +function foo(){var message="HEY THERE FRIEND!";var para=document.createElement("p");para.innerHTML=message;var body=document.getElementsByTagName("body")[0];body.insertBefore(para,body.firstChild)}window.onload=foo; +//# sourceMappingURL=application.js.map diff --git a/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js.map b/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js.map new file mode 100644 index 00000000..6a5acd5c --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/source/javascripts/application.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["source/javascripts/application.js"],"names":["foo","message","para","document","createElement","innerHTML","body","getElementsByTagName","insertBefore","firstChild","window","onload"],"mappings":"AAAA,QAASA,OACP,GAAIC,SAAU,mBACd,IAAIC,MAAOC,SAASC,cAAc,IAClCF,MAAKG,UAAYJ,OACb,IAAIK,MAAOH,SAASI,qBAAqB,QAAQ,EAC/CD,MAAKE,aAAaN,KAAMI,KAAKG,YAGpCC,OAAOC,OAASX"} \ No newline at end of file diff --git a/middleman-core/fixtures/asset-hash-source-map/source/layout.erb b/middleman-core/fixtures/asset-hash-source-map/source/layout.erb new file mode 100644 index 00000000..c8aacecf --- /dev/null +++ b/middleman-core/fixtures/asset-hash-source-map/source/layout.erb @@ -0,0 +1,17 @@ + + + + + + <%= javascript_include_tag "application" %> + <%= yield_content :head %> + + + + +
+ <%= yield %> +
+ + + diff --git a/middleman-core/fixtures/asset-host-app/source/asset_host.html.erb b/middleman-core/fixtures/asset-host-app/source/asset_host.html.erb index 30843176..25f4a9d9 100755 --- a/middleman-core/fixtures/asset-host-app/source/asset_host.html.erb +++ b/middleman-core/fixtures/asset-host-app/source/asset_host.html.erb @@ -44,3 +44,12 @@ Angular.js + + diff --git a/middleman-cli/features/.gitkeep b/middleman-core/fixtures/asset-host-app/source/images/blank0.gif similarity index 100% rename from middleman-cli/features/.gitkeep rename to middleman-core/fixtures/asset-host-app/source/images/blank0.gif diff --git a/middleman-cli/fixtures/.gitkeep b/middleman-core/fixtures/asset-host-app/source/images/blank1.gif similarity index 100% rename from middleman-cli/fixtures/.gitkeep rename to middleman-core/fixtures/asset-host-app/source/images/blank1.gif diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank10.gif b/middleman-core/fixtures/asset-host-app/source/images/blank10.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank100.gif b/middleman-core/fixtures/asset-host-app/source/images/blank100.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank101.gif b/middleman-core/fixtures/asset-host-app/source/images/blank101.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1010.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1010.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank102.gif b/middleman-core/fixtures/asset-host-app/source/images/blank102.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1020.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1020.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1021.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1021.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1022.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1022.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1023.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1023.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1024.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1024.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank103.gif b/middleman-core/fixtures/asset-host-app/source/images/blank103.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1030.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1030.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1031.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1031.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1032.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1032.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1033.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1033.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1034.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1034.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank104.gif b/middleman-core/fixtures/asset-host-app/source/images/blank104.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1043.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1043.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank1054.gif b/middleman-core/fixtures/asset-host-app/source/images/blank1054.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank2.gif b/middleman-core/fixtures/asset-host-app/source/images/blank2.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank20.gif b/middleman-core/fixtures/asset-host-app/source/images/blank20.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank21.gif b/middleman-core/fixtures/asset-host-app/source/images/blank21.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank22.gif b/middleman-core/fixtures/asset-host-app/source/images/blank22.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank23.gif b/middleman-core/fixtures/asset-host-app/source/images/blank23.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank24.gif b/middleman-core/fixtures/asset-host-app/source/images/blank24.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank3.gif b/middleman-core/fixtures/asset-host-app/source/images/blank3.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank30.gif b/middleman-core/fixtures/asset-host-app/source/images/blank30.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank31.gif b/middleman-core/fixtures/asset-host-app/source/images/blank31.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank32.gif b/middleman-core/fixtures/asset-host-app/source/images/blank32.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank33.gif b/middleman-core/fixtures/asset-host-app/source/images/blank33.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank34.gif b/middleman-core/fixtures/asset-host-app/source/images/blank34.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank4.gif b/middleman-core/fixtures/asset-host-app/source/images/blank4.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank43.gif b/middleman-core/fixtures/asset-host-app/source/images/blank43.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/images/blank54.gif b/middleman-core/fixtures/asset-host-app/source/images/blank54.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/asset-host-app/source/javascripts/asset_host.js b/middleman-core/fixtures/asset-host-app/source/javascripts/asset_host.js new file mode 100644 index 00000000..251ce693 --- /dev/null +++ b/middleman-core/fixtures/asset-host-app/source/javascripts/asset_host.js @@ -0,0 +1,2 @@ +var a = jQuery.css("h1", "font-size"); +console.log(a); diff --git a/middleman-core/fixtures/automatic-image-size-app/source/markdown-sizes.html.markdown b/middleman-core/fixtures/automatic-image-size-app/source/markdown-sizes.html.markdown new file mode 100644 index 00000000..1f9c8dcd --- /dev/null +++ b/middleman-core/fixtures/automatic-image-size-app/source/markdown-sizes.html.markdown @@ -0,0 +1 @@ +![Alt text](/images/blank.gif) diff --git a/middleman-core/fixtures/dynamic-pages-app/config.rb b/middleman-core/fixtures/dynamic-pages-app/config.rb index 75fab5e0..b195e0f9 100644 --- a/middleman-core/fixtures/dynamic-pages-app/config.rb +++ b/middleman-core/fixtures/dynamic-pages-app/config.rb @@ -28,3 +28,7 @@ page "fake/*", locals: { glob_var: "I am one glob" } page "fake2/*", locals: { glob_var: "I am two glob" } page "fake3/*", locals: { glob_var: "I am three glob" } page "fake4/*", locals: { glob_var: "I am four glob" } + +["tom", "dick", "harry"].each do |name| + proxy "/about/#{name}.html", "/should_be_ignored9.html", locals: { person_name: name }, ignore: true +end diff --git a/middleman-core/fixtures/dynamic-pages-app/source/should_be_ignored9.html b/middleman-core/fixtures/dynamic-pages-app/source/should_be_ignored9.html new file mode 100644 index 00000000..53571d5e --- /dev/null +++ b/middleman-core/fixtures/dynamic-pages-app/source/should_be_ignored9.html @@ -0,0 +1 @@ +

Ignore me! 9

diff --git a/middleman-core/fixtures/external-pipeline-error/config.rb b/middleman-core/fixtures/external-pipeline-error/config.rb new file mode 100644 index 00000000..96bb2b94 --- /dev/null +++ b/middleman-core/fixtures/external-pipeline-error/config.rb @@ -0,0 +1,5 @@ +activate :external_pipeline, + name: :failing, + command: "mv does-not-exist tmp/file.js", + source: "tmp", + latency: 2 diff --git a/middleman-core/fixtures/external-pipeline-error/source/javascripts/file.js b/middleman-core/fixtures/external-pipeline-error/source/javascripts/file.js new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/frontmatter-neighbor-app/config.rb b/middleman-core/fixtures/frontmatter-neighbor-app/config.rb index 6fa6e37c..019d65f7 100644 --- a/middleman-core/fixtures/frontmatter-neighbor-app/config.rb +++ b/middleman-core/fixtures/frontmatter-neighbor-app/config.rb @@ -15,7 +15,7 @@ class NeighborFrontmatter < ::Middleman::Extension next unless file - fmdata = ::Middleman::Util::Data.parse(file[:full_path], app.config[:frontmatter_delims], :yaml).first + fmdata = ::Middleman::Util::Data.parse(file, app.config[:frontmatter_delims], :yaml).first opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type) opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options) ignored = fmdata.delete(:ignored) diff --git a/middleman-core/fixtures/frontmatter-settings-neighbor-app/config.rb b/middleman-core/fixtures/frontmatter-settings-neighbor-app/config.rb index a7e0fc55..7adbe389 100644 --- a/middleman-core/fixtures/frontmatter-settings-neighbor-app/config.rb +++ b/middleman-core/fixtures/frontmatter-settings-neighbor-app/config.rb @@ -26,7 +26,7 @@ class NeighborFrontmatter < ::Middleman::Extension end def apply_neighbor_data(resource, file) - fmdata = ::Middleman::Util::Data.parse(file[:full_path], app.config[:frontmatter_delims], :yaml).first + fmdata = ::Middleman::Util::Data.parse(file, app.config[:frontmatter_delims], :yaml).first opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type) opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options) ignored = fmdata.delete(:ignored) diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/inner.erb b/middleman-core/fixtures/nested-layout-app/source/layouts/inner.erb index 62dfc12b..3e29f567 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/inner.erb +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/inner.erb @@ -1,4 +1,7 @@ +--- +inner: true +--- <% wrap_layout :outer do %> - Inner + I am Inner <%= yield %> -<% end %> \ No newline at end of file +<% end %> diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/inner_haml.haml b/middleman-core/fixtures/nested-layout-app/source/layouts/inner_haml.haml index a8c1938d..5f99da1e 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/inner_haml.haml +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/inner_haml.haml @@ -1,3 +1,7 @@ +--- +inner_haml: true +--- + = wrap_layout :outer_haml do - Inner - = yield \ No newline at end of file + I am Inner + = yield diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/inner_slim.slim b/middleman-core/fixtures/nested-layout-app/source/layouts/inner_slim.slim index 49f1ab6f..f7d9c924 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/inner_slim.slim +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/inner_slim.slim @@ -1,3 +1,7 @@ +--- +inner_slim: true +--- + = wrap_layout :outer_slim do - h3 Inner - == yield \ No newline at end of file + h3 I am Inner + == yield diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/master.erb b/middleman-core/fixtures/nested-layout-app/source/layouts/master.erb index 7bd170af..fc862aa4 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/master.erb +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/master.erb @@ -1,3 +1,9 @@ -Master +--- +master: true +--- + +Master Erb

<%= current_page.data.title %>

<%= yield %> + +Using Inner: <%= current_page.data.inner ? 'true' : 'false' %> diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/master_haml.haml b/middleman-core/fixtures/nested-layout-app/source/layouts/master_haml.haml index 273f21e7..3c949d5c 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/master_haml.haml +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/master_haml.haml @@ -1,3 +1,7 @@ -Master +--- +master_haml: true +--- + +Master Haml %h1= current_page.data.title = yield diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/master_slim.slim b/middleman-core/fixtures/nested-layout-app/source/layouts/master_slim.slim index 4ade5748..cd5eac1d 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/master_slim.slim +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/master_slim.slim @@ -1,3 +1,7 @@ -h1 Master +--- +master_slim: true +--- + +h1 Master Slim p== current_page.data.title div== yield diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/outer.erb b/middleman-core/fixtures/nested-layout-app/source/layouts/outer.erb index 643d8efc..adc4f9e2 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/outer.erb +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/outer.erb @@ -1,4 +1,8 @@ +--- +outer: true +--- + <% wrap_layout :master do %> - Outer + I am Outer <%= yield %> -<% end %> \ No newline at end of file +<% end %> diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/outer_haml.haml b/middleman-core/fixtures/nested-layout-app/source/layouts/outer_haml.haml index eaf1671f..d6d4b05b 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/outer_haml.haml +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/outer_haml.haml @@ -1,3 +1,7 @@ +--- +outer_haml: true +--- + = wrap_layout :master_haml do - Outer + I am Outer = yield diff --git a/middleman-core/fixtures/nested-layout-app/source/layouts/outer_slim.slim b/middleman-core/fixtures/nested-layout-app/source/layouts/outer_slim.slim index 0c17185b..65eb3277 100644 --- a/middleman-core/fixtures/nested-layout-app/source/layouts/outer_slim.slim +++ b/middleman-core/fixtures/nested-layout-app/source/layouts/outer_slim.slim @@ -1,3 +1,7 @@ +--- +outer_slim: true +--- + = wrap_layout :master_slim do - h2 Outer + h2 I am Outer == yield diff --git a/middleman-core/fixtures/page-id-app/config-proc.rb b/middleman-core/fixtures/page-id-app/config-proc.rb new file mode 100644 index 00000000..03070f0e --- /dev/null +++ b/middleman-core/fixtures/page-id-app/config-proc.rb @@ -0,0 +1,7 @@ +%w(1 2 3).each do |n| + proxy "/#{n}.html", "/index.html", id: "page#{n}" +end + +page "/overwrites/*", id: :"something-else" + +config[:page_id_generator] = ->(path){ path + "-foo" } diff --git a/middleman-core/fixtures/page-id-app/config.rb b/middleman-core/fixtures/page-id-app/config.rb new file mode 100644 index 00000000..d0475e7a --- /dev/null +++ b/middleman-core/fixtures/page-id-app/config.rb @@ -0,0 +1,5 @@ +%w(1 2 3).each do |n| + proxy "/#{n}.html", "/index.html", id: "page#{n}" +end + +page "/overwrites/*", id: :"something-else" diff --git a/middleman-core/fixtures/page-id-app/source/feed.xml.erb b/middleman-core/fixtures/page-id-app/source/feed.xml.erb new file mode 100644 index 00000000..a27800bd --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/feed.xml.erb @@ -0,0 +1 @@ +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/page-id-app/source/fm.html.erb b/middleman-core/fixtures/page-id-app/source/fm.html.erb new file mode 100644 index 00000000..4d6d0772 --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/fm.html.erb @@ -0,0 +1,5 @@ +--- +id: frontmatter +--- + +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/page-id-app/source/folder/foldern.html.erb b/middleman-core/fixtures/page-id-app/source/folder/foldern.html.erb new file mode 100644 index 00000000..a27800bd --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/folder/foldern.html.erb @@ -0,0 +1 @@ +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/page-id-app/source/implicit.html.erb b/middleman-core/fixtures/page-id-app/source/implicit.html.erb new file mode 100644 index 00000000..a27800bd --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/implicit.html.erb @@ -0,0 +1 @@ +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/page-id-app/source/index.html.erb b/middleman-core/fixtures/page-id-app/source/index.html.erb new file mode 100644 index 00000000..6060bc3f --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/index.html.erb @@ -0,0 +1,14 @@ +I am: <%= current_resource.page_id %> + +URL1: <%= url_for "frontmatter" %> +URL2: <%= url_for "page2" %> +URL3: <%= link_to "Hi", "page3" %> +URL4: <%= link_to "Sym", :"something-else" %> +URL5: <%= link_to "Imp", :implicit %> +URL6: <%= link_to "Foldern", "folder/foldern" %> +URL7: <%= link_to "Feed", "feed.xml" %> + +<%# If custom proc %> +URL8: <%= link_to "Imp", "implicit.html-foo" %> +URL9: <%= link_to "Foldern", "folder/foldern.html-foo" %> +URL10: <%= link_to "Feed", "feed.xml-foo" %> diff --git a/middleman-core/fixtures/page-id-app/source/overwrites/from-default.html.erb b/middleman-core/fixtures/page-id-app/source/overwrites/from-default.html.erb new file mode 100644 index 00000000..a27800bd --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/overwrites/from-default.html.erb @@ -0,0 +1 @@ +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/page-id-app/source/overwrites/from-frontmatter.html.erb b/middleman-core/fixtures/page-id-app/source/overwrites/from-frontmatter.html.erb new file mode 100644 index 00000000..194cf4c1 --- /dev/null +++ b/middleman-core/fixtures/page-id-app/source/overwrites/from-frontmatter.html.erb @@ -0,0 +1,5 @@ +--- +id: from_frontmatter +--- + +I am: <%= current_resource.page_id %> diff --git a/middleman-core/fixtures/partials-app/source/_block.erb b/middleman-core/fixtures/partials-app/source/_block.erb new file mode 100644 index 00000000..179e0c82 --- /dev/null +++ b/middleman-core/fixtures/partials-app/source/_block.erb @@ -0,0 +1,3 @@ +Start +<%= yield %> +End diff --git a/middleman-core/fixtures/partials-app/source/block.html.erb b/middleman-core/fixtures/partials-app/source/block.html.erb new file mode 100644 index 00000000..613f7ccb --- /dev/null +++ b/middleman-core/fixtures/partials-app/source/block.html.erb @@ -0,0 +1,3 @@ +<% partial "block" do %> +Contents +<% end %> diff --git a/middleman-core/fixtures/partials-app/source/index_missing.html.erb b/middleman-core/fixtures/partials-app/source/index_missing.html.erb new file mode 100755 index 00000000..bcd70b82 --- /dev/null +++ b/middleman-core/fixtures/partials-app/source/index_missing.html.erb @@ -0,0 +1,3 @@ +<%= partial "shared/header" %> +<%= partial "i_do_not_exist" %> +<%= partial "shared/footer" %> diff --git a/middleman-core/fixtures/relative-assets-app/source/images/blank2.gif b/middleman-core/fixtures/relative-assets-app/source/images/blank2.gif new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/sass-in-slim-app/config.rb b/middleman-core/fixtures/sass-in-slim-app/config.rb new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/lib/middleman-core.rb b/middleman-core/lib/middleman-core.rb index 8170fefb..687a53e5 100644 --- a/middleman-core/lib/middleman-core.rb +++ b/middleman-core/lib/middleman-core.rb @@ -6,9 +6,6 @@ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir) # Top-level Middleman namespace module Middleman - # Backwards compatibility namespace - module Features; end - autoload :Application, 'middleman-core/application' end diff --git a/middleman-core/lib/middleman-core/application.rb b/middleman-core/lib/middleman-core/application.rb index 659bd1ba..52b31c92 100644 --- a/middleman-core/lib/middleman-core/application.rb +++ b/middleman-core/lib/middleman-core/application.rb @@ -96,6 +96,10 @@ module Middleman # @return [String] define_setting :source, 'source', 'Name of the source directory' + # If we should not run the sitemap. + # @return [Boolean] + define_setting :disable_sitemap, false, 'If we should not run the sitemap.' + # If we should exit before ready event. # @return [Boolean] define_setting :exit_before_ready, false, 'If we should exit before ready event.' @@ -106,7 +110,7 @@ module Middleman # Middleman environment. Defaults to :development # @return [String] - define_setting :environment, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :development), 'Middleman environment. Defaults to :development' + define_setting :environment, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :development), 'Middleman environment. Defaults to :development', import: proc { |s| s.to_sym } # Which file should be used for directory indexes # @return [String] @@ -149,9 +153,17 @@ module Middleman define_setting :http_prefix, '/', 'Default prefix for building paths' # Default layout name - # @return [String, Symbold] + # @return [String] define_setting :layout, :_auto_layout, 'Default layout name' + # Which file extensions have a layout by default. + # @return [Array.] + define_setting :extensions_with_layout, %w(.htm .html .xhtml .php), 'Which file extensions have a layout by default.' + + # Which file extensions are "assets." + # @return [Array.] + define_setting :asset_extensions, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif .ttf .otf .woff .woff2 .eot .ico .map), 'Which file extensions are treated as assets.' + # Default string encoding for templates and output. # @return [String] define_setting :encoding, 'utf-8', 'Default string encoding for templates and output' @@ -170,7 +182,7 @@ module Middleman ignored = false file[:relative_path].ascend do |f| - if f.basename.to_s.match %r{^_[^_]} + if f.basename.to_s =~ %r{^_[^_]} ignored = true break end @@ -179,23 +191,19 @@ module Middleman ignored end, - layout: proc do |file, _sitemap_app| - file[:relative_path].to_s.start_with?('layout.') || - file[:relative_path].to_s.start_with?('layouts/') + layout: proc do |file, app| + file[:relative_path].to_s.start_with?('layout.', app.config[:layouts_dir] + '/') end }, 'Callbacks that can exclude paths from the sitemap' - # Set textual delimiters that denote the start and end of frontmatter - define_setting :frontmatter_delims, { - json: [%w(;;; ;;;)], - yaml: [%w(--- ---), %w(--- ...)] - }, 'Allowed frontmatter delimiters' + define_setting :skip_build_clean, proc { |p| [/\.git/].any? { |r| p =~ r } }, 'Whether some paths should not be removed during a clean build.' - define_setting :skip_build_clean, proc { |p| [/\.git/].any? { |r| r.match(p) } }, 'Whether some paths should not be removed during a clean build.' + define_setting :cli_options, {}, 'Options from the Command Line.' define_setting :watcher_disable, false, 'If the Listen watcher should not run' define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode' define_setting :watcher_latency, nil, 'The Listen watcher latency' + define_setting :watcher_wait_for_delay, 0.5, 'The Listen watcher delay between calls when changes exist' # Delegate convenience methods off to their implementations def_delegator :"::Middleman::Logger", :singleton, :logger @@ -210,26 +218,27 @@ module Middleman # Search the root of the project for required files $LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root) - ::Middleman::Util.instrument "application.setup" do + ::Middleman::Util.instrument 'application.setup' do @callbacks = ::Middleman::CallbackManager.new @callbacks.install_methods!(self, [ - :initialized, - :configure, - :before_extensions, - :before_instance_block, - :before_sitemap, - :before_configuration, - :after_configuration, - :after_configuration_eval, - :ready, - :before_build, - :after_build, - :before_shutdown, - :before, # Before Rack requests - :before_render, - :after_render, - :before_server - ]) + :initialized, + :configure, + :before_extensions, + :before_instance_block, + :before_sitemap, + :before_configuration, + :after_configuration, + :after_configuration_eval, + :ready, + :before_build, + :after_build, + :before_shutdown, + :before, # Before Rack requests + :before_render, + :after_render, + :before_server, + :reload + ]) @middleware = Set.new @mappings = Set.new @@ -258,6 +267,8 @@ module Middleman # Evaluate a passed block if given config_context.instance_exec(&block) if block_given? + apply_cli_options + execute_callbacks(:before_sitemap) # Initialize the Sitemap @@ -280,6 +291,8 @@ module Middleman # Run any `configure` blocks for the current mode. execute_callbacks([:configure, config[:mode]]) + apply_cli_options + # Post parsing, pre-extension callback execute_callbacks(:after_configuration_eval) @@ -296,6 +309,17 @@ module Middleman execute_callbacks(:ready) unless config[:exit_before_ready] end + def apply_cli_options + config[:cli_options].each do |k, v| + setting = config.setting(k.to_sym) + next unless setting + + v = setting.options[:import].call(v) if setting.options[:import] + + config[k.to_sym] = v + end + end + # Eval config def evaluate_configuration! # Check for and evaluate local configuration in `config.rb` @@ -321,11 +345,11 @@ module Middleman # Clean up missing Tilt exts def prune_tilt_templates! - ::Tilt.mappings.each do |key, _| + ::Tilt.default_mapping.lazy_map.each_key do |key| begin ::Tilt[".#{key}"] rescue LoadError, NameError - ::Tilt.mappings.delete(key) + ::Tilt.default_mapping.lazy_map.delete(key) end end end @@ -431,6 +455,6 @@ module Middleman def to_s "#" end - alias_method :inspect, :to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s + alias inspect to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s end end diff --git a/middleman-core/lib/middleman-core/builder.rb b/middleman-core/lib/middleman-core/builder.rb index add35fe9..1796d4d7 100644 --- a/middleman-core/lib/middleman-core/builder.rb +++ b/middleman-core/lib/middleman-core/builder.rb @@ -1,6 +1,7 @@ require 'pathname' require 'fileutils' require 'tempfile' +require 'parallel' require 'middleman-core/rack' require 'middleman-core/callback_manager' require 'middleman-core/contracts' @@ -20,7 +21,7 @@ module Middleman def_delegator :@app, :logger # Sort order, images, fonts, js/css and finally everything else. - SORT_ORDER = %w(.png .jpeg .jpg .gif .bmp .svg .svgz .webp .ico .woff .woff2 .otf .ttf .eot .js .css) + SORT_ORDER = %w(.png .jpeg .jpg .gif .bmp .svg .svgz .webp .ico .woff .woff2 .otf .ttf .eot .js .css).freeze # Create a new Builder instance. # @param [Middleman::Application] app The app to build. @@ -36,6 +37,7 @@ module Middleman @glob = opts.fetch(:glob) @cleaning = opts.fetch(:clean) + @parallel = opts.fetch(:parallel, true) rack_app = ::Middleman::Rack.new(@app).to_app @rack = ::Rack::MockRequest.new(rack_app) @@ -51,18 +53,33 @@ module Middleman @has_error = false @events = {} - @app.execute_callbacks(:before_build, [self]) + ::Middleman::Util.instrument 'builder.before' do + @app.execute_callbacks(:before_build, [self]) + end - queue_current_paths if @cleaning + ::Middleman::Util.instrument 'builder.queue' do + queue_current_paths if @cleaning + end - prerender_css - output_files + ::Middleman::Util.instrument 'builder.prerender' do + prerender_css + end - clean! if @cleaning + ::Middleman::Profiling.start + + ::Middleman::Util.instrument 'builder.output' do + output_files + end ::Middleman::Profiling.report('build') - @app.execute_callbacks(:after_build, [self]) + ::Middleman::Util.instrument 'builder.clean' do + clean! if @cleaning + end + + ::Middleman::Util.instrument 'builder.after' do + @app.execute_callbacks(:after_build, [self]) + end !@has_error end @@ -73,14 +90,17 @@ module Middleman def prerender_css logger.debug '== Prerendering CSS' - css_files = @app.sitemap.resources - .select { |resource| resource.ext == '.css' } - .each(&method(:output_resource)) + css_files = ::Middleman::Util.instrument 'builder.prerender.output' do + resources = @app.sitemap.resources.select { |resource| resource.ext == '.css' } + output_resources(resources) + end - # Double-check for compass sprites - if @app.files.find_new_files!.length > 0 - logger.debug '== Checking for Compass sprites' - @app.sitemap.ensure_resource_list_updated! + ::Middleman::Util.instrument 'builder.prerender.check-files' do + # Double-check for compass sprites + unless @app.files.find_new_files!.empty? + logger.debug '== Checking for Compass sprites' + @app.sitemap.ensure_resource_list_updated! + end end css_files @@ -92,11 +112,49 @@ module Middleman def output_files logger.debug '== Building files' - @app.sitemap.resources - .sort_by { |resource| SORT_ORDER.index(resource.ext) || 100 } - .reject { |resource| resource.ext == '.css' } - .select { |resource| !@glob || File.fnmatch(@glob, resource.destination_path) } - .each(&method(:output_resource)) + resources = @app.sitemap.resources + .reject { |resource| resource.ext == '.css' } + .sort_by { |resource| SORT_ORDER.index(resource.ext) || 100 } + + if @glob + resources = resources.select do |resource| + if defined?(::File::FNM_EXTGLOB) + File.fnmatch(@glob, resource.destination_path, ::File::FNM_EXTGLOB) + else + File.fnmatch(@glob, resource.destination_path) + end + end + end + + output_resources(resources) + end + + Contract ResourceList => ResourceList + def output_resources(resources) + results = if @parallel + ::Parallel.map(resources, &method(:output_resource)) + else + resources.map(&method(:output_resource)) + end + + @has_error = true if results.any? { |r| r == false } + + if @cleaning && !@has_error + results.each do |p| + next unless p.exist? + + # handle UTF-8-MAC filename on MacOS + cleaned_name = if RUBY_PLATFORM =~ /darwin/ + p.to_s.encode('UTF-8', 'UTF-8-MAC') + else + p + end + + @to_clean.delete(Pathname(cleaned_name)) + end + end + + resources end # Figure out the correct event mode. @@ -119,9 +177,9 @@ module Middleman Contract Pathname, String => Tempfile def write_tempfile(output_file, contents) file = Tempfile.new([ - File.basename(output_file), - File.extname(output_file) - ]) + File.basename(output_file), + File.extname(output_file) + ]) file.binmode file.write(contents) file.close @@ -136,64 +194,56 @@ module Middleman Contract Pathname, Or[String, Pathname] => Any def export_file!(output_file, source) # ::Middleman::Util.instrument "write_file", output_file: output_file do - source = write_tempfile(output_file, source.to_s) if source.is_a? String + source = write_tempfile(output_file, source.to_s) if source.is_a? String - method, source_path = if source.is_a? Tempfile - [::FileUtils.method(:mv), source.path] - else - [::FileUtils.method(:cp), source.to_s] - end + method, source_path = if source.is_a? Tempfile + [::FileUtils.method(:mv), source.path] + else + [::FileUtils.method(:cp), source.to_s] + end - mode = which_mode(output_file, source_path) + mode = which_mode(output_file, source_path) - if mode == :created || mode == :updated - ::FileUtils.mkdir_p(output_file.dirname) - method.call(source_path, output_file.to_s) - end + if mode == :created || mode == :updated + ::FileUtils.mkdir_p(output_file.dirname) + method.call(source_path, output_file.to_s) + end - source.unlink if source.is_a? Tempfile + source.unlink if source.is_a? Tempfile - trigger(mode, output_file) + trigger(mode, output_file) # end end # Try to output a resource and capture errors. # @param [Middleman::Sitemap::Resource] resource The resource. # @return [void] - Contract IsA['Middleman::Sitemap::Resource'] => Any + Contract IsA['Middleman::Sitemap::Resource'] => Or[Pathname, Bool] def output_resource(resource) - output_file = @build_dir + resource.destination_path.gsub('%20', ' ') + ::Middleman::Util.instrument 'builder.output.resource', path: File.basename(resource.destination_path) do + output_file = @build_dir + resource.destination_path.gsub('%20', ' ') - begin - if resource.binary? - export_file!(output_file, resource.file_descriptor[:full_path]) - else - response = @rack.get(::URI.escape(resource.request_path)) - - # If we get a response, save it to a tempfile. - if response.status == 200 - export_file!(output_file, binary_encode(response.body)) + begin + if resource.binary? + export_file!(output_file, resource.file_descriptor[:full_path]) else - @has_error = true - trigger(:error, output_file, response.body) + response = @rack.get(::URI.escape(resource.request_path)) + + # If we get a response, save it to a tempfile. + if response.status == 200 + export_file!(output_file, binary_encode(response.body)) + else + trigger(:error, output_file, response.body) + return false + end end + rescue => e + trigger(:error, output_file, "#{e}\n#{e.backtrace.join("\n")}") + return false end - rescue => e - @has_error = true - trigger(:error, output_file, "#{e}\n#{e.backtrace.join("\n")}") - end - return unless @cleaning - return unless output_file.exist? - - # handle UTF-8-MAC filename on MacOS - cleaned_name = if RUBY_PLATFORM =~ /darwin/ - output_file.to_s.encode('UTF-8', 'UTF-8-MAC') - else output_file end - - @to_clean.delete(Pathname(cleaned_name)) end # Get a list of all the paths in the destination folder and save them diff --git a/middleman-core/lib/middleman-core/callback_manager.rb b/middleman-core/lib/middleman-core/callback_manager.rb index 5db86302..0edaf4cd 100644 --- a/middleman-core/lib/middleman-core/callback_manager.rb +++ b/middleman-core/lib/middleman-core/callback_manager.rb @@ -54,8 +54,8 @@ module Middleman return if callbacks_count < 1 # ::Middleman::Util.instrument "callbacks.execute", keys: keys, length: callbacks_count do - callbacks.each { |b| scope.instance_exec(*args, &b) } - @subscribers.each { |b| scope.instance_exec(keys, args, &b) } + callbacks.each { |b| scope.instance_exec(*args, &b) } + @subscribers.each { |b| scope.instance_exec(keys, args, &b) } # end end diff --git a/middleman-core/lib/middleman-core/config_context.rb b/middleman-core/lib/middleman-core/config_context.rb index 1f9f32f6..3ee98632 100644 --- a/middleman-core/lib/middleman-core/config_context.rb +++ b/middleman-core/lib/middleman-core/config_context.rb @@ -8,7 +8,7 @@ module Middleman attr_reader :app # Whitelist methods that can reach out. - def_delegators :@app, :config, :logger, :use, :map, :mime_type, :files, :root, :build?, :server?, :environment? + def_delegators :@app, :config, :logger, :use, :map, :mime_type, :files, :root, :build?, :server?, :environment?, :extensions def_delegator :"@app.extensions", :activate def initialize(app, template_context_class) @@ -22,6 +22,10 @@ module Middleman app.subscribe_to_callbacks(&method(:execute_callbacks)) end + def include(mod) + extend(mod) + end + def helpers(*helper_modules, &block) helper_modules ||= [] diff --git a/middleman-core/lib/middleman-core/configuration.rb b/middleman-core/lib/middleman-core/configuration.rb index 3f889c00..c916fc90 100644 --- a/middleman-core/lib/middleman-core/configuration.rb +++ b/middleman-core/lib/middleman-core/configuration.rb @@ -40,7 +40,7 @@ module Middleman # Allow configuration settings to be read and written via methods def method_missing(method, *args) - if defines_setting?(method) && args.size == 0 + if defines_setting?(method) && args.empty? self[method] elsif method.to_s =~ /^(\w+)=$/ && args.size == 1 self[$1.to_sym] = args[0] diff --git a/middleman-core/lib/middleman-core/contracts.rb b/middleman-core/lib/middleman-core/contracts.rb index e99d0d59..55aa0aad 100644 --- a/middleman-core/lib/middleman-core/contracts.rb +++ b/middleman-core/lib/middleman-core/contracts.rb @@ -1,23 +1,112 @@ -require 'contracts' -require 'hamster' +if ENV['CONTRACTS'] != 'false' + require 'contracts' + require 'hamster' -module Contracts - class IsA - def self.[](val) - @lookup ||= {} - @lookup[val] ||= new(val) + module Contracts + class IsA + def self.[](val) + @lookup ||= {} + @lookup[val] ||= new(val) + end + + def initialize(val) + @val = val + end + + def valid?(val) + val.is_a? @val.constantize + end end - def initialize(val) - @val = val + VectorOf = Contracts::CollectionOf::Factory.new(::Hamster::Vector) + ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']] + end +else + module Contracts + def self.included(base) + base.extend self end - def valid?(val) - val.is_a? @val.constantize + # rubocop:disable MethodName + def Contract(*) + end + + class Callable + def self.[](*) + end + end + + class Bool + end + + class Num + end + + class Pos + end + + class Neg + end + + class Any + end + + class None + end + + class Or < Callable + end + + class Xor < Callable + end + + class And < Callable + end + + class Not < Callable + end + + class RespondTo < Callable + end + + class Send < Callable + end + + class Exactly < Callable + end + + class ArrayOf < Callable + end + + class ResourceList < Callable + end + + class Args < Callable + end + + class HashOf < Callable + end + + class Bool + end + + class Maybe < Callable + end + + class IsA < Callable + end + + class SetOf < Callable + end + + class Frozen < Callable + end + + class VectorOf < Callable end end +end - VectorOf = ::Contracts::CollectionOf::Factory.new(::Hamster::Vector) - ResourceList = ::Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']] +module Contracts PATH_MATCHER = Or[String, RespondTo[:match], RespondTo[:call], RespondTo[:to_s]] end diff --git a/middleman-core/lib/middleman-core/core_extensions/collections.rb b/middleman-core/lib/middleman-core/core_extensions/collections.rb index 434455f1..b915fffd 100644 --- a/middleman-core/lib/middleman-core/core_extensions/collections.rb +++ b/middleman-core/lib/middleman-core/core_extensions/collections.rb @@ -1,3 +1,4 @@ +require 'monitor' require 'middleman-core/core_extensions/collections/pagination' require 'middleman-core/core_extensions/collections/step_context' require 'middleman-core/core_extensions/collections/lazy_root' @@ -41,6 +42,8 @@ module Middleman @values_by_name = {} @collector_roots = [] + + @lock = Monitor.new end def before_configuration @@ -81,27 +84,35 @@ module Middleman Contract ResourceList => ResourceList def manipulate_resource_list(resources) - @collector_roots.each do |pair| - dataset = pair[:block].call(app, resources) - pair[:root].realize!(dataset) - end + @lock.synchronize do + @collector_roots.each do |pair| + dataset = pair[:block].call(app, resources) + pair[:root].realize!(dataset) + end - ctx = StepContext.new - leaves = @leaves.dup + ctx = StepContext.new(app) + StepContext.current = ctx - @collectors_by_name.each do |k, v| - @values_by_name[k] = v.value(ctx) - leaves.delete v - end + leaves = @leaves.dup - # Execute code paths - leaves.each do |v| - v.value(ctx) - end + @collectors_by_name.each do |k, v| + @values_by_name[k] = v.value(ctx) + leaves.delete v + end - # Inject descriptors - ctx.descriptors.reduce(resources) do |sum, d| - d.execute_descriptor(app, sum) + # Execute code paths + leaves.each do |v| + v.value(ctx) + end + + # Inject descriptors + results = ctx.descriptors.reduce(resources) do |sum, d| + d.execute_descriptor(app, sum) + end + + StepContext.current = nil + + results end end end diff --git a/middleman-core/lib/middleman-core/core_extensions/collections/lazy_step.rb b/middleman-core/lib/middleman-core/core_extensions/collections/lazy_step.rb index 1286af2c..b316b3e3 100644 --- a/middleman-core/lib/middleman-core/core_extensions/collections/lazy_step.rb +++ b/middleman-core/lib/middleman-core/core_extensions/collections/lazy_step.rb @@ -2,7 +2,7 @@ module Middleman module CoreExtensions module Collections class LazyCollectorStep < BasicObject - DELEGATE = [:hash, :eql?] + DELEGATE = [:hash, :eql?].freeze def initialize(name, args, block, parent=nil) @name = name diff --git a/middleman-core/lib/middleman-core/core_extensions/collections/step_context.rb b/middleman-core/lib/middleman-core/core_extensions/collections/step_context.rb index 2ce90b83..0549b826 100644 --- a/middleman-core/lib/middleman-core/core_extensions/collections/step_context.rb +++ b/middleman-core/lib/middleman-core/core_extensions/collections/step_context.rb @@ -2,23 +2,30 @@ module Middleman module CoreExtensions module Collections class StepContext - def self.add_to_context(name, &func) - send(:define_method, :"_internal_#{name}", &func) + class << self + attr_accessor :current + + def add_to_context(name, &func) + send(:define_method, :"_internal_#{name}", &func) + end end attr_reader :descriptors - def initialize + def initialize(app) + @app = app @descriptors = [] end def method_missing(name, *args, &block) internal = :"_internal_#{name}" - return super unless respond_to?(internal) - - send(internal, *args, &block).tap do |r| - @descriptors << r if r.respond_to?(:execute_descriptor) + if respond_to?(internal) + send(internal, *args, &block).tap do |r| + @descriptors << r if r.respond_to?(:execute_descriptor) + end + else + @app.config_context.send(name, *args, &block) end end end diff --git a/middleman-core/lib/middleman-core/core_extensions/data.rb b/middleman-core/lib/middleman-core/core_extensions/data.rb index 22d571be..d711ef4f 100644 --- a/middleman-core/lib/middleman-core/core_extensions/data.rb +++ b/middleman-core/lib/middleman-core/core_extensions/data.rb @@ -8,7 +8,7 @@ module Middleman class Data < Extension attr_reader :data_store - define_setting :data_dir, 'data', 'The directory data files are stored in' + define_setting :data_dir, ENV['MM_DATA_DIR'] || 'data', 'The directory data files are stored in' # Make the internal `data_store` method available as `app.data` expose_to_application data: :data_store @@ -57,6 +57,7 @@ module Middleman @app = app @data_file_matcher = data_file_matcher @local_data = {} + @local_data_enhanced = nil @local_sources = {} @callback_sources = {} end @@ -66,7 +67,7 @@ module Middleman # @param [Symbol] name Name of the data, used for namespacing # @param [Hash] content The content for this data # @return [Hash] - Contract Symbol, Hash => Hash + Contract Symbol, Or[Hash, Array] => Hash def store(name=nil, content=nil) @local_sources[name.to_s] = content unless name.nil? || content.nil? @local_sources @@ -87,6 +88,8 @@ module Middleman def update_files(updated_files, removed_files) updated_files.each(&method(:touch_file)) removed_files.each(&method(:remove_file)) + + @app.sitemap.rebuild_resource_list!(:touched_data_file) end # Update the internal cache for a given file path @@ -99,13 +102,13 @@ module Middleman extension = File.extname(data_path) basename = File.basename(data_path, extension) + return unless %w(.yaml .yml .json).include?(extension) + if %w(.yaml .yml).include?(extension) - data, postscript = ::Middleman::Util::Data.parse(file[:full_path], @app.config[:frontmatter_delims], :yaml) + data, postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :yaml) data[:postscript] = postscript if !postscript.nil? && data.is_a?(Hash) elsif extension == '.json' - data, _postscript = ::Middleman::Util::Data.parse(file[:full_path], @app.config[:frontmatter_delims], :json) - else - return + data, _postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :json) end data_branch = @local_data @@ -117,6 +120,8 @@ module Middleman end data_branch[basename] = data + + @local_data_enhanced = nil end # Remove a given file from the internal cache @@ -137,13 +142,15 @@ module Middleman end data_branch.delete(basename) if data_branch.key?(basename) + + @local_data_enhanced = nil end # Get a hash from either internal static data or a callback # # @param [String, Symbol] path The name of the data namespace # @return [Hash, nil] - Contract Or[String, Symbol] => Maybe[Hash] + Contract Or[String, Symbol] => Maybe[Or[Array, IsA['Middleman::Util::EnhancedHash']]] def data_for_path(path) response = if store.key?(path.to_s) store[path.to_s] @@ -151,8 +158,7 @@ module Middleman callbacks[path.to_s].call end - response = ::Middleman::Util.recursively_enhance(response) - response + ::Middleman::Util.recursively_enhance(response) end # "Magically" find namespaces of data if they exist @@ -162,7 +168,8 @@ module Middleman def method_missing(path) if @local_data.key?(path.to_s) # Any way to cache this? - return ::Middleman::Util.recursively_enhance(@local_data[path.to_s]) + @local_data_enhanced ||= ::Middleman::Util.recursively_enhance(@local_data) + return @local_data_enhanced[path.to_s] else result = data_for_path(path) return result if result @@ -189,7 +196,7 @@ module Middleman (@local_data.keys + @local_sources.keys + @callback_sources.keys).include?(key.to_s) end - alias_method :has_key?, :key? + alias has_key? key? # Convert all the data into a static hash # @@ -198,11 +205,11 @@ module Middleman def to_h data = {} - store.each do |k, _| + store.each_key do |k| data[k] = data_for_path(k) end - callbacks.each do |k, _| + callbacks.each_key do |k| data[k] = data_for_path(k) end diff --git a/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb b/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb index be6371c1..774522db 100644 --- a/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb +++ b/middleman-core/lib/middleman-core/core_extensions/default_helpers.rb @@ -1,4 +1,5 @@ require 'padrino-helpers' +require 'middleman-core/contracts' # Don't fail on invalid locale, that's not what our current # users expect. @@ -9,7 +10,7 @@ class Padrino::Helpers::OutputHelpers::ErbHandler def capture_from_template(*args, &block) self.output_buffer = '' buf_was = output_buffer - raw = block.call(*args) + raw = yield(*args) captured = template.instance_variable_get(:@_out_buf) self.output_buffer = buf_was engine_matches?(block) && !captured.empty? ? captured : raw @@ -55,7 +56,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension output.safe_concat ::Padrino::Helpers::TagHelpers::NEWLINE end else - output.safe_concat "#{content}" + output.safe_concat content.to_s end output.safe_concat "" @@ -66,7 +67,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension result = if handler = auto_find_proper_handler(&block) handler.capture_from_template(*args, &block) else - block.call(*args) + yield(*args) end ::ActiveSupport::SafeBuffer.new.safe_concat(result) @@ -113,7 +114,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension path_options = {} path_options[:relative] = options.delete(:relative) if options.key?(:relative) - sources.flatten.inject(::ActiveSupport::SafeBuffer.new) do |all, source| + sources.flatten.reduce(::ActiveSupport::SafeBuffer.new) do |all, source| all << tag(:link, { href: asset_path(:css, source, path_options) }.update(options)) @@ -127,7 +128,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension path_options = {} path_options[:relative] = options.delete(:relative) if options.key?(:relative) - sources.flatten.inject(::ActiveSupport::SafeBuffer.new) do |all, source| + sources.flatten.reduce(::ActiveSupport::SafeBuffer.new) do |all, source| all << content_tag(:script, nil, { src: asset_path(:js, source, path_options) }.update(options)) @@ -152,7 +153,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension # If the basename of the request as no extension, assume we are serving a # directory and join index_file to the path. path = File.join(asset_dir, current_resource.path) - path = path.sub(/#{Regexp.escape(File.extname(path))}$/, ".#{asset_ext}") + path = path[0..-(File.extname(path).length + 1)] + ".#{asset_ext}" yield path if sitemap.find_resource_by_path(path) end @@ -191,7 +192,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension # @param [Hash] options Data to pass through. # @return [String] def asset_path(kind, source, options={}) - options_with_resource = options.merge(current_resource: current_resource) + options_with_resource = {}.merge!(options).merge!(current_resource: current_resource) ::Middleman::Util.asset_path(app, kind, source, options_with_resource) end @@ -202,7 +203,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension # @param [Hash] options Additional options. # @return [String] The fully qualified asset url def asset_url(path, prefix='', options={}) - options_with_resource = options.merge(current_resource: current_resource) + options_with_resource = {}.merge!(options).merge!(current_resource: current_resource) ::Middleman::Util.asset_url(app, path, prefix, options_with_resource) end @@ -210,7 +211,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension # or a Resource, this will produce the nice URL configured for that # path, respecting :relative_links, directory indexes, etc. def url_for(path_or_resource, options={}) - options_with_resource = options.merge(current_resource: current_resource) + options_with_resource = {}.merge!(options).merge!(current_resource: current_resource) ::Middleman::Util.url_for(app, path_or_resource, options_with_resource) end @@ -276,5 +277,14 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension super(path, params) end + + def partial(template, options={}, &block) + including_parent_locals = {} + including_parent_locals.merge!(@locs || {}) + including_parent_locals.merge!(options[:locals] || {}) + + options[:locals] = including_parent_locals + super(template, options, &block) + end end end diff --git a/middleman-core/lib/middleman-core/core_extensions/file_watcher.rb b/middleman-core/lib/middleman-core/core_extensions/file_watcher.rb index 617e0ac7..6fd16ae9 100644 --- a/middleman-core/lib/middleman-core/core_extensions/file_watcher.rb +++ b/middleman-core/lib/middleman-core/core_extensions/file_watcher.rb @@ -21,17 +21,14 @@ module Middleman tilde_files: /~$/, ds_store: /\.DS_Store$/, git: /(^|\/)\.git(ignore|modules|\/)/ - } + }.freeze # Setup the extension. def initialize(app, config={}, &block) super # Setup source collection. - @sources = ::Middleman::Sources.new(app, - disable_watcher: app.config[:watcher_disable], - force_polling: app.config[:watcher_force_polling], - latency: app.config[:watcher_latency]) + @sources = ::Middleman::Sources.new(app) # Add default ignores. IGNORES.each do |key, value| @@ -47,7 +44,7 @@ module Middleman # @return [void] Contract Any def before_configuration - @sources.find_new_files! + @sources.poll_once! end # After we config, find new files since config can change paths. @@ -55,12 +52,19 @@ module Middleman # @return [void] Contract Any def after_configuration + @watcher.update_config( + disable_watcher: app.config[:watcher_disable], + force_polling: app.config[:watcher_force_polling], + latency: app.config[:watcher_latency], + wait_for_delay: app.config[:watcher_wait_for_delay] + ) + if @original_source_dir != app.config[:source] @watcher.update_path(app.config[:source]) end @sources.start! - @sources.find_new_files! + @sources.poll_once! end protected diff --git a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb index 8bd31e4c..0f69c634 100644 --- a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb +++ b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb @@ -14,6 +14,12 @@ module Middleman::CoreExtensions # Try to run after routing but before directory_indexes self.resource_list_manipulator_priority = 20 + # Set textual delimiters that denote the start and end of frontmatter + define_setting :frontmatter_delims, { + json: [%w(;;; ;;;)], + yaml: [%w(--- ---), %w(--- ...)] + }, 'Allowed frontmatter delimiters' + def initialize(app, options_hash={}, &block) super @@ -28,9 +34,9 @@ module Middleman::CoreExtensions Contract ResourceList => ResourceList def manipulate_resource_list(resources) resources.each do |resource| - next if resource.ignored? + next if resource.binary? next if resource.file_descriptor.nil? - next unless resource.template? + next if resource.file_descriptor[:types].include?(:no_frontmatter) fmdata = data(resource.file_descriptor[:full_path].to_s).first.dup @@ -67,16 +73,20 @@ module Middleman::CoreExtensions return [{}, nil] unless file - @cache[file[:full_path]] ||= ::Middleman::Util::Data.parse( - file[:full_path], - app.config[:frontmatter_delims] - ) + file_path = file[:full_path].to_s + + @cache[file_path] ||= begin + ::Middleman::Util::Data.parse( + file, + app.config[:frontmatter_delims] + ) + end end Contract ArrayOf[IsA['Middleman::SourceFile']], ArrayOf[IsA['Middleman::SourceFile']] => Any def clear_data(updated_files, removed_files) (updated_files + removed_files).each do |file| - @cache.delete(file[:full_path]) + @cache.delete(file[:full_path].to_s) end end end diff --git a/middleman-core/lib/middleman-core/core_extensions/i18n.rb b/middleman-core/lib/middleman-core/core_extensions/i18n.rb index ce16ab48..156f2694 100644 --- a/middleman-core/lib/middleman-core/core_extensions/i18n.rb +++ b/middleman-core/lib/middleman-core/core_extensions/i18n.rb @@ -102,7 +102,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension locale_suffix = ::I18n.locale extname = File.extname(partial_name) - maybe_static = extname.length > 0 + maybe_static = !extname.empty? suffixed_partial_name = if maybe_static partial_name.sub(extname, ".#{locale_suffix}#{extname}") else @@ -127,7 +127,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension end # Backwards API compat - alias_method :langs, :locales + alias langs locales Contract Symbol def locale @@ -135,7 +135,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension end # Backwards API compat - alias_method :lang, :locale + alias lang locale # Update the main sitemap resource list # @return Array @@ -190,7 +190,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension end end - Contract String, Symbol => String + Contract String, Symbol => Maybe[String] def localized_path(path, locale) lookup_path = path.dup lookup_path << app.config[:index_file] if lookup_path.end_with?('/') @@ -203,7 +203,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension if (options[:mount_at_root] == locale) || (options[:mount_at_root].nil? && locales[0] == locale) '/' else - replacement = options[:locale_map].fetch(locale, locale) + replacement = options[:locale_map][locale] || locale options[:path].sub(':locale', replacement.to_s).sub(':lang', replacement.to_s) # Backward compat end end @@ -213,6 +213,8 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension def on_file_changed(_updated_files, _removed_files) ::I18n.load_path |= app.files.by_type(:locales).files.map { |p| p[:full_path].to_s } ::I18n.reload! + + @app.sitemap.rebuild_resource_list!(:touched_locale_file) end def configure_i18n @@ -274,7 +276,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension 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)}" + partially_localized_path = "#{partially_localized_path}/#{::I18n.t("paths.#{path_sub}", default: path_sub)}" end path = "#{partially_localized_path}/#{File.basename(path)}" diff --git a/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb b/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb index 2d04902d..43354e97 100644 --- a/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb +++ b/middleman-core/lib/middleman-core/core_extensions/inline_url_rewriter.rb @@ -1,25 +1,24 @@ require 'rack' require 'rack/response' -require 'addressable/uri' +require 'memoist' require 'middleman-core/util' require 'middleman-core/contracts' module Middleman module CoreExtensions - class InlineURLRewriter < ::Middleman::Extension include Contracts expose_to_application rewrite_inline_urls: :add - IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String] REWRITER_DESCRIPTOR = { id: Symbol, proc: Or[Proc, Method], url_extensions: ArrayOf[String], source_extensions: ArrayOf[String], - ignore: ArrayOf[IGNORE_DESCRIPTOR] - } + ignore: ArrayOf[::Middleman::Util::IGNORE_DESCRIPTOR], + after: Maybe[Symbol] + }.freeze def initialize(app, options_hash={}, &block) super @@ -33,23 +32,42 @@ module Middleman end def after_configuration - app.use Rack, { - rewriters: @rewriters.values, - middleman_app: @app - } + return if @rewriters.empty? + + rewriters = @rewriters.values.sort do |a, b| + if b[:after] && b[:after] == a[:id] + 1 + else + 0 + end + end + + app.use Rack, rewriters: rewriters, middleman_app: @app end class Rack + extend Memoist include Contracts - Contract RespondTo[:call], ({ + Contract RespondTo[:call], { middleman_app: IsA['Middleman::Application'], rewriters: ArrayOf[REWRITER_DESCRIPTOR] - }) => Any + } => Any def initialize(app, options={}) @rack_app = app @middleman_app = options.fetch(:middleman_app) @rewriters = options.fetch(:rewriters) + + all_source_exts = @rewriters + .reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] } + .flatten + .uniq + @source_exts_regex_text = Regexp.union(all_source_exts).to_s + + @all_asset_exts = @rewriters + .reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] } + .flatten + .uniq end def call(env) @@ -58,29 +76,16 @@ module Middleman # Allow configuration or upstream request to skip all rewriting return [status, headers, response] if env['bypass_inline_url_rewriter'] == 'true' - all_source_exts = @rewriters - .reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] } - .flatten - .uniq - source_exts_regex_text = Regexp.union(all_source_exts).to_s - - all_asset_exts = @rewriters - .reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] } - .flatten - .uniq - path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app) - return [status, headers, response] unless path =~ /(^\/$)|(#{source_exts_regex_text}$)/ + return [status, headers, response] unless path =~ /(^\/$)|(#{@source_exts_regex_text}$)/ return [status, headers, response] unless body = ::Middleman::Util.extract_response_text(response) dirpath = ::Pathname.new(File.dirname(path)) - rewritten = nil - - # ::Middleman::Util.instrument "inline_url_rewriter", path: path do - rewritten = ::Middleman::Util.rewrite_paths(body, path, all_asset_exts) do |asset_path| - uri = ::Addressable::URI.parse(asset_path) + rewritten = ::Middleman::Util.instrument 'inline_url_rewriter', path: path do + ::Middleman::Util.rewrite_paths(body, path, @all_asset_exts, @middleman_app) do |asset_path| + uri = ::Middleman::Util.parse_uri(asset_path) relative_path = uri.host.nil? @@ -103,10 +108,10 @@ module Middleman next unless source_exts.include?(::File.extname(path)) ignore = rewriter.fetch(:ignore) - next if ignore.any? { |r| should_ignore?(r, full_asset_path) } + next if ignore.any? { |r| ::Middleman::Util.should_ignore?(r, full_asset_path) } - rewrite_ignore = Array(rewriter.fetch(:rewrite_ignore, [])) - next if rewrite_ignore.any? { |ignore| ::Middleman::Util.path_match(ignore, path) } + rewrite_ignore = Array(rewriter[:rewrite_ignore] || []) + next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) } proc = rewriter.fetch(:proc) @@ -115,7 +120,7 @@ module Middleman end asset_path - # end + end end ::Rack::Response.new( @@ -124,25 +129,7 @@ module Middleman headers ).finish end - - Contract IGNORE_DESCRIPTOR, String => Bool - def should_ignore?(validator, value) - if validator.is_a? Regexp - # Treat as Regexp - !value.match(validator).nil? - elsif validator.respond_to? :call - # Treat as proc - validator.call(value) - elsif validator.is_a? String - # Treat as glob - File.fnmatch(value, validator) - else - # If some unknown thing, don't ignore - false - end - end end end - end end diff --git a/middleman-core/lib/middleman-core/core_extensions/routing.rb b/middleman-core/lib/middleman-core/core_extensions/routing.rb index c5655dfe..f47ac16b 100644 --- a/middleman-core/lib/middleman-core/core_extensions/routing.rb +++ b/middleman-core/lib/middleman-core/core_extensions/routing.rb @@ -4,7 +4,7 @@ module Middleman class Routing < ConfigExtension # This should always run late, but not as late as :directory_indexes, # so it can add metadata to any pages generated by other extensions - self.resource_list_manipulator_priority = 10 + self.resource_list_manipulator_priority = [10, 130] # Expose the `page` method to config. expose_to_config :page @@ -24,8 +24,8 @@ module Middleman normalized_path = '/' + ::Middleman::Util.strip_leading_slash(normalized_path) if normalized_path.is_a?(String) resources - .select { |r| ::Middleman::Util.path_match(normalized_path, "/#{r.path}") } - .each { |r| r.add_metadata(metadata) } + .select { |r| ::Middleman::Util.path_match(normalized_path, "/#{r.path}") } + .each { |r| r.add_metadata(metadata, true) } resources end @@ -52,10 +52,13 @@ module Middleman def page(path, opts={}) options = opts.dup + page_data = options.delete(:data) || {} + page_data[:id] = options.delete(:id) if options.key?(:id) + # Default layout metadata = { locals: options.delete(:locals) || {}, - page: options.delete(:data) || {}, + page: page_data, options: options } diff --git a/middleman-core/lib/middleman-core/extension.rb b/middleman-core/lib/middleman-core/extension.rb index a94a9e12..9805455a 100644 --- a/middleman-core/lib/middleman-core/extension.rb +++ b/middleman-core/lib/middleman-core/extension.rb @@ -1,4 +1,5 @@ require 'forwardable' +require 'memoist' require 'active_support/core_ext/class/attribute' require 'middleman-core/configuration' require 'middleman-core/contracts' @@ -66,6 +67,8 @@ module Middleman # @see http://middlemanapp.com/advanced/custom/ Middleman Custom Extensions Documentation class Extension extend Forwardable + extend Memoist + include Contracts def_delegator :@app, :logger @@ -402,11 +405,11 @@ module Middleman ext.after_configuration if ext.respond_to?(:after_configuration) if ext.respond_to?(:manipulate_resource_list) - ext.app.sitemap.register_resource_list_manipulator(ext.class.ext_name, ext, ext.class.resource_list_manipulator_priority) + ext.app.sitemap.register_resource_list_manipulators(ext.class.ext_name, ext, ext.class.resource_list_manipulator_priority) end if ext.class.resources_generators && !ext.class.resources_generators.empty? - ext.app.sitemap.register_resource_list_manipulator( + ext.app.sitemap.register_resource_list_manipulators( :"#{ext.class.ext_name}_generator", ext, ext.class.resource_list_manipulator_priority, @@ -432,7 +435,7 @@ module Middleman {} end - sum.merge(resource_definitions) + sum.merge!(resource_definitions) end resources + generator_defs.map do |path, g| @@ -490,15 +493,14 @@ module Middleman class ConfigExtension < Extension def initialize(app, config={}, &block) @descriptors = {} - @wrapped = {} + @ready = false self.class.exposed_to_config.each do |k, v| @descriptors[k] = [] define_singleton_method(:"__original_#{v}", &method(v)) - define_singleton_method(v) do |*args, &block| - @descriptors[k] << method(:"__original_#{v}").call(*args, &block) - @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}") + define_singleton_method(v) do |*args, &b| + proxy_method_call(k, v, args, &b) end end @@ -506,11 +508,24 @@ module Middleman end def after_configuration + context = self + self.class.exposed_to_config.each do |k, v| - ::Middleman::CoreExtensions::Collections::StepContext.add_to_context(k, &method(:"__original_#{v}")) + ::Middleman::CoreExtensions::Collections::StepContext.add_to_context(k) do |*args, &b| + r = context.method(:"__original_#{v}").call(*args, &b) + descriptors << r if r.respond_to?(:execute_descriptor) + end end end + def ready + @ready = true + + # @descriptors.each do |k, v| + # @descriptors[k] = [] + # end + end + # Update the main sitemap resource list # @return Array Contract ResourceList => ResourceList @@ -519,5 +534,25 @@ module Middleman c.execute_descriptor(app, sum) end end + + Contract Symbol, Symbol, ArrayOf[Any], Maybe[Proc] => Any + def proxy_method_call(k, v, args, &b) + if @ready + ctx = ::Middleman::CoreExtensions::Collections::StepContext.current + r = method(:"__original_#{v}").call(*args, &b) + + if r.respond_to?(:execute_descriptor) + if ctx + ctx.descriptors << r + else + @descriptors[k] << r + @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}") + end + end + else + @descriptors[k] << method(:"__original_#{v}").call(*args, &b) + @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}") + end + end end end diff --git a/middleman-core/lib/middleman-core/extensions.rb b/middleman-core/lib/middleman-core/extensions.rb index c295efe3..001b4344 100644 --- a/middleman-core/lib/middleman-core/extensions.rb +++ b/middleman-core/lib/middleman-core/extensions.rb @@ -52,7 +52,7 @@ module Middleman def register(name, extension_class=nil, options={}, &block) raise 'Extension name must be a symbol' unless name.is_a?(Symbol) # If we've already got an extension registered under this name, bail out - raise "There is already an extension registered with the name '#{name}'" if registered.key?(name) + # raise "There is a already an extension registered with the name '#{name}'" if registered.key?(name) # If the extension is defined with a block, grab options out of the "extension_class" parameter. if extension_class && block_given? && options.empty? && extension_class.is_a?(Hash) diff --git a/middleman-core/lib/middleman-core/extensions/asset_hash.rb b/middleman-core/lib/middleman-core/extensions/asset_hash.rb index e33ebf34..3e2a02aa 100644 --- a/middleman-core/lib/middleman-core/extensions/asset_hash.rb +++ b/middleman-core/lib/middleman-core/extensions/asset_hash.rb @@ -2,10 +2,11 @@ require 'middleman-core/util' require 'middleman-core/rack' class Middleman::Extensions::AssetHash < ::Middleman::Extension - option :sources, %w(.htm .html .php .css .js), 'List of extensions that are searched for hashable assets.' - 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 :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for hashable assets.' + option :exts, nil, 'List of extensions that get asset hashes appended to them.' option :ignore, [], 'Regexes of filenames to skip adding asset hashes to' option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites' + option :prefix, '', 'Prefix for hash' def initialize(app, options_hash={}, &block) super @@ -17,18 +18,23 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension # Allow specifying regexes to ignore, plus always ignore apple touch icons @ignore = Array(options.ignore) + [/^apple-touch-icon/] + # Exclude .ico from the default list because browsers expect it + # to be named "favicon.ico" + @exts = options.exts || (app.config[:asset_extensions] - %w(.ico)) + app.rewrite_inline_urls id: :asset_hash, - url_extensions: options.exts.sort.reverse, + url_extensions: @exts.sort.reverse, source_extensions: options.sources, ignore: @ignore, rewrite_ignore: options.rewrite_ignore, - proc: method(:rewrite_url) + proc: method(:rewrite_url), + after: :asset_host end Contract String, Or[String, Pathname], Any => Maybe[String] def rewrite_url(asset_path, dirpath, _request_path) - uri = ::Addressable::URI.parse(asset_path) - relative_path = uri.path[0..0] != '/' + uri = ::Middleman::Util.parse_uri(asset_path) + relative_path = !uri.path.start_with?('/') full_asset_path = if relative_path dirpath.join(asset_path).to_s @@ -69,11 +75,13 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension Contract IsA['Middleman::Sitemap::Resource'] => Maybe[IsA['Middleman::Sitemap::Resource']] def manipulate_single_resource(resource) - return unless options.exts.include?(resource.ext) + return unless @exts.include?(resource.ext) return if ignored_resource?(resource) return if resource.ignored? - digest = if resource.template? + digest = if resource.binary? + ::Digest::SHA1.file(resource.source_file).hexdigest[0..7] + else # Render through the Rack interface so middleware and mounted apps get a shot response = @rack_client.get( ::URI.escape(resource.destination_path), @@ -83,11 +91,9 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension raise "#{resource.path} should be in the sitemap!" unless response.status == 200 ::Digest::SHA1.hexdigest(response.body)[0..7] - else - ::Digest::SHA1.file(resource.source_file).hexdigest[0..7] end - resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" } + resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{options.prefix}#{digest}#{ext}" } resource end diff --git a/middleman-core/lib/middleman-core/extensions/asset_host.rb b/middleman-core/lib/middleman-core/extensions/asset_host.rb index 00d463fa..7cb83d07 100644 --- a/middleman-core/lib/middleman-core/extensions/asset_host.rb +++ b/middleman-core/lib/middleman-core/extensions/asset_host.rb @@ -2,8 +2,8 @@ require 'addressable/uri' class Middleman::Extensions::AssetHost < ::Middleman::Extension option :host, nil, 'The asset host to use or a Proc to determine asset host', required: true - option :exts, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif), 'List of extensions that get cache busters strings appended to them.' - option :sources, %w(.htm .html .php .css .js), 'List of extensions that are searched for bustable assets.' + option :exts, nil, 'List of extensions that get cache busters strings appended to them.' + option :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for bustable assets.' option :ignore, [], 'Regexes of filenames to skip adding query strings to' option :rewrite_ignore, [], 'Regexes of filenames to skip processing for host rewrites' @@ -11,7 +11,7 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension super app.rewrite_inline_urls id: :asset_host, - url_extensions: options.exts, + url_extensions: options.exts || app.config[:asset_extensions], source_extensions: options.sources, ignore: options.ignore, rewrite_ignore: options.rewrite_ignore, @@ -20,7 +20,7 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension Contract String, Or[String, Pathname], Any => String def rewrite_url(asset_path, dirpath, _request_path) - uri = ::Addressable::URI.parse(asset_path) + uri = ::Middleman::Util.parse_uri(asset_path) relative_path = uri.path[0..0] != '/' full_asset_path = if relative_path @@ -37,4 +37,5 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension File.join(asset_prefix, full_asset_path) end + memoize :rewrite_url end diff --git a/middleman-core/lib/middleman-core/extensions/automatic_image_sizes.rb b/middleman-core/lib/middleman-core/extensions/automatic_image_sizes.rb index b88721de..5d12501f 100644 --- a/middleman-core/lib/middleman-core/extensions/automatic_image_sizes.rb +++ b/middleman-core/lib/middleman-core/extensions/automatic_image_sizes.rb @@ -19,7 +19,7 @@ class Middleman::Extensions::AutomaticImageSizes < ::Middleman::Extension real_path = path.dup real_path = File.join(config[:images_dir], real_path) unless real_path.start_with?('/') - file = app.files.find(:source, real_path) + file = app.files.find(:source, real_path) || app.files.find(:source, real_path.sub(/^\//, '')) if file && file[:full_path].exist? begin diff --git a/middleman-core/lib/middleman-core/extensions/cache_buster.rb b/middleman-core/lib/middleman-core/extensions/cache_buster.rb index 44eda9bc..2de11632 100644 --- a/middleman-core/lib/middleman-core/extensions/cache_buster.rb +++ b/middleman-core/lib/middleman-core/extensions/cache_buster.rb @@ -1,7 +1,7 @@ # The Cache Buster extension class Middleman::Extensions::CacheBuster < ::Middleman::Extension - option :exts, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif), 'List of extensions that get cache busters strings appended to them.' - option :sources, %w(.htm .html .php .css .js), 'List of extensions that are searched for bustable assets.' + option :exts, nil, 'List of extensions that get cache busters strings appended to them.' + option :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for bustable assets.' option :ignore, [], 'Regexes of filenames to skip adding query strings to' option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites' @@ -9,7 +9,7 @@ class Middleman::Extensions::CacheBuster < ::Middleman::Extension super app.rewrite_inline_urls id: :cache_buster, - url_extensions: options.exts, + url_extensions: options.exts || app.config[:asset_extensions], source_extensions: options.sources, ignore: options.ignore, rewrite_ignore: options.rewrite_ignore, diff --git a/middleman-core/lib/middleman-core/extensions/directory_indexes.rb b/middleman-core/lib/middleman-core/extensions/directory_indexes.rb index 171b1493..cef88868 100644 --- a/middleman-core/lib/middleman-core/extensions/directory_indexes.rb +++ b/middleman-core/lib/middleman-core/extensions/directory_indexes.rb @@ -11,16 +11,22 @@ class Middleman::Extensions::DirectoryIndexes < ::Middleman::Extension index_file = app.config[:index_file] new_index_path = "/#{index_file}" + extensions = %w(.htm .html .php .xhtml) + resources.each do |resource| # Check if it would be pointless to reroute next if resource.destination_path == index_file || resource.destination_path.end_with?(new_index_path) || - File.extname(index_file) != resource.ext + !extensions.include?(resource.ext) # Check if file metadata (options set by "page" in config.rb or frontmatter) turns directory_index off next if resource.options[:directory_index] == false - resource.destination_path = resource.destination_path.chomp(File.extname(index_file)) + new_index_path + extensions.each do |ext| + resource.destination_path = resource.destination_path.chomp(ext) + end + + resource.destination_path += new_index_path end end end diff --git a/middleman-core/lib/middleman-core/extensions/external_pipeline.rb b/middleman-core/lib/middleman-core/extensions/external_pipeline.rb index 44a4e6b3..ae5e4c3c 100644 --- a/middleman-core/lib/middleman-core/extensions/external_pipeline.rb +++ b/middleman-core/lib/middleman-core/extensions/external_pipeline.rb @@ -10,32 +10,79 @@ class Middleman::Extensions::ExternalPipeline < ::Middleman::Extension def initialize(app, config={}, &block) super + return if app.mode?(:config) + + require 'servolux' require 'thread' + require 'fileutils' + + source_path = File.expand_path(options[:source], app.root) + + # Make sure it exists, or `listen` will explode. + ::FileUtils.mkdir_p(source_path) @watcher = app.files.watch :source, - path: File.expand_path(options[:source], app.root), - latency: options[:latency] + path: source_path, + latency: options[:latency], + frontmatter: false + + @current_thread = nil + app.reload(&method(:reload!)) logger.info "== Executing: `#{options[:command]}`" if app.build? || options[:disable_background_execution] - watch_command! + watch_command!(false) + + @watcher.poll_once! else - ::Thread.new { watch_command! } + watch_command!(true) end end - def watch_command! - ::IO.popen(options[:command], 'r') do |pipe| - while buf = pipe.gets + def reload! + if @current_thread + logger.info "== Stopping: `#{options[:command]}`" + + @current_thread.stop + @current_thread = nil + end + end + + def watch_command!(async) + @current_thread = ::Servolux::Child.new( + command: options[:command], + suspend: 2 + ) + + @current_thread.start + + watch_thread = Thread.new do + while buf = @current_thread.io.gets without_newline = buf.sub(/\n$/, '') - logger.info "== External: #{without_newline}" if without_newline.length > 0 + logger.info "== External: #{without_newline}" unless without_newline.empty? + end + + @current_thread.wait + + if !@current_thread.exitstatus.nil? && @current_thread.exitstatus != 0 + logger.error '== External: Command failed with non-zero exit status' + exit(1) end end - @watcher.poll_once! + watch_thread.join unless async rescue ::Errno::ENOENT => e logger.error "== External: Command failed with message: #{e.message}" exit(1) end + + private + + def print_command(stdout) + while buf = stdout.gets + without_newline = buf.sub(/\n$/, '') + logger.info "== External: #{without_newline}" unless without_newline.empty? + end + end end diff --git a/middleman-core/lib/middleman-core/extensions/gzip.rb b/middleman-core/lib/middleman-core/extensions/gzip.rb index cc1a7fea..0483fe32 100644 --- a/middleman-core/lib/middleman-core/extensions/gzip.rb +++ b/middleman-core/lib/middleman-core/extensions/gzip.rb @@ -7,10 +7,10 @@ # to serve your Gzipped files whenever the normal (non-.gz) filename is requested. # # Pass the :exts options to customize which file extensions get zipped (defaults -# to .html, .htm, .js and .css. +# to .css, .htm, .html, .js, and .xhtml # class Middleman::Extensions::Gzip < ::Middleman::Extension - option :exts, %w(.js .css .html .htm .svg), 'File extensions to Gzip when building.' + option :exts, %w(.css .htm .html .js .svg .xhtml), 'File extensions to Gzip when building.' option :ignore, [], 'Patterns to avoid gzipping' option :overwrite, false, 'Overwrite original files instead of adding .gz extension.' @@ -64,10 +64,10 @@ class Middleman::Extensions::Gzip < ::Middleman::Extension total_savings += (old_size - new_size) size_change_word = (old_size - new_size) > 0 ? 'smaller' : 'larger' - builder.trigger :gzip, "#{output_filename} (#{NumberHelpers.new.number_to_human_size((old_size - new_size).abs)} #{size_change_word})" + builder.trigger :created, "#{output_filename} (#{NumberHelpers.new.number_to_human_size((old_size - new_size).abs)} #{size_change_word})" end - builder.trigger :gzip, "Total gzip savings: #{NumberHelpers.new.number_to_human_size(total_savings)}" + builder.trigger :gzip, '', "Total gzip savings: #{NumberHelpers.new.number_to_human_size(total_savings)}" I18n.locale = old_locale end diff --git a/middleman-core/lib/middleman-core/extensions/lorem.rb b/middleman-core/lib/middleman-core/extensions/lorem.rb index 91a0612d..6cad9abf 100644 --- a/middleman-core/lib/middleman-core/extensions/lorem.rb +++ b/middleman-core/lib/middleman-core/extensions/lorem.rb @@ -44,7 +44,7 @@ class Middleman::Extensions::Lorem < ::Middleman::Extension module LoremObject class << self # Words for use in lorem text - WORDS = %w(alias consequatur aut perferendis sit voluptatem accusantium doloremque aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo aspernatur aut odit aut fugit sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque dolorem ipsum quia dolor sit amet consectetur adipisci velit sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem ut enim ad minima veniam quis nostrum exercitationem ullam corporis nemo enim ipsam voluptatem quia voluptas sit suscipit laboriosam nisi ut aliquid ex ea commodi consequatur quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae et iusto odio dignissimos ducimus qui blanditiis praesentium laudantium totam rem voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident sed ut perspiciatis unde omnis iste natus error similique sunt in culpa qui officia deserunt mollitia animi id est laborum et dolorum fuga et harum quidem rerum facilis est et expedita distinctio nam libero tempore cum soluta nobis est eligendi optio cumque nihil impedit quo porro quisquam est qui minus id quod maxime placeat facere possimus omnis voluptas assumenda est omnis dolor repellendus temporibus autem quibusdam et aut consequatur vel illum qui dolorem eum fugiat quo voluptas nulla pariatur at vero eos et accusamus officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae itaque earum rerum hic tenetur a sapiente delectus ut aut reiciendis voluptatibus maiores doloribus asperiores repellat) + WORDS = %w(alias consequatur aut perferendis sit voluptatem accusantium doloremque aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo aspernatur aut odit aut fugit sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque dolorem ipsum quia dolor sit amet consectetur adipisci velit sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem ut enim ad minima veniam quis nostrum exercitationem ullam corporis nemo enim ipsam voluptatem quia voluptas sit suscipit laboriosam nisi ut aliquid ex ea commodi consequatur quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae et iusto odio dignissimos ducimus qui blanditiis praesentium laudantium totam rem voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident sed ut perspiciatis unde omnis iste natus error similique sunt in culpa qui officia deserunt mollitia animi id est laborum et dolorum fuga et harum quidem rerum facilis est et expedita distinctio nam libero tempore cum soluta nobis est eligendi optio cumque nihil impedit quo porro quisquam est qui minus id quod maxime placeat facere possimus omnis voluptas assumenda est omnis dolor repellendus temporibus autem quibusdam et aut consequatur vel illum qui dolorem eum fugiat quo voluptas nulla pariatur at vero eos et accusamus officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae itaque earum rerum hic tenetur a sapiente delectus ut aut reiciendis voluptatibus maiores doloribus asperiores repellat).freeze # Get one placeholder word # @return [String] diff --git a/middleman-core/lib/middleman-core/extensions/minify_css.rb b/middleman-core/lib/middleman-core/extensions/minify_css.rb index e58b7852..aca9c60b 100644 --- a/middleman-core/lib/middleman-core/extensions/minify_css.rb +++ b/middleman-core/lib/middleman-core/extensions/minify_css.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/try' +require 'memoist' require 'middleman-core/contracts' # Minify CSS Extension @@ -23,24 +25,25 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension class SassCompressor def self.compress(style, options={}) root_node = ::Sass::SCSS::CssParser.new(style, 'middleman-css-input', 1).parse - root_node.options = options.merge(style: :compressed) + root_node.options = {}.merge!(options).merge!(style: :compressed) root_node.render.strip end end # Rack middleware to look for CSS and compress it class Rack + extend Memoist include Contracts INLINE_CSS_REGEX = /(]*>\s*(?:\/\*\*\/)?\s*<\/style>)/m # Init # @param [Class] app # @param [Hash] options - Contract RespondTo[:call], ({ + Contract RespondTo[:call], { ignore: ArrayOf[PATH_MATCHER], inline: Bool, compressor: Or[Proc, RespondTo[:to_proc], RespondTo[:compress]] - }) => Any + } => Any def initialize(app, options={}) @app = app @ignore = options.fetch(:ignore) @@ -69,7 +72,7 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension end if minified - headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s + headers['Content-Length'] = minified.bytesize.to_s response = [minified] end @@ -82,8 +85,9 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension # @param [String] path # @return [Boolean] def ignore?(path) - @ignore.any? { |ignore| Middleman::Util.path_match(ignore, path) } + @ignore.any? { |ignore| ::Middleman::Util.path_match(ignore, path) } end + memoize :ignore? # Whether this type of content can be minified # @param [String, nil] content_type @@ -91,6 +95,7 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension def minifiable?(content_type) @content_types.include?(content_type) end + memoize :minifiable? # Whether this type of content contains inline content that can be minified # @param [String, nil] content_type @@ -98,6 +103,7 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension def minifiable_inline?(content_type) @inline_content_types.include?(content_type) end + memoize :minifiable_inline? # Minify the content # @param [String] content @@ -105,6 +111,7 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension def minify(content) @compressor.compress(content) end + memoize :minify # Detect and minify inline content # @param [String] content @@ -114,5 +121,6 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension $1 + minify($2) + $3 end end + memoize :minify_inline end end diff --git a/middleman-core/lib/middleman-core/extensions/minify_javascript.rb b/middleman-core/lib/middleman-core/extensions/minify_javascript.rb index 73a75cd0..714d0645 100644 --- a/middleman-core/lib/middleman-core/extensions/minify_javascript.rb +++ b/middleman-core/lib/middleman-core/extensions/minify_javascript.rb @@ -1,4 +1,6 @@ +require 'active_support/core_ext/object/try' require 'middleman-core/contracts' +require 'memoist' # Minify Javascript Extension class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension @@ -22,17 +24,18 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension # Rack middleware to look for JS and compress it class Rack + extend Memoist include Contracts INLINE_JS_REGEX = /(]*>\s*(?:\/\/(?:(?:)|(?:\]\]>)))?\s*<\/script>)/m # Init # @param [Class] app # @param [Hash] options - Contract RespondTo[:call], ({ + Contract RespondTo[:call], { ignore: ArrayOf[PATH_MATCHER], inline: Bool, compressor: Or[Proc, RespondTo[:to_proc], RespondTo[:compress]] - }) => Any + } => Any def initialize(app, options={}) @app = app @ignore = options.fetch(:ignore) @@ -61,7 +64,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension end if minified - headers['Content-Length'] = ::Rack::Utils.bytesize(minified).to_s + headers['Content-Length'] = minified.bytesize.to_s response = [minified] end @@ -76,6 +79,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension def ignore?(path) @ignore.any? { |ignore| Middleman::Util.path_match(ignore, path) } end + memoize :ignore? # Whether this type of content can be minified # @param [String, nil] content_type @@ -83,6 +87,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension def minifiable?(content_type) @content_types.include?(content_type) end + memoize :minifiable? # Whether this type of content contains inline content that can be minified # @param [String, nil] content_type @@ -90,6 +95,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension def minifiable_inline?(content_type) @inline_content_types.include?(content_type) end + memoize :minifiable_inline? # Minify the content # @param [String] content @@ -100,6 +106,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension warn "WARNING: Couldn't compress JavaScript in #{@path}: #{e.message}" content end + memoize :minify # Detect and minify inline content # @param [String] content @@ -112,12 +119,13 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension # Only compress script tags that contain JavaScript (as opposed to # something like jQuery templates, identified with a "text/html" type). - if first.include?('