Extract compass support into extension, rewrite all features that rely on it to be pure Ruby

This commit is contained in:
Thomas Reynolds 2014-04-07 12:43:16 -07:00
parent 3879be0f23
commit 29bf25ace6
63 changed files with 766 additions and 363 deletions

View file

@ -22,6 +22,8 @@ platforms :ruby do
gem 'therubyracer' gem 'therubyracer'
gem 'redcarpet', '~> 3.1' gem 'redcarpet', '~> 3.1'
gem 'pry', require: false, group: :development gem 'pry', require: false, group: :development
# gem 'pry-debugger', require: false, group: :development
# gem 'pry-stack_explorer', require: false, group: :development
end end
platforms :jruby do platforms :jruby do
@ -35,5 +37,6 @@ gem 'rubocop', require: false
# Middleman itself # Middleman itself
gem 'middleman-core', path: 'middleman-core' gem 'middleman-core', path: 'middleman-core'
gem 'middleman-cli', path: 'middleman-cli' gem 'middleman-cli', path: 'middleman-cli'
gem 'middleman-compass', path: 'middleman-compass', require: false
gem 'middleman-sprockets', github: 'middleman/middleman-sprockets', require: false gem 'middleman-sprockets', github: 'middleman/middleman-sprockets', require: false
gem 'middleman', path: 'middleman' gem 'middleman', path: 'middleman'

View file

@ -46,7 +46,6 @@ task :test do
GEM_PATHS.each do |g| GEM_PATHS.each do |g|
Dir.chdir("#{File.join(ROOT, g)}") { sh "#{Gem.ruby} -S rake test" } Dir.chdir("#{File.join(ROOT, g)}") { sh "#{Gem.ruby} -S rake test" }
end end
Rake::Task['rubocop'].invoke
end end
desc 'Run specs for all middleman gems' desc 'Run specs for all middleman gems'
@ -56,10 +55,15 @@ task :spec do
end end
end end
require 'rubocop/rake_task' begin
desc 'Run RuboCop to check code consistency' require 'rubocop/rake_task'
Rubocop::RakeTask.new(:rubocop) do |task| if defined?(Rubocop)
desc 'Run RuboCop to check code consistency'
Rubocop::RakeTask.new(:rubocop) do |task|
task.fail_on_error = false task.fail_on_error = false
end
end
rescue LoadError
end end
desc 'Run tests for all middleman gems' desc 'Run tests for all middleman gems'

View file

@ -187,9 +187,9 @@ module Middleman::Cli
resource.ext == '.css' resource.ext == '.css'
end.each(&method(:build_resource)) end.each(&method(:build_resource))
logger.debug '== Checking for Compass sprites' logger.debug '== Checking for generated images'
# Double-check for compass sprites # Double-check for generated images
@app.files.find_new_files((@source_dir + @app.config[:images_dir]).relative_path_from(@app.root_path)) @app.files.find_new_files((@source_dir + @app.config[:images_dir]).relative_path_from(@app.root_path))
@app.sitemap.ensure_resource_list_updated! @app.sitemap.ensure_resource_list_updated!

10
middleman-compass/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
.DS_Store
Gemfile.lock
Gemfile-v4.lock
tmp
.rbenv-*
.sass-cache
pkg
build
.ruby-version
.cache

View file

@ -0,0 +1,16 @@
rvm:
- 1.9.3
- 2.0.0
- 2.1.1
- jruby-19mode
gemfile:
- Gemfile
- Gemfile-v4
script: "bundle exec rake test"
env: TEST=true
matrix:
fast_finish: true

View file

@ -0,0 +1,43 @@
# Contributing
In the spirit of [free software][free-sw], **everyone** is encouraged to help
improve this project.
[free-sw]: http://www.fsf.org/licensing/essays/free-sw.html
Here are some ways *you* can contribute:
* by using alpha, beta, and prerelease versions
* by reporting bugs
* by suggesting new features
* by writing or editing documentation
* by writing specifications
* by writing code ( **no patch is too small** : fix typos, add comments, clean up inconsistent whitespace )
* by refactoring code
* by closing [issues][]
* by reviewing patches
[issues]: https://github.com/middleman/middleman-compass/issues
## Submitting an Issue
We use the [GitHub issue tracker][issues] to track bugs and features. Before
submitting a bug report or feature request, check to make sure it hasn't
already been submitted. When submitting a bug report, please include a [Gist][]
that includes a stack trace and any details that may be necessary to reproduce
the bug, including your gem version, Ruby version, and operating system.
Ideally, a bug report should include a pull request with failing specs.
[gist]: https://gist.github.com/
## Submitting a Pull Request
1. [Fork the repository.][fork]
2. [Create a topic branch.][branch]
3. Add specs for your unimplemented feature or bug fix.
4. Run `bundle exec rake test`. If your specs pass, return to step 3.
5. Implement your feature or bug fix.
6. Run `bundle exec rake test`. If your specs fail, return to step 5.
7. Add, commit, and push your changes.
8. [Submit a pull request.][pr]
[fork]: http://help.github.com/fork-a-repo/
[branch]: http://learn.github.com/p/branching.html
[pr]: http://help.github.com/send-pull-requests/

17
middleman-compass/Gemfile Normal file
View file

@ -0,0 +1,17 @@
source "https://rubygems.org"
gem "middleman-cli", :github => "middleman/middleman", :branch => "master"
gem "middleman-core", :github => "middleman/middleman", :branch => "master"
# Specify your gem's dependencies in middleman-sprockets.gemspec
gemspec
gem "rake", "~> 10.0.3", :require => false
gem "yard", "~> 0.8.0", :require => false
# Test tools
gem "cucumber"
gem "fivemat", "~> 1.2.1"
gem "aruba"
gem "rspec", "~> 2.14"
gem "builder", "~> 3.0"

View file

@ -0,0 +1,20 @@
Copyright (c) 2012-2013 Thomas Reynolds
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,59 @@
# Middleman-compass
`middleman-compass` is an extension for the [Middleman] static site generator that allows support for [Compass](http://compass-style.org) in your assets.
## Installation
If you're just getting started, install the `middleman` gem and generate a new project:
```
gem install middleman
middleman init MY_PROJECT
```
If you already have a Middleman project: Add `gem "middleman-compass"` to your `Gemfile` and run `bundle install`
## Configuration
```
activate :compass
```
## Build & Dependency Status
[![Gem Version](https://badge.fury.io/rb/middleman-compass.png)][gem]
[![Build Status](https://travis-ci.org/middleman/middleman-compass.png)][travis]
[![Dependency Status](https://gemnasium.com/middleman/middleman-compass.png?travis)][gemnasium]
[![Code Quality](https://codeclimate.com/github/middleman/middleman-compass.png)][codeclimate]
## Community
The official community forum is available at: http://forum.middlemanapp.com
## Bug Reports
Github Issues are used for managing bug reports and feature requests. If you run into issues, please search the issues and submit new problems: https://github.com/middleman/middleman-compass/issues
The best way to get quick responses to your issues and swift fixes to your bugs is to submit detailed bug reports, include test cases and respond to developer questions in a timely manner. Even better, if you know Ruby, you can submit [Pull Requests](https://help.github.com/articles/using-pull-requests) containing Cucumber Features which describe how your feature should work or exploit the bug you are submitting.
## How to Run Cucumber Tests
1. Checkout Repository: `git clone https://github.com/middleman/middleman-compass.git`
2. Install Bundler: `gem install bundler`
3. Run `bundle install` inside the project root to install the gem dependencies.
4. Run test cases: `bundle exec rake test`
## Donate
[Click here to lend your support to Middleman](https://spacebox.io/s/4dXbHBorC3)
## License
Copyright (c) 2012-2013 Thomas Reynolds. MIT Licensed, see [LICENSE] for details.
[middleman]: http://middlemanapp.com
[gem]: https://rubygems.org/gems/middleman-compass
[travis]: http://travis-ci.org/middleman/middleman-compass
[gemnasium]: https://gemnasium.com/middleman/middleman-compass
[codeclimate]: https://codeclimate.com/github/middleman/middleman-compass
[LICENSE]: https://github.com/middleman/middleman-compass/blob/master/LICENSE.md

View file

@ -0,0 +1,20 @@
require 'bundler'
Bundler::GemHelper.install_tasks
require 'cucumber/rake/task'
require 'middleman-core/version'
Cucumber::Rake::Task.new(:cucumber, 'Run features that should pass') do |t|
exempt_tags = ["--tags ~@wip"]
t.cucumber_opts = "--color #{exempt_tags.join(" ")} --strict --format #{ENV['CUCUMBER_FORMAT'] || 'Fivemat'}"
end
require 'rake/clean'
task :test => [:cucumber]
desc "Build HTML documentation"
task :doc do
sh 'bundle exec yard'
end

View file

@ -0,0 +1,8 @@
PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__)))
ENV['TEST'] = 'true'
ENV["AUTOLOAD_COMPASS"] = "true"
require "middleman-core"
require "middleman-core/step_definitions"
require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-compass')
require "erubis"

View file

@ -0,0 +1,2 @@
require 'middleman-compass'
activate :compass

View file

@ -0,0 +1,6 @@
require "middleman-core"
Middleman::Extensions.register(:compass) do
require "middleman-compass/extension"
Middleman::CompassExtension
end

View file

@ -0,0 +1,63 @@
module Middleman
class CompassExtension < Extension
def initialize(app, options_hash={}, &block)
require 'middleman-core/renderers/sass'
require 'compass'
super
# Hooks to manually update the compass config after we're
# done with it
app.define_hook :compass_config end
def after_configuration
::Compass.configuration do |compass_config|
compass_config.project_path = app.source_dir
compass_config.environment = :development
compass_config.cache = false
compass_config.sass_dir = app.config[:css_dir]
compass_config.css_dir = app.config[:css_dir]
compass_config.javascripts_dir = app.config[:js_dir]
compass_config.fonts_dir = app.config[:fonts_dir]
compass_config.images_dir = app.config[:images_dir]
compass_config.http_path = app.config[:http_prefix]
# Disable this initially, the cache_buster extension will
# re-enable it if requested.
compass_config.asset_cache_buster { |_| nil }
# Disable this initially, the relative_assets extension will
compass_config.relative_assets = false
# Default output style
compass_config.output_style = :nested
end
# Call hook
app.run_hook_for :compass_config, app, ::Compass.configuration
# Tell Tilt to use it as well (for inline sass blocks)
::Tilt.register 'sass', CompassSassTemplate
::Tilt.prefer(CompassSassTemplate)
# Tell Tilt to use it as well (for inline scss blocks)
::Tilt.register 'scss', CompassScssTemplate
::Tilt.prefer(CompassScssTemplate)
end
# A Compass Sass template for Tilt, adding our options in
class CompassSassTemplate < ::Middleman::Renderers::Sass::SassPlusCSSFilenameTemplate
def sass_options
super.merge(::Compass.configuration.to_sass_engine_options)
end
end
# A Compass Scss template for Tilt, adding our options in
class CompassScssTemplate < ::Middleman::Renderers::Sass::ScssPlusCSSFilenameTemplate
def sass_options
super.merge(::Compass.configuration.to_sass_engine_options)
end
end
end
end

View file

@ -0,0 +1,5 @@
module Middleman
module Compass
VERSION = "4.0.0"
end
end

View file

@ -0,0 +1,20 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "middleman-compass/version"
Gem::Specification.new do |s|
s.name = "middleman-compass"
s.version = Middleman::Compass::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ['Thomas Reynolds', 'Ben Hollis', 'Karl Freeman']
s.email = ['me@tdreyno.com', 'ben@benhollis.net', 'karlfreeman@gmail.com']
s.homepage = "https://github.com/middleman/middleman-compass"
s.summary = %q{Compass support for Middleman}
s.description = %q{Compass support for Middleman}
s.license = "MIT"
s.files = `git ls-files -z`.split("\0")
s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
s.require_paths = ["lib"]
s.add_dependency("middleman-core")#, [">= 4.0.0"])
s.add_dependency('compass', ['>= 1.0.0.alpha.19'])
end

View file

@ -10,7 +10,7 @@ Feature: Assets get a file hash appended to their and references to them are upd
| images/100px-5fd6fb90.jpg | | images/100px-5fd6fb90.jpg |
| images/100px-5fd6fb90.gif | | images/100px-5fd6fb90.gif |
| javascripts/application-1d8d5276.js | | javascripts/application-1d8d5276.js |
| stylesheets/site-50eaa978.css | | stylesheets/site-7474cadd.css |
| index.html | | index.html |
| subdir/index.html | | subdir/index.html |
| other/index.html | | other/index.html |
@ -22,15 +22,18 @@ Feature: Assets get a file hash appended to their and references to them are upd
| stylesheets/site.css | | stylesheets/site.css |
And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'" And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'"
And the file "stylesheets/site-50eaa978.css" should contain "background-image: url('../images/100px-5fd6fb90.jpg')" And the file "stylesheets/site-7474cadd.css" should contain:
"""
background-image: url("../images/100px-5fd6fb90.jpg")
"""
And the file "index.html" should contain 'href="apple-touch-icon.png"' And the file "index.html" should contain 'href="apple-touch-icon.png"'
And the file "index.html" should contain 'href="stylesheets/site-50eaa978.css"' And the file "index.html" should contain 'href="stylesheets/site-7474cadd.css"'
And the file "index.html" should contain 'src="javascripts/application-1d8d5276.js"' And the file "index.html" should contain 'src="javascripts/application-1d8d5276.js"'
And the file "index.html" should contain 'src="images/100px-5fd6fb90.jpg"' And the file "index.html" should contain 'src="images/100px-5fd6fb90.jpg"'
And the file "subdir/index.html" should contain 'href="../stylesheets/site-50eaa978.css"' And the file "subdir/index.html" should contain 'href="../stylesheets/site-7474cadd.css"'
And the file "subdir/index.html" should contain 'src="../javascripts/application-1d8d5276.js"' And the file "subdir/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
And the file "subdir/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"' And the file "subdir/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
And the file "other/index.html" should contain 'href="../stylesheets/site-50eaa978.css"' And the file "other/index.html" should contain 'href="../stylesheets/site-7474cadd.css"'
And the file "other/index.html" should contain 'src="../javascripts/application-1d8d5276.js"' And the file "other/index.html" should contain 'src="../javascripts/application-1d8d5276.js"'
And the file "other/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"' And the file "other/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"'
@ -38,32 +41,35 @@ Feature: Assets get a file hash appended to their and references to them are upd
Given the Server is running at "asset-hash-app" Given the Server is running at "asset-hash-app"
When I go to "/" When I go to "/"
Then I should see 'href="apple-touch-icon.png"' Then I should see 'href="apple-touch-icon.png"'
And I should see 'href="stylesheets/site-50eaa978.css"' And I should see 'href="stylesheets/site-7474cadd.css"'
And I should see 'src="javascripts/application-1d8d5276.js"' 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"'
When I go to "/subdir/" When I go to "/subdir/"
Then I should see 'href="../stylesheets/site-50eaa978.css"' Then I should see 'href="../stylesheets/site-7474cadd.css"'
And I should see 'src="../javascripts/application-1d8d5276.js"' 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"'
When I go to "/other/" When I go to "/other/"
Then I should see 'href="../stylesheets/site-50eaa978.css"' Then I should see 'href="../stylesheets/site-7474cadd.css"'
And I should see 'src="../javascripts/application-1d8d5276.js"' 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"'
When I go to "/javascripts/application-1d8d5276.js" When I go to "/javascripts/application-1d8d5276.js"
Then I should see "img.src = '/images/100px-5fd6fb90.jpg'" Then I should see "img.src = '/images/100px-5fd6fb90.jpg'"
When I go to "/stylesheets/site-50eaa978.css" When I go to "/stylesheets/site-7474cadd.css"
Then I should see "background-image: url('../images/100px-5fd6fb90.jpg')" Then I should see:
"""
background-image: url("../images/100px-5fd6fb90.jpg")
"""
Scenario: Enabling an asset host still produces hashed files and references Scenario: Enabling an asset host still produces hashed files and references
Given the Server is running at "asset-hash-host-app" Given the Server is running at "asset-hash-host-app"
When I go to "/" When I go to "/"
Then I should see 'href="http://middlemanapp.com/stylesheets/site-54baaf3a.css"' Then I should see 'href="http://middlemanapp.com/stylesheets/site-1fdf4fb5.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"'
When I go to "/subdir/" When I go to "/subdir/"
Then I should see 'href="http://middlemanapp.com/stylesheets/site-54baaf3a.css"' Then I should see 'href="http://middlemanapp.com/stylesheets/site-1fdf4fb5.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"'
When I go to "/other/" When I go to "/other/"
Then I should see 'href="http://middlemanapp.com/stylesheets/site-54baaf3a.css"' Then I should see 'href="http://middlemanapp.com/stylesheets/site-1fdf4fb5.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"'
# Asset helpers don't appear to work from Compass right now # Asset helpers don't appear to work from Compass right now
# When I go to "/stylesheets/site-e5a31a3e.css" # When I go to "/stylesheets/site-e5a31a3e.css"
@ -98,11 +104,11 @@ Feature: Assets get a file hash appended to their and references to them are upd
""" """
Given the Server is running at "asset-hash-app" Given the Server is running at "asset-hash-app"
When I go to "/" When I go to "/"
Then I should see 'href="stylesheets/site-5770af52.css' Then I should see 'href="stylesheets/site-ac2166fd.css'
When I go to "stylesheets/site-5770af52.css" When I go to "stylesheets/site-ac2166fd.css"
Then I should see 'background-image' Then I should see 'background-image'
Then I should see 'Added by Rack filter' Then I should see 'Added by Rack filter'
When I go to "stylesheets/site-50eaa978.css" When I go to "stylesheets/site-7474cadd.css"
Then I should see 'Not Found' Then I should see 'Not Found'
Scenario: Hashed-asset files are not produced for ignored paths Scenario: Hashed-asset files are not produced for ignored paths
@ -137,7 +143,7 @@ Feature: Assets get a file hash appended to their and references to them are upd
| images/100px-5fd6fb90.jpg | | images/100px-5fd6fb90.jpg |
| images/100px-5fd6fb90.gif | | images/100px-5fd6fb90.gif |
| javascripts/application-1d8d5276.js | | javascripts/application-1d8d5276.js |
| stylesheets/site-50eaa978.css | | stylesheets/site-7474cadd.css |
# @wip Currently broken, we should move all asset-host functionality out of Compass and into something more similar to asset_hash with Rack-based rewrites # @wip Currently broken, we should move all asset-host functionality out of Compass and into something more similar to asset_hash with Rack-based rewrites
# Scenario: Enabling an asset host and referencing assets in CSS with URL fragments are rewritten correctly # Scenario: Enabling an asset host and referencing assets in CSS with URL fragments are rewritten correctly

View file

@ -2,34 +2,6 @@ Feature: Alternate between multiple asset hosts
In order to speed up page loading In order to speed up page loading
Scenario: Set single host globally Scenario: Set single host globally
Given a fixture app "asset-host-app"
And a file named "config.rb" with:
"""
activate :asset_host
set :asset_host, "http://assets1.example.com"
"""
And the Server is running
When I go to "/asset_host.html"
Then I should see "http://assets1"
When I go to "/stylesheets/asset_host.css"
Then I should see "http://assets1"
Scenario: Set proc host globally
Given a fixture app "asset-host-app"
And a file named "config.rb" with:
"""
activate :asset_host
set :asset_host do |asset|
"http://assets%d.example.com" % (asset.hash % 4)
end
"""
And the Server is running
When I go to "/asset_host.html"
Then I should see "http://assets"
When I go to "/stylesheets/asset_host.css"
Then I should see "http://assets"
Scenario: Set single host with inline-option
Given a fixture app "asset-host-app" Given a fixture app "asset-host-app"
And a file named "config.rb" with: And a file named "config.rb" with:
""" """
@ -41,6 +13,20 @@ Feature: Alternate between multiple asset hosts
When I go to "/stylesheets/asset_host.css" When I go to "/stylesheets/asset_host.css"
Then I should see "http://assets1" Then I should see "http://assets1"
Scenario: Set single host with inline-option
Given a fixture app "asset-host-app"
And a file named "config.rb" with:
"""
activate :asset_host, host: "http://assets1.example.com"
"""
And the Server is running
When I go to "/asset_host.html"
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 "/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//}
Scenario: Set proc host with inline-option Scenario: Set proc host with inline-option
Given a fixture app "asset-host-app" Given a fixture app "asset-host-app"
And a file named "config.rb" with: And a file named "config.rb" with:
@ -51,6 +37,8 @@ Feature: Alternate between multiple asset hosts
""" """
And the Server is running And the Server is running
When I go to "/asset_host.html" When I go to "/asset_host.html"
Then I should see "http://assets" 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 "/stylesheets/asset_host.css" When I go to "/stylesheets/asset_host.css"
Then I should see "http://assets" Then I should see content matching %r{http://assets1.example.com/}
Then I should not see content matching %r{http://assets1.example.com//}

View file

@ -5,7 +5,7 @@ Feature: Generate mtime-based query string for busting browser caches
Given "cache_buster" feature is "disabled" Given "cache_buster" feature is "disabled"
And the Server is running at "cache-buster-app" And the Server is running at "cache-buster-app"
When I go to "/stylesheets/relative_assets.css" When I go to "/stylesheets/relative_assets.css"
Then I should see "blank.gif'" Then I should see 'blank.gif"'
Scenario: Rendering html with the feature disabled Scenario: Rendering html with the feature disabled
Given "cache_buster" feature is "disabled" Given "cache_buster" feature is "disabled"

View file

@ -8,7 +8,7 @@ Feature: Minify CSS
""" """
And the Server is running at "minify-css-app" And the Server is running at "minify-css-app"
When I go to "/stylesheets/site.css" When I go to "/stylesheets/site.css"
Then I should see "50" lines Then I should see "7" lines
And I should see "only screen and (device-width" And I should see "only screen and (device-width"
Scenario: Rendering external css with the feature enabled Scenario: Rendering external css with the feature enabled
@ -40,7 +40,7 @@ Feature: Minify CSS
""" """
And the Server is running at "passthrough-app" And the Server is running at "passthrough-app"
When I go to "/stylesheets/site.css" When I go to "/stylesheets/site.css"
Then I should see "46" lines Then I should see "5" lines
Scenario: Rendering inline css with the feature disabled Scenario: Rendering inline css with the feature disabled
Given a fixture app "minify-css-app" Given a fixture app "minify-css-app"

View file

@ -6,7 +6,7 @@ Feature: Relative Assets
And the Server is running at "relative-assets-app" And the Server is running at "relative-assets-app"
When I go to "/stylesheets/relative_assets.css" When I go to "/stylesheets/relative_assets.css"
Then I should not see "url('../" Then I should not see "url('../"
And I should see "/images/blank.gif')" And I should see '/images/blank.gif")'
Scenario: Building css with the feature disabled Scenario: Building css with the feature disabled
Given a fixture app "relative-assets-app" Given a fixture app "relative-assets-app"
@ -15,7 +15,7 @@ Feature: Relative Assets
""" """
Given a successfully built app at "relative-assets-app" Given a successfully built app at "relative-assets-app"
When I cd to "build" When I cd to "build"
Then the file "stylesheets/relative_assets.css" should contain "url('/images/blank.gif')" Then the file "stylesheets/relative_assets.css" should contain 'url("/images/blank.gif")'
Scenario: Rendering html with the feature disabled Scenario: Rendering html with the feature disabled
Given "relative_assets" feature is "disabled" Given "relative_assets" feature is "disabled"
@ -27,7 +27,9 @@ Feature: Relative Assets
Given "relative_assets" feature is "enabled" Given "relative_assets" feature is "enabled"
And the Server is running at "relative-assets-app" And the Server is running at "relative-assets-app"
When I go to "/stylesheets/relative_assets.css" When I go to "/stylesheets/relative_assets.css"
Then I should see "url('../images/blank.gif" Then I should see 'url("../images/blank.gif'
When I go to "/javascripts/application.js"
Then I should not see "../"
Scenario: Building css with the feature enabled Scenario: Building css with the feature enabled
Given a fixture app "relative-assets-app" Given a fixture app "relative-assets-app"
@ -37,7 +39,8 @@ Feature: Relative Assets
""" """
Given a successfully built app at "relative-assets-app" Given a successfully built app at "relative-assets-app"
When I cd to "build" When I cd to "build"
Then the file "stylesheets/relative_assets.css" should contain "url('../images/blank.gif')" Then the file "stylesheets/relative_assets.css" should contain 'url("../images/blank.gif")'
Then the file "javascripts/application.js" should not contain "../"
Scenario: Relative css reference with directory indexes Scenario: Relative css reference with directory indexes
Given a fixture app "relative-assets-app" Given a fixture app "relative-assets-app"
@ -57,48 +60,18 @@ Feature: Relative Assets
Then I should not see "/images/blank.gif" Then I should not see "/images/blank.gif"
And I should see "images/blank.gif" And I should see "images/blank.gif"
Scenario: Rendering css with a custom images_dir
Given "relative_assets" feature is "enabled"
And "images_dir" is set to "img"
And the Server is running at "relative-assets-app"
When I go to "/stylesheets/relative_assets.css"
Then I should see "url('../img/blank.gif')"
Scenario: Building css with a custom images_dir
Given a fixture app "relative-assets-app"
And a file named "config.rb" with:
"""
set :images_dir, "img"
activate :relative_assets
"""
Given a successfully built app at "relative-assets-app"
When I cd to "build"
Then the file "stylesheets/relative_assets.css" should contain "url('../img/blank.gif')"
Scenario: Rendering html with a custom images_dir
Given "relative_assets" feature is "enabled"
And "images_dir" is set to "img"
And the Server is running at "relative-assets-app"
When I go to "/relative_image.html"
Then I should not see "/images/blank.gif"
Then I should not see "/img/blank.gif"
And I should see "img/blank.gif"
Scenario: Rendering scss with the feature enabled Scenario: Rendering scss with the feature enabled
Given "relative_assets" feature is "enabled" Given "relative_assets" feature is "enabled"
And the Server is running at "fonts-app" And the Server is running at "fonts-app"
When I go to "/stylesheets/fonts.css" When I go to "/stylesheets/fonts.css"
Then I should see "url('../fonts/StMarie-Thin.otf" Then I should see:
And I should see "url('../fonts/blank/blank.otf" """
url("../fonts/StMarie-Thin.otf"
Scenario: Rendering scss with the feature enabled and a custom fonts_dir """
Given "relative_assets" feature is "enabled" And I should see:
And "fonts_dir" is set to "otf" """
And the Server is running at "fonts-app" url("../fonts/blank/blank.otf"
When I go to "/stylesheets/fonts.css" """
Then I should not see "url('../fonts/StMarie-Thin.otf"
And I should see "url('../otf/StMarie-Thin.otf"
And I should see "url('../otf/blank/blank.otf"
Scenario: Building scss with the feature enabled Scenario: Building scss with the feature enabled
Given a fixture app "fonts-app" Given a fixture app "fonts-app"
@ -108,21 +81,14 @@ Feature: Relative Assets
""" """
Given a successfully built app at "fonts-app" Given a successfully built app at "fonts-app"
When I cd to "build" When I cd to "build"
Then the file "stylesheets/fonts.css" should contain "url('../fonts/StMarie-Thin.otf')" Then the file "stylesheets/fonts.css" should contain:
And the file "stylesheets/fonts.css" should contain "url('../fonts/blank/blank.otf')"
Scenario: Building scss with the feature enabled and a custom fonts_dir
Given a fixture app "fonts-app"
And a file named "config.rb" with:
""" """
set :fonts_dir, "otf" url("../fonts/StMarie-Thin.otf")
activate :relative_assets """
And the file "stylesheets/fonts.css" should contain:
"""
url("../fonts/blank/blank.otf")
""" """
Given a successfully built app at "fonts-app"
When I cd to "build"
Then the file "stylesheets/fonts.css" should not contain "url('../fonts/StMarie-Thin.otf')"
And the file "stylesheets/fonts.css" should contain "url('../otf/StMarie-Thin.otf')"
And the file "stylesheets/fonts.css" should contain "url('../otf/blank/blank.otf')"
Scenario: Relative assets via image_tag Scenario: Relative assets via image_tag
Given a fixture app "relative-assets-app" Given a fixture app "relative-assets-app"

View file

@ -24,6 +24,8 @@ Feature: Support slim templating language
Given an empty app Given an empty app
And a file named "config.rb" with: And a file named "config.rb" with:
""" """
require 'middleman-compass'
activate :compass
""" """
And a file named "source/scss.html.slim" with: And a file named "source/scss.html.slim" with:
""" """

View file

@ -1,5 +1,6 @@
ENV["TEST"] = "true" ENV["TEST"] = "true"
ENV["AUTOLOAD_SPROCKETS"] = "false" ENV["AUTOLOAD_SPROCKETS"] ||= "false"
ENV["AUTOLOAD_COMPASS"] ||= "false"
require 'simplecov' require 'simplecov'
SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/../..')) SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/../..'))

View file

@ -1,6 +1,4 @@
activate :asset_hash activate :asset_hash
activate :directory_indexes activate :directory_indexes
activate :asset_host activate :asset_host, host: 'http://middlemanapp.com'
set :asset_host, 'http://middlemanapp.com'

View file

@ -1 +1,20 @@
<%= image_tag "blank.gif" %> <%= image_tag "blank0.gif" %>
<%= image_tag "blank1.gif" %>
<%= image_tag "blank2.gif" %>
<%= image_tag "blank3.gif" %>
<%= image_tag "blank4.gif" %>
<%= image_tag "blank10.gif" %>
<%= image_tag "blank21.gif" %>
<%= image_tag "blank32.gif" %>
<%= image_tag "blank43.gif" %>
<%= image_tag "blank54.gif" %>
<%= image_tag "blank20.gif" %>
<%= image_tag "blank21.gif" %>
<%= image_tag "blank22.gif" %>
<%= image_tag "blank23.gif" %>
<%= image_tag "blank24.gif" %>
<%= image_tag "blank30.gif" %>
<%= image_tag "blank31.gif" %>
<%= image_tag "blank32.gif" %>
<%= image_tag "blank33.gif" %>
<%= image_tag "blank34.gif" %>

View file

@ -1,3 +1,48 @@
@import "compass"
h1 h1
background: image-url("blank.gif") background: image-url("blank1.gif")
h2
background: image-url("blank2.gif")
h3
background: image-url("blank3.gif")
h4
background: image-url("blank4.gif")
h5
background: image-url("blank5.gif")
h6
background: image-url("blank6.gif")
h7
background: image-url("blank7.gif")
h8
background: image-url("blank8.gif")
h11
background: image-url("blank11.gif")
h12
background: image-url("blank21.gif")
h13
background: image-url("blank31.gif")
h14
background: image-url("blank41.gif")
h15
background: image-url("blank51.gif")
h16
background: image-url("blank61.gif")
h17
background: image-url("blank71.gif")
h18
background: image-url("blank81.gif")
h21
background: image-url("blank12.gif")
h22
background: image-url("blank22.gif")
h23
background: image-url("blank32.gif")
h24
background: image-url("blank42.gif")
h25
background: image-url("blank52.gif")
h26
background: image-url("blank62.gif")
h27
background: image-url("blank72.gif")
h28
background: image-url("blank82.gif")

View file

@ -1,3 +1,2 @@
@import "compass"
h1 h1
background: image-url("blank.gif") background: image-url("blank.gif")

View file

@ -1 +1,3 @@
@import "compass/reset" body {
background: white;
}

View file

@ -0,0 +1,6 @@
@font-face {
font-family: "St Marie";
src: url("/fonts/StMarie-Thin.otf") format('opentype'); }
@font-face {
font-family: "St Marie";
src: url("/fonts/blank/blank.otf") format('opentype'); }

View file

@ -1,4 +1,6 @@
@import "compass/reset" body
margin: 0px
padding: 0px
@media handheld, only screen and (device-width: 768px) @media handheld, only screen and (device-width: 768px)
body body

View file

@ -1 +1,5 @@
@import "compass/reset" body
padding: 0px
margin: 0
div
background: white

View file

@ -1,3 +1,2 @@
@import "compass"
h1 h1
background: image-url("blank.gif") background: url("images/blank.gif")

View file

@ -0,0 +1,8 @@
function foo() {
var img = document.createElement('img');
img.src = '/images/100px.jpg';
var body = document.getElementsByTagName('body')[0];
body.insertBefore(img, body.firstChild);
}
window.onload = foo;

View file

@ -1,3 +1,2 @@
@import "compass"
h1 h1
background: image-url("blank.gif") background: url("/images/blank.gif")

View file

@ -1 +1,3 @@
@import "compass/reset"; html, body {
width: 100%;
}

View file

@ -32,14 +32,6 @@ Middleman::Extensions.register :default_helpers, auto_activate: :before_configur
Middleman::CoreExtensions::DefaultHelpers Middleman::CoreExtensions::DefaultHelpers
end end
# Compass framework
begin
require 'middleman-core/core_extensions/compass'
Middleman::Extensions.register :compass, Middleman::CoreExtensions::Compass, auto_activate: :before_configuration
rescue LoadError
# Compass is not available, don't complain about it
end
# Lorem provides a handful of helpful prototyping methods to generate # Lorem provides a handful of helpful prototyping methods to generate
# words, paragraphs, fake images, names and email addresses. # words, paragraphs, fake images, names and email addresses.
Middleman::Extensions.register :lorem, auto_activate: :before_configuration do Middleman::Extensions.register :lorem, auto_activate: :before_configuration do

View file

@ -1,74 +0,0 @@
require 'middleman-core/renderers/sass'
require 'compass'
class Middleman::CoreExtensions::Compass < ::Middleman::Extension
def initialize(app, options_hash={}, &block)
super
# Hooks to manually update the compass config after we're
# done with it
app.define_hook :compass_config
# Location of SASS/SCSS files external to source directory.
# @return [Array]
# config[:sass_assets_paths] = ["#{root}/assets/sass/", "/path/2/external/sass/repository/"]
app.config.define_setting :sass_assets_paths, [], 'Paths to extra SASS/SCSS files'
end
def after_configuration
::Compass.configuration do |compass_config|
compass_config.project_path = app.source_dir
compass_config.environment = :development
compass_config.cache = false
compass_config.sass_dir = app.config[:css_dir]
compass_config.css_dir = app.config[:css_dir]
compass_config.javascripts_dir = app.config[:js_dir]
compass_config.fonts_dir = app.config[:fonts_dir]
compass_config.images_dir = app.config[:images_dir]
compass_config.http_path = app.config[:http_prefix]
app.config[:sass_assets_paths].each do |path|
compass_config.add_import_path path
end
# Disable this initially, the cache_buster extension will
# re-enable it if requested.
compass_config.asset_cache_buster { |_| nil }
# Disable this initially, the relative_assets extension will
compass_config.relative_assets = false
# Default output style
compass_config.output_style = :nested
# No line-comments in test mode (changing paths mess with sha1)
compass_config.line_comments = false if ENV['TEST']
end
# Call hook
app.run_hook_for :compass_config, app, ::Compass.configuration
# Tell Tilt to use it as well (for inline sass blocks)
::Tilt.register 'sass', CompassSassTemplate
::Tilt.prefer(CompassSassTemplate)
# Tell Tilt to use it as well (for inline scss blocks)
::Tilt.register 'scss', CompassScssTemplate
::Tilt.prefer(CompassScssTemplate)
end
# A Compass Sass template for Tilt, adding our options in
class CompassSassTemplate < ::Middleman::Renderers::Sass::SassPlusCSSFilenameTemplate
def sass_options
super.merge(::Compass.configuration.to_sass_engine_options)
end
end
# A Compass Scss template for Tilt, adding our options in
class CompassScssTemplate < ::Middleman::Renderers::Sass::ScssPlusCSSFilenameTemplate
def sass_options
super.merge(::Compass.configuration.to_sass_engine_options)
end
end
end

View file

@ -162,27 +162,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
# @param [Hash] options Data to pass through. # @param [Hash] options Data to pass through.
# @return [String] # @return [String]
def asset_path(kind, source, options={}) def asset_path(kind, source, options={})
return source if source.to_s.include?('//') || source.to_s.start_with?('data:') ::Middleman::Util.asset_path(app, kind, source, options)
asset_folder = case kind
when :css
config[:css_dir]
when :js
config[:js_dir]
when :images
config[:images_dir]
when :fonts
config[:fonts_dir]
else
kind.to_s
end
source = source.to_s.tr(' ', '')
ignore_extension = (kind == :images || kind == :fonts) # don't append extension
source << ".#{kind}" unless ignore_extension || source.end_with?(".#{kind}")
asset_folder = '' if source.start_with?('/') # absolute path
asset_url(source, asset_folder, options)
end end
# Get the URL of an asset given a type/prefix # Get the URL of an asset given a type/prefix
@ -190,22 +170,8 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
# @param [String] path The path (such as "photo.jpg") # @param [String] path The path (such as "photo.jpg")
# @param [String] prefix The type prefix (such as "images") # @param [String] prefix The type prefix (such as "images")
# @return [String] The fully qualified asset url # @return [String] The fully qualified asset url
def asset_url(path, prefix='', _) def asset_url(path, prefix='', options={})
# Don't touch assets which already have a full path ::Middleman::Util.asset_url(app, prefix, options)
if path.include?('//') || path.start_with?('data:')
path
else # rewrite paths to use their destination path
if resource = sitemap.find_resource_by_destination_path(url_for(path))
resource.url
else
path = File.join(prefix, path)
if resource = sitemap.find_resource_by_path(path)
resource.url
else
File.join(config[:http_prefix], path)
end
end
end
end end
# Given a source path (referenced either absolutely or relatively) # Given a source path (referenced either absolutely or relatively)

View file

@ -14,6 +14,12 @@ module Middleman
app.define_hook :build_config app.define_hook :build_config
app.define_hook :development_config app.define_hook :development_config
app.config.define_setting :autoload_sprockets, true, 'Automatically load sprockets at startup?'
app.config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS']
app.config.define_setting :autoload_compass, true, 'Automatically load compass at startup?'
app.config[:autoload_compass] = (ENV['AUTOLOAD_COMPASS'] == 'true') if ENV['AUTOLOAD_COMPASS']
app.extend ClassMethods app.extend ClassMethods
app.delegate :configure, to: :"self.class" app.delegate :configure, to: :"self.class"
end end
@ -90,7 +96,7 @@ module Middleman
activate ext_name activate ext_name
end end
if ENV['AUTOLOAD_SPROCKETS'] != 'false' if config[:autoload_sprockets]
begin begin
require 'middleman-sprockets' require 'middleman-sprockets'
activate :sprockets activate :sprockets
@ -99,6 +105,15 @@ module Middleman
end end
end end
if config[:autoload_compass]
begin
require 'middleman-compass'
activate :compass
rescue LoadError
# Compass is not available, don't complain about it
end
end
# Evaluate a passed block if given # Evaluate a passed block if given
config_context.instance_exec(&block) if block_given? config_context.instance_exec(&block) if block_given?

View file

@ -26,7 +26,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
:proc => method(:rewrite_url) :proc => method(:rewrite_url)
end end
def rewrite_url(asset_path, dirpath) def rewrite_url(asset_path, dirpath, request_path)
relative_path = Pathname.new(asset_path).relative? relative_path = Pathname.new(asset_path).relative?
full_asset_path = if relative_path full_asset_path = if relative_path

View file

@ -1,51 +1,41 @@
# Asset Host module # Asset Host module
class Middleman::Extensions::AssetHost < ::Middleman::Extension class Middleman::Extensions::AssetHost < ::Middleman::Extension
option :host, nil, 'The asset host to use, or false for no asset host, or a Proc to determine asset host' option :host, nil, 'The asset host to use or a Proc to determine asset host'
option :exts, %w(.css .png .jpg .jpeg .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 :ignore, [], 'Regexes of filenames to skip adding query strings to'
def initialize(app, options_hash={}, &block) def initialize(app, options_hash={}, &block)
super super
# Backwards compatible API require 'middleman-core/middleware/inline_url_rewriter'
app.config.define_setting :asset_host, nil, 'The asset host to use, or false for no asset host, or a Proc to determine asset host' end
app.compass_config do |config| def after_configuration
if asset_host = extensions[:asset_host].host app.use ::Middleman::Middleware::InlineURLRewriter,
if asset_host.is_a?(Proc) :id => :asset_host,
config.asset_host(&asset_host) :url_extensions => options.exts,
:source_extensions => options.sources,
:ignore => options.ignore,
:middleman_app => app,
:proc => method(:rewrite_url)
end
def rewrite_url(asset_path, dirpath, request_path)
relative_path = Pathname.new(asset_path).relative?
full_asset_path = if relative_path
dirpath.join(asset_path).to_s
else else
config.asset_host do |_| asset_path
asset_host
end
end
end
end if app.respond_to?(:compass_config)
end end
def host asset_prefix = if options[:host].is_a?(Proc)
app.config[:asset_host] || options[:host] options[:host].call(full_asset_path)
elsif options[:host].is_a?(String)
options[:host]
end end
helpers do File.join(asset_prefix, full_asset_path)
# Override default asset url helper to include asset hosts
#
# @param [String] path
# @param [String] prefix
# @param [Hash] options Data to pass through.
# @return [String]
def asset_url(path, prefix='', options={})
controller = extensions[:asset_host]
original_output = super
return original_output unless controller.host
asset_prefix = if controller.host.is_a?(Proc)
controller.host.call(original_output)
elsif controller.host.is_a?(String)
controller.host
end
File.join(asset_prefix, original_output)
end
end end
end end

View file

@ -1,56 +1,26 @@
# The Cache Buster extension # The Cache Buster extension
class Middleman::Extensions::CacheBuster < ::Middleman::Extension class Middleman::Extensions::CacheBuster < ::Middleman::Extension
option :exts, %w(.css .png .jpg .jpeg .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 :ignore, [], 'Regexes of filenames to skip adding query strings to'
def initialize(app, options_hash={}, &block) def initialize(app, options_hash={}, &block)
super super
# After compass is setup, make it use the registered cache buster require 'middleman-core/middleware/inline_url_rewriter'
app.compass_config do |config|
config.asset_cache_buster do |path, real_path|
real_path = real_path.path if real_path.is_a? File
real_path = real_path.gsub(File.join(app.root, app.config[:build_dir]), app.config[:source])
if File.readable?(real_path)
File.mtime(real_path).strftime('%s')
else
logger.warn "WARNING: '#{File.basename(path)}' was not found (or cannot be read) in #{File.dirname(real_path)}"
end
end
end if app.respond_to?(:compass_config)
end end
helpers do def after_configuration
# asset_url override if we're using cache busting app.use ::Middleman::Middleware::InlineURLRewriter,
# @param [String] path :id => :cache_buster,
# @param [String] prefix :url_extensions => options.exts,
# @param [Hash] options Data to pass through. :source_extensions => options.sources,
def asset_url(path, prefix='', options={}) :ignore => options.ignore,
http_path = super :middleman_app => app,
:proc => method(:rewrite_url)
if http_path.include?('://') || !%w(.css .png .jpg .jpeg .svg .svgz .js .gif).include?(File.extname(http_path))
http_path
else
if respond_to?(:http_images_path) && prefix == http_images_path
prefix = images_dir
end end
real_path_static = File.join(prefix, path) def rewrite_url(asset_path, dirpath, request_path)
asset_path + '?' + Time.now.strftime('%s')
if build?
real_path_dynamic = File.join(config[:build_dir], prefix, path)
real_path_dynamic = File.expand_path(real_path_dynamic, root)
http_path << '?' + File.mtime(real_path_dynamic).strftime('%s') if File.readable?(real_path_dynamic)
elsif resource = sitemap.find_resource_by_path(real_path_static)
if !resource.template?
http_path << '?' + File.mtime(resource.source_file).strftime('%s')
else
# It's a template, possible with partials. We can't really
# know when it's updated, so generate fresh cache buster every
# time during developement
http_path << '?' + Time.now.strftime('%s')
end
end
http_path
end
end
end end
end end

View file

@ -1,31 +1,37 @@
# Relative Assets extension # Relative Assets extension
class Middleman::Extensions::RelativeAssets < ::Middleman::Extension class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
option :exts, %w(.css .png .jpg .jpeg .svg .svgz .js .gif .ttf .otf .woff), 'List of extensions that get cache busters strings appended to them.'
option :sources, %w(.htm .html .css), 'List of extensions that are searched for relative assets.'
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
def initialize(app, options_hash={}, &block) def initialize(app, options_hash={}, &block)
super super
# After compass is setup, make it use the registered cache buster require 'middleman-core/middleware/inline_url_rewriter'
app.compass_config do |config|
config.relative_assets = true
end if app.respond_to?(:compass_config)
end end
helpers do def after_configuration
# asset_url override for relative assets app.use ::Middleman::Middleware::InlineURLRewriter,
# @param [String] path :id => :asset_hash,
# @param [String] prefix :url_extensions => options.exts,
# @param [Hash] options Data to pass through. :source_extensions => options.sources,
# @return [String] :ignore => options.ignore,
def asset_url(path, prefix='', options={}) :middleman_app => app,
path = super :proc => method(:rewrite_url)
end
requested_resource = options[:current_resource] || current_resource def rewrite_url(asset_path, dirpath, request_path)
relative_path = Pathname.new(asset_path).relative?
if path.include?('//') || path.start_with?('data:') || !requested_resource full_asset_path = if relative_path
path dirpath.join(asset_path).to_s
else else
current_dir = Pathname('/' + requested_resource.destination_path) asset_path
Pathname(path).relative_path_from(current_dir.dirname).to_s
end end
if !full_asset_path.include?('//') && !asset_path.start_with?('data:')
current_dir = Pathname('/' + request_path).dirname
Pathname(full_asset_path).relative_path_from(current_dir).to_s
end end
end end
end end

View file

@ -49,7 +49,7 @@ module Middleman
asset_path asset_path
end end
@ignore.none? { |r| should_ignore?(r, full_asset_path) } && @proc.call(asset_path, dirpath) @ignore.none? { |r| should_ignore?(r, full_asset_path) } && @proc.call(asset_path, dirpath, path)
end end
status, headers, response = ::Rack::Response.new( status, headers, response = ::Rack::Response.new(

View file

@ -38,8 +38,13 @@ module Middleman
class << self class << self
# Once registered # Once registered
def registered(app) def registered(app)
opts = { output_style: :nested }
opts[:line_comments] = false if ENV['TEST']
# Default sass options # Default sass options
app.config.define_setting :sass, {}, 'Sass engine options' app.config.define_setting :sass, opts, 'Sass engine options'
app.config.define_setting :sass_assets_paths, [], 'Paths to extra SASS/SCSS files'
# Tell Tilt to use it as well (for inline sass blocks) # Tell Tilt to use it as well (for inline sass blocks)
::Tilt.register 'sass', SassPlusCSSFilenameTemplate ::Tilt.register 'sass', SassPlusCSSFilenameTemplate
@ -50,6 +55,8 @@ module Middleman
::Tilt.prefer(ScssPlusCSSFilenameTemplate) ::Tilt.prefer(ScssPlusCSSFilenameTemplate)
::Compass::ImportOnce.activate! ::Compass::ImportOnce.activate!
require 'middleman-core/renderers/sass_functions'
end end
alias_method :included, :registered alias_method :included, :registered
@ -88,14 +95,22 @@ module Middleman
# Change Sass path, for url functions, to the build folder if we're building # Change Sass path, for url functions, to the build folder if we're building
# @return [Hash] # @return [Hash]
def sass_options def sass_options
more_opts = { filename: eval_file, line: line, syntax: syntax } ctx = ::Middleman::Renderers::Haml.last_haml_scope || @context
if @context.is_a?(::Middleman::TemplateContext) && file more_opts = {
location_of_sass_file = @context.source_dir load_paths: ctx.config[:sass_assets_paths],
filename: eval_file,
line: line,
syntax: syntax,
custom: { middleman_context: ctx.app }
}
if ctx.is_a?(::Middleman::TemplateContext) && file
location_of_sass_file = ctx.source_dir
parts = basename.split('.') parts = basename.split('.')
parts.pop parts.pop
more_opts[:css_filename] = File.join(location_of_sass_file, @context.config[:css_dir], parts.join('.')) more_opts[:css_filename] = File.join(location_of_sass_file, ctx.config[:css_dir], parts.join('.'))
end end
options.merge(more_opts) options.merge(more_opts)

View file

@ -0,0 +1,117 @@
module Sprockets
module Sass
module Functions
# Using Middleman::Util#asset_path, return the full path
# for the given +source+ as a Sass String. This supports keyword
# arguments that mirror the +options+.
#
# === Examples
#
# background: url(image-path("image.jpg")); // background: url("/assets/image.jpg");
# background: url(image-path("image.jpg", $digest: true)); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
#
def image_path(source, options = {})
p = ::Middleman::Util.asset_path(middleman_context, :images, source.value, map_options(options))
::Sass::Script::String.new p.to_s, :string
end
# Using Middleman::Util#asset_path, return the url CSS
# for the given +source+ as a Sass String. This supports keyword
# arguments that mirror the +options+.
#
# === Examples
#
# background: image-url("image.jpg"); // background: url("/assets/image.jpg");
# background: image-url("image.jpg", $digest: true); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
#
def image_url(source, options = {}, cache_buster = nil)
# Work with the Compass #image_url API
if options.respond_to? :value
case options.value
when true
return image_path source
else
options = {}
end
end
::Sass::Script::String.new "url(#{image_path(source, options)})"
end
# Using Middleman::Util#asset_path, return the full path
# for the given +source+ as a Sass String. This supports keyword
# arguments that mirror the +options+.
#
# === Examples
#
# src: url(font-path("font.ttf")); // src: url("/assets/font.ttf");
# src: url(font-path("font.ttf", $digest: true)); // src: url("/assets/font-27a8f1f96afd8d4c67a59eb9447f45bd.ttf");
#
def font_path(source, options = {})
p = ::Middleman::Util.asset_path(middleman_context, :fonts, source.value, map_options(options))
::Sass::Script::String.new p.to_s, :string
end
# Using Middleman::Util#asset_path, return the url CSS
# for the given +source+ as a Sass String. This supports keyword
# arguments that mirror the +options+.
#
# === Examples
#
# src: font-url("font.ttf"); // src: url("/assets/font.ttf");
# src: font-url("image.jpg", $digest: true); // src: url("/assets/font-27a8f1f96afd8d4c67a59eb9447f45bd.ttf");
#
def font_url(source, options = {})
# Work with the Compass #font_url API
if options.respond_to? :value
case options.value
when true
return font_path source
else
options = {}
end
end
::Sass::Script::String.new "url(#{font_path(source, options)})"
end
protected
# Returns a reference to Middleman's context through
# the importer.
def middleman_context # :nodoc:
options[:custom][:middleman_context]
end
# Returns an options hash where the keys are symbolized
# and the values are unwrapped Sass literals.
def map_options(options = {}) # :nodoc:
::Sass::Util.map_hash(options) do |key, value|
[key.to_sym, value.respond_to?(:value) ? value.value : value]
end
end
end
end
end
module Sass::Script::Functions
include Sprockets::Sass::Functions
# Hack to ensure previous API declarations (by Compass or whatever)
# don't take precedence.
[:asset_path, :asset_url, :image_path, :image_url, :font_path, :font_url, :asset_data_uri].each do |method|
defined?(@signatures) && @signatures.delete(method)
end
declare :asset_path, [:source], :var_kwargs => true
declare :asset_path, [:source, :kind]
declare :asset_url, [:source], :var_kwargs => true
declare :asset_url, [:source, :kind]
declare :image_path, [:source], :var_kwargs => true
declare :image_url, [:source], :var_kwargs => true
declare :image_url, [:source, :only_path]
declare :image_url, [:source, :only_path, :cache_buster]
declare :font_path, [:source], :var_kwargs => true
declare :font_url, [:source], :var_kwargs => true
declare :font_url, [:source, :only_path]
declare :asset_data_uri, [:source]
end

View file

@ -33,7 +33,7 @@ module Middleman
app.after_configuration do app.after_configuration do
context_hack = { context_hack = {
context: self context: self.template_context_class.new(self)
} }
::Slim::Embedded::SassEngine.disable_option_validator! ::Slim::Embedded::SassEngine.disable_option_validator!

View file

@ -97,6 +97,14 @@ Then /^I should not see "([^\"]*)"$/ do |expected|
@last_response.body.should_not include(expected) @last_response.body.should_not include(expected)
end end
Then /^I should see content matching %r{(.*)}$/ do |expected|
@last_response.body.should match(expected)
end
Then /^I should not see content matching %r{(.*)}$/ do |expected|
@last_response.body.should_not match(expected)
end
Then /^I should see "([^\"]*)" lines$/ do |lines| Then /^I should see "([^\"]*)" lines$/ do |lines|
@last_response.body.chomp.split($/).length.should == lines.to_i @last_response.body.chomp.split($/).length.should == lines.to_i
end end

View file

@ -37,6 +37,7 @@ module Middleman
# Sandboxed class for template eval # Sandboxed class for template eval
context = @app.template_context_class.new(@app, locs, opts) context = @app.template_context_class.new(@app, locs, opts)
# TODO: Only for HAML files
context.init_haml_helpers if context.respond_to?(:init_haml_helpers) context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
# Keep rendering template until we've used up all extensions. This # Keep rendering template until we've used up all extensions. This

View file

@ -135,6 +135,55 @@ module Middleman
end end
end end
# Get the path of a file of a given type
#
# @param [Symbol] kind The type of file
# @param [String] source The path to the file
# @param [Hash] options Data to pass through.
# @return [String]
def asset_path(app, kind, source, options={})
return source if source.to_s.include?('//') || source.to_s.start_with?('data:')
asset_folder = case kind
when :css then app.config[:css_dir]
when :js then app.config[:js_dir]
when :images then app.config[:images_dir]
when :fonts then app.config[:fonts_dir]
else kind.to_s
end
source = source.to_s.tr(' ', '')
ignore_extension = (kind == :images || kind == :fonts) # don't append extension
source << ".#{kind}" unless ignore_extension || source.end_with?(".#{kind}")
asset_folder = '' if source.start_with?('/') # absolute path
asset_url(app, source, asset_folder, options)
end
# Get the URL of an asset given a type/prefix
#
# @param [String] path The path (such as "photo.jpg")
# @param [String] prefix The type prefix (such as "images")
# @param [Hash] options Data to pass through.
# @return [String] The fully qualified asset url
def asset_url(app, path, prefix='', options={})
# Don't touch assets which already have a full path
if path.include?('//') or path.start_with?('data:')
path
else # rewrite paths to use their destination path
if resource = app.sitemap.find_resource_by_destination_path(url_for(app, path))
resource.url
else
path = File.join(prefix, path)
if resource = app.sitemap.find_resource_by_path(path)
resource.url
else
File.join(app.config[:http_prefix], path)
end
end
end
end
# Given a source path (referenced either absolutely or relatively) # Given a source path (referenced either absolutely or relatively)
# or a Resource, this will produce the nice URL configured for that # or a Resource, this will produce the nice URL configured for that
# path, respecting :relative_links, directory indexes, etc. # path, respecting :relative_links, directory indexes, etc.

View file

@ -37,4 +37,14 @@ Gem::Specification.new do |s|
# Automatic Image Sizes # Automatic Image Sizes
s.add_dependency('fastimage', ['~> 1.6.2']) s.add_dependency('fastimage', ['~> 1.6.2'])
# Minify CSS
s.add_dependency('sass', ['>= 3.3.4'])
# Work around Sass performance
s.add_dependency('compass-import-once', ['~> 1.0.4'])
# Minify JS
s.add_dependency('uglifier', ['~> 2.5'])
s.add_dependency('execjs', ['~> 2.0'])
end end

View file

@ -21,12 +21,8 @@ Gem::Specification.new do |s|
s.add_dependency('middleman-core', Middleman::VERSION) s.add_dependency('middleman-core', Middleman::VERSION)
s.add_dependency('middleman-cli', Middleman::VERSION) s.add_dependency('middleman-cli', Middleman::VERSION)
s.add_dependency('middleman-sprockets', '>= 3.1.2') s.add_dependency('middleman-sprockets', '>= 3.1.2')
s.add_dependency('middleman-compass', '~> 4.0.0')
s.add_dependency('haml', ['>= 4.0.5']) s.add_dependency('haml', ['>= 4.0.5'])
s.add_dependency('sass', ['>= 3.3.4'])
s.add_dependency("compass-import-once", ["1.0.4"])
s.add_dependency('compass', ['>= 1.0.0.alpha.19'])
s.add_dependency('uglifier', ['~> 2.5'])
s.add_dependency('coffee-script', ['~> 2.2.0']) s.add_dependency('coffee-script', ['~> 2.2.0'])
s.add_dependency('execjs', ['~> 2.0'])
s.add_dependency('kramdown', ['~> 1.2']) s.add_dependency('kramdown', ['~> 1.2'])
end end