diff --git a/lib/compass/sass_extensions/functions/urls.rb b/lib/compass/sass_extensions/functions/urls.rb index 581a080a..f72cdeb0 100644 --- a/lib/compass/sass_extensions/functions/urls.rb +++ b/lib/compass/sass_extensions/functions/urls.rb @@ -1,167 +1,203 @@ module Compass::SassExtensions::Functions::Urls - def stylesheet_url(path, only_path = Sass::Script::Bool.new(false)) - # Compute the path to the stylesheet, either root relative or stylesheet relative - # or nil if the http_stylesheets_path is not set in the configuration. - http_stylesheets_path = if relative? - compute_relative_path(Compass.configuration.css_path) - elsif Compass.configuration.http_stylesheets_path - Compass.configuration.http_stylesheets_path - else - Compass.configuration.http_root_relative(Compass.configuration.css_dir) - end - path = "#{http_stylesheets_path}/#{path.value}" - if only_path.to_bool - Sass::Script::String.new(clean_path(path)) - else - clean_url(path) - end + def self.has?(base, instance_method) + Sass::Util.has?(:instance_method, base, instance_method) end - Sass::Script::Functions.declare :stylesheet_url, [:path] - Sass::Script::Functions.declare :stylesheet_url, [:path, :only_path] - def font_url(path, only_path = Sass::Script::Bool.new(false)) - path = path.value # get to the string value of the literal. - - # Short curcuit if they have provided an absolute url. - if absolute_path?(path) - return Sass::Script::String.new("url(#{path})") - end - - # Compute the path to the font file, either root relative or stylesheet relative - # or nil if the http_fonts_path cannot be determined from the configuration. - http_fonts_path = if relative? - compute_relative_path(Compass.configuration.fonts_path) - else - Compass.configuration.http_fonts_path - end - - path = "#{http_fonts_path}/#{path}" - - if only_path.to_bool - Sass::Script::String.new(clean_path(path)) - else - clean_url(path) - end + def self.included(base) + base.send(:include, StylesheetUrl) unless has?(base, :stylesheet_url) + base.send(:include, FontUrl) unless has?(base, :font_url) + base.send(:include, ImageUrl) unless has?(base, :image_url) + base.send(:include, GeneratedImageUrl) unless has?(base, :generated_image_url) end - Sass::Script::Functions.declare :font_url, [:path] - Sass::Script::Functions.declare :font_url, [:path, :only_path] - def image_url(path, only_path = Sass::Script::Bool.new(false), cache_buster = Sass::Script::Bool.new(true)) - path = path.value # get to the string value of the literal. - - if path =~ %r{^#{Regexp.escape(Compass.configuration.http_images_path)}/(.*)} - # Treat root relative urls (without a protocol) like normal if they start with - # the 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_images_path is not set in the configuration. - http_images_path = if relative? - compute_relative_path(Compass.configuration.images_path) - elsif Compass.configuration.http_images_path - Compass.configuration.http_images_path - else - Compass.configuration.http_root_relative(Compass.configuration.images_dir) - end - - # Compute the real path to the image on the file stystem if the images_dir is set. - real_path = if Compass.configuration.images_dir - File.join(Compass.configuration.project_path, Compass.configuration.images_dir, path) - end - - # prepend the path to the image if there's one - if http_images_path - http_images_path = "#{http_images_path}/" unless http_images_path[-1..-1] == "/" - path = "#{http_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) + module StylesheetUrl + def self.included(base) + if base.respond_to?(:declare) + base.declare :stylesheet_url, [:path] + base.declare :stylesheet_url, [:path, :only_path] end end + def stylesheet_url(path, only_path = Sass::Script::Bool.new(false)) + # 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. + http_stylesheets_path = if relative? + compute_relative_path(Compass.configuration.css_path) + elsif Compass.configuration.http_stylesheets_path + Compass.configuration.http_stylesheets_path + else + Compass.configuration.http_root_relative(Compass.configuration.css_dir) + end - # prepend the asset host if there is one. - path = "#{asset_host}#{'/' unless path[0..0] == "/"}#{path}" if asset_host + path = "#{http_stylesheets_path}/#{path.value}" + if only_path.to_bool + Sass::Script::String.new(clean_path(path)) + else + clean_url(path) + end + end + end + + module FontUrl + def self.included(base) + if base.respond_to?(:declare) + base.declare :font_url, [:path] + base.declare :font_url, [:path, :only_path] + end + end + def font_url(path, only_path = Sass::Script::Bool.new(false)) + path = path.value # get to the string value of the literal. + + # Short curcuit if they have provided an absolute url. + if absolute_path?(path) + return Sass::Script::String.new("url(#{path})") + end + + # Compute the path to the font file, either root relative or stylesheet relative + # or nil if the http_fonts_path cannot be determined from the configuration. + http_fonts_path = if relative? + compute_relative_path(Compass.configuration.fonts_path) + else + Compass.configuration.http_fonts_path + end + + path = "#{http_fonts_path}/#{path}" + + if only_path.to_bool + Sass::Script::String.new(clean_path(path)) + else + clean_url(path) + end + end + end + + module ImageUrl + def self.included(base) + if base.respond_to?(:declare) + base.declare :image_url, [:path] + base.declare :image_url, [:path, :only_path] + base.declare :image_url, [:path, :only_path, :cache_buster] + end + end + def image_url(path, only_path = Sass::Script::Bool.new(false), cache_buster = Sass::Script::Bool.new(true)) + path = path.value # get to the string value of the literal. + + if path =~ %r{^#{Regexp.escape(Compass.configuration.http_images_path)}/(.*)} + # Treat root relative urls (without a protocol) like normal if they start with + # the 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_images_path is not set in the configuration. + http_images_path = if relative? + compute_relative_path(Compass.configuration.images_path) + elsif Compass.configuration.http_images_path + Compass.configuration.http_images_path + else + Compass.configuration.http_root_relative(Compass.configuration.images_dir) + end + + # Compute the real path to the image on the file stystem if the images_dir is set. + real_path = if Compass.configuration.images_dir + File.join(Compass.configuration.project_path, Compass.configuration.images_dir, path) + end + + # prepend the path to the image if there's one + if http_images_path + http_images_path = "#{http_images_path}/" unless http_images_path[-1..-1] == "/" + path = "#{http_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 + + if only_path.to_bool + Sass::Script::String.new(clean_path(path)) + else + clean_url(path) + end + end + end + + module GeneratedImageUrl + def self.included(base) + if base.respond_to?(:declare) + base.declare :generated_image_url, [:path] + base.declare :generated_image_url, [:path, :cache_buster] + end + end + 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 - if only_path.to_bool - Sass::Script::String.new(clean_path(path)) - else clean_url(path) end end - Sass::Script::Functions.declare :image_url, [:path] - Sass::Script::Functions.declare :image_url, [:path, :only_path] - 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 diff --git a/test/units/sass_extensions_test.rb b/test/units/sass_extensions_test.rb index 8b8aeabd..372d54e6 100644 --- a/test/units/sass_extensions_test.rb +++ b/test/units/sass_extensions_test.rb @@ -98,6 +98,20 @@ class SassExtensionsTest < Test::Unit::TestCase assert_equal "true", evaluate("prefixed(-css2, css2-fallback(css3, css2))") end + %w(stylesheet_url font_url image_url generated_image_url).each do |helper| + class_eval %Q{ + def test_#{helper}_helper_defers_to_existing_helper + c = Class.new do + def #{helper}(*args) + :original + end + end + c.send(:include, Compass::SassExtensions::Functions::Urls) + assert_equal :original, c.new.#{helper}("logo.png") + end + } + end + protected def evaluate(value) Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new).to_s