diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2009-01-10 18:43:27 +0000 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2009-01-10 18:43:27 +0000 |
commit | b6f33d6bf80c27c7fd9d597cbac00ce7e77805c2 (patch) | |
tree | caf315b50e65fdb1e82a2d92454d335097c364f8 /actionpack/lib/action_view | |
parent | a5981517e6676818c3031834627e4a0763ce4fba (diff) | |
parent | 40a75a509187b6759099a3644b7ae8db9fc14045 (diff) | |
download | rails-b6f33d6bf80c27c7fd9d597cbac00ce7e77805c2.tar.gz rails-b6f33d6bf80c27c7fd9d597cbac00ce7e77805c2.tar.bz2 rails-b6f33d6bf80c27c7fd9d597cbac00ce7e77805c2.zip |
Merge commit 'mainstream/master'
Conflicts:
activerecord/lib/active_record/base.rb
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r-- | actionpack/lib/action_view/base.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/asset_tag_helper.rb | 474 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/benchmark_helper.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_view/inline_template.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/paths.rb | 107 | ||||
-rw-r--r-- | actionpack/lib/action_view/renderable.rb | 9 | ||||
-rw-r--r-- | actionpack/lib/action_view/renderable_partial.rb | 7 | ||||
-rw-r--r-- | actionpack/lib/action_view/template.rb | 85 | ||||
-rw-r--r-- | actionpack/lib/action_view/test_case.rb | 3 |
9 files changed, 271 insertions, 447 deletions
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 8958e61e9d..70a0ba91a7 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -225,7 +225,7 @@ module ActionView #:nodoc: end # Returns the result of a render that's dictated by the options hash. The primary options are: - # + # # * <tt>:partial</tt> - See ActionView::Partials. # * <tt>:update</tt> - Calls update_page with the block given. # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those. diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index e595c534dd..7e1110afab 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 @@ -473,353 +468,190 @@ module ActionView tag("img", options) 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 - end - - def extension - nil - end - end - - module JavaScriptAsset - DIRECTORY = 'javascripts'.freeze - EXTENSION = 'js'.freeze - - def public_directory - JAVASCRIPTS_DIR - end - - def directory - DIRECTORY - end + def self.cache_asset_timestamps + @@cache_asset_timestamps + end - def extension - EXTENSION - end - end + # You can enable or disable the asset tag timestamps cache. + # With the cache enabled, the asset tag helper methods will make fewer + # expense file system calls. However this prevents you from modifying + # any asset files while the server is running. + # + # ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false + def self.cache_asset_timestamps=(value) + @@cache_asset_timestamps = value + end - module StylesheetAsset - DIRECTORY = 'stylesheets'.freeze - EXTENSION = 'css'.freeze + @@cache_asset_timestamps = true - def public_directory - STYLESHEETS_DIR + private + # 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 directory - DIRECTORY - end + unless source =~ %r{^[-a-z]+://} + source = "/#{dir}/#{source}" unless source[0] == ?/ - def extension - EXTENSION - end - end + source = rewrite_asset_path(source) - 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, - ActionController::Base.asset_host, - ActionController::Base.relative_url_root, - source, include_host] - else - [self.class.name,ActionController::Base.asset_host, source, include_host] + if has_request && include_host + unless source =~ %r{^#{ActionController::Base.relative_url_root}/} + source = "#{ActionController::Base.relative_url_root}#{source}" + end end end - - def public_path - compute_public_path(@source) - end - memoize :public_path - def asset_file_path - File.join(ASSETS_DIR, public_path.split('?').first) - end - memoize :asset_file_path - - def contents - File.read(asset_file_path) - end - - def mtime - File.mtime(asset_file_path) - end - - private - def request - request? && @controller.request - end + if include_host && source !~ %r{^[-a-z]+://} + host = compute_asset_host(source) - def request? - @controller.respond_to?(:request) + if has_request && !host.blank? && host !~ %r{^[-a-z]+://} + host = "#{@controller.request.protocol}#{host}" 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 + "#{host}#{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}" + # 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 - 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 + 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) + @@asset_timestamps_cache = {} + @@asset_timestamps_cache_guard = Mutex.new + + # 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 + if @@cache_asset_timestamps && (asset_id = @@asset_timestamps_cache[source]) + asset_id + else + path = File.join(ASSETS_DIR, source) + asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : '' - if File.exist?(path) - File.mtime(path).to_i.to_s - else - '' + if @@cache_asset_timestamps + @@asset_timestamps_cache_guard.synchronize do + @@asset_timestamps_cache[source] = asset_id 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 + asset_id end + end end - class ImageTag < AssetTag - include ImageAsset + # 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 end - class JavaScriptTag < AssetTag - include JavaScriptAsset + def javascript_src_tag(source, options) + content_tag("script", "", { "type" => Mime::JS, "src" => path_to_javascript(source) }.merge(options)) end - class StylesheetTag < AssetTag - include StylesheetAsset + 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 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 compute_javascript_paths(*args) + expand_javascript_sources(*args).collect { |source| compute_public_path(source, 'javascripts', 'js', false) } + 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 diff --git a/actionpack/lib/action_view/helpers/benchmark_helper.rb b/actionpack/lib/action_view/helpers/benchmark_helper.rb index 372d24a22e..61c2cecb04 100644 --- a/actionpack/lib/action_view/helpers/benchmark_helper.rb +++ b/actionpack/lib/action_view/helpers/benchmark_helper.rb @@ -18,12 +18,33 @@ module ActionView # That would add something like "Process data files (345.2ms)" to the log, # which you can then use to compare timings when optimizing your code. # - # You may give an optional logger level as the second argument + # You may give an optional logger level as the :level option. # (:debug, :info, :warn, :error); the default value is :info. - def benchmark(message = "Benchmarking", level = :info) + # + # <% benchmark "Low-level files", :level => :debug do %> + # <%= lowlevel_files_operation %> + # <% end %> + # + # Finally, you can pass true as the third argument to silence all log activity + # inside the block. This is great for boiling down a noisy block to just a single statement: + # + # <% benchmark "Process data files", :level => :info, :silence => true do %> + # <%= expensive_and_chatty_files_operation %> + # <% end %> + def benchmark(message = "Benchmarking", options = {}) if controller.logger - ms = Benchmark.ms { yield } - controller.logger.send(level, '%s (%.1fms)' % [message, ms]) + if options.is_a?(Symbol) + ActiveSupport::Deprecation.warn("use benchmark('#{message}', :level => :#{options}) instead", caller) + options = { :level => options, :silence => false } + else + options.assert_valid_keys(:level, :silence) + options[:level] ||= :info + end + + result = nil + ms = Benchmark.ms { result = options[:silence] ? controller.logger.silence { yield } : yield } + controller.logger.send(options[:level], '%s (%.1fms)' % [ message, ms ]) + result else yield end diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/inline_template.rb index 5e00cef13f..54efa543c8 100644 --- a/actionpack/lib/action_view/inline_template.rb +++ b/actionpack/lib/action_view/inline_template.rb @@ -12,7 +12,7 @@ module ActionView #:nodoc: private # Always recompile inline templates - def recompile?(local_assigns) + def recompile? true end end diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index b030156889..19207e7262 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -2,7 +2,7 @@ module ActionView #:nodoc: class PathSet < Array #:nodoc: def self.type_cast(obj) if obj.is_a?(String) - Path.new(obj) + Template::EagerPath.new(obj) else obj end @@ -32,111 +32,6 @@ module ActionView #:nodoc: super(*objs.map { |obj| self.class.type_cast(obj) }) end - class Path #:nodoc: - attr_reader :path, :paths - delegate :hash, :inspect, :to => :path - - def initialize(path, load = false) - raise ArgumentError, "path already is a Path class" if path.is_a?(Path) - @path = path.freeze - reload! if load - end - - def to_s - if defined?(RAILS_ROOT) - path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') - else - path.to_s - end - end - - def to_str - path.to_str - end - - def ==(path) - to_str == path.to_str - end - - def eql?(path) - to_str == path.to_str - end - - # Returns a ActionView::Template object for the given path string. The - # input path should be relative to the view path directory, - # +hello/index.html.erb+. This method also has a special exception to - # match partial file names without a handler extension. So - # +hello/index.html+ will match the first template it finds with a - # known template extension, +hello/index.html.erb+. Template extensions - # should not be confused with format extensions +html+, +js+, +xml+, - # etc. A format must be supplied to match a formated file. +hello/index+ - # will never match +hello/index.html.erb+. - # - # This method also has two different implementations, one that is "lazy" - # and makes file system calls every time and the other is cached, - # "eager" which looks up the template in an in memory index. The "lazy" - # version is designed for development where you want to automatically - # find new templates between requests. The "eager" version is designed - # for production mode and it is much faster but requires more time - # upfront to build the file index. - def [](path) - if loaded? - @paths[path] - else - Dir.glob("#{@path}/#{path}*").each do |file| - template = create_template(file) - if template.accessible_paths.include?(path) - return template - end - end - nil - end - end - - def loaded? - @loaded ? true : false - end - - def load - reload! unless loaded? - self - end - - # Rebuild load path directory cache - def reload! - @paths = {} - - templates_in_path do |template| - template.load! - template.accessible_paths.each do |path| - @paths[path] = template - end - end - - @paths.freeze - @loaded = true - end - - private - def templates_in_path - (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file| - yield create_template(file) unless File.directory?(file) - end - end - - def create_template(file) - Template.new(file.split("#{self}/").last, self) - end - end - - def load - each { |path| path.load } - end - - def reload! - each { |path| path.reload! } - end - def find_template(original_template_path, format = nil) return original_template_path if original_template_path.respond_to?(:render) template_path = original_template_path.sub(/^\//, '') diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index d8e72f1179..153e14f68b 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -60,7 +60,7 @@ module ActionView def compile(local_assigns) render_symbol = method_name(local_assigns) - if recompile?(render_symbol) + if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile? compile!(render_symbol, local_assigns) end end @@ -89,11 +89,8 @@ module ActionView end end - # Method to check whether template compilation is necessary. - # The template will be compiled if the file has not been compiled yet, or - # if local_assigns has a new key, which isn't supported by the compiled code yet. - def recompile?(symbol) - !Base::CompiledTemplates.method_defined?(symbol) || !loaded? + def recompile? + false end end end diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb index d92ff1b8d3..3ea836fa25 100644 --- a/actionpack/lib/action_view/renderable_partial.rb +++ b/actionpack/lib/action_view/renderable_partial.rb @@ -25,12 +25,11 @@ module ActionView end def render_partial(view, object = nil, local_assigns = {}, as = nil) - object ||= local_assigns[:object] || - local_assigns[variable_name] + object ||= local_assigns[:object] || local_assigns[variable_name] - if view.respond_to?(:controller) + if object.nil? && view.respond_to?(:controller) ivar = :"@#{variable_name}" - object ||= + object = if view.controller.instance_variable_defined?(ivar) ActiveSupport::Deprecation::DeprecatedObjectProxy.new( view.controller.instance_variable_get(ivar), diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 5b384d0e4d..88ee07d95b 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,5 +1,83 @@ module ActionView #:nodoc: class Template + class Path + attr_reader :path, :paths + delegate :hash, :inspect, :to => :path + + def initialize(path) + raise ArgumentError, "path already is a Path class" if path.is_a?(Path) + @path = path.freeze + end + + def to_s + if defined?(RAILS_ROOT) + path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') + else + path.to_s + end + end + + def to_str + path.to_str + end + + def ==(path) + to_str == path.to_str + end + + def eql?(path) + to_str == path.to_str + end + + # Returns a ActionView::Template object for the given path string. The + # input path should be relative to the view path directory, + # +hello/index.html.erb+. This method also has a special exception to + # match partial file names without a handler extension. So + # +hello/index.html+ will match the first template it finds with a + # known template extension, +hello/index.html.erb+. Template extensions + # should not be confused with format extensions +html+, +js+, +xml+, + # etc. A format must be supplied to match a formated file. +hello/index+ + # will never match +hello/index.html.erb+. + def [](path) + templates_in_path do |template| + if template.accessible_paths.include?(path) + return template + end + end + nil + end + + private + def templates_in_path + (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file| + yield create_template(file) unless File.directory?(file) + end + end + + def create_template(file) + Template.new(file.split("#{self}/").last, self) + end + end + + class EagerPath < Path + def initialize(path) + super + + @paths = {} + templates_in_path do |template| + template.load! + template.accessible_paths.each do |path| + @paths[path] = template + end + end + @paths.freeze + end + + def [](path) + @paths[path] + end + end + extend TemplateHandlers extend ActiveSupport::Memoizable include Renderable @@ -115,13 +193,12 @@ module ActionView #:nodoc: File.mtime(filename) > mtime end - def loaded? - @loaded + def recompile? + !@cached end def load! - @loaded = true - compile({}) + @cached = true freeze end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 1a9ef983a5..ec337bb05b 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,3 +1,5 @@ +require 'active_support/test_case' + module ActionView class Base alias_method :initialize_without_template_tracking, :initialize @@ -21,6 +23,7 @@ module ActionView class TestCase < ActiveSupport::TestCase include ActionController::TestCase::Assertions + include ActionController::TestProcess class_inheritable_accessor :helper_class @@helper_class = nil |