diff options
23 files changed, 343 insertions, 284 deletions
diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 1d0738588d..2063df54b4 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -494,8 +494,18 @@ module ActionController #:nodoc: end protected :filter_parameters end + + @@exempt_from_layout = [ActionView::TemplateHandlers::RJS] + + def exempt_from_layout(*types) + types.each do |type| + @@exempt_from_layout << + ActionView::Template.handler_class_for_extension(type) + end + + @@exempt_from_layout + end - delegate :exempt_from_layout, :to => 'ActionView::Template' end public @@ -856,13 +866,13 @@ module ActionController #:nodoc: return (performed? ? ret : default_render) if called begin - default_render - rescue ActionView::MissingTemplate => e - raise e unless e.action_name == action_name - # If the path is the same as the action_name, the action is completely missing + view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path) + rescue => e raise UnknownAction, "No action responded to #{action_name}. Actions: " + "#{action_methods.sort.to_sentence}", caller end + + default_render end # Returns true if a render or redirect has already been performed. diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 601c5429c3..4286577ec5 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -378,13 +378,14 @@ module ActionController # ==== Arguments # parts<Array[String, Array[Symbol*], String, Boolean]>:: # Example: ["show", [:html, :xml], "users", false] - def render_for_parts(parts, layout, options = {}) + def render_for_parts(parts, layout_details, options = {}) parts[1] = {:formats => parts[1], :locales => [I18n.locale]} tmp = view_paths.find_by_parts(*parts) - layout = _pick_layout(*layout) unless tmp.exempt_from_layout? - + layout = _pick_layout(*layout_details) unless + self.class.exempt_from_layout.include?(tmp.handler) + render_for_text( @template._render_template_with_layout(tmp, layout, options, parts[3])) end diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index c57cbecc44..574b8d6825 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -98,22 +98,22 @@ module ActionController clean_backtrace do case options when NilClass, String - rendered = @controller.response.rendered[:template].to_s + rendered = (@controller.response.rendered[:template] || []).map { |t| t.identifier } msg = build_message(message, "expecting <?> but rendering with <?>", - options, rendered) + options, rendered.join(', ')) assert_block(msg) do if options.nil? @controller.response.rendered[:template].blank? else - rendered.to_s.match(options) + rendered.any? { |t| t.match(options) } end end when Hash if expected_partial = options[:partial] partials = @controller.response.rendered[:partials] if expected_count = options[:count] - found = partials.detect { |p, _| p.to_s.match(expected_partial) } + found = partials.detect { |p, _| p.identifier.match(expected_partial) } actual_count = found.nil? ? 0 : found.second msg = build_message(message, "expecting ? to be rendered ? time(s) but rendered ? time(s)", @@ -123,7 +123,7 @@ module ActionController msg = build_message(message, "expecting partial <?> but action rendered <?>", options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.to_s.match(expected_partial) }, msg) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) end else assert @controller.response.rendered[:partials].empty?, diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index efed19a21d..d087395361 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -196,7 +196,9 @@ module ActionView #:nodoc: delegate :controller_path, :to => :controller, :allow_nil => true delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :action_name, :controller_name, :to => :controller + :flash, :action_name, :controller_name, :to => :controller + + delegate :logger, :to => :controller, :allow_nil => true delegate :find_by_parts, :to => :view_paths diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index e48088f344..f6d021c92a 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -3,7 +3,7 @@ module ActionView #:nodoc: def self.type_cast(obj) if obj.is_a?(String) cache = !Object.const_defined?(:Rails) || Rails.configuration.cache_classes - Template::FileSystemPath.new(obj, :cache => cache) + Template::FileSystemPathWithFallback.new(obj, :cache => cache) else obj end @@ -34,18 +34,18 @@ module ActionView #:nodoc: end def find_by_parts(path, details = {}, prefix = nil, partial = false) - template_path = path.sub(/^\//, '') + # template_path = path.sub(/^\//, '') + template_path = path each do |load_path| if template = load_path.find_by_parts(template_path, details, prefix, partial) return template end end - - Template.new(path, self) - rescue ActionView::MissingTemplate => e + + # TODO: Have a fallback absolute path? extension = details[:formats] || [] - raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}") + raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}") end def find_by_parts?(path, extension = nil, prefix = nil, partial = false) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 4213b09e48..f174053b86 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -46,8 +46,8 @@ module ActionView locals ||= {} if controller && layout - response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response) - logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger + response.layout = layout.identifier if controller.respond_to?(:response) + logger.info("Rendering template within #{layout.identifier}") if logger end begin @@ -76,7 +76,6 @@ module ActionView end end rescue Exception => e - raise e if template.is_a?(InlineTemplate) || !template.filename if TemplateError === e e.sub_template_of(template) raise e @@ -86,7 +85,9 @@ module ActionView end def _render_inline(inline, layout, options) - content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {}) + handler = Template.handler_class_for_extension(options[:type] || "erb") + template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) + content = _render_template(template, options[:locals] || {}) layout ? _render_content_with_layout(content, layout, options[:locals]) : content end @@ -96,7 +97,7 @@ module ActionView def _render_template_with_layout(template, layout = nil, options = {}, partial = false) if controller && logger - logger.info("Rendering #{template.path_without_extension}" + + logger.info("Rendering #{template.identifier}" + (options[:status] ? " (#{options[:status]})" : '')) end @@ -107,7 +108,7 @@ module ActionView _render_template(template, options[:locals] || {}) end - return content unless layout && !template.exempt_from_layout? + return content unless layout _render_content_with_layout(content, layout, options[:locals] || {}) end end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 37cb1c7c6c..a06e80b294 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -12,7 +12,7 @@ module ActionView end def file_name - @template.relative_path + @template.identifier end def message @@ -30,7 +30,7 @@ module ActionView def sub_template_message if @sub_templates "Trace of template inclusion: " + - @sub_templates.collect { |template| template.relative_path }.join(", ") + @sub_templates.collect { |template| template.identifier }.join(", ") else "" end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 448ab6731b..0590372d09 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -46,7 +46,7 @@ module ActionView #:nodoc: end def handler_class_for_extension(extension) - registered_template_handler(extension) || @@default_template_handlers + (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers end end end diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb index 660a7e91a2..478bf96c9a 100644 --- a/actionpack/lib/action_view/template/path.rb +++ b/actionpack/lib/action_view/template/path.rb @@ -1,3 +1,5 @@ +require "pathname" + module ActionView class Template # Abstract super class @@ -26,13 +28,6 @@ module ActionView def find_templates(name, details, prefix, partial) raise NotImplementedError end - - # TODO: Refactor this to abstract out the file system - def initialize_template(file) - t = Template.new(file.split("#{self}/").last, self) - t.load! - t - end def valid_handlers @valid_handlers ||= TemplateHandlers.extensions @@ -44,10 +39,10 @@ module ActionView /\.(?:#{e})$/ end end - + def handler_glob - e = TemplateHandlers.extensions.join(',') - ".{#{e}}" + e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + "{#{e}}" end def formats_glob @@ -69,23 +64,19 @@ module ActionView def initialize(path, options = {}) raise ArgumentError, "path already is a Path class" if path.is_a?(Path) super(options) - @path = path + @path = Pathname.new(path).expand_path end - + # TODO: This is the currently needed API. Make this suck less # ==== <suck> attr_reader :path def to_s - if defined?(RAILS_ROOT) - path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') - else - path.to_s - end + path.to_s end def to_str - path.to_str + path.to_s end def ==(path) @@ -97,11 +88,15 @@ module ActionView end # ==== </suck> - def find_templates(name, details, prefix, partial) - if glob = parts_to_glob(name, details, prefix, partial) + def find_templates(name, details, prefix, partial, root = "#{@path}/") + if glob = details_to_glob(name, details, prefix, partial, root) cached(glob) do Dir[glob].map do |path| - initialize_template(path) unless File.directory?(path) + next if File.directory?(path) + source = File.read(path) + identifier = Pathname.new(path).expand_path.to_s + + Template.new(source, identifier, *path_to_details(path)) end.compact end end @@ -109,7 +104,8 @@ module ActionView private - def parts_to_glob(name, details, prefix, partial) + # :api: plugin + def details_to_glob(name, details, prefix, partial, root) path = "" path << "#{prefix}/" unless prefix.empty? path << (partial ? "_#{name}" : name) @@ -123,8 +119,34 @@ module ActionView end end - "#{@path}/#{path}#{extensions}#{handler_glob}" + "#{root}#{path}#{extensions}#{handler_glob}" + end + + # TODO: fix me + # :api: plugin + def path_to_details(path) + # [:erb, :format => :html, :locale => :en, :partial => true/false] + if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$') + partial = m[1] == '_' + details = (m[2]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[3]) + + format = Mime[details.last] && details.pop.to_sym + locale = details.last && details.pop.to_sym + + return handler, :format => format, :locale => locale, :partial => partial + end end end + + class FileSystemPathWithFallback < FileSystemPath + + def find_templates(name, details, prefix, partial) + templates = super + return super(name, details, prefix, partial, '') if templates.empty? + templates + end + + end end end
\ No newline at end of file diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index e541336613..ce6268729a 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -1,188 +1,230 @@ +# encoding: utf-8 +# This is so that templates compiled in this file are UTF-8 + require 'set' require "action_view/template/path" -module ActionView #:nodoc: +module ActionView class Template extend TemplateHandlers - extend ActiveSupport::Memoizable + attr_reader :source, :identifier, :handler - module Loading - def load! - @cached = true - # freeze - end + def initialize(source, identifier, handler, details) + @source = source + @identifier = identifier + @handler = handler + @details = details end - include Loading - include Renderable - - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - - # Don't render layouts for templates with the given extensions. - def self.exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge(regexps) + def render(view, locals, &blk) + method_name = compile(locals, view) + view.send(method_name, locals, &blk) + end + + # TODO: Figure out how to abstract this + def variable_name + identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym end - attr_accessor :template_path, :filename, :load_path, :base_path - attr_accessor :locale, :name, :format, :extension - delegate :to_s, :to => :path + # TODO: Figure out how to abstract this + def counter_name + "#{variable_name}_counter".to_sym + end + + # TODO: kill hax + def partial? + @details[:partial] + end + + # TODO: Move out of Template + def mime_type + Mime::Type.lookup_by_extension(@details[:format]) if @details[:format] + end + + private - def initialize(template_path, load_paths = []) - template_path = template_path.dup - @load_path, @filename = find_full_path(template_path, load_paths) - @base_path, @name, @locale, @format, @extension = split(template_path) - @base_path.to_s.gsub!(/\/$/, '') # Push to split method + def compile(locals, view) + method_name = build_method_name(locals) + + return method_name if view.respond_to?(method_name) + + locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + + source = <<-end_src + def #{method_name}(local_assigns) + old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)} + ensure + self.output_buffer = old_output_buffer + end + end_src + + begin + ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0) + method_name + rescue Exception => e # errors from template code + if logger = (view && view.logger) + logger.debug "ERROR: compiling #{method_name} RAISED #{e}" + logger.debug "Function body: #{source}" + logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end - # Extend with partial super powers - extend RenderablePartial if @name =~ /^_/ + raise ActionView::TemplateError.new(self, {}, e) + end + end + + def build_method_name(locals) + # TODO: is locals.keys.hash reliably the same? + "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end + end +end + +if false + module ActionView #:nodoc: + class Template + extend TemplateHandlers + extend ActiveSupport::Memoizable - def accessible_paths - paths = [] + module Loading + def load! + @cached = true + # freeze + end + end + include Loading + + include Renderable - if valid_extension?(extension) - paths << path - paths << path_without_extension - if multipart? - formats = format.split(".") - paths << "#{path_without_format_and_extension}.#{formats.first}" - paths << "#{path_without_format_and_extension}.#{formats.second}" + # Templates that are exempt from layouts + @@exempt_from_layout = Set.new([/\.rjs$/]) + + # Don't render layouts for templates with the given extensions. + def self.exempt_from_layout(*extensions) + regexps = extensions.collect do |extension| + extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ end - else - # template without explicit template handler should only be reachable through its exact path - paths << template_path + @@exempt_from_layout.merge(regexps) end - paths - end + attr_accessor :template_path, :filename, :load_path, :base_path + attr_accessor :locale, :name, :format, :extension + delegate :to_s, :to => :path + + def initialize(template_path, load_paths = []) + template_path = template_path.dup + @load_path, @filename = find_full_path(template_path, load_paths) + @name = template_path.to_s.split("/").last.split(".").first + # @base_path, @name, @locale, @format, @extension = split(template_path) + @base_path.to_s.gsub!(/\/$/, '') # Push to split method + + # Extend with partial super powers + extend RenderablePartial if @name =~ /^_/ + end - def relative_path - path = File.expand_path(filename) - path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) - path - end - memoize :relative_path + def accessible_paths + paths = [] + + if valid_extension?(extension) + paths << path + paths << path_without_extension + if multipart? + formats = format.split(".") + paths << "#{path_without_format_and_extension}.#{formats.first}" + paths << "#{path_without_format_and_extension}.#{formats.second}" + end + else + # template without explicit template handler should only be reachable through its exact path + paths << template_path + end + + paths + end - def source - File.read(filename) - end - memoize :source + def relative_path + path = File.expand_path(filename) + path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) + path + end + memoize :relative_path - def exempt_from_layout? - @@exempt_from_layout.any? { |exempted| path =~ exempted } - end + def source + File.read(filename) + end + memoize :source - def path_without_extension - [base_path, [name, locale, format].compact.join('.')].compact.join('/') - end - memoize :path_without_extension + def exempt_from_layout? + @@exempt_from_layout.any? { |exempted| path =~ exempted } + end + + def path_without_extension + [base_path, [name, locale, format].compact.join('.')].compact.join('/') + end + memoize :path_without_extension - def path_without_format_and_extension - [base_path, [name, locale].compact.join('.')].compact.join('/') - end - memoize :path_without_format_and_extension + def path_without_format_and_extension + [base_path, [name, locale].compact.join('.')].compact.join('/') + end + memoize :path_without_format_and_extension - def path - [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') - end - memoize :path + def path + [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') + end + memoize :path - def mime_type - Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) - end - memoize :mime_type + def mime_type + Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) + end + memoize :mime_type - def multipart? - format && format.include?('.') - end + def multipart? + format && format.include?('.') + end - def content_type - format && format.gsub('.', '/') - end + def content_type + format && format.gsub('.', '/') + end - private + private - def format_and_extension - (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions - end - memoize :format_and_extension - - def mtime - File.mtime(filename) - end - memoize :mtime + def format_and_extension + (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions + end + memoize :format_and_extension - def method_segment - relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } - end - memoize :method_segment + def mtime + File.mtime(filename) + end + memoize :mtime - def stale? - File.mtime(filename) > mtime - end + def method_segment + relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } + end + memoize :method_segment - def recompile? - !@cached - end + def stale? + File.mtime(filename) > mtime + end - def valid_extension?(extension) - !Template.registered_template_handler(extension).nil? - end + def recompile? + !@cached + end - def valid_locale?(locale) - I18n.available_locales.include?(locale.to_sym) - end + def valid_extension?(extension) + !Template.registered_template_handler(extension).nil? + end - def find_full_path(path, load_paths) - load_paths = Array(load_paths) + [nil] - load_paths.each do |load_path| - file = load_path ? "#{load_path.to_str}/#{path}" : path - return load_path, file if File.file?(file) + def valid_locale?(locale) + I18n.available_locales.include?(locale.to_sym) end - raise MissingTemplate.new(load_paths, path) - end - # Returns file split into an array - # [base_path, name, locale, format, extension] - def split(file) - if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/) - base_path = m[1] - name = m[2] - extensions = m[3] - else - return - end - - locale = nil - format = nil - extension = nil - - if m = extensions.split(".") - if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three - locale = m[0] - format = m[1] - extension = m[2] - elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats - format = "#{m[0]}.#{m[1]}" - extension = m[2] - elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension - locale = m[0] - extension = m[1] - elsif valid_extension?(m[1]) # format and extension - format = m[0] - extension = m[1] - elsif valid_extension?(m[0]) # Just extension - extension = m[0] - else # No extension - format = m[0] + def find_full_path(path, load_paths) + load_paths = Array(load_paths) + [nil] + load_paths.each do |load_path| + file = load_path ? "#{load_path.to_str}/#{path}" : path + return load_path, file if File.file?(file) end + raise MissingTemplate.new(load_paths, path) end - - [base_path, name, locale, format, extension] end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index c8f204046b..dddd671812 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -10,9 +10,10 @@ module ActionView alias_method :_render_template_without_template_tracking, :_render_template def _render_template(template, local_assigns = {}) - if template.respond_to?(:path) && !template.is_a?(InlineTemplate) - @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial) - @_rendered[:template] ||= template + if template.respond_to?(:identifier) + @_rendered[:partials][template] += 1 if template.partial? + @_rendered[:template] ||= [] + @_rendered[:template] << template end _render_template_without_template_tracking(template, local_assigns) end diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index f1dcb39ef1..331797afcf 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -139,7 +139,7 @@ module AbstractController private def self.layout(formats) begin - view_paths.find_by_parts(name.underscore, {:formats => formats}t, "layouts") + view_paths.find_by_parts(name.underscore, {:formats => formats}, "layouts") rescue ActionView::MissingTemplate begin view_paths.find_by_parts("application", {:formats => formats}, "layouts") diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 5f36461b89..58addc123d 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -211,7 +211,7 @@ class IsolatedHelpersTest < Test::Unit::TestCase end def test_helper_in_a - assert_raise(NameError) { A.process(@request, @response) } + assert_raise(ActionView::TemplateError) { A.process(@request, @response) } end def test_helper_in_b diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index f2721e274d..11559b4071 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -56,8 +56,8 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase def test_third_party_template_library_auto_discovers_layout @controller = ThirdPartyTemplateLibraryController.new get :hello - assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout(true).to_s - assert_equal 'layouts/third_party_template_library', @response.layout + assert @controller.active_layout(true).identifier.include?('layouts/third_party_template_library.mab') + assert @response.layout.include?('layouts/third_party_template_library') assert_response :success assert_equal 'Mab', @response.body end @@ -72,7 +72,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase def test_namespaced_controllers_auto_detect_layouts @controller = MultipleExtensions.new get :hello - assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout(true).to_s + assert @controller.active_layout(true).identifier.include?('layouts/multiple_extensions.html.erb') assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip end end @@ -116,22 +116,24 @@ class RendersNoLayoutController < LayoutTest end class LayoutSetInResponseTest < ActionController::TestCase + include ActionView::TemplateHandlers + def test_layout_set_when_using_default_layout @controller = DefaultLayoutController.new get :hello - assert_equal 'layouts/layout_test', @response.layout + assert @response.layout.include?('layouts/layout_test') end def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_only_exception_when_included @controller = OnlyLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_only_exception_when_excepted @@ -143,7 +145,7 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_except_exception_when_included @controller = ExceptLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_except_exception_when_excepted @@ -155,7 +157,7 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_render @controller = SetsLayoutInRenderController.new get :hello - assert_equal 'layouts/third_party_template_library', @response.layout + assert @response.layout.include?('layouts/third_party_template_library') end def test_layout_is_not_set_when_none_rendered @@ -165,14 +167,14 @@ class LayoutSetInResponseTest < ActionController::TestCase end def test_exempt_from_layout_honored_by_render_template - ActionController::Base.exempt_from_layout :rhtml + ActionController::Base.exempt_from_layout :erb @controller = RenderWithTemplateOptionController.new get :hello assert_equal "alt/hello.rhtml", @response.body.strip ensure - ActionController::Base.exempt_from_layout.delete(/\.rhtml$/) + ActionController::Base.exempt_from_layout.delete(ERB) end def test_layout_is_picked_from_the_controller_instances_view_path @@ -232,7 +234,7 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/ @controller = LayoutSymlinkedTest.new get :hello assert_response 200 - assert_equal "layouts/symlinked/symlinked_layout", @response.layout + assert @response.layout.include?("layouts/symlinked/symlinked_layout") end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index af7236ed26..da063710a9 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -773,7 +773,7 @@ class RenderTest < ActionController::TestCase begin get :render_line_offset flunk "the action should have raised an exception" - rescue RuntimeError => exc + rescue StandardError => exc line = exc.backtrace.first assert(line =~ %r{:(\d+):}) assert_equal "1", $1, @@ -1736,7 +1736,7 @@ class RenderingLoggingTest < ActionController::TestCase @controller.logger = MockLogger.new get :layout_test logged = @controller.logger.logged.find_all {|l| l =~ /render/i } - assert_equal "Rendering test/hello_world", logged[0] - assert_equal "Rendering template within layouts/standard", logged[1] + assert logged[0] =~ %r{Rendering.*test/hello_world} + assert logged[1] =~ %r{Rendering template within.*layouts/standard} end end diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index 1539f8f506..0ac10634b2 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -20,7 +20,7 @@ class ViewLoadPathsTest < ActionController::TestCase layout 'test/sub' def hello_world; render(:template => 'test/hello_world'); end end - + def setup TestController.view_paths = nil @@ -42,30 +42,39 @@ class ViewLoadPathsTest < ActionController::TestCase ActiveSupport::Deprecation.behavior = @old_behavior end + def expand(array) + array.map {|x| File.expand_path(x)} + end + + def assert_paths(*paths) + controller = paths.first.is_a?(Class) ? paths.shift : @controller + assert_equal expand(paths), controller.view_paths.map(&:to_s) + end + def test_template_load_path_was_set_correctly - assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH end def test_controller_appends_view_path_correctly @controller.append_view_path 'foo' - assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s) + assert_paths(FIXTURE_LOAD_PATH, "foo") @controller.append_view_path(%w(bar baz)) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) - + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz") + @controller.append_view_path(FIXTURE_LOAD_PATH) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH) end def test_controller_prepends_view_path_correctly @controller.prepend_view_path 'baz' - assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths("baz", FIXTURE_LOAD_PATH) @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH @controller.prepend_view_path(FIXTURE_LOAD_PATH) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH end def test_template_appends_view_path_correctly @@ -73,11 +82,11 @@ class ViewLoadPathsTest < ActionController::TestCase class_view_paths = TestController.view_paths @controller.append_view_path 'foo' - assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH, "foo" @controller.append_view_path(%w(bar baz)) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) - assert_equal class_view_paths, TestController.view_paths + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz" + assert_paths TestController, *class_view_paths end def test_template_prepends_view_path_correctly @@ -85,11 +94,11 @@ class ViewLoadPathsTest < ActionController::TestCase class_view_paths = TestController.view_paths @controller.prepend_view_path 'baz' - assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths "baz", FIXTURE_LOAD_PATH @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) - assert_equal class_view_paths, TestController.view_paths + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH + assert_paths TestController, *class_view_paths end def test_view_paths @@ -130,12 +139,12 @@ class ViewLoadPathsTest < ActionController::TestCase A.view_paths = ['a/path'] - assert_equal ['a/path'], A.view_paths.map(&:to_s) - assert_equal A.view_paths, B.view_paths - assert_equal original_load_paths, C.view_paths - + assert_paths A, "a/path" + assert_paths A, *B.view_paths + assert_paths C, *original_load_paths + C.view_paths = [] assert_nothing_raised { C.view_paths << 'c/path' } - assert_equal ['c/path'], C.view_paths.map(&:to_s) + assert_paths C, "c/path" end end diff --git a/actionpack/test/fixtures/layouts/standard.erb b/actionpack/test/fixtures/layouts/standard.html.erb index 368764e6f4..368764e6f4 100644 --- a/actionpack/test/fixtures/layouts/standard.erb +++ b/actionpack/test/fixtures/layouts/standard.html.erb diff --git a/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb b/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb new file mode 100644 index 0000000000..9b4900acc5 --- /dev/null +++ b/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb @@ -0,0 +1 @@ +<%= secret ||= 'one' %>
\ No newline at end of file diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index c75e29ed9a..b29b03f99d 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -5,37 +5,13 @@ class CompiledTemplatesTest < Test::Unit::TestCase def setup @compiled_templates = ActionView::Base::CompiledTemplates @compiled_templates.instance_methods.each do |m| - @compiled_templates.send(:remove_method, m) if m =~ /^_run_/ + @compiled_templates.send(:remove_method, m) if m =~ /^_render_template_/ end end - - def test_template_gets_compiled - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - assert_equal 1, @compiled_templates.instance_methods.size - end - + def test_template_gets_recompiled_when_using_different_keys_in_local_assigns - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"}) - assert_equal 2, @compiled_templates.instance_methods.size - end - - def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - ActionView::Template.any_instance.expects(:compile!).never - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - end - - def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached - ActionView::Template.any_instance.expects(:recompile?).times(3).returns(true) - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") - ActionView::Template.any_instance.expects(:compile!).times(3) - 3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") } - assert_equal 1, @compiled_templates.instance_methods.size + assert_equal "one", render(:file => "test/render_file_with_locals_and_default.erb") + assert_equal "two", render(:file => "test/render_file_with_locals_and_default.erb", :locals => { :secret => "two" }) end def test_template_changes_are_not_reflected_with_cached_templates @@ -61,14 +37,12 @@ class CompiledTemplatesTest < Test::Unit::TestCase def render_with_cache(*args) view_paths = ActionController::Base.view_paths - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end def render_without_cache(*args) - path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH) + path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH) view_paths = ActionView::Base.process_view_paths(path) - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 7191df0dfd..71291f009c 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -91,10 +91,6 @@ module RenderTestCases assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar") end - def test_render_has_access_current_template - assert_equal "test/template.erb", @view.render(:file => "test/template.erb") - end - def test_render_update # TODO: You should not have to stub out template because template is self! @view.instance_variable_set(:@template, @view) @@ -240,10 +236,6 @@ module RenderTestCases end end - def test_template_with_malformed_template_handler_is_reachable_through_its_exact_filename - assert_equal "Don't render me!", @view.render(:file => 'test/malformed/malformed.html.erb~') - end - def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield") @@ -269,7 +261,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase # Ensure view path cache is primed def setup view_paths = ActionController::Base.view_paths - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class + assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class setup_view(view_paths) end end @@ -280,9 +272,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase # Test the same thing as above, but make sure the view path # is not eager loaded def setup - path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH) + path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH) view_paths = ActionView::Base.process_view_paths(path) - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class + assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class setup_view(view_paths) end end diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index fb4b5f0f3c..a44344806d 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -110,8 +110,10 @@ class Module allow_nil = options[:allow_nil] && "#{to} && " + file, line = caller[0].split(":") + methods.each do |method| - module_eval(<<-EOS, "(__DELEGATION__)", 1) + module_eval(<<-EOS, file, line.to_i) def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{allow_nil}#{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block) end # end diff --git a/railties/test/plugin_loader_test.rb b/railties/test/plugin_loader_test.rb index b270748dd6..c647d7b478 100644 --- a/railties/test/plugin_loader_test.rb +++ b/railties/test/plugin_loader_test.rb @@ -132,8 +132,8 @@ class TestPluginLoader < Test::Unit::TestCase @loader.send :add_engine_view_paths - assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionController::Base.view_paths - assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionMailer::Base.view_paths + assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionController::Base.view_paths.map { |p| p.to_s } + assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionMailer::Base.view_paths.map { |p| p.to_s } end def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths diff --git a/railties/test/plugin_test_helper.rb b/railties/test/plugin_test_helper.rb index 93d50dc07f..55d1a1fa96 100644 --- a/railties/test/plugin_test_helper.rb +++ b/railties/test/plugin_test_helper.rb @@ -12,7 +12,7 @@ RAILS_ROOT = '.' unless defined?(RAILS_ROOT) class Test::Unit::TestCase private def plugin_fixture_root_path - File.join(File.dirname(__FILE__), 'fixtures', 'plugins') + File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'plugins')) end def only_load_the_following_plugins!(plugins) |