diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2008-06-12 17:48:30 -0500 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2008-06-12 17:48:30 -0500 |
commit | ea3a7e1bb1efc8b3ca10c4163bc116f3d5e23af1 (patch) | |
tree | a3cce25be0c613a8e1444e1d0ff53aaed3497057 /actionpack/lib | |
parent | 556204abaf95f7c995576cb1358f13de406682ab (diff) | |
parent | dd4181f47dc0f166eb5d3e47a4a0dc1594cc5669 (diff) | |
download | rails-ea3a7e1bb1efc8b3ca10c4163bc116f3d5e23af1.tar.gz rails-ea3a7e1bb1efc8b3ca10c4163bc116f3d5e23af1.tar.bz2 rails-ea3a7e1bb1efc8b3ca10c4163bc116f3d5e23af1.zip |
Merge branch 'master' of git@github.com:rails/rails
Diffstat (limited to 'actionpack/lib')
26 files changed, 210 insertions, 256 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index a036600c2b..44269fc735 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -283,13 +283,6 @@ module ActionController #:nodoc: @@debug_routes = true cattr_accessor :debug_routes - # Indicates to Mongrel or Webrick whether to allow concurrent action - # processing. Your controller actions and any other code they call must - # also behave well when called from concurrent threads. Turned off by - # default. - @@allow_concurrency = false - cattr_accessor :allow_concurrency - # Modern REST web services often need to submit complex data to the web application. # The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the # <tt>params</tt> hash. These handlers are invoked for POST and PUT requests. diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index c4b0a97a33..65a36f7f98 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -67,10 +67,10 @@ module ActionController #:nodoc: if options[:action].is_a?(Array) options[:action].dup.each do |action| - expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }))) + expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action }), false)) end else - expire_fragment(ActionCachePath.path_for(self, options)) + expire_fragment(ActionCachePath.path_for(self, options, false)) end end @@ -125,16 +125,24 @@ module ActionController #:nodoc: attr_reader :path, :extension class << self - def path_for(controller, options) - new(controller, options).path + def path_for(controller, options, infer_extension=true) + new(controller, options, infer_extension).path end end - - def initialize(controller, options = {}) - @extension = extract_extension(controller.request.path) + + # When true, infer_extension will look up the cache path extension from the request's path & format. + # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format. + def initialize(controller, options = {}, infer_extension=true) + if infer_extension and options.is_a? Hash + request_extension = extract_extension(controller.request) + options = options.reverse_merge(:format => request_extension) + end path = controller.url_for(options).split('://').last normalize!(path) - add_extension!(path, @extension) + if infer_extension + @extension = request_extension + add_extension!(path, @extension) + end @path = URI.unescape(path) end @@ -144,13 +152,22 @@ module ActionController #:nodoc: end def add_extension!(path, extension) - path << ".#{extension}" if extension + path << ".#{extension}" if extension and !path.ends_with?(extension) end - - def extract_extension(file_path) + + def extract_extension(request) # Don't want just what comes after the last '.' to accommodate multi part extensions # such as tar.gz. - file_path[/^[^.]+\.(.+)$/, 1] + extension = request.path[/^[^.]+\.(.+)$/, 1] + + # If there's no extension in the path, check request.format + if extension.nil? + extension = request.format.to_sym.to_s + if extension=='all' + extension = nil + end + end + extension end end end diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb index 37b56dabca..9b4aa9b7cf 100644 --- a/actionpack/lib/action_controller/rack_process.rb +++ b/actionpack/lib/action_controller/rack_process.rb @@ -189,6 +189,8 @@ end_msg if @body.respond_to?(:call) @writer = lambda { |x| callback.call(x) } @body.call(self, self) + elsif @body.is_a?(String) + @body.each_line(&callback) else @body.each(&callback) end diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 643ff7e5f4..f69c3d6163 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -31,18 +31,21 @@ module ActionController module RecordIdentifier extend self + JOIN = '_'.freeze + NEW = 'new'.freeze + # Returns plural/singular for a record or class. Example: # # partial_path(post) # => "posts/post" # partial_path(Person) # => "people/person" # partial_path(Person, "admin/games") # => "admin/people/person" def partial_path(record_or_class, controller_path = nil) - klass = class_from_record_or_class(record_or_class) + name = model_name_from_record_or_class(record_or_class) if controller_path && controller_path.include?("/") - "#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + "#{File.dirname(controller_path)}/#{name.partial_path}" else - "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + name.partial_path end end @@ -56,7 +59,8 @@ module ActionController # dom_class(post, :edit) # => "edit_post" # dom_class(Person, :edit) # => "edit_person" def dom_class(record_or_class, prefix = nil) - [ prefix, singular_class_name(record_or_class) ].compact * '_' + singular = singular_class_name(record_or_class) + prefix ? "#{prefix}#{JOIN}#{singular}" : singular end # The DOM id convention is to use the singular form of an object or class with the id following an underscore. @@ -69,8 +73,11 @@ module ActionController # # dom_id(Post.new(:id => 45), :edit) # => "edit_post_45" def dom_id(record, prefix = nil) - prefix ||= 'new' unless record.id - [ prefix, singular_class_name(record), record.id ].compact * '_' + if record_id = record.id + "#{dom_class(record, prefix)}#{JOIN}#{record_id}" + else + dom_class(record, prefix || NEW) + end end # Returns the plural class name of a record or class. Examples: @@ -78,7 +85,7 @@ module ActionController # plural_class_name(post) # => "posts" # plural_class_name(Highrise::Person) # => "highrise_people" def plural_class_name(record_or_class) - singular_class_name(record_or_class).pluralize + model_name_from_record_or_class(record_or_class).plural end # Returns the singular class name of a record or class. Examples: @@ -86,12 +93,12 @@ module ActionController # singular_class_name(post) # => "post" # singular_class_name(Highrise::Person) # => "highrise_person" def singular_class_name(record_or_class) - class_from_record_or_class(record_or_class).name.underscore.tr('/', '_') + model_name_from_record_or_class(record_or_class).singular end private - def class_from_record_or_class(record_or_class) - record_or_class.is_a?(Class) ? record_or_class : record_or_class.class + def model_name_from_record_or_class(record_or_class) + (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 864e068004..f0ad066bad 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -249,7 +249,7 @@ module ActionController end def extract_value - "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" + "#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" end def default diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session_management.rb index 80a3ddd2c5..ad1013b379 100644 --- a/actionpack/lib/action_controller/session_management.rb +++ b/actionpack/lib/action_controller/session_management.rb @@ -1,10 +1,3 @@ -require 'action_controller/session/cookie_store' -require 'action_controller/session/drb_store' -require 'action_controller/session/mem_cache_store' -if Object.const_defined?(:ActiveRecord) - require 'action_controller/session/active_record_store' -end - module ActionController #:nodoc: module SessionManagement #:nodoc: def self.included(base) @@ -22,6 +15,8 @@ module ActionController #:nodoc: # <tt>:p_store</tt>, <tt>:drb_store</tt>, <tt>:mem_cache_store</tt>, or # <tt>:memory_store</tt>) or your own custom class. def session_store=(store) + require "action_controller/session/#{store.to_s}" if [:active_record_store, :drb_store, :mem_cache_store].include?(store) + ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] = store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store end diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 5f4126e4e9..2f6894a8f9 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -21,12 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'action_view/template_handler' -require 'action_view/template_handlers/compilable' -require 'action_view/template_handlers/builder' -require 'action_view/template_handlers/erb' -require 'action_view/template_handlers/rjs' - +require 'action_view/template_handlers' require 'action_view/template_finder' require 'action_view/template' require 'action_view/partial_template' diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f398756550..c417cc07ac 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -156,10 +156,12 @@ module ActionView #:nodoc: attr_reader :finder attr_accessor :base_path, :assigns, :template_extension, :first_render attr_accessor :controller - + attr_writer :template_format attr_accessor :current_render_extension + attr_accessor :output_buffer + # Specify trim mode for the ERB compiler. Defaults to '-'. # See ERb documentation for suitable values. @@erb_trim_mode = '-' @@ -178,14 +180,11 @@ module ActionView #:nodoc: # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false cattr_accessor :debug_rjs - - @@erb_variable = '_erbout' - cattr_accessor :erb_variable - + attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :action_name, :to => :controller + :flash, :logger, :action_name, :controller_name, :to => :controller module CompiledTemplates #:nodoc: # holds compiled template code @@ -253,12 +252,13 @@ If you are rendering a subtemplate, you must now use controller-like partial syn elsif options == :update update_page(&block) elsif options.is_a?(Hash) + use_full_path = options[:use_full_path] options = options.reverse_merge(:locals => {}, :use_full_path => true) if partial_layout = options.delete(:layout) if block_given? wrap_content_for_layout capture(&block) do - concat(render(options.merge(:partial => partial_layout)), block.binding) + concat(render(options.merge(:partial => partial_layout))) end else wrap_content_for_layout render(options) do @@ -266,7 +266,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn end end elsif options[:file] - render_file(options[:file], options[:use_full_path], options[:locals]) + render_file(options[:file], use_full_path || false, options[:locals]) elsif options[:partial] && options[:collection] render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals]) elsif options[:partial] @@ -316,9 +316,10 @@ If you are rendering a subtemplate, you must now use controller-like partial syn private def wrap_content_for_layout(content) - original_content_for_layout = @content_for_layout - @content_for_layout = content - returning(yield) { @content_for_layout = original_content_for_layout } + original_content_for_layout, @content_for_layout = @content_for_layout, content + yield + ensure + @content_for_layout = original_content_for_layout end # Evaluate the local assigns and pushes them to the view. diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 9ea06568cf..9cd9d3d06a 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -31,20 +31,13 @@ module ActionView # </body></html> # def capture(*args, &block) - # execute the block - begin - buffer = eval(ActionView::Base.erb_variable, block.binding) - rescue - buffer = nil - end - - if buffer.nil? - capture_block(*args, &block).to_s + if output_buffer + with_output_buffer { block.call(*args) } else - capture_erb_with_buffer(buffer, *args, &block).to_s + block.call(*args) end end - + # Calling content_for stores a block of markup in an identifier for later use. # You can make subsequent calls to the stored content in other templates or the layout # by passing the identifier as an argument to <tt>yield</tt>. @@ -121,40 +114,18 @@ module ActionView # named <tt>@content_for_#{name_of_the_content_block}</tt>. The preferred usage is now # <tt><%= yield :footer %></tt>. def content_for(name, content = nil, &block) - existing_content_for = instance_variable_get("@content_for_#{name}").to_s - new_content_for = existing_content_for + (block_given? ? capture(&block) : content) - instance_variable_set("@content_for_#{name}", new_content_for) + ivar = "@content_for_#{name}" + content = capture(&block) if block_given? + instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}") end private - def capture_block(*args, &block) - block.call(*args) - end - - def capture_erb(*args, &block) - buffer = eval(ActionView::Base.erb_variable, block.binding) - capture_erb_with_buffer(buffer, *args, &block) - end - - def capture_erb_with_buffer(buffer, *args, &block) - pos = buffer.length - block.call(*args) - - # extract the block - data = buffer[pos..-1] - - # replace it in the original with empty string - buffer[pos..-1] = '' - - data - end - - def erb_content_for(name, &block) - eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)" - end - - def block_content_for(name, &block) - eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)" + def with_output_buffer(buf = '') + self.output_buffer, old_buffer = buf, output_buffer + yield + output_buffer + ensure + self.output_buffer = old_buffer end end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0791feb9ac..63a932320e 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -249,9 +249,9 @@ module ActionView args.unshift object end - concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding) + concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) fields_for(object_name, *(args << options), &proc) - concat('</form>', proc.binding) + concat('</form>') end def apply_form_for_options!(object_or_array, options) #:nodoc: diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index e0a097e367..b3f8e63c1b 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -304,7 +304,7 @@ module ActionView # # NOTE: Only the option tags are returned, you have to wrap this call in # a regular HTML select tag. - def time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone) + def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone) zone_options = "" zones = model.all @@ -417,7 +417,7 @@ module ActionView value = value(object) content_tag("select", add_options( - time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || TimeZone), + time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone), options, value ), html_options ) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index ca58f4ba26..3a97f1390f 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -407,10 +407,10 @@ module ActionView # # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset> def field_set_tag(legend = nil, &block) content = capture(&block) - concat(tag(:fieldset, {}, true), block.binding) - concat(content_tag(:legend, legend), block.binding) unless legend.blank? - concat(content, block.binding) - concat("</fieldset>", block.binding) + concat(tag(:fieldset, {}, true)) + concat(content_tag(:legend, legend)) unless legend.blank? + concat(content) + concat("</fieldset>") end private @@ -442,9 +442,9 @@ module ActionView def form_tag_in_block(html_options, &block) content = capture(&block) - concat(form_tag_html(html_options), block.binding) - concat(content, block.binding) - concat("</form>", block.binding) + concat(form_tag_html(html_options)) + concat(content) + concat("</form>") end def token_tag diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 1ea3cbd74e..7404a251e4 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -172,20 +172,17 @@ module ActionView # alert('All is good') # <% end -%> def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block) - if block_given? - html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - content = capture(&block) - else - content = content_or_options_with_block - end + content = + if block_given? + html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + capture(&block) + else + content_or_options_with_block + end - javascript_tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS)) - - if block_given? && block_is_within_action_view?(block) - concat(javascript_tag, block.binding) - else - javascript_tag - end + tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS)) + + block_given? ? concat(tag) : tag end def javascript_cdata_section(content) #:nodoc: @@ -205,11 +202,6 @@ module ActionView end js_option end - - private - def block_is_within_action_view?(block) - eval("defined? _erbout", block.binding) - end end JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 5a1012954e..a7c3b9ddc3 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -382,9 +382,9 @@ module ActionView args.unshift object end - concat(form_remote_tag(options), proc.binding) + concat(form_remote_tag(options)) fields_for(object_name, *(args << options), &proc) - concat('</form>', proc.binding) + concat('</form>') end alias_method :form_remote_for, :remote_form_for diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 66c596f3a9..9bb235175e 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -51,9 +51,8 @@ module ActionView prefix = args.first.is_a?(Hash) ? nil : args.shift options = args.first.is_a?(Hash) ? args.shift : {} concat content_tag(tag_name, capture(&block), - options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })), - block.binding + options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })) end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 999cbfb52a..e1abec1847 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -1,5 +1,6 @@ require 'cgi' require 'erb' +require 'set' module ActionView module Helpers #:nodoc: @@ -8,7 +9,8 @@ module ActionView module TagHelper include ERB::Util - BOOLEAN_ATTRIBUTES = Set.new(%w(disabled readonly multiple)) + BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple).to_set + BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym)) # Returns an empty HTML tag of type +name+ which by default is XHTML # compliant. Set +open+ to true to create an open tag compatible @@ -37,7 +39,7 @@ module ActionView # tag("img", { :src => "open & shut.png" }, false, false) # # => <img src="open & shut.png" /> def tag(name, options = nil, open = false, escape = true) - "<#{name}#{tag_options(options, escape) if options}" + (open ? ">" : " />") + "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}" end # Returns an HTML block tag of type +name+ surrounding the +content+. Add @@ -66,12 +68,9 @@ module ActionView def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) if block_given? options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - content = capture(&block) - content_tag = content_tag_string(name, content, options, escape) - block_is_within_action_view?(block) ? concat(content_tag, block.binding) : content_tag + concat(content_tag_string(name, capture(&block), options, escape)) else - content = content_or_options_with_block - content_tag_string(name, content, options, escape) + content_tag_string(name, content_or_options_with_block, options, escape) end end @@ -114,7 +113,6 @@ module ActionView if escape options.each do |key, value| next unless value - key = key.to_s value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value) attrs << %(#{key}="#{value}") end @@ -124,10 +122,6 @@ module ActionView " #{attrs.sort * ' '}" unless attrs.empty? end end - - def block_is_within_action_view?(block) - eval("defined? _erbout", block.binding) - end end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 669a285424..a1a91f6b3d 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -15,18 +15,26 @@ module ActionView # # ==== Examples # <% - # concat "hello", binding + # concat "hello" # # is the equivalent of <%= "hello" %> # # if (logged_in == true): - # concat "Logged in!", binding + # concat "Logged in!" # else - # concat link_to('login', :action => login), binding + # concat link_to('login', :action => login) # end # # will either display "Logged in!" or a login link # %> - def concat(string, binding) - eval(ActionView::Base.erb_variable, binding) << string + def concat(string, unused_binding = nil) + if unused_binding + ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.") + end + + if output_buffer && string + output_buffer << string + else + string + end end if RUBY_VERSION < '1.9' diff --git a/actionpack/lib/action_view/partial_template.rb b/actionpack/lib/action_view/partial_template.rb index 1fb3aaee02..0b374db888 100644 --- a/actionpack/lib/action_view/partial_template.rb +++ b/actionpack/lib/action_view/partial_template.rb @@ -22,10 +22,10 @@ module ActionView #:nodoc: end def render_member(object) - @locals[@counter_name] += 1 @locals[:object] = @locals[@variable_name] = object template = render_template + @locals[@counter_name] += 1 @locals.delete(@variable_name) @locals.delete(:object) diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 369526188f..500ff713bb 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,5 +1,6 @@ module ActionView #:nodoc: class Template #:nodoc: + extend TemplateHandlers attr_accessor :locals attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method @@ -13,7 +14,7 @@ module ActionView #:nodoc: @view.first_render ||= @path @source = nil # Don't read the source until we know that it is required set_extension_and_file_name(use_full_path) - + @locals = locals || {} @handler = self.class.handler_class_for_extension(@extension).new(@view) end @@ -29,7 +30,7 @@ module ActionView #:nodoc: raise TemplateError.new(self, @view.assigns, e) end end - + def render prepare! @handler.render(self) @@ -46,11 +47,11 @@ module ActionView #:nodoc: def base_path_for_exception @finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first end - + def prepare! @view.send :evaluate_assigns @view.current_render_extension = @extension - + if @handler.compilable? @handler.compile_template(self) # compile the given template, if necessary @method = @view.method_names[method_key] # Set the method name for this template and run it @@ -58,70 +59,30 @@ module ActionView #:nodoc: end private - - def set_extension_and_file_name(use_full_path) - @path_without_extension, @extension = @finder.path_and_extension(@path) - if use_full_path - if @extension - @filename = @finder.pick_template(@path_without_extension, @extension) + def set_extension_and_file_name(use_full_path) + @path_without_extension, @extension = @finder.path_and_extension(@path) + if use_full_path + if @extension + @filename = @finder.pick_template(@path_without_extension, @extension) + else + @extension = @finder.pick_template_extension(@path).to_s + raise_missing_template_exception unless @extension + + @filename = @finder.pick_template(@path, @extension) + @extension = @extension.gsub(/^.+\./, '') # strip off any formats + end else - @extension = @finder.pick_template_extension(@path).to_s - raise_missing_template_exception unless @extension - - @filename = @finder.pick_template(@path, @extension) - @extension = @extension.gsub(/^.+\./, '') # strip off any formats + @filename = @path end - else - @filename = @path - end - - raise_missing_template_exception if @filename.blank? - end - - def raise_missing_template_exception - full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb" - display_paths = @finder.view_paths.join(':') - template_type = (@path =~ /layouts/i) ? 'layout' : 'template' - raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}") - end - # Template Handlers - - @@template_handlers = HashWithIndifferentAccess.new - @@default_template_handlers = nil - - # Register a class that knows how to handle template files with the given - # extension. This can be used to implement new template types. - # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a +render+ method that - # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The +render+ method ought to - # return the rendered template as a string. - def self.register_template_handler(extension, klass) - @@template_handlers[extension.to_sym] = klass - TemplateFinder.update_extension_cache_for(extension.to_s) - end - - def self.template_handler_extensions - @@template_handlers.keys.map(&:to_s).sort - end - - def self.register_default_template_handler(extension, klass) - register_template_handler(extension, klass) - @@default_template_handlers = klass - end - - def self.handler_class_for_extension(extension) - (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers - end - - register_default_template_handler :erb, TemplateHandlers::ERB - register_template_handler :rjs, TemplateHandlers::RJS - register_template_handler :builder, TemplateHandlers::Builder + raise_missing_template_exception if @filename.blank? + end - # TODO: Depreciate old template extensions - register_template_handler :rhtml, TemplateHandlers::ERB - register_template_handler :rxml, TemplateHandlers::Builder - + def raise_missing_template_exception + full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb" + display_paths = @finder.view_paths.join(':') + template_type = (@path =~ /layouts/i) ? 'layout' : 'template' + raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}") + end end end diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb index 83b7e27c09..7e9a310810 100644 --- a/actionpack/lib/action_view/template_finder.rb +++ b/actionpack/lib/action_view/template_finder.rb @@ -1,14 +1,5 @@ module ActionView #:nodoc: class TemplateFinder #:nodoc: - - class InvalidViewPath < StandardError #:nodoc: - attr_reader :unprocessed_path - def initialize(path) - @unprocessed_path = path - super("Unprocessed view path found: #{@unprocessed_path.inspect}. Set your view paths with #append_view_path, #prepend_view_path, or #view_paths=.") - end - end - cattr_reader :processed_view_paths @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} @@ -18,7 +9,6 @@ module ActionView #:nodoc: } class << self #:nodoc: - # This method is not thread safe. Mutex should be used whenever this is accessed from an instance method def process_view_paths(*view_paths) view_paths.flatten.compact.each do |dir| @@ -35,7 +25,7 @@ module ActionView #:nodoc: # Build extension cache extension = file.split(".").last - if template_handler_extensions.include?(extension) + if ActionView::Template.template_handler_extensions.include?(extension) key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') @@file_extension_cache[dir][key] << extension end @@ -44,19 +34,6 @@ module ActionView #:nodoc: end end - def update_extension_cache_for(extension) - @@processed_view_paths.keys.each do |dir| - Dir.glob("#{dir}/**/*.#{extension}").each do |file| - key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') - @@file_extension_cache[dir][key] << extension - end - end - end - - def template_handler_extensions - ActionView::Template.template_handler_extensions - end - def reload! view_paths = @@processed_view_paths.keys @@ -76,7 +53,7 @@ module ActionView #:nodoc: @view_paths = args.flatten @view_paths = @view_paths.respond_to?(:find) ? @view_paths.dup : [*@view_paths].compact - check_view_paths(@view_paths) + self.class.process_view_paths(@view_paths) end def prepend_view_path(path) @@ -166,12 +143,5 @@ module ActionView #:nodoc: def find_template_extension_from_first_render File.basename(@template.first_render.to_s)[/^[^.]+\.(.+)$/, 1] end - - private - def check_view_paths(view_paths) - view_paths.each do |path| - raise InvalidViewPath.new(path) unless @@processed_view_paths.has_key?(path) - end - end end end diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template_handler.rb index ec407e3fb3..39e578e586 100644 --- a/actionpack/lib/action_view/template_handler.rb +++ b/actionpack/lib/action_view/template_handler.rb @@ -1,6 +1,5 @@ module ActionView class TemplateHandler - def self.line_offset 0 end diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template_handlers.rb new file mode 100644 index 0000000000..1471e99e01 --- /dev/null +++ b/actionpack/lib/action_view/template_handlers.rb @@ -0,0 +1,46 @@ +require 'action_view/template_handler' +require 'action_view/template_handlers/compilable' +require 'action_view/template_handlers/builder' +require 'action_view/template_handlers/erb' +require 'action_view/template_handlers/rjs' + +module ActionView #:nodoc: + module TemplateHandlers #:nodoc: + def self.extended(base) + base.register_default_template_handler :erb, TemplateHandlers::ERB + base.register_template_handler :rjs, TemplateHandlers::RJS + base.register_template_handler :builder, TemplateHandlers::Builder + + # TODO: Depreciate old template extensions + base.register_template_handler :rhtml, TemplateHandlers::ERB + base.register_template_handler :rxml, TemplateHandlers::Builder + end + + @@template_handlers = {} + @@default_template_handlers = nil + + # Register a class that knows how to handle template files with the given + # extension. This can be used to implement new template types. + # The constructor for the class must take the ActiveView::Base instance + # as a parameter, and the class must implement a +render+ method that + # takes the contents of the template to render as well as the Hash of + # local assigns available to the template. The +render+ method ought to + # return the rendered template as a string. + def register_template_handler(extension, klass) + @@template_handlers[extension.to_sym] = klass + end + + def template_handler_extensions + @@template_handlers.keys.map(&:to_s).sort + end + + def register_default_template_handler(extension, klass) + register_template_handler(extension, klass) + @@default_template_handlers = klass + end + + def handler_class_for_extension(extension) + (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers + end + end +end diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb index f76d89777a..ee02ce1a6f 100644 --- a/actionpack/lib/action_view/template_handlers/builder.rb +++ b/actionpack/lib/action_view/template_handlers/builder.rb @@ -11,10 +11,11 @@ module ActionView def compile(template) content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller") + "#{content_type_handler}.content_type ||= Mime::XML\n" + - "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" + - template.source + - "\nxml.target!\n" + "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" + + template.source + + "\nxml.target!\n" end def cache_fragment(block, name = {}, options = nil) diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb index 25bd0fea7f..1aef81ba1a 100644 --- a/actionpack/lib/action_view/template_handlers/compilable.rb +++ b/actionpack/lib/action_view/template_handlers/compilable.rb @@ -106,7 +106,7 @@ module ActionView locals_code << "#{key} = local_assigns[:#{key}]\n" end - "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" + "def #{render_symbol}(local_assigns)\nold_output_buffer = output_buffer;#{locals_code}#{body}\nensure\nself.output_buffer = old_output_buffer\nend" end # Return true if the given template was compiled for a superset of the keys in local_assigns @@ -125,4 +125,4 @@ module ActionView end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb index 15a9064461..ad4ccc7c42 100644 --- a/actionpack/lib/action_view/template_handlers/erb.rb +++ b/actionpack/lib/action_view/template_handlers/erb.rb @@ -43,13 +43,11 @@ module ActionView include Compilable def compile(template) - ::ERB.new(template.source, nil, @view.erb_trim_mode).src + ::ERB.new(template.source, nil, @view.erb_trim_mode, '@output_buffer').src end def cache_fragment(block, name = {}, options = nil) #:nodoc: - @view.fragment_for(block, name, options) do - eval(ActionView::Base.erb_variable, block.binding) - end + @view.fragment_for(block, name, options) { @view.response.template.output_buffer ||= '' } end end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 16fedd9732..1a3c93c283 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -37,6 +37,8 @@ module ActionView if helper_class && !self.class.ancestors.include?(helper_class) self.class.send(:include, helper_class) end + + self.output_buffer = '' end class TestController < ActionController::Base @@ -48,6 +50,9 @@ module ActionView end end + protected + attr_accessor :output_buffer + private def method_missing(selector, *args) controller = TestController.new |