Merge branch 'master' into rails31

* master: (23 commits)
  updated change log
  fixed horizontal height and width calculation
  horizontal layout now respects positions and spacing correctly
  Changed the descriptions of the sin, cos, and tan to be more descriptive.
  derp double require
  smart pack docs - forgot something
  smart pack docs
  smart packing implimentation thanks @johnbintz
  tests for smart packing
  smart packing helper classes
  new tests
  docs for diagonal layout
  layout for diagonal sprite
  added test for diagonal layout
  fixed trig functions closes #498
  patched image functions to accept a real path
  Fix failing test for change to http_path in rails
  Failing test for changing http_path with rails
  reverted sorting back to one liner
  more importer tests
  ...

Conflicts:
	Gemfile.lock
This commit is contained in:
Chris Eppstein 2011-08-19 14:42:42 -07:00
commit 000e4e1ed7
30 changed files with 631 additions and 157 deletions

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
compass (0.12.0.alpha.0.33263ca)
compass (0.12.0.alpha.0.91a748a)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
@ -10,12 +10,12 @@ GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
actionmailer (3.0.9)
actionpack (= 3.0.9)
actionmailer (3.0.10)
actionpack (= 3.0.10)
mail (~> 2.2.19)
actionpack (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
actionpack (3.0.10)
activemodel (= 3.0.10)
activesupport (= 3.0.10)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.5.0)
@ -23,23 +23,23 @@ GEM
rack-mount (~> 0.6.14)
rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
activemodel (3.0.9)
activesupport (= 3.0.9)
activemodel (3.0.10)
activesupport (= 3.0.10)
builder (~> 2.1.2)
i18n (~> 0.5.0)
activerecord (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
activerecord (3.0.10)
activemodel (= 3.0.10)
activesupport (= 3.0.10)
arel (~> 2.0.10)
tzinfo (~> 0.3.23)
activeresource (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
activesupport (3.0.9)
activeresource (3.0.10)
activemodel (= 3.0.10)
activesupport (= 3.0.10)
activesupport (3.0.10)
addressable (2.2.6)
arel (2.0.10)
builder (2.1.2)
chunky_png (1.2.0)
chunky_png (1.2.1)
compass-validator (3.0.1)
css_parser (1.0.1)
cucumber (0.9.4)
@ -50,7 +50,7 @@ GEM
term-ansicolor (~> 1.0.5)
diff-lcs (1.1.2)
em-dir-watcher (0.9.4)
em-websocket (0.3.0)
em-websocket (0.3.1)
addressable (>= 2.1.1)
eventmachine (>= 0.12.9)
erubis (2.6.6)
@ -74,29 +74,29 @@ GEM
treetop (~> 1.4.8)
mime-types (1.16)
mocha (0.9.12)
polyglot (0.3.1)
polyglot (0.3.2)
rack (1.2.3)
rack-mount (0.6.14)
rack (>= 1.0.0)
rack-test (0.5.7)
rack (>= 1.0)
rails (3.0.9)
actionmailer (= 3.0.9)
actionpack (= 3.0.9)
activerecord (= 3.0.9)
activeresource (= 3.0.9)
activesupport (= 3.0.9)
rails (3.0.10)
actionmailer (= 3.0.10)
actionpack (= 3.0.10)
activerecord (= 3.0.10)
activeresource (= 3.0.10)
activesupport (= 3.0.10)
bundler (~> 1.0)
railties (= 3.0.9)
railties (3.0.9)
actionpack (= 3.0.9)
activesupport (= 3.0.9)
railties (= 3.0.10)
railties (3.0.10)
actionpack (= 3.0.10)
activesupport (= 3.0.10)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (~> 0.14.4)
rake (0.8.7)
rcov (0.9.9)
rdoc (3.8)
rcov (0.9.10)
rdoc (3.9.2)
rspec (2.0.1)
rspec-core (~> 2.0.1)
rspec-expectations (~> 2.0.1)
@ -110,11 +110,12 @@ GEM
ruby-json (1.1.2)
ruby-prof (0.10.8)
rubyzip (0.9.4)
sass (3.1.5)
sass (3.1.7)
term-ansicolor (1.0.6)
thor (0.14.6)
timecop (0.3.5)
treetop (1.4.9)
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.29)

View File

@ -14,6 +14,14 @@ The Documentation for the [latest stable release](http://compass-style.org/docs/
The Documentation for the [latest preview release](http://beta.compass-style.org/)
0.12.0 pending
-------------------
* Added support for diagonal, horizontal, and smart sprite layout
* Fixed a bug with spacing in horizontal layout
* Changed the descriptions of the sin, cos, and tan to be more descriptive
* Fixed trig functions via issue #498
* 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
0.11.5 (07/10/2011)
-------------------

View File

@ -55,11 +55,21 @@ is located within it.
<a name="layout-control"></a>
## Layout Control
If you prefer horizontal sprites to the `vertical` default just set the magic variable `$<sprite>-layout` variable.
Set the `$<sprite>-layout` variable to the preferred layout method.
* vertical - default
* horizontal - lays images out side by side
* diagonal - lays images out corner to corner none of the spacing of padding options are taken into account
* smart - lays the images out using a bin packing algorithm which allows for much smaller surface areas in your sprite files - does not support spacing or padding
Example:
$icon-layout:horizontal;
@import "icon/*.png";
$dropcap-layout:diagonal
@import "dropcap/*.png";
<a name="selector-control"></a>
## Selector Control

View File

@ -35,8 +35,9 @@ documented_functions:
sin($number)
.details
%p
Takes the sine of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Degrees will first be converted to radians.
Returns the sine of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Unless the number has a unit of <code>deg</code> it
will be evaluated as radians. Degrees will first be converted to radians.
If the number is any other unit, the units will be passed thru to the result,
and the number will be treated as radians.
@ -46,8 +47,9 @@ documented_functions:
cos($number)
.details
%p
Takes the cosine of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Degrees will first be converted to radians.
Returns the cosine of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Unless the number has a unit of <code>deg</code> it
will be evaluated as radians. Degrees will first be converted to radians.
If the number is any other unit, the units will be passed thru to the result,
and the number will be treated as radians.
#tan.helper
@ -56,7 +58,8 @@ documented_functions:
tan($number)
.details
%p
Takes the tangent of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Degrees will first be converted to radians.
Returns the tangent of a number. If the number is unitless or has a unit of <code>deg</code>
then it will return a unitless result. Unless the number has a unit of <code>deg</code> it
will be evaluated as radians. Degrees will first be converted to radians.
If the number is any other unit, the units will be passed thru to the result,
and the number will be treated as radians.

View File

@ -40,10 +40,7 @@ module Compass
initializer "compass.initialize_rails" do |app|
# Configure compass for use within rails, and provide the project configuration
# that came via the rails boot process.
Compass::AppIntegration::Rails.check_for_double_boot!
Compass.discover_extensions!
Compass.configure_sass_plugin!
Compass.handle_configuration_change!
Compass::AppIntegration::Rails.initialize!(app.config.compass)
end
end
end

View File

@ -70,19 +70,21 @@ module Compass
end
def default_http_images_path
"#{top_level.http_path}images"
# Relies on the fact that this will be loaded after the "normal"
# defaults, so that method_missing finds http_root_relative
http_root_relative "images"
end
def default_http_javascripts_path
"#{top_level.http_path}javascripts"
http_root_relative "javascripts"
end
def default_http_fonts_path
"#{top_level.http_path}fonts"
http_root_relative "fonts"
end
def default_http_stylesheets_path
"#{top_level.http_path}stylesheets"
http_root_relative "stylesheets"
end
def default_extensions_dir

View File

@ -24,7 +24,7 @@ module Compass
attributes_for_directory(:fonts),
attributes_for_directory(:extensions, nil),
# Compilation options
:sprite_search_path,
:sprite_load_path,
:output_style,
:environment,
:relative_assets,

View File

@ -89,7 +89,7 @@ module Compass
top_level.images_dir
end
def default_sprite_search_path
def default_sprite_load_path
[top_level.images_path]
end

View File

@ -1,14 +1,22 @@
module Compass::SassExtensions::Functions::ImageSize
# Returns the width of the image relative to the images directory
def image_width(image_file)
image_path = real_path(image_file)
image_path = if File.exists?(image_file.value)
image_file.value
else
real_path(image_file)
end
width = ImageProperties.new(image_path).size.first
Sass::Script::Number.new(width,["px"])
end
# Returns the height of the image relative to the images directory
def image_height(image_file)
image_path = real_path(image_file)
image_path = if File.exists?(image_file.value)
image_file.value
else
real_path(image_file)
end
height = ImageProperties.new(image_path).size.last
Sass::Script::Number.new(height, ["px"])
end

View File

@ -61,7 +61,7 @@ module Compass::SassExtensions::Functions::Sprites
verify_map(map, "sprite")
verify_sprite(sprite)
if image = map.image_for(sprite.value)
Sass::Script::String.new(image.relative_file)
Sass::Script::String.new(image.file)
else
missing_image!(map, sprite)
end

View File

@ -19,9 +19,10 @@ module Compass::SassExtensions::Functions::Trig
private
def trig(operation, number)
if number.numerator_units == ["deg"] && number.denominator_units == []
Sass::Script::Number.new(Math.send(operation, Math::PI * number.value / 360))
Sass::Script::Number.new(Math.send(operation, (number.value * Math::PI / 180)))
else
Sass::Script::Number.new(Math.send(operation, number.value), number.numerator_units, number.denominator_units)
end
end
end

View File

@ -7,7 +7,8 @@ module Compass
end
end
end
require 'compass/sass_extensions/sprites/image_row'
require 'compass/sass_extensions/sprites/row_fitter'
require 'compass/sass_extensions/sprites/image'
require 'compass/sass_extensions/sprites/layout_methods'
require 'compass/sass_extensions/sprites/sprite_methods'

View File

@ -17,7 +17,16 @@ module Compass
# The Full path to the image
def file
File.join(Compass.configuration.images_path, relative_file)
@file ||= find_file
end
def find_file
Compass.configuration.sprite_load_path.each do |path|
f = File.join(path, relative_file)
if File.exists?(f)
return f
end
end
end
# Width of the image
@ -25,6 +34,10 @@ module Compass
dimensions.first
end
def size
@size ||= File.size(file)
end
# Height of the image
def height
dimensions.last
@ -35,19 +48,18 @@ module Compass
File.basename(relative_file, '.png')
end
# Value of <tt> $#{name}-repeat </tt> or <tt> $repeat </tt>
def repeat
[ "#{name}-repeat", "repeat" ].each { |which|
if var = options.get_var(which)
return var.value
end
}
"no-repeat"
def get_var_file(var)
options.get_var "#{name}_#{var}"
end
# Value of <tt> $#{name}-position </tt> or <tt> $position </tt> defaults o <tt>0px</tt>
# Value of <tt> $#{name}-repeat </tt> or <tt> $repeat </tt>
def repeat
(get_var_file("repeat") || options.get_var("repeat") || Sass::Script::String.new("no-repeat")).value
end
# Value of <tt> $#{name}-position </tt> or <tt> $position </tt> defaults to <tt>0px</tt>
def position
options.get_var("#{name}-position") || options.get_var("position") || Sass::Script::Number.new(0, ["px"])
get_var_file("position") || options.get_var("position") || Sass::Script::Number.new(0, ["px"])
end
# Offset within the sprite
@ -57,7 +69,7 @@ module Compass
# Spacing between this image and the next
def spacing
(options.get_var("#{name}-spacing") || options.get_var("spacing") || Sass::Script::Number.new(0)).value
(get_var_file("spacing") || options.get_var("spacing") || Sass::Script::Number.new(0, ['px'])).value
end
# MD5 hash of this file

View File

@ -0,0 +1,47 @@
require 'forwardable'
module Compass
module SassExtensions
module Sprites
class ImageRow
extend Forwardable
attr_reader :images, :max_width
def_delegators :@images, :last, :delete, :empty?, :length
def initialize(max_width)
@images = []
@max_width = max_width
end
def add(image)
return false if !will_fit?(image)
@images << image
true
end
alias :<< :add
def height
images.map(&:height).max
end
def width
images.map(&:width).max
end
def total_width
images.inject(0) {|sum, img| sum + img.width }
end
def efficiency
1 - (total_width.to_f / max_width.to_f)
end
def will_fit?(image)
(total_width + image.width) <= max_width
end
end
end
end
end

View File

@ -3,23 +3,76 @@ module Compass
module Sprites
module LayoutMethods
HORIZONTAL = 'horizontal'
DIAGONAL = 'diagonal'
SMART = 'smart'
def smart?
@kwargs.get_var('layout').value == SMART
end
def horizontal?
@kwargs.get_var('layout').value == HORIZONTAL
end
def diagonal?
@kwargs.get_var('layout').value == DIAGONAL
end
# Calculates the overal image dimensions
# collects image sizes and input parameters for each sprite
def compute_image_positions!
if horizontal?
calculate_height
case @kwargs.get_var('layout').value
when SMART
calculate_smart_positions
when DIAGONAL
calculate_diagonal_dimensions
calculate_diagonal_positions
when HORIZONTAL
@height = height_for_horizontal_layout
calculate_horizontal_positions
calculate_width
@width = width_for_horizontal_layout
else
@images.sort! {|a,b| File.size(b.file) <=> File.size(a.file)} #put small images first
calculate_width
@images.sort! {|a,b| b.size <=> a.size}
@width = width_for_vertical_layout
calulate_vertical_postions
calculate_height
@height = height_for_vertical_layout
end
end
def calculate_smart_positions
fitter = ::Compass::SassExtensions::Sprites::RowFitter.new(@images)
current_y = 0
fitter.fit!.each do |row|
current_x = 0
row.images.each_with_index do |image, index|
image.left = current_x
image.top = current_y
current_x += image.width
end
current_y += row.height
end
@width = fitter.width
@height = fitter.height
end
def calculate_diagonal_dimensions
@width = @images.map {|image| image.width}.inject(0) {|width, sum| sum + width}
@height = @images.map {|image| image.height}.inject(0) {|height, sum| sum + height}
end
def calculate_diagonal_positions
previous = nil
@images.each_with_index do |image, index|
if previous.nil?
previous = image
image.top = 0
image.left = 0
next
end
image.top = previous.top + previous.height
image.left = previous.left + previous.width
previous = image
end
end
@ -28,7 +81,7 @@ module Compass
image.top = image.position.unit_str == '%' ? (@height - image.height) * (image.position.value / 100.0) : image.position.value
next if index == 0
last_image = @images[index-1]
image.left = last_image.left + last_image.width + [image.offset, last_image.offset].max
image.left = last_image.left + last_image.width + [image.spacing, last_image.spacing].max
end
end
@ -41,39 +94,17 @@ module Compass
end
end
def calculate_dimensions!
calculate_width
calculate_height
end
def calculate_height
@height = if horizontal?
height_for_horizontal_layout
else
height_for_vertical_layout
end
end
def height_for_vertical_layout
last = @images.last
last.top + last.height
end
def height_for_horizontal_layout
@height = @images.map {|image| image.height + image.spacing}.max
end
def calculate_width
@width = if horizontal?
width_for_horizontal_layout
else
width_for_vertical_layout
end
@height = @images.map {|image| image.height + image.offset}.max
end
def width_for_horizontal_layout
@images.inject(0) { |sum, image| sum += (image.width + image.offset) }
@images.inject(0) { |sum, image| sum += (image.width + image.spacing) }
end
def width_for_vertical_layout

View File

@ -0,0 +1,86 @@
require 'forwardable'
module Compass
module SassExtensions
module Sprites
class RowFitter
extend Forwardable
attr_reader :images, :rows
def_delegators :rows, :[]
def initialize(images)
@images = images.sort {|a,b| a.height <=> b.height }
@rows = []
end
def fit!(style = :scan)
send("#{style}_fit")
@rows
end
def width
@width ||= @images.collect(&:width).max
end
def height
@height ||= @rows.inject(0) {|sum, row| sum += row.height}
end
def efficiency
@rows.inject(0) { |sum, row| sum += row.efficiency } ** @rows.length
end
private
def new_row(image = nil)
row = Compass::SassExtensions::Sprites::ImageRow.new(width)
row.add(image) if image
row
end
def fast_fit
row = new_row
@images.each do |image|
if !row.add(image)
@rows << row
row = new_row(image)
end
end
@rows << row
end
def scan_fit
fast_fit
moved_images = []
begin
removed = false
catch :done do
@rows.each do |row|
(@rows - [ row ]).each do |other_row|
other_row.images.each do |image|
if !moved_images.include?(image)
if row.will_fit?(image)
other_row.delete(image)
row << image
@rows.delete(other_row) if other_row.empty?
removed = true
moved_images << image
throw :done
end
end
end
end
end
end
end while removed
end
end
end
end
end

View File

@ -17,11 +17,21 @@ module Compass
name, path = Compass::SpriteImporter.path_and_name(uri)
files = Compass::SpriteImporter.files(uri)
sprites = files.map do |sprite|
sprite.gsub("#{Compass.configuration.images_path}/", "")
relative_name(sprite)
end
new(sprites, path, name, context, kwargs)
end
def self.relative_name(sprite)
sprite = File.expand_path(sprite)
Compass.configuration.sprite_load_path.each do |path|
path = File.expand_path(path)
if sprite.include?(path)
return sprite.gsub("#{path}/", "")
end
end
end
def initialize(sprites, path, name, context, kwargs)
@image_names = sprites
@path = path

View File

@ -66,7 +66,7 @@ module Compass
# Returns the Glob of image files for the uri
def self.files(uri)
Compass.configuration.sprite_search_path.each do |folder|
Compass.configuration.sprite_load_path.each do |folder|
files = Dir[File.join(folder, uri)].sort
next if files.empty?
return files

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,50 @@
require 'test_helper'
require 'compass'
require 'stringio'
class ConfigurationTest < Test::Unit::TestCase
setup do
Compass.reset_configuration!
end
after do
Compass.reset_configuration!
end
def test_defaults
contents = StringIO.new(<<-CONFIG)
project_type = :rails
CONFIG
config = Compass.configuration_for(contents, "config/compass.rb")
Compass.add_project_configuration(config, :project_type => "rails")
assert_equal 'public/images', Compass.configuration.images_dir
assert_equal 'public/stylesheets', Compass.configuration.css_dir
assert_equal 'public/fonts', Compass.configuration.fonts_dir
assert_equal '/', Compass.configuration.http_path
assert_equal '/images', Compass.configuration.http_images_path
assert_equal '/stylesheets', Compass.configuration.http_stylesheets_path
assert_equal '/fonts', Compass.configuration.http_fonts_path
# Other default values must wait until I have a better idea of how to mock Sass::Util.app_geq
end
def test_http_path_change
contents = StringIO.new(<<-CONFIG)
project_type = :rails
http_path = "/test/alternative_path"
CONFIG
config = Compass.configuration_for(contents, "config/compass.rb")
Compass.add_project_configuration(config, :project_type => "rails")
assert_equal '/test/alternative_path', Compass.configuration.http_path
assert_equal '/test/alternative_path/images', Compass.configuration.http_images_path
assert_equal '/test/alternative_path/stylesheets', Compass.configuration.http_stylesheets_path
assert_equal '/test/alternative_path/fonts', Compass.configuration.http_fonts_path
end
end

View File

@ -65,18 +65,21 @@ class SassExtensionsTest < Test::Unit::TestCase
end
def test_trig_functions
assert_equal "0.841", evaluate("sin(1)")
assert_equal "0.841px", evaluate("sin(1px)")
assert_equal "0.0", evaluate("sin(pi())")
assert_equal "1", evaluate("sin(pi() / 2)")
assert_equal "1", evaluate("sin(180deg)")
assert_equal "0.0", evaluate("sin(180deg)")
assert_equal "-1", evaluate("sin(3* pi() / 2)")
assert_equal "-1", evaluate("cos(pi())")
assert_equal "-1", evaluate("cos(360deg)")
assert_equal "1", evaluate("cos(360deg)")
assert_equal "-0.176", evaluate("sin(270)")
assert_equal "1", evaluate("cos(2*pi())")
assert_equal "0.0", evaluate("cos(pi() / 2)")
assert_equal "0.0", evaluate("cos(3* pi() / 2)")
assert_equal "0.0", evaluate("tan(pi())")
assert_equal "0.0", evaluate("tan(360deg)")
assert_equal "0.959", evaluate("sin(360)")
assert evaluate("tan(pi()/2 - 0.0001)").to_f > 1000, evaluate("tan(pi()/2 - 0.0001)")
assert evaluate("tan(pi()/2 + 0.0001)").to_f < -1000, evaluate("tan(pi()/2 - 0.0001)")
end

View File

@ -0,0 +1,57 @@
require 'test_helper'
class ImageRowTest < Test::Unit::TestCase
include SpriteHelper
def setup
create_sprite_temp
file = StringIO.new("images_path = #{@images_src_path.inspect}\n")
Compass.add_configuration(file, "sprite_config")
@filenames = %w(large.png large_square.png medium.png tall.png small.png)
@image_files = Dir["#{@images_src_path}/image_row/*.png"].sort
@images = @image_files.map do |img|
img.gsub!("#{@images_src_path}/", '')
Compass::SassExtensions::Sprites::Image.new(nil, img, {})
end
image_row(1000)
end
def teardown
clean_up_sprites
end
def image_row(max)
@image_row = Compass::SassExtensions::Sprites::ImageRow.new(max)
end
def populate_row
@images.each do |image|
assert @image_row.add(image)
end
end
it "should return false if image will not fit in row" do
image_row(100)
img = Compass::SassExtensions::Sprites::Image.new(nil, File.join('image_row', 'large.png'), {})
assert !@image_row.add(img)
end
it "should have 5 images" do
populate_row
assert_equal 5, @image_row.images.size
end
it "should return max image width" do
populate_row
assert_equal 400, @image_row.width
end
it "should return max image height" do
populate_row
assert_equal 40, @image_row.height
end
it "should have an efficiency rating" do
populate_row
assert_equal 1 - (580.0 / 1000.0), @image_row.efficiency
end
end

View File

@ -6,41 +6,36 @@ class SpritesImageTest < Test::Unit::TestCase
include SpriteHelper
def setup
create_sprite_temp
file = StringIO.new("images_path = #{@images_src_path.inspect}\n")
Compass.add_configuration(file, "sprite_config")
@repeat = 'no-repeat'
@spacing = 0
@position = 100
@offset = 100
end
let(:sprite_filename) { 'squares/ten-by-ten.png' }
let(:sprite_path) { File.join(@images_src_path, sprite_filename) }
let(:sprite_name) { File.basename(sprite_filename, '.png') }
SPRITE_FILENAME = 'selectors/ten-by-ten.png'
def options
options = {:offset => @offset}
options.stubs(:get_var).with(anything).returns(nil)
::OpenStruct.any_instance.stubs(:unitless?).returns(true)
options.stubs(:get_var).with("#{sprite_name}-repeat").returns(::OpenStruct.new(:value => @repeat))
options.stubs(:get_var).with("#{sprite_name}-spacing").returns(::OpenStruct.new(:value => @spacing))
options.stubs(:get_var).with("#{sprite_name}-position").returns(::OpenStruct.new(:value => @position))
options.stubs(:get_var).with("layout").returns(::OpenStruct.new(:value => 'vertical'))
options
def sprite_path
File.join(@images_tmp_path, SPRITE_FILENAME)
end
def sprite_name
File.basename(SPRITE_FILENAME, '.png')
end
def digest
Digest::MD5.file(sprite_path).hexdigest
end
let(:digest) { Digest::MD5.file(sprite_path).hexdigest }
def test_map(options ={})
options = {'cleanup' => Sass::Script::Bool.new(true), 'layout' => Sass::Script::String.new('vertical')}.merge(options)
map = sprite_map_test(options)
end
let(:image) { Compass::SassExtensions::Sprites::Image.new(sprite_map_test(options), File.join(sprite_filename), options)}
def test_image(options ={})
test_map(options).images.first
end
test 'initialize' do
image = test_image
assert_equal sprite_name, image.name
assert_equal sprite_path, image.file
assert_equal sprite_filename, image.relative_file
assert_equal SPRITE_FILENAME, image.relative_file
assert_equal 10, image.width
assert_equal 10, image.height
assert_equal digest, image.digest
@ -49,46 +44,62 @@ class SpritesImageTest < Test::Unit::TestCase
end
test 'hover' do
assert_equal 'ten-by-ten_hover', image.hover.name
assert_equal 'ten-by-ten_hover', test_image.hover.name
end
test 'no parent' do
assert_nil image.parent
assert_nil test_image.parent
end
test 'image type is nil' do
@repeat = nil
assert_nil image.repeat
end
test 'image type is "global"' do
@repeat = 'global'
assert_equal @repeat, image.repeat
image = test_image "ten_by_ten_repeat" => Sass::Script::String.new('global')
assert_equal 'global', image.repeat
end
test 'image type is "no-repeat"' do
assert_equal 'no-repeat', image.repeat
assert_equal 'no-repeat', test_image.repeat
end
test 'image position' do
assert_equal Sass::Script::Number.new(100, ["px"]).value, image.position.value
image = test_image "ten_by_ten_position" => Sass::Script::Number.new(100, ["px"])
assert_equal 100, image.position.value
end
test 'image spacing' do
@spacing = 10
assert_equal @spacing, image.spacing
image = test_image "spacing" => Sass::Script::Number.new(100, ["px"])
assert_equal 100, image.spacing
end
test 'offset' do
assert_equal @offset, image.offset
image = test_image "ten_by_ten_position" => Sass::Script::Number.new(100, ["px"])
assert_equal 100, image.offset
end
test 'neither, uses 0' do
@offset = 0
img = image
img = test_image
img.position.stubs(:unitless?).returns(false)
assert_equal 0, img.offset
end
test 'gets name for sprite in search path' do
Compass.reset_configuration!
uri = 'foo/*.png'
other_folder = File.join(@images_tmp_path, '../other-temp')
FileUtils.mkdir_p other_folder
FileUtils.mkdir_p File.join(other_folder, 'foo')
%w(my bar).each do |file|
FileUtils.touch(File.join(other_folder, "foo/#{file}.png"))
end
config = Compass::Configuration::Data.new('config')
config.images_path = @images_tmp_path
config.sprite_load_path = [@images_tmp_path, other_folder]
Compass.add_configuration(config, "sprite_config")
image = Compass::SassExtensions::Sprites::Image.new(test_map, "foo/my.png", {})
assert_equal File.join(other_folder, 'foo/my.png'), image.file
assert_equal 0, image.size
FileUtils.rm_rf other_folder
end
end

View File

@ -29,11 +29,11 @@ class ImporterTest < Test::Unit::TestCase
end
config = Compass::Configuration::Data.new('config')
config.images_path = @images_tmp_path
config.sprite_search_path = [@images_tmp_path, other_folder]
config.sprite_load_path = [@images_tmp_path, other_folder]
Compass.add_configuration(config, "sprite_config")
importer = Compass::SpriteImporter.new
assert_equal 2, Compass.configuration.sprite_search_path.compact.size
assert Compass.configuration.sprite_search_path.include?(other_folder)
assert_equal 2, Compass.configuration.sprite_load_path.compact.size
assert Compass.configuration.sprite_load_path.include?(other_folder)
assert_equal ["bar", "my"], Compass::SpriteImporter.sprite_names(uri)
FileUtils.rm_rf other_folder

View File

@ -0,0 +1,66 @@
require 'test_helper'
require 'compass/sass_extensions/sprites/row_fitter'
class RowFitterTest < Test::Unit::TestCase
include SpriteHelper
def setup
file = StringIO.new("images_path = #{@images_src_path.inspect}\n")
Compass.add_configuration(file, "sprite_config")
end
def row_fitter(images = nil)
@row_fitter ||= Compass::SassExtensions::Sprites::RowFitter.new(images)
end
def teardown
@row_fitter = nil
end
def create_images(dims)
dims.collect { |width, height|
image = Compass::SassExtensions::Sprites::Image.new('blah', 'blah', {})
image.stubs(:width => width, :height => height)
image
}
end
def basic_dims
[
[ 100, 10 ],
[ 80, 10 ],
[ 50, 10 ],
[ 35, 10 ],
[ 20, 10 ]
]
end
it 'should use the fast placement algorithm' do
images = create_images(basic_dims)
row_fitter(images)
assert_equal 100, row_fitter.width
row_fitter.fit!(:fast)
assert_equal 4, row_fitter.rows.length
assert_equal [ images[0] ], row_fitter[0].images
assert_equal [ images[1] ], row_fitter[1].images
assert_equal [ images[2], images[3] ], row_fitter[2].images
assert_equal [ images[4] ], row_fitter[3].images
end
it 'should use the scan placement algorithm' do
images = create_images(basic_dims)
row_fitter(images)
row_fitter.fit!(:scan)
assert_equal 3, row_fitter.rows.length
assert_equal [ images[0] ], row_fitter[0].images
assert_equal [ images[1], images[4] ], row_fitter[1].images
assert_equal [ images[2], images[3] ], row_fitter[2].images
end
end

View File

@ -5,20 +5,16 @@ class SpriteMapTest < Test::Unit::TestCase
def setup
Hash.send(:include, Compass::SassExtensions::Functions::Sprites::VariableReader)
@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')
FileUtils.cp_r @images_src_path, @images_tmp_path
config = Compass::Configuration::Data.new('config')
config.images_path = @images_tmp_path
config.sprite_search_path = [@images_tmp_path]
Compass.add_configuration(config)
create_sprite_temp
file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n")
Compass.add_configuration(file, "sprite_config")
Compass.configure_sass_plugin!
@options = {'cleanup' => Sass::Script::Bool.new(true), 'layout' => Sass::Script::String.new('vertical')}
@base = sprite_map_test(@options)
end
def teardown
FileUtils.rm_r @images_tmp_path
clean_up_sprites
@base = nil
end
@ -90,10 +86,55 @@ class SpriteMapTest < Test::Unit::TestCase
assert_equal [0, 0, 0, 0], @base.images.map(&:left)
end
it "should have a vertical layout with spacing" do
base = sprite_map_test(@options.merge({"spacing" => Sass::Script::Number.new(10, ['px'])}))
assert_equal [0, 20, 40, 60], base.images.map(&:top)
end
it "should layout vertical with position" do
base = sprite_map_test("ten_by_ten_active_position" => Sass::Script::Number.new(10, ['px']))
assert_equal [0, 10, 0, 0], base.images.map(&:left)
end
def smart
options = @options.merge("layout" => Sass::Script::String.new('smart'))
importer = Compass::SpriteImporter.new
uri = "image_row/*.png"
path, name = Compass::SpriteImporter.path_and_name(uri)
sprite_names = Compass::SpriteImporter.sprite_names(uri)
sass_engine = Compass::SpriteImporter.sass_engine(uri, name, importer, options)
Compass::SassExtensions::Sprites::SpriteMap.new(sprite_names.map {|n| "image_row/#{n}.png"}, path, name, sass_engine, options)
end
it "should have a smart layout" do
base = smart
base.generate
assert_equal 400, base.width
assert_equal 60, base.height
assert_equal [[0, 0], [20, 120], [20, 20], [20, 0], [20, 160]], base.images.map {|i| [i.top, i.left]}
assert File.exists?(base.filename)
FileUtils.rm base.filename
end
def diagonal
opts = @options.merge("layout" => Sass::Script::String.new('diagonal'))
sprite_map_test(opts)
end
it "should generate a diagonal sprite" do
base = diagonal
base.generate
assert_equal 40, base.width
assert_equal 40, base.height
assert_equal [[0,0], [10,10], [20,20], [30,30]], base.images.map {|i| [i.top, i.left]}
assert File.exists?(base.filename)
FileUtils.rm base.filename
end
# Horizontal tests
def horizontal
def horizontal(options= {})
opts = @options.merge("layout" => Sass::Script::String.new('horizontal'))
opts.merge!(options)
sprite_map_test(opts)
end
@ -109,6 +150,18 @@ class SpriteMapTest < Test::Unit::TestCase
assert_equal [0, 0, 0, 0], base.images.map(&:top)
end
it "should layout horizontaly with spacing" do
base = horizontal("spacing" => Sass::Script::Number.new(10, ['px']))
assert_equal [0, 20, 40, 60], base.images.map(&:left)
assert_equal [0, 0, 0, 0], base.images.map(&:top)
assert_equal 80, base.width
end
it "should layout horizontaly with position" do
base = horizontal("ten_by_ten_active_position" => Sass::Script::Number.new(10, ['px']))
assert_equal [0, 10, 0, 0], base.images.map(&:top)
end
it "should generate a horrizontal sprite" do
base = horizontal
base.generate
@ -122,5 +175,22 @@ class SpriteMapTest < Test::Unit::TestCase
assert_equal sizes.max, File.size(@base.images.last.file)
end
test "should get correct relative_name" do
Compass.reset_configuration!
uri = 'foo/*.png'
other_folder = File.join(@images_tmp_path, '../other-temp')
FileUtils.mkdir_p other_folder
FileUtils.mkdir_p File.join(other_folder, 'foo')
%w(my bar).each do |file|
FileUtils.touch(File.join(other_folder, "foo/#{file}.png"))
end
config = Compass::Configuration::Data.new('config')
config.images_path = @images_tmp_path
config.sprite_load_path = [@images_tmp_path, other_folder]
Compass.add_configuration(config, "sprite_config")
assert_equal 'foo/my.png', Compass::SassExtensions::Sprites::SpriteMap.relative_name(File.join(other_folder, 'foo/my.png'))
FileUtils.rm_rf other_folder
end
end