diff options
| author | Joshua Peek <josh@joshpeek.com> | 2009-01-02 13:40:23 -0600 | 
|---|---|---|
| committer | Joshua Peek <josh@joshpeek.com> | 2009-01-02 13:40:23 -0600 | 
| commit | 104898fcb7958bcb69ba0239d6de8aa37f2da9ba (patch) | |
| tree | 138434f3d7d9d25ad1eb0f0e2b8fd77745068851 /actionpack/lib | |
| parent | 606176a55b90c27687ae17f40fd1af0a86b62246 (diff) | |
| download | rails-104898fcb7958bcb69ba0239d6de8aa37f2da9ba.tar.gz rails-104898fcb7958bcb69ba0239d6de8aa37f2da9ba.tar.bz2 rails-104898fcb7958bcb69ba0239d6de8aa37f2da9ba.zip  | |
Revert to the good old days when AssetTag didn't cause anyone problems
Diffstat (limited to 'actionpack/lib')
| -rw-r--r-- | actionpack/lib/action_controller/dispatcher.rb | 1 | ||||
| -rw-r--r-- | actionpack/lib/action_view/helpers/asset_tag_helper.rb | 456 | 
2 files changed, 131 insertions, 326 deletions
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index c4e7357b81..d5af45f0da 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -91,7 +91,6 @@ module ActionController        run_callbacks :prepare_dispatch        Routing::Routes.reload -      ActionView::Helpers::AssetTagHelper::AssetTag::Cache.clear      end      # Cleanup the application by clearing out loaded classes so they can diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 79b1cdbc48..a341b453ec 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -157,7 +157,7 @@ module ActionView        #   javascript_path "http://www.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr.js        #   javascript_path "http://www.railsapplication.com/js/xmlhr.js" # => http://www.railsapplication.com/js/xmlhr.js        def javascript_path(source) -        JavaScriptTag.new(self, @controller, source).public_path +        compute_public_path(source, 'javascripts', 'js')        end        alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route @@ -255,17 +255,15 @@ module ActionView            joined_javascript_name = (cache == true ? "all" : cache) + ".js"            joined_javascript_path = File.join(JAVASCRIPTS_DIR, joined_javascript_name) -          unless File.exists?(joined_javascript_path) -            JavaScriptSources.create(self, @controller, sources, recursive).write_asset_file_contents(joined_javascript_path) -          end +          write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) unless File.exists?(joined_javascript_path)            javascript_src_tag(joined_javascript_name, options)          else -          JavaScriptSources.create(self, @controller, sources, recursive).expand_sources.collect { |source| -            javascript_src_tag(source, options) -          }.join("\n") +          expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n")          end        end +      @@javascript_expansions = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup } +        # Register one or more javascript files to be included when <tt>symbol</tt>        # is passed to <tt>javascript_include_tag</tt>. This method is typically intended        # to be called from plugin initialization to register javascript files @@ -278,9 +276,11 @@ module ActionView        #     <script type="text/javascript" src="/javascripts/body.js"></script>        #     <script type="text/javascript" src="/javascripts/tail.js"></script>        def self.register_javascript_expansion(expansions) -        JavaScriptSources.expansions.merge!(expansions) +        @@javascript_expansions.merge!(expansions)        end +      @@stylesheet_expansions = {} +        # Register one or more stylesheet files to be included when <tt>symbol</tt>        # is passed to <tt>stylesheet_link_tag</tt>. This method is typically intended        # to be called from plugin initialization to register stylesheet files @@ -293,7 +293,7 @@ module ActionView        #     <link href="/stylesheets/body.css"  media="screen" rel="stylesheet" type="text/css" />        #     <link href="/stylesheets/tail.css"  media="screen" rel="stylesheet" type="text/css" />        def self.register_stylesheet_expansion(expansions) -        StylesheetSources.expansions.merge!(expansions) +        @@stylesheet_expansions.merge!(expansions)        end        # Register one or more additional JavaScript files to be included when @@ -301,11 +301,11 @@ module ActionView        # typically intended to be called from plugin initialization to register additional        # .js files that the plugin installed in <tt>public/javascripts</tt>.        def self.register_javascript_include_default(*sources) -        JavaScriptSources.expansions[:defaults].concat(sources) +        @@javascript_expansions[:defaults].concat(sources)        end        def self.reset_javascript_include_default #:nodoc: -        JavaScriptSources.expansions[:defaults] = JAVASCRIPT_DEFAULT_SOURCES.dup +        @@javascript_expansions[:defaults] = JAVASCRIPT_DEFAULT_SOURCES.dup        end        # Computes the path to a stylesheet asset in the public stylesheets directory. @@ -320,7 +320,7 @@ module ActionView        #   stylesheet_path "http://www.railsapplication.com/css/style" # => http://www.railsapplication.com/css/style.css        #   stylesheet_path "http://www.railsapplication.com/css/style.js" # => http://www.railsapplication.com/css/style.css        def stylesheet_path(source) -        StylesheetTag.new(self, @controller, source).public_path +        compute_public_path(source, 'stylesheets', 'css')        end        alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route @@ -365,7 +365,6 @@ module ActionView        # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching        # is set to true (which is the case by default for the Rails production environment, but not for the development        # environment). Examples: -              #        # ==== Examples        #   stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false => @@ -396,14 +395,10 @@ module ActionView            joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"            joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name) -          unless File.exists?(joined_stylesheet_path) -            StylesheetSources.create(self, @controller, sources, recursive).write_asset_file_contents(joined_stylesheet_path) -          end +          write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) unless File.exists?(joined_stylesheet_path)            stylesheet_tag(joined_stylesheet_name, options)          else -          StylesheetSources.create(self, @controller, sources, recursive).expand_sources.collect { |source| -            stylesheet_tag(source, options) -          }.join("\n") +          expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n")          end        end @@ -418,7 +413,7 @@ module ActionView        #   image_path("/icons/edit.png")                              # => /icons/edit.png        #   image_path("http://www.railsapplication.com/img/edit.png") # => http://www.railsapplication.com/img/edit.png        def image_path(source) -        ImageTag.new(self, @controller, source).public_path +        compute_public_path(source, 'images')        end        alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route @@ -474,352 +469,163 @@ module ActionView        end        private -        def javascript_src_tag(source, options) -          content_tag("script", "", { "type" => Mime::JS, "src" => path_to_javascript(source) }.merge(options)) -        end - -        def stylesheet_tag(source, options) -          tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false) -        end - -        module ImageAsset -          DIRECTORY = 'images'.freeze - -          def directory -            DIRECTORY +        # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. +        # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL +        # roots. Rewrite the asset path for cache-busting asset ids. Include +        # asset host, if configured, with the correct request protocol. +        def compute_public_path(source, dir, ext = nil, include_host = true) +          has_request = @controller.respond_to?(:request) + +          if ext && (File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}"))) +            source += ".#{ext}"            end -          def extension -            nil -          end -        end - -        module JavaScriptAsset -          DIRECTORY = 'javascripts'.freeze -          EXTENSION = 'js'.freeze +          unless source =~ %r{^[-a-z]+://} +            source = "/#{dir}/#{source}" unless source[0] == ?/ -          def public_directory -            JAVASCRIPTS_DIR -          end +            source = rewrite_asset_path(source) -          def directory -            DIRECTORY +            if has_request && include_host +              unless source =~ %r{^#{ActionController::Base.relative_url_root}/} +                source = "#{ActionController::Base.relative_url_root}#{source}" +              end +            end            end -          def extension -            EXTENSION -          end -        end +          if include_host && source !~ %r{^[-a-z]+://} +            host = compute_asset_host(source) -        module StylesheetAsset -          DIRECTORY = 'stylesheets'.freeze -          EXTENSION = 'css'.freeze - -          def public_directory -            STYLESHEETS_DIR -          end - -          def directory -            DIRECTORY -          end +            if has_request && !host.blank? && host !~ %r{^[-a-z]+://} +              host = "#{@controller.request.protocol}#{host}" +            end -          def extension -            EXTENSION +            "#{host}#{source}" +          else +            source            end          end -        class AssetTag -          extend ActiveSupport::Memoizable - -          Cache = {} -          CacheGuard = Mutex.new - -          ProtocolRegexp = %r{^[-a-z]+://}.freeze - -          def initialize(template, controller, source, include_host = true) -            # NOTE: The template arg is temporarily needed for a legacy plugin -            # hook that is expected to call rewrite_asset_path on the -            # template. This should eventually be removed. -            @template = template -            @controller = controller -            @source = source -            @include_host = include_host -            @cache_key = if controller.respond_to?(:request) -              [ self.class.name,controller.request.protocol, -                compute_asset_host(source), -                ActionController::Base.relative_url_root, -                source, include_host ] +        # Pick an asset host for this source. Returns +nil+ if no host is set, +        # the host if no wildcard is set, the host interpolated with the +        # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4), +        # or the value returned from invoking the proc if it's a proc or the value from +        # invoking call if it's an object responding to call. +        def compute_asset_host(source) +          if host = ActionController::Base.asset_host +            if host.is_a?(Proc) || host.respond_to?(:call) +              case host.is_a?(Proc) ? host.arity : host.method(:call).arity +              when 2 +                request = @controller.respond_to?(:request) && @controller.request +                host.call(source, request) +              else +                host.call(source) +              end              else -              [ self.class.name, compute_asset_host(source), source, include_host ] +              (host =~ /%d/) ? host % (source.hash % 4) : host              end            end -           -          def public_path -            compute_public_path(@source) -          end -          memoize :public_path +        end -          def asset_file_path -            File.join(ASSETS_DIR, public_path.split('?').first) -          end -          memoize :asset_file_path +        # Use the RAILS_ASSET_ID environment variable or the source's +        # modification time as its cache-busting asset id. +        def rails_asset_id(source) +          if asset_id = ENV["RAILS_ASSET_ID"] +            asset_id +          else +            path = File.join(ASSETS_DIR, source) -          def contents -            File.read(asset_file_path) +            if File.exist?(path) +              File.mtime(path).to_i.to_s +            else +              '' +            end            end +        end -          def mtime -            File.mtime(asset_file_path) +        # Break out the asset path rewrite in case plugins wish to put the asset id +        # someplace other than the query string. +        def rewrite_asset_path(source) +          asset_id = rails_asset_id(source) +          if asset_id.blank? +            source +          else +            source + "?#{asset_id}"            end - -          private -            def request -              request? && @controller.request -            end - -            def request? -              @controller.respond_to?(:request) -            end - -            # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. -            # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL -            # roots. Rewrite the asset path for cache-busting asset ids. Include -            # asset host, if configured, with the correct request protocol. -            def compute_public_path(source) -              if source =~ ProtocolRegexp -                source += ".#{extension}" if missing_extension?(source) -                source = prepend_asset_host(source) -                source -              else -                CacheGuard.synchronize do -                  Cache[@cache_key + [source]] ||= begin -                    source += ".#{extension}" if missing_extension?(source) || file_exists_with_extension?(source) -                    source = "/#{directory}/#{source}" unless source[0] == ?/ -                    source = rewrite_asset_path(source) -                    source = prepend_relative_url_root(source)                 -                    source = prepend_asset_host(source) -                    source -                  end -                end -              end -            end -             -            def missing_extension?(source) -              extension && File.extname(source).blank? -            end -             -            def file_exists_with_extension?(source) -              extension && File.exist?(File.join(ASSETS_DIR, directory, "#{source}.#{extension}")) -            end -             -            def prepend_relative_url_root(source) -              relative_url_root = ActionController::Base.relative_url_root -              if request? && @include_host && source !~ %r{^#{relative_url_root}/} -                "#{relative_url_root}#{source}" -              else -                source -              end -            end - -            def prepend_asset_host(source) -              if @include_host && source !~ ProtocolRegexp -                host = compute_asset_host(source) -                if request? && !host.blank? && host !~ ProtocolRegexp -                  host = "#{request.protocol}#{host}" -                end -                "#{host}#{source}" -              else -                source -              end -            end - -            # Pick an asset host for this source. Returns +nil+ if no host is set, -            # the host if no wildcard is set, the host interpolated with the -            # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4), -            # or the value returned from invoking the proc if it's a proc or the value from -            # invoking call if it's an object responding to call. -            def compute_asset_host(source) -              if host = ActionController::Base.asset_host -                if host.is_a?(Proc) || host.respond_to?(:call) -                  case host.is_a?(Proc) ? host.arity : host.method(:call).arity -                  when 2 -                    host.call(source, request) -                  else -                    host.call(source) -                  end -                else -                  (host =~ /%d/) ? host % (source.hash % 4) : host -                end -              end -            end - -            # Use the RAILS_ASSET_ID environment variable or the source's -            # modification time as its cache-busting asset id. -            def rails_asset_id(source) -              if asset_id = ENV["RAILS_ASSET_ID"] -                asset_id -              else -                path = File.join(ASSETS_DIR, source) - -                if File.exist?(path) -                  File.mtime(path).to_i.to_s -                else -                  '' -                end -              end -            end - -            # Break out the asset path rewrite in case plugins wish to put the asset id -            # someplace other than the query string. -            def rewrite_asset_path(source) -              if @template.respond_to?(:rewrite_asset_path) -                # DEPRECATE: This way to override rewrite_asset_path -                @template.send(:rewrite_asset_path, source) -              else -                asset_id = rails_asset_id(source) -                if asset_id.blank? -                  source -                else -                  "#{source}?#{asset_id}" -                end -              end -            end          end -        class ImageTag < AssetTag -          include ImageAsset +        def javascript_src_tag(source, options) +          content_tag("script", "", { "type" => Mime::JS, "src" => path_to_javascript(source) }.merge(options))          end -        class JavaScriptTag < AssetTag -          include JavaScriptAsset +        def stylesheet_tag(source, options) +          tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false)          end -        class StylesheetTag < AssetTag -          include StylesheetAsset +        def compute_javascript_paths(*args) +          expand_javascript_sources(*args).collect { |source| compute_public_path(source, 'javascripts', 'js', false) }          end -        class AssetCollection -          extend ActiveSupport::Memoizable - -          Cache = {} -          CacheGuard = Mutex.new - -          def self.create(template, controller, sources, recursive) -            CacheGuard.synchronize do -              key = [self, sources, recursive] -              Cache[key] ||= new(template, controller, sources, recursive).freeze -            end -          end - -          def initialize(template, controller, sources, recursive) -            # NOTE: The template arg is temporarily needed for a legacy plugin -            # hook. See NOTE under AssetTag#initialize for more details -            @template = template -            @controller = controller -            @sources = sources -            @recursive = recursive -          end +        def compute_stylesheet_paths(*args) +          expand_stylesheet_sources(*args).collect { |source| compute_public_path(source, 'stylesheets', 'css', false) } +        end -          def write_asset_file_contents(joined_asset_path) -            FileUtils.mkdir_p(File.dirname(joined_asset_path)) -            File.open(joined_asset_path, "w+") { |cache| cache.write(joined_contents) } -            mt = latest_mtime -            File.utime(mt, mt, joined_asset_path) +        def expand_javascript_sources(sources, recursive = false) +          if sources.include?(:all) +            all_javascript_files = collect_asset_files(JAVASCRIPTS_DIR, ('**' if recursive), '*.js') +            ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq +          else +            expanded_sources = sources.collect do |source| +              determine_source(source, @@javascript_expansions) +            end.flatten +            expanded_sources << "application" if sources.include?(:defaults) && File.exist?(File.join(JAVASCRIPTS_DIR, "application.js")) +            expanded_sources            end - -          private -            def determine_source(source, collection) -              case source -              when Symbol -                collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}") -              else -                source -              end -            end - -            def validate_sources! -              @sources.collect { |source| determine_source(source, self.class.expansions) }.flatten -            end - -            def all_asset_files -              path = [public_directory, ('**' if @recursive), "*.#{extension}"].compact -              Dir[File.join(*path)].collect { |file| -                file[-(file.size - public_directory.size - 1)..-1].sub(/\.\w+$/, '') -              }.sort -            end - -            def tag_sources -              expand_sources.collect { |source| tag_class.new(@template, @controller, source, false) } -            end - -            def joined_contents -              tag_sources.collect { |source| source.contents }.join("\n\n") -            end - -            # Set mtime to the latest of the combined files to allow for -            # consistent ETag without a shared filesystem. -            def latest_mtime -              tag_sources.map { |source| source.mtime }.max -            end          end -        class JavaScriptSources < AssetCollection -          include JavaScriptAsset - -          EXPANSIONS = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup } - -          def self.expansions -            EXPANSIONS +        def expand_stylesheet_sources(sources, recursive) +          if sources.first == :all +            collect_asset_files(STYLESHEETS_DIR, ('**' if recursive), '*.css') +          else +            sources.collect do |source| +              determine_source(source, @@stylesheet_expansions) +            end.flatten            end +        end -          APPLICATION_JS = "application".freeze -          APPLICATION_FILE = "application.js".freeze - -          def expand_sources -            if @sources.include?(:all) -              assets = all_asset_files -              ((defaults.dup & assets) + assets).uniq! -            else -              expanded_sources = validate_sources! -              expanded_sources << APPLICATION_JS if include_application? -              expanded_sources -            end +        def determine_source(source, collection) +          case source +          when Symbol +            collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}") +          else +            source            end -          memoize :expand_sources - -          private -            def tag_class -              JavaScriptTag -            end - -            def defaults -              determine_source(:defaults, self.class.expansions) -            end +        end -            def include_application? -              @sources.include?(:defaults) && File.exist?(File.join(JAVASCRIPTS_DIR, APPLICATION_FILE)) -            end +        def join_asset_file_contents(paths) +          paths.collect { |path| File.read(asset_file_path(path)) }.join("\n\n")          end -        class StylesheetSources < AssetCollection -          include StylesheetAsset +        def write_asset_file_contents(joined_asset_path, asset_paths) +          FileUtils.mkdir_p(File.dirname(joined_asset_path)) +          File.open(joined_asset_path, "w+") { |cache| cache.write(join_asset_file_contents(asset_paths)) } -          EXPANSIONS = {} +          # Set mtime to the latest of the combined files to allow for +          # consistent ETag without a shared filesystem. +          mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max +          File.utime(mt, mt, joined_asset_path) +        end -          def self.expansions -            EXPANSIONS -          end +        def asset_file_path(path) +          File.join(ASSETS_DIR, path.split('?').first) +        end -          def expand_sources -            @sources.first == :all ? all_asset_files : validate_sources! -          end -          memoize :expand_sources +        def collect_asset_files(*path) +          dir = path.first -          private -            def tag_class -              StylesheetTag -            end +          Dir[File.join(*path.compact)].collect do |file| +            file[-(file.size - dir.size - 1)..-1].sub(/\.\w+$/, '') +          end.sort          end      end    end -end +end
\ No newline at end of file  | 
