提交 c01c8967 编写于 作者: E Emilio Tagua

Merge commit 'rails/master'

Conflicts:
	activerecord/lib/active_record/calculations.rb
......@@ -19,15 +19,20 @@ def inherited(klass)
end
end
def clear_template_caches!
@found_layouts.clear if @found_layouts
super
end
def cache_layout(details)
layout = @found_layouts
values = details.values_at(:formats, :locale)
key = Thread.current[:format_locale_key]
# Cache nil
if layout.key?(values)
return layout[values]
if layout.key?(key)
return layout[key]
else
layout[values] = yield
layout[key] = yield
end
end
......
......@@ -111,12 +111,21 @@ def self.body_to_s(body)
def _determine_template(options)
name = (options[:_template_name] || action_name).to_s
options[:_template] ||= view_paths.find(
name, { :formats => formats }, options[:_prefix], options[:_partial]
)
options[:_template] ||= with_template_cache(name) do
view_paths.find(
name, { :formats => formats }, options[:_prefix], options[:_partial]
)
end
end
def with_template_cache(name)
yield
end
module ClassMethods
def clear_template_caches!
end
# Append a path to the list of view paths for this controller.
#
# ==== Parameters
......@@ -134,6 +143,7 @@ def append_view_path(path)
# the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def prepend_view_path(path)
clear_template_caches!
self.view_paths.unshift(path)
end
......@@ -148,6 +158,7 @@ def view_paths
# paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
# otherwise, process the parameter into a ViewPathSet.
def view_paths=(paths)
clear_template_caches!
self._view_paths = paths.is_a?(ActionView::PathSet) ?
paths : ActionView::Base.process_view_paths(paths)
end
......
module ActionController
class HashKey
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
def self.get(klass, formats, locale)
@hash_keys[klass][formats][locale] ||= new(klass, formats, locale)
end
attr_accessor :hash
def initialize(klass, formats, locale)
@formats, @locale = formats, locale
@hash = [formats, locale].hash
end
alias_method :eql?, :equal?
def inspect
"#<HashKey -- formats: #{@formats} locale: #{@locale}>"
end
end
module RenderingController
extend ActiveSupport::Concern
include AbstractController::RenderingController
module ClassMethods
def clear_template_caches!
ActionView::Partials::PartialRenderer::TEMPLATES.clear
template_cache.clear
super
end
def template_cache
@template_cache ||= Hash.new {|h,k| h[k] = {} }
end
end
def process_action(*)
self.formats = request.formats.map {|x| x.to_sym}
super
end
def _determine_template(*)
super
end
def render(options)
Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale)
super
self.content_type ||= begin
mime = options[:_template].mime_type
formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first)
end.to_s
self.content_type ||= options[:_template].mime_type.to_s
response_body
end
......@@ -34,6 +70,10 @@ def _prefix
controller_path
end
def with_template_cache(name)
self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super
end
def _determine_template(options)
if options.key?(:text)
options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
......
......@@ -531,14 +531,14 @@ def map_resource(entities, options = {}, &block)
with_options :controller => resource.controller do |map|
map_associations(resource, options)
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
end
end
......@@ -546,16 +546,16 @@ def map_singleton_resource(entities, options = {}, &block)
resource = SingletonResource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
map_default_singleton_actions(map, resource)
map_associations(resource, options)
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
map_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
map_default_singleton_actions(map, resource)
end
end
......
......@@ -407,22 +407,9 @@ def generate(options, recall = {}, method=:generate)
# don't use the recalled keys when determining which routes to check
routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
routes[1].each_with_index do |route, index|
routes.each_with_index do |route, index|
results = route.__send__(method, options, merged, expire_on)
if results && (!results.is_a?(Array) || results.first)
# Compare results with Rails 3.0 behavior
if routes[0][index] != route
routes[0].each do |route2|
new_results = route2.__send__(method, options, merged, expire_on)
if new_results && (!new_results.is_a?(Array) || new_results.first)
ActiveSupport::Deprecation.warn "The URL you generated will use the first matching route in routes.rb rather than the \"best\" match. " +
"In Rails 3.0 #{new_results} would of been generated instead of #{results}"
break
end
end
end
return results
end
end
......@@ -463,10 +450,7 @@ def routes_by_controller
@routes_by_controller ||= Hash.new do |controller_hash, controller|
controller_hash[controller] = Hash.new do |action_hash, action|
action_hash[action] = Hash.new do |key_hash, keys|
key_hash[keys] = [
routes_for_controller_and_action_and_keys(controller, action, keys),
deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
]
key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys)
end
end
end
......@@ -487,15 +471,6 @@ def routes_for_controller_and_action_and_keys(controller, action, keys)
end
end
def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
selected = routes.select do |route|
route.matches_controller_and_action? controller, action
end
selected.sort_by do |route|
(keys - route.significant_keys).length
end
end
# Subclasses and plugins may override this method to extract further attributes
# from the request, for use by route conditions and such.
def extract_request_environment(request)
......
......@@ -148,7 +148,7 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
returning __send__(request_method, action, parameters, session, flash) do
@request.env.delete 'HTTP_X_REQUESTED_WITH'
@request.env.delete 'HTTP_ACCEPT'
......
......@@ -106,16 +106,10 @@ def accepts
@env["action_dispatch.request.accepts"] ||= begin
header = @env['HTTP_ACCEPT'].to_s.strip
fallback = xhr? ? Mime::JS : Mime::HTML
if header.empty?
[content_type, fallback, Mime::ALL].compact
[content_type]
else
ret = Mime::Type.parse(header)
if ret.last == Mime::ALL
ret.insert(-2, fallback)
end
ret
Mime::Type.parse(header)
end
end
end
......@@ -163,26 +157,20 @@ def fresh?(response)
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
#
def format(view_path = [])
@env["action_dispatch.request.format"] ||=
if parameters[:format]
Mime[parameters[:format]]
elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL)
accepts.first
elsif xhr? then Mime::JS
else Mime::HTML
end
formats.first
end
def formats
if ActionController::Base.use_accept_header
if param = parameters[:format]
Array.wrap(Mime[param])
accept = @env['HTTP_ACCEPT']
@env["action_dispatch.request.formats"] ||=
if parameters[:format]
[Mime[parameters[:format]]]
elsif xhr? || (accept && !accept.include?(?,))
accepts
else
accepts.dup
[Mime::HTML]
end
else
[format]
end
end
# Sets the \format by string extension, which can be used to force custom formats
......@@ -198,7 +186,7 @@ def formats
# end
def format=(extension)
parameters[:format] = extension.to_s
@env["action_dispatch.request.format"] = Mime::Type.lookup_by_extension(parameters[:format])
@env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])]
end
# Returns a symbolized version of the <tt>:format</tt> parameter of the request.
......
......@@ -47,6 +47,8 @@ def parse_formatted_parameters(env)
false
end
rescue Exception => e # YAML, XML or Ruby code block errors
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise
{ "body" => request.raw_post,
"content_type" => request.content_type,
......@@ -67,5 +69,9 @@ def content_type_from_legacy_post_data_format_header(env)
nil
end
def logger
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
end
......@@ -175,6 +175,17 @@ module Subclasses
attr_accessor :controller
attr_internal :captures
def reset_formats(formats)
@formats = formats
if defined?(ActionController)
# This is expensive, but we need to reset this when the format is updated,
# which currently only happens
Thread.current[:format_locale_key] =
ActionController::HashKey.get(self.class, formats, I18n.locale)
end
end
class << self
delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
......@@ -240,7 +251,7 @@ def self.for_controller(controller)
end
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
@formats = formats || [:html]
@formats = formats
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
@controller = controller
@helpers = self.class.helpers || Module.new
......@@ -255,15 +266,6 @@ def view_paths=(paths)
@view_paths = self.class.process_view_paths(paths)
end
def with_template(current_template)
_evaluate_assigns_and_ivars
last_template, self.template = template, current_template
last_formats, self.formats = formats, current_template.formats
yield
ensure
self.template, self.formats = last_template, last_formats
end
def punctuate_body!(part)
flush_output_buffer
response.body_parts << part
......@@ -272,18 +274,11 @@ def punctuate_body!(part)
# Evaluates the local assigns and controller ivars, pushes them to the view.
def _evaluate_assigns_and_ivars #:nodoc:
@assigns_added ||= _copy_ivars_from_controller
end
private
def _copy_ivars_from_controller #:nodoc:
if @controller
variables = @controller.instance_variable_names
variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables)
variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) }
end
true
end
end
......
......@@ -991,12 +991,13 @@ def record(line)
def render(*options_for_render)
old_formats = @context && @context.formats
@context.formats = [:html] if @context
@context.reset_formats([:html]) if @context
Hash === options_for_render.first ?
@context.render(*options_for_render) :
options_for_render.first.to_s
ensure
@context.formats = old_formats if @context
@context.reset_formats(old_formats) if @context
end
def javascript_object_for(object)
......
......@@ -173,44 +173,50 @@ module Partials
extend ActiveSupport::Concern
class PartialRenderer
def self.partial_names
@partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new }
end
PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
TEMPLATES = Hash.new {|h,k| h[k] = {} }
def self.formats
@formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}}
end
attr_reader :template
def initialize(view_context, options, block)
partial = options[:partial]
@memo = {}
@view = view_context
@options = options
@locals = options[:locals] || {}
@block = block
# Set up some instance variables to speed up memoizing
@partial_names = self.class.partial_names[@view.controller.class]
@templates = self.class.formats
@format = view_context.formats
# Set up the object and path
@object = partial.is_a?(String) ? options[:object] : partial
@path = partial_path(partial)
@partial_names = PARTIAL_NAMES[@view.controller.class]
key = Thread.current[:format_locale_key]
@templates = TEMPLATES[key] if key
setup(options, block)
end
def setup(options, block)
partial = options[:partial]
@options = options
@locals = options[:locals] || {}
@block = block
if String === partial
@object = options[:object]
@path = partial
else
@object = partial
@path = partial_path(partial)
end
end
def render
return render_collection if collection
template = find_template
render_template(template, @object || @locals[template.variable_name])
if @collection = collection
render_collection
else
@template = template = find_template
render_template(template, @object || @locals[template.variable_name])
end
end
def render_collection
@options[:_template] = template = find_template
@template = template = find_template
return nil if collection.blank?
return nil if @collection.blank?
if @options.key?(:spacer_template)
spacer = find_template(@options[:spacer_template]).render(@view, @locals)
......@@ -223,57 +229,58 @@ def render_collection
def collection_with_template(template)
options = @options
segments, locals, as = [], @locals, options[:as] || :object
segments, locals, as = [], @locals, options[:as] || template.variable_name
variable_name = template.variable_name
counter_name = template.counter_name
locals[counter_name] = -1
collection.each do |object|
@collection.each do |object|
locals[counter_name] += 1
locals[variable_name] = object
locals[as] = object if as
locals[as] = object
segments << template.render(@view, locals)
end
@template = template
segments
end
def collection_without_template
options = @options
segments, locals, as = [], @locals, options[:as] || :object
segments, locals, as = [], @locals, options[:as]
index, template = -1, nil
collection.each do |object|
@collection.each do |object|
template = find_template(partial_path(object))
locals[template.counter_name] = (index += 1)
locals[template.variable_name] = object
locals[as] = object if as
segments << template.render(@view, locals)
end
@options[:_template] = template
@template = template
segments
end
def render_template(template, object = @object)
@options[:_template] ||= template
options, locals, view = @options, @locals, @view
locals[options[:as] || template.variable_name] = object
# TODO: is locals[:object] really necessary?
@locals[:object] = @locals[template.variable_name] = object
@locals[@options[:as]] = object if @options[:as]
content = template.render(view, locals) do |*name|
@view._layout_for(*name, &@block)
end
content = @view._render_single_template(template, @locals, &@block)
return content if @block || !@options[:layout]
find_template(@options[:layout]).render(@view, @locals) { content }
if @block || !options[:layout]
content
else
find_template(options[:layout]).render(@view, @locals) { content }
end
end
private
def collection
@collection ||= if @object.respond_to?(:to_ary)
if @object.respond_to?(:to_ary)
@object
elsif @options.key?(:collection)
@options[:collection] || []
......@@ -281,15 +288,19 @@ def collection
end
def find_template(path = @path)
return if !path
@templates[path][@view.controller_path][@format][I18n.locale] ||= begin
prefix = @view.controller.controller_path unless path.include?(?/)
@view.find(path, {:formats => @view.formats}, prefix, true)
unless @templates
path && _find_template(path)
else
path && @templates[path] ||= _find_template(path)
end
end
def _find_template(path)
prefix = @view.controller.controller_path unless path.include?(?/)
@view.find(path, {:formats => @view.formats}, prefix, true)
end
def partial_path(object = @object)
return object if object.is_a?(String)
@partial_names[object.class] ||= begin
return nil unless object.respond_to?(:to_model)
......@@ -302,14 +313,26 @@ def partial_path(object = @object)
end
def render_partial(options)
@assigns_added = false
# TODO: Handle other details here.
self.formats = options[:_details][:formats] if options[:_details]
_render_partial(options)
_evaluate_assigns_and_ivars
details = options[:_details]
# Is this needed
self.formats = details[:formats] if details
renderer = PartialRenderer.new(self, options, nil)
text = renderer.render
options[:_template] = renderer.template
text
end
def _render_partial(options, &block) #:nodoc:
PartialRenderer.new(self, options, block).render
if @renderer
@renderer.setup(options, block)
else
@renderer = PartialRenderer.new(self, options, block)
end
@renderer.render
end
end
......
......@@ -12,8 +12,6 @@ module Rendering
# as the locals hash.
def render(options = {}, locals = {}, &block) #:nodoc:
case options
when String, NilClass
_render_partial(:partial => options, :locals => locals || {})
when Hash
layout = options[:layout]
......@@ -35,26 +33,8 @@ def render(options = {}, locals = {}, &block) #:nodoc:
end
when :update
update_page(&block)
end
end
def _render_content(content, layout, locals)
return content unless layout
locals ||= {}
if controller && layout
@_layout = layout.identifier
logger.info("Rendering template within #{layout.identifier}") if logger
end
begin
old_content, @_content_for[:layout] = @_content_for[:layout], content
@cached_content_for_layout = @_content_for[:layout]
_render_single_template(layout, locals)
ensure
@_content_for[:layout] = old_content
else
_render_partial(:partial => options, :locals => locals)
end
end
......@@ -90,48 +70,25 @@ def _render_content(content, layout, locals)
# In this case, the layout would receive the block passed into <tt>render :layout</tt>,
# and the Struct specified in the layout would be passed into the block. The result
# would be <html>Hello David</html>.
def _layout_for(names, &block)
with_output_buffer do
# This is due to the potentially ambiguous use of yield when
# a block is passed in to a template *and* there is a content_for()
# of the same name. Suggested solution: require explicit use of content_for
# in these ambiguous cases.
#
# We would be able to continue supporting yield in all non-ambiguous
# cases. Question: should we deprecate yield in favor of content_for
# and reserve yield for cases where there is a yield into a real block?
if @_content_for.key?(names.first) || !block_given?
return @_content_for[names.first || :layout]
else
return yield(names)
end
end
end
def _layout_for(name = nil)
return @_content_for[name || :layout] if !block_given? || name
def _render_single_template(template, locals = {}, &block)
with_template(template) do
template.render(self, locals) do |*names|
_layout_for(names, &block)
end
end
rescue Exception => e
if e.is_a?(TemplateError)
e.sub_template_of(template)
raise e
else
raise TemplateError.new(template, assigns, e)
with_output_buffer do
return yield
end
end
def _render_inline(inline, layout, options)
handler = Template.handler_class_for_extension(options[:type] || "erb")
template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
content = _render_single_template(template, options[:locals] || {})
layout ? _render_content(content, layout, options[:locals]) : content
locals = options[:locals] || {}
content = template.render(self, locals)
content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout
content
end
def _render_text(text, layout, options)
layout ? _render_content(text, layout, options[:locals]) : text
text = layout.render(self, options[:locals]) { text } if layout
end
# This is the API to render a ViewContext's template from a controller.
......@@ -141,7 +98,7 @@ def _render_text(text, layout, options)
# _layout:: The layout, if any, to wrap the Template in
# _partial:: true if the template is a partial
def render_template(options)
@assigns_added = nil
_evaluate_assigns_and_ivars
template, layout, partial = options.values_at(:_template, :_layout, :_partial)
_render_template(template, layout, options, partial)
end
......@@ -158,10 +115,18 @@ def _render_template(template, layout = nil, options = {}, partial = nil)
content = if partial
_render_partial_object(template, options)
else
_render_single_template(template, locals)
template.render(self, locals)
end
_render_content(content, layout, locals)
@cached_content_for_layout = content
@_content_for[:layout] = content
if layout
@_layout = layout.identifier
logger.info("Rendering template within #{layout.identifier}") if logger
content = layout.render(self, locals) {|*name| _layout_for(*name) }
end
content
end
end
end
\ No newline at end of file
......@@ -26,11 +26,7 @@ class TemplateHandler
self.default_format = Mime::HTML
def self.call(template)
"#{name}.new(self).render(template, local_assigns)"
end
def initialize(view = nil)
@view = view
raise "Need to implement #{self.class.name}#call(template)"
end
def render(template, local_assigns)
......
......@@ -42,7 +42,7 @@ def handler_matcher
def handler_glob
@handler_glob ||= begin
e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join
e = TemplateHandlers.extensions.map{|h| ".#{h}"}.join(",")
"{#{e}}"
end
end
......
......@@ -26,9 +26,16 @@ def initialize(source, identifier, handler, details)
@details[:formats] = Array.wrap(format.to_sym)
end
def render(view, locals, &blk)
def render(view, locals, &block)
method_name = compile(locals, view)
view.send(method_name, locals, &blk)
view.send(method_name, locals, &block)
rescue Exception => e
if e.is_a?(TemplateError)
e.sub_template_of(self)
raise e
else
raise TemplateError.new(self, view.assigns, e)
end
end
# TODO: Figure out how to abstract this
......@@ -90,7 +97,22 @@ def #{method_name}(local_assigns)
raise ActionView::TemplateError.new(self, {}, e)
end
end
class LocalsKey
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
def self.get(*locals)
@hash_keys[*locals] ||= new(klass, format, locale)
end
attr_accessor :hash
def initialize(klass, format, locale)
@hash = locals.hash
end
alias_method :eql?, :equal?
end
def build_method_name(locals)
# TODO: is locals.keys.hash reliably the same?
@method_names[locals.keys.hash] ||=
......
......@@ -46,7 +46,7 @@ def render_change_for_rxml
def render_default_content_types_for_respond_to
respond_to do |format|
format.html { render :text => "hello world!" }
format.xml { render :action => "render_default_content_types_for_respond_to.rhtml" }
format.xml { render :action => "render_default_content_types_for_respond_to" }
format.js { render :text => "hello world!" }
format.rss { render :text => "hello world!", :content_type => Mime::XML }
end
......
......@@ -79,29 +79,20 @@ def custom_type_handling
end
end
def custom_constant_handling
Mime::Type.register("text/x-mobile", :mobile)
Mime::Type.register("text/x-mobile", :mobile)
def custom_constant_handling
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile { render :text => "Mobile" }
end
ensure
Mime::SET.delete(:mobile)
Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) }
end
def custom_constant_handling_without_block
Mime::Type.register("text/x-mobile", :mobile)
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile
end
ensure
Mime::SET.delete(:mobile)
Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) }
end
def handle_any
......@@ -125,32 +116,24 @@ def all_types_with_layout
end
end
Mime::Type.register_alias("text/html", :iphone)
def iphone_with_html_response_type
Mime::Type.register_alias("text/html", :iphone)
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox" }
type.iphone { @type = "iPhone" }
end
ensure
Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
def iphone_with_html_response_type_without_layout
Mime::Type.register_alias("text/html", :iphone)
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" }
type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" }
end
ensure
Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
def rescue_action(e)
......@@ -213,18 +196,20 @@ def test_xml
def test_js_or_html
@request.accept = "text/javascript, text/html"
get :js_or_html
xhr :get, :js_or_html
assert_equal 'JS', @response.body
get :html_or_xml
@request.accept = "text/javascript, text/html"
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
get :just_xml
@request.accept = "text/javascript, text/html"
xhr :get, :just_xml
assert_response 406
end
def test_json_or_yaml
get :json_or_yaml
xhr :get, :json_or_yaml
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'json'
......@@ -246,13 +231,13 @@ def test_json_or_yaml
def test_js_or_anything
@request.accept = "text/javascript, */*"
get :js_or_html
xhr :get, :js_or_html
assert_equal 'JS', @response.body
get :html_or_xml
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
get :just_xml
xhr :get, :just_xml
assert_equal 'XML', @response.body
end
......@@ -291,14 +276,16 @@ def test_using_defaults_with_type_list
end
def test_with_atom_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/atom+xml"
get :made_for_content_type
xhr :get, :made_for_content_type
assert_equal "ATOM", @response.body
end
def test_with_rss_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/rss+xml"
get :made_for_content_type
xhr :get, :made_for_content_type
assert_equal "RSS", @response.body
end
......@@ -795,12 +782,8 @@ def index
protected
def with_iphone
Mime::Type.register_alias("text/html", :iphone)
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
yield
ensure
Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
end
......
......@@ -13,7 +13,7 @@ def greeting
# let's just rely on the template
end
def partial
def show_partial
render :partial => 'partial'
end
end
......@@ -33,7 +33,7 @@ def test_render_with_default_from_accept_header
end
def test_should_render_js_partial
xhr :get, :partial, :format => 'js'
xhr :get, :show_partial, :format => 'js'
assert_equal 'partial js', @response.body
end
end
end
\ No newline at end of file
......@@ -486,10 +486,6 @@ def render_using_layout_around_block
render :action => "using_layout_around_block"
end
def render_using_layout_around_block_with_args
render :action => "using_layout_around_block_with_args"
end
def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
render :action => "using_layout_around_block", :layout => "layouts/block_with_layout"
end
......@@ -1161,11 +1157,6 @@ def test_using_layout_around_block_in_main_layout_and_within_content_for_layout
assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body
end
def test_using_layout_around_block_with_args
get :render_using_layout_around_block_with_args
assert_equal "Before\narg1arg2\nAfter", @response.body
end
def test_partial_only
get :partial_only
assert_equal "only partial", @response.body
......
......@@ -56,7 +56,7 @@ class MimeTypeTest < ActiveSupport::TestCase
test "type convenience methods" do
# Don't test Mime::ALL, since it Mime::ALL#html? == true
types = Mime::SET.symbols.uniq - [:all]
types = Mime::SET.symbols.uniq - [:all, :iphone]
# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }
......
......@@ -30,16 +30,36 @@ def teardown
)
end
test "logs error if parsing unsuccessful" do
with_test_routing do
begin
$stderr = StringIO.new
json = "[\"person]\": {\"name\": \"David\"}}"
post "/parse", json, {'CONTENT_TYPE' => 'application/json'}
assert_response :error
$stderr.rewind && err = $stderr.read
assert err =~ /Error occurred while parsing request parameters/
ensure
$stderr = STDERR
end
end
end
private
def assert_parses(expected, actual, headers = {})
with_test_routing do
post "/parse", actual, headers
assert_response :ok
assert_equal(expected, TestController.last_request_parameters)
end
end
def with_test_routing
with_routing do |set|
set.draw do |map|
map.connect ':action', :controller => "json_params_parsing_test/test"
end
post "/parse", actual, headers
assert_response :ok
assert_equal(expected, TestController.last_request_parameters)
yield
end
end
end
......@@ -38,6 +38,21 @@ def teardown
end
end
test "logs error if parsing unsuccessful" do
with_test_routing do
begin
$stderr = StringIO.new
xml = "<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></pineapple>"
post "/parse", xml, default_headers
assert_response :error
$stderr.rewind && err = $stderr.read
assert err =~ /Error occurred while parsing request parameters/
ensure
$stderr = STDERR
end
end
end
test "parses multiple files" do
xml = <<-end_body
<person>
......@@ -85,4 +100,4 @@ class LegacyXmlParamsParsingTest < XmlParamsParsingTest
def default_headers
{'HTTP_X_POST_DATA_FORMAT' => 'xml'}
end
end
end
\ No newline at end of file
......@@ -366,12 +366,12 @@ def teardown
end
test "XMLHttpRequest" do
with_accept_header false do
request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
request.expects(:parameters).at_least_once.returns({})
assert request.xhr?
assert_equal Mime::JS, request.format
end
request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
'HTTP_ACCEPT' =>
[Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(",")
request.expects(:parameters).at_least_once.returns({})
assert request.xhr?
assert_equal Mime::JS, request.format
end
test "content type" do
......@@ -420,37 +420,34 @@ def teardown
end
test "formats with accept header" do
with_accept_header true do
request = stub_request 'HTTP_ACCEPT' => 'text/html'
request.expects(:parameters).at_least_once.returns({})
assert_equal [ Mime::HTML ], request.formats
request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
request.expects(:parameters).at_least_once.returns({})
assert_equal with_set(Mime::XML, Mime::HTML, Mime::ALL), request.formats
end
request = stub_request 'HTTP_ACCEPT' => 'text/html'
request.expects(:parameters).at_least_once.returns({})
assert_equal [ Mime::HTML ], request.formats
with_accept_header false do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :txt })
assert_equal with_set(Mime::TEXT), request.formats
end
request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
request.expects(:parameters).at_least_once.returns({})
assert_equal with_set(Mime::XML), request.formats
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :txt })
assert_equal with_set(Mime::TEXT), request.formats
end
test "negotiate_mime" do
with_accept_header true do
request = stub_request 'HTTP_ACCEPT' => 'text/html'
request.expects(:parameters).at_least_once.returns({})
assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL])
request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
request.expects(:parameters).at_least_once.returns({})
assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV])
assert_equal Mime::CSV, request.negotiate_mime([Mime::CSV, Mime::YAML])
end
request = stub_request 'HTTP_ACCEPT' => 'text/html',
'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
request.expects(:parameters).at_least_once.returns({})
assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL])
request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
request.expects(:parameters).at_least_once.returns({})
assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV])
end
protected
......
<%= customer.name %> <%= customer.name %> <%= customer_with_var.name %>
\ No newline at end of file
<%= customer.name %> <%= customer.name %> <%= customer.name %>
\ No newline at end of file
<%= hash_object[:first_name] %>
<%= object[:first_name].reverse %>
<%= hash_object[:first_name].reverse %>
<% render(:layout => "layout_for_block_with_args") do |*args| %><%= args.join %><% end %>
\ No newline at end of file
......@@ -4,7 +4,7 @@ def initialize(hash = {}, options = {})
super(options)
@hash = hash
end
def find_templates(name, details, prefix, partial)
if regexp = details_to_regexp(name, details, prefix, partial)
cached(regexp) do
......@@ -16,26 +16,26 @@ def find_templates(name, details, prefix, partial)
end
end
end
private
def formats_regexp
@formats_regexp ||= begin
formats = Mime::SET.symbols
'(?:' + formats.map { |l| "\\.#{Regexp.escape(l.to_s)}" }.join('|') + ')?'
end
end
def handler_regexp
e = TemplateHandlers.extensions.map{|h| "\\.#{Regexp.escape(h.to_s)}"}.join("|")
"(?:#{e})?"
"(?:#{e})"
end
def details_to_regexp(name, details, prefix, partial)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
extensions = ""
[:locales, :formats].each do |k|
extensions << if exts = details[k]
......@@ -47,7 +47,7 @@ def details_to_regexp(name, details, prefix, partial)
%r'^#{Regexp.escape(path)}#{extensions}#{handler_regexp}$'
end
# TODO: fix me
# :api: plugin
def path_to_details(path)
......@@ -56,10 +56,10 @@ def path_to_details(path)
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
......
......@@ -75,7 +75,7 @@ class ImpliedContentTypeTest < SimpleRouteCase
end
test "sets Content-Type as application/xml when rendering *.xml.erb" do
get "/content_type/implied/i_am_xml_erb"
get "/content_type/implied/i_am_xml_erb", "format" => "xml"
assert_header "Content-Type", "application/xml; charset=utf-8"
end
......@@ -87,7 +87,7 @@ class ImpliedContentTypeTest < SimpleRouteCase
end
test "sets Content-Type as application/xml when rendering *.xml.builder" do
get "/content_type/implied/i_am_xml_builder"
get "/content_type/implied/i_am_xml_builder", "format" => "xml"
assert_header "Content-Type", "application/xml; charset=utf-8"
end
......
......@@ -83,7 +83,7 @@ class MismatchFormatTest < SimpleRouteCase
testing ControllerLayouts::MismatchFormatController
test "if JS is selected, an HTML template is not also selected" do
get :index
get :index, "format" => "js"
assert_response "$(\"test\").omg();"
end
......
......@@ -21,24 +21,23 @@ def index
def index_locale
old_locale, I18n.locale = I18n.locale, :da
end
end
class TestBasic < SimpleRouteCase
testing BasicController
test "rendering a partial in an RJS template should pick the JS template over the HTML one" do
get :index
get :index, "format" => "js"
assert_response("$(\"customer\").update(\"JS Partial\");")
end
test "replacing an element with a partial in an RJS template should pick the HTML template over the JS one" do
get :index_html
get :index_html, "format" => "js"
assert_response("$(\"customer\").update(\"HTML Partial\");")
end
test "replacing an element with a partial in an RJS template with a locale should pick the localed HTML template" do
get :index_locale, :format => :js
get :index_locale, "format" => "js"
assert_response("$(\"customer\").update(\"Danish HTML Partial\");")
end
......
......@@ -73,7 +73,7 @@ class TestWithoutLayout < SimpleRouteCase
end
test "rendering a builder template" do
get :builder_template
get :builder_template, "format" => "xml"
assert_response "<html>\n <p>Hello</p>\n</html>\n"
end
end
......
......@@ -7,6 +7,10 @@ def _evaluate_assigns_and_ivars() end
attr_accessor :formats, :output_buffer
def reset_formats(format)
@format = format
end
def setup
super
@template = self
......
......@@ -36,6 +36,10 @@ class Author::Nested < Author; end
class PrototypeHelperBaseTest < ActionView::TestCase
attr_accessor :formats, :output_buffer
def reset_formats(format)
@format = format
end
def setup
super
@template = self
......
......@@ -2,10 +2,14 @@
require 'abstract_unit'
require 'controller/fake_models'
class TestController < ActionController::Base
end
module RenderTestCases
def setup_view(paths)
@assigns = { :secret => 'in the sauce' }
@view = ActionView::Base.new(paths, @assigns)
@controller_view = ActionView::Base.for_controller(TestController.new)
# Reload and register danish language for testing
I18n.reload!
......@@ -138,7 +142,7 @@ def test_render_partial_collection_as
end
def test_render_partial_collection_without_as
assert_equal "local_inspector,local_inspector_counter,object",
assert_equal "local_inspector,local_inspector_counter",
@view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ])
end
......@@ -158,6 +162,25 @@ def test_render_partial_with_empty_array_should_return_nil
assert_nil @view.render(:partial => [])
end
def test_render_partial_using_string
assert_equal "Hello: Anonymous", @controller_view.render('customer')
end
def test_render_partial_with_locals_using_string
assert_equal "Hola: david", @controller_view.render('customer_greeting', :greeting => 'Hola', :customer_greeting => Customer.new("david"))
end
def test_render_partial_using_object
assert_equal "Hello: lifo",
@controller_view.render(Customer.new("lifo"), :greeting => "Hello")
end
def test_render_partial_using_collection
customers = [ Customer.new("Amazon"), Customer.new("Yahoo") ]
assert_equal "Hello: AmazonHello: Yahoo",
@controller_view.render(customers, :greeting => "Hello")
end
# TODO: The reason for this test is unclear, improve documentation
def test_render_partial_and_fallback_to_layout
assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
......@@ -167,6 +190,8 @@ def test_render_partial_and_fallback_to_layout
def test_render_missing_xml_partial_and_raise_missing_template
@view.formats = [:xml]
assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }
ensure
@view.formats = nil
end
def test_render_inline
......@@ -196,17 +221,6 @@ def test_render_inline_with_locals_and_compilable_custom_type
assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
end
class LegacyHandler < ActionView::TemplateHandler
def render(template, local_assigns)
"source: #{template.source}; locals: #{local_assigns.inspect}"
end
end
def test_render_legacy_handler_with_custom_type
ActionView::Template.register_template_handler :foo, LegacyHandler
assert_equal 'source: Hello, <%= name %>!; locals: {:name=>"Josh"}', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
end
def test_render_ignores_templates_with_malformed_template_handlers
%w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name|
assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") }
......
......@@ -86,8 +86,8 @@ task :rebuild_mysql_databases => 'mysql:rebuild_databases'
namespace :postgresql do
desc 'Build the PostgreSQL test databases'
task :build_databases do
%x( createdb activerecord_unittest )
%x( createdb activerecord_unittest2 )
%x( createdb -E UTF8 activerecord_unittest )
%x( createdb -E UTF8 activerecord_unittest2 )
end
desc 'Drop the PostgreSQL test databases'
......
......@@ -381,7 +381,7 @@ def test_has_many_through_has_many_find_by_id
end
def test_has_many_through_polymorphic_has_one
assert_equal Tagging.find(1,2), authors(:david).tagging
assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).tagging
end
def test_has_many_through_polymorphic_has_many
......
......@@ -52,8 +52,8 @@ def setup
:notable_rivers => [
{ :id => 1, :name => 'Willamette' },
{ :id => 2, :name => 'Columbia', :rafted_by => @matz }],
:postal_codes => [97018,1234567890],
:places => ["Columbia City", "Unknown"]}}}
:postal_codes => [ 97018, 1234567890 ],
:places => [ "Columbia City", "Unknown" ]}}}
@person = Person.new
end
......@@ -135,7 +135,7 @@ def test_recursively_loaded_collections
assert_equal 2, postal_codes.size
assert_kind_of Fixnum, postal_codes.first
assert_equal @deep[:street][:state][:postal_codes].first, postal_codes.first
assert_kind_of Bignum, postal_codes.last
assert_kind_of Numeric, postal_codes.last
assert_equal @deep[:street][:state][:postal_codes].last, postal_codes.last
places = state.places
......
require 'abstract_unit'
# Does awesome
if ENV['CHILD']
if defined?(MiniTest)
$stderr.puts "Umm, MiniTest not supported yet, mmkay?"
elsif ENV['CHILD']
class ChildIsolationTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
......@@ -153,4 +155,4 @@ def assert_erroring(name)
end
end
end
\ No newline at end of file
end
......@@ -12,7 +12,7 @@ gems:
#version: >= 2.7
version: = 2.7
- name: pg
version: >= 0.7.9.2008.10.13
version: >= 0.8.0
- name: rack
version: '~> 1.0.0'
- name: rake
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册