From a89d61ce2100c7dcafffa10a6dded17751b680dc Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 5 Dec 2010 17:50:25 -0800 Subject: [PATCH] Generated sprite filename is now unique based on inputs. --- .../content/help/tutorials/spriting.markdown | 4 +- .../sass_extensions/functions/sprites.rb | 26 +++++++- spec/sprites_spec.rb | 66 ++++++++++--------- test/fixtures/stylesheets/compass/css/pie.css | 1 + 4 files changed, 61 insertions(+), 36 deletions(-) diff --git a/doc-src/content/help/tutorials/spriting.markdown b/doc-src/content/help/tutorials/spriting.markdown index 448aff9e..90ec7e42 100644 --- a/doc-src/content/help/tutorials/spriting.markdown +++ b/doc-src/content/help/tutorials/spriting.markdown @@ -34,7 +34,7 @@ And you'll get the following CSS output: .icon-delete, .icon-edit, .icon-new, - .icon-save { background: url('/images/icon.png?1291584143') no-repeat; } + .icon-save { background: url('/images/icon-34fe0604ab.png') no-repeat; } .icon-delete { background-position: 0 0; } .icon-edit { background-position: 0 -32px; } @@ -73,7 +73,7 @@ And your stylesheet will compile to: .actions .new, .actions .edit, .actions .save, - .actions .delete { background: url('/images/icon.png?1291584143') no-repeat; } + .actions .delete { background: url('/images/icon-34fe0604ab.png') no-repeat; } .actions .new { background-position: 0 -64px; } .actions .edit { background-position: 0 -32px; } diff --git a/lib/compass/sass_extensions/functions/sprites.rb b/lib/compass/sass_extensions/functions/sprites.rb index afd7bff9..adc18765 100644 --- a/lib/compass/sass_extensions/functions/sprites.rb +++ b/lib/compass/sass_extensions/functions/sprites.rb @@ -1,3 +1,4 @@ +require 'md5' module Compass::SassExtensions::Functions::Sprites ZERO = Sass::Script::Number::new(0) @@ -12,6 +13,10 @@ module Compass::SassExtensions::Functions::Sprites class SpriteMap < Sass::Script::Literal + # Changing this string will invalidate all previously generated sprite images. + # We should do so only when the packing algorithm changes + SPRITE_VERSION = "1" + attr_accessor :image_names, :path, :name, :options attr_accessor :images, :width, :height @@ -63,7 +68,8 @@ module Compass::SassExtensions::Functions::Sprites :width => width, :repeat => repeat_for(sprite_name), :spacing => spacing_for(sprite_name), - :position => position_for(sprite_name) + :position => position_for(sprite_name), + :digest => MD5.file(file).hexdigest } end @images.each_with_index do |image, index| @@ -151,7 +157,21 @@ module Compass::SassExtensions::Functions::Sprites # The on-the-disk filename of the sprite def filename - File.join(Compass.configuration.images_path, "#{path}.png") + File.join(Compass.configuration.images_path, "#{path}-#{uniqueness_hash}.png") + end + + def uniqueness_hash + @uniqueness_hash ||= begin + sum = MD5.md5(SPRITE_VERSION) + sum << path + images.each do |image| + [:relative_file, :height, :width, :repeat, :spacing, :position, :digest].each do |attr| + sum << image[attr].to_s + end + end + sum.hexdigest[0...10] + end + @uniqueness_hash end # saves the sprite for later retrieval @@ -268,7 +288,7 @@ module Compass::SassExtensions::Functions::Sprites missing_sprite!("sprite-url") end map.generate - image_url(Sass::Script::String.new("#{map.path}.png")) + image_url(Sass::Script::String.new("#{map.path}-#{map.uniqueness_hash}.png")) end Sass::Script::Functions.declare :sprite_url, [:map] diff --git a/spec/sprites_spec.rb b/spec/sprites_spec.rb index c86d3d45..b4f90337 100644 --- a/spec/sprites_spec.rb +++ b/spec/sprites_spec.rb @@ -16,13 +16,17 @@ describe Compass::Sprites do FileUtils.rm_r @images_tmp_path end + def map_location(file) + Dir.glob(File.join(@images_tmp_path, file)).first + end + def image_size(file) - IO.read(File.join(@images_tmp_path, file))[0x10..0x18].unpack('NN') + IO.read(map_location(file))[0x10..0x18].unpack('NN') end def image_md5(file) md5 = Digest::MD5.new - md5.update IO.read(File.join(@images_tmp_path, file)) + md5.update IO.read(map_location(file)) md5.hexdigest end @@ -46,7 +50,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-161c60ad78.png') no-repeat; } .squares-ten-by-ten { @@ -57,8 +61,8 @@ describe Compass::Sprites do background-position: 0 -10px; } CSS - image_size('squares.png').should == [20, 30] - image_md5('squares.png').should == 'e8cd71d546aae6951ea44cb01af35820' + image_size('squares-*.png').should == [20, 30] + image_md5('squares-*.png').should == 'e8cd71d546aae6951ea44cb01af35820' end it "should generate sprite classes with dimensions" do @@ -69,7 +73,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-161c60ad78.png') no-repeat; } .squares-ten-by-ten { @@ -84,7 +88,7 @@ describe Compass::Sprites do width: 20px; } CSS - image_size('squares.png').should == [20, 30] + image_size('squares-*.png').should == [20, 30] end it "should provide sprite mixin" do @@ -101,7 +105,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .cubicle, .large-cube { - background: url('/squares.png') no-repeat; + background: url('/squares-161c60ad78.png') no-repeat; } .cubicle { @@ -114,7 +118,7 @@ describe Compass::Sprites do width: 20px; } CSS - image_size('squares.png').should == [20, 30] + image_size('squares-*.png').should == [20, 30] end # CUSTOMIZATIONS: @@ -126,10 +130,10 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .circles { - background: url('/squares.png') no-repeat; + background: url('/squares-161c60ad78.png') no-repeat; } CSS - image_size('squares.png').should == [20, 30] + image_size('squares-*.png').should == [20, 30] end it "should calculate the spacing between images but not before first image" do @@ -140,7 +144,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-89450808af.png') no-repeat; } .squares-ten-by-ten { @@ -151,7 +155,7 @@ describe Compass::Sprites do background-position: 0 -43px; } CSS - image_size('squares.png').should == [20, 63] + image_size('squares-*.png').should == [20, 63] end it "should calculate the spacing between images" do @@ -162,7 +166,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-673837183a.png') no-repeat; } .squares-ten-by-ten { @@ -173,7 +177,7 @@ describe Compass::Sprites do background-position: 0 -43px; } CSS - image_size('squares.png').should == [20, 63] + image_size('squares-*.png').should == [20, 63] end it "should calculate the maximum spacing between images" do @@ -185,7 +189,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-1cd84c9068.png') no-repeat; } .squares-ten-by-ten { @@ -196,7 +200,7 @@ describe Compass::Sprites do background-position: 0 -54px; } CSS - image_size('squares.png').should == [20, 74] + image_size('squares-*.png').should == [20, 74] end it "should calculate the maximum spacing between images in reversed order" do @@ -208,7 +212,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-f25b7090ca.png') no-repeat; } .squares-ten-by-ten { @@ -219,7 +223,7 @@ describe Compass::Sprites do background-position: 0 -54px; } CSS - image_size('squares.png').should == [20, 74] + image_size('squares-*.png').should == [20, 74] end it "should calculate the default spacing between images" do @@ -230,7 +234,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-d66bf24bab.png') no-repeat; } .squares-ten-by-ten { @@ -241,7 +245,7 @@ describe Compass::Sprites do background-position: 0 -32px; } CSS - image_size('squares.png').should == [20, 52] + image_size('squares-*.png').should == [20, 52] end it "should use position adjustments in functions" do @@ -265,7 +269,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite { - background: url('/squares.png') no-repeat; + background: url('/squares-8e490168dd.png') no-repeat; } .adjusted-percentage { @@ -280,8 +284,8 @@ describe Compass::Sprites do background-position: -3px -8px; } CSS - image_size('squares.png').should == [20, 30] - image_md5('squares.png').should == 'b61700e6d402d9df5f3820b73479f371' + image_size('squares-*.png').should == [20, 30] + image_md5('squares-*.png').should == 'b61700e6d402d9df5f3820b73479f371' end it "should use position adjustments in mixins" do @@ -303,7 +307,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .adjusted-percentage, .adjusted-px-1, .adjusted-px-2 { - background: url('/squares.png') no-repeat; + background: url('/squares-8e490168dd.png') no-repeat; } .adjusted-percentage { @@ -318,8 +322,8 @@ describe Compass::Sprites do background-position: -3px -8px; } CSS - image_size('squares.png').should == [20, 30] - image_md5('squares.png').should == 'b61700e6d402d9df5f3820b73479f371' + image_size('squares-*.png').should == [20, 30] + image_md5('squares-*.png').should == 'b61700e6d402d9df5f3820b73479f371' end it "should repeat the image" do @@ -330,7 +334,7 @@ describe Compass::Sprites do SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { - background: url('/squares.png') no-repeat; + background: url('/squares-a5550fd132.png') no-repeat; } .squares-ten-by-ten { @@ -341,8 +345,8 @@ describe Compass::Sprites do background-position: 0 -10px; } CSS - image_size('squares.png').should == [20, 30] - image_md5('squares.png').should == '0187306f3858136feee87d3017e7f307' + image_size('squares-*.png').should == [20, 30] + image_md5('squares-*.png').should == '0187306f3858136feee87d3017e7f307' end it "should provide a nice errors for lemonade's old users" do @@ -382,7 +386,7 @@ describe Compass::Sprites do SCSS actual_css.should == <<-CSS .squares { - background: url('/squares.png') 0 -10px no-repeat; + background: url('/squares-145869726f.png') 0 -10px no-repeat; } CSS end diff --git a/test/fixtures/stylesheets/compass/css/pie.css b/test/fixtures/stylesheets/compass/css/pie.css index c911df07..d7898353 100644 --- a/test/fixtures/stylesheets/compass/css/pie.css +++ b/test/fixtures/stylesheets/compass/css/pie.css @@ -1,3 +1,4 @@ +@charset "UTF-8"; .pie-element, .bordered, .gradient { behavior: url('/tmp/PIE.htc'); position: relative; }