Add support for a separate output location for generated images. This is necessary for rails 3.1 support of sprites.

This commit is contained in:
Chris Eppstein 2011-08-20 17:22:50 -07:00
parent 8a407a6df7
commit f23bf58e8d
10 changed files with 167 additions and 13 deletions

View File

@ -14,14 +14,22 @@ The Documentation for the [latest stable release](http://compass-style.org/docs/
The Documentation for the [latest preview release](http://beta.compass-style.org/) The Documentation for the [latest preview release](http://beta.compass-style.org/)
0.12.0 pending 0.12.0 (UNRELEASED)
------------------- -------------------
* Added support for diagonal, horizontal, and smart sprite layout * Added support for diagonal, horizontal, and smart sprite layout
* Fixed a bug with spacing in horizontal layout * Fixed a bug with spacing in horizontal layout
* Changed the descriptions of the sin, cos, and tan to be more descriptive * Changed the descriptions of the sin, cos, and tan to be more descriptive
* Fixed trig functions via issue #498 * Fixed trig functions via issue #498
* Fixed the default `http_path` in rails * Fixed the default `http_path` in rails
* Sprites can now have a `sprite_seach_path` that is an array of directories that contain source images for sprites handy for using sprites in extensions of gems * Sprites can now have a `sprite_seach_path` that is an array of directories that
contain source images for sprites handy for using sprites in extensions of gems
* Added a new set of configuration properties for generated images.
`generated_images_dir`, `generated_images_path`, `http_generated_images_dir`,
and `http_generated_images_path` can now be set to control where generated
images are written and how they are served. Added a corresponding
`generated-image-url()` helper function. These should rarely be needed and
will default to your corresponding image directories and paths.
0.11.5 (07/10/2011) 0.11.5 (07/10/2011)
------------------- -------------------

View File

@ -170,11 +170,33 @@ later on.
</tr> </tr>
<tr> <tr>
<td style="vertical-align:top;"><code>http_images_path</code> </td> <td style="vertical-align:top;"><code>http_images_path</code> </td>
<td style="vertical-align:top;">String </td> <td style="vertical-align:top;">String</td>
<td style="vertical-align:top;">The full http path to images on the web server. <td style="vertical-align:top;">The full http path to images on the web server.
Defaults to <code>http_path + "/" + images_dir</code>. Defaults to <code>http_path + "/" + images_dir</code>.
</td> </td>
</tr> </tr>
<tr>
<td style="vertical-align:top;"><code>generated_images_dir</code> </td>
<td style="vertical-align:top;">String</td>
<td style="vertical-align:top;">The directory where generated images are kept.
It is relative to the <code>project_path</code>.
Defaults to the value of <code>images_dir</code>.
</td>
</tr>
<tr>
<td style="vertical-align:top;"><code>generated_images_path</code> </td>
<td style="vertical-align:top;">String</td>
<td style="vertical-align:top;">The full path to where generated images are kept.
Defaults to the value of <code>&lt;project_path&gt;/&lt;generated_images_dir&gt;</code>.
</td>
</tr>
<tr>
<td style="vertical-align:top;"><code>http_generated_images_path</code> </td>
<td style="vertical-align:top;">String</td>
<td style="vertical-align:top;">The full http path to generated images on
the web server. Defaults to <code>http_path + "/" + generated_images_dir</code>.
</td>
</tr>
<tr> <tr>
<td style="vertical-align:top;"><code>javascripts_dir</code> </td> <td style="vertical-align:top;"><code>javascripts_dir</code> </td>
<td style="vertical-align:top;">String </td> <td style="vertical-align:top;">String </td>

View File

@ -12,6 +12,7 @@ documented_functions:
- "stylesheet-url" - "stylesheet-url"
- "font-url" - "font-url"
- "image-url" - "image-url"
- "generated-image-url"
--- ---
%h1 Compass URL Helpers %h1 Compass URL Helpers
@ -31,7 +32,7 @@ documented_functions:
Generates a path to an asset found relative to the project's css directory. Generates a path to an asset found relative to the project's css directory.
%br %br
Passing a true value as the second argument will cause the only the path to be returned Passing a true value as the second argument will cause the only the path to be returned
instead of a `url()` function instead of a <code>url()</code> function
#font-url.helper #font-url.helper
%h3 %h3
@ -42,7 +43,7 @@ documented_functions:
Generates a path to an asset found relative to the project's font directory. Generates a path to an asset found relative to the project's font directory.
%br %br
Passing a true value as the second argument will cause the only the path to be returned Passing a true value as the second argument will cause the only the path to be returned
instead of a `url()` function instead of a <code>url()</code> function
#image-url.helper #image-url.helper
%h3 %h3
@ -53,9 +54,27 @@ documented_functions:
Generates a path to an asset found relative to the project's images directory. Generates a path to an asset found relative to the project's images directory.
%p %p
Passing a true value as the second argument will cause the only the path to be returned Passing a true value as the second argument will cause the only the path to be returned
instead of a `url()` function instead of a <code>url()</code> function
%p %p
The third argument is used to control the cache buster on a per-use basis. The third argument is used to control the cache buster on a per-use basis.
When set to `false` no cache buster will be used. When a string, that When set to <code>false</code> no cache buster will be used. When a string, that
value will be used as the cache buster. value will be used as the cache buster.
#generated-image-url.helper
%h3
%a(href="#generated-image-url")
generated-image-url($path, $cache-buster: false)
.details
%p
Generates a path to an image generated during compilation using the
<code>generated_image</code> related configuration properties.
%p
Most users will never call this helper directly, it is primarily provided
for use by plugins that need to generate paths to images they create. E.g.
The <code>sprite-url()</code> helper calls this helper.
%p
The second argument is used to control the cache buster on a per-use basis.
Defaults to <code>false</code>, meaning that no cache buster will be used.
When a string, that value will be used as the cache buster, when <code>true</code>
Compass will generate a cache-buster based on the image's modification time.

View File

@ -30,7 +30,7 @@ module Compass
def perform def perform
compiler = new_compiler_instance compiler = new_compiler_instance
compiler.clean! compiler.clean!
Compass::SpriteImporter.find_all_sprite_map_files(Compass.configuration.images_path).each do |sprite| Compass::SpriteImporter.find_all_sprite_map_files(Compass.configuration.generated_images_path).each do |sprite|
remove sprite remove sprite
end end
end end

View File

@ -20,6 +20,7 @@ module Compass
attributes_for_directory(:css, :stylesheets), attributes_for_directory(:css, :stylesheets),
attributes_for_directory(:sass, nil), attributes_for_directory(:sass, nil),
attributes_for_directory(:images), attributes_for_directory(:images),
attributes_for_directory(:generated_images),
attributes_for_directory(:javascripts), attributes_for_directory(:javascripts),
attributes_for_directory(:fonts), attributes_for_directory(:fonts),
attributes_for_directory(:extensions, nil), attributes_for_directory(:extensions, nil),

View File

@ -60,6 +60,14 @@ module Compass
end end
end end
def default_generated_images_path
if (pp = top_level.project_path) && (dir = top_level.generated_images_dir)
Compass.projectize(dir, pp)
else
top_level.images_path
end
end
def default_javascripts_path def default_javascripts_path
if (pp = top_level.project_path) && (dir = top_level.javascripts_dir) if (pp = top_level.project_path) && (dir = top_level.javascripts_dir)
Compass.projectize(dir, pp) Compass.projectize(dir, pp)
@ -84,6 +92,13 @@ module Compass
end end
end end
def default_generated_images_dir
top_level.images_dir
end
def default_http_generated_images_dir
top_level.http_images_dir
end
def default_http_images_dir def default_http_images_dir
top_level.images_dir top_level.images_dir
@ -105,6 +120,10 @@ module Compass
http_root_relative top_level.http_stylesheets_dir http_root_relative top_level.http_stylesheets_dir
end end
def default_http_generated_images_path
http_root_relative top_level.http_generated_images_dir
end
def default_http_fonts_dir def default_http_fonts_dir
if fd = top_level.fonts_dir_without_default if fd = top_level.fonts_dir_without_default
fd fd

View File

@ -96,9 +96,7 @@ module Compass::SassExtensions::Functions::Sprites
def sprite_url(map) def sprite_url(map)
verify_map(map, "sprite-url") verify_map(map, "sprite-url")
map.generate map.generate
image_url(Sass::Script::String.new("#{map.path}-s#{map.uniqueness_hash}.png"), generated_image_url(Sass::Script::String.new("#{map.path}-s#{map.uniqueness_hash}.png"))
Sass::Script::Bool.new(false),
Sass::Script::Bool.new(false))
end end
Sass::Script::Functions.declare :sprite_url, [:map] Sass::Script::Functions.declare :sprite_url, [:map]

View File

@ -2,7 +2,7 @@ module Compass::SassExtensions::Functions::Urls
def stylesheet_url(path, only_path = Sass::Script::Bool.new(false)) def stylesheet_url(path, only_path = Sass::Script::Bool.new(false))
# Compute the path to the stylesheet, either root relative or stylesheet relative # Compute the path to the stylesheet, either root relative or stylesheet relative
# or nil if the http_images_path is not set in the configuration. # or nil if the http_stylesheets_path is not set in the configuration.
http_stylesheets_path = if relative? http_stylesheets_path = if relative?
compute_relative_path(Compass.configuration.css_path) compute_relative_path(Compass.configuration.css_path)
elsif Compass.configuration.http_stylesheets_path elsif Compass.configuration.http_stylesheets_path
@ -108,6 +108,61 @@ module Compass::SassExtensions::Functions::Urls
Sass::Script::Functions.declare :image_url, [:path, :only_path] Sass::Script::Functions.declare :image_url, [:path, :only_path]
Sass::Script::Functions.declare :image_url, [:path, :only_path, :cache_buster] Sass::Script::Functions.declare :image_url, [:path, :only_path, :cache_buster]
def generated_image_url(path, cache_buster = Sass::Script::Bool.new(false))
path = path.value # get to the string value of the literal.
if path =~ %r{^#{Regexp.escape(Compass.configuration.http_generated_images_path)}/(.*)}
# Treat root relative urls (without a protocol) like normal if they start with
# the generated_images path.
path = $1
elsif absolute_path?(path)
# Short curcuit if they have provided an absolute url.
return Sass::Script::String.new("url(#{path})")
end
# Compute the path to the image, either root relative or stylesheet relative
# or nil if the http_generated_images_path is not set in the configuration.
http_generated_images_path = if relative?
compute_relative_path(Compass.configuration.generated_images_path)
elsif Compass.configuration.http_generated_images_path
Compass.configuration.http_generated_images_path
else
Compass.configuration.http_root_relative(Compass.configuration.generated_images_dir)
end
# Compute the real path to the image on the file stystem if the generated_images_dir is set.
real_path = if Compass.configuration.generated_images_dir
File.join(Compass.configuration.project_path, Compass.configuration.generated_images_dir, path)
end
# prepend the path to the image if there's one
if http_generated_images_path
http_generated_images_path = "#{http_generated_images_path}/" unless http_generated_images_path[-1..-1] == "/"
path = "#{http_generated_images_path}#{path}"
end
# Compute the asset host unless in relative mode.
asset_host = if !relative? && Compass.configuration.asset_host
Compass.configuration.asset_host.call(path)
end
# Compute and append the cache buster if there is one.
if cache_buster.to_bool
if cache_buster.is_a?(Sass::Script::String)
path += "?#{cache_buster.value}"
else
path = cache_busted_path(path, real_path)
end
end
# prepend the asset host if there is one.
path = "#{asset_host}#{'/' unless path[0..0] == "/"}#{path}" if asset_host
clean_url(path)
end
Sass::Script::Functions.declare :generated_image_url, [:path]
Sass::Script::Functions.declare :generated_image_url, [:path, :cache_buster]
private private
# Emits a path, taking off any leading "./" # Emits a path, taking off any leading "./"

View File

@ -43,7 +43,7 @@ module Compass
# The on-the-disk filename of the sprite # The on-the-disk filename of the sprite
def filename def filename
File.join(Compass.configuration.images_path, "#{path}-s#{uniqueness_hash}.png") File.join(Compass.configuration.generated_images_path, "#{path}-s#{uniqueness_hash}.png")
end end
# Generate a sprite image if necessary # Generate a sprite image if necessary
@ -87,6 +87,7 @@ module Compass
# Saves the sprite engine # Saves the sprite engine
def save! def save!
FileUtils.mkdir_p(File.dirname(filename))
saved = engine.save(filename) saved = engine.save(filename)
Compass.configuration.run_callback(:sprite_saved, filename) Compass.configuration.run_callback(:sprite_saved, filename)
saved saved

View File

@ -11,6 +11,7 @@ class SpritesTest < Test::Unit::TestCase
Compass.reset_configuration! Compass.reset_configuration!
@images_src_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images') @images_src_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images')
@images_tmp_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images-tmp') @images_tmp_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images-tmp')
@generated_images_tmp_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'generated-images-tmp')
::FileUtils.cp_r @images_src_path, @images_tmp_path ::FileUtils.cp_r @images_src_path, @images_tmp_path
file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n") file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n")
Compass.add_configuration(file, "sprite_config") Compass.add_configuration(file, "sprite_config")
@ -20,6 +21,7 @@ class SpritesTest < Test::Unit::TestCase
def teardown def teardown
Compass.reset_configuration! Compass.reset_configuration!
::FileUtils.rm_r @images_tmp_path ::FileUtils.rm_r @images_tmp_path
::FileUtils.rm_rf @generated_images_tmp_path
end end
@ -74,6 +76,35 @@ class SpritesTest < Test::Unit::TestCase
assert_equal image_md5('squares-s*.png'), '7349a0f4e88ea80abddcf6ac2486abe3' assert_equal image_md5('squares-s*.png'), '7349a0f4e88ea80abddcf6ac2486abe3'
end end
it "should output and serve sprite files using the generated images directory" do
Compass.reset_configuration!
file = StringIO.new(<<-CONFIG)
images_path = #{@images_tmp_path.inspect}
generated_images_path = #{@generated_images_tmp_path.inspect}
http_generated_images_path = "/images/generated"
CONFIG
Compass.add_configuration(file, "sprite_config")
Compass.configure_sass_plugin!
css = render <<-SCSS
@import "squares/*.png";
@include all-squares-sprites;
SCSS
assert_not_nil Dir.glob("#{@generated_images_tmp_path}/squares-s*.png").first
assert_correct <<-CSS, css
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
background: url('/images/generated/squares-s161c60ad78.png') no-repeat;
}
.squares-ten-by-ten {
background-position: 0 0;
}
.squares-twenty-by-twenty {
background-position: 0 -10px;
}
CSS
end
it "should generate sprite classes with dimensions" do it "should generate sprite classes with dimensions" do
css = render <<-SCSS css = render <<-SCSS
$squares-sprite-dimensions: true; $squares-sprite-dimensions: true;