diff options
48 files changed, 551 insertions, 325 deletions
@@ -63,7 +63,7 @@ platforms :ruby do gem "nokogiri", ">= 1.4.5" # AR - gem "sqlite3", "~> 1.3.3" + gem "sqlite3", "~> 1.3.4" group :db do gem "pg", ">= 0.11.0" unless ENV['TRAVIS'] # once pg is on travis this can be removed diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb index 9416bc718e..e55d72fdb4 100644 --- a/actionmailer/test/mailers/base_mailer.rb +++ b/actionmailer/test/mailers/base_mailer.rb @@ -113,6 +113,6 @@ class BaseMailer < ActionMailer::Base end def email_with_translations - mail :body => render("email_with_translations.html") + mail :body => render("email_with_translations", :formats => [:html]) end end diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 5ee14dbdf1..c3ff677529 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,13 @@ *Rails 3.2.0 (unreleased)* +* Passing formats or handlers to render :template and friends is deprecated. For example: [Nick Sutterer & José Valim] + + render :template => "foo.html.erb" + + Instead, you can provide :handlers and :formats directly as option: + + render :template => "foo", :formats => [:html, :js], :handlers => :erb + * Changed log level of warning for missing CSRF token from :debug to :warn. [Mike Dillon] * content_tag_for and div_for can now take the collection of records. It will also yield the record as the first argument if you set a receiving argument in your block [Prem Sichanugrist] diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 66dd88f0c6..d9e3e56fcc 100755 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -26,6 +26,11 @@ namespace :test do Rake::TestTask.new(:isolated) do |t| t.pattern = 'test/ts_isolated.rb' end + + Rake::TestTask.new(:template) do |t| + t.libs << 'test' + t.pattern = 'test/template/**/*.rb' + end end desc 'ActiveRecord Integration Tests' diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 6acbb23907..e0d8e1c992 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -141,19 +141,16 @@ module ActionController # try to find Foo::Bar::User, Foo::User and finally User. def _default_wrap_model #:nodoc: return nil if self.anonymous? - model_name = self.name.sub(/Controller$/, '').singularize begin - model_klass = model_name.constantize - rescue NameError, ArgumentError => e - if e.message =~ /is not missing constant|uninitialized constant #{model_name}/ + if model_klass = model_name.safe_constantize + model_klass + else namespaces = model_name.split("::") namespaces.delete_at(-2) break if namespaces.last == model_name model_name = namespaces.join("::") - else - raise end end until model_klass diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index a765c23dae..2fa68c64c5 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -86,8 +86,8 @@ module ActionDispatch :framework_trace => framework_trace(exception), :full_trace => full_trace(exception) ) - file = "rescues/#{@@rescue_templates[exception.class.name]}.erb" - body = template.render(:file => file, :layout => 'rescues/layout.erb') + file = "rescues/#{@@rescue_templates[exception.class.name]}" + body = template.render(:template => file, :layout => 'rescues/layout') render(status_code(exception), body) end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 46a68a32ae..e921269331 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -165,13 +165,14 @@ module ActionDispatch remove_possible_method :#{selector} def #{selector}(*args) options = args.extract_options! + result = #{options.inspect} if args.any? - options[:_positional_args] = args - options[:_positional_keys] = #{route.segment_keys.inspect} + result[:_positional_args] = args + result[:_positional_keys] = #{route.segment_keys.inspect} end - options ? #{options.inspect}.merge(options) : #{options.inspect} + result.merge(options) end protected :#{selector} END_EVAL diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 9ec410ac2b..fa4bf70f77 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/module/remove_method' module ActionView # = Action View Lookup Context @@ -17,23 +18,25 @@ module ActionView mattr_accessor :registered_details self.registered_details = [] - mattr_accessor :registered_detail_setters - self.registered_detail_setters = [] - def self.register_detail(name, options = {}, &block) self.registered_details << name - self.registered_detail_setters << [name, "#{name}="] + initialize = registered_details.map { |n| "self.#{n} = details[:#{n}]" } - Accessors.send :define_method, :"_#{name}_defaults", &block + Accessors.send :define_method, :"default_#{name}", &block Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{name} @details[:#{name}] end def #{name}=(value) - value = Array.wrap(value.presence || _#{name}_defaults) + value = Array.wrap(value.presence || default_#{name}) _set_detail(:#{name}, value) if value != @details[:#{name}] end + + remove_possible_method :initialize_details + def initialize_details(details) + #{initialize.join("\n")} + end METHOD end @@ -41,8 +44,9 @@ module ActionView module Accessors #:nodoc: end - register_detail(:formats) { Mime::SET.symbols } register_detail(:locale) { [I18n.locale, I18n.default_locale] } + register_detail(:formats) { Mime::SET.symbols } + register_detail(:handlers){ Template::Handlers.extensions } class DetailsKey #:nodoc: alias :eql? :equal? @@ -60,18 +64,34 @@ module ActionView end end - def initialize(view_paths, details = {}, prefixes = []) - @details, @details_key = { :handlers => default_handlers }, nil - @frozen_formats, @skip_default_locale = false, false - @cache = true - @prefixes = prefixes + # Add caching behavior on top of Details. + module DetailsCache + attr_accessor :cache - self.view_paths = view_paths - self.registered_detail_setters.each do |key, setter| - send(setter, details[key]) + # Calculate the details key. Remove the handlers from calculation to improve performance + # since the user cannot modify it explicitly. + def details_key #:nodoc: + @details_key ||= DetailsKey.get(@details) if @cache + end + + # Temporary skip passing the details_key forward. + def disable_cache + old_value, @cache = @cache, false + yield + ensure + @cache = old_value + end + + protected + + def _set_detail(key, value) + @details_key = nil + @details = @details.dup if @details.frozen? + @details[key] = value.freeze end end + # Helpers related to template lookup using the lookup context information. module ViewPaths attr_reader :view_paths @@ -81,17 +101,17 @@ module ActionView @view_paths = ActionView::PathSet.new(Array.wrap(paths)) end - def find(name, prefixes = [], partial = false, keys = []) - @view_paths.find(*args_for_lookup(name, prefixes, partial, keys)) + def find(name, prefixes = [], partial = false, keys = [], options = {}) + @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options)) end alias :find_template :find - def find_all(name, prefixes = [], partial = false, keys = []) - @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys)) + def find_all(name, prefixes = [], partial = false, keys = [], options = {}) + @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options)) end - def exists?(name, prefixes = [], partial = false, keys = []) - @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys)) + def exists?(name, prefixes = [], partial = false, keys = [], options = {}) + @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options)) end alias :template_exists? :exists? @@ -110,16 +130,29 @@ module ActionView protected - def args_for_lookup(name, prefixes, partial, keys) #:nodoc: + def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc: name, prefixes = normalize_name(name, prefixes) - [name, prefixes, partial || false, @details, details_key, keys] + details, details_key = detail_args_for(details_options) + [name, prefixes, partial || false, details, details_key, keys] + end + + # Compute details hash and key according to user options (e.g. passed from #render). + def detail_args_for(options) + return @details, details_key if options.empty? # most common path. + user_details = @details.merge(options) + [user_details, DetailsKey.get(user_details)] end # Support legacy foo.erb names even though we now ignore .erb # as well as incorrectly putting part of the path in the template # name instead of the prefix. def normalize_name(name, prefixes) #:nodoc: - name = name.to_s.gsub(handlers_regexp, '') + name = name.to_s.sub(handlers_regexp) do |match| + ActiveSupport::Deprecation.warn "Passing a template handler in the template name is deprecated. " \ + "You can simply remove the handler name or pass render :handlers => [:#{match[1..-1]}] instead.", caller + "" + end + parts = name.split('/') name = parts.pop @@ -132,120 +165,82 @@ module ActionView return name, prefixes end - def default_handlers #:nodoc: - @@default_handlers ||= Template::Handlers.extensions - end - def handlers_regexp #:nodoc: @@handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/ end end - module Details - attr_accessor :cache - - # Calculate the details key. Remove the handlers from calculation to improve performance - # since the user cannot modify it explicitly. - def details_key #:nodoc: - @details_key ||= DetailsKey.get(@details) if @cache - end - - # Temporary skip passing the details_key forward. - def disable_cache - old_value, @cache = @cache, false - yield - ensure - @cache = old_value - end + include Accessors + include DetailsCache + include ViewPaths - # Freeze the current formats in the lookup context. By freezing them, you are guaranteeing - # that next template lookups are not going to modify the formats. The controller can also - # use this, to ensure that formats won't be further modified (as it does in respond_to blocks). - def freeze_formats(formats, unless_frozen=false) #:nodoc: - return if unless_frozen && @frozen_formats - self.formats = formats - @frozen_formats = true - end + def initialize(view_paths, details = {}, prefixes = []) + @details, @details_key = {}, nil + @frozen_formats, @skip_default_locale = false, false + @cache = true + @prefixes = prefixes - # Overload formats= to expand ["*/*"] values and automatically - # add :html as fallback to :js. - def formats=(values) - if values - values.concat(_formats_defaults) if values.delete "*/*" - values << :html if values == [:js] - end - super(values) - end + self.view_paths = view_paths + initialize_details(details) + end - # Do not use the default locale on template lookup. - def skip_default_locale! - @skip_default_locale = true - self.locale = nil - end + # Freeze the current formats in the lookup context. By freezing them, you + # that next template lookups are not going to modify the formats. The con + # use this, to ensure that formats won't be further modified (as it does + def freeze_formats(formats, unless_frozen=false) #:nodoc: + return if unless_frozen && @frozen_formats + self.formats = formats + @frozen_formats = true + end - # Overload locale to return a symbol instead of array. - def locale - @details[:locale].first + # Override formats= to expand ["*/*"] values and automatically + # add :html as fallback to :js. + def formats=(values) + if values + values.concat(default_formats) if values.delete "*/*" + values << :html if values == [:js] end + super(values) + end - # Overload locale= to also set the I18n.locale. If the current I18n.config object responds - # to original_config, it means that it's has a copy of the original I18n configuration and it's - # acting as proxy, which we need to skip. - def locale=(value) - if value - config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config - config.locale = value - end + # Do not use the default locale on template lookup. + def skip_default_locale! + @skip_default_locale = true + self.locale = nil + end - super(@skip_default_locale ? I18n.locale : _locale_defaults) - end + # Override locale to return a symbol instead of array. + def locale + @details[:locale].first + end - # A method which only uses the first format in the formats array for layout lookup. - # This method plays straight with instance variables for performance reasons. - def with_layout_format - if formats.size == 1 - yield - else - old_formats = formats - _set_detail(:formats, formats[0,1]) - - begin - yield - ensure - _set_detail(:formats, old_formats) - end - end + # Overload locale= to also set the I18n.locale. If the current I18n.config object responds + # to original_config, it means that it's has a copy of the original I18n configuration and it's + # acting as proxy, which we need to skip. + def locale=(value) + if value + config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config + config.locale = value end - # Update the details keys by merging the given hash into the current - # details hash. If a block is given, the details are modified just during - # the execution of the block and reverted to the previous value after. - def update_details(new_details) - old_details = @details.dup + super(@skip_default_locale ? I18n.locale : default_locale) + end - registered_detail_setters.each do |key, setter| - send(setter, new_details[key]) if new_details.key?(key) - end + # A method which only uses the first format in the formats array for layout lookup. + # This method plays straight with instance variables for performance reasons. + def with_layout_format + if formats.size == 1 + yield + else + old_formats = formats + _set_detail(:formats, formats[0,1]) begin yield ensure - @details_key = nil - @details = old_details + _set_detail(:formats, old_formats) end end - - protected - - def _set_detail(key, value) - @details_key = nil - @details = @details.dup if @details.frozen? - @details[key] = value.freeze - end end - - include Accessors - include Details - include ViewPaths end end diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb index 60c527beeb..c0936441ac 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb @@ -11,15 +11,22 @@ module ActionView raise NotImplementedError end - # Checks if the given path contains a format and if so, change - # the lookup context to take this new format into account. - def wrap_formats(value) - return yield unless value.is_a?(String) - - if value.sub!(formats_regexp, "") - update_details(:formats => [$1.to_sym]){ yield } - else - yield + protected + + def extract_details(options) + details = {} + @lookup_context.registered_details.each do |key| + next unless value = options[key] + details[key] = Array.wrap(value) + end + details + end + + def extract_format(value, details) + if value.is_a?(String) && value.sub!(formats_regexp, "") + ActiveSupport::Deprecation.warn "Passing the format in the template name is deprecated. " \ + "Please pass render with :formats => [:#{$1}] instead.", caller + details[:formats] ||= [$1.to_sym] end end @@ -27,8 +34,6 @@ module ActionView @@formats_regexp ||= /\.(#{Mime::SET.symbols.join('|')})$/ end - protected - def instrument(name, options={}) ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield } end diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index cd0f7054a9..e808fa3415 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -216,18 +216,15 @@ module ActionView def render(context, options, block) setup(context, options, block) + identifier = (@template = find_partial) ? @template.identifier : @path - wrap_formats(@path) do - identifier = ((@template = find_partial) ? @template.identifier : @path) - - if @collection - instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do - render_collection - end - else - instrument(:partial, :identifier => identifier) do - render_partial - end + if @collection + instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do + render_collection + end + else + instrument(:partial, :identifier => identifier) do + render_partial end end end @@ -271,6 +268,7 @@ module ActionView @options = options @locals = options[:locals] || {} @block = block + @details = extract_details(options) if String === partial @object = options[:object] @@ -299,6 +297,7 @@ module ActionView "and is followed by any combinations of letters, numbers, or underscores.") end + extract_format(@path, @details) self end @@ -326,7 +325,7 @@ module ActionView def find_template(path=@path, locals=@locals.keys) prefixes = path.include?(?/) ? [] : @lookup_context.prefixes - @lookup_context.find_template(path, prefixes, true, locals) + @lookup_context.find_template(path, prefixes, true, locals, @details) end def collection_with_template diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index d04c00fd40..ac91d333ba 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -4,13 +4,12 @@ require 'active_support/core_ext/array/wrap' module ActionView class TemplateRenderer < AbstractRenderer #:nodoc: def render(context, options) - @view = context - - wrap_formats(options[:template] || options[:file]) do - template = determine_template(options) - freeze_formats(template.formats, true) - render_template(template, options[:layout], options[:locals]) - end + @view = context + @details = extract_details(options) + extract_format(options[:file] || options[:template], @details) + template = determine_template(options) + freeze_formats(template.formats, true) + render_template(template, options[:layout], options[:locals]) end # Determine the template to be rendered using the given options. @@ -20,13 +19,13 @@ module ActionView if options.key?(:text) Template::Text.new(options[:text], formats.try(:first)) elsif options.key?(:file) - with_fallbacks { find_template(options[:file], nil, false, keys) } + with_fallbacks { find_template(options[:file], nil, false, keys, @details) } elsif options.key?(:inline) handler = Template.handler_for_extension(options[:type] || "erb") Template.new(options[:inline], "inline template", handler, :locals => keys) elsif options.key?(:template) options[:template].respond_to?(:render) ? - options[:template] : find_template(options[:template], options[:prefixes], false, keys) + options[:template] : find_template(options[:template], options[:prefixes], false, keys, @details) end end @@ -62,12 +61,11 @@ module ActionView begin with_layout_format do layout =~ /^\// ? - with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys) + with_fallbacks { find_template(layout, nil, false, keys, @details) } : find_template(layout, nil, false, keys, @details) end rescue ActionView::MissingTemplate - update_details(:formats => nil) do - raise unless template_exists?(layout) - end + all_details = @details.merge(:formats => @lookup_context.default_formats) + raise unless template_exists?(layout, nil, false, keys, all_details) end end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 2cc85a9f69..c4d51d7946 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -54,10 +54,8 @@ module ActionView end def determine_default_helper_class(name) - mod = name.sub(/Test$/, '').constantize + mod = name.sub(/Test$/, '').safe_constantize mod.is_a?(Class) ? nil : mod - rescue NameError - nil end def helper_method(*methods) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 81223b7ead..7241671db0 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -1,6 +1,9 @@ namespace :assets do desc "Compile all the assets named in config.assets.precompile" task :precompile do + # let rails know we're precompiling assets + ENV["RAILS_ASSETS_PRECOMPILE"] = 'true' + # We need to do this dance because RAILS_GROUPS is used # too early in the boot process and changing here is already too late. if ENV["RAILS_GROUPS"].to_s.empty? || ENV["RAILS_ENV"].to_s.empty? @@ -20,30 +23,10 @@ namespace :assets do config = Rails.application.config env = Rails.application.assets target = Pathname.new(File.join(Rails.public_path, config.assets.prefix)) - manifest = {} manifest_path = config.assets.manifest || target - config.assets.precompile.each do |path| - env.each_logical_path do |logical_path| - if path.is_a?(Regexp) - next unless path.match(logical_path) - elsif path.is_a?(Proc) - next unless path.call(logical_path) - else - next unless File.fnmatch(path.to_s, logical_path) - end - - if asset = env.find_asset(logical_path) - asset_path = config.assets.digest ? asset.digest_path : logical_path - manifest[logical_path] = asset_path - filename = target.join(asset_path) - - mkdir_p filename.dirname - asset.write_to(filename) - asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/ - end - end - end + static_compiler = Sprockets::StaticCompiler.new(env, target, :digest => config.assets.digest) + manifest = static_compiler.precompile(config.assets.precompile) File.open("#{manifest_path}/manifest.yml", 'wb') do |f| YAML.dump(manifest, f) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index f05d835554..9b31604dbe 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -2,6 +2,7 @@ module Sprockets autoload :Helpers, "sprockets/helpers" autoload :LazyCompressor, "sprockets/compressors" autoload :NullCompressor, "sprockets/compressors" + autoload :StaticCompiler, "sprockets/static_compiler" # TODO: Get rid of config.assets.enabled class Railtie < ::Rails::Railtie diff --git a/actionpack/lib/sprockets/static_compiler.rb b/actionpack/lib/sprockets/static_compiler.rb new file mode 100644 index 0000000000..fa4f9451df --- /dev/null +++ b/actionpack/lib/sprockets/static_compiler.rb @@ -0,0 +1,53 @@ +require 'fileutils' +require 'pathname' + +module Sprockets + class StaticCompiler + attr_accessor :env, :target, :digest + + def initialize(env, target, options = {}) + @env = env + @target = target + @digest = options.key?(:digest) ? options.delete(:digest) : true + end + + def precompile(paths) + Rails.application.config.assets.digest = digest + manifest = {} + + env.each_logical_path do |logical_path| + next unless precompile_path?(logical_path, paths) + if asset = env.find_asset(logical_path) + manifest[logical_path] = compile(asset) + end + end + manifest + end + + def compile(asset) + asset_path = digest_asset(asset) + filename = target.join(asset_path) + FileUtils.mkdir_p filename.dirname + asset.write_to(filename) + asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/ + asset_path + end + + def precompile_path?(logical_path, paths) + paths.each do |path| + if path.is_a?(Regexp) + return true if path.match(logical_path) + elsif path.is_a?(Proc) + return true if path.call(logical_path) + else + return true if File.fnmatch(path.to_s, logical_path) + end + end + false + end + + def digest_asset(asset) + digest ? asset.digest_path : asset.logical_path + end + end +end diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb index 5823e64637..bf068aedcd 100644 --- a/actionpack/test/abstract/abstract_controller_test.rb +++ b/actionpack/test/abstract/abstract_controller_test.rb @@ -50,7 +50,7 @@ module AbstractController end def index_to_string - self.response_body = render_to_string "index.erb" + self.response_body = render_to_string "index" end def action_with_ivars @@ -63,11 +63,11 @@ module AbstractController end def rendering_to_body - self.response_body = render_to_body :template => "naked_render.erb" + self.response_body = render_to_body :template => "naked_render" end def rendering_to_string - self.response_body = render_to_string :template => "naked_render.erb" + self.response_body = render_to_string :template => "naked_render" end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index da3314fe6d..f3b180283f 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -197,7 +197,7 @@ class ActionCachingTestController < CachingController caches_action :layout_false, :layout => false caches_action :record_not_found, :four_oh_four, :simple_runtime_error - layout 'talk_from_action.erb' + layout 'talk_from_action' def index @cache_this = MockTime.now.to_f.to_s diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index cafe2b9320..25299eb8b8 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -79,7 +79,7 @@ class DefaultLayoutController < LayoutTest end class AbsolutePathLayoutController < LayoutTest - layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test.erb') + layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test') end class HasOwnLayoutController < LayoutTest @@ -184,7 +184,7 @@ class RenderWithTemplateOptionController < LayoutTest end class SetsNonExistentLayoutFile < LayoutTest - layout "nofile.erb" + layout "nofile" end class LayoutExceptionRaised < ActionController::TestCase diff --git a/actionpack/test/controller/new_base/render_file_test.rb b/actionpack/test/controller/new_base/render_file_test.rb index 8b2fdf8f96..a961cbf849 100644 --- a/actionpack/test/controller/new_base/render_file_test.rb +++ b/actionpack/test/controller/new_base/render_file_test.rb @@ -10,7 +10,7 @@ module RenderFile def with_instance_variables @secret = 'in the sauce' - render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb') + render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar') end def without_file_key @@ -19,7 +19,7 @@ module RenderFile def without_file_key_with_instance_variable @secret = 'in the sauce' - render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb') + render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar') end def relative_path @@ -34,16 +34,16 @@ module RenderFile def pathname @secret = 'in the sauce' - render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar.erb]) + render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar]) end def with_locals - path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals.erb') + path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals') render :file => path, :locals => {:secret => 'in the sauce'} end def without_file_key_with_locals - path = FIXTURES.join('test/render_file_with_locals.erb').to_s + path = FIXTURES.join('test/render_file_with_locals').to_s render path, :locals => {:secret => 'in the sauce'} end end diff --git a/actionpack/test/controller/new_base/render_partial_test.rb b/actionpack/test/controller/new_base/render_partial_test.rb index 83b0d039ad..b4a25c49c9 100644 --- a/actionpack/test/controller/new_base/render_partial_test.rb +++ b/actionpack/test/controller/new_base/render_partial_test.rb @@ -7,12 +7,12 @@ module RenderPartial self.view_paths = [ActionView::FixtureResolver.new( "render_partial/basic/_basic.html.erb" => "BasicPartial!", "render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>", - "render_partial/basic/with_json.html.erb" => "<%= render 'with_json.json' %>", - "render_partial/basic/_with_json.json.erb" => "<%= render 'final' %>", + "render_partial/basic/with_json.html.erb" => "<%= render :partial => 'with_json', :formats => [:json] %>", + "render_partial/basic/_with_json.json.erb" => "<%= render :partial => 'final', :formats => [:json] %>", "render_partial/basic/_final.json.erb" => "{ final: json }", - "render_partial/basic/overriden.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'overriden' %><%= @test_unchanged %>", - "render_partial/basic/_overriden.html.erb" => "ParentPartial!", - "render_partial/child/_overriden.html.erb" => "OverridenPartial!" + "render_partial/basic/overriden.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'overriden' %><%= @test_unchanged %>", + "render_partial/basic/_overriden.html.erb" => "ParentPartial!", + "render_partial/child/_overriden.html.erb" => "OverridenPartial!" )] def html_with_json_inside_json diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index 584f2d772c..ba804421da 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -10,8 +10,8 @@ module RenderTemplate "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend", "with_raw.html.erb" => "Hello <%=raw '<strong>this is raw</strong>' %>", "with_implicit_raw.html.erb" => "Hello <%== '<strong>this is also raw</strong>' %>", - "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>", - "test/with_json.json.erb" => "<%= render :template => 'test/final' %>", + "test/with_json.html.erb" => "<%= render :template => 'test/with_json', :formats => [:json] %>", + "test/with_json.json.erb" => "<%= render :template => 'test/final', :formats => [:json] %>", "test/final.json.erb" => "{ final: json }", "test/with_error.html.erb" => "<%= idontexist %>" )] @@ -117,7 +117,7 @@ module RenderTemplate assert_response "{ final: json }" end - test "rendering a template with error properly exceprts the code" do + test "rendering a template with error properly excerts the code" do get :with_error assert_status 500 assert_match "undefined local variable or method `idontexist'", response.body diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index c46755417f..aea603b014 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -163,14 +163,14 @@ class TestController < ActionController::Base # :ported: def render_file_with_instance_variables @secret = 'in the sauce' - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') + path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar') render :file => path end # :ported: def render_file_as_string_with_instance_variables @secret = 'in the sauce' - path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) + path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar')) render path end @@ -187,21 +187,21 @@ class TestController < ActionController::Base def render_file_using_pathname @secret = 'in the sauce' - render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar.erb') + render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar') end def render_file_from_template @secret = 'in the sauce' - @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) + @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar')) end def render_file_with_locals - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb') + path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals') render :file => path, :locals => {:secret => 'in the sauce'} end def render_file_as_string_with_locals - path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')) + path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals')) render path, :locals => {:secret => 'in the sauce'} end @@ -453,17 +453,13 @@ class TestController < ActionController::Base render :action => "potential_conflicts" end - # :deprecated: - # Tests being able to pick a .builder template over a .erb - # For instance, being able to have hello.xml.builder and hello.xml.erb - # and select one via "hello.builder" or "hello.erb" def hello_world_from_rxml_using_action - render :action => "hello_world_from_rxml.builder" + render :action => "hello_world_from_rxml", :handlers => [:builder] end # :deprecated: def hello_world_from_rxml_using_template - render :template => "test/hello_world_from_rxml.builder" + render :template => "test/hello_world_from_rxml", :handlers => [:builder] end def action_talk_to_layout @@ -525,8 +521,8 @@ class TestController < ActionController::Base render :action => "using_layout_around_block", :layout => "layouts/block_with_layout" end - def partial_dot_html - render :partial => 'partial.html.erb' + def partial_formats_html + render :partial => 'partial', :formats => [:html] end def partial @@ -797,7 +793,9 @@ class RenderTest < ActionController::TestCase end def test_render_file - get :hello_world_file + assert_deprecated do + get :hello_world_file + end assert_equal "Hello world!", @response.body end @@ -1233,8 +1231,8 @@ class RenderTest < ActionController::TestCase assert_equal 'partial html', @response.body end - def test_should_render_html_partial_with_dot - get :partial_dot_html + def test_should_render_html_partial_with_formats + get :partial_formats_html assert_equal 'partial html', @response.body end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 9685b24c1c..c0b74bc9f9 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -863,6 +863,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal original_options, options end + # tests the arguments modification free version of define_hash_access + def test_named_route_with_no_side_effects + original_options = { :host => 'test.host' } + options = original_options.dup + + profile_customer_url("customer_model", options) + + # verify that the options passed in have not changed from the original ones + assert_equal original_options, options + end + def test_projects_status with_test_routes do assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true) diff --git a/actionpack/test/fixtures/comments/empty.de.html.erb b/actionpack/test/fixtures/comments/empty.de.html.erb new file mode 100644 index 0000000000..cffd90dd26 --- /dev/null +++ b/actionpack/test/fixtures/comments/empty.de.html.erb @@ -0,0 +1 @@ +<h1>Kein Kommentar</h1>
\ No newline at end of file diff --git a/actionpack/test/fixtures/comments/empty.html.builder b/actionpack/test/fixtures/comments/empty.html.builder new file mode 100644 index 0000000000..2b0c7207a3 --- /dev/null +++ b/actionpack/test/fixtures/comments/empty.html.builder @@ -0,0 +1 @@ +xml.h1 'No Comment'
\ No newline at end of file diff --git a/actionpack/test/fixtures/comments/empty.html.erb b/actionpack/test/fixtures/comments/empty.html.erb new file mode 100644 index 0000000000..827f3861de --- /dev/null +++ b/actionpack/test/fixtures/comments/empty.html.erb @@ -0,0 +1 @@ +<h1>No Comment</h1>
\ No newline at end of file diff --git a/actionpack/test/fixtures/comments/empty.xml.erb b/actionpack/test/fixtures/comments/empty.xml.erb new file mode 100644 index 0000000000..db1027cd7d --- /dev/null +++ b/actionpack/test/fixtures/comments/empty.xml.erb @@ -0,0 +1 @@ +<error>No Comment</error>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb b/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb index 5db0822f07..820e7db789 100644 --- a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb +++ b/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb @@ -1,4 +1,4 @@ Before -<%= render :partial => "test/partial.html.erb" %> +<%= render :partial => "test/partial" %> <%= yield %> After diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index 8be0f452fb..8fc78283d8 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -10,24 +10,24 @@ class CompiledTemplatesTest < Test::Unit::TestCase end def test_template_gets_recompiled_when_using_different_keys_in_local_assigns - 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" }) + assert_equal "one", render(:file => "test/render_file_with_locals_and_default") + assert_equal "two", render(:file => "test/render_file_with_locals_and_default", :locals => { :secret => "two" }) end def test_template_changes_are_not_reflected_with_cached_templates - assert_equal "Hello world!", render(:file => "test/hello_world.erb") + assert_equal "Hello world!", render(:file => "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Hello world!", render(:file => "test/hello_world.erb") + assert_equal "Hello world!", render(:file => "test/hello_world") end - assert_equal "Hello world!", render(:file => "test/hello_world.erb") + assert_equal "Hello world!", render(:file => "test/hello_world") end def test_template_changes_are_reflected_with_uncached_templates - assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb") + assert_equal "Hello world!", render_without_cache(:file => "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world.erb") + assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world") end - assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb") + assert_equal "Hello world!", render_without_cache(:file => "test/hello_world") end private diff --git a/actionpack/test/template/log_subscriber_test.rb b/actionpack/test/template/log_subscriber_test.rb index 50e1cccd3b..752b0f23a8 100644 --- a/actionpack/test/template/log_subscriber_test.rb +++ b/actionpack/test/template/log_subscriber_test.rb @@ -27,7 +27,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase end def test_render_file_template - @view.render(:file => "test/hello_world.erb") + @view.render(:file => "test/hello_world") wait assert_equal 1, @logger.logged(:info).size diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index 47b70f05ab..bac2530e3d 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -31,16 +31,6 @@ class LookupContextTest < ActiveSupport::TestCase assert @lookup_context.formats.frozen? end - test "allows me to change some details to execute an specific block of code" do - formats = Mime::SET - @lookup_context.update_details(:locale => :pt) do - assert_equal formats, @lookup_context.formats - assert_equal :pt, @lookup_context.locale - end - assert_equal formats, @lookup_context.formats - assert_equal :en, @lookup_context.locale - end - test "provides getters and setters for formats" do @lookup_context.formats = [:html] assert_equal [:html], @lookup_context.formats diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 8a582030f6..0ef3239f83 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -21,18 +21,48 @@ module RenderTestCases end def test_render_file - assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb") + assert_equal "Hello world!", @view.render(:file => "test/hello_world") end def test_render_file_not_using_full_path - assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb") + assert_equal "Hello world!", @view.render(:file => "test/hello_world") end def test_render_file_without_specific_extension assert_equal "Hello world!", @view.render(:file => "test/hello_world") end - def test_render_file_with_localization + # Test if :formats, :locale etc. options are passed correctly to the resolvers. + def test_render_file_with_format + assert_match "<h1>No Comment</h1>", @view.render(:file => "comments/empty", :formats => [:html]) + assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => [:xml]) + assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => :xml) + end + + def test_render_template_with_format + assert_match "<h1>No Comment</h1>", @view.render(:template => "comments/empty", :formats => [:html]) + assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml]) + end + + def test_render_file_with_locale + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => [:de]) + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => :de) + end + + def test_render_template_with_locale + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:template => "comments/empty", :locale => [:de]) + end + + def test_render_file_with_handlers + assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => [:builder]) + assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => :builder) + end + + def test_render_template_with_handlers + assert_equal "<h1>No Comment</h1>\n", @view.render(:template => "comments/empty", :handlers => [:builder]) + end + + def test_render_file_with_localization_on_context_level old_locale, @view.locale = @view.locale, :da assert_equal "Hey verden", @view.render(:file => "test/hello_world") ensure @@ -51,17 +81,17 @@ module RenderTestCases end def test_render_file_with_full_path - template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world.erb') + template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world') assert_equal "Hello world!", @view.render(:file => template_path) end def test_render_file_with_instance_variables - assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar.erb") + assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar") end def test_render_file_with_locals locals = { :secret => 'in the sauce' } - assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals.erb", :locals => locals) + assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals", :locals => locals) end def test_render_file_not_using_full_path_with_dot_in_path @@ -80,13 +110,18 @@ module RenderTestCases assert_equal 'partial html', @view.render(:partial => 'test/partial') end + def test_render_partial_with_selected_format + assert_equal 'partial html', @view.render(:partial => 'test/partial', :formats => :html) + assert_equal 'partial js', @view.render(:partial => 'test/partial', :formats => [:js]) + end + def test_render_partial_at_top_level - # file fixtures/_top_level_partial_only.erb (not fixtures/test) + # file fixtures/_top_level_partial_only (not fixtures/test) assert_equal 'top level partial', @view.render(:partial => '/top_level_partial_only') end def test_render_partial_with_format_at_top_level - # file fixtures/_top_level_partial.html.erb (not fixtures/test, with format extension) + # file fixtures/_top_level_partial.html (not fixtures/test, with format extension) assert_equal 'top level partial html', @view.render(:partial => '/top_level_partial') end @@ -245,7 +280,7 @@ module RenderTestCases end def test_render_layout_with_block_and_other_partial_inside - render = @view.render(:layout => "test/layout_with_partial_and_yield.html.erb") { "Yield!" } + render = @view.render(:layout => "test/layout_with_partial_and_yield") { "Yield!" } assert_equal "Before\npartial html\nYield!\nAfter\n", render end @@ -282,24 +317,26 @@ module RenderTestCases 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}") } + ActiveSupport::Deprecation.silence do + %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| + assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } + end end end def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), - @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield") + @view.render(:file => "test/hello_world", :layout => "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), - @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside") + @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), - @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside") + @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") end def test_render_layout_with_block_and_yield @@ -344,17 +381,17 @@ module RenderTestCases def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), - @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") + @view.render(:file => "test/nested_layout", :layout => "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\n<title>title</title>\n\n), - @view.render(:file => "test/layout_render_file.erb") + @view.render(:file => "test/layout_render_file") end def test_render_layout_with_object assert_equal %(<title>David</title>), - @view.render(:file => "test/layout_render_object.erb") + @view.render(:file => "test/layout_render_object") end end @@ -392,7 +429,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase if '1.9'.respond_to?(:force_encoding) def test_render_utf8_template_with_magic_comment with_external_encoding Encoding::ASCII_8BIT do - result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") + result = @view.render(:file => "test/utf8_magic.html", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -400,7 +437,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_default_external_encoding with_external_encoding Encoding::UTF_8 do - result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + result = @view.render(:file => "test/utf8.html", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -409,7 +446,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do begin - @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + @view.render(:file => "test/utf8.html", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message @@ -420,7 +457,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do begin - @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") + @view.render(:file => "test/utf8_magic_with_bare_partial.html", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message diff --git a/actionpack/test/template/streaming_render_test.rb b/actionpack/test/template/streaming_render_test.rb index 023ce723ed..4d01352b43 100644 --- a/actionpack/test/template/streaming_render_test.rb +++ b/actionpack/test/template/streaming_render_test.rb @@ -28,7 +28,7 @@ class FiberedTest < ActiveSupport::TestCase def test_streaming_works content = [] - body = render_body(:template => "test/hello_world.erb", :layout => "layouts/yield") + body = render_body(:template => "test/hello_world", :layout => "layouts/yield") body.each do |piece| content << piece @@ -42,12 +42,12 @@ class FiberedTest < ActiveSupport::TestCase end def test_render_file - assert_equal "Hello world!", buffered_render(:file => "test/hello_world.erb") + assert_equal "Hello world!", buffered_render(:file => "test/hello_world") end def test_render_file_with_locals locals = { :secret => 'in the sauce' } - assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals.erb", :locals => locals) + assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals", :locals => locals) end def test_render_partial @@ -64,27 +64,27 @@ class FiberedTest < ActiveSupport::TestCase def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), - buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield") + buffered_render(:template => "test/hello_world", :layout => "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), - buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside") + buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), - buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside") + buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") end def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), - buffered_render(:template => "test/nested_layout.erb", :layout => "layouts/yield") + buffered_render(:template => "test/nested_layout", :layout => "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\n<title>title</title>\n\n), - buffered_render(:template => "test/layout_render_file.erb") + buffered_render(:template => "test/layout_render_file") end def test_render_with_handler_without_streaming_support diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index 4fbccd7419..885964633f 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -86,21 +86,15 @@ module ActiveModel # "title": "Welcome to the weblog"}, # {"comments": [{"body": "Don't think too hard"}], # "title": "So I was thinking"}]} - def as_json(options = nil) - hash = serializable_hash(options) - - include_root = include_root_in_json - if options.try(:key?, :root) - include_root = options[:root] + root = include_root_in_json + root = options[:root] if options.try(:key?, :root) + if root + root = self.class.model_name.element if root == true + { root => serializable_hash(options) } + else + serializable_hash(options) end - - if include_root - custom_root = options && options[:root] - hash = { custom_root || self.class.model_name.element => hash } - end - - hash end def from_json(json, include_root=include_root_in_json) diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 5e1e7d897a..40fdcf20ca 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -56,6 +56,16 @@ class JsonSerializationTest < ActiveModel::TestCase end end + test "should include root in json (option) even if the default is set to false" do + begin + Contact.include_root_in_json = false + json = @contact.to_json(:root => true) + assert_match %r{^\{"contact":\{}, json + ensure + Contact.include_root_in_json = true + end + end + test "should not include root in json (option)" do json = @contact.to_json(:root => false) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 537980d6a1..63f406cd9f 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.2.0 (unreleased)* +* Added safe_constantize that constantizes a string but returns nil instead of an exception if the constant (or part of it) does not exist [Ryan Oblak] + * ActiveSupport::OrderedHash is now marked as extractable when using Array#extract_options! [Prem Sichanugrist] * Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH] diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index f7c01948b4..3f516d4808 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -13,6 +13,7 @@ module ActiveSupport attr_reader :cache_path DIR_FORMATTER = "%03X" + FILENAME_MAX_SIZE = 230 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write) def initialize(cache_path, options = nil) super(options) @@ -129,15 +130,13 @@ module ActiveSupport hash, dir_1 = hash.divmod(0x1000) dir_2 = hash.modulo(0x1000) fname_paths = [] - # Make sure file name is < 255 characters so it doesn't exceed file system limits. - if fname.size <= 255 - fname_paths << fname - else - while fname.size <= 255 - fname_path << fname[0, 255] - fname = fname[255, -1] - end - end + + # Make sure file name doesn't exceed file system limits. + begin + fname_paths << fname[0, FILENAME_MAX_SIZE] + fname = fname[FILENAME_MAX_SIZE..-1] + end until fname.blank? + File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths) end diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb index 443d2c3d53..5d3d0e9851 100644 --- a/activesupport/lib/active_support/core_ext/module/reachable.rb +++ b/activesupport/lib/active_support/core_ext/module/reachable.rb @@ -3,8 +3,6 @@ require 'active_support/core_ext/string/inflections' class Module def reachable? #:nodoc: - !anonymous? && name.constantize.equal?(self) - rescue NameError - false + !anonymous? && name.safe_constantize.equal?(self) end end diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 002688d6c0..b4218cb42c 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -33,14 +33,27 @@ class String # +constantize+ tries to find a declared constant with the name specified # in the string. It raises a NameError when the name is not in CamelCase - # or is not initialized. + # or is not initialized. See ActiveSupport::Inflector.constantize # # Examples - # "Module".constantize # => Module - # "Class".constantize # => Class + # "Module".constantize # => Module + # "Class".constantize # => Class + # "blargle".safe_constantize # => NameError: wrong constant name blargle def constantize ActiveSupport::Inflector.constantize(self) end + + # +safe_constantize+ tries to find a declared constant with the name specified + # in the string. It returns nil when the name is not in CamelCase + # or is not initialized. See ActiveSupport::Inflector.safe_constantize + # + # Examples + # "Module".safe_constantize # => Module + # "Class".safe_constantize # => Class + # "blargle".safe_constantize # => nil + def safe_constantize + ActiveSupport::Inflector.safe_constantize(self) + end # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize # is set to <tt>:lower</tt> then camelize produces lowerCamelCase. diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 3ae3d64fa4..94999807dd 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -144,7 +144,7 @@ module ActiveSupport #:nodoc: UNSAFE_STRING_METHODS.each do |unsafe_method| class_eval <<-EOT, __FILE__, __LINE__ + 1 def #{unsafe_method}(*args, &block) # def capitalize(*args, &block) - to_str.#{unsafe_method}(*args, &block) # to_str.gsub(*args, &block) + to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block) end # end def #{unsafe_method}!(*args) # def capitalize!(*args) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 423b5abd20..934529d496 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -224,6 +224,39 @@ module ActiveSupport end end + # Tries to find a constant with the name specified in the argument string: + # + # "Module".safe_constantize # => Module + # "Test::Unit".safe_constantize # => Test::Unit + # + # The name is assumed to be the one of a top-level constant, no matter whether + # it starts with "::" or not. No lexical context is taken into account: + # + # C = 'outside' + # module M + # C = 'inside' + # C # => 'inside' + # "C".safe_constantize # => 'outside', same as ::C + # end + # + # nil is returned when the name is not in CamelCase or the constant (or part of it) is + # unknown. + # + # "blargle".safe_constantize # => nil + # "UnknownModule".safe_constantize # => nil + # "UnknownModule::Foo::Bar".safe_constantize # => nil + # + def safe_constantize(camel_cased_word) + begin + constantize(camel_cased_word) + rescue NameError => e + raise unless e.message =~ /uninitialized constant #{const_regexp(camel_cased_word)}$/ || + e.name.to_s == camel_cased_word.to_s + rescue ArgumentError => e + raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/ + end + end + # Turns a number into an ordinal string used to denote the position in an # ordered sequence such as 1st, 2nd, 3rd, 4th. # @@ -246,5 +279,18 @@ module ActiveSupport end end end + + private + + # Mount a regular expression that will match part by part of the constant. + # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)? + def const_regexp(camel_cased_word) #:nodoc: + parts = camel_cased_word.split("::") + last = parts.pop + + parts.reverse.inject(last) do |acc, part| + part.empty? ? acc : "#{part}(::#{acc})?" + end + end end end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 6bb13ec9b8..b692a41312 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -357,7 +357,7 @@ module CacheStoreBehavior def test_really_long_keys key = "" - 1000.times{key << "x"} + 900.times{key << "x"} assert_equal true, @cache.write(key, "bar") assert_equal "bar", @cache.read(key) assert_equal "bar", @cache.fetch(key) @@ -557,6 +557,15 @@ class FileStoreTest < ActiveSupport::TestCase key = @cache_with_pathname.send(:key_file_path, "views/index?id=1") assert_equal "views/index?id=1", @cache_with_pathname.send(:file_path_key, key) end + + # Because file systems have a maximum filename size, filenames > max size should be split in to directories + # If filename is 'AAAAB', where max size is 4, the returned path should be AAAA/B + def test_key_transformation_max_filename_size + key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}B" + path = @cache.send(:key_file_path, key) + assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE} + assert_equal 'B', File.basename(path) + end end class MemoryStoreTest < ActiveSupport::TestCase diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb new file mode 100644 index 0000000000..81d200a0c8 --- /dev/null +++ b/activesupport/test/constantize_test_cases.rb @@ -0,0 +1,37 @@ +module Ace + module Base + class Case + end + end +end + +module ConstantizeTestCases + def run_constantize_tests_on + assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") } + assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") } + assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } + assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } + assert_raise(NameError) { yield("UnknownClass") } + assert_raise(NameError) { yield("UnknownClass::Ace") } + assert_raise(NameError) { yield("UnknownClass::Ace::Base") } + assert_raise(NameError) { yield("An invalid string") } + assert_raise(NameError) { yield("InvalidClass\n") } + assert_raise(NameError) { yield("Ace::ConstantizeTestCases") } + assert_raise(NameError) { yield("Ace::Base::ConstantizeTestCases") } + end + + def run_safe_constantize_tests_on + assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") } + assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") } + assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } + assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } + assert_nothing_raised { assert_equal nil, yield("UnknownClass") } + assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace") } + assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace::Base") } + assert_nothing_raised { assert_equal nil, yield("An invalid string") } + assert_nothing_raised { assert_equal nil, yield("InvalidClass\n") } + assert_nothing_raised { assert_equal nil, yield("blargle") } + assert_nothing_raised { assert_equal nil, yield("Ace::ConstantizeTestCases") } + assert_nothing_raised { assert_equal nil, yield("Ace::Base::ConstantizeTestCases") } + end +end
\ No newline at end of file diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 81a284dded..5c1dddaf96 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -2,6 +2,7 @@ require 'date' require 'abstract_unit' require 'inflector_test_cases' +require 'constantize_test_cases' require 'active_support/inflector' require 'active_support/core_ext/string' @@ -9,9 +10,17 @@ require 'active_support/time' require 'active_support/core_ext/string/strip' require 'active_support/core_ext/string/output_safety' +module Ace + module Base + class Case + end + end +end + class StringInflectionsTest < Test::Unit::TestCase include InflectorTestCases - + include ConstantizeTestCases + def test_erb_escape string = [192, 60].pack('CC') expected = 192.chr + "<" @@ -292,6 +301,18 @@ class StringInflectionsTest < Test::Unit::TestCase "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8').truncate(10) end end + + def test_constantize + run_constantize_tests_on do |string| + string.constantize + end + end + + def test_safe_constantize + run_safe_constantize_tests_on do |string| + string.safe_constantize + end + end end class StringBehaviourTest < Test::Unit::TestCase diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index b9e299af75..5c956e0075 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -2,16 +2,11 @@ require 'abstract_unit' require 'active_support/inflector' require 'inflector_test_cases' - -module Ace - module Base - class Case - end - end -end +require 'constantize_test_cases' class InflectorTest < Test::Unit::TestCase include InflectorTestCases + include ConstantizeTestCases def test_pluralize_plurals assert_equal "plurals", ActiveSupport::Inflector.pluralize("plurals") @@ -282,17 +277,15 @@ class InflectorTest < Test::Unit::TestCase end def test_constantize - assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("Ace::Base::Case") } - assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("::Ace::Base::Case") } - assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("InflectorTest") } - assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("::InflectorTest") } - assert_raise(NameError) { ActiveSupport::Inflector.constantize("UnknownClass") } - assert_raise(NameError) { ActiveSupport::Inflector.constantize("An invalid string") } - assert_raise(NameError) { ActiveSupport::Inflector.constantize("InvalidClass\n") } + run_constantize_tests_on do |string| + ActiveSupport::Inflector.constantize(string) + end end - - def test_constantize_does_lexical_lookup - assert_raise(NameError) { ActiveSupport::Inflector.constantize("Ace::Base::InflectorTest") } + + def test_safe_constantize + run_safe_constantize_tests_on do |string| + ActiveSupport::Inflector.safe_constantize(string) + end end def test_ordinal diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index a48db3b6d2..141b39fb4b 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -38,7 +38,7 @@ module Rails @assets.enabled = false @assets.paths = [] @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) }, - /application.(css|js)$/ ] + /(?:\/|\\|\A)application\.(css|js)$/ ] @assets.prefix = "/assets" @assets.version = '' @assets.debug = false diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 160baa6906..f4efd3af74 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -5,6 +5,9 @@ source "http://rubygems.org" # development dependencies will be added by default to the :development group. gemspec +# jquery-rails is used by the dummy application +gem "jquery-rails" + # Declare any dependencies that are still in development here instead of in # your gemspec. These might include edge Rails or gems from your path or # Git. Remember to move these dependencies to your gemspec before releasing @@ -17,4 +20,4 @@ gemspec <% end -%> # To use debugger -# <%= ruby_debugger_gemfile_entry %>
\ No newline at end of file +# <%= ruby_debugger_gemfile_entry %> diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index dfd950aae3..c4a24f0f73 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -68,6 +68,10 @@ module ApplicationTests test "precompile application.js and application.css and all other files not ending with .js or .css by default" do app_file "app/assets/javascripts/application.js", "alert();" app_file "app/assets/stylesheets/application.css", "body{}" + + app_file "app/assets/javascripts/someapplication.js", "alert();" + app_file "app/assets/stylesheets/someapplication.css", "body{}" + app_file "app/assets/javascripts/something.min.js", "alert();" app_file "app/assets/stylesheets/something.min.css", "body{}" @@ -87,12 +91,26 @@ module ApplicationTests images_should_compile.each do |filename| assert File.exists?("#{app_path}/public/assets/#{filename}") end + assert File.exists?("#{app_path}/public/assets/application.js") assert File.exists?("#{app_path}/public/assets/application.css") + + assert !File.exists?("#{app_path}/public/assets/someapplication.js") + assert !File.exists?("#{app_path}/public/assets/someapplication.css") + assert !File.exists?("#{app_path}/public/assets/something.min.js") assert !File.exists?("#{app_path}/public/assets/something.min.css") end + test "precompile sets flag notifying rails its precompiling" do + compile = <<COMPILE +raise "ENV RAILS_ASSETS_PRECOMPILE not set" unless ENV["RAILS_ASSETS_PRECOMPILE"] +COMPILE + app_file "config/initializers/compile.rb", compile + Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + assert $?.success? + end + test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do add_to_config "config.assets.digest = true" add_to_config "config.action_controller.perform_caching = false" |