diff --git a/lib/rack/less/request.rb b/lib/rack/less/request.rb index f70f774..365d9ba 100644 --- a/lib/rack/less/request.rb +++ b/lib/rack/less/request.rb @@ -23,28 +23,42 @@ def request_method @env['REQUEST_METHOD'] end - def path_info - @env['PATH_INFO'] - end - def http_accept @env['HTTP_ACCEPT'] end - def path_resource_format - File.extname(path_info) + def path_info + @env['PATH_INFO'] + end + + def hosted_at_option + # sanitized :hosted_at option + # remove any trailing '/' + # ensure single leading '/' + @hosted_at_option ||= options(:hosted_at).sub(/\/+$/, '').sub(/^\/*/, '/') end - def path_resource_name - File.basename(path_info, path_resource_format) + def path_info_resource + # sanitized path to the resource being requested + # ensure single leading '/' + # remove any resource format + # ex: + # '/something.css' => '/something' + # '/nested/something.css' => '/nested/something' + # '///something.css' => '/something' + # '/nested///something.css' => '/nested/something' + @path_info_resource ||= File.join( + File.dirname(path_info.gsub(/\/+/, '/')).sub(/^#{hosted_at_option}/, ''), + File.basename(path_info.gsub(/\/+/, '/'), path_info_format) + ).sub(/^\/*/, '/') end - def path_resource_source - File.join(File.dirname(path_info).gsub(/#{options(:hosted_at)}/, ''), path_resource_name).gsub(/^\//, '') + def path_info_format + @path_info_format ||= File.extname(path_info.gsub(/\/+/, '/')) end def cache - File.join(options(:root), options(:public), options(:hosted_at)) + File.join(options(:root), options(:public), hosted_at_option) end # The Rack::Less::Source that the request is for @@ -55,35 +69,35 @@ def source :cache => Rack::Less.config.cache? ? cache : nil, :compress => Rack::Less.config.compress? } - Source.new(path_resource_source, source_opts) + Source.new(path_info_resource, source_opts) end end def for_css? (http_accept && http_accept.include?(Rack::Less::MIME_TYPE)) || (media_type && media_type.include?(Rack::Less::MIME_TYPE )) || - CSS_PATH_FORMATS.include?(path_resource_format) + CSS_PATH_FORMATS.include?(path_info_format) end def hosted_at? - path_info =~ /^#{options(:hosted_at)}\// + path_info =~ /^#{hosted_at_option}\// end - def exists? - File.exists?(File.join(cache, "#{path_resource_source}#{path_resource_format}")) + def cached? + File.exists?(File.join(cache, "#{path_info_resource}#{path_info_format}")) end - # Determine if the request is for existing LESS CSS file + # Determine if the request is for a non-cached existing LESS CSS source file # This will be called on every request so speed is an issue - # => first check if the request is a GET on a css resource :hosted_at (fast) - # => don't process if a file already exists in :hosted_at + # => first check if the request is a GET on a css resource in :hosted_at (fast) + # => don't process if a file has already been cached # => otherwise, check for less source files that match the request (slow) def for_less? - get? && + get? && # GET on css resource in :hosted_at (fast, check first) for_css? && hosted_at? && - !exists? && - !source.files.empty? + !cached? && # resource not cached (little slower) + !source.files.empty? # there is source for the resource (slow, check last) end end diff --git a/test/request_test.rb b/test/request_test.rb index b0b5193..0d25d63 100644 --- a/test/request_test.rb +++ b/test/request_test.rb @@ -11,12 +11,14 @@ class RequestTest < Test::Unit::TestCase context "basic object" do should "have some attributes" do [ :options, + :hosted_at_option, :request_method, :path_info, - :path_resource_format, - :path_resource_name, - :path_resource_source, + :path_info_format, + :path_info_resource, :source, + :hosted_at?, + :cached?, :for_css?, :for_less? ].each do |a| @@ -25,21 +27,42 @@ class RequestTest < Test::Unit::TestCase end should "know it's resource format" do - assert_equal '.css', less_request("GET", "/foo.css").path_resource_format - assert_equal '.css', less_request("GET", "/foo/bar.css").path_resource_format + assert_equal '.css', less_request("GET", "/foo.css").path_info_format + assert_equal '.css', less_request("GET", "/foo/bar.css").path_info_format + assert_equal '', less_request("GET", "/foo/bar").path_info_format end - should "know it's resource name" do - assert_equal 'foo', less_request("GET", "/foo.css").path_resource_name - assert_equal 'bar', less_request("GET", "/foo/bar.css").path_resource_name - assert_equal 'awesome', less_request("GET", "/stylesheets/awesome.css").path_resource_name - assert_equal 'awesome', less_request("GET", "/stylesheets/something/really/awesome.css").path_resource_name + should "sanitize the :hosted_at options" do + req = less_request("GET", "/something.css") + req.options = {:hosted_at => "/here"} + assert_equal "/here", req.hosted_at_option + + req = less_request("GET", "/something.css") + req.options = {:hosted_at => "//there"} + assert_equal "/there", req.hosted_at_option + + req = less_request("GET", "/something.css") + req.options = {:hosted_at => "/where/"} + assert_equal "/where", req.hosted_at_option + + req = less_request("GET", "/something.css") + req.options = {:hosted_at => "what/"} + assert_equal "/what", req.hosted_at_option + + req = less_request("GET", "/something.css") + req.options = {:hosted_at => "why//"} + assert_equal "/why", req.hosted_at_option end - should "know it's resource source" do - assert_equal 'foo/bar', less_request("GET", "/foo/bar.css").path_resource_source - assert_equal 'awesome', less_request("GET", "/stylesheets/awesome.css").path_resource_source - assert_equal 'something/really/awesome', less_request("GET", "/stylesheets/something/really/awesome.css").path_resource_source + should "know it's resource" do + assert_equal '/something', less_request("GET", "/stylesheets/something.css").path_info_resource + assert_equal '/something.awesome', less_request("GET", "/stylesheets/something.awesome.css").path_info_resource + assert_equal '/nested/something', less_request("GET", "/stylesheets/nested/something.css").path_info_resource + assert_equal '/something/really/awesome', less_request("GET", "/stylesheets/something/really/awesome.css").path_info_resource + assert_equal '/something', less_request("GET", "/something.css").path_info_resource + assert_equal '/something', less_request("GET", "///something.css").path_info_resource + assert_equal '/nested/something', less_request("GET", "/nested/something.css").path_info_resource + assert_equal '/nested/something', less_request("GET", "/nested///something.css").path_info_resource end end @@ -60,7 +83,7 @@ class RequestTest < Test::Unit::TestCase should "set it's cache to the appropriate path when Rack::Less configured to cache" do Rack::Less.config = Rack::Less::Config.new :cache => true req = less_request("GET", "/stylesheets/normal.css") - cache_path = File.join(req.options(:root), req.options(:public), req.options(:hosted_at)) + cache_path = File.join(req.options(:root), req.options(:public), req.hosted_at_option) assert_equal true, req.source.cache? assert_equal cache_path, req.source.cache