diff options
author | Rizwan Reza <rizwanreza@gmail.com> | 2010-03-28 12:04:00 +0430 |
---|---|---|
committer | Rizwan Reza <rizwanreza@gmail.com> | 2010-03-28 12:04:00 +0430 |
commit | b4c91de9462f59d6395c7c871aafa3301afdc383 (patch) | |
tree | fadcaf603a6f473e8ccd52070a1f3b4f957c34cb | |
parent | 4b4f69b9bfbd33556e23262f57cf6d944dfd9f63 (diff) | |
parent | 66d57d7ba83df52ff1e0485c89f6192c2f84c6b8 (diff) | |
download | rails-b4c91de9462f59d6395c7c871aafa3301afdc383.tar.gz rails-b4c91de9462f59d6395c7c871aafa3301afdc383.tar.bz2 rails-b4c91de9462f59d6395c7c871aafa3301afdc383.zip |
Merge remote branch 'rails/master'
411 files changed, 3065 insertions, 1786 deletions
@@ -7,14 +7,17 @@ gem "rails", "3.0.0.beta1" gem "rake", ">= 0.8.7" gem "mocha", ">= 0.9.8" -if RUBY_VERSION < '1.9' - gem "ruby-debug", ">= 0.10.3" +group :mri do + if RUBY_VERSION < '1.9' + gem "system_timer" + gem "ruby-debug", ">= 0.10.3" + end end # AR gem "sqlite3-ruby", ">= 1.2.5", :require => 'sqlite3' -group :test do +group :db do gem "pg", ">= 0.9.0" gem "mysql", ">= 2.8.1" end @@ -49,13 +49,13 @@ end desc "Install gems for all projects." task :install => :gem do - require File.expand_path("../actionpack/lib/action_pack/version", __FILE__) + version = File.read("RAILS_VERSION").strip (PROJECTS - ["railties"]).each do |project| puts "INSTALLING #{project}" - system("gem install #{project}/pkg/#{project}-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc") + system("gem install #{project}/pkg/#{project}-#{version}.gem --no-ri --no-rdoc") end - system("gem install railties/pkg/railties-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc") - system("gem install pkg/rails-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc") + system("gem install railties/pkg/railties-#{version}.gem --no-ri --no-rdoc") + system("gem install pkg/rails-#{version}.gem --no-ri --no-rdoc") end desc "Generate documentation for the Rails framework" diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index f94e23fe05..0519783d02 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,6 +1,7 @@ require 'mail' require 'action_mailer/tmail_compat' require 'action_mailer/collector' +require 'active_support/core_ext/array/wrap' module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. @@ -590,7 +591,7 @@ module ActionMailer #:nodoc: responses, parts_order = [], nil if block_given? - collector = ActionMailer::Collector.new(self) { render(action_name) } + collector = ActionMailer::Collector.new(lookup_context) { render(action_name) } yield(collector) parts_order = collector.responses.map { |r| r[:content_type] } responses = collector.responses @@ -604,6 +605,8 @@ module ActionMailer #:nodoc: templates_name = headers.delete(:template_name) || action_name each_template(templates_path, templates_name) do |template| + self.formats = template.formats + responses << { :body => render(:template => template), :content_type => template.mime_type.to_s @@ -615,7 +618,7 @@ module ActionMailer #:nodoc: end def each_template(paths, name, &block) #:nodoc: - Array(paths).each do |path| + Array.wrap(paths).each do |path| templates = lookup_context.find_all(name, path) templates = templates.uniq_by { |t| t.formats } diff --git a/actionmailer/lib/action_mailer/collector.rb b/actionmailer/lib/action_mailer/collector.rb index 5431efccfe..d03e085e83 100644 --- a/actionmailer/lib/action_mailer/collector.rb +++ b/actionmailer/lib/action_mailer/collector.rb @@ -11,7 +11,6 @@ module ActionMailer #:nodoc: @context = context @responses = [] @default_render = block - @default_formats = context.formats end def any(*args, &block) @@ -21,16 +20,11 @@ module ActionMailer #:nodoc: end alias :all :any - def custom(mime, options={}, &block) + def custom(mime, options={}) options.reverse_merge!(:content_type => mime.to_s) - @context.formats = [mime.to_sym] - options[:body] = if block - block.call - else - @default_render.call - end + @context.freeze_formats([mime.to_sym]) + options[:body] = block_given? ? yield : @default_render.call @responses << options - @context.formats = @default_formats end end end
\ No newline at end of file diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb index fb4b6701dd..c7f341d46c 100644 --- a/actionmailer/lib/action_mailer/old_api.rb +++ b/actionmailer/lib/action_mailer/old_api.rb @@ -31,9 +31,6 @@ module ActionMailer # replies to this message. adv_attr_accessor :reply_to - # Specify additional headers to be added to the message. - adv_attr_accessor :headers - # Specify the order in which parts should be sorted, based on content-type. # This defaults to the value for the +default_implicit_parts_order+. adv_attr_accessor :implicit_parts_order @@ -207,6 +204,7 @@ module ActionMailer @parts.unshift create_inline_part(@body) elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ } lookup_context.find_all(@template, @mailer_name).each do |template| + self.formats = template.formats @parts << create_inline_part(render(:template => template), template.mime_type) end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index 0182e48425..2703367fdb 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -3,14 +3,14 @@ require "rails" module ActionMailer class Railtie < Rails::Railtie - railtie_name :action_mailer + config.action_mailer = ActiveSupport::OrderedOptions.new initializer "action_mailer.url_for", :before => :load_environment_config do |app| ActionMailer.base_hook { include app.routes.url_helpers } end require "action_mailer/railties/log_subscriber" - log_subscriber ActionMailer::Railties::LogSubscriber.new + log_subscriber :action_mailer, ActionMailer::Railties::LogSubscriber.new initializer "action_mailer.logger" do ActionMailer.base_hook { self.logger ||= Rails.logger } diff --git a/actionmailer/lib/action_mailer/railties/log_subscriber.rb b/actionmailer/lib/action_mailer/railties/log_subscriber.rb index d1b3dd33af..af76d807d0 100644 --- a/actionmailer/lib/action_mailer/railties/log_subscriber.rb +++ b/actionmailer/lib/action_mailer/railties/log_subscriber.rb @@ -1,8 +1,10 @@ +require 'active_support/core_ext/array/wrap' + module ActionMailer module Railties class LogSubscriber < Rails::LogSubscriber def deliver(event) - recipients = Array(event.payload[:to]).join(', ') + recipients = Array.wrap(event.payload[:to]).join(', ') info("\nSent mail to #{recipients} (%1.fms)" % event.duration) debug(event.payload[:mail]) end @@ -17,4 +19,4 @@ module ActionMailer end end end -end
\ No newline at end of file +end diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 16fef3a9a4..ea15709b45 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -1,4 +1,23 @@ -require File.expand_path('../../../load_paths', __FILE__) +# Pathname has a warning, so require it first while silencing +# warnings to shut it up. +# +# Also, in 1.9, Bundler creates warnings due to overriding +# Rubygems methods +begin + old, $VERBOSE = $VERBOSE, nil + require 'pathname' + require File.expand_path('../../../load_paths', __FILE__) +ensure + $VERBOSE = old +end + + +require 'active_support/core_ext/kernel/reporting' +silence_warnings do + # These external dependencies have warnings :/ + require 'text/format' + require 'mail' +end lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index f5fd12a6b0..6f274c11df 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -74,13 +74,20 @@ class BaseTest < ActiveSupport::TestCase end end - def custom_block(include_html=false) + def explicit_multipart_with_options(include_html = false) mail do |format| format.text(:content_transfer_encoding => "base64"){ render "welcome" } format.html{ render "welcome" } if include_html end end + def explicit_multipart_with_one_template(hash = {}) + mail(hash) do |format| + format.html + format.text + end + end + def implicit_different_template(template_name='') mail(:template_name => template_name) end @@ -148,6 +155,13 @@ class BaseTest < ActiveSupport::TestCase assert_equal("Hello there", email.body.encoded) end + test "should set template content type if mail has only one part" do + mail = BaseMailer.html_only + assert_equal('text/html', mail.mime_type) + mail = BaseMailer.plain_text_only + assert_equal('text/plain', mail.mime_type) + end + # Custom headers test "custom headers" do email = BaseMailer.welcome @@ -162,7 +176,7 @@ class BaseTest < ActiveSupport::TestCase assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) end - test "can pass random headers in as a hash" do + test "can pass random headers in as a hash to headers" do hash = {'X-Special-Domain-Specific-Header' => "SecretValue", 'In-Reply-To' => '1234@mikel.me.com' } mail = BaseMailer.welcome_with_headers(hash) @@ -366,6 +380,11 @@ class BaseTest < ActiveSupport::TestCase assert_equal("HTML Explicit Multipart", email.parts[1].body.encoded) end + test "explicit multipart have a boundary" do + mail = BaseMailer.explicit_multipart + assert_not_nil(mail.content_type_parameters[:boundary]) + end + test "explicit multipart does not sort order" do order = ["text/html", "text/plain"] with_default BaseMailer, :parts_order => order do @@ -399,7 +418,7 @@ class BaseTest < ActiveSupport::TestCase assert_equal("TEXT Explicit Multipart Templates", email.parts[1].body.encoded) end - test "explicit multipart with any" do + test "explicit multipart with format.any" do email = BaseMailer.explicit_multipart_with_any assert_equal(2, email.parts.size) assert_equal("multipart/alternative", email.mime_type) @@ -409,8 +428,8 @@ class BaseTest < ActiveSupport::TestCase assert_equal("Format with any!", email.parts[1].body.encoded) end - test "explicit multipart with options" do - email = BaseMailer.custom_block(true) + test "explicit multipart with format(Hash)" do + email = BaseMailer.explicit_multipart_with_options(true) email.ready_to_send! assert_equal(2, email.parts.size) assert_equal("multipart/alternative", email.mime_type) @@ -420,28 +439,23 @@ class BaseTest < ActiveSupport::TestCase assert_equal("7bit", email.parts[1].content_transfer_encoding) end - test "explicit multipart should be multipart" do - mail = BaseMailer.explicit_multipart - assert_not_nil(mail.content_type_parameters[:boundary]) - end - - test "should set a content type if only has an html part" do - mail = BaseMailer.html_only - assert_equal('text/html', mail.mime_type) - end - - test "should set a content type if only has an plain text part" do - mail = BaseMailer.plain_text_only - assert_equal('text/plain', mail.mime_type) - end - - test "explicit multipart with one part is rendered as body" do - email = BaseMailer.custom_block + test "explicit multipart with one part is rendered as body and options are merged" do + email = BaseMailer.explicit_multipart_with_options assert_equal(0, email.parts.size) assert_equal("text/plain", email.mime_type) assert_equal("base64", email.content_transfer_encoding) end + test "explicit multipart with one template has the expected format" do + email = BaseMailer.explicit_multipart_with_one_template + assert_equal(2, email.parts.size) + assert_equal("multipart/alternative", email.mime_type) + assert_equal("text/html", email.parts[0].mime_type) + assert_equal("[:html]", email.parts[0].body.encoded) + assert_equal("text/plain", email.parts[1].mime_type) + assert_equal("[:text]", email.parts[1].body.encoded) + end + # Class level API with method missing test "should respond to action methods" do assert BaseMailer.respond_to?(:welcome) diff --git a/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb b/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb new file mode 100644 index 0000000000..8a69657b08 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb @@ -0,0 +1 @@ +<%= self.formats.inspect %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/test_mailer/signed_up_with_url.erb b/actionmailer/test/fixtures/url_test_mailer/signed_up_with_url.erb index 4c5806d30d..4c5806d30d 100644 --- a/actionmailer/test/fixtures/test_mailer/signed_up_with_url.erb +++ b/actionmailer/test/fixtures/url_test_mailer/signed_up_with_url.erb diff --git a/actionmailer/test/old_base/mail_layout_test.rb b/actionmailer/test/old_base/mail_layout_test.rb index 5679aa5a64..2c2daa0f28 100644 --- a/actionmailer/test/old_base/mail_layout_test.rb +++ b/actionmailer/test/old_base/mail_layout_test.rb @@ -69,47 +69,25 @@ class LayoutMailerTest < Test::Unit::TestCase def test_should_pickup_multipart_layout mail = AutoLayoutMailer.multipart - # CHANGED: content_type returns an object - # assert_equal "multipart/alternative", mail.content_type assert_equal "multipart/alternative", mail.mime_type assert_equal 2, mail.parts.size - # CHANGED: content_type returns an object - # assert_equal 'text/plain', mail.parts.first.content_type assert_equal 'text/plain', mail.parts.first.mime_type - - # CHANGED: body returns an object - # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s - # CHANGED: content_type returns an object - # assert_equal 'text/html', mail.parts.last.content_type assert_equal 'text/html', mail.parts.last.mime_type - - # CHANGED: body returns an object - # assert_equal "Hello from layout text/html multipart", mail.parts.last.body assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s end def test_should_pickup_multipartmixed_layout mail = AutoLayoutMailer.multipart("multipart/mixed") - # CHANGED: content_type returns an object - # assert_equal "multipart/mixed", mail.content_type assert_equal "multipart/mixed", mail.mime_type assert_equal 2, mail.parts.size - # CHANGED: content_type returns an object - # assert_equal 'text/plain', mail.parts.first.content_type assert_equal 'text/plain', mail.parts.first.mime_type - # CHANGED: body returns an object - # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s - # CHANGED: content_type returns an object - # assert_equal 'text/html', mail.parts.last.content_type assert_equal 'text/html', mail.parts.last.mime_type - # CHANGED: body returns an object - # assert_equal "Hello from layout text/html multipart", mail.parts.last.body assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s end diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index 6d0b2c53a3..e49307bfda 100644 --- a/actionmailer/test/old_base/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -340,6 +340,8 @@ class ActionMailerTest < Test::Unit::TestCase @original_logger = TestMailer.logger @recipient = 'test@localhost' + + TestMailer.delivery_method = :test end def teardown @@ -1191,6 +1193,6 @@ class RespondToTest < Test::Unit::TestCase RespondToMailer.not_a_method end - assert_match(/undefined method.*not_a_method/, error.message) + assert_match(/method.*not_a_method/, error.message) end -end
\ No newline at end of file +end diff --git a/actionmailer/test/old_base/url_test.rb b/actionmailer/test/old_base/url_test.rb index 60740d6b0b..17b383cc2a 100644 --- a/actionmailer/test/old_base/url_test.rb +++ b/actionmailer/test/old_base/url_test.rb @@ -10,7 +10,7 @@ class ActionMailer::Base include AppRoutes.url_helpers end -class TestMailer < ActionMailer::Base +class UrlTestMailer < ActionMailer::Base default_url_options[:host] = 'www.basecamphq.com' configure do |c| @@ -26,14 +26,6 @@ class TestMailer < ActionMailer::Base @recipient = recipient @welcome_url = url_for :host => "example.com", :controller => "welcome", :action => "greeting" end - - class <<self - attr_accessor :received_body - end - - def receive(mail) - self.class.received_body = mail.body - end end class ActionMailerUrlTest < Test::Unit::TestCase @@ -65,7 +57,7 @@ class ActionMailerUrlTest < Test::Unit::TestCase end def test_signed_up_with_url - TestMailer.delivery_method = :test + UrlTestMailer.delivery_method = :test AppRoutes.draw do |map| map.connect ':controller/:action/:id' @@ -80,14 +72,14 @@ class ActionMailerUrlTest < Test::Unit::TestCase expected.date = Time.local(2004, 12, 12) created = nil - assert_nothing_raised { created = TestMailer.signed_up_with_url(@recipient) } + assert_nothing_raised { created = UrlTestMailer.signed_up_with_url(@recipient) } assert_not_nil created expected.message_id = '<123@456>' created.message_id = '<123@456>' assert_equal expected.encoded, created.encoded - assert_nothing_raised { TestMailer.signed_up_with_url(@recipient).deliver } + assert_nothing_raised { UrlTestMailer.signed_up_with_url(@recipient).deliver } assert_not_nil ActionMailer::Base.deliveries.first delivered = ActionMailer::Base.deliveries.first diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index f875213afb..53cf6b3931 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -6,16 +6,10 @@ module AbstractController include Rendering - def self.next_serial - @helper_serial ||= 0 - @helper_serial += 1 - end - included do - class_attribute :_helpers, :_helper_serial + class_attribute :_helpers delegate :_helpers, :to => :'self.class' self._helpers = Module.new - self._helper_serial = ::AbstractController::Helpers.next_serial end module ClassMethods @@ -95,8 +89,6 @@ module AbstractController # helper(:three, BlindHelper) { def mice() 'mice' end } # def helper(*args, &block) - self._helper_serial = AbstractController::Helpers.next_serial + 1 - modules_for_helpers(args).each do |mod| add_template_helper(mod) end diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 95a6101109..319472c937 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/module/remove_method" + module AbstractController # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in # repeated setups. The inclusion pattern has pages that look like this: @@ -182,7 +184,9 @@ module AbstractController # # ==== Returns # Boolean:: True if the action has a layout, false otherwise. - def _action_has_layout? + def action_has_layout? + return unless super + conditions = _layout_conditions if only = conditions[:only] @@ -237,6 +241,8 @@ module AbstractController # name, return that string. Otherwise, use the superclass' # layout (which might also be implied) def _write_layout_method + remove_possible_method(:_layout) + case defined?(@_layout) ? @_layout : nil when String self.class_eval %{def _layout; #{@_layout.inspect} end} @@ -284,15 +290,20 @@ module AbstractController layout = options.key?(:layout) ? options.delete(:layout) : :default value = _layout_for_option(layout) options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value - - # TODO Layout for partials should be handled here, because inside the - # partial renderer it looks for the layout as a partial. - if options.key?(:partial) && options[:layout] - options[:layout] = view_context.find_layout(options[:layout]) - end end end + attr_writer :action_has_layout + + def initialize(*) + @action_has_layout = true + super + end + + def action_has_layout? + @action_has_layout + end + private # This will be overwritten by _write_layout_method @@ -332,13 +343,13 @@ module AbstractController # Template:: The template object for the default layout (or nil) def _default_layout(require_layout = false) begin - layout_name = _layout if _action_has_layout? + layout_name = _layout if action_has_layout? rescue NameError => e raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end - if require_layout && _action_has_layout? && !layout_name + if require_layout && action_has_layout? && !layout_name raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" end @@ -349,9 +360,5 @@ module AbstractController def _include_layout?(options) (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout) end - - def _action_has_layout? - true - end end end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 16664098e5..b251bd6405 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -32,7 +32,6 @@ module AbstractController module Rendering extend ActiveSupport::Concern - include AbstractController::Assigns include AbstractController::ViewPaths # Overwrite process to setup I18n proxy. @@ -43,17 +42,48 @@ module AbstractController I18n.config = old_config end + module ClassMethods + def view_context_class + @view_context_class ||= begin + controller = self + Class.new(ActionView::Base) do + if controller.respond_to?(:_helpers) + include controller._helpers + + if controller.respond_to?(:_router) + include controller._router.url_helpers + end + + # TODO: Fix RJS to not require this + self.helpers = controller._helpers + end + end + end + end + end + + attr_writer :view_context_class + + def view_context_class + @view_context_class || self.class.view_context_class + end + + def initialize(*) + @view_context_class = nil + super + end + # An instance of a view class. The default view class is ActionView::Base # # The view class must have the following methods: - # View.for_controller[controller] + # View.new[lookup_context, assigns, controller] # Create a new ActionView instance for a controller - # View#render_template[options] + # View#render[options] # Returns String with the rendered template # # Override this method in a module to change the default behavior. def view_context - @_view_context ||= ActionView::Base.for_controller(self) + view_context_class.new(lookup_context, view_assigns, self) end # Normalize arguments, options and then delegates render_to_body and @@ -76,13 +106,12 @@ module AbstractController # :api: plugin def render_to_string(options={}) _normalize_options(options) - AbstractController::Rendering.body_to_s(render_to_body(options)) + render_to_body(options) end # Find and renders a template based on the options given. # :api: private def _render_template(options) #:nodoc: - _evaluate_assigns(view_context) view_context.render(options) end @@ -91,20 +120,19 @@ module AbstractController controller_path end - # Return a string representation of a Rack-compatible response body. - def self.body_to_s(body) - if body.respond_to?(:to_str) - body - else - strings = [] - body.each { |part| strings << part.to_s } - body.close if body.respond_to?(:close) - strings.join - end - end - private + # This method should return a hash with assigns. + # You can overwrite this configuration per controller. + # :api: public + def view_assigns + hash = {} + variables = instance_variable_names + variables -= protected_instance_variables if respond_to?(:protected_instance_variables) + variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) } + hash + end + # Normalize options by converting render "foo" to render :action => "foo" and # render "foo/bar" to render :file => "foo/bar". def _normalize_args(action=nil, options={}) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ad2b68af21..5797282b41 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -19,6 +19,7 @@ module ActionController include SessionManagement include ActionController::Caching include ActionController::MimeResponds + include ActionController::PolymorphicRoutes # Rails 2.x compatibility include ActionController::Compatibility diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 35111a4b92..43ddf6435a 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -80,6 +80,7 @@ module ActionController #:nodoc: def caches_action(*actions) return unless cache_configured? options = actions.extract_options! + options[:layout] = true unless options.key?(:layout) filter_options = options.extract!(:if, :unless).merge(:only => actions) cache_options = options.extract!(:layout, :cache_path).merge(:store_options => options) @@ -87,14 +88,12 @@ module ActionController #:nodoc: end end - def _render_cache_fragment(cache, extension, layout) - render :text => cache, :layout => layout, :content_type => Mime[extension || :html] - end - - def _save_fragment(name, layout, options) + def _save_fragment(name, options) return unless caching_allowed? - content = layout ? view_context.content_for(:layout) : response_body + content = response_body + content = content.join if content.is_a?(Array) + write_fragment(name, content, options) end @@ -112,7 +111,7 @@ module ActionController #:nodoc: class ActionCacheFilter #:nodoc: def initialize(options, &block) - @cache_path, @store_options, @layout = + @cache_path, @store_options, @cache_layout = options.values_at(:cache_path, :store_options, :layout) end @@ -125,12 +124,19 @@ module ActionController #:nodoc: cache_path = ActionCachePath.new(controller, path_options || {}) - if cache = controller.read_fragment(cache_path.path, @store_options) - controller._render_cache_fragment(cache, cache_path.extension, @layout == false) - else + body = controller.read_fragment(cache_path.path, @store_options) + + unless body + controller.action_has_layout = false unless @cache_layout yield - controller._save_fragment(cache_path.path, @layout == false, @store_options) + controller.action_has_layout = true + body = controller._save_fragment(cache_path.path, @store_options) end + + body = controller.render_to_string(:text => cache, :layout => true) unless @cache_layout + + controller.response_body = body + controller.content_type = Mime[cache_path.extension || :html] end end diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index 89787727bd..473a2fe214 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -34,20 +34,6 @@ module ActionController #:nodoc: ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views) end - def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc: - if perform_caching - if fragment_exist?(name, options) - buffer.safe_concat(read_fragment(name, options)) - else - pos = buffer.length - block.call - write_fragment(name, buffer[pos..-1], options) - end - else - block.call - end - end - # Writes <tt>content</tt> to the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats) def write_fragment(key, content, options = nil) return content unless cache_configured? diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 1d05b3fbd6..bbde570ca9 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -63,7 +63,7 @@ module ActionController def ip_spoofing_check ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check is deprecated. " << "Configuring ip_spoofing_check on the application configures a middleware.", caller - Rails.application.config.action_disaptch.ip_spoofing_check + Rails.application.config.action_dispatch.ip_spoofing_check end def trusted_proxies=(value) diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index eebd2c943a..30aa34d956 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -34,11 +34,12 @@ module ActionController # and response object available. You might wish to control the # environment and response manually for performance reasons. - attr_internal :status, :headers, :content_type, :response, :request + attr_internal :headers, :response, :request delegate :session, :to => "@_request" def initialize(*) - @_headers = {} + @_headers = {"Content-Type" => "text/html"} + @_status = 200 super end @@ -62,10 +63,19 @@ module ActionController headers["Location"] = url end + def status + @_status + end + def status=(status) @_status = Rack::Utils.status_code(status) end + def response_body=(val) + body = val.respond_to?(:each) ? val : [val] + super body + end + # :api: private def dispatch(name, request) @_request = request diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index ab8d87b2c4..e6cea483bb 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -40,15 +40,6 @@ module ActionController def initialize_template_class(*) end def assign_shortcuts(*) end - def template - @template ||= view_context - end - - def process_action(*) - template - super - end - def _normalize_options(options) if options[:action] && options[:action].to_s.include?(?/) ActiveSupport::Deprecation.warn "Giving a path to render :action is deprecated. " << diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 2ac199265d..4f384d1ec5 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -262,7 +262,7 @@ module ActionController #:nodoc: if format = request.negotiate_mime(collector.order) self.content_type ||= format.to_s - self.formats = [format.to_sym] + lookup_context.freeze_formats([format.to_sym]) collector.response_for(format) else head :not_acceptable diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb index 37106733cb..060117756e 100644 --- a/actionpack/lib/action_controller/metal/rack_delegation.rb +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -5,10 +5,8 @@ module ActionController module RackDelegation extend ActiveSupport::Concern - included do - delegate :headers, :status=, :location=, :content_type=, - :status, :location, :content_type, :to => "@_response" - end + delegate :headers, :status=, :location=, :content_type=, + :status, :location, :content_type, :to => "@_response" def dispatch(action, request) @_response = ActionDispatch::Response.new diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 25e4e18493..b5f1d23ef0 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -76,7 +76,7 @@ module ActionController # The scheme name consist of a letter followed by any combination of # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") # characters; and is terminated by a colon (":"). - when %r{^\w[\w\d+.-]*:.*} + when %r{^\w[\w+.-]*:.*} options when String request.protocol + request.host_with_port + options diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 08325b468c..d906e1fb5b 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -87,7 +87,7 @@ module ActionController end add :update do |proc, options| - _evaluate_assigns(view_context) + view_context = self.view_context generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc) self.content_type = Mime::JS self.response_body = generator.to_s diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 6178a59029..0b2cee6868 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -1,3 +1,5 @@ +require 'active_support/json' + module ActionController #:nodoc: # Responder is responsible for exposing a resource to different mime requests, # usually depending on the HTTP verb. The responder is triggered when diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 6a3afbb157..0ec89928af 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -1,16 +1,17 @@ require "rails" require "action_controller" +require "action_dispatch/railtie" require "action_view/railtie" require "active_support/core_ext/class/subclasses" require "active_support/deprecation/proxy_wrappers" require "active_support/deprecation" +require "action_controller/railties/log_subscriber" +require "action_controller/railties/url_helpers" + module ActionController class Railtie < Rails::Railtie - railtie_name :action_controller - - require "action_controller/railties/log_subscriber" - require "action_controller/railties/url_helpers" + config.action_controller = ActiveSupport::OrderedOptions.new ad = config.action_dispatch config.action_controller.singleton_class.send(:define_method, :session) do @@ -37,7 +38,7 @@ module ActionController ad.session_store = val end - log_subscriber ActionController::Railties::LogSubscriber.new + log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new initializer "action_controller.logger" do ActionController.base_hook { self.logger ||= Rails.logger } @@ -52,7 +53,9 @@ module ActionController ac.stylesheets_dir = paths.public.stylesheets.to_a.first ac.secret = app.config.cookie_secret - ActionController.base_hook { self.config.replace(ac) } + ActionController.base_hook do + self.config.merge!(ac) + end end initializer "action_controller.initialize_framework_caches" do @@ -67,7 +70,7 @@ module ActionController initializer "action_controller.url_helpers" do |app| ActionController.base_hook do - extend ::ActionController::Railtie::UrlHelpers.with(app.routes) + extend ::ActionController::Railties::UrlHelpers.with(app.routes) end message = "ActionController::Routing::Routes is deprecated. " \ diff --git a/actionpack/lib/action_controller/railties/url_helpers.rb b/actionpack/lib/action_controller/railties/url_helpers.rb index ad2a8d4ef3..5f95e1c621 100644 --- a/actionpack/lib/action_controller/railties/url_helpers.rb +++ b/actionpack/lib/action_controller/railties/url_helpers.rb @@ -1,5 +1,5 @@ module ActionController - class Railtie + module Railties module UrlHelpers def self.with(router) Module.new do diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index cdb5db32aa..120f34460e 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,7 +1,107 @@ require 'rack/session/abstract/id' -require 'action_view/test_case' module ActionController + module TemplateAssertions + extend ActiveSupport::Concern + + included do + setup :setup_subscriptions + teardown :teardown_subscriptions + end + + def setup_subscriptions + @partials = Hash.new(0) + @templates = Hash.new(0) + @layouts = Hash.new(0) + + ActiveSupport::Notifications.subscribe("action_view.render_template") do |name, start, finish, id, payload| + path = payload[:layout] + @layouts[path] += 1 + end + + ActiveSupport::Notifications.subscribe("action_view.render_template!") do |name, start, finish, id, payload| + path = payload[:virtual_path] + next unless path + partial = path =~ /^.*\/_[^\/]*$/ + if partial + @partials[path] += 1 + @partials[path.split("/").last] += 1 + @templates[path] += 1 + else + @templates[path] += 1 + end + end + end + + def teardown_subscriptions + ActiveSupport::Notifications.unsubscribe("action_view.render_template!") + end + + # Asserts that the request was rendered with the appropriate template file or partials + # + # ==== Examples + # + # # assert that the "new" view template was rendered + # assert_template "new" + # + # # assert that the "_customer" partial was rendered twice + # assert_template :partial => '_customer', :count => 2 + # + # # assert that no partials were rendered + # assert_template :partial => false + # + def assert_template(options = {}, message = nil) + validate_request! + + case options + when NilClass, String + rendered = @templates + msg = build_message(message, + "expecting <?> but rendering with <?>", + options, rendered.keys.join(', ')) + assert_block(msg) do + if options.nil? + @templates.blank? + else + rendered.any? { |t,num| t.match(options) } + end + end + when Hash + if expected_partial = options[:partial] + if expected_count = options[:count] + actual_count = @partials[expected_partial] + # actual_count = found.nil? ? 0 : found[1] + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) + elsif options.key?(:layout) + msg = build_message(message, + "expecting layout <?> but action rendered <?>", + expected_layout, @layouts.keys) + + case layout = options[:layout] + when String + assert(@layouts.include?(expected_layout), msg) + when Regexp + assert(@layouts.any? {|l| l =~ layout }, msg) + when nil + assert(@layouts.empty?, msg) + end + else + msg = build_message(message, + "expecting partial <?> but action rendered <?>", + options[:partial], @partials.keys) + assert(@partials.include?(expected_partial), msg) + end + else + assert @partials.empty?, + "Expected no partials to be rendered" + end + end + end + end + class TestRequest < ActionDispatch::TestRequest #:nodoc: def initialize(env = {}) super @@ -181,6 +281,7 @@ module ActionController # assert_redirected_to page_url(:title => 'foo') class TestCase < ActiveSupport::TestCase include ActionDispatch::TestProcess + include ActionController::TemplateAssertions # Executes a request simulating GET HTTP method and set/volley the response def get(action, parameters = nil, session = nil, flash = nil) diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 451b79b190..e42b4d09b0 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -25,7 +25,6 @@ module ActionDispatch module FilterParameters extend ActiveSupport::Concern - mattr_reader :compiled_parameter_filter_for @@compiled_parameter_filter_for = {} # Return a hash of parameters with all sensitive data replaced. diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 13c0f2bad0..3f1a77295d 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -52,12 +52,6 @@ module Mime cattr_reader :browser_generated_types attr_reader :symbol - @@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml] - def self.unverifiable_types - ActiveSupport::Deprecation.warn("unverifiable_types is deprecated and has no effect", caller) - @@unverifiable_types - end - # A simple helper class used in parsing the accept header class AcceptItem #:nodoc: attr_accessor :order, :name, :q @@ -100,7 +94,7 @@ module Mime end def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false) - Mime.instance_eval { const_set symbol.to_s.upcase, Type.new(string, symbol, mime_type_synonyms) } + Mime.const_set(symbol.to_s.upcase, Type.new(string, symbol, mime_type_synonyms)) SET << Mime.const_get(symbol.to_s.upcase) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 0dc03a1a7e..ab7130ab08 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -84,6 +84,7 @@ module ActionDispatch options[:path] ||= "/" @set_cookies[key] = options + @delete_cookies.delete(key) value end diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index e486bd4079..563df0f256 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -3,9 +3,8 @@ require "rails" module ActionDispatch class Railtie < Rails::Railtie - railtie_name :action_dispatch - - config.action_dispatch.x_sendfile_header = "X-Sendfile" + config.action_dispatch = ActiveSupport::OrderedOptions.new + config.action_dispatch.x_sendfile_header = "" config.action_dispatch.ip_spoofing_check = true # Prepare dispatcher callbacks and run 'prepare' callbacks diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 5bc3205c51..c6e942555f 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/object/to_param' require 'active_support/core_ext/regexp' +require 'action_controller/polymorphic_routes' module ActionDispatch # == Routing diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index f9b27a5a03..5a3868e1d4 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -32,6 +32,8 @@ module ActionDispatch end class Mapping + IGNORE_OPTIONS = [:to, :as, :controller, :action, :via, :on, :constraints, :defaults, :only, :except, :anchor] + def initialize(set, scope, args) @set, @scope = set, scope @path, @options = extract_path_and_options(args) @@ -45,18 +47,21 @@ module ActionDispatch def extract_path_and_options(args) options = args.extract_options! - case - when using_to_shorthand?(args, options) + if using_to_shorthand?(args, options) path, to = options.find { |name, value| name.is_a?(String) } options.merge!(:to => to).delete(path) if path - when using_match_shorthand?(args, options) - path = args.first - options = { :to => path.gsub("/", "#"), :as => path.gsub("/", "_") } else path = args.first end - [ normalize_path(path), options ] + path = normalize_path(path) + + if using_match_shorthand?(path, options) + options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1') + options[:as] ||= path[1..-1].gsub("/", "_") + end + + [ path, options ] end # match "account" => "account#index" @@ -65,14 +70,13 @@ module ActionDispatch end # match "account/overview" - def using_match_shorthand?(args, options) - args.present? && options.except(:via, :anchor).empty? && !args.first.include?(':') + def using_match_shorthand?(path, options) + path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$} end def normalize_path(path) - path = "#{@scope[:path]}/#{path}" - raise ArgumentError, "path is required" if path.empty? - Mapper.normalize_path(path) + raise ArgumentError, "path is required" if @scope[:path].blank? && path.blank? + Mapper.normalize_path("#{@scope[:path]}/#{path}") end def app @@ -94,7 +98,15 @@ module ActionDispatch end def defaults - @defaults ||= if to.respond_to?(:call) + @defaults ||= (@options[:defaults] || {}).tap do |defaults| + defaults.merge!(default_controller_and_action) + defaults.reverse_merge!(@scope[:defaults]) if @scope[:defaults] + @options.each { |k, v| defaults[k] = v unless v.is_a?(Regexp) || IGNORE_OPTIONS.include?(k.to_sym) } + end + end + + def default_controller_and_action + if to.respond_to?(:call) { } else defaults = case to @@ -144,8 +156,8 @@ module ActionDispatch def segment_keys @segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new( - Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS) - ).names + Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS) + ).names end def to @@ -297,11 +309,14 @@ module ActionDispatch scope(:constraints => constraints) { yield } end + def defaults(defaults = {}) + scope(:defaults => defaults) { yield } + end + def match(*args) options = args.extract_options! options = (@scope[:options] || {}).merge(options) - options[:anchor] = true unless options.key?(:anchor) if @scope[:name_prefix] && !options[:as].blank? options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}" @@ -342,6 +357,10 @@ module ActionDispatch merge_options_scope(parent, child) end + def merge_defaults_scope(parent, child) + merge_options_scope(parent, child) + end + def merge_blocks_scope(parent, child) (parent || []) + [child] end @@ -460,7 +479,7 @@ module ActionDispatch scope(:path => resource.name.to_s, :controller => resource.controller) do with_scope_level(:resource, resource) do - scope(:name_prefix => resource.name.to_s) do + scope(:name_prefix => resource.name.to_s, :as => "") do yield if block_given? end @@ -563,6 +582,8 @@ module ActionDispatch def match(*args) options = args.extract_options! + options[:anchor] = true unless options.key?(:anchor) + if args.length > 1 args.each { |path| match(path, options) } return self diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 722be432c7..bb689beed9 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -65,7 +65,7 @@ module ActionDispatch # named routes. class NamedRouteCollection #:nodoc: include Enumerable - attr_reader :routes, :helpers + attr_reader :routes, :helpers, :module def initialize clear! @@ -179,6 +179,7 @@ module ActionDispatch url_for(options) end + protected :#{selector} END_EVAL helpers << selector end @@ -219,14 +220,16 @@ module ActionDispatch end def finalize! + return if @finalized + @finalized = true @set.add_route(NotFound) - install_helpers @set.freeze end def clear! # Clear the controller cache so we may discover new ones @controller_constraints = nil + @finalized = false routes.clear named_routes.clear @set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY) @@ -239,21 +242,30 @@ module ActionDispatch def url_helpers @url_helpers ||= begin - router = self + routes = self - Module.new do + helpers = Module.new do extend ActiveSupport::Concern include UrlFor + @routes = routes + class << self + delegate :url_for, :to => '@routes' + end + extend routes.named_routes.module + # ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that # we can include? # Yes plz - JP included do - router.install_helpers(self) + routes.install_helpers(self) + singleton_class.send(:define_method, :_router) { routes } end - define_method(:_router) { router } + define_method(:_router) { routes } end + + helpers end end @@ -406,6 +418,7 @@ module ActionDispatch RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash] def url_for(options) + finalize! options = default_url_options.merge(options || {}) handle_positional_args(options) @@ -437,6 +450,7 @@ module ActionDispatch end def call(env) + finalize! @set.call(env) end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index ec78f53fa6..b8c02f402c 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -72,7 +72,7 @@ module ActionDispatch # you can do that by including ActionController::UrlFor in your class: # # class User < ActiveRecord::Base - # include ActionController::UrlFor + # include Rails.application.routes.url_helpers # # def base_uri # user_path(self) diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 937c9f48d2..ec5e9efe44 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -73,58 +73,6 @@ module ActionDispatch end end - # Asserts that the request was rendered with the appropriate template file or partials - # - # ==== Examples - # - # # assert that the "new" view template was rendered - # assert_template "new" - # - # # assert that the "_customer" partial was rendered twice - # assert_template :partial => '_customer', :count => 2 - # - # # assert that no partials were rendered - # assert_template :partial => false - # - def assert_template(options = {}, message = nil) - validate_request! - - case options - when NilClass, String - rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting <?> but rendering with <?>", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - @controller.template.rendered[:template].blank? - else - rendered.any? { |t| t.match(options) } - end - end - when Hash - if expected_partial = options[:partial] - partials = @controller.template.rendered[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found.second - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial <?> but action rendered <?>", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end - else - assert @controller.template.rendered[:partials].empty?, - "Expected no partials to be rendered" - end - end - end - private # Proxy to to_param if the object will respond to it. def parameterize(value) diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 1d7e8090e4..1bb81ede3b 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -145,11 +145,25 @@ module ActionDispatch old_routes, @router = @router, ActionDispatch::Routing::RouteSet.new old_controller, @controller = @controller, @controller.clone if @controller _router = @router - @controller.singleton_class.send(:send, :include, @router.url_helpers) if @controller + + # Unfortunately, there is currently an abstraction leak between AC::Base + # and AV::Base which requires having the URL helpers in both AC and AV. + # To do this safely at runtime for tests, we need to bump up the helper serial + # to that the old AV subclass isn't cached. + # + # TODO: Make this unnecessary + if @controller + @controller.singleton_class.send(:include, _router.url_helpers) + @controller.view_context_class = Class.new(@controller.view_context_class) do + include _router.url_helpers + end + end yield @router ensure @router = old_routes - @controller = old_controller if @controller + if @controller + @controller = old_controller + end end # ROUTES TODO: These assertions should really work in an integration context diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 0aff4250c1..621d63c5e2 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -2,6 +2,7 @@ require 'stringio' require 'uri' require 'active_support/core_ext/object/singleton_class' require 'rack/test' +require 'test/unit/assertions' module ActionDispatch module Integration #:nodoc: @@ -177,14 +178,8 @@ module ActionDispatch reset! end - def url_options - opts = super.reverse_merge( - :host => host, - :protocol => https? ? "https" : "http" - ) - - opts.merge!(:port => 443) if !opts.key?(:port) && https? - opts + def default_url_options + { :host => host, :protocol => https? ? "https" : "http" } end # Resets the instance. This can be used to reset the state information @@ -293,6 +288,8 @@ module ActionDispatch end module Runner + include ActionDispatch::Assertions + def app @app end @@ -300,7 +297,7 @@ module ActionDispatch # Reset the current session. This is useful for testing multiple sessions # in a single test case. def reset! - @integration_session = open_session + @integration_session = Integration::Session.new(app) end %w(get post put head delete cookies assigns @@ -326,30 +323,9 @@ module ActionDispatch # can use this method to open multiple sessions that ought to be tested # simultaneously. def open_session(app = nil) - session = Integration::Session.new(app || self.app) - - # delegate the fixture accessors back to the test instance - extras = Module.new { attr_accessor :delegate, :test_result } - if self.class.respond_to?(:fixture_table_names) - self.class.fixture_table_names.each do |table_name| - name = table_name.tr(".", "_") - next unless respond_to?(name) - extras.__send__(:define_method, name) { |*args| - delegate.send(name, *args) - } - end + dup.tap do |session| + yield session if block_given? end - - # delegate add_assertion to the test case - extras.__send__(:define_method, :add_assertion) { - test_result.add_assertion - } - session.extend(extras) - session.delegate = self - session.test_result = @_result - - yield session if block_given? - session end # Copy the instance variables from the current session instance into the @@ -460,6 +436,7 @@ module ActionDispatch # end class IntegrationTest < ActiveSupport::TestCase include Integration::Runner + include ActionController::TemplateAssertions @@app = nil diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index afe6386105..5555217ee2 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -44,13 +44,15 @@ module ActionView autoload :Base autoload :LookupContext - autoload :MissingTemplate, 'action_view/base' autoload :Resolver, 'action_view/template/resolver' autoload :PathResolver, 'action_view/template/resolver' autoload :FileSystemResolver, 'action_view/template/resolver' autoload :PathSet, 'action_view/paths' + autoload :MissingTemplate, 'action_view/template/error' + autoload :ActionViewError, 'action_view/template/error' autoload :TemplateError, 'action_view/template/error' + autoload :TemplateHandler, 'action_view/template' autoload :TemplateHandlers, 'action_view/template' end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index feaf45c333..919b1e3470 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,27 +1,10 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/array/wrap' module ActionView #:nodoc: - class ActionViewError < StandardError #:nodoc: - end - - class MissingTemplate < ActionViewError #:nodoc: - attr_reader :path - - def initialize(paths, path, details, partial) - @path = path - display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ") - template_type = if partial - "partial" - elsif path =~ /layouts/i - 'layout' - else - 'template' - end - - super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}") - end + class NonConcattingString < ActiveSupport::SafeBuffer end # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb @@ -176,14 +159,13 @@ module ActionView #:nodoc: include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context extend ActiveSupport::Memoizable - ActionView.run_base_hooks(self) - # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). cattr_accessor :debug_rjs @@debug_rjs = false class_attribute :helpers + remove_method :helpers attr_reader :helpers class << self @@ -191,8 +173,10 @@ module ActionView #:nodoc: delegate :logger, :to => 'ActionController::Base', :allow_nil => true end + ActionView.run_base_hooks(self) + attr_accessor :base_path, :assigns, :template_extension, :lookup_context - attr_internal :captures, :request, :layout, :controller, :template, :config + attr_internal :captures, :request, :controller, :template, :config delegate :find_template, :template_exists?, :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context @@ -202,42 +186,17 @@ module ActionView #:nodoc: delegate :logger, :to => :controller, :allow_nil => true + # TODO: HACK FOR RJS + def view_context + self + end + def self.xss_safe? #:nodoc: true end def self.process_view_paths(value) - ActionView::PathSet.new(Array(value)) - end - - def self.for_controller(controller) - @views ||= {} - - # TODO: Decouple this so helpers are a separate concern in AV just like - # they are in AC. - if controller.class.respond_to?(:_helper_serial) - klass = @views[controller.class._helper_serial] ||= Class.new(self) do - # Try to make stack traces clearer - class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 - def self.name - "ActionView for #{controller.class}" - end - - def inspect - "#<#{self.class.name}>" - end - ruby_eval - - if controller.respond_to?(:_helpers) - include controller._helpers - self.helpers = controller._helpers - end - end - else - klass = self - end - - klass.new(controller.lookup_context, {}, controller) + ActionView::PathSet.new(Array.wrap(value)) end def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc: @@ -246,7 +205,7 @@ module ActionView #:nodoc: @helpers = self.class.helpers || Module.new @_controller = controller - @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller + @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller && controller.respond_to?(:config) @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new } @_virtual_path = nil diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb index df078a7151..61d2e702a7 100644 --- a/actionpack/lib/action_view/context.rb +++ b/actionpack/lib/action_view/context.rb @@ -10,8 +10,6 @@ module ActionView # In order to work with ActionController, a Context # must implement: # - # Context.for_controller[controller] Create a new ActionView instance for a - # controller # Context#render_partial[options] # - responsible for setting options[:_template] # - Returns String with the rendered partial diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index e359b0bdac..a50c180f63 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -2,30 +2,32 @@ require 'active_support/benchmarkable' module ActionView #:nodoc: module Helpers #:nodoc: - autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper' - autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper' - autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper' - autoload :CacheHelper, 'action_view/helpers/cache_helper' - autoload :CaptureHelper, 'action_view/helpers/capture_helper' - autoload :CsrfHelper, 'action_view/helpers/csrf_helper' - autoload :DateHelper, 'action_view/helpers/date_helper' - autoload :DebugHelper, 'action_view/helpers/debug_helper' - autoload :DeprecatedBlockHelpers, 'action_view/helpers/deprecated_block_helpers' - autoload :FormHelper, 'action_view/helpers/form_helper' - autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper' - autoload :FormTagHelper, 'action_view/helpers/form_tag_helper' - autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper' - autoload :NumberHelper, 'action_view/helpers/number_helper' - autoload :PrototypeHelper, 'action_view/helpers/prototype_helper' - autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper' - autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper' - autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper' - autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper' - autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper' - autoload :TagHelper, 'action_view/helpers/tag_helper' - autoload :TextHelper, 'action_view/helpers/text_helper' - autoload :TranslationHelper, 'action_view/helpers/translation_helper' - autoload :UrlHelper, 'action_view/helpers/url_helper' + extend ActiveSupport::Autoload + + autoload :ActiveModelHelper + autoload :AssetTagHelper + autoload :AtomFeedHelper + autoload :CacheHelper + autoload :CaptureHelper + autoload :CsrfHelper + autoload :DateHelper + autoload :DebugHelper + autoload :DeprecatedBlockHelpers + autoload :FormHelper + autoload :FormOptionsHelper + autoload :FormTagHelper + autoload :JavaScriptHelper, "action_view/helpers/javascript_helper" + autoload :NumberHelper + autoload :PrototypeHelper + autoload :RawOutputHelper + autoload :RecordIdentificationHelper + autoload :RecordTagHelper + autoload :SanitizeHelper + autoload :ScriptaculousHelper + autoload :TagHelper + autoload :TextHelper + autoload :TranslationHelper + autoload :UrlHelper def self.included(base) base.extend(ClassMethods) diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index e3db2923f7..80b3d3a664 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -3,6 +3,7 @@ require 'action_view/helpers/form_helper' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/enumerable' require 'active_support/core_ext/kernel/reporting' +require 'active_support/core_ext/object/blank' module ActionView ActionView.base_hook do @@ -127,7 +128,7 @@ module ActionView object = convert_to_model(object) if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) && - (errors = obj.errors[method]) + (errors = obj.errors[method]).presence content_tag("div", "#{options[:prepend_text]}#{ERB::Util.h(errors.first)}#{options[:append_text]}".html_safe, :class => options[:css_class] @@ -295,6 +296,10 @@ module ActionView end end + def error_message + object.errors[@method_name] + end + def column_type object.send(:column_for_attribute, @method_name).type end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index b594002629..02ad41719b 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -3,6 +3,7 @@ require 'cgi' require 'action_view/helpers/url_helper' require 'action_view/helpers/tag_helper' require 'active_support/core_ext/file' +require 'active_support/core_ext/object/blank' module ActionView module Helpers #:nodoc: @@ -623,41 +624,37 @@ module ActionView @@cache_asset_timestamps = true private + def rewrite_extension?(source, dir, ext) + source_ext = File.extname(source)[1..-1] + ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}")))) + end + + def rewrite_host_and_protocol(source, has_request) + host = compute_asset_host(source) + if has_request && host.present? && !is_uri?(host) + host = "#{controller.request.protocol}#{host}" + end + "#{host}#{source}" + end + # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL # roots. Rewrite the asset path for cache-busting asset ids. Include # asset host, if configured, with the correct request protocol. def compute_public_path(source, dir, ext = nil, include_host = true) - has_request = controller.respond_to?(:request) - - source_ext = File.extname(source)[1..-1] - if ext && !is_uri?(source) && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}")))) - source += ".#{ext}" - end + return source if is_uri?(source) - unless is_uri?(source) - source = "/#{dir}/#{source}" unless source[0] == ?/ + source += ".#{ext}" if rewrite_extension?(source, dir, ext) + source = "/#{dir}/#{source}" unless source[0] == ?/ + source = rewrite_asset_path(source) - source = rewrite_asset_path(source) - - if has_request && include_host - unless source =~ %r{^#{controller.config.relative_url_root}/} - source = "#{controller.config.relative_url_root}#{source}" - end - end + has_request = controller.respond_to?(:request) + if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/} + source = "#{controller.config.relative_url_root}#{source}" end + source = rewrite_host_and_protocol(source, has_request) if include_host - if include_host && !is_uri?(source) - host = compute_asset_host(source) - - if has_request && !host.blank? && !is_uri?(host) - host = "#{controller.request.protocol}#{host}" - end - - "#{host}#{source}" - else - source - end + source end def is_uri?(path) diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index d5cc14b29a..a904af56bb 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -32,7 +32,28 @@ module ActionView # <i>Topics listed alphabetically</i> # <% end %> def cache(name = {}, options = nil, &block) - controller.fragment_for(output_buffer, name, options, &block) + safe_concat fragment_for(name, options, &block) + nil + end + + private + # TODO: Create an object that has caching read/write on it + def fragment_for(name = {}, options = nil, &block) #:nodoc: + if controller.perform_caching + if controller.fragment_exist?(name, options) + controller.read_fragment(name, options) + else + # VIEW TODO: Make #capture usable outside of ERB + # This dance is needed because Builder can't use capture + pos = output_buffer.length + yield + fragment = output_buffer.slice!(pos..-1) + controller.write_fragment(name, fragment, options) + end + else + ret = yield + ActiveSupport::SafeBuffer.new(ret) if ret.is_a?(String) + end end end end diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 03c7ba5a87..f0be814700 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -2,22 +2,22 @@ module ActionView module Helpers # CaptureHelper exposes methods to let you extract generated markup which # can be used in other parts of a template or layout file. - # It provides a method to capture blocks into variables through capture and + # It provides a method to capture blocks into variables through capture and # a way to capture a block of markup for use in a layout through content_for. module CaptureHelper - # The capture method allows you to extract part of a template into a - # variable. You can then use this variable anywhere in your templates or layout. - # + # The capture method allows you to extract part of a template into a + # variable. You can then use this variable anywhere in your templates or layout. + # # ==== Examples # The capture method can be used in ERb templates... - # + # # <% @greeting = capture do %> # Welcome to my shiny new web page! The date and time is # <%= Time.now %> # <% end %> # # ...and Builder (RXML) templates. - # + # # @timestamp = capture do # "The current timestamp is #{Time.now}." # end @@ -32,16 +32,18 @@ module ActionView # def capture(*args) value = nil - buffer = with_output_buffer { value = yield *args } - buffer.presence || value + buffer = with_output_buffer { value = yield(*args) } + if string = buffer.presence || value and string.is_a?(String) + NonConcattingString.new(string) + end end # Calling content_for stores a block of markup in an identifier for later use. # You can make subsequent calls to the stored content in other templates or the layout # by passing the identifier as an argument to <tt>yield</tt>. - # + # # ==== Examples - # + # # <% content_for :not_authorized do %> # alert('You are not authorized to do that!') # <% end %> @@ -75,7 +77,7 @@ module ActionView # # Then, in another view, you could to do something like this: # - # <%= link_to_remote 'Logout', :action => 'logout' %> + # <%= link_to 'Logout', :action => 'logout', :remote => true %> # # <% content_for :script do %> # <%= javascript_include_tag :defaults %> @@ -92,7 +94,7 @@ module ActionView # <% end %> # # <%# Add some other content, or use a different template: %> - # + # # <% content_for :navigation do %> # <li><%= link_to 'Login', :action => 'login' %></li> # <% end %> @@ -109,13 +111,13 @@ module ActionView # for elements that will be fragment cached. def content_for(name, content = nil, &block) content = capture(&block) if block_given? - return @_content_for[name] << content if content - @_content_for[name] + @_content_for[name] << content if content + @_content_for[name] unless content end # content_for? simply checks whether any content has been captured yet using content_for # Useful to render parts of your layout differently based on what is in your views. - # + # # ==== Examples # # Perhaps you will use different css in you layout if no content_for :right_column diff --git a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb b/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb deleted file mode 100644 index 3d0657e873..0000000000 --- a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb +++ /dev/null @@ -1,52 +0,0 @@ -module ActionView - module Helpers - module DeprecatedBlockHelpers - extend ActiveSupport::Concern - - include ActionView::Helpers::TagHelper - include ActionView::Helpers::TextHelper - include ActionView::Helpers::JavaScriptHelper - include ActionView::Helpers::FormHelper - - def content_tag(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - def javascript_tag(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - def form_for(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - def form_tag(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - def fields_for(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - def field_set_tag(*, &block) - block_called_from_erb?(block) ? safe_concat(super) : super - end - - BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template' - - if RUBY_VERSION < '1.9.0' - # Check whether we're called from an erb template. - # We'd return a string in any other case, but erb <%= ... %> - # can't take an <% end %> later on, so we have to use <% ... %> - # and implicitly concat. - def block_called_from_erb?(block) - block && eval(BLOCK_CALLED_FROM_ERB, block) - end - else - def block_called_from_erb?(block) - block && eval(BLOCK_CALLED_FROM_ERB, block.binding) - end - end - end - end -end
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 6176f1fb06..2ba5339b7d 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1014,7 +1014,7 @@ module ActionView class FormBuilder #:nodoc: # The methods which wrap a form helper call. class_inheritable_accessor :field_helpers - self.field_helpers = (FormHelper.instance_methods - ['form_for']) + self.field_helpers = (FormHelper.instance_method_names - ['form_for']) attr_accessor :object_name, :object, :options @@ -1040,7 +1040,7 @@ module ActionView end (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector| - src = <<-end_src + src, file, line = <<-end_src, __FILE__, __LINE__ + 1 def #{selector}(method, options = {}) # def text_field(method, options = {}) @template.send( # @template.send( #{selector.inspect}, # "text_field", @@ -1049,7 +1049,7 @@ module ActionView objectify_options(options)) # objectify_options(options)) end # end end_src - class_eval src, __FILE__, __LINE__ + class_eval src, file, line end def fields_for(record_or_name_or_array, *args, &block) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 07eee3b399..b0a7718f22 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -1,5 +1,4 @@ require 'action_view/helpers/tag_helper' -require 'action_view/helpers/prototype_helper' module ActionView module Helpers @@ -89,6 +88,93 @@ module ActionView def javascript_cdata_section(content) #:nodoc: "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe end + + # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the + # onclick handler. + # + # The first argument +name+ is used as the button's value or display text. + # + # The next arguments are optional and may include the javascript function definition and a hash of html_options. + # + # The +function+ argument can be omitted in favor of an +update_page+ + # block, which evaluates to a string when the template is rendered + # (instead of making an Ajax request first). + # + # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button" + # + # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil + # + # Examples: + # button_to_function "Greeting", "alert('Hello world!')" + # button_to_function "Delete", "if (confirm('Really?')) do_delete()" + # button_to_function "Details" do |page| + # page[:details].visual_effect :toggle_slide + # end + # button_to_function "Details", :class => "details_button" do |page| + # page[:details].visual_effect :toggle_slide + # end + def button_to_function(name, *args, &block) + html_options = args.extract_options!.symbolize_keys + + function = block_given? ? update_page(&block) : args[0] || '' + onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};" + + tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick)) + end + + # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the + # onclick handler and return false after the fact. + # + # The first argument +name+ is used as the link text. + # + # The next arguments are optional and may include the javascript function definition and a hash of html_options. + # + # The +function+ argument can be omitted in favor of an +update_page+ + # block, which evaluates to a string when the template is rendered + # (instead of making an Ajax request first). + # + # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button" + # + # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil + # + # + # Examples: + # link_to_function "Greeting", "alert('Hello world!')" + # Produces: + # <a onclick="alert('Hello world!'); return false;" href="#">Greeting</a> + # + # link_to_function(image_tag("delete"), "if (confirm('Really?')) do_delete()") + # Produces: + # <a onclick="if (confirm('Really?')) do_delete(); return false;" href="#"> + # <img src="/images/delete.png?" alt="Delete"/> + # </a> + # + # link_to_function("Show me more", nil, :id => "more_link") do |page| + # page[:details].visual_effect :toggle_blind + # page[:more_link].replace_html "Show me less" + # end + # Produces: + # <a href="#" id="more_link" onclick="try { + # $("details").visualEffect("toggle_blind"); + # $("more_link").update("Show me less"); + # } + # catch (e) { + # alert('RJS error:\n\n' + e.toString()); + # alert('$(\"details\").visualEffect(\"toggle_blind\"); + # \n$(\"more_link\").update(\"Show me less\");'); + # throw e + # }; + # return false;">Show me more</a> + # + def link_to_function(name, *args, &block) + html_options = args.extract_options!.symbolize_keys + + function = block_given? ? update_page(&block) : args[0] || '' + onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;" + href = html_options[:href] || '#' + + content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick)) + end end end end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 46e41bc406..719b64b940 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -3,10 +3,24 @@ require 'active_support/core_ext/float/rounding' module ActionView module Helpers #:nodoc: + # Provides methods for converting numbers into formatted strings. # Methods are provided for phone numbers, currency, percentage, - # precision, positional notation, and file size. + # precision, positional notation, file size and pretty printing. + # + # Most methods expect a +number+ argument, and will return it + # unchanged if can't be converted into a valid number. module NumberHelper + + # Raised when argument +number+ param given to the helpers is invalid and + # the option :raise is set to +true+. + class InvalidNumberError < StandardError + attr_accessor :number + def initialize(number) + @number = number + end + end + # Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format # in the +options+ hash. # @@ -30,6 +44,17 @@ module ActionView def number_to_phone(number, options = {}) return nil if number.nil? + begin + Float(number) + is_number_html_safe = true + rescue ArgumentError, TypeError + if options[:raise] + raise InvalidNumberError, number + else + is_number_html_safe = number.to_s.html_safe? + end + end + number = number.to_s.strip options = options.symbolize_keys area_code = options[:area_code] || nil @@ -46,7 +71,7 @@ module ActionView number.starts_with?('-') ? number.slice!(1..-1) : number end str << " x #{extension}" unless extension.blank? - str + is_number_html_safe ? str.html_safe : str end # Formats a +number+ into a currency string (e.g., $13.65). You can customize the format @@ -72,38 +97,42 @@ module ActionView # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "", :format => "%n %u") # # => 1234567890,50 £ def number_to_currency(number, options = {}) + return nil if number.nil? + options.symbolize_keys! - defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {} - currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :raise => true) rescue {} + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) + currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {}) defaults = defaults.merge(currency) - precision = options[:precision] || defaults[:precision] - unit = options[:unit] || defaults[:unit] - separator = options[:separator] || defaults[:separator] - delimiter = options[:delimiter] || defaults[:delimiter] - format = options[:format] || defaults[:format] - separator = '' if precision == 0 + options = options.reverse_merge(defaults) - value = number_with_precision(number, - :precision => precision, - :delimiter => delimiter, - :separator => separator) + unit = options.delete(:unit) + format = options.delete(:format) - if value + begin + value = number_with_precision(number, options.merge(:raise => true)) format.gsub(/%n/, value).gsub(/%u/, unit).html_safe - else - number + rescue InvalidNumberError => e + if options[:raise] + raise + else + formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit) + e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number + end end + end # Formats a +number+ as a percentage string (e.g., 65%). You can customize the # format in the +options+ hash. # # ==== Options - # * <tt>:precision</tt> - Sets the level of precision (defaults to 3). - # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3). + # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+) + # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to "."). # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). + # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +false+) # # ==== Examples # number_to_percentage(100) # => 100.000% @@ -111,21 +140,25 @@ module ActionView # number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000% # number_to_percentage(302.24398923423, :precision => 5) # => 302.24399% def number_to_percentage(number, options = {}) + return nil if number.nil? + options.symbolize_keys! - defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {} - percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :raise => true) rescue {} + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) + percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {}) defaults = defaults.merge(percentage) - precision = options[:precision] || defaults[:precision] - separator = options[:separator] || defaults[:separator] - delimiter = options[:delimiter] || defaults[:delimiter] + options = options.reverse_merge(defaults) - value = number_with_precision(number, - :precision => precision, - :separator => separator, - :delimiter => delimiter) - value ? value + "%" : number + begin + "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe + rescue InvalidNumberError => e + if options[:raise] + raise + else + e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%" + end + end end # Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can @@ -133,7 +166,7 @@ module ActionView # # ==== Options # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ","). - # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to "."). # # ==== Examples # number_with_delimiter(12345678) # => 12,345,678 @@ -146,148 +179,186 @@ module ActionView # You can still use <tt>number_with_delimiter</tt> with the old API that accepts the # +delimiter+ as its optional second and the +separator+ as its # optional third parameter: - # number_with_delimiter(12345678, " ") # => 12 345.678 + # number_with_delimiter(12345678, " ") # => 12 345 678 # number_with_delimiter(12345678.05, ".", ",") # => 12.345.678,05 def number_with_delimiter(number, *args) options = args.extract_options! options.symbolize_keys! - defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {} + begin + Float(number) + rescue ArgumentError, TypeError + if options[:raise] + raise InvalidNumberError, number + else + return number + end + end + + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) unless args.empty? ActiveSupport::Deprecation.warn('number_with_delimiter takes an option hash ' + 'instead of separate delimiter and precision arguments.', caller) - delimiter = args[0] || defaults[:delimiter] - separator = args[1] || defaults[:separator] + options[:delimiter] ||= args[0] if args[0] + options[:separator] ||= args[1] if args[1] end - delimiter ||= (options[:delimiter] || defaults[:delimiter]) - separator ||= (options[:separator] || defaults[:separator]) + options = options.reverse_merge(defaults) parts = number.to_s.split('.') - if parts[0] - parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}") - parts.join(separator) - else - number - end + parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}") + parts.join(options[:separator]).html_safe + end - # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision of 2). + # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision + # of 2 if +:significant+ is +false+, and 5 if +:significant+ is +true+). # You can customize the format in the +options+ hash. # # ==== Options - # * <tt>:precision</tt> - Sets the level of precision (defaults to 3). - # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3). + # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+) + # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to "."). # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). + # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +false+) # # ==== Examples - # number_with_precision(111.2345) # => 111.235 - # number_with_precision(111.2345, :precision => 2) # => 111.23 - # number_with_precision(13, :precision => 5) # => 13.00000 - # number_with_precision(389.32314, :precision => 0) # => 389 + # number_with_precision(111.2345) # => 111.235 + # number_with_precision(111.2345, :precision => 2) # => 111.23 + # number_with_precision(13, :precision => 5) # => 13.00000 + # number_with_precision(389.32314, :precision => 0) # => 389 + # number_with_precision(111.2345, :significant => true) # => 111 + # number_with_precision(111.2345, :precision => 1, :significant => true) # => 100 + # number_with_precision(13, :precision => 5, :significant => true) # => 13.000 + # number_with_precision(13, :precision => 5, :significant => true, strip_insignificant_zeros => true) + # # => 13 + # number_with_precision(389.32314, :precision => 4, :significant => true) # => 389.3 # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.') # # => 1.111,23 # # You can still use <tt>number_with_precision</tt> with the old API that accepts the # +precision+ as its optional second parameter: - # number_with_precision(number_with_precision(111.2345, 2) # => 111.23 + # number_with_precision(111.2345, 2) # => 111.23 def number_with_precision(number, *args) + options = args.extract_options! options.symbolize_keys! - defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {} - precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], - :raise => true) rescue {} + number = begin + Float(number) + rescue ArgumentError, TypeError + if options[:raise] + raise InvalidNumberError, number + else + return number + end + end + + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) + precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {}) defaults = defaults.merge(precision_defaults) + #Backwards compatibility unless args.empty? ActiveSupport::Deprecation.warn('number_with_precision takes an option hash ' + 'instead of a separate precision argument.', caller) - precision = args[0] || defaults[:precision] + options[:precision] ||= args[0] if args[0] end - precision ||= (options[:precision] || defaults[:precision]) - separator ||= (options[:separator] || defaults[:separator]) - delimiter ||= (options[:delimiter] || defaults[:delimiter]) + options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false + precision = options.delete :precision + significant = options.delete :significant + strip_insignificant_zeros = options.delete :strip_insignificant_zeros - begin - value = Float(number) - rescue ArgumentError, TypeError - value = nil + if significant and precision > 0 + digits = (Math.log10(number) + 1).floor + rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision) + precision = precision - digits + precision = precision > 0 ? precision : 0 #don't let it be negative + else + rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision end - - if value - rounded_number = BigDecimal.new((Float(number) * (10 ** precision)).to_s).round.to_f / 10 ** precision - number_with_delimiter("%01.#{precision}f" % rounded_number, - :separator => separator, - :delimiter => delimiter) + formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options) + if strip_insignificant_zeros + escaped_separator = Regexp.escape(options[:separator]) + formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe else - number + formatted_number end + end STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze - # Formats the bytes in +size+ into a more understandable representation + # Formats the bytes in +number+ into a more understandable representation # (e.g., giving it 1500 yields 1.5 KB). This method is useful for - # reporting file sizes to users. This method returns nil if - # +size+ cannot be converted into a number. You can customize the + # reporting file sizes to users. You can customize the # format in the +options+ hash. # + # See <tt>number_to_human</tt> if you want to pretty-print a generic number. + # # ==== Options - # * <tt>:precision</tt> - Sets the level of precision (defaults to 1). - # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3). + # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+) + # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to "."). # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). - # + # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+) # ==== Examples # number_to_human_size(123) # => 123 Bytes - # number_to_human_size(1234) # => 1.2 KB + # number_to_human_size(1234) # => 1.21 KB # number_to_human_size(12345) # => 12.1 KB - # number_to_human_size(1234567) # => 1.2 MB - # number_to_human_size(1234567890) # => 1.1 GB - # number_to_human_size(1234567890123) # => 1.1 TB - # number_to_human_size(1234567, :precision => 2) # => 1.18 MB - # number_to_human_size(483989, :precision => 0) # => 473 KB - # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB + # number_to_human_size(1234567) # => 1.18 MB + # number_to_human_size(1234567890) # => 1.15 GB + # number_to_human_size(1234567890123) # => 1.12 TB + # number_to_human_size(1234567, :precision => 2) # => 1.2 MB + # number_to_human_size(483989, :precision => 2) # => 470 KB + # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,2 MB # - # Zeros after the decimal point are always stripped out, regardless of the - # specified precision: - # helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB" - # helper.number_to_human_size(524288000, :precision=>5) # => "500 MB" + # Unsignificant zeros after the fractional separator are stripped out by default (set + # <tt>:strip_insignificant_zeros</tt> to +false+ to change that): + # number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB" + # number_to_human_size(524288000, :precision=>5) # => "500 MB" # # You can still use <tt>number_to_human_size</tt> with the old API that accepts the # +precision+ as its optional second parameter: - # number_to_human_size(1234567, 2) # => 1.18 MB - # number_to_human_size(483989, 0) # => 473 KB + # number_to_human_size(1234567, 1) # => 1 MB + # number_to_human_size(483989, 2) # => 470 KB def number_to_human_size(number, *args) - return nil if number.nil? - options = args.extract_options! options.symbolize_keys! - defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {} - human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {} + number = begin + Float(number) + rescue ArgumentError, TypeError + if options[:raise] + raise InvalidNumberError, number + else + return number + end + end + + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) + human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {}) defaults = defaults.merge(human) unless args.empty? ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' + 'instead of a separate precision argument.', caller) - precision = args[0] || defaults[:precision] + options[:precision] ||= args[0] if args[0] end - precision ||= (options[:precision] || defaults[:precision]) - separator ||= (options[:separator] || defaults[:separator]) - delimiter ||= (options[:delimiter] || defaults[:delimiter]) + options = options.reverse_merge(defaults) + #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true) if number.to_i < 1024 unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true) - storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit) + storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe else max_exp = STORAGE_UNITS.size - 1 - number = Float(number) exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024 exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit number /= 1024 ** exponent @@ -295,15 +366,138 @@ module ActionView unit_key = STORAGE_UNITS[exponent] unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true) - escaped_separator = Regexp.escape(separator) - formatted_number = number_with_precision(number, - :precision => precision, - :separator => separator, - :delimiter => delimiter - ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') - storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit) + formatted_number = number_with_precision(number, options) + storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe + end + end + + DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, + -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze + + # Pretty prints (formats and approximates) a number in a way it is more readable by humans + # (eg.: 1200000000 becomes "1.2 Billion"). This is useful for numbers that + # can get very large (and too hard to read). + # + # See <tt>number_to_human_size</tt> if you want to print a file size. + # + # You can also define you own unit-quantifier names if you want to use other decimal units + # (eg.: 1500 becomes "1.5 kilometers", 0.150 becomes "150 mililiters", etc). You may define + # a wide range of unit quantifiers, even fractional ones (centi, deci, mili, etc). + # + # ==== Options + # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3). + # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+) + # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to "."). + # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ""). + # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+) + # * <tt>:units</tt> - A Hash of unit quantifier names. Or a string containing an i18n scope where to find this hash. It might have the following keys: + # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>, <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt> + # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt> + # * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are: + # + # %u The quantifier (ex.: 'thousand') + # %n The number + # + # ==== Examples + # number_to_human(123) # => "123" + # number_to_human(1234) # => "1.23 Thousand" + # number_to_human(12345) # => "12.3 Thousand" + # number_to_human(1234567) # => "1.23 Million" + # number_to_human(1234567890) # => "1.23 Billion" + # number_to_human(1234567890123) # => "1.23 Trillion" + # number_to_human(1234567890123456) # => "1.23 Quadrillion" + # number_to_human(1234567890123456789) # => "1230 Quadrillion" + # number_to_human(489939, :precision => 2) # => "490 Thousand" + # number_to_human(489939, :precision => 4) # => "489.9 Thousand" + # number_to_human(1234567, :precision => 4, + # :significant => false) # => "1.2346 Million" + # number_to_human(1234567, :precision => 1, + # :separator => ',', + # :significant => false) # => "1,2 Million" + # + # Unsignificant zeros after the decimal separator are stripped out by default (set + # <tt>:strip_insignificant_zeros</tt> to +false+ to change that): + # number_to_human(12345012345, :significant_digits => 6) # => "12.345 Billion" + # number_to_human(500000000, :precision=>5) # => "500 Million" + # + # ==== Custom Unit Quantifiers + # + # You can also use your own custom unit quantifiers: + # number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"}) # => "500 lt" + # + # If in your I18n locale you have: + # distance: + # centi: + # one: "centimeter" + # other: "centimeters" + # unit: + # one: "meter" + # other: "meters" + # thousand: + # one: "kilometer" + # other: "kilometers" + # billion: "gazilion-distance" + # + # Then you could do: + # + # number_to_human(543934, :units => :distance) # => "544 kilometers" + # number_to_human(54393498, :units => :distance) # => "54400 kilometers" + # number_to_human(54393498000, :units => :distance) # => "54.4 gazilion-distance" + # number_to_human(343, :units => :distance, :precision => 1) # => "300 meters" + # number_to_human(1, :units => :distance) # => "1 meter" + # number_to_human(0.34, :units => :distance) # => "34 centimeters" + # + def number_to_human(number, options = {}) + options.symbolize_keys! + + number = begin + Float(number) + rescue ArgumentError, TypeError + if options[:raise] + raise InvalidNumberError, number + else + return number + end end + + defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) + human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {}) + defaults = defaults.merge(human) + + options = options.reverse_merge(defaults) + #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) + + units = options.delete :units + unit_exponents = case units + when Hash + units + when String, Symbol + I18n.translate(:"#{units}", :locale => options[:locale], :raise => true) + when nil + I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true) + else + raise ArgumentError, ":units must be a Hash or String translation scope." + end.keys.map{|e_name| DECIMAL_UNITS.invert[e_name] }.sort_by{|e| -e} + + number_exponent = Math.log10(number).floor + display_exponent = unit_exponents.find{|e| number_exponent >= e } + number /= 10 ** display_exponent + + unit = case units + when Hash + units[DECIMAL_UNITS[display_exponent]] + when String, Symbol + I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i) + else + I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i) + end + + decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u") + formatted_number = number_with_precision(number, options) + decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe end + end end end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index dc3c6d88f5..ccdc8181db 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -102,39 +102,6 @@ module ActionView :form, :with, :update, :script, :type ]).merge(CALLBACKS) end - # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the - # onclick handler. - # - # The first argument +name+ is used as the button's value or display text. - # - # The next arguments are optional and may include the javascript function definition and a hash of html_options. - # - # The +function+ argument can be omitted in favor of an +update_page+ - # block, which evaluates to a string when the template is rendered - # (instead of making an Ajax request first). - # - # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button" - # - # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil - # - # Examples: - # button_to_function "Greeting", "alert('Hello world!')" - # button_to_function "Delete", "if (confirm('Really?')) do_delete()" - # button_to_function "Details" do |page| - # page[:details].visual_effect :toggle_slide - # end - # button_to_function "Details", :class => "details_button" do |page| - # page[:details].visual_effect :toggle_slide - # end - def button_to_function(name, *args, &block) - html_options = args.extract_options!.symbolize_keys - - function = block_given? ? update_page(&block) : args[0] || '' - onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};" - - tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick)) - end - # Returns the JavaScript needed for a remote function. # Takes the same arguments as link_to_remote. # @@ -181,11 +148,9 @@ module ActionView class JavaScriptGenerator #:nodoc: def initialize(context, &block) #:nodoc: @context, @lines = context, [] - @context.update_details(:formats => [:js, :html]) do - include_helpers_from_context - @context.with_output_buffer(@lines) do - @context.instance_exec(self, &block) - end + include_helpers_from_context + @context.with_output_buffer(@lines) do + @context.instance_exec(self, &block) end end @@ -615,7 +580,7 @@ module ActionView # page.hide 'spinner' # end def update_page(&block) - JavaScriptGenerator.new(@template, &block).to_s.html_safe + JavaScriptGenerator.new(view_context, &block).to_s.html_safe end # Works like update_page but wraps the generated JavaScript in a <script> @@ -689,6 +654,10 @@ module ActionView @generator << root if root end + def is_a?(klass) + klass == JavaScriptProxy + end + private def method_missing(method, *arguments, &block) if method.to_s =~ /(.*)=$/ @@ -882,5 +851,3 @@ module ActionView end end end - -require 'action_view/helpers/javascript_helper' diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index e1ce65f90a..27be1690dd 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -29,7 +29,7 @@ module ActionView end def safe_concat(string) - output_buffer.safe_concat(string) + output_buffer.respond_to?(:safe_concat) ? output_buffer.safe_concat(string) : concat(string) end # Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt> @@ -576,7 +576,7 @@ module ActionView # each email is yielded and the result is used as the link text. def auto_link_email_addresses(text, html_options = {}) body = text.dup - text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do + text.gsub(/([\w\.!#\$%\-+]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do text = $1 if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/) diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 8a89ee58a0..457944dbb6 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -13,7 +13,7 @@ module ActionView def translate(key, options = {}) options[:raise] = true translation = I18n.translate(scope_key_by_partial(key), options) - translation.is_a?(Array) ? translation.map { |entry| entry.html_safe } : translation.html_safe + (translation.respond_to?(:join) ? translation.join : translation).html_safe rescue I18n::MissingTranslationData => e keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope]) content_tag('span', keys.join(', '), :class => 'translation_missing') @@ -29,9 +29,10 @@ module ActionView private def scope_key_by_partial(key) - if (key.respond_to?(:join) ? key.join : key.to_s).first == "." + strkey = key.respond_to?(:join) ? key.join : key.to_s + if strkey.first == "." if @_virtual_path - @_virtual_path.gsub(%r{/_?}, ".") + key.to_s + @_virtual_path.gsub(%r{/_?}, ".") + strkey else raise "Cannot use t(#{key.inspect}) shortcut because path is not available" end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 131e950b18..b23d5fcb68 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -1,6 +1,7 @@ require 'action_view/helpers/javascript_helper' require 'active_support/core_ext/array/access' require 'active_support/core_ext/hash/keys' +require 'action_dispatch' module ActionView module Helpers #:nodoc: @@ -9,6 +10,9 @@ module ActionView # This allows you to use the same format for links in views # and controllers. module UrlHelper + extend ActiveSupport::Concern + + include ActionDispatch::Routing::UrlFor include JavaScriptHelper # Need to map default url options to controller one. @@ -16,6 +20,10 @@ module ActionView controller.send(:default_url_options, *args) end + def url_options + controller.url_options + end + # Returns the URL for the set of +options+ provided. This takes the # same options as +url_for+ in Action Controller (see the # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default @@ -206,7 +214,7 @@ module ActionView if block_given? options = args.first || {} html_options = args.second - safe_concat(link_to(capture(&block), options, html_options)) + link_to(capture(&block), options, html_options) else name = args[0] options = args[1] || {} @@ -578,8 +586,6 @@ module ActionView add_confirm_to_attributes!(html_options, confirm) if confirm add_method_to_attributes!(html_options, method) if method - html_options["data-url"] = options[:url] if options.is_a?(Hash) && options[:url] - html_options end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index a3548051c1..a3e2230f6f 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -9,6 +9,11 @@ delimiter: "," # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) precision: 3 + # If set to true, precision will mean the number of significant digits instead + # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2) + significant: false + # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2) + strip_insignificant_zeros: false # Used in number_to_currency() currency: @@ -16,34 +21,43 @@ # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) format: "%u%n" unit: "$" - # These three are to override number.format and are optional + # These five are to override number.format and are optional separator: "." delimiter: "," precision: 2 + significant: false + strip_insignificant_zeros: false # Used in number_to_percentage() percentage: format: - # These three are to override number.format and are optional + # These five are to override number.format and are optional # separator: delimiter: "" # precision: + # significant: false + # strip_insignificant_zeros: false # Used in number_to_precision() precision: format: - # These three are to override number.format and are optional + # These five are to override number.format and are optional # separator: delimiter: "" # precision: + # significant: false + # strip_insignificant_zeros: false - # Used in number_to_human_size() + # Used in number_to_human_size() and number_to_human() human: format: - # These three are to override number.format and are optional + # These five are to override number.format and are optional # separator: delimiter: "" - precision: 1 + precision: 3 + significant: true + strip_insignificant_zeros: true + # Used in number_to_human_size() storage_units: # Storage units output formatting. # %u is the storage unit, %n is the number (default: 2 MB) @@ -56,6 +70,31 @@ mb: "MB" gb: "GB" tb: "TB" + # Used in number_to_human() + decimal_units: + format: "%n %u" + # Decimal units output formatting + # By default we will only quantify some of the exponents + # but the commented ones might be defined or overridden + # by the user. + units: + # femto: Quadrillionth + # pico: Trillionth + # nano: Billionth + # micro: Millionth + # mili: Thousandth + # centi: Hundredth + # deci: Tenth + unit: "" + # ten: + # one: Ten + # other: Tens + # hundred: Hundred + thousand: Thousand + million: Million + billion: Billion + trillion: Trillion + quadrillion: Quadrillion # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() datetime: diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 8eb17bf8f1..9b59aac0eb 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/try' +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' module ActionView @@ -15,23 +15,26 @@ module ActionView def self.register_detail(name, options = {}, &block) self.registered_details << name + Accessors.send :define_method, :"_#{name}_defaults", &block + Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1 + def #{name} + @details[:#{name}] + end - Setters.send :define_method, :"_#{name}_defaults", &block - Setters.module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{name}=(value) - value = Array(value.presence || _#{name}_defaults) - #{"value << nil unless value.include?(nil)" unless options[:allow_nil] == false} + value = Array.wrap(value.presence || _#{name}_defaults) - unless value == @details[:#{name}] - @details_key, @details = nil, @details.merge(:#{name} => value) - @details.freeze + if value != @details[:#{name}] + @details_key = nil + @details = @details.dup if @details.frozen? + @details[:#{name}] = value.freeze end end METHOD end - # Holds raw setters for the registered details. - module Setters #:nodoc: + # Holds accessors for the registered details. + module Accessors #:nodoc: end register_detail(:formats) { Mime::SET.symbols } @@ -45,7 +48,7 @@ module ActionView @details_keys = Hash.new def self.get(details) - @details_keys[details] ||= new + @details_keys[details.freeze] ||= new end def initialize @@ -54,9 +57,10 @@ module ActionView end def initialize(view_paths, details = {}) - @details, @details_key = {}, nil + @details, @details_key = { :handlers => default_handlers }, nil + @frozen_formats = false self.view_paths = view_paths - self.details = details + self.update_details(details, true) end module ViewPaths @@ -69,16 +73,16 @@ module ActionView end def find(name, prefix = nil, partial = false) - @view_paths.find(name, prefix, partial, details, details_key) + @view_paths.find(*args_for_lookup(name, prefix, partial)) end alias :find_template :find def find_all(name, prefix = nil, partial = false) - @view_paths.find_all(name, prefix, partial, details, details_key) + @view_paths.find_all(*args_for_lookup(name, prefix, partial)) end def exists?(name, prefix = nil, partial = false) - @view_paths.exists?(name, prefix, partial, details, details_key) + @view_paths.exists?(*args_for_lookup(name, prefix, partial)) end alias :template_exists? :exists? @@ -94,51 +98,80 @@ module ActionView ensure added_resolvers.times { view_paths.pop } end - end - module Details - attr_reader :details + protected + + def args_for_lookup(name, prefix, partial) #:nodoc: + name, prefix = normalize_name(name, prefix) + [name, prefix, partial || false, @details, details_key] + 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, prefix) #:nodoc: + name = name.to_s.gsub(handlers_regexp, '') + parts = name.split('/') + return parts.pop, [prefix, *parts].compact.join("/") + end - def details=(given_details) - registered_details.each { |key| send(:"#{key}=", given_details[key]) } + def default_handlers #:nodoc: + @default_handlers ||= Template::Handlers.extensions end - def details_key + def handlers_regexp #:nodoc: + @handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/ + end + end + + module Details + # 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) end - # Shortcut to read formats from details. - def formats - @details[:formats].compact + # 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 # Overload formats= to reject [:"*/*"] values. - def formats=(value, freeze=true) - value = nil if value == [:"*/*"] + def formats=(value) + value = nil if value == [:"*/*"] + value << :html if value == [:js] super(value) end - # Shortcut to read locale. + # Overload locale to return a symbol instead of array def locale - I18n.locale + @details[:locale].first end # Overload locale= to also set the I18n.locale. If the current I18n.config object responds # to i18n_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) - value = value.first if value.is_a?(Array) - config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config - config.locale = value if value + if value + config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config + config.locale = value + end super(I18n.locale) 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 - self.details = old_details.merge(new_details) + def update_details(new_details, force=false) + old_details = @details.dup + + registered_details.each do |key| + send(:"#{key}=", new_details[key]) if force || new_details.key?(key) + end if block_given? begin @@ -150,7 +183,7 @@ module ActionView end end - include Setters + include Accessors include Details include ViewPaths end diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index 2e5d115630..9cf007cd2b 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -3,10 +3,10 @@ require "rails" module ActionView class Railtie < Rails::Railtie - railtie_name :action_view + config.action_view = ActiveSupport::OrderedOptions.new require "action_view/railties/log_subscriber" - log_subscriber ActionView::Railties::LogSubscriber.new + log_subscriber :action_view, ActionView::Railties::LogSubscriber.new initializer "action_view.cache_asset_timestamps" do |app| unless app.config.cache_classes @@ -15,5 +15,13 @@ module ActionView end end end + + initializer "action_view.set_configs" do |app| + ActionView.base_hook do + app.config.action_view.each do |k,v| + send "#{k}=", v + end + end + end end end
\ No newline at end of file diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb index 11ff05ce5b..578f39d817 100644 --- a/actionpack/lib/action_view/render/layouts.rb +++ b/actionpack/lib/action_view/render/layouts.rb @@ -43,10 +43,16 @@ module ActionView # This is the method which actually finds the layout using details in the lookup # context object. If no layout is found, it checkes if at least a layout with # the given name exists across all details before raising the error. - def find_layout(layout) #:nodoc: + # + # If self.formats contains several formats, just the first one is considered in + # the layout lookup. + def find_layout(layout) begin - layout =~ /^\// ? - with_fallbacks { find_template(layout) } : find_template(layout) + if formats.size == 1 + _find_layout(layout) + else + update_details(:formats => self.formats.first){ _find_layout(layout) } + end rescue ActionView::MissingTemplate => e update_details(:formats => nil) do raise unless template_exists?(layout) @@ -54,6 +60,11 @@ module ActionView end end + def _find_layout(layout) #:nodoc: + layout =~ /^\// ? + with_fallbacks { find_template(layout) } : find_template(layout) + end + # Contains the logic that actually renders the layout. def _render_layout(layout, locals, &block) #:nodoc: layout.render(self, locals){ |*name| _layout_for(*name, &block) } diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 310efe40e2..492326964a 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -16,13 +16,12 @@ module ActionView case options when Hash if block_given? - content = _render_partial(options.merge(:partial => options[:layout]), &block) - safe_concat(content) + _render_partial(options.merge(:partial => options[:layout]), &block) elsif options.key?(:partial) _render_partial(options) else template = _determine_template(options) - self.formats = template.formats + lookup_context.freeze_formats(template.formats, true) _render_template(template, options[:layout], options) end when :update @@ -54,16 +53,12 @@ module ActionView layout = find_layout(layout) if layout ActiveSupport::Notifications.instrument("action_view.render_template", - :identifier => template.identifier, :layout => layout.try(:identifier)) do + :identifier => template.identifier, :layout => layout.try(:virtual_path)) do content = template.render(self, locals) { |*name| _layout_for(*name) } @_content_for[:layout] = content - if layout - @_layout = layout.identifier - content = _render_layout(layout, locals) - end - + content = _render_layout(layout, locals) if layout content end end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index b4fdb49d3b..8abc1633ff 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,8 +1,7 @@ # encoding: utf-8 # This is so that templates compiled in this file are UTF-8 - -require 'set' -require "action_view/template/resolver" +require 'active_support/core_ext/array/wrap' +require 'active_support/core_ext/object/blank' module ActionView class Template @@ -24,19 +23,20 @@ module ActionView @identifier = identifier @handler = handler - @partial = details[:partial] @virtual_path = details[:virtual_path] @method_names = {} - format = details[:format] - format ||= handler.default_format.to_sym if handler.respond_to?(:default_format) - format ||= :html - @formats = [format.to_sym] + format = details[:format] || :html + @formats = Array.wrap(format).map(&:to_sym) end def render(view, locals, &block) - method_name = compile(locals, view) - view.send(method_name, locals, &block) + # Notice that we use a bang in this instrumentation because you don't want to + # consume this in production. This is only slow if it's being listened to. + ActiveSupport::Notifications.instrument("action_view.render_template!", :virtual_path => @virtual_path) do + method_name = compile(locals, view) + view.send(method_name, locals, &block) + end rescue Exception => e if e.is_a?(Template::Error) e.sub_template_of(self) @@ -58,10 +58,6 @@ module ActionView @counter_name ||= "#{variable_name}_counter".to_sym end - def partial? - @partial - end - def inspect if defined?(Rails.root) identifier.sub("#{Rails.root}/", '') diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 648f708d3d..5222ffa89c 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -1,6 +1,26 @@ require "active_support/core_ext/enumerable" module ActionView + class ActionViewError < StandardError #:nodoc: + end + + class MissingTemplate < ActionViewError #:nodoc: + attr_reader :path + + def initialize(paths, path, details, partial) + @path = path + display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ") + template_type = if partial + "partial" + elsif path =~ /layouts/i + 'layout' + else + 'template' + end + + super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}") + end + end class Template # The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a # bunch of intimate details and uses it to report a very precise exception message. @@ -73,11 +93,11 @@ module ActionView end def to_s - "\n#{self.class} (#{message}) #{source_location}:\n" + + "\n#{self.class} (#{message}) #{source_location}:\n" + "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n" end - # don't do anything nontrivial here. Any raised exception from here becomes fatal + # don't do anything nontrivial here. Any raised exception from here becomes fatal # (and can't be rescued). def backtrace @backtrace diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index ac5902cc0e..705c2bf82e 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -8,6 +8,13 @@ module ActionView super(value.to_s) end alias :append= :<< + + def append_if_string=(value) + if value.is_a?(String) && !value.is_a?(NonConcattingString) + ActiveSupport::Deprecation.warn("<% %> style block helpers are deprecated. Please use <%= %>", caller) + self << value + end + end end module Template::Handlers @@ -21,14 +28,24 @@ module ActionView src << "@output_buffer.safe_concat('" << escape_text(text) << "');" end + BLOCK_EXPR = /(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + def add_expr_literal(src, code) - if code =~ /(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + if code =~ BLOCK_EXPR src << '@output_buffer.append= ' << code else src << '@output_buffer.append= (' << code << ');' end end + def add_stmt(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append_if_string= ' << code + else + super + end + end + def add_expr_escaped(src, code) src << '@output_buffer.append= ' << escaped_expr(code) << ';' end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index a43597e728..8e8afaa43f 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -1,6 +1,5 @@ require "pathname" require "active_support/core_ext/class" -require "active_support/core_ext/array/wrap" require "action_view/template" module ActionView @@ -14,15 +13,8 @@ module ActionView @cached.clear end - def find(*args) - find_all(*args).first - end - # Normalizes the arguments and passes it on to find_template. def find_all(name, prefix=nil, partial=false, details={}, key=nil) - name, prefix = normalize_name(name, prefix) - details = details.merge(:handlers => default_handlers) - cached(key, prefix, name, partial) do find_templates(name, prefix, partial, details) end @@ -34,10 +26,6 @@ module ActionView @caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes end - def default_handlers - Template::Handlers.extensions + [nil] - end - # This is what child classes implement. No defaults are needed # because Resolver guarantees that the arguments are present and # normalized. @@ -45,17 +33,6 @@ module ActionView raise NotImplementedError 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, prefix) - handlers = Template::Handlers.extensions.join('|') - name = name.to_s.gsub(/\.(?:#{handlers})$/, '') - - parts = name.split('/') - return parts.pop, [prefix, *parts].compact.join("/") - end - def cached(key, prefix, name, partial) return yield unless key && caching? scope = @cached[key][prefix][name] @@ -79,7 +56,7 @@ module ActionView def find_templates(name, prefix, partial, details) path = build_path(name, prefix, partial, details) - query(partial, path, EXTENSION_ORDER.map { |ext| details[ext] }) + query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats]) end def build_path(name, prefix, partial, details) @@ -89,26 +66,32 @@ module ActionView path end - def query(partial, path, exts) + def query(path, exts, formats) query = File.join(@path, path) exts.each do |ext| - query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}' + query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << ',}' end Dir[query].reject { |p| File.directory?(p) }.map do |p| - handler, format = extract_handler_and_format(p) + handler, format = extract_handler_and_format(p, formats) Template.new(File.read(p), File.expand_path(p), handler, - :partial => partial, :virtual_path => path, :format => format) + :virtual_path => path, :format => format) end end - def extract_handler_and_format(path) + # Extract handler and formats from path. If a format cannot be a found neither + # from the path, or the handler, we should return the array of formats given + # to the resolver. + def extract_handler_and_format(path, default_formats) pieces = File.basename(path).split(".") pieces.shift - handler = Template.handler_class_for_extension(pieces.pop) - format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym + handler = Template.handler_class_for_extension(pieces.pop) + format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym + format ||= handler.default_format if handler.respond_to?(:default_format) + format ||= default_formats + [handler, format] end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 1578ac9479..b0ababe344 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -2,29 +2,10 @@ require 'action_controller/test_case' require 'action_view' module ActionView - class Base - alias_method :initialize_without_template_tracking, :initialize - def initialize(*args) - @_rendered = { :template => nil, :partials => Hash.new(0) } - initialize_without_template_tracking(*args) - end - - attr_internal :rendered - end - - class Template - alias_method :render_without_tracking, :render - def render(view, locals, &blk) - rendered = view.rendered - rendered[:partials][self] += 1 if partial? - rendered[:template] ||= [] - rendered[:template] << self - render_without_tracking(view, locals, &blk) - end - end - class TestCase < ActiveSupport::TestCase class TestController < ActionController::Base + include ActionDispatch::TestProcess + attr_accessor :request, :response, :params def self.controller_path @@ -42,6 +23,7 @@ module ActionView end include ActionDispatch::Assertions, ActionDispatch::TestProcess + include ActionController::TemplateAssertions include ActionView::Context include ActionController::PolymorphicRoutes @@ -64,7 +46,7 @@ module ActionView end def config - @controller.config + @controller.config if @controller.respond_to?(:config) end def render(options = {}, local_assigns = {}, &block) @@ -124,7 +106,8 @@ module ActionView def _view view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller) - view.class.send :include, _helpers + view.singleton_class.send :include, _helpers + view.singleton_class.send :include, @controller._router.url_helpers view.output_buffer = self.output_buffer view end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 67aa412d3d..5b2ff3e871 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -44,6 +44,19 @@ ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') FIXTURES = Pathname.new(FIXTURE_LOAD_PATH) +module RackTestUtils + def body_to_string(body) + if body.respond_to?(:each) + str = "" + body.each {|s| str << s } + str + else + body + end + end + extend self +end + module SetupOnce extend ActiveSupport::Concern @@ -239,47 +252,6 @@ module ActionController setup do @router = SharedTestRoutes end - - def assert_template(options = {}, message = nil) - validate_request! - - hax = @controller.view_context.instance_variable_get(:@_rendered) - - case options - when NilClass, String - rendered = (hax[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting <?> but rendering with <?>", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - hax[:template].blank? - else - rendered.any? { |t| t.match(options) } - end - end - when Hash - if expected_partial = options[:partial] - partials = hax[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found[1] - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial <?> but action rendered <?>", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end - else - assert hax[:partials].empty?, - "Expected no partials to be rendered" - end - end - end end end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 26e0d6d844..1741b58f72 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -181,6 +181,8 @@ module Admin end end +# require "action_dispatch/test_process" + # a test case to exercise the new capabilities TestRequest & TestResponse class ActionPackAssertionsControllerTest < ActionController::TestCase # -- assertion-based testing ------------------------------------------------ @@ -303,14 +305,14 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # make sure that the template objects exist def test_template_objects_alive process :assign_this - assert !@controller.template.instance_variable_get(:"@hi") - assert @controller.template.instance_variable_get(:"@howdy") + assert !@controller.instance_variable_get(:"@hi") + assert @controller.instance_variable_get(:"@howdy") end # make sure we don't have template objects when we shouldn't def test_template_object_missing process :nothing - assert_nil @controller.template.assigns['howdy'] + assert_nil @controller.instance_variable_get(:@howdy) end # check the empty flashing @@ -365,11 +367,10 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # check if we were rendered by a file-based template? def test_rendered_action process :nothing - assert_nil @controller.template.rendered[:template] + assert_template nil process :hello_world - assert @controller.template.rendered[:template] - assert 'hello_world', @controller.template.rendered[:template].to_s + assert_template 'hello_world' end # check the redirection location diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index f047e7da30..49f79681f6 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -56,6 +56,16 @@ protected end end +class AnotherMethodMissingController < ActionController::Base + cattr_accessor :_exception + rescue_from Exception, :with => :_exception= + + protected + def method_missing(*attrs, &block) + super + end +end + class DefaultUrlOptionsController < ActionController::Base def from_view render :inline => "<%= #{params[:route]} %>" @@ -124,11 +134,11 @@ class ControllerInstanceTests < Test::Unit::TestCase def test_action_methods @empty_controllers.each do |c| - assert_equal Set.new, c.class.__send__(:action_methods), "#{c.controller_path} should be empty!" + assert_equal Set.new, c.class.action_methods, "#{c.controller_path} should be empty!" end @non_empty_controllers.each do |c| - assert_equal Set.new(%w(public_action)), c.class.__send__(:action_methods), "#{c.controller_path} should not be empty!" + assert_equal Set.new(%w(public_action)), c.class.action_methods, "#{c.controller_path} should not be empty!" end end @@ -173,6 +183,12 @@ class PerformActionTest < ActionController::TestCase assert_equal 'method_missing', @response.body end + def test_method_missing_should_recieve_symbol + use_controller AnotherMethodMissingController + get :some_action + assert_kind_of NameError, @controller._exception + end + def test_get_on_hidden_should_fail use_controller NonEmptyController assert_raise(ActionController::UnknownAction) { get :hidden_action } @@ -191,7 +207,7 @@ class UrlOptionsTest < ActionController::TestCase def test_url_options_override with_routing do |set| - set.draw do |map| + set.draw do match 'from_view', :to => 'url_options#from_view', :as => :from_view match ':controller/:action' end @@ -202,7 +218,18 @@ class UrlOptionsTest < ActionController::TestCase assert_equal 'http://www.override.com/from_view?locale=en', @controller.send(:from_view_url) assert_equal 'http://www.override.com/default_url_options/new?locale=en', @controller.url_for(:controller => 'default_url_options') end - end + end + + def test_url_helpers_does_not_become_actions + with_routing do |set| + set.draw do + match "account/overview" + end + + @controller.class.send(:include, set.url_helpers) + assert !@controller.class.action_methods.include?("account_overview_path") + end + end end class DefaultUrlOptionsTest < ActionController::TestCase @@ -216,7 +243,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase def test_default_url_options_override with_routing do |set| - set.draw do |map| + set.draw do match 'from_view', :to => 'default_url_options#from_view', :as => :from_view match ':controller/:action' end @@ -231,7 +258,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase def test_default_url_options_are_used_in_non_positional_parameters with_routing do |set| - set.draw do |map| + set.draw do scope("/:locale") do resources :descriptions end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index a792752ef4..f0ad652d50 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -285,6 +285,8 @@ class ActionCacheTest < ActionController::TestCase assert_not_equal cached_time, @response.body end + include RackTestUtils + def test_action_cache_with_layout get :with_layout cached_time = content_to_cache @@ -294,8 +296,8 @@ class ActionCacheTest < ActionController::TestCase get :with_layout assert_not_equal cached_time, @response.body - - assert_equal @response.body, read_fragment('hostname.com/action_caching_test/with_layout') + body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout')) + assert_equal @response.body, body end def test_action_cache_with_layout_and_layout_cache_false @@ -308,7 +310,8 @@ class ActionCacheTest < ActionController::TestCase get :layout_false assert_not_equal cached_time, @response.body - assert_equal cached_time, read_fragment('hostname.com/action_caching_test/layout_false') + body = body_to_string(read_fragment('hostname.com/action_caching_test/layout_false')) + assert_equal cached_time, body end def test_action_cache_conditional_options @@ -616,8 +619,10 @@ class FragmentCachingTest < ActionController::TestCase @store.write('views/expensive', 'fragment content') fragment_computed = false + view_context = @controller.view_context + buffer = 'generated till now -> '.html_safe - @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } + buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true } assert fragment_computed assert_equal 'generated till now -> ', buffer @@ -627,8 +632,10 @@ class FragmentCachingTest < ActionController::TestCase @store.write('views/expensive', 'fragment content') fragment_computed = false + view_context = @controller.view_context + buffer = 'generated till now -> '.html_safe - @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } + buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true } assert !fragment_computed assert_equal 'generated till now -> fragment content', buffer @@ -704,8 +711,8 @@ CACHED def test_fragment_caching_in_partials get :html_fragment_cached_with_partial assert_response :success - assert_match /Fragment caching in a partial/, @response.body - assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial') + assert_match /Old fragment caching in a partial/, @response.body + assert_match "Old fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial') end def test_render_inline_before_fragment_caching @@ -719,14 +726,14 @@ CACHED def test_fragment_caching_in_rjs_partials xhr :get, :js_fragment_cached_with_partial assert_response :success - assert_match /Fragment caching in a partial/, @response.body - assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/js_fragment_cached_with_partial') + assert_match /Old fragment caching in a partial/, @response.body + assert_match "Old fragment caching in a partial", @store.read('views/test.host/functional_caching/js_fragment_cached_with_partial') end def test_html_formatted_fragment_caching get :formatted_fragment_cached, :format => "html" assert_response :success - expected_body = "<body>\n<p>ERB</p>\n</body>" + expected_body = "<body>\n<p>ERB</p>\n</body>\n" assert_equal expected_body, @response.body @@ -742,15 +749,4 @@ CACHED assert_equal " <p>Builder</p>\n", @store.read('views/test.host/functional_caching/formatted_fragment_cached') end - - def test_js_formatted_fragment_caching - get :formatted_fragment_cached, :format => "js" - assert_response :success - expected_body = %(title = "Hey";\n$("element_1").visualEffect("highlight");\n) + - %($("element_2").visualEffect("highlight");\nfooter = "Bye";) - assert_equal expected_body, @response.body - - assert_equal ['$("element_1").visualEffect("highlight");', '$("element_2").visualEffect("highlight");'], - @store.read('views/test.host/functional_caching/formatted_fragment_cached') - end end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 908967a110..36498d13a9 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -64,6 +64,12 @@ class CookieTest < ActionController::TestCase cookies.permanent.signed[:remember_me] = 100 head :ok end + + def delete_and_set_cookie + cookies.delete :user_name + cookies[:user_name] = { :value => "david", :expires => Time.utc(2005, 10, 10,5) } + head :ok + end end tests TestController @@ -152,6 +158,11 @@ class CookieTest < ActionController::TestCase assert_equal 100, @controller.send(:cookies).signed[:remember_me] end + def test_delete_and_set_cookie + get :delete_and_set_cookie + assert_cookie_header "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT" + assert_equal({"user_name" => "david"}, @response.cookies) + end private def assert_cookie_header(expected) diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 004e1369d3..ea740f7233 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -651,9 +651,9 @@ class FilterTest < ActionController::TestCase assert_equal %w( ensure_login find_user ), assigns["ran_filter"] test_process(ConditionalSkippingController, "login") - assert_nil @controller.template.controller.instance_variable_get("@ran_after_filter") + assert_nil @controller.instance_variable_get("@ran_after_filter") test_process(ConditionalSkippingController, "change_password") - assert_equal %w( clean_up ), @controller.template.controller.instance_variable_get("@ran_after_filter") + assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_filter") end def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 2180466ca7..c9782856bd 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -173,14 +173,12 @@ class IntegrationTestTest < Test::Unit::TestCase end def test_opens_new_session - @test.class.expects(:fixture_table_names).times(2).returns(['foo']) - session1 = @test.open_session { |sess| } session2 = @test.open_session # implicit session - assert_kind_of ::ActionController::Integration::Session, session1 - assert_kind_of ::ActionController::Integration::Session, session2 - assert_not_equal session1, session2 + assert session1.respond_to?(:assert_template), "open_session makes assert_template available" + assert session2.respond_to?(:assert_template), "open_session makes assert_template available" + assert !session1.equal?(session2) end # RSpec mixes Matchers (which has a #method_missing) into diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index f635253156..4d687c1ec6 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -120,19 +120,19 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_default_layout @controller = DefaultLayoutController.new get :hello - assert @controller.template.layout.include?('layouts/layout_test') + assert_template :layout => "layouts/layout_test" end def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello - assert @controller.template.layout.include?('layouts/item') + assert_template :layout => "layouts/item" end def test_layout_only_exception_when_included @controller = OnlyLayoutController.new get :hello - assert @controller.template.layout.include?('layouts/item') + assert_template :layout => "layouts/item" end def test_layout_only_exception_when_excepted @@ -144,7 +144,7 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_except_exception_when_included @controller = ExceptLayoutController.new get :hello - assert @controller.template.layout.include?('layouts/item') + assert_template :layout => "layouts/item" end def test_layout_except_exception_when_excepted @@ -156,19 +156,19 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_render @controller = SetsLayoutInRenderController.new get :hello - assert @controller.template.layout.include?('layouts/third_party_template_library') + assert_template :layout => "layouts/third_party_template_library" end def test_layout_is_not_set_when_none_rendered @controller = RendersNoLayoutController.new get :hello - assert_nil @controller.template.layout + assert_template :layout => nil end def test_layout_is_picked_from_the_controller_instances_view_path @controller = PrependsViewPathController.new get :hello - assert @controller.template.layout =~ /layouts\/alt\.\w+/ + assert_template :layout => /layouts\/alt\.\w+/ end def test_absolute_pathed_layout @@ -219,7 +219,7 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/ @controller = LayoutSymlinkedTest.new get :hello assert_response 200 - assert @controller.template.layout.include?("layouts/symlinked/symlinked_layout") + assert_template :layout => "layouts/symlinked/symlinked_layout" end end end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 5c1eaf453c..53cd3f0801 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -765,7 +765,7 @@ class RespondWithControllerTest < ActionController::TestCase Customer.any_instance.stubs(:errors).returns(errors) post :using_resource_with_action - assert_equal "foo - #{[:html].to_s}", @controller.response_body + assert_equal "foo - #{[:html].to_s}", @controller.response.body end def test_respond_as_responder_entry_point diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb new file mode 100644 index 0000000000..df4b39a103 --- /dev/null +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -0,0 +1,27 @@ +require "abstract_unit" + +module BareMetalTest + class BareController < ActionController::Metal + def index + self.response_body = "Hello world" + end + end + + class BareTest < ActiveSupport::TestCase + test "response body is a Rack-compatible response" do + status, headers, body = BareController.action(:index).call(Rack::MockRequest.env_for("/")) + assert_equal 200, status + string = "" + + body.each do |part| + assert part.is_a?(String), "Each part of the body must be a String" + string << part + end + + assert headers.is_a?(Hash), "Headers must be a Hash" + assert headers["Content-Type"], "Content-Type must exist" + + assert_equal "Hello world", string + end + end +end
\ No newline at end of file diff --git a/actionpack/test/controller/new_base/metal_test.rb b/actionpack/test/controller/new_base/metal_test.rb index ab61fd98ee..45a6619eb4 100644 --- a/actionpack/test/controller/new_base/metal_test.rb +++ b/actionpack/test/controller/new_base/metal_test.rb @@ -18,6 +18,8 @@ module MetalTest end class TestMiddleware < ActiveSupport::TestCase + include RackTestUtils + def setup @app = Rack::Builder.new do use MetalTest::MetalMiddleware @@ -29,14 +31,14 @@ module MetalTest env = Rack::MockRequest.env_for("/authed") response = @app.call(env) - assert_equal "Hello World", response[2] + assert_equal "Hello World", body_to_string(response[2]) end test "it can return a response using the normal AC::Metal techniques" do env = Rack::MockRequest.env_for("/") response = @app.call(env) - assert_equal "Not authed!", response[2] + assert_equal "Not authed!", body_to_string(response[2]) assert_equal 401, response[0] end end diff --git a/actionpack/test/controller/new_base/middleware_test.rb b/actionpack/test/controller/new_base/middleware_test.rb index ada0215b1a..65942ebc15 100644 --- a/actionpack/test/controller/new_base/middleware_test.rb +++ b/actionpack/test/controller/new_base/middleware_test.rb @@ -44,7 +44,7 @@ module MiddlewareTest test "middleware that is 'use'd is called as part of the Rack application" do result = @app.call(env_for("/")) - assert_equal "Hello World", result[2] + assert_equal "Hello World", RackTestUtils.body_to_string(result[2]) assert_equal "Success", result[1]["Middleware-Test"] end diff --git a/actionpack/test/controller/new_base/render_action_test.rb b/actionpack/test/controller/new_base/render_action_test.rb index 0804d7b09d..d92e9c4bf2 100644 --- a/actionpack/test/controller/new_base/render_action_test.rb +++ b/actionpack/test/controller/new_base/render_action_test.rb @@ -117,7 +117,7 @@ module RenderActionWithApplicationLayout # # ==== Render actions with layouts ==== class BasicController < ::ApplicationController # Set the view path to an application view structure with layouts - self.view_paths = self.view_paths = [ActionView::FixtureResolver.new( + self.view_paths = [ActionView::FixtureResolver.new( "render_action_with_application_layout/basic/hello_world.html.erb" => "Hello World!", "render_action_with_application_layout/basic/hello.html.builder" => "xml.p 'Hello'", "layouts/application.html.erb" => "Hi <%= yield %> OK, Bye", @@ -202,7 +202,7 @@ end module RenderActionWithControllerLayout class BasicController < ActionController::Base - self.view_paths = self.view_paths = [ActionView::FixtureResolver.new( + self.view_paths = [ActionView::FixtureResolver.new( "render_action_with_controller_layout/basic/hello_world.html.erb" => "Hello World!", "layouts/render_action_with_controller_layout/basic.html.erb" => "With Controller Layout! <%= yield %> Bye" )] diff --git a/actionpack/test/controller/new_base/render_rjs_test.rb b/actionpack/test/controller/new_base/render_rjs_test.rb index f4516ade63..b602b9f8e9 100644 --- a/actionpack/test/controller/new_base/render_rjs_test.rb +++ b/actionpack/test/controller/new_base/render_rjs_test.rb @@ -5,8 +5,10 @@ module RenderRjs self.view_paths = [ActionView::FixtureResolver.new( "render_rjs/basic/index.js.rjs" => "page[:customer].replace_html render(:partial => 'customer')", "render_rjs/basic/index_html.js.rjs" => "page[:customer].replace_html :partial => 'customer'", + "render_rjs/basic/index_no_js.js.erb" => "<%= render(:partial => 'developer') %>", "render_rjs/basic/_customer.js.erb" => "JS Partial", "render_rjs/basic/_customer.html.erb" => "HTML Partial", + "render_rjs/basic/_developer.html.erb" => "HTML Partial", "render_rjs/basic/index_locale.js.rjs" => "page[:customer].replace_html :partial => 'customer'", "render_rjs/basic/_customer.da.html.erb" => "Danish HTML Partial", "render_rjs/basic/_customer.da.js.erb" => "Danish JS Partial" @@ -16,6 +18,12 @@ module RenderRjs render end + def index_respond_to + respond_to do |format| + format.js { render :action => "index_no_js" } + end + end + def index_locale self.locale = :da end @@ -37,6 +45,16 @@ module RenderRjs assert_response("$(\"customer\").update(\"JS Partial\");") end + test "rendering a partial in an RJS template should pick the HTML one if no JS is available" do + get :index_no_js, "format" => "js" + assert_response("HTML Partial") + end + + test "rendering a partial in an RJS template should pick the HTML one if no JS is available on respond_to" do + get :index_respond_to, "format" => "js" + assert_response("HTML 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, "format" => "js" assert_response("$(\"customer\").update(\"HTML Partial\");") diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 20fcb87da6..2f3997518f 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -18,6 +18,13 @@ class TestController < ActionController::Base layout :determine_layout + def name + nil + end + + private :name + helper_method :name + def hello_world end @@ -418,7 +425,6 @@ class TestController < ActionController::Base def rendering_with_conflicting_local_vars @name = "David" - def @template.name() nil end render :action => "potential_conflicts" end @@ -507,10 +513,6 @@ class TestController < ActionController::Base end end - def partial_only_with_layout - render :partial => "partial_only", :layout => true - end - def render_to_string_with_partial @partial_only = render_to_string :partial => "partial_only" @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } @@ -526,11 +528,11 @@ class TestController < ActionController::Base end def partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, @template, {}, Proc.new {}) + render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}, Proc.new {}) end def partial_with_form_builder_subclass - render :partial => LabellingFormBuilder.new(:post, nil, @template, {}, Proc.new {}) + render :partial => LabellingFormBuilder.new(:post, nil, view_context, {}, Proc.new {}) end def partial_collection @@ -634,8 +636,7 @@ class TestController < ActionController::Base "rendering_nothing_on_layout", "render_text_hello_world", "render_text_hello_world_with_layout", "hello_world_with_layout_false", - "partial_only", "partial_only_with_layout", - "accessing_params_in_template", + "partial_only", "accessing_params_in_template", "accessing_params_in_template_with_layout", "render_with_explicit_template", "render_with_explicit_string_template", @@ -1198,11 +1199,6 @@ class RenderTest < ActionController::TestCase assert_equal 'partial html', @response.body end - def test_partial_only_with_layout - get :partial_only_with_layout - assert_equal "<html>only partial</html>", @response.body - end - def test_render_to_string_partial get :render_to_string_with_partial assert_equal "only partial", assigns(:partial_only) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index f5fcf9b0df..c4e71a8689 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -18,14 +18,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest default_url_options :host => "rubyonrails.org" controller :sessions do - get 'login' => :new, :as => :login + get 'login' => :new post 'login' => :create - - delete 'logout' => :destroy, :as => :logout + delete 'logout' => :destroy end resource :session do get :create + post :reset resource :info end @@ -34,6 +34,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match 'account/login', :to => redirect("/login") match 'account/overview' + match '/account/nested/overview' + match 'sign_in' => "sessions#new" match 'account/modulo/:name', :to => redirect("/%{name}s") match 'account/proc/:name', :to => redirect {|params| "/#{params[:name].pluralize}" } @@ -120,7 +122,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest # misc match 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article + # default params + match 'inline_pages/(:id)', :to => 'pages#show', :id => 'home' + match 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' } + defaults :id => 'home' do + match 'scoped_pages/(:id)', :to => 'pages#show' + end + namespace :account do + match 'shorthand' match 'description', :to => "account#description", :as => "description" resource :subscription, :credit, :credit_card @@ -193,6 +203,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true) assert_equal 'http://rubyonrails.org/login', Routes.url_for(:controller => 'sessions', :action => 'create') + assert_equal 'http://rubyonrails.org/login', Routes.url_helpers.login_url end end @@ -237,6 +248,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/session/edit' assert_equal 'sessions#edit', @response.body assert_equal '/session/edit', edit_session_path + + post '/session/reset' + assert_equal 'sessions#reset', @response.body + assert_equal '/session/reset', reset_session_path end end @@ -654,6 +669,30 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_convention_match_inside_namespace + with_test_routes do + assert_equal '/account/shorthand', account_shorthand_path + get '/account/shorthand' + assert_equal 'account#shorthand', @response.body + end + end + + def test_convention_match_nested_and_with_leading_slash + with_test_routes do + assert_equal '/account/nested/overview', account_nested_overview_path + get '/account/nested/overview' + assert_equal 'account/nested#overview', @response.body + end + end + + def test_convention_with_explicit_end + with_test_routes do + get '/sign_in' + assert_equal 'sessions#new', @response.body + assert_equal '/sign_in', sign_in_path + end + end + def test_redirect_with_complete_url with_test_routes do get '/account/google' @@ -742,6 +781,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_default_params + with_test_routes do + get '/inline_pages' + assert_equal 'home', @request.params[:id] + + get '/default_pages' + assert_equal 'home', @request.params[:id] + + get '/scoped_pages' + assert_equal 'home', @request.params[:id] + end + end + private def with_test_routes yield diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 18b5b7ee00..326b336a1a 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -34,5 +34,10 @@ module TestUrlGeneration get "/foo", {}, 'SCRIPT_NAME' => "/new" assert_equal "/new/foo", response.body end + + test "handling http protocol with https set" do + https! + assert_equal "http://www.example.com/foo", foo_url(:protocol => "http") + end end -end
\ No newline at end of file +end diff --git a/actionpack/test/fixtures/functional_caching/_partial.erb b/actionpack/test/fixtures/functional_caching/_partial.erb index d0e4f72b95..ec0da7cf50 100644 --- a/actionpack/test/fixtures/functional_caching/_partial.erb +++ b/actionpack/test/fixtures/functional_caching/_partial.erb @@ -1,3 +1,3 @@ <% cache do %> -Fragment caching in a partial -<% end %>
\ No newline at end of file +Old fragment caching in a partial +<% end %> diff --git a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb index d7f43ad95e..9b88fa1f5a 100644 --- a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +++ b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb @@ -1,3 +1,3 @@ <body> -<% cache do %><p>ERB</p><% end %> -</body>
\ No newline at end of file +<%= cache do %><p>ERB</p><% end %> +</body> diff --git a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb index 268a298a42..c479adb897 100644 --- a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb +++ b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb @@ -1,2 +1,2 @@ Hello -<% cache do %>This bit's fragment cached<% end %> +<%= cache do %>This bit's fragment cached<% end %> diff --git a/actionpack/test/fixtures/functional_caching/inline_fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/inline_fragment_cached.html.erb index 87309b8ccb..41647f1404 100644 --- a/actionpack/test/fixtures/functional_caching/inline_fragment_cached.html.erb +++ b/actionpack/test/fixtures/functional_caching/inline_fragment_cached.html.erb @@ -1,2 +1,2 @@ <%= render :inline => 'Some inline content' %> -<% cache do %>Some cached content<% end %> +<%= cache do %>Some cached content<% end %> diff --git a/actionpack/test/fixtures/layouts/block_with_layout.erb b/actionpack/test/fixtures/layouts/block_with_layout.erb index f25b41271d..73ac833e52 100644 --- a/actionpack/test/fixtures/layouts/block_with_layout.erb +++ b/actionpack/test/fixtures/layouts/block_with_layout.erb @@ -1,3 +1,3 @@ -<% render(:layout => "layout_for_partial", :locals => { :name => "Anthony" }) do %>Inside from first block in layout<% "Return value should be discarded" %><% end %> +<%= render(:layout => "layout_for_partial", :locals => { :name => "Anthony" }) do %>Inside from first block in layout<% "Return value should be discarded" %><% end %> <%= yield %> -<% render(:layout => "layout_for_partial", :locals => { :name => "Ramm" }) do %>Inside from second block in layout<% end %> +<%= render(:layout => "layout_for_partial", :locals => { :name => "Ramm" }) do %>Inside from second block in layout<% end %> diff --git a/actionpack/test/fixtures/test/array_translation.erb b/actionpack/test/fixtures/test/array_translation.erb new file mode 100644 index 0000000000..12c0763313 --- /dev/null +++ b/actionpack/test/fixtures/test/array_translation.erb @@ -0,0 +1 @@ +<%= t(['foo', 'bar']) %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/deprecated_nested_layout.erb b/actionpack/test/fixtures/test/deprecated_nested_layout.erb new file mode 100644 index 0000000000..7b6dcbb6c7 --- /dev/null +++ b/actionpack/test/fixtures/test/deprecated_nested_layout.erb @@ -0,0 +1,3 @@ +<% content_for :title, "title" -%> +<% content_for :column do -%>column<% end -%> +<% render :layout => 'layouts/column' do -%>content<% end -%>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/nested_layout.erb b/actionpack/test/fixtures/test/nested_layout.erb index 7b6dcbb6c7..6078f74b4c 100644 --- a/actionpack/test/fixtures/test/nested_layout.erb +++ b/actionpack/test/fixtures/test/nested_layout.erb @@ -1,3 +1,3 @@ <% content_for :title, "title" -%> <% content_for :column do -%>column<% end -%> -<% render :layout => 'layouts/column' do -%>content<% end -%>
\ No newline at end of file +<%= render :layout => 'layouts/column' do -%>content<% end -%>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/scoped_array_translation.erb b/actionpack/test/fixtures/test/scoped_array_translation.erb new file mode 100644 index 0000000000..0a0c79f717 --- /dev/null +++ b/actionpack/test/fixtures/test/scoped_array_translation.erb @@ -0,0 +1 @@ +<%= t(['.foo', '.bar']) %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/using_layout_around_block.html.erb b/actionpack/test/fixtures/test/using_layout_around_block.html.erb index a93fa02c9c..3d6661df9a 100644 --- a/actionpack/test/fixtures/test/using_layout_around_block.html.erb +++ b/actionpack/test/fixtures/test/using_layout_around_block.html.erb @@ -1 +1 @@ -<% render(:layout => "layout_for_partial", :locals => { :name => "David" }) do %>Inside from block<% end %>
\ No newline at end of file +<%= render(:layout => "layout_for_partial", :locals => { :name => "David" }) do %>Inside from block<% end %>
\ No newline at end of file diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb index 02248d84ad..b49ccd39ca 100644 --- a/actionpack/test/lib/fixture_template.rb +++ b/actionpack/test/lib/fixture_template.rb @@ -9,17 +9,17 @@ module ActionView #:nodoc: private - def query(partial, path, exts) + def query(path, exts, formats) query = Regexp.escape(path) exts.each do |ext| - query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << ')' + query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)' end templates = [] @hash.select { |k,v| k =~ /^#{query}$/ }.each do |path, source| - handler, format = extract_handler_and_format(path) + handler, format = extract_handler_and_format(path, formats) templates << Template.new(source, path, handler, - :partial => partial, :virtual_path => path, :format => format) + :virtual_path => path, :format => format) end templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size } diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb index 371aa53c68..7a665b00bc 100644 --- a/actionpack/test/template/active_model_helper_test.rb +++ b/actionpack/test/template/active_model_helper_test.rb @@ -147,6 +147,20 @@ class ActiveModelHelperTest < ActionView::TestCase ) end + def test_field_error_proc + old_proc = ActionView::Base.field_error_proc + ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| + %(<div class=\"fieldWithErrors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe + end + + assert_dom_equal( + %(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>), + text_field("post", "author_name") + ) + ensure + ActionView::Base.field_error_proc = old_proc if old_proc + end + def test_form_with_string assert_dom_equal( %(<form action="create" method="post"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>), @@ -252,6 +266,10 @@ class ActiveModelHelperTest < ActionView::TestCase assert_dom_equal "<div class=\"differentError\">beforecan't be emptyafter</div>", error_message_on(:post, :author_name, :css_class => 'differentError', :prepend_text => 'before', :append_text => 'after') end + def test_error_message_on_handles_empty_errors + assert_equal "", error_message_on(@post, :tag) + end + def test_error_messages_for_many_objects assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li><li>User email can't be empty</li></ul></div>), error_messages_for("post", "user") diff --git a/actionpack/test/template/body_parts_test.rb b/actionpack/test/template/body_parts_test.rb index defe85107e..69cf684083 100644 --- a/actionpack/test/template/body_parts_test.rb +++ b/actionpack/test/template/body_parts_test.rb @@ -8,9 +8,8 @@ class BodyPartsTest < ActionController::TestCase def index RENDERINGS.each do |rendering| - @template.punctuate_body! rendering + view_context.punctuate_body! rendering end - @performed_render = true end end diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index f887c9ab5b..bf541c17d3 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -3,9 +3,33 @@ require 'abstract_unit' class CaptureHelperTest < ActionView::TestCase def setup super + @av = ActionView::Base.new @_content_for = Hash.new {|h,k| h[k] = "" } end + def test_capture_captures_the_temporary_output_buffer_in_its_block + assert_nil @av.output_buffer + string = @av.capture do + @av.output_buffer << 'foo' + @av.output_buffer << 'bar' + end + assert_nil @av.output_buffer + assert_equal 'foobar', string + assert_kind_of ActionView::NonConcattingString, string + end + + def test_capture_captures_the_value_returned_by_the_block_if_the_temporary_buffer_is_blank + string = @av.capture('foo', 'bar') do |a, b| + a + b + end + assert_equal 'foobar', string + assert_kind_of ActionView::NonConcattingString, string + end + + def test_capture_returns_nil_if_the_returned_value_is_not_a_string + assert_nil @av.capture { 1 } + end + def test_content_for assert ! content_for?(:title) content_for :title, 'title' @@ -13,9 +37,85 @@ class CaptureHelperTest < ActionView::TestCase assert ! content_for?(:something_else) end + def test_with_output_buffer_swaps_the_output_buffer_given_no_argument + assert_nil @av.output_buffer + buffer = @av.with_output_buffer do + @av.output_buffer << '.' + end + assert_equal '.', buffer + assert_nil @av.output_buffer + end + + def test_with_output_buffer_swaps_the_output_buffer_with_an_argument + assert_nil @av.output_buffer + buffer = ActionView::OutputBuffer.new('.') + @av.with_output_buffer(buffer) do + @av.output_buffer << '.' + end + assert_equal '..', buffer + assert_nil @av.output_buffer + end + + def test_with_output_buffer_restores_the_output_buffer + buffer = ActionView::OutputBuffer.new + @av.output_buffer = buffer + @av.with_output_buffer do + @av.output_buffer << '.' + end + assert buffer.equal?(@av.output_buffer) + end + + unless RUBY_VERSION < '1.9' + def test_with_output_buffer_sets_proper_encoding + @av.output_buffer = ActionView::OutputBuffer.new + + # Ensure we set the output buffer to an encoding different than the default one. + alt_encoding = alt_encoding(@av.output_buffer) + @av.output_buffer.force_encoding(alt_encoding) + + @av.with_output_buffer do + assert alt_encoding, @av.output_buffer.encoding + end + end + end + def test_with_output_buffer_does_not_assume_there_is_an_output_buffer - av = ActionView::Base.new - assert_nil av.output_buffer - assert_equal "", av.with_output_buffer {} + assert_nil @av.output_buffer + assert_equal "", @av.with_output_buffer {} + end + + def test_flush_output_buffer_concats_output_buffer_to_response + view = view_with_controller + assert_equal [], view.response.body_parts + + view.output_buffer << 'OMG' + view.flush_output_buffer + assert_equal ['OMG'], view.response.body_parts + assert_equal '', view.output_buffer + + view.output_buffer << 'foobar' + view.flush_output_buffer + assert_equal ['OMG', 'foobar'], view.response.body_parts + assert_equal '', view.output_buffer + end + + unless RUBY_VERSION < '1.9' + def test_flush_output_buffer_preserves_the_encoding_of_the_output_buffer + view = view_with_controller + alt_encoding = alt_encoding(view.output_buffer) + view.output_buffer.force_encoding(alt_encoding) + flush_output_buffer + assert_equal alt_encoding, view.output_buffer.encoding + end + end + + def alt_encoding(output_buffer) + output_buffer.encoding == Encoding::US_ASCII ? Encoding::UTF_8 : Encoding::US_ASCII + end + + def view_with_controller + returning(TestController.new.view_context) do |view| + view.output_buffer = ActionView::OutputBuffer.new + end end end diff --git a/actionpack/test/template/erb/form_for_test.rb b/actionpack/test/template/erb/form_for_test.rb new file mode 100644 index 0000000000..482dbb0287 --- /dev/null +++ b/actionpack/test/template/erb/form_for_test.rb @@ -0,0 +1,11 @@ +require "abstract_unit" +require "template/erb/helper" + +module ERBTest + class TagHelperTest < BlockTestCase + test "form_for works" do + output = render_content "form_for(:staticpage, :url => {:controller => 'blah', :action => 'update'})", "" + assert_equal "<form action=\"/blah/update\" method=\"post\"></form>", output + end + end +end
\ No newline at end of file diff --git a/actionpack/test/template/erb/helper.rb b/actionpack/test/template/erb/helper.rb new file mode 100644 index 0000000000..7147178849 --- /dev/null +++ b/actionpack/test/template/erb/helper.rb @@ -0,0 +1,30 @@ +module ERBTest + class ViewContext + mock_controller = Class.new do + include SharedTestRoutes.url_helpers + end + + include ActionView::Helpers::TagHelper + include ActionView::Helpers::JavaScriptHelper + include ActionView::Helpers::FormHelper + + attr_accessor :output_buffer + + def protect_against_forgery?() false end + + define_method(:controller) do + mock_controller.new + end + end + + class BlockTestCase < ActiveSupport::TestCase + def render_content(start, inside) + template = block_helper(start, inside) + ActionView::Template::Handlers::Erubis.new(template).evaluate(ViewContext.new) + end + + def block_helper(str, rest) + "<%= #{str} do %>#{rest}<% end %>" + end + end +end
\ No newline at end of file diff --git a/actionpack/test/template/erb/tag_helper_test.rb b/actionpack/test/template/erb/tag_helper_test.rb index cc96a43901..64a88bde1d 100644 --- a/actionpack/test/template/erb/tag_helper_test.rb +++ b/actionpack/test/template/erb/tag_helper_test.rb @@ -1,66 +1,44 @@ require "abstract_unit" +require "template/erb/helper" module ERBTest - class ViewContext - mock_controller = Class.new do - include SharedTestRoutes.url_helpers - end - - include ActionView::Helpers::TagHelper - include ActionView::Helpers::JavaScriptHelper - include ActionView::Helpers::FormHelper - - attr_accessor :output_buffer - - def protect_against_forgery?() false end - - define_method(:controller) do - mock_controller.new - end - end - - class DeprecatedViewContext < ViewContext - include ActionView::Helpers::DeprecatedBlockHelpers - end - module SharedTagHelpers extend ActiveSupport::Testing::Declarative - def render_content(start, inside) - template = block_helper(start, inside) - ActionView::Template::Handlers::Erubis.new(template).evaluate(context.new) + def maybe_deprecated + if @deprecated + assert_deprecated { yield } + else + yield + end end test "percent equals works for content_tag and does not require parenthesis on method call" do - assert_equal "<div>Hello world</div>", render_content("content_tag :div", "Hello world") + maybe_deprecated { assert_equal "<div>Hello world</div>", render_content("content_tag :div", "Hello world") } end test "percent equals works for javascript_tag" do expected_output = "<script type=\"text/javascript\">\n//<![CDATA[\nalert('Hello')\n//]]>\n</script>" - assert_equal expected_output, render_content("javascript_tag", "alert('Hello')") + maybe_deprecated { assert_equal expected_output, render_content("javascript_tag", "alert('Hello')") } end test "percent equals works for javascript_tag with options" do expected_output = "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('Hello')\n//]]>\n</script>" - assert_equal expected_output, render_content("javascript_tag(:id => 'the_js_tag')", "alert('Hello')") + maybe_deprecated { assert_equal expected_output, render_content("javascript_tag(:id => 'the_js_tag')", "alert('Hello')") } end test "percent equals works with form tags" do expected_output = "<form action=\"foo\" method=\"post\">hello</form>" - assert_equal expected_output, render_content("form_tag('foo')", "<%= 'hello' %>") + maybe_deprecated { assert_equal expected_output, render_content("form_tag('foo')", "<%= 'hello' %>") } end test "percent equals works with fieldset tags" do expected_output = "<fieldset><legend>foo</legend>hello</fieldset>" - assert_equal expected_output, render_content("field_set_tag('foo')", "<%= 'hello' %>") + maybe_deprecated { assert_equal expected_output, render_content("field_set_tag('foo')", "<%= 'hello' %>") } end end - class TagHelperTest < ActiveSupport::TestCase - def context - ViewContext - end - + class TagHelperTest < BlockTestCase def block_helper(str, rest) "<%= #{str} do %>#{rest}<% end %>" end @@ -68,15 +46,15 @@ module ERBTest include SharedTagHelpers end - class DeprecatedTagHelperTest < ActiveSupport::TestCase - def context - DeprecatedViewContext - end - + class DeprecatedTagHelperTest < BlockTestCase def block_helper(str, rest) "<% __in_erb_template=true %><% #{str} do %>#{rest}<% end %>" end + def setup + @deprecated = true + end + include SharedTagHelpers end end
\ No newline at end of file diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index f49b763881..c5c2a6b952 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -17,7 +17,7 @@ class JavaScriptHelperTest < ActionView::TestCase ActiveSupport.escape_html_entities_in_json = true @template = self end - + def teardown ActiveSupport.escape_html_entities_in_json = false end @@ -60,6 +60,35 @@ class JavaScriptHelperTest < ActionView::TestCase button_to_function("Greeting") end + def test_link_to_function + assert_dom_equal %(<a href="#" onclick="alert('Hello world!'); return false;">Greeting</a>), + link_to_function("Greeting", "alert('Hello world!')") + end + + def test_link_to_function_with_existing_onclick + assert_dom_equal %(<a href="#" onclick="confirm('Sanity!'); alert('Hello world!'); return false;">Greeting</a>), + link_to_function("Greeting", "alert('Hello world!')", :onclick => "confirm('Sanity!')") + end + + def test_link_to_function_with_rjs_block + html = link_to_function( "Greet me!" ) do |page| + page.replace_html 'header', "<h1>Greetings</h1>" + end + assert_dom_equal %(<a href="#" onclick="Element.update("header", "\\u003Ch1\\u003EGreetings\\u003C/h1\\u003E");; return false;">Greet me!</a>), html + end + + def test_link_to_function_with_rjs_block_and_options + html = link_to_function( "Greet me!", :class => "updater" ) do |page| + page.replace_html 'header', "<h1>Greetings</h1>" + end + assert_dom_equal %(<a href="#" class="updater" onclick="Element.update("header", "\\u003Ch1\\u003EGreetings\\u003C/h1\\u003E");; return false;">Greet me!</a>), html + end + + def test_link_to_function_with_href + assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>), + link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/') + end + def test_javascript_tag self.output_buffer = 'foo' diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index 697ebc694a..df1aa2edb2 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -22,34 +22,35 @@ class LookupContextTest < ActiveSupport::TestCase end test "normalizes details on initialization" do - formats = Mime::SET + [nil] - locale = [I18n.locale, nil] - assert_equal Hash[:formats => formats, :locale => locale], @lookup_context.details - end - - test "allows me to set details" do - @lookup_context.details = { :formats => [:html], :locale => :pt } - assert_equal Hash[:formats => [:html, nil], :locale => [:pt, nil]], @lookup_context.details + assert_equal Mime::SET, @lookup_context.formats + assert_equal :en, @lookup_context.locale end - test "does not allow details to be modified in place" do - assert @lookup_context.details.frozen? + test "allows me to update details" do + @lookup_context.update_details(:formats => [:html], :locale => :pt) + assert_equal [:html], @lookup_context.formats + assert_equal :pt, @lookup_context.locale end test "allows me to update an specific detail" do @lookup_context.update_details(:locale => :pt) assert_equal :pt, I18n.locale - formats = Mime::SET + [nil] - locale = [I18n.locale, nil] - assert_equal Hash[:formats => formats, :locale => locale], @lookup_context.details + assert_equal :pt, @lookup_context.locale + end + + test "allows me to freeze and retrieve frozen formats" do + @lookup_context.formats.freeze + assert @lookup_context.formats.frozen? end test "allows me to change some details to execute an specific block of code" do - formats = Mime::SET + [nil] + formats = Mime::SET @lookup_context.update_details(:locale => :pt) do - assert_equal Hash[:formats => formats, :locale => [:pt, nil]], @lookup_context.details + assert_equal formats, @lookup_context.formats + assert_equal :pt, @lookup_context.locale end - assert_equal Hash[:formats => formats, :locale => [:en, nil]], @lookup_context.details + assert_equal formats, @lookup_context.formats + assert_equal :en, @lookup_context.locale end test "provides getters and setters for formats" do @@ -62,6 +63,11 @@ class LookupContextTest < ActiveSupport::TestCase assert_equal Mime::SET, @lookup_context.formats end + test "adds :html fallback to :js formats" do + @lookup_context.formats = [:js] + assert_equal [:js, :html], @lookup_context.formats + end + test "provides getters and setters for locale" do @lookup_context.locale = :pt assert_equal :pt, @lookup_context.locale @@ -94,6 +100,13 @@ class LookupContextTest < ActiveSupport::TestCase assert_equal "Hey verden", template.source end + test "found templates respects given formats if one cannot be found from template or handler" do + ActionView::Template::Handlers::ERB.expects(:default_format).returns(nil) + @lookup_context.formats = [:text] + template = @lookup_context.find("hello_world", "test") + assert_equal [:text], template.formats + end + test "adds fallbacks to view paths when required" do assert_equal 1, @lookup_context.view_paths.size diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb index bf5b81292f..f730a0d7f5 100644 --- a/actionpack/test/template/number_helper_i18n_test.rb +++ b/actionpack/test/template/number_helper_i18n_test.rb @@ -1,69 +1,95 @@ require 'abstract_unit' -class NumberHelperI18nTests < Test::Unit::TestCase - include ActionView::Helpers::NumberHelper - - attr_reader :request +class NumberHelperTest < ActionView::TestCase + tests ActionView::Helpers::NumberHelper def setup - @number_defaults = { :precision => 3, :delimiter => ',', :separator => '.' } - @currency_defaults = { :unit => '$', :format => '%u%n', :precision => 2 } - @human_defaults = { :precision => 1 } - @human_storage_units_format_default = "%n %u" - @human_storage_units_units_byte_other = "Bytes" - @human_storage_units_units_kb_other = "KB" - @percentage_defaults = { :delimiter => '' } - @precision_defaults = { :delimiter => '' } + I18n.backend.store_translations 'ts', + :number => { + :format => { :precision => 3, :delimiter => ',', :separator => '.', :significant => false, :strip_insignificant_zeros => false }, + :currency => { :format => { :unit => '&$', :format => '%u - %n', :precision => 2 } }, + :human => { + :format => { + :precision => 2, + :significant => true, + :strip_insignificant_zeros => true + }, + :storage_units => { + :format => "%n %u", + :units => { + :byte => "b", + :kb => "k" + } + }, + :decimal_units => { + :format => "%n %u", + :units => { + :deci => {:one => "Tenth", :other => "Tenths"}, + :unit => "u", + :ten => {:one => "Ten", :other => "Tens"}, + :thousand => "t", + :million => "m" , + :billion =>"b" , + :trillion =>"t" , + :quadrillion =>"q" + } + } + }, + :percentage => { :format => {:delimiter => '', :precision => 2, :strip_insignificant_zeros => true} }, + :precision => { :format => {:delimiter => '', :significant => true} } + }, + :custom_units_for_number_to_human => {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} + end - I18n.backend.store_translations 'en', :number => { :format => @number_defaults, - :currency => { :format => @currency_defaults }, :human => @human_defaults } + def test_number_to_currency + assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) end - def test_number_to_currency_translates_currency_formats - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - I18n.expects(:translate).with(:'number.currency.format', :locale => 'en', - :raise => true).returns(@currency_defaults) - number_to_currency(1, :locale => 'en') + def test_number_with_precision + #Delimiter was set to "" + assert_equal("10000", number_with_precision(10000, :locale => 'ts')) + + #Precision inherited and significant was set + assert_equal("1.00", number_with_precision(1.0, :locale => 'ts')) + end - def test_number_with_precision_translates_number_formats - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - I18n.expects(:translate).with(:'number.precision.format', :locale => 'en', - :raise => true).returns(@precision_defaults) - number_with_precision(1, :locale => 'en') + def test_number_with_delimiter + #Delimiter "," and separator "." + assert_equal("1,000,000.234", number_with_delimiter(1000000.234, :locale => 'ts')) end - def test_number_with_delimiter_translates_number_formats - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - number_with_delimiter(1, :locale => 'en') + def test_number_to_percentage + # to see if strip_insignificant_zeros is true + assert_equal("1%", number_to_percentage(1, :locale => 'ts')) + # precision is 2, significant should be inherited + assert_equal("1.24%", number_to_percentage(1.2434, :locale => 'ts')) + # no delimiter + assert_equal("12434%", number_to_percentage(12434, :locale => 'ts')) end - def test_number_to_percentage_translates_number_formats - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - I18n.expects(:translate).with(:'number.percentage.format', :locale => 'en', - :raise => true).returns(@percentage_defaults) - number_to_percentage(1, :locale => 'en') + def test_number_to_human_size + #b for bytes and k for kbytes + assert_equal("2 k", number_to_human_size(2048, :locale => 'ts')) + assert_equal("42 b", number_to_human_size(42, :locale => 'ts')) end - def test_number_to_human_size_translates_human_formats - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - I18n.expects(:translate).with(:'number.human.format', :locale => 'en', - :raise => true).returns(@human_defaults) - I18n.expects(:translate).with(:'number.human.storage_units.format', :locale => 'en', - :raise => true).returns(@human_storage_units_format_default) - I18n.expects(:translate).with(:'number.human.storage_units.units.kb', :locale => 'en', :count => 2, - :raise => true).returns(@human_storage_units_units_kb_other) - # 2KB - number_to_human_size(2048, :locale => 'en') + def test_number_to_human_with_default_translation_scope + #Using t for thousand + assert_equal "2 t", number_to_human(2000, :locale => 'ts') + #Significant was set to true with precision 2, using b for billion + assert_equal "1.2 b", number_to_human(1234567890, :locale => 'ts') + #Using pluralization (Ten/Tens and Tenth/Tenths) + assert_equal "1 Tenth", number_to_human(0.1, :locale => 'ts') + assert_equal "1.3 Tenth", number_to_human(0.134, :locale => 'ts') + assert_equal "2 Tenths", number_to_human(0.2, :locale => 'ts') + assert_equal "1 Ten", number_to_human(10, :locale => 'ts') + assert_equal "1.2 Ten", number_to_human(12, :locale => 'ts') + assert_equal "2 Tens", number_to_human(20, :locale => 'ts') + end - I18n.expects(:translate).with(:'number.format', :locale => 'en', :raise => true).returns(@number_defaults) - I18n.expects(:translate).with(:'number.human.format', :locale => 'en', - :raise => true).returns(@human_defaults) - I18n.expects(:translate).with(:'number.human.storage_units.format', :locale => 'en', - :raise => true).returns(@human_storage_units_format_default) - I18n.expects(:translate).with(:'number.human.storage_units.units.byte', :locale => 'en', :count => 42, - :raise => true).returns(@human_storage_units_units_byte_other) - # 42 Bytes - number_to_human_size(42, :locale => 'en') + def test_number_to_human_with_custom_translation_scope + #Significant was set to true with precision 2, with custom translated units + assert_equal "4.3 cm", number_to_human(0.0432, :locale => 'ts', :units => :custom_units_for_number_to_human) end end diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index 0a2b82bd89..50c57a5588 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -19,6 +19,15 @@ class NumberHelperTest < ActionView::TestCase gigabytes(number) * 1024 end + def silence_deprecation_warnings + @old_deprecatios_silenced = ActiveSupport::Deprecation.silenced + ActiveSupport::Deprecation.silenced = true + end + + def restore_deprecation_warnings + ActiveSupport::Deprecation.silenced = @old_deprecatios_silenced + end + def test_number_to_phone assert_equal("555-1234", number_to_phone(5551234)) assert_equal("800-555-1212", number_to_phone(8005551212)) @@ -31,8 +40,6 @@ class NumberHelperTest < ActionView::TestCase assert_equal("+18005551212", number_to_phone(8005551212, :country_code => 1, :delimiter => '')) assert_equal("22-555-1212", number_to_phone(225551212)) assert_equal("+45-22-555-1212", number_to_phone(225551212, :country_code => 45)) - assert_equal("x", number_to_phone("x")) - assert_nil number_to_phone(nil) end def test_number_to_currency @@ -43,9 +50,6 @@ class NumberHelperTest < ActionView::TestCase assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50")) assert_equal("1,234,567,890.50 Kč", number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"})) - #assert_equal("$x.", number_to_currency("x")) # fails due to API consolidation - assert_equal("$x", number_to_currency("x")) - assert_nil number_to_currency(nil) end def test_number_to_percentage @@ -54,9 +58,8 @@ class NumberHelperTest < ActionView::TestCase assert_equal("302.06%", number_to_percentage(302.0574, {:precision => 2})) assert_equal("100.000%", number_to_percentage("100")) assert_equal("1000.000%", number_to_percentage("1000")) - assert_equal("x%", number_to_percentage("x")) + assert_equal("123.4%", number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) assert_equal("1.000,000%", number_to_percentage(1000, :delimiter => '.', :separator => ',')) - assert_nil number_to_percentage(nil) end def test_number_with_delimiter @@ -70,8 +73,6 @@ class NumberHelperTest < ActionView::TestCase assert_equal("123,456,789.78901", number_with_delimiter(123456789.78901)) assert_equal("0.78901", number_with_delimiter(0.78901)) assert_equal("123,456.78", number_with_delimiter("123456.78")) - assert_equal("x", number_with_delimiter("x")) - assert_nil number_with_delimiter(nil) end def test_number_with_delimiter_with_options_hash @@ -81,6 +82,16 @@ class NumberHelperTest < ActionView::TestCase assert_equal '12.345.678,05', number_with_delimiter(12345678.05, :delimiter => '.', :separator => ',') end + def test_number_with_delimiter_old_api + silence_deprecation_warnings + assert_equal '12 345 678', number_with_delimiter(12345678, " ") + assert_equal '12-345-678.05', number_with_delimiter(12345678.05, '-') + assert_equal '12.345.678,05', number_with_delimiter(12345678.05, '.', ',') + assert_equal '12,345,678.05', number_with_delimiter(12345678.05, ',', '.') + assert_equal '12 345 678-05', number_with_delimiter(12345678.05, ',', '.', :delimiter => ' ', :separator => '-') + restore_deprecation_warnings + end + def test_number_with_precision assert_equal("111.235", number_with_precision(111.2346)) assert_equal("31.83", number_with_precision(31.825, :precision => 2)) @@ -91,10 +102,6 @@ class NumberHelperTest < ActionView::TestCase assert_equal("3268", number_with_precision((32.6751 * 100.00), :precision => 0)) assert_equal("112", number_with_precision(111.50, :precision => 0)) assert_equal("1234567892", number_with_precision(1234567891.50, :precision => 0)) - - # Return non-numeric params unchanged. - assert_equal("x", number_with_precision("x")) - assert_nil number_with_precision(nil) end def test_number_with_precision_with_custom_delimiter_and_separator @@ -102,48 +109,272 @@ class NumberHelperTest < ActionView::TestCase assert_equal '1.231,83', number_with_precision(1231.825, :precision => 2, :separator => ',', :delimiter => '.') end + def test_number_with_precision_with_significant_digits + assert_equal "124000", number_with_precision(123987, :precision => 3, :significant => true) + assert_equal "120000000", number_with_precision(123987876, :precision => 2, :significant => true ) + assert_equal "40000", number_with_precision("43523", :precision => 1, :significant => true ) + assert_equal "9775", number_with_precision(9775, :precision => 4, :significant => true ) + assert_equal "5.4", number_with_precision(5.3923, :precision => 2, :significant => true ) + assert_equal "5", number_with_precision(5.3923, :precision => 1, :significant => true ) + assert_equal "1", number_with_precision(1.232, :precision => 1, :significant => true ) + assert_equal "7", number_with_precision(7, :precision => 1, :significant => true ) + assert_equal "1", number_with_precision(1, :precision => 1, :significant => true ) + assert_equal "53", number_with_precision(52.7923, :precision => 2, :significant => true ) + assert_equal "9775.00", number_with_precision(9775, :precision => 6, :significant => true ) + assert_equal "5.392900", number_with_precision(5.3929, :precision => 7, :significant => true ) + end + + def test_number_with_precision_with_strip_insignificant_zeros + assert_equal "9775.43", number_with_precision(9775.43, :precision => 4, :strip_insignificant_zeros => true ) + assert_equal "9775.2", number_with_precision(9775.2, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) + end + + def test_number_with_precision_with_significant_true_and_zero_precision + # Zero precision with significant is a mistake (would always return zero), + # so we treat it as if significant was false (increases backwards compatibily for number_to_human_size) + assert_equal "124", number_with_precision(123.987, :precision => 0, :significant => true) + assert_equal "12", number_with_precision(12, :precision => 0, :significant => true ) + assert_equal "12", number_with_precision("12.3", :precision => 0, :significant => true ) + end + + def test_number_with_precision_old_api + silence_deprecation_warnings + assert_equal("31.8250", number_with_precision(31.825, 4)) + assert_equal("111.235", number_with_precision(111.2346, 3)) + assert_equal("111.00", number_with_precision(111, 2)) + assert_equal("111.000", number_with_precision(111, 2, :precision =>3)) + restore_deprecation_warnings + end + def test_number_to_human_size assert_equal '0 Bytes', number_to_human_size(0) assert_equal '1 Byte', number_to_human_size(1) assert_equal '3 Bytes', number_to_human_size(3.14159265) assert_equal '123 Bytes', number_to_human_size(123.0) assert_equal '123 Bytes', number_to_human_size(123) - assert_equal '1.2 KB', number_to_human_size(1234) + assert_equal '1.21 KB', number_to_human_size(1234) assert_equal '12.1 KB', number_to_human_size(12345) - assert_equal '1.2 MB', number_to_human_size(1234567) - assert_equal '1.1 GB', number_to_human_size(1234567890) - assert_equal '1.1 TB', number_to_human_size(1234567890123) - assert_equal '1025 TB', number_to_human_size(terabytes(1025)) + assert_equal '1.18 MB', number_to_human_size(1234567) + assert_equal '1.15 GB', number_to_human_size(1234567890) + assert_equal '1.12 TB', number_to_human_size(1234567890123) + assert_equal '1030 TB', number_to_human_size(terabytes(1026)) assert_equal '444 KB', number_to_human_size(kilobytes(444)) - assert_equal '1023 MB', number_to_human_size(megabytes(1023)) + assert_equal '1020 MB', number_to_human_size(megabytes(1023)) assert_equal '3 TB', number_to_human_size(terabytes(3)) - assert_equal '1.18 MB', number_to_human_size(1234567, :precision => 2) + assert_equal '1.2 MB', number_to_human_size(1234567, :precision => 2) assert_equal '3 Bytes', number_to_human_size(3.14159265, :precision => 4) - assert_equal("123 Bytes", number_to_human_size("123")) - assert_equal '1.01 KB', number_to_human_size(kilobytes(1.0123), :precision => 2) + assert_equal '123 Bytes', number_to_human_size('123') + assert_equal '1 KB', number_to_human_size(kilobytes(1.0123), :precision => 2) assert_equal '1.01 KB', number_to_human_size(kilobytes(1.0100), :precision => 4) assert_equal '10 KB', number_to_human_size(kilobytes(10.000), :precision => 4) assert_equal '1 Byte', number_to_human_size(1.1) assert_equal '10 Bytes', number_to_human_size(10) - #assert_nil number_to_human_size('x') # fails due to API consolidation - assert_nil number_to_human_size(nil) end def test_number_to_human_size_with_options_hash - assert_equal '1.18 MB', number_to_human_size(1234567, :precision => 2) + assert_equal '1.2 MB', number_to_human_size(1234567, :precision => 2) assert_equal '3 Bytes', number_to_human_size(3.14159265, :precision => 4) - assert_equal '1.01 KB', number_to_human_size(kilobytes(1.0123), :precision => 2) + assert_equal '1 KB', number_to_human_size(kilobytes(1.0123), :precision => 2) assert_equal '1.01 KB', number_to_human_size(kilobytes(1.0100), :precision => 4) assert_equal '10 KB', number_to_human_size(kilobytes(10.000), :precision => 4) - assert_equal '1 TB', number_to_human_size(1234567890123, :precision => 0) - assert_equal '500 MB', number_to_human_size(524288000, :precision=>0) - assert_equal '40 KB', number_to_human_size(41010, :precision => 0) - assert_equal '40 KB', number_to_human_size(41100, :precision => 0) + assert_equal '1 TB', number_to_human_size(1234567890123, :precision => 1) + assert_equal '500 MB', number_to_human_size(524288000, :precision=>3) + assert_equal '40 KB', number_to_human_size(41010, :precision => 1) + assert_equal '40 KB', number_to_human_size(41100, :precision => 2) + assert_equal '1.0 KB', number_to_human_size(kilobytes(1.0123), :precision => 2, :strip_insignificant_zeros => false) + assert_equal '1.012 KB', number_to_human_size(kilobytes(1.0123), :precision => 3, :significant => false) + assert_equal '1 KB', number_to_human_size(kilobytes(1.0123), :precision => 0, :significant => true) #ignores significant it precision is 0 end def test_number_to_human_size_with_custom_delimiter_and_separator - assert_equal '1,01 KB', number_to_human_size(kilobytes(1.0123), :precision => 2, :separator => ',') + assert_equal '1,01 KB', number_to_human_size(kilobytes(1.0123), :precision => 3, :separator => ',') assert_equal '1,01 KB', number_to_human_size(kilobytes(1.0100), :precision => 4, :separator => ',') - assert_equal '1.000,1 TB', number_to_human_size(terabytes(1000.1), :delimiter => '.', :separator => ',') + assert_equal '1.000,1 TB', number_to_human_size(terabytes(1000.1), :precision => 5, :delimiter => '.', :separator => ',') + end + + def test_number_to_human_size_old_api + silence_deprecation_warnings + assert_equal '1.3143 KB', number_to_human_size(kilobytes(1.3143), 4, :significant => false) + assert_equal '10.45 KB', number_to_human_size(kilobytes(10.453), 4) + assert_equal '10 KB', number_to_human_size(kilobytes(10.453), 4, :precision => 2) + restore_deprecation_warnings + end + + def test_number_to_human + assert_equal '123', number_to_human(123) + assert_equal '1.23 Thousand', number_to_human(1234) + assert_equal '12.3 Thousand', number_to_human(12345) + assert_equal '1.23 Million', number_to_human(1234567) + assert_equal '1.23 Billion', number_to_human(1234567890) + assert_equal '1.23 Trillion', number_to_human(1234567890123) + assert_equal '1.23 Quadrillion', number_to_human(1234567890123456) + assert_equal '1230 Quadrillion', number_to_human(1234567890123456789) + assert_equal '490 Thousand', number_to_human(489939, :precision => 2) + assert_equal '489.9 Thousand', number_to_human(489939, :precision => 4) + assert_equal '489 Thousand', number_to_human(489000, :precision => 4) + assert_equal '489.0 Thousand', number_to_human(489000, :precision => 4, :strip_insignificant_zeros => false) + assert_equal '1.2346 Million', number_to_human(1234567, :precision => 4, :significant => false) + assert_equal '1,2 Million', number_to_human(1234567, :precision => 1, :significant => false, :separator => ',') + assert_equal '1 Million', number_to_human(1234567, :precision => 0, :significant => true, :separator => ',') #significant forced to false + end + + def test_number_to_human_with_custom_units + #Only integers + volume = {:unit => "ml", :thousand => "lt", :million => "m3"} + assert_equal '123 lt', number_to_human(123456, :units => volume) + assert_equal '12 ml', number_to_human(12, :units => volume) + assert_equal '1.23 m3', number_to_human(1234567, :units => volume) + + #Including fractionals + distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} + assert_equal '1.23 mm', number_to_human(0.00123, :units => distance) + assert_equal '1.23 cm', number_to_human(0.0123, :units => distance) + assert_equal '1.23 dm', number_to_human(0.123, :units => distance) + assert_equal '1.23 m', number_to_human(1.23, :units => distance) + assert_equal '1.23 dam', number_to_human(12.3, :units => distance) + assert_equal '1.23 hm', number_to_human(123, :units => distance) + assert_equal '1.23 km', number_to_human(1230, :units => distance) + assert_equal '1.23 km', number_to_human(1230, :units => distance) + assert_equal '1.23 km', number_to_human(1230, :units => distance) + assert_equal '12.3 km', number_to_human(12300, :units => distance) + + #The quantifiers don't need to be a continuous sequence + gangster = {:hundred => "hundred bucks", :million => "thousand quids"} + assert_equal '1 hundred bucks', number_to_human(100, :units => gangster) + assert_equal '25 hundred bucks', number_to_human(2500, :units => gangster) + assert_equal '25 thousand quids', number_to_human(25000000, :units => gangster) + assert_equal '12300 thousand quids', number_to_human(12345000000, :units => gangster) + + #Spaces are stripped from the resulting string + assert_equal '4', number_to_human(4, :units => {:unit => "", :ten => 'tens '}) + assert_equal '4.5 tens', number_to_human(45, :units => {:unit => "", :ten => ' tens '}) end + + def test_number_to_human_with_custom_format + assert_equal '123 times Thousand', number_to_human(123456, :format => "%n times %u") + volume = {:unit => "ml", :thousand => "lt", :million => "m3"} + assert_equal '123.lt', number_to_human(123456, :units => volume, :format => "%n.%u") + end + + def test_number_helpers_should_return_nil_when_given_nil + assert_nil number_to_phone(nil) + assert_nil number_to_currency(nil) + assert_nil number_to_percentage(nil) + assert_nil number_with_delimiter(nil) + assert_nil number_with_precision(nil) + assert_nil number_to_human_size(nil) + assert_nil number_to_human(nil) + end + + def test_number_helpers_should_return_non_numeric_param_unchanged + assert_equal("+1-x x 123", number_to_phone("x", :country_code => 1, :extension => 123)) + assert_equal("x", number_to_phone("x")) + assert_equal("$x.", number_to_currency("x.")) + assert_equal("$x", number_to_currency("x")) + assert_equal("x%", number_to_percentage("x")) + assert_equal("x", number_with_delimiter("x")) + assert_equal("x.", number_with_precision("x.")) + assert_equal("x", number_with_precision("x")) + assert_equal "x", number_to_human_size('x') + assert_equal "x", number_to_human('x') + end + + def test_number_helpers_outputs_are_html_safe + assert number_to_human(1).html_safe? + assert !number_to_human("<script></script>").html_safe? + assert number_to_human("asdf".html_safe).html_safe? + + assert number_to_human_size(1).html_safe? + assert number_to_human_size(1000000).html_safe? + assert !number_to_human_size("<script></script>").html_safe? + assert number_to_human_size("asdf".html_safe).html_safe? + + assert number_with_precision(1, :strip_insignificant_zeros => false).html_safe? + assert number_with_precision(1, :strip_insignificant_zeros => true).html_safe? + assert !number_with_precision("<script></script>").html_safe? + assert number_with_precision("asdf".html_safe).html_safe? + + assert number_to_currency(1).html_safe? + assert !number_to_currency("<script></script>").html_safe? + assert number_to_currency("asdf".html_safe).html_safe? + + assert number_to_percentage(1).html_safe? + assert !number_to_percentage("<script></script>").html_safe? + assert number_to_percentage("asdf".html_safe).html_safe? + + assert number_to_phone(1).html_safe? + assert !number_to_phone("<script></script>").html_safe? + assert number_to_phone("asdf".html_safe).html_safe? + + assert number_with_delimiter(1).html_safe? + assert !number_with_delimiter("<script></script>").html_safe? + assert number_with_delimiter("asdf".html_safe).html_safe? + end + + def test_number_helpers_should_raise_error_if_invalid_when_specified + assert_raise InvalidNumberError do + number_to_human("x", :raise => true) + end + begin + number_to_human("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_to_human_size("x", :raise => true) + end + begin + number_to_human_size("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_with_precision("x", :raise => true) + end + begin + number_with_precision("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_to_currency("x", :raise => true) + end + begin + number_with_precision("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_to_percentage("x", :raise => true) + end + begin + number_to_percentage("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_with_delimiter("x", :raise => true) + end + begin + number_with_delimiter("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + assert_raise InvalidNumberError do + number_to_phone("x", :raise => true) + end + begin + number_to_phone("x", :raise => true) + rescue InvalidNumberError => e + assert_equal "x", e.number + end + + end + end diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index 36bbaf9099..bd49a11af1 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -10,6 +10,7 @@ class OutputBufferTest < ActionController::TestCase tests TestController def setup + @vc = @controller.view_context get :index assert_equal ['foo'], body_parts end @@ -19,21 +20,21 @@ class OutputBufferTest < ActionController::TestCase end test 'flushing ignores nil output buffer' do - @controller.template.flush_output_buffer + @controller.view_context.flush_output_buffer assert_nil output_buffer assert_equal ['foo'], body_parts end test 'flushing ignores empty output buffer' do - @controller.template.output_buffer = '' - @controller.template.flush_output_buffer + @vc.output_buffer = '' + @vc.flush_output_buffer assert_equal '', output_buffer assert_equal ['foo'], body_parts end test 'flushing appends the output buffer to the body parts' do - @controller.template.output_buffer = 'bar' - @controller.template.flush_output_buffer + @vc.output_buffer = 'bar' + @vc.flush_output_buffer assert_equal '', output_buffer assert_equal ['foo', 'bar'], body_parts end @@ -41,8 +42,8 @@ class OutputBufferTest < ActionController::TestCase if '1.9'.respond_to?(:force_encoding) test 'flushing preserves output buffer encoding' do original_buffer = ' '.force_encoding(Encoding::EUC_JP) - @controller.template.output_buffer = original_buffer - @controller.template.flush_output_buffer + @vc.output_buffer = original_buffer + @vc.flush_output_buffer assert_equal ['foo', original_buffer], body_parts assert_not_equal original_buffer, output_buffer assert_equal Encoding::EUC_JP, output_buffer.encoding @@ -51,10 +52,10 @@ class OutputBufferTest < ActionController::TestCase protected def output_buffer - @controller.template.output_buffer + @vc.output_buffer end def body_parts - @controller.template.response.body_parts + @controller.response.body_parts end end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index cea8ab1bce..e54ebfbf8d 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -9,7 +9,7 @@ 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) + @controller_view = TestController.new.view_context # Reload and register danish language for testing I18n.reload! @@ -228,6 +228,14 @@ module RenderTestCases @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield") end + # TODO: Move to deprecated_tests.rb + def test_render_with_nested_layout_deprecated + assert_deprecated do + assert_equal %(<title>title</title>\n\n\n<div id="column">column</div>\n<div id="content">content</div>\n), + @view.render(:file => "test/deprecated_nested_layout.erb", :layout => "layouts/yield") + end + end + def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n\n<div id="column">column</div>\n<div id="content">content</div>\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index 699fb2f5bc..6782bf06d4 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -20,7 +20,14 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_translation_of_an_array I18n.expects(:translate).with(["foo", "bar"], :raise => true).returns(["foo", "bar"]) - assert_equal ["foo", "bar"], translate(["foo", "bar"]) + assert_equal "foobar", translate(["foo", "bar"]) + end + + def test_translation_of_an_array_with_html + expected = '<a href="#">foo</a><a href="#">bar</a>' + I18n.expects(:translate).with(["foo", "bar"], :raise => true).returns(['<a href="#">foo</a>', '<a href="#">bar</a>']) + @view = ActionView::Base.new(ActionController::Base.view_paths, {}) + assert_equal expected, @view.render(:file => "test/array_translation") end def test_delegates_localize_to_i18n @@ -34,4 +41,10 @@ class TranslationHelperTest < ActiveSupport::TestCase @view = ActionView::Base.new(ActionController::Base.view_paths, {}) assert_equal "helper", @view.render(:file => "test/translation") end + + def test_scoping_by_partial_of_an_array + I18n.expects(:translate).with("test.scoped_array_translation.foo.bar", :raise => true).returns(["foo", "bar"]) + @view = ActionView::Base.new(ActionController::Base.view_paths, {}) + assert_equal "foobar", @view.render(:file => "test/scoped_array_translation") + end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 165cb655da..87b2e59255 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -238,10 +238,7 @@ class UrlHelperTest < ActionView::TestCase end def test_link_tag_using_block_in_erb - __in_erb_template = '' - - link_to("http://example.com") { concat("Example site") } - + output_buffer = link_to("http://example.com") { concat("Example site") } assert_equal '<a href="http://example.com">Example site</a>', output_buffer end diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index c1334069fa..f04829ef09 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -89,13 +89,20 @@ module ActiveModel # # => 'address_id' def define_attr_method(name, value=nil, &block) sing = singleton_class - sing.send :alias_method, "original_#{name}", name + sing.class_eval <<-eorb, __FILE__, __LINE__ + 1 + if method_defined?(:original_#{name}) + undef :original_#{name} + end + alias_method :original_#{name}, :#{name} + eorb if block_given? sing.send :define_method, name, &block else # use eval instead of a block to work around a memory leak in dev # mode in fcgi - sing.class_eval "def #{name}; #{value.to_s.inspect}; end" + sing.class_eval <<-eorb, __FILE__, __LINE__ + 1 + def #{name}; #{value.to_s.inspect}; end + eorb end end @@ -256,8 +263,13 @@ module ActiveModel if respond_to?(generate_method) send(generate_method, attr_name) else + method_name = matcher.method_name(attr_name) + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__+1 - def #{matcher.method_name(attr_name)}(*args) + if method_defined?(:#{method_name}) + undef :#{method_name} + end + def #{method_name}(*args) send(:#{matcher.method_missing_target}, '#{attr_name}', *args) end STR diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index a7e0cf90c1..d4e98de57b 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/array/wrap' require 'active_support/callbacks' module ActiveModel @@ -91,7 +92,7 @@ module ActiveModel options = callbacks.extract_options! options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options) - types = Array(options.delete(:only)) + types = Array.wrap(options.delete(:only)) types = [:before, :around, :after] if types.empty? callbacks.each do |callback| @@ -124,10 +125,10 @@ module ActiveModel def self.after_#{callback}(*args, &block) options = args.extract_options! options[:prepend] = true - options[:if] = Array(options[:if]) << "!halted && value != false" + options[:if] = Array.wrap(options[:if]) << "!halted && value != false" set_callback(:#{callback}, :after, *(args << options), &block) end CALLBACK end end -end
\ No newline at end of file +end diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 5f02929a9d..cb67ef7270 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -1,3 +1,5 @@ +require 'active_support/hash_with_indifferent_access' + module ActiveModel # <tt>ActiveModel::Dirty</tt> provides a way to track changes in your # object in the same way as ActiveRecord does. @@ -86,12 +88,17 @@ module ActiveModel attribute_method_affix :prefix => 'reset_', :suffix => '!' end + def initialize(*) + @changed_attributes = {} + super + end + # Do any attributes have unsaved changes? # person.changed? # => false # person.name = 'bob' # person.changed? # => true def changed? - !changed_attributes.empty? + !@changed_attributes.empty? end # List of attributes with unsaved changes. @@ -99,7 +106,7 @@ module ActiveModel # person.name = 'bob' # person.changed # => ['name'] def changed - changed_attributes.keys + @changed_attributes.keys end # Map of changed attrs => [original value, new value]. @@ -107,7 +114,7 @@ module ActiveModel # person.name = 'bob' # person.changes # => { 'name' => ['bill', 'bob'] } def changes - changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h } + changed.inject(HashWithIndifferentAccess.new){ |h, attr| h[attr] = attribute_change(attr); h } end # Map of attributes that were changed when the model was saved. @@ -116,33 +123,23 @@ module ActiveModel # person.save # person.previous_changes # => {'name' => ['bob, 'robert']} def previous_changes - previously_changed_attributes + @previously_changed end private - # Map of change <tt>attr => original value</tt>. - def changed_attributes - @changed_attributes ||= {} - end - - # Map of fields that were changed when the model was saved - def previously_changed_attributes - @previously_changed || {} - end - # Handle <tt>*_changed?</tt> for +method_missing+. def attribute_changed?(attr) - changed_attributes.include?(attr) + @changed_attributes.include?(attr) end # Handle <tt>*_change</tt> for +method_missing+. def attribute_change(attr) - [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) + [@changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) end # Handle <tt>*_was</tt> for +method_missing+. def attribute_was(attr) - attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) + attribute_changed?(attr) ? @changed_attributes[attr] : __send__(attr) end # Handle <tt>*_will_change!</tt> for +method_missing+. @@ -153,12 +150,12 @@ module ActiveModel rescue TypeError, NoMethodError end - changed_attributes[attr] = value + @changed_attributes[attr] = value end # Handle <tt>reset_*!</tt> for +method_missing+. def reset_attribute!(attr) - __send__("#{attr}=", changed_attributes[attr]) if attribute_changed?(attr) + __send__("#{attr}=", @changed_attributes[attr]) if attribute_changed?(attr) end end end diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index d8320275df..a9a54a90e0 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/string/inflections' require 'active_support/ordered_hash' @@ -206,7 +207,7 @@ module ActiveModel full_messages = [] each do |attribute, messages| - messages = Array(messages) + messages = Array.wrap(messages) next if messages.empty? if attribute == :base diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb index a185204680..c226359ea7 100644 --- a/activemodel/lib/active_model/serializers/xml.rb +++ b/activemodel/lib/active_model/serializers/xml.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/hash/conversions' @@ -108,7 +109,7 @@ module ActiveModel end def serializable_method_attributes - Array(options[:methods]).inject([]) do |methods, name| + Array.wrap(options[:methods]).inject([]) do |methods, name| methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s) methods end diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index ba8648f8c9..708557f4ae 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/array/extract_options' +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/keys' require 'active_model/errors' @@ -112,11 +113,10 @@ module ActiveModel # end # end # - # This usage applies to +validate_on_create+ and +validate_on_update as well+. def validate(*args, &block) options = args.last if options.is_a?(Hash) && options.key?(:on) - options[:if] = Array(options[:if]) + options[:if] = Array.wrap(options[:if]) options[:if] << "@_on_validate == :#{options[:on]}" end set_callback(:validate, *args, &block) diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index b61f0cb266..b7c52be3f0 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/array/wrap' require "active_support/core_ext/module/anonymous" module ActiveModel #:nodoc: @@ -130,7 +131,7 @@ module ActiveModel #:nodoc: # +options+ reader, however the <tt>:attributes</tt> option will be removed # and instead be made available through the +attributes+ reader. def initialize(options) - @attributes = Array(options.delete(:attributes)) + @attributes = Array.wrap(options.delete(:attributes)) raise ":attributes cannot be blank" if @attributes.empty? super check_validity! diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb new file mode 100644 index 0000000000..0883363baf --- /dev/null +++ b/activemodel/test/cases/dirty_test.rb @@ -0,0 +1,30 @@ +require "cases/helper" + +class DirtyTest < ActiveModel::TestCase + class DirtyModel + include ActiveModel::Dirty + define_attribute_methods [:name] + + def initialize + super + @name = nil + end + + def name + @name + end + + def name=(val) + name_will_change! + @name = val + end + end + + test "changes accessible through both strings and symbols" do + model = DirtyModel.new + model.name = "David" + assert !model.changes[:name].nil? + assert !model.changes['name'].nil? + end + +end diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index 8b1ea8596a..8121530ab3 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -22,5 +22,5 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 0.3.1') + s.add_dependency('arel', '~> 0.3.3') end diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 9ecf231a66..08389907ef 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -213,6 +213,11 @@ module ActiveRecord module_eval do define_method(name) do |*args| force_reload = args.first || false + + unless instance_variable_defined?("@#{name}") + instance_variable_set("@#{name}", nil) + end + if (instance_variable_get("@#{name}").nil? || force_reload) && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? }) attrs = mapping.collect {|pair| read_attribute(pair.first)} object = case constructor diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c47e0c37b8..d623ddb915 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1545,15 +1545,19 @@ module ActiveRecord case name when :destroy, :delete - define_method(method_name) do - association = send(reflection.name) - association.send(name) if association - end + class_eval <<-eoruby, __FILE__, __LINE__ + 1 + def #{method_name} + association = #{reflection.name} + association.#{name} if association + end + eoruby when :nullify - define_method(method_name) do - association = send(reflection.name) - association.update_attribute(reflection.primary_key_name, nil) if association - end + class_eval <<-eoruby, __FILE__, __LINE__ + 1 + def #{method_name} + association = #{reflection.name} + association.update_attribute(#{reflection.primary_key_name.inspect}, nil) if association + end + eoruby else raise ArgumentError, "The :dependent option expects either :destroy, :delete or :nullify (#{reflection.options[:dependent].inspect})" end @@ -1571,10 +1575,12 @@ module ActiveRecord end method_name = :"belongs_to_dependent_#{name}_for_#{reflection.name}" - define_method(method_name) do - association = send(reflection.name) - association.send(name) if association - end + class_eval <<-eoruby, __FILE__, __LINE__ + 1 + def #{method_name} + association = #{reflection.name} + association.#{name} if association + end + eoruby after_destroy method_name end end @@ -1673,15 +1679,6 @@ module ActiveRecord reflection end - def using_limitable_reflections?(reflections) - reflections.collect(&:collection?).length.zero? - end - - def column_aliases(join_dependency) - join_dependency.joins.collect{|join| join.column_names_with_alias.collect{|column_name, aliased_name| - "#{connection.quote_table_name join.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}"}}.flatten.join(", ") - end - def add_association_callbacks(association_name, options) callbacks = %w(before_add after_add before_remove after_remove) callbacks.each do |callback_name| diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 0ff89df1e3..4fb1df3ab9 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -53,6 +53,7 @@ module ActiveRecord def initialize(owner, reflection) @owner, @reflection = owner, reflection + @updated = false reflection.check_validity! Array(reflection.options[:extend]).each { |ext| proxy_extend(ext) } reset diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 146a6ca55f..0464e8ceea 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -5,6 +5,10 @@ module ActiveRecord # If the association has a <tt>:through</tt> option further specialization # is provided by its child HasManyThroughAssociation. class HasManyAssociation < AssociationCollection #:nodoc: + def initialize(owner, reflection) + @finder_sql = nil + super + end protected def owner_quoted_id if @reflection.options[:primary_key] diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 4a3ab9ea82..a8698a2f5a 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -18,7 +18,7 @@ module ActiveRecord def save_with_dirty(*args) #:nodoc: if status = save_without_dirty(*args) @previously_changed = changes - changed_attributes.clear + @changed_attributes.clear end status end @@ -26,16 +26,16 @@ module ActiveRecord # Attempts to <tt>save!</tt> the record and clears changed attributes if successful. def save_with_dirty!(*args) #:nodoc: save_without_dirty!(*args).tap do - @previously_changed = changes - changed_attributes.clear + @previously_changed = changes + @changed_attributes.clear end end # <tt>reload</tt> the record and clears changed attributes. def reload_with_dirty(*args) #:nodoc: reload_without_dirty(*args).tap do - previously_changed_attributes.clear - changed_attributes.clear + @previously_changed.clear + @changed_attributes.clear end end @@ -45,12 +45,12 @@ module ActiveRecord attr = attr.to_s # The attribute already has an unsaved change. - if changed_attributes.include?(attr) - old = changed_attributes[attr] - changed_attributes.delete(attr) unless field_changed?(attr, old, value) + if attribute_changed?(attr) + old = @changed_attributes[attr] + @changed_attributes.delete(attr) unless field_changed?(attr, old, value) else old = clone_attribute_value(:read_attribute, attr) - changed_attributes[attr] = old if field_changed?(attr, old, value) + @changed_attributes[attr] = old if field_changed?(attr, old, value) end # Carry on. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 1488d9f967..367b4ce217 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1045,6 +1045,8 @@ module ActiveRecord #:nodoc: object.instance_variable_set(:@readonly, false) object.instance_variable_set(:@destroyed, false) object.instance_variable_set(:@marked_for_destruction, false) + object.instance_variable_set(:@previously_changed, {}) + object.instance_variable_set(:@changed_attributes, {}) object.send(:_run_find_callbacks) object.send(:_run_initialize_callbacks) @@ -1513,6 +1515,8 @@ module ActiveRecord #:nodoc: @readonly = false @destroyed = false @marked_for_destruction = false + @previously_changed = {} + @changed_attributes = {} ensure_proper_type @@ -2050,26 +2054,6 @@ module ActiveRecord #:nodoc: end # Returns a copy of the attributes hash where all the values have been safely quoted for use in - # an SQL statement. - def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys) - quoted = {} - connection = self.class.connection - attribute_names.each do |name| - if (column = column_for_attribute(name)) && (include_primary_key || !column.primary) - value = read_attribute(name) - - # We need explicit to_yaml because quote() does not properly convert Time/Date fields to YAML. - if value && self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time)) - value = value.to_yaml - end - - quoted[name] = connection.quote(value, column) - end - end - include_readonly_attributes ? quoted : remove_readonly_attributes(quoted) - end - - # Returns a copy of the attributes hash where all the values have been safely quoted for use in # an Arel insert/update method. def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys) attrs = {} diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index abb695264e..0c87e052c4 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -181,6 +181,29 @@ module ActiveRecord # done if the transaction block raises an exception or returns false. def rollback_db_transaction() end + # Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL + # fragment that has the same semantics as LIMIT and OFFSET. + # + # +options+ must be a Hash which contains a +:limit+ option + # and an +:offset+ option. + # + # This method *modifies* the +sql+ parameter. + # + # ===== Examples + # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50}) + # generates + # SELECT * FROM suppliers LIMIT 10 OFFSET 50 + + def add_limit_offset!(sql, options) + if limit = options[:limit] + sql << " LIMIT #{sanitize_limit(limit)}" + end + if offset = options[:offset] + sql << " OFFSET #{offset.to_i}" + end + sql + end + def default_sequence_name(table, column) nil end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 1f1df7e8c3..521bd810d0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -61,7 +61,7 @@ module ActiveRecord begin require_library_or_gem('mysql') rescue LoadError - $stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.' + $stderr.puts '!!! Please install the mysql gem and try again: gem install mysql.' raise end end @@ -375,6 +375,18 @@ module ActiveRecord execute("RELEASE SAVEPOINT #{current_savepoint_name}") end + def add_limit_offset!(sql, options) #:nodoc: + limit, offset = options[:limit], options[:offset] + if limit && offset + sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" + elsif limit + sql << " LIMIT #{sanitize_limit(limit)}" + elsif offset + sql << " OFFSET #{offset.to_i}" + end + sql + end + # SCHEMA STATEMENTS ======================================== def structure_dump #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index b3ce8c79dd..31d5266da8 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -651,14 +651,33 @@ module ActiveRecord end end + # Creates a schema for the given user + # + # Example: + # create_schema('products', 'postgres') + def create_schema(schema_name, pg_username) + execute("CREATE SCHEMA \"#{schema_name}\" AUTHORIZATION \"#{pg_username}\"") + end + + # Drops a schema + # + # Example: + # drop_schema('products') + def drop_schema(schema_name) + execute("DROP SCHEMA \"#{schema_name}\"") + end + + # Returns an array of all schemas in the database + def all_schemas + query('SELECT schema_name FROM information_schema.schemata').flatten + end # Returns the list of all tables in the schema search path or a specified schema. def tables(name = nil) - schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',') query(<<-SQL, name).map { |row| row[0] } SELECT tablename FROM pg_tables - WHERE schemaname IN (#{schemas}) + WHERE schemaname = ANY (current_schemas(false)) SQL end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5825482db7..d4cda927ad 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -374,7 +374,7 @@ module ActiveRecord end def load_migration - load(filename) + require(File.expand_path(filename)) name.constantize end diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index d8fae495e7..76ec7eb681 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -243,11 +243,14 @@ module ActiveRecord # def pirate_attributes=(attributes) # assign_nested_attributes_for_one_to_one_association(:pirate, attributes) # end - class_eval %{ + class_eval <<-eoruby, __FILE__, __LINE__ + 1 + if method_defined?(:#{association_name}_attributes=) + remove_method(:#{association_name}_attributes=) + end def #{association_name}_attributes=(attributes) assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes) end - }, __FILE__, __LINE__ + eoruby else raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?" end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 60addd46c6..de47461c73 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -10,7 +10,7 @@ require "action_controller/railtie" module ActiveRecord class Railtie < Rails::Railtie - railtie_name :active_record + config.active_record = ActiveSupport::OrderedOptions.new config.generators.orm :active_record, :migration => true, :timestamps => true @@ -19,9 +19,8 @@ module ActiveRecord load "active_record/railties/databases.rake" end - # TODO If we require the wrong file, the error never comes up. require "active_record/railties/log_subscriber" - log_subscriber ActiveRecord::Railties::LogSubscriber.new + log_subscriber :active_record, ActiveRecord::Railties::LogSubscriber.new initializer "active_record.initialize_timezone" do ActiveRecord.base_hook do diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index fa6caa4910..06485b9033 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -85,8 +85,14 @@ namespace :db do end when 'postgresql' @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8' + schema_search_path = config['schema_search_path'] || 'public' + first_in_schema_search_path = schema_search_path.split(',').first.strip begin ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public')) + unless ActiveRecord::Base.connection.all_schemas.include?(first_in_schema_search_path) + ActiveRecord::Base.connection.create_schema(first_in_schema_search_path, config['username']) + $stderr.puts "Schema #{first_in_schema_search_path} has been created." + end ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding)) ActiveRecord::Base.establish_connection(config) rescue @@ -435,7 +441,7 @@ namespace :db do task :create => :environment do raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations? require 'rails/generators' - require 'generators/rails/session_migration/session_migration_generator' + require 'rails/generators/rails/session_migration/session_migration_generator' Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ] end diff --git a/activerecord/lib/active_record/railties/log_subscriber.rb b/activerecord/lib/active_record/railties/log_subscriber.rb index 48b25032ce..31b98bb6ed 100644 --- a/activerecord/lib/active_record/railties/log_subscriber.rb +++ b/activerecord/lib/active_record/railties/log_subscriber.rb @@ -1,6 +1,11 @@ module ActiveRecord module Railties class LogSubscriber < Rails::LogSubscriber + def initialize + super + @odd_or_even = false + end + def sql(event) name = '%s (%.1fms)' % [event.payload[:name], event.duration] sql = event.payload[:sql].squeeze(' ') @@ -24,4 +29,4 @@ module ActiveRecord end end end -end
\ No newline at end of file +end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 1a84f70a8e..a20c152eeb 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -15,13 +15,10 @@ module ActiveRecord def initialize(klass, table) @klass, @table = klass, table - @readonly_value = nil - @create_with_value = nil @implicit_readonly = nil - @limit_value = nil - @offset_value = nil @loaded = nil + SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)} (ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])} end @@ -62,7 +59,7 @@ module ActiveRecord preload = @preload_values preload += @includes_values unless eager_loading? - preload.each {|associations| @klass.send(:preload_associations, @records, associations) } + preload.each {|associations| @klass.send(:preload_associations, @records, associations) } # @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT. readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index d6d3d66642..c1cce679b6 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -175,7 +175,7 @@ module ActiveRecord end def construct_relation_for_association_find(join_dependency) - relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency)) + relation = except(:includes, :eager_load, :preload, :select).select(column_aliases(join_dependency)) apply_join_dependency(relation, join_dependency) end @@ -184,7 +184,7 @@ module ActiveRecord relation = association.join_relation(relation) end - limitable_reflections = @klass.send(:using_limitable_reflections?, join_dependency.reflections) + limitable_reflections = using_limitable_reflections?(join_dependency.reflections) if !limitable_reflections && relation.limit_value limited_id_condition = construct_limited_ids_condition(relation.except(:select)) @@ -311,5 +311,14 @@ module ActiveRecord end end + def column_aliases(join_dependency) + join_dependency.joins.collect{|join| join.column_names_with_alias.collect{|column_name, aliased_name| + "#{connection.quote_table_name join.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}"}}.flatten.join(", ") + end + + def using_limitable_reflections?(reflections) + reflections.collect(&:collection?).length.zero? + end + end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index e00d9cdf27..0250e739b8 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -6,6 +6,7 @@ module ActiveRecord (ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS).each do |query_method| attr_accessor :"#{query_method}_values" + next if [:where, :having].include?(query_method) class_eval <<-CEVAL def #{query_method}(*args) new_relation = clone @@ -133,13 +134,8 @@ module ActiveRecord arel = h.is_a?(String) ? arel.having(h) : arel.having(*h) end - if defined?(@limit_value) && @limit_value.present? - arel = arel.take(@limit_value) - end - - if defined?(@offset_value) && @offset_value.present? - arel = arel.skip(@offset_value) - end + arel = arel.take(@limit_value) if @limit_value.present? + arel = arel.skip(@offset_value) if @offset_value.present? @group_values.uniq.each do |g| arel = arel.group(g) if g.present? @@ -162,19 +158,14 @@ module ActiveRecord arel = arel.project(quoted_table_name + '.*') end - arel = - if defined?(@from_value) && @from_value.present? - arel.from(@from_value) - else - arel.from(quoted_table_name) - end + arel = @from_value.present? ? arel.from(@from_value) : arel.from(quoted_table_name) case @lock_value when TrueClass arel = arel.lock when String arel = arel.lock(@lock_value) - end if defined?(@lock_value) + end if @lock_value.present? arel end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index a18380f01c..2841ff1239 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -4,30 +4,14 @@ module ActiveRecord merged_relation = clone return merged_relation unless r - merged_relation = merged_relation.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values) - - merged_relation.readonly_value = r.readonly_value unless r.readonly_value.nil? - merged_relation.limit_value = r.limit_value if r.limit_value.present? - merged_relation.lock_value = r.lock_value unless merged_relation.lock_value - merged_relation.offset_value = r.offset_value if r.offset_value.present? - - merged_relation = merged_relation. - joins(r.joins_values). - group(r.group_values). - select(r.select_values). - from(r.from_value). - having(r.having_values) - - merged_relation.order_values = r.order_values if r.order_values.present? - - merged_relation.create_with_value = @create_with_value - - if @create_with_value && r.create_with_value - merged_relation.create_with_value = @create_with_value.merge(r.create_with_value) - else - merged_relation.create_with_value = r.create_with_value || @create_with_value + (ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS).reject {|m| [:joins, :where].include?(m)}.each do |method| + unless (value = r.send(:"#{method}_values")).blank? + merged_relation.send(:"#{method}_values=", value) + end end + merged_relation = merged_relation.joins(r.joins_values) + merged_wheres = @where_values r.where_values.each do |w| @@ -40,6 +24,14 @@ module ActiveRecord merged_relation.where_values = merged_wheres + ActiveRecord::Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method| + unless (value = r.send(:"#{method}_value")).nil? + merged_relation.send(:"#{method}_value=", value) + end + end + + merged_relation.lock_value = r.lock_value unless merged_relation.lock_value + merged_relation end diff --git a/activerecord/lib/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb index 1ca838b4f2..1ca838b4f2 100644 --- a/activerecord/lib/generators/active_record.rb +++ b/activerecord/lib/rails/generators/active_record.rb diff --git a/activerecord/lib/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb index 7939977f72..f6159deeeb 100644 --- a/activerecord/lib/generators/active_record/migration/migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb @@ -1,4 +1,4 @@ -require 'generators/active_record' +require 'rails/generators/active_record' module ActiveRecord module Generators diff --git a/activerecord/lib/generators/active_record/migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb index bbb7c53d86..bbb7c53d86 100644 --- a/activerecord/lib/generators/active_record/migration/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb diff --git a/activerecord/lib/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb index 2641083e0d..3e72fbeca8 100644 --- a/activerecord/lib/generators/active_record/model/model_generator.rb +++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb @@ -1,4 +1,4 @@ -require 'generators/active_record' +require 'rails/generators/active_record' module ActiveRecord module Generators diff --git a/activerecord/lib/generators/active_record/model/templates/migration.rb b/activerecord/lib/rails/generators/active_record/model/templates/migration.rb index 1f68487304..1f68487304 100644 --- a/activerecord/lib/generators/active_record/model/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/model/templates/migration.rb diff --git a/activerecord/lib/generators/active_record/model/templates/model.rb b/activerecord/lib/rails/generators/active_record/model/templates/model.rb index 21ae29e9f2..21ae29e9f2 100644 --- a/activerecord/lib/generators/active_record/model/templates/model.rb +++ b/activerecord/lib/rails/generators/active_record/model/templates/model.rb diff --git a/activerecord/lib/generators/active_record/observer/observer_generator.rb b/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb index a6b57423b8..c1c0e3f25b 100644 --- a/activerecord/lib/generators/active_record/observer/observer_generator.rb +++ b/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb @@ -1,4 +1,4 @@ -require 'generators/active_record' +require 'rails/generators/active_record' module ActiveRecord module Generators diff --git a/activerecord/lib/generators/active_record/observer/templates/observer.rb b/activerecord/lib/rails/generators/active_record/observer/templates/observer.rb index b9a3004161..b9a3004161 100644 --- a/activerecord/lib/generators/active_record/observer/templates/observer.rb +++ b/activerecord/lib/rails/generators/active_record/observer/templates/observer.rb diff --git a/activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb b/activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb index 59c4792066..afcda2a98a 100644 --- a/activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb @@ -1,4 +1,4 @@ -require 'generators/active_record' +require 'rails/generators/active_record' module ActiveRecord module Generators diff --git a/activerecord/lib/generators/active_record/session_migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb index 919822af7b..919822af7b 100644 --- a/activerecord/lib/generators/active_record/session_migration/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb diff --git a/activerecord/test/cases/active_schema_test_postgresql.rb b/activerecord/test/cases/active_schema_test_postgresql.rb index af80f724f2..67c662d694 100644 --- a/activerecord/test/cases/active_schema_test_postgresql.rb +++ b/activerecord/test/cases/active_schema_test_postgresql.rb @@ -17,6 +17,13 @@ class PostgresqlActiveSchemaTest < Test::Unit::TestCase assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1) end + def test_create_schema + assert_equal %(CREATE SCHEMA "rizwan" AUTHORIZATION "postgres"), create_schema(:rizwan, :postgres) + end + + def test_drop_schema + assert_equal %(DROP SCHEMA "rizwan"), drop_schema(:rizwan) + end private def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index c59be264a4..9f78ae008c 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -81,6 +81,12 @@ class AdapterTest < ActiveRecord::TestCase def test_encoding assert_not_nil @connection.encoding end + + def test_all_schemas + @connection.create_schema(:test_schema, :postgres) + assert @connection.all_schemas.include?('test_schema') + @connection.drop_schema(:test_schema) + end end def test_table_alias @@ -142,4 +148,25 @@ class AdapterTest < ActiveRecord::TestCase end end end + + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas + sql_inject = "1 select * from schema" + assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit => sql_inject) + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7) + else + assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7) + end + end + + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas + sql_inject = "1, 7 procedure help()" + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit => sql_inject) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit => '1 ; DROP TABLE USERS', :offset => 7) + else + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit => sql_inject) + assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7) + end + end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index ffa6d45948..42a891bc3b 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -805,7 +805,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_include_has_many_using_primary_key - expected = Firm.find(1).clients_using_primary_key.sort_by &:name + expected = Firm.find(1).clients_using_primary_key.sort_by(&:name) # Oracle adapter truncates alias to 30 characters if current_adapter?(:OracleAdapter) firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name' diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index d47c8bba7d..ff799191c2 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -291,7 +291,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase ], log.last(2) post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")] - assert_equal (%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort + assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort) assert_equal [ [:added, :before, "Julian"], [:added, :after, "Julian"], @@ -300,7 +300,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase ], log.last(4) post.people_with_callbacks.clear - assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort + assert_equal((%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort) end def test_dynamic_find_should_respect_association_include diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index d5dbb88886..7372f2da1b 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -186,15 +186,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal account, firm.account end - def test_failing_build_association - firm = Firm.new("name" => "GlobalMegaCorp") - firm.save - - account = firm.build_account - assert !account.save - assert_equal ["can't be empty"], account.errors["credit_limit"] - end - def test_build_association_twice_without_saving_affects_nothing count_of_account = Account.count firm = Firm.find(:first) diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index 43abcae75e..4ba867dc7c 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -15,12 +15,12 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase def test_construct_finder_sql_ignores_empty_joins_hash sql = Author.joins({}).to_sql - assert_no_match /JOIN/i, sql + assert_no_match(/JOIN/i, sql) end def test_construct_finder_sql_ignores_empty_joins_array sql = Author.joins([]).to_sql - assert_no_match /JOIN/i, sql + assert_no_match(/JOIN/i, sql) end def test_find_with_implicit_inner_joins_honors_readonly_without_select diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index e9af5a60d8..8bdf8bcd55 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -52,18 +52,6 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size end - def test_polymorphic_has_many - assert posts(:welcome).taggings.include?(taggings(:welcome_general)) - end - - def test_polymorphic_has_one - assert_equal taggings(:welcome_general), posts(:welcome).tagging - end - - def test_polymorphic_belongs_to - assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable - end - def test_polymorphic_has_many_going_through_join_model assert_equal tags(:general), tag = posts(:welcome).tags.first assert_no_queries do diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index e3047fe873..8774ed58aa 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -674,10 +674,10 @@ class BasicsTest < ActiveRecord::TestCase def test_decrement_counter Topic.decrement_counter("replies_count", 2) - assert_equal -1, Topic.find(2).replies_count + assert_equal(-1, Topic.find(2).replies_count) Topic.decrement_counter("replies_count", 2) - assert_equal -2, Topic.find(2).replies_count + assert_equal(-2, Topic.find(2).replies_count) end def test_reset_counters @@ -1533,7 +1533,7 @@ class BasicsTest < ActiveRecord::TestCase def test_auto_id auto = AutoId.new auto.save - assert (auto.id > 0) + assert(auto.id > 0) end def quote_column_name(name) @@ -2181,7 +2181,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_inspect_new_instance - assert_match /Topic id: nil/, Topic.new.inspect + assert_match(/Topic id: nil/, Topic.new.inspect) end def test_inspect_limited_select_instance @@ -2240,9 +2240,9 @@ class BasicsTest < ActiveRecord::TestCase ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count } ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count } ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count } - assert_no_match /Debug Topic Count/, log.string - assert_match /Warn Topic Count/, log.string - assert_match /Error Topic Count/, log.string + assert_no_match(/Debug Topic Count/, log.string) + assert_match(/Warn Topic Count/, log.string) + assert_match(/Error Topic Count/, log.string) ensure ActiveRecord::Base.logger = original_logger end @@ -2253,8 +2253,8 @@ class BasicsTest < ActiveRecord::TestCase ActiveRecord::Base.logger = Logger.new(log) ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => true) { ActiveRecord::Base.logger.debug "Loud" } ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" } - assert_no_match /Loud/, log.string - assert_match /Quiet/, log.string + assert_no_match(/Loud/, log.string) + assert_match(/Quiet/, log.string) ensure ActiveRecord::Base.logger = original_logger end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index ff2322ac15..dc7f82b001 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -43,6 +43,11 @@ class CallbackDeveloper < ActiveRecord::Base end end +class CallbackDeveloperWithFalseValidation < CallbackDeveloper + before_validation proc { |model| model.history << [:before_validation, :returning_false]; return false } + before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] } +end + class ParentDeveloper < ActiveRecord::Base set_table_name 'developers' attr_accessor :after_save_called @@ -139,7 +144,7 @@ class CallbackCancellationDeveloper < ActiveRecord::Base attr_reader :after_save_called, :after_create_called, :after_update_called, :after_destroy_called attr_accessor :cancel_before_save, :cancel_before_create, :cancel_before_update, :cancel_before_destroy - before_save { !@cancel_before_save } + before_save {defined?(@cancel_before_save) ? !@cancel_before_save : false} before_create { !@cancel_before_create } before_update { !@cancel_before_update } before_destroy { !@cancel_before_destroy } @@ -437,10 +442,8 @@ class CallbacksTest < ActiveRecord::TestCase end private :assert_save_callbacks_not_called - def test_zzz_callback_returning_false # must be run last since we modify CallbackDeveloper - david = CallbackDeveloper.find(1) - CallbackDeveloper.before_validation proc { |model| model.history << [:before_validation, :returning_false]; return false } - CallbackDeveloper.before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] } + def test_callback_returning_false + david = CallbackDeveloperWithFalseValidation.find(1) david.save assert_equal [ [ :after_find, :method ], diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index b4032c23e6..bba216ae19 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -24,7 +24,7 @@ class DefaultTest < ActiveRecord::TestCase assert_instance_of Fixnum, default.positive_integer assert_equal 1, default.positive_integer assert_instance_of Fixnum, default.negative_integer - assert_equal -1, default.negative_integer + assert_equal(-1, default.negative_integer) assert_instance_of BigDecimal, default.decimal_number assert_equal BigDecimal.new("2.78"), default.decimal_number end @@ -33,7 +33,7 @@ class DefaultTest < ActiveRecord::TestCase if current_adapter?(:PostgreSQLAdapter) def test_multiline_default_text # older postgres versions represent the default with escapes ("\\012" for a newline) - assert ( "--- []\n\n" == Default.columns_hash['multiline_default'].default || + assert( "--- []\n\n" == Default.columns_hash['multiline_default'].default || "--- []\\012\\012" == Default.columns_hash['multiline_default'].default) end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 4961d12a44..a64ccb2120 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -26,6 +26,11 @@ class NumericData < ActiveRecord::Base end class DirtyTest < ActiveRecord::TestCase + # Dummy to force column loads so query counts are clean. + def setup + Person.create :first_name => 'foo' + end + def test_attribute_changes # New record - no changes. pirate = Pirate.new diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index d2451f24c1..9e88ec8016 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -502,6 +502,18 @@ class FinderTest < ActiveRecord::TestCase assert_kind_of Time, Topic.find(:first, :conditions => ["id = :id", { :id => 1 }]).written_on end + class SimpleEnumerable + include Enumerable + + def initialize(ary) + @ary = ary + end + + def each(&b) + @ary.each(&b) + end + end + def test_bind_enumerable quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')}) @@ -511,12 +523,11 @@ class FinderTest < ActiveRecord::TestCase assert_equal '1,2,3', bind(':a', :a => [1, 2, 3]) assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # ' - require 'set' - assert_equal '1,2,3', bind('?', Set.new([1, 2, 3])) - assert_equal quoted_abc, bind('?', Set.new(%w(a b c))) + assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3])) + assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c))) - assert_equal '1,2,3', bind(':a', :a => Set.new([1, 2, 3])) - assert_equal quoted_abc, bind(':a', :a => Set.new(%w(a b c))) # ' + assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3])) + assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # ' end def test_bind_empty_enumerable diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index f965652a9a..e78b522b65 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -244,14 +244,14 @@ class FixturesWithoutInstantiationTest < ActiveRecord::TestCase fixtures :topics, :developers, :accounts def test_without_complete_instantiation - assert_nil @first - assert_nil @topics - assert_nil @developers - assert_nil @accounts + assert !defined?(@first) + assert !defined?(@topics) + assert !defined?(@developers) + assert !defined?(@accounts) end def test_fixtures_from_root_yml_without_instantiation - assert_nil @unknown + assert !defined?(@unknown), "@unknown is not defined" end def test_accessor_methods @@ -279,7 +279,7 @@ class FixturesWithoutInstanceInstantiationTest < ActiveRecord::TestCase fixtures :topics, :developers, :accounts def test_without_instance_instantiation - assert_nil @first + assert !defined?(@first), "@first is not defined" assert_not_nil @topics assert_not_nil @developers assert_not_nil @accounts diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 54bc8e2343..a3145d2c04 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -27,6 +27,8 @@ class JsonSerializationTest < ActiveRecord::TestCase @contact = NamespacedContact.new :name => 'whatever' json = @contact.to_json assert_match %r{^\{"namespaced_contact":\{}, json + ensure + NamespacedContact.include_root_in_json = false end def test_should_include_root_in_json diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index aa7ce2ecb6..fcad3e90d3 100644 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -6,25 +6,6 @@ require 'models/minimalistic' class SpecialDeveloper < Developer; end -class TopicManualObserver - include Singleton - - attr_reader :action, :object, :callbacks - - def initialize - Topic.add_observer(self) - @callbacks = [] - end - - def update(callback_method, object) - @callbacks << { "callback_method" => callback_method, "object" => object } - end - - def has_been_notified? - !@callbacks.empty? - end -end - class TopicaAuditor < ActiveRecord::Observer observe :topic @@ -85,27 +66,6 @@ class LifecycleTest < ActiveRecord::TestCase assert_equal original_count - (1 + topic_to_be_destroyed.replies.size), Topic.count end - def test_after_save - ActiveRecord::Base.observers = :topic_manual_observer - ActiveRecord::Base.instantiate_observers - - topic = Topic.find(1) - topic.title = "hello" - topic.save - - assert TopicManualObserver.instance.has_been_notified? - assert_equal :after_save, TopicManualObserver.instance.callbacks.last["callback_method"] - end - - def test_observer_update_on_save - ActiveRecord::Base.observers = TopicManualObserver - ActiveRecord::Base.instantiate_observers - - topic = Topic.find(1) - assert TopicManualObserver.instance.has_been_notified? - assert_equal :after_find, TopicManualObserver.instance.callbacks.first["callback_method"] - end - def test_auto_observer topic_observer = TopicaAuditor.instance assert_nil TopicaAuditor.observed_class diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index f3b94eb829..6ba84fa57b 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -26,8 +26,8 @@ class LogSubscriberTest < ActiveSupport::TestCase Developer.all wait assert_equal 1, @logger.logged(:debug).size - assert_match /Developer Load/, @logger.logged(:debug).last - assert_match /SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last + assert_match(/Developer Load/, @logger.logged(:debug).last) + assert_match(/SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last) end def test_cached_queries @@ -37,7 +37,7 @@ class LogSubscriberTest < ActiveSupport::TestCase end wait assert_equal 2, @logger.logged(:debug).size - assert_match /CACHE/, @logger.logged(:debug).last - assert_match /SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last + assert_match(/CACHE/, @logger.logged(:debug).last) + assert_match(/SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last) end -end
\ No newline at end of file +end diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 3151457440..a3b496a0e6 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -382,7 +382,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => "salary < 100000" }) do Developer.send(:with_scope, :find => { :offset => 1, :order => 'id asc' }) do # Oracle adapter does not generated space after asc therefore trailing space removed from regex - assert_sql /ORDER BY id asc/ do + assert_sql(/ORDER BY id asc/) do assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc')) end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index dd32eeeff2..e213986ede 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -477,7 +477,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_not_equal "Z", bob.moment_of_truth.zone # US/Eastern is -5 hours from GMT assert_equal Rational(-5, 24), bob.moment_of_truth.offset - assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM + assert_match(/\A-05:?00\Z/, bob.moment_of_truth.zone) #ruby 1.8.6 uses HH:MM, prior versions use HHMM assert_equal DateTime::ITALY, bob.moment_of_truth.start end end @@ -493,7 +493,7 @@ if ActiveRecord::Base.connection.supports_migrations? ActiveRecord::Migration.add_column :people, :intelligence_quotient, :tinyint Person.reset_column_information - assert_match /tinyint/, Person.columns_hash['intelligence_quotient'].sql_type + assert_match(/tinyint/, Person.columns_hash['intelligence_quotient'].sql_type) ensure ActiveRecord::Migration.remove_column :people, :intelligence_quotient rescue nil end @@ -1104,13 +1104,25 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal migrations[0].name, 'InnocentJointable' end + def test_relative_migrations + $".delete_if do |fname| + fname == (MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb") + end + Object.send(:remove_const, :PeopleHaveLastNames) + + Dir.chdir(MIGRATIONS_ROOT) do + ActiveRecord::Migrator.up("valid/", 1) + end + + assert defined?(PeopleHaveLastNames) + end + def test_only_loads_pending_migrations # migrate up to 1 ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1) # now unload the migrations that have been defined - PeopleHaveLastNames.unloadable - ActiveSupport::Dependencies.remove_unloadable_constants! + Object.send(:remove_const, :PeopleHaveLastNames) ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 894d96346e..6c2b4fa3a7 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -83,8 +83,8 @@ class NamedScopeTest < ActiveRecord::TestCase end def test_scopes_are_composable - assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved - assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied + assert_equal((approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved) + assert_equal((replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied) assert !(approved == replied) assert !(approved & replied).empty? diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 3710f8e40b..91349689bc 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -10,6 +10,10 @@ require 'models/post' class QueryCacheTest < ActiveRecord::TestCase fixtures :tasks, :topics, :categories, :posts, :categories_posts + def setup + Task.connection.clear_query_cache + end + def test_find_queries assert_queries(2) { Task.find(1); Task.find(1) } end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 2c9158aa7b..67818622d7 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -22,12 +22,6 @@ class ReflectionTest < ActiveRecord::TestCase assert_equal "Subscriber", Subscriber.model_name.human end - def test_column_null_not_null - subscriber = Subscriber.find(:first) - assert subscriber.column_for_attribute("name").null - assert !subscriber.column_for_attribute("nick").null - end - def test_read_attribute_names assert_equal( %w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id parent_title type ).sort, diff --git a/activerecord/test/cases/schema_authorization_test_postgresql.rb b/activerecord/test/cases/schema_authorization_test_postgresql.rb index ba7754513d..2860f1ad48 100644 --- a/activerecord/test/cases/schema_authorization_test_postgresql.rb +++ b/activerecord/test/cases/schema_authorization_test_postgresql.rb @@ -66,6 +66,15 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase end end end + + def test_tables_in_current_schemas + assert !@connection.tables.include?(TABLE_NAME) + USERS.each do |u| + set_session_auth u + assert @connection.tables.include?(TABLE_NAME) + set_session_auth + end + end private def set_session_auth auth = nil diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index aca70b4238..c550030329 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -51,6 +51,7 @@ class TransactionTest < ActiveRecord::TestCase assert !Topic.find(2).approved?, "Second should have been unapproved" ensure class << Topic.connection + remove_method :commit_db_transaction alias :commit_db_transaction :real_commit_db_transaction rescue nil end end @@ -382,28 +383,53 @@ class TransactionTest < ActiveRecord::TestCase private def add_exception_raising_after_save_callback_to_topic - Topic.class_eval "def after_save_for_transaction; raise 'Make the transaction rollback' end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method(:after_save_for_transaction) + def after_save_for_transaction + raise 'Make the transaction rollback' + end + eoruby end def remove_exception_raising_after_save_callback_to_topic - Topic.class_eval "def after_save_for_transaction; end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method :after_save_for_transaction + def after_save_for_transaction; end + eoruby end def add_exception_raising_after_create_callback_to_topic - Topic.class_eval "def after_create_for_transaction; raise 'Make the transaction rollback' end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method(:after_create_for_transaction) + def after_create_for_transaction + raise 'Make the transaction rollback' + end + eoruby end def remove_exception_raising_after_create_callback_to_topic - Topic.class_eval "def after_create_for_transaction; end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method :after_create_for_transaction + def after_create_for_transaction; end + eoruby end %w(validation save destroy).each do |filter| define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do - Topic.class_eval "def before_#{filter}_for_transaction() Book.create; false end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method :before_#{filter}_for_transaction + def before_#{filter}_for_transaction + Book.create + false + end + eoruby end define_method("remove_cancelling_before_#{filter}_with_db_side_effect_to_topic") do - Topic.class_eval "def before_#{filter}_for_transaction; end" + Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1 + remove_method :before_#{filter}_for_transaction + def before_#{filter}_for_transaction; end + eoruby end end end diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index a0ff35f948..38fa2b821d 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -47,25 +47,6 @@ class I18nValidationTest < ActiveRecord::TestCase @topic.valid? end - # validates_uniqueness_of w/o mocha - - def test_validates_associated_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:taken => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:taken => 'global message'}}} - - Topic.validates_uniqueness_of :title - unique_topic.valid? - assert_equal ['custom message'], unique_topic.errors[:replies] - end - - def test_validates_associated_finds_global_default_translation - I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:taken => 'global message'}}} - - Topic.validates_uniqueness_of :title - unique_topic.valid? - assert_equal ['global message'], unique_topic.errors[:replies] - end - # validates_associated w/ mocha def test_validates_associated_generates_message diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index b841108bd1..67296a171a 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -625,6 +625,22 @@ module ActiveResource "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}" end + # Gets the new element path for REST resources. + # + # ==== Options + # * +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt> + # would yield a URL like <tt>/accounts/19/purchases/new.xml</tt>). + # + # ==== Examples + # Post.new_element_path + # # => /posts/new.xml + # + # Comment.collection_path(:post_id => 5) + # # => /posts/5/comments/new.xml + def new_element_path(prefix_options = {}) + "#{prefix(prefix_options)}#{collection_name}/new.#{format.extension}" + end + # Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails # will split from the +prefix_options+. # @@ -653,6 +669,19 @@ module ActiveResource alias_method :set_primary_key, :primary_key= #:nodoc: + # Builds a new, unsaved record using the default values from the remote server so + # that it can be used with RESTful forms. + # + # ==== Options + # * +attributes+ - A hash that overrides the default values from the server. + # + # Returns the new resource instance. + # + def build(attributes = {}) + attrs = connection.get("#{new_element_path}").merge(attributes) + self.new(attrs) + end + # Creates a new resource instance and makes a request to the remote service # that it be saved, making it equivalent to the following simultaneous calls: # @@ -989,6 +1018,22 @@ module ActiveResource end alias :new_record? :new? + # Returns +true+ if this object has been saved, otherwise returns +false+. + # + # ==== Examples + # persisted = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall') + # persisted.persisted? # => true + # + # not_persisted = Computer.new(:brand => 'IBM', :make => 'Thinkpad', :vendor => 'IBM') + # not_persisted.persisted? # => false + # + # not_persisted.save + # not_persisted.persisted? # => true + # + def persisted? + !new? + end + # Gets the <tt>\id</tt> attribute of the resource. def id attributes[self.class.primary_key] @@ -1346,6 +1391,10 @@ module ActiveResource self.class.element_path(to_param, options || prefix_options) end + def new_element_path + self.class.new_element_path(prefix_options) + end + def collection_path(options = nil) self.class.collection_path(options || prefix_options) end diff --git a/activeresource/lib/active_resource/railtie.rb b/activeresource/lib/active_resource/railtie.rb index 27c88415f6..aa878c7212 100644 --- a/activeresource/lib/active_resource/railtie.rb +++ b/activeresource/lib/active_resource/railtie.rb @@ -3,10 +3,10 @@ require "rails" module ActiveResource class Railtie < Rails::Railtie - railtie_name :active_resource + config.active_resource = ActiveSupport::OrderedOptions.new require "active_resource/railties/log_subscriber" - log_subscriber ActiveResource::Railties::LogSubscriber.new + log_subscriber :active_resource, ActiveResource::Railties::LogSubscriber.new initializer "active_resource.set_configs" do |app| app.config.active_resource.each do |k,v| diff --git a/activeresource/test/setter_trap.rb b/activeresource/test/setter_trap.rb index 7cfd9ca111..437fbdad32 100644 --- a/activeresource/test/setter_trap.rb +++ b/activeresource/test/setter_trap.rb @@ -1,3 +1,5 @@ +require 'abstract_unit' + class SetterTrap < ActiveSupport::BasicObject class << self def rollback_sets(obj) diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index 78fb48924e..bfb1e83002 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -18,8 +18,8 @@ Gem::Specification.new do |s| s.has_rdoc = true - s.add_dependency('i18n', '~> 0.3.6.pre') + s.add_dependency('i18n', '~> 0.3.6') s.add_dependency('tzinfo', '~> 0.3.16') s.add_dependency('builder', '~> 2.1.2') - s.add_dependency('memcache-client', '~> 1.7.5') + s.add_dependency('memcache-client', '>= 1.7.5') end diff --git a/activesupport/lib/active_support/core_ext/array/extract_options.rb b/activesupport/lib/active_support/core_ext/array/extract_options.rb index 9ca32dc7aa..40ceb3eb9e 100644 --- a/activesupport/lib/active_support/core_ext/array/extract_options.rb +++ b/activesupport/lib/active_support/core_ext/array/extract_options.rb @@ -1,3 +1,14 @@ +class Hash + # By default, only instances of Hash itself are extractable. + # Subclasses of Hash may implement this method and return + # true to declare themselves as extractable. If a Hash + # is extractable, Array#extract_options! pops it from + # the Array when it is the last element of the Array. + def extractable_options? + instance_of?(Hash) + end +end + class Array # Extracts options from a set of arguments. Removes and returns the last # element in the array if it's a hash, otherwise returns a blank hash. @@ -9,6 +20,10 @@ class Array # options(1, 2) # => {} # options(1, 2, :a => :b) # => {:a=>:b} def extract_options! - last.is_a?(::Hash) ? pop : {} + if last.is_a?(Hash) && last.extractable_options? + pop + else + {} + end end end diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index c18905b369..9631a7d242 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/object/singleton_class' require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/module/remove_method' class Class # Declare a class-level attribute whose value is inheritable and @@ -45,12 +46,14 @@ class Class s.send(:define_method, attr) { } s.send(:define_method, :"#{attr}?") { !!send(attr) } s.send(:define_method, :"#{attr}=") do |value| + singleton_class.remove_possible_method(attr) singleton_class.send(:define_method, attr) { value } end define_method(attr) { self.class.send(attr) } define_method(:"#{attr}?") { !!send(attr) } define_method(:"#{attr}=") do |value| + singleton_class.remove_possible_method(attr) singleton_class.send(:define_method, attr) { value } end if instance_writer end diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb index 1602a609eb..feef5d2d57 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -10,42 +10,48 @@ require 'active_support/core_ext/array/extract_options' # Person.hair_colors = [:brown, :black, :blonde, :red] class Class def cattr_reader(*syms) - syms.flatten.each do |sym| - next if sym.is_a?(Hash) + options = syms.extract_options! + syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} # unless defined? @@hair_colors - @@#{sym} = nil # @@hair_colors = nil - end # end - # - def self.#{sym} # def self.hair_colors - @@#{sym} # @@hair_colors - end # end - # - def #{sym} # def hair_colors - @@#{sym} # @@hair_colors - end # end + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym} + @@#{sym} + end EOS + + unless options[:instance_reader] == false + class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def #{sym} + @@#{sym} + end + EOS + end end end def cattr_writer(*syms) options = syms.extract_options! - syms.flatten.each do |sym| + syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} # unless defined? @@hair_colors - @@#{sym} = nil # @@hair_colors = nil - end # end - # - def self.#{sym}=(obj) # def self.hair_colors=(obj) - @@#{sym} = obj # @@hair_colors = obj - end # end - # - #{" # - def #{sym}=(obj) # def hair_colors=(obj) - @@#{sym} = obj # @@hair_colors = obj - end # end - " unless options[:instance_writer] == false } # # instance writer above is generated unless options[:instance_writer] == false + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym}=(obj) + @@#{sym} = obj + end EOS + + unless options[:instance_writer] == false + class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def #{sym}=(obj) + @@#{sym} = obj + end + EOS + end self.send("#{sym}=", yield) if block_given? end end diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb index b5785bdcd3..12caa76c98 100644 --- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/object/singleton_class' +require 'active_support/core_ext/module/remove_method' class Class def superclass_delegating_accessor(name, options = {}) @@ -27,7 +28,9 @@ private # inheritance behavior, without having to store the object in an instance # variable and look up the superclass chain manually. def _stash_object_in_method(object, method, instance_reader = true) + singleton_class.remove_possible_method(method) singleton_class.send(:define_method, method) { object } + remove_possible_method(method) define_method(method) { object } if instance_reader end @@ -35,7 +38,7 @@ private singleton_class.send(:define_method, "#{name}=") do |value| _stash_object_in_method(value, name, options[:instance_reader] != false) end - self.send("#{name}=", nil) + send("#{name}=", nil) end end diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index 47a31839a6..a9f821b01e 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -1,4 +1,5 @@ require 'active_support/inflector' +require 'active_support/core_ext/time/conversions' class DateTime # Ruby 1.9 has DateTime#to_time which internally relies on Time. We define our own #to_time which allows diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 48b185d05e..c882434f78 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -54,6 +54,15 @@ class Hash "string" => Proc.new { |string| string.to_s }, "yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml }, "base64Binary" => Proc.new { |bin| ActiveSupport::Base64.decode64(bin) }, + "binary" => Proc.new do |bin, entity| + case entity['encoding'] + when 'base64' + ActiveSupport::Base64.decode64(bin) + # TODO: Add support for other encodings + else + bin + end + end, "file" => Proc.new do |file, entity| f = StringIO.new(ActiveSupport::Base64.decode64(file)) f.extend(FileLike) diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb index d9b84e6543..ac35db6ab6 100644 --- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb +++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb @@ -37,7 +37,7 @@ module Kernel # puts 'But this will' def silence_stream(stream) old_stream = stream.dup - stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') + stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') stream.sync = true yield ensure diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index bf272e9e73..f59fcd123c 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -7,4 +7,6 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/attr_accessor_with_default' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/module/synchronization' -require 'active_support/core_ext/module/deprecation'
\ No newline at end of file +require 'active_support/core_ext/module/deprecation' +require 'active_support/core_ext/module/remove_method' +require 'active_support/core_ext/module/method_names'
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 131b512944..9c4d5fae26 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -2,21 +2,25 @@ require 'active_support/core_ext/array/extract_options' class Module def mattr_reader(*syms) - syms.extract_options! + options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} # unless defined? @@pagination_options - @@#{sym} = nil # @@pagination_options = nil - end # end - - def self.#{sym} # def self.pagination_options - @@#{sym} # @@pagination_options - end # end + unless defined? @@#{sym} + @@#{sym} = nil + end - def #{sym} # def pagination_options - @@#{sym} # @@pagination_options - end # end + def self.#{sym} + @@#{sym} + end EOS + + unless options[:instance_reader] == false + class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def #{sym} + @@#{sym} + end + EOS + end end end @@ -24,20 +28,20 @@ class Module options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} # unless defined? @@pagination_options - @@#{sym} = nil # @@pagination_options = nil - end # end + unless defined? @@#{sym} + @@#{sym} = nil + end - def self.#{sym}=(obj) # def self.pagination_options=(obj) - @@#{sym} = obj # @@pagination_options = obj - end # end + def self.#{sym}=(obj) + @@#{sym} = obj + end EOS unless options[:instance_writer] == false - class_eval(<<-EOS, __FILE__, __LINE__) - def #{sym}=(obj) # def pagination_options=(obj) - @@#{sym} = obj # @@pagination_options = obj - end # end + class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def #{sym}=(obj) + @@#{sym} = obj + end EOS end end diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 381181b2f4..b73f4c2b59 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/module/remove_method" + class Module # Provides a delegate class method to easily expose contained objects' methods # as your own. Pass one or more methods (specified as symbols or strings) @@ -39,7 +41,7 @@ class Module # class Foo # CONSTANT_ARRAY = [0,1,2,3] # @@class_array = [4,5,6,7] - # + # # def initialize # @instance_array = [8,9,10,11] # end @@ -125,6 +127,10 @@ class Module end module_eval(<<-EOS, file, line) + if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}") + remove_possible_method("#{prefix}#{method}") + end + def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block) rescue NoMethodError # rescue NoMethodError diff --git a/activesupport/lib/active_support/core_ext/module/method_names.rb b/activesupport/lib/active_support/core_ext/module/method_names.rb new file mode 100644 index 0000000000..2eb40a83ab --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/method_names.rb @@ -0,0 +1,14 @@ +class Module + if instance_methods[0].is_a?(Symbol) + def instance_method_names(*args) + instance_methods(*args).map(&:to_s) + end + + def method_names(*args) + methods(*args).map(&:to_s) + end + else + alias_method :instance_method_names, :instance_methods + alias_method :method_names, :methods + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb new file mode 100644 index 0000000000..2714a46b28 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb @@ -0,0 +1,6 @@ +class Module + def remove_possible_method(method) + remove_method(method) + rescue NameError + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index fbb7b79fc6..48b028bb64 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -1,5 +1,3 @@ -require 'active_support/inflector' - # String inflections define new methods on the String class to transform names for different purposes. # For instance, you can figure out the name of a database from the name of a class. # 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 9a7c520e75..3ee5bcaab4 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,4 +1,5 @@ -require "erb" +require 'erb' +require 'active_support/core_ext/object/singleton_class' class ERB module Util @@ -23,12 +24,14 @@ class ERB end end - undef :h + remove_method(:h) alias h html_escape - module_function :html_escape module_function :h + singleton_class.send(:remove_method, :html_escape) + module_function :html_escape + # A utility method for escaping HTML entities in JSON strings. # This method is also aliased as <tt>j</tt>. # diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index 6d9c080442..86103ebce2 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -1,4 +1,5 @@ require 'active_support/inflector' +require 'active_support/core_ext/time/publicize_conversion_methods' require 'active_support/values/time_zone' class Time diff --git a/activesupport/lib/active_support/core_ext/time/marshal_with_utc_flag.rb b/activesupport/lib/active_support/core_ext/time/marshal_with_utc_flag.rb index 9de8157eb0..8d46d80251 100644 --- a/activesupport/lib/active_support/core_ext/time/marshal_with_utc_flag.rb +++ b/activesupport/lib/active_support/core_ext/time/marshal_with_utc_flag.rb @@ -7,14 +7,18 @@ if RUBY_VERSION < '1.9' alias_method :_original_load, :_load def _load(marshaled_time) time = _original_load(marshaled_time) - utc = time.instance_variable_get('@marshal_with_utc_coercion') - utc ? time.utc : time + time.instance_eval do + if defined?(@marshal_with_utc_coercion) + val = remove_instance_variable("@marshal_with_utc_coercion") + end + val ? utc : self + end end end alias_method :_original_dump, :_dump def _dump(*args) - obj = frozen? ? dup : self + obj = dup obj.instance_variable_set('@marshal_with_utc_coercion', utc?) obj._original_dump(*args) end diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 543dab4a75..8241b69c8b 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -4,6 +4,10 @@ module ActiveSupport class HashWithIndifferentAccess < Hash + def extractable_options? + true + end + def initialize(constructor = {}) if constructor.is_a?(Hash) super() diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb index 236f2eb628..2ce27cf406 100644 --- a/activesupport/lib/active_support/inflector/transliterate.rb +++ b/activesupport/lib/active_support/inflector/transliterate.rb @@ -14,8 +14,8 @@ module ActiveSupport if RUBY_VERSION >= '1.9' undef_method :transliterate def transliterate(string) - warn "Ruby 1.9 doesn't support Unicode normalization yet" - string.dup + proxy = ActiveSupport::Multibyte.proxy_class.new(string) + proxy.normalize(:kd).gsub(/[^\x00-\x7F]+/, '') end # The iconv transliteration code doesn't function correctly diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb index 7e6f7d754b..428c48a484 100644 --- a/activesupport/lib/active_support/multibyte.rb +++ b/activesupport/lib/active_support/multibyte.rb @@ -53,8 +53,8 @@ module ActiveSupport #:nodoc: \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf])\z /xn, # Quick check for valid Shift-JIS characters, disregards the odd-even pairing 'Shift_JIS' => /\A(?: - [\x00-\x7e \xa1-\xdf] | - [\x81-\x9f \xe0-\xef] [\x40-\x7e \x80-\x9e \x9f-\xfc])\z /xn + [\x00-\x7e\xa1-\xdf] | + [\x81-\x9f\xe0-\xef] [\x40-\x7e\x80-\x9e\x9f-\xfc])\z /xn } end end diff --git a/activesupport/lib/active_support/multibyte/utils.rb b/activesupport/lib/active_support/multibyte/utils.rb index b243df46d8..94b393cee2 100644 --- a/activesupport/lib/active_support/multibyte/utils.rb +++ b/activesupport/lib/active_support/multibyte/utils.rb @@ -27,7 +27,7 @@ module ActiveSupport #:nodoc: def self.verify(string) if expression = valid_character # Splits the string on character boundaries, which are determined based on $KCODE. - string.split(//).all? { |c| expression.match(c) } + string.split(//).all? { |c| expression =~ c } else true end diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index cd60054862..a3ddc7705a 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -44,7 +44,7 @@ module ActiveSupport when Regexp, NilClass pattern else - /^#{Regexp.escape(pattern.to_s)}/ + /^#{Regexp.escape(pattern.to_s)}$/ end end diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index d2c13e030d..e45d16ee96 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -3,7 +3,7 @@ require "rails" module ActiveSupport class Railtie < Rails::Railtie - railtie_name :active_support + config.active_support = ActiveSupport::OrderedOptions.new # Loads support for "whiny nil" (noisy warnings when methods are invoked # on +nil+ values) if Configuration#whiny_nils is true. @@ -30,9 +30,7 @@ end module I18n class Railtie < Rails::Railtie - railtie_name :i18n - - # Initialize I18n load paths to an array + config.i18n = ActiveSupport::OrderedOptions.new config.i18n.railties_load_path = [] config.i18n.load_path = [] diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb index f0db5b3021..4a9ac920e8 100644 --- a/activesupport/lib/active_support/ruby/shim.rb +++ b/activesupport/lib/active_support/ruby/shim.rb @@ -18,3 +18,4 @@ require 'active_support/core_ext/string/interpolation' require 'active_support/core_ext/rexml' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/file/path' +require 'active_support/core_ext/module/method_names'
\ No newline at end of file diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index ab30984d62..ed8c02ba3e 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -5,9 +5,10 @@ require 'active_support/testing/deprecation' require 'active_support/testing/declarative' require 'active_support/testing/pending' require 'active_support/testing/isolation' +require 'active_support/core_ext/kernel/reporting' begin - require 'mocha' + silence_warnings { require 'mocha' } rescue LoadError # Fake Mocha::ExpectationError so we can rescue it in #run. Bleh. Object.const_set :Mocha, Module.new diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 453f4fcc0f..9507dbf473 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -78,8 +78,8 @@ module ActiveSupport @@ran_class_setup = true end - serialized = run_in_isolation do |runner| - super(runner) + serialized = run_in_isolation do |isolated_runner| + super(isolated_runner) end retval, proxy = Marshal.load(serialized) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 4db3dd1705..3cb4d89e02 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -305,8 +305,8 @@ module ActiveSupport # TODO: Preload instead of lazy load for thread safety def tzinfo - require 'tzinfo' unless defined?(TZInfo) - @tzinfo ||= TZInfo::Timezone.get(MAPPING[name]) + require 'tzinfo' unless defined?(::TZInfo) + @tzinfo ||= ::TZInfo::Timezone.get(MAPPING[name]) end unless const_defined?(:ZONES) diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index da338a2a26..67f652325e 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,10 +1,17 @@ -require File.expand_path('../../../load_paths', __FILE__) +begin + old, $VERBOSE = $VERBOSE, nil + require File.expand_path('../../../load_paths', __FILE__) +ensure + $VERBOSE = old +end lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) require 'test/unit' -require 'mocha' +require 'active_support/core_ext/kernel/reporting' + +silence_warnings { require 'mocha' } ENV['NO_RELOAD'] = '1' require 'active_support' diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb index e74c64ba8d..8caf000c5d 100644 --- a/activesupport/test/callback_inheritance_test.rb +++ b/activesupport/test/callback_inheritance_test.rb @@ -1,3 +1,4 @@ +require 'abstract_unit' require 'test/unit' require 'active_support' diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 3fb940ad3c..49d9de63b0 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,4 +1,4 @@ -# require 'abstract_unit' +require 'abstract_unit' require 'test/unit' require 'active_support' diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index b374eca370..aecc644549 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/big_decimal' require 'active_support/core_ext/object/conversions' require 'active_support/core_ext' # FIXME: pulling in all to_xml extensions +require 'active_support/hash_with_indifferent_access' class ArrayExtAccessTests < Test::Unit::TestCase def test_from @@ -294,12 +295,45 @@ class ArrayToXmlTests < Test::Unit::TestCase end class ArrayExtractOptionsTests < Test::Unit::TestCase + class HashSubclass < Hash + end + + class ExtractableHashSubclass < Hash + def extractable_options? + true + end + end + def test_extract_options assert_equal({}, [].extract_options!) assert_equal({}, [1].extract_options!) assert_equal({:a=>:b}, [{:a=>:b}].extract_options!) assert_equal({:a=>:b}, [1, {:a=>:b}].extract_options!) end + + def test_extract_options_doesnt_extract_hash_subclasses + hash = HashSubclass.new + hash[:foo] = 1 + array = [hash] + options = array.extract_options! + assert_equal({}, options) + assert_equal [hash], array + end + + def test_extract_options_extracts_extractable_subclass + hash = ExtractableHashSubclass.new + hash[:foo] = 1 + array = [hash] + options = array.extract_options! + assert_equal({:foo => 1}, options) + assert_equal [], array + end + + def test_extract_options_extracts_hwia + hash = [{:foo => 1}.with_indifferent_access] + options = hash.extract_options! + assert_equal 1, options[:foo] + end end class ArrayUniqByTests < Test::Unit::TestCase diff --git a/activesupport/test/core_ext/class/attribute_accessor_test.rb b/activesupport/test/core_ext/class/attribute_accessor_test.rb index 2214ba9894..0f579d12e5 100644 --- a/activesupport/test/core_ext/class/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/class/attribute_accessor_test.rb @@ -5,7 +5,8 @@ class ClassAttributeAccessorTest < Test::Unit::TestCase def setup @class = Class.new do cattr_accessor :foo - cattr_accessor :bar, :instance_writer => false + cattr_accessor :bar, :instance_writer => false + cattr_reader :shaq, :instance_reader => false end @object = @class.new end @@ -29,4 +30,9 @@ class ClassAttributeAccessorTest < Test::Unit::TestCase assert @object.respond_to?(:bar) assert !@object.respond_to?(:bar=) end + + def test_should_not_create_instance_reader + assert @class.respond_to?(:shaq) + assert !@object.respond_to?(:shaq) + end end diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb index 636edb8d4b..6d6cb61571 100644 --- a/activesupport/test/core_ext/class/delegating_attributes_test.rb +++ b/activesupport/test/core_ext/class/delegating_attributes_test.rb @@ -11,6 +11,13 @@ module DelegatingFixtures class Mokopuna < Child end + + class PercysMom + superclass_delegating_accessor :superpower + end + + class Percy < PercysMom + end end class DelegatingAttributesTest < Test::Unit::TestCase @@ -70,18 +77,17 @@ class DelegatingAttributesTest < Test::Unit::TestCase end def test_delegation_stops_at_the_right_level - assert_nil Mokopuna.some_attribute - assert_nil Child.some_attribute - Child.some_attribute="1" - assert_equal "1", Mokopuna.some_attribute - ensure - Child.some_attribute=nil + assert_nil Percy.superpower + assert_nil PercysMom.superpower + + PercysMom.superpower = :heatvision + assert_equal :heatvision, Percy.superpower end - + def test_delegation_stops_for_nil Mokopuna.some_attribute = nil Child.some_attribute="1" - + assert_equal "1", Child.some_attribute assert_nil Mokopuna.some_attribute ensure diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 5b1d53ac7b..86272a28c1 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -757,6 +757,7 @@ class HashToXmlTest < Test::Unit::TestCase <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at> <notes type="string"></notes> <illustration type="base64Binary">YmFiZS5wbmc=</illustration> + <caption type="binary" encoding="base64">VGhhdCdsbCBkbywgcGlnLg==</caption> </bacon> EOT @@ -766,7 +767,8 @@ class HashToXmlTest < Test::Unit::TestCase :price => BigDecimal("12.50"), :expires_at => Time.utc(2007,12,25,12,34,56), :notes => "", - :illustration => "babe.png" + :illustration => "babe.png", + :caption => "That'll do, pig." }.stringify_keys assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"] diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index bd9461e62c..263e78feaa 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -6,6 +6,7 @@ class ModuleAttributeAccessorTest < Test::Unit::TestCase m = @module = Module.new do mattr_accessor :foo mattr_accessor :bar, :instance_writer => false + mattr_reader :shaq, :instance_reader => false end @class = Class.new @class.instance_eval { include m } @@ -31,4 +32,9 @@ class ModuleAttributeAccessorTest < Test::Unit::TestCase assert @object.respond_to?(:bar) assert !@object.respond_to?(:bar=) end + + def test_should_not_create_instance_reader + assert @module.respond_to?(:shaq) + assert !@object.respond_to?(:shaq) + end end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 9edd7cc7c0..1712b0649b 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -141,6 +141,20 @@ class ModuleTest < Test::Unit::TestCase assert_equal 0.0, nil_project.to_f end + def test_delegation_does_not_raise_error_when_removing_singleton_instance_methods + parent = Class.new do + def self.parent_method; end + end + + assert_nothing_raised do + child = Class.new(parent) do + class << self + delegate :parent_method, :to => :superclass + end + end + end + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index a50e259726..234e41c772 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -285,7 +285,7 @@ class TestGetTextString < Test::Unit::TestCase def test_percent assert_equal("% 1", "%% %<num>d" % {:num => 1.0}) - assert_equal("%{num} %<num>d", "%%{num} %%<num>d" % {:num => 1}) + assert_equal("%{num} %<num>d 1", "%%{num} %%<num>d %<num>d" % {:num => 1}) end def test_sprintf_percent_in_replacement diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 08c079e113..159b7d8366 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -761,7 +761,7 @@ class TimeExtMarshalingTest < Test::Unit::TestCase marshaled = Marshal.dump t unmarshaled = Marshal.load marshaled assert_equal t, unmarshaled - assert_equal t.zone, unmarshaled.zone + assert_equal "UTC", unmarshaled.zone end def test_marshaling_with_local_instance @@ -777,7 +777,7 @@ class TimeExtMarshalingTest < Test::Unit::TestCase marshaled = Marshal.dump t unmarshaled = Marshal.load marshaled assert_equal t, unmarshaled - assert_equal t.zone, unmarshaled.zone + assert_equal "UTC", unmarshaled.zone end def test_marshaling_with_frozen_local_instance diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 6ff6dfb607..2cbf9e5042 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -88,7 +88,7 @@ class DependenciesTest < Test::Unit::TestCase old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true filename = "check_warnings" - expanded = File.expand_path("test/dependencies/#{filename}") + expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}") $check_warnings_load_count = 0 assert !ActiveSupport::Dependencies.loaded.include?(expanded) diff --git a/activesupport/test/flush_cache_on_private_memoization_test.rb b/activesupport/test/flush_cache_on_private_memoization_test.rb index 1cd313ec81..91b856ed7c 100644 --- a/activesupport/test/flush_cache_on_private_memoization_test.rb +++ b/activesupport/test/flush_cache_on_private_memoization_test.rb @@ -1,3 +1,4 @@ +require 'abstract_unit' require 'active_support' require 'test/unit' diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index ebd26d3fc6..56372903f3 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -180,18 +180,10 @@ module InflectorTestCases "Test with + sign" => "test_with_sign" } - # Ruby 1.9 doesn't do Unicode normalization yet. - if RUBY_VERSION >= '1.9' - StringToParameterizedAndNormalized = { - "Malmö" => "malm", - "Garçons" => "gar-ons" - } - else - StringToParameterizedAndNormalized = { - "Malmö" => "malmo", - "Garçons" => "garcons" - } - end + StringToParameterizedAndNormalized = { + "Malmö" => "malmo", + "Garçons" => "garcons" + } UnderscoreToHuman = { "employee_salary" => "Employee salary", diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 67c3527e23..92fbe5b92f 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -65,7 +65,7 @@ module Notifications assert_equal [[:foo]] * 4, @events end - def test_log_subscriber_with_pattern + def test_log_subscriber_with_string events = [] @notifier.subscribe('1') { |*args| events << args } @@ -74,10 +74,10 @@ module Notifications @notifier.publish 'a.1' @notifier.wait - assert_equal [['1'], ['1.a']], events + assert_equal [['1']], events end - def test_log_subscriber_with_pattern_as_regexp + def test_log_subscriber_with_pattern events = [] @notifier.subscribe(/\d/) { |*args| events << args } diff --git a/activesupport/test/ts_isolated.rb b/activesupport/test/ts_isolated.rb index cbab61a523..58710e0165 100644 --- a/activesupport/test/ts_isolated.rb +++ b/activesupport/test/ts_isolated.rb @@ -1,3 +1,5 @@ +$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') + require 'test/unit' require 'rbconfig' require 'active_support/core_ext/kernel/reporting' diff --git a/ci/ci_build.rb b/ci/ci_build.rb index 02351729f2..1602c5106d 100755 --- a/ci/ci_build.rb +++ b/ci/ci_build.rb @@ -35,7 +35,7 @@ cd "#{root_dir}/activesupport" do puts "[CruiseControl] Building ActiveSupport" puts build_results[:activesupport] = rake 'test' - build_results[:activesupport_isolated] = rake 'test:isolated' + # build_results[:activesupport_isolated] = rake 'test:isolated' end cd "#{root_dir}/railties" do @@ -50,7 +50,7 @@ cd "#{root_dir}/actionpack" do puts "[CruiseControl] Building ActionPack" puts build_results[:actionpack] = rake 'test' - build_results[:actionpack_isolated] = rake 'test:isolated' + # build_results[:actionpack_isolated] = rake 'test:isolated' end cd "#{root_dir}/actionmailer" do @@ -58,7 +58,7 @@ cd "#{root_dir}/actionmailer" do puts "[CruiseControl] Building ActionMailer" puts build_results[:actionmailer] = rake 'test' - build_results[:actionmailer_isolated] = rake 'test:isolated' + # build_results[:actionmailer_isolated] = rake 'test:isolated' end cd "#{root_dir}/activemodel" do @@ -66,7 +66,7 @@ cd "#{root_dir}/activemodel" do puts "[CruiseControl] Building ActiveModel" puts build_results[:activemodel] = rake 'test' - build_results[:activemodel_isolated] = rake 'test:isolated' + # build_results[:activemodel_isolated] = rake 'test:isolated' end rm_f "#{root_dir}/activeresource/debug.log" @@ -75,7 +75,7 @@ cd "#{root_dir}/activeresource" do puts "[CruiseControl] Building ActiveResource" puts build_results[:activeresource] = rake 'test' - build_results[:activeresource_isolated] = rake 'test:isolated' + # build_results[:activeresource_isolated] = rake 'test:isolated' end rm_f "#{root_dir}/activerecord/debug.log" @@ -84,7 +84,7 @@ cd "#{root_dir}/activerecord" do puts "[CruiseControl] Building ActiveRecord with MySQL" puts build_results[:activerecord_mysql] = rake 'mysql:rebuild_databases', 'mysql:test' - build_results[:activerecord_mysql_isolated] = rake 'mysql:rebuild_databases', 'mysql:isolated_test' + # build_results[:activerecord_mysql_isolated] = rake 'mysql:rebuild_databases', 'mysql:isolated_test' end cd "#{root_dir}/activerecord" do @@ -92,7 +92,7 @@ cd "#{root_dir}/activerecord" do puts "[CruiseControl] Building ActiveRecord with PostgreSQL" puts build_results[:activerecord_postgresql8] = rake 'postgresql:rebuild_databases', 'postgresql:test' - build_results[:activerecord_postgresql8_isolated] = rake 'postgresql:rebuild_databases', 'postgresql:isolated_test' + # build_results[:activerecord_postgresql8_isolated] = rake 'postgresql:rebuild_databases', 'postgresql:isolated_test' end cd "#{root_dir}/activerecord" do @@ -100,7 +100,7 @@ cd "#{root_dir}/activerecord" do puts "[CruiseControl] Building ActiveRecord with SQLite 3" puts build_results[:activerecord_sqlite3] = rake 'sqlite3:test' - build_results[:activerecord_sqlite3_isolated] = rake 'sqlite3:isolated_test' + # build_results[:activerecord_sqlite3_isolated] = rake 'sqlite3:isolated_test' end diff --git a/load_paths.rb b/load_paths.rb index b87e0d7235..873315f978 100644 --- a/load_paths.rb +++ b/load_paths.rb @@ -2,7 +2,13 @@ begin require File.expand_path('../.bundle/environment', __FILE__) rescue LoadError begin - require 'rubygems' + # bust gem prelude + if defined? Gem + Gem.cache + gem 'bundler' + else + require 'rubygems' + end require 'bundler' Bundler.setup rescue LoadError diff --git a/railties/Rakefile b/railties/Rakefile index fe049d565f..6368456366 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -36,7 +36,7 @@ end desc "Updates application README to the latest version Railties README" task :update_readme do - readme = "lib/generators/rails/app/templates/README" + readme = "lib/rails/generators/rails/app/templates/README" rm readme cp "./README", readme end @@ -48,7 +48,7 @@ task :generate_guides do end task :update_prototype_ujs do - system "curl http://github.com/rails/prototype-ujs/raw/master/src/rails.js > lib/generators/rails/app/templates/public/javascripts/rails.js" + system "curl http://github.com/rails/prototype-ujs/raw/master/src/rails.js > lib/rails/generators/rails/app/templates/public/javascripts/rails.js" end # Generate documentation ------------------------------------------------------------------ @@ -62,8 +62,8 @@ Rake::RDocTask.new { |rdoc| rdoc.rdoc_files.include('README', 'CHANGELOG') rdoc.rdoc_files.include('lib/*.rb') rdoc.rdoc_files.include('lib/rails/*.rb') - rdoc.rdoc_files.include('lib/generators/*.rb') - rdoc.rdoc_files.include('lib/commands/**/*.rb') + rdoc.rdoc_files.include('lib/rails/generators/*.rb') + rdoc.rdoc_files.include('lib/rails/commands/**/*.rb') } # Generate GEM ---------------------------------------------------------------------------- diff --git a/railties/builtin/rails_info/rails/info_helper.rb b/railties/builtin/rails_info/rails/info_helper.rb deleted file mode 100644 index e5605a8d9b..0000000000 --- a/railties/builtin/rails_info/rails/info_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module Rails::InfoHelper -end diff --git a/railties/lib/generators/erb.rb b/railties/lib/generators/erb.rb deleted file mode 100644 index d468d012dc..0000000000 --- a/railties/lib/generators/erb.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'rails/generators/named_base' - -module Erb - module Generators - class Base < Rails::Generators::NamedBase #:nodoc: - end - end -end diff --git a/railties/lib/generators/erb/mailer/mailer_generator.rb b/railties/lib/generators/erb/mailer/mailer_generator.rb deleted file mode 100644 index 408c942cef..0000000000 --- a/railties/lib/generators/erb/mailer/mailer_generator.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'generators/erb' - -module Erb - module Generators - class MailerGenerator < Base - argument :actions, :type => :array, :default => [], :banner => "method method" - - def create_view_folder - empty_directory File.join("app/views", file_path) - end - - def create_view_files - actions.each do |action| - @action, @path = action, File.join(file_path, action) - template "view.text.erb", File.join("app/views", "#{@path}.text.erb") - end - end - end - end -end diff --git a/railties/lib/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/generators/test_unit/controller/templates/functional_test.rb deleted file mode 100644 index 62fa5d86fd..0000000000 --- a/railties/lib/generators/test_unit/controller/templates/functional_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'test_helper' - -class <%= class_name %>ControllerTest < ActionController::TestCase - # Replace this with your real tests. - test "the truth" do - assert true - end -end diff --git a/railties/lib/generators/test_unit/mailer/templates/fixture b/railties/lib/generators/test_unit/mailer/templates/fixture deleted file mode 100644 index 171648d6fd..0000000000 --- a/railties/lib/generators/test_unit/mailer/templates/fixture +++ /dev/null @@ -1,3 +0,0 @@ -<%= class_name %>#<%= @action %> - -Hi, find me in app/views/<%= @path %> diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 3d3151bd8f..9d02da104d 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -26,6 +26,9 @@ else end module Rails + autoload :Info, 'rails/info' + autoload :InfoController, 'rails/info_controller' + class << self def application @@application ||= nil diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 49388c5060..0084309ea4 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,5 +1,4 @@ require 'fileutils' -require 'rails/railties_path' require 'rails/plugin' require 'rails/engine' @@ -82,6 +81,8 @@ module Rails end end + delegate :metal_loader, :to => :config + def require_environment! environment = config.paths.config.environment.to_a.first require environment if environment diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index d3a0ecb243..44635ff4f6 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -6,7 +6,7 @@ module Rails include ::Rails::Configuration::Deprecated attr_accessor :allow_concurrency, :cache_classes, :cache_store, - :consider_all_requests_local, :dependency_loading, + :cookie_secret, :consider_all_requests_local, :dependency_loading, :filter_parameters, :log_level, :logger, :metals, :plugins, :preload_frameworks, :reload_engines, :reload_plugins, :serve_static_assets, :time_zone, :whiny_nils @@ -19,10 +19,16 @@ module Rails @serve_static_assets = true @time_zone = "UTC" @consider_all_requests_local = true + @session_store = :cookie_store + @session_options = {} end def middleware - @@default_middleware_stack ||= default_middleware + @middleware ||= default_middleware_stack + end + + def metal_loader + @metal_loader ||= Rails::Application::MetalLoader.new end def paths @@ -78,7 +84,7 @@ module Rails end def builtin_controller - File.join(RAILTIES_PATH, "builtin", "rails_info") if Rails.env.development? + File.expand_path('../info_routes', __FILE__) if Rails.env.development? end def log_level @@ -94,6 +100,51 @@ module Rails Rails::LogSubscriber.colorize_logging = val self.generators.colorize_logging = val end + + def session_store(*args) + if args.empty? + case @session_store + when :disabled + nil + when :active_record_store + ActiveRecord::SessionStore + when Symbol + ActionDispatch::Session.const_get(@session_store.to_s.camelize) + else + @session_store + end + else + @session_store = args.shift + @session_options = args.shift || {} + end + end + + protected + + def session_options + return @session_options unless @session_store == :cookie_store + @session_options.merge(:secret => @cookie_secret) + end + + def default_middleware_stack + ActionDispatch::MiddlewareStack.new.tap do |middleware| + middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets }) + middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency }) + middleware.use('::Rack::Runtime') + middleware.use('::Rails::Rack::Logger') + middleware.use('::ActionDispatch::ShowExceptions', lambda { consider_all_requests_local }) + middleware.use("::ActionDispatch::RemoteIp", lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies }) + middleware.use('::Rack::Sendfile', lambda { action_dispatch.x_sendfile_header }) + middleware.use('::ActionDispatch::Callbacks', lambda { !cache_classes }) + middleware.use('::ActionDispatch::Cookies') + middleware.use(lambda { session_store }, lambda { session_options }) + middleware.use('::ActionDispatch::Flash', :if => lambda { session_store }) + middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? }) + middleware.use('ActionDispatch::ParamsParser') + middleware.use('::Rack::MethodOverride') + middleware.use('::ActionDispatch::Head') + end + end end end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index cb38d5a5db..978490f25f 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -23,7 +23,7 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? - app.routes_reloader.paths << File.join(RAILTIES_PATH, 'builtin', 'routes.rb') + app.routes_reloader.paths << File.expand_path('../../info_routes.rb', __FILE__) end end @@ -45,4 +45,4 @@ module Rails end end end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index fe2f89ee98..438c976b35 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -8,6 +8,6 @@ ARGV << "--help" if ARGV.empty? require 'rubygems' if ARGV.include?("--dev") require 'rails/generators' -require 'generators/rails/app/app_generator' +require 'rails/generators/rails/app/app_generator' Rails::Generators::AppGenerator.start
\ No newline at end of file diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index 593e2d8ee3..68982b9f52 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -91,6 +91,18 @@ module Rails args << config['database'] exec(find_cmd('sqlite3'), *args) + + when "oracle", "oracle_enhanced" + logon = "" + + if config['username'] + logon = config['username'] + logon << "/#{config['password']}" if config['password'] && include_password + logon << "@#{config['database']}" if config['database'] + end + + exec(find_cmd('sqlplus'), logon) + else abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!" end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 7ee0f31359..85cae75bce 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -93,11 +93,11 @@ module Rails class << self attr_accessor :called_from - alias :engine_name :railtie_name - alias :engine_names :railtie_names + # TODO Remove this. It's deprecated. + alias :engine_name :railtie_name def inherited(base) - unless abstract_railtie?(base) + unless base.abstract_railtie? base.called_from = begin # Remove the line number from backtraces making sure we don't leave anything behind call_stack = caller.map { |p| p.split(':')[0..-2].join(':') } @@ -124,7 +124,7 @@ module Rails end end - delegate :middleware, :paths, :metal_loader, :root, :to => :config + delegate :middleware, :paths, :root, :to => :config def load_tasks super diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 9a51171cf5..57462707f4 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -242,7 +242,7 @@ module Rails paths = namespaces_to_paths(namespaces) paths.each do |raw_path| - ["rails_generators", "generators"].each do |base| + ["rails/generators", "generators"].each do |base| path = "#{base}/#{raw_path}_generator" begin @@ -265,7 +265,7 @@ module Rails load_generators_from_railties! $LOAD_PATH.each do |base| - Dir[File.join(base, "{generators,rails_generators}", "**", "*_generator.rb")].each do |path| + Dir[File.join(base, "{rails/generators,generators}", "**", "*_generator.rb")].each do |path| begin require path rescue Exception => e diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 9624c35c0b..0da85ea4a4 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -1,4 +1,12 @@ -require 'thor/group' +begin + require 'thor/group' +rescue LoadError + puts "Thor is not available.\nIf you ran this command from a git checkout " \ + "of Rails, please make sure thor is installed,\nand run this command " \ + "as `ruby /path/to/rails myapp --dev`" + exit +end + require 'rails/generators/actions' module Rails @@ -17,7 +25,7 @@ module Rails def self.source_root @_rails_source_root ||= begin if base_name && generator_name - File.expand_path(File.join("../../generators", base_name, generator_name, 'templates'), File.dirname(__FILE__)) + File.expand_path(File.join(base_name, generator_name, 'templates'), File.dirname(__FILE__)) end end end diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb new file mode 100644 index 0000000000..3e6371268f --- /dev/null +++ b/railties/lib/rails/generators/erb.rb @@ -0,0 +1,21 @@ +require 'rails/generators/named_base' + +module Erb + module Generators + class Base < Rails::Generators::NamedBase #:nodoc: + protected + + def format + :html + end + + def handler + :erb + end + + def filename_with_extensions(name) + [name, format, handler].compact.join(".") + end + end + end +end diff --git a/railties/lib/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb index ab7b273662..ac57140c23 100644 --- a/railties/lib/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -1,19 +1,18 @@ -require 'generators/erb' +require 'rails/generators/erb' module Erb module Generators class ControllerGenerator < Base argument :actions, :type => :array, :default => [], :banner => "action action" - def create_view_files + def copy_view_files base_path = File.join("app/views", class_path, file_name) empty_directory base_path actions.each do |action| @action = action - @path = File.join(base_path, "#{action}.html.erb") - - template 'view.html.erb', @path + @path = File.join(base_path, filename_with_extensions(action)) + template filename_with_extensions(:view), @path end end end diff --git a/railties/lib/generators/erb/controller/templates/view.html.erb b/railties/lib/rails/generators/erb/controller/templates/view.html.erb index cd54d13d83..cd54d13d83 100644 --- a/railties/lib/generators/erb/controller/templates/view.html.erb +++ b/railties/lib/rails/generators/erb/controller/templates/view.html.erb diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb new file mode 100644 index 0000000000..943d0c9f8d --- /dev/null +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -0,0 +1,13 @@ +require 'rails/generators/erb/controller/controller_generator' + +module Erb + module Generators + class MailerGenerator < ControllerGenerator + protected + + def format + :text + end + end + end +end diff --git a/railties/lib/generators/erb/mailer/templates/view.text.erb b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb index 6d597256a6..6d597256a6 100644 --- a/railties/lib/generators/erb/mailer/templates/view.text.erb +++ b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb diff --git a/railties/lib/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index 846540476f..f607e580a5 100644 --- a/railties/lib/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -1,4 +1,4 @@ -require 'generators/erb' +require 'rails/generators/erb' require 'rails/generators/resource_helpers' module Erb @@ -15,39 +15,27 @@ module Erb empty_directory File.join("app/views", controller_file_path) end - def copy_index_file - return if options[:singleton] - copy_view :index - end - - def copy_edit_file - copy_view :edit - end + def copy_view_files + views = available_views + views.delete("index") if options[:singleton] - def copy_show_file - copy_view :show - end - - def copy_new_file - copy_view :new - end - - def copy_form_file - copy_view :_form + views.each do |view| + filename = filename_with_extensions(view) + template filename, File.join("app/views", controller_file_path, filename) + end end def copy_layout_file return unless options[:layout] - template "layout.html.erb", - File.join("app/views/layouts", controller_class_path, "#{controller_file_name}.html.erb") + template filename_with_extensions(:layout), + File.join("app/views/layouts", controller_class_path, filename_with_extensions(controller_file_name)) end - protected - - def copy_view(view) - template "#{view}.html.erb", File.join("app/views", controller_file_path, "#{view}.html.erb") - end + protected + def available_views + %w(index edit show new _form) + end end end end diff --git a/railties/lib/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 01ec58c615..01ec58c615 100644 --- a/railties/lib/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb diff --git a/railties/lib/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb index 5bc507ffc8..5bc507ffc8 100644 --- a/railties/lib/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb diff --git a/railties/lib/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index b5c7fd1e58..d30d306d42 100644 --- a/railties/lib/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -24,4 +24,4 @@ <br /> -<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %> +<%%= link_to 'New <%= human_name %>', new_<%= singular_name %>_path %> diff --git a/railties/lib/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb index 3f64be0c45..3f64be0c45 100644 --- a/railties/lib/generators/erb/scaffold/templates/layout.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb diff --git a/railties/lib/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb index 9a1c489331..9a1c489331 100644 --- a/railties/lib/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb diff --git a/railties/lib/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 24f13fc0f8..24f13fc0f8 100644 --- a/railties/lib/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 12e918731e..8d1dfbd947 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -27,6 +27,10 @@ module Rails @class_name ||= (class_path + [file_name]).map!{ |m| m.camelize }.join('::') end + def human_name + @human_name ||= singular_name.humanize + end + def plural_name @plural_name ||= singular_name.pluralize end diff --git a/railties/lib/generators/rails/app/USAGE b/railties/lib/rails/generators/rails/app/USAGE index 36d6061a59..36d6061a59 100644 --- a/railties/lib/generators/rails/app/USAGE +++ b/railties/lib/rails/generators/rails/app/USAGE diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 1e1acc1141..fccae9190a 100644 --- a/railties/lib/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -5,7 +5,7 @@ require 'rails/version' unless defined?(Rails::VERSION) module Rails::Generators # We need to store the RAILS_DEV_PATH in a constant, otherwise the path # can change in Ruby 1.8.7 when we FileUtils.cd. - RAILS_DEV_PATH = File.expand_path("../../../../..", File.dirname(__FILE__)) + RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) RESERVED_NAMES = %w[generate console server dbconsole application destroy benchmarker profiler diff --git a/railties/lib/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 0dd10f3f2d..0dd10f3f2d 100644 --- a/railties/lib/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile diff --git a/railties/lib/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README index ded8570c42..ded8570c42 100644 --- a/railties/lib/generators/rails/app/templates/README +++ b/railties/lib/rails/generators/rails/app/templates/README diff --git a/railties/lib/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile index 9cb2046439..9cb2046439 100755 --- a/railties/lib/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile diff --git a/railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb index e8065d9505..e8065d9505 100644 --- a/railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb diff --git a/railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb index de6be7945c..de6be7945c 100644 --- a/railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb diff --git a/railties/lib/generators/rails/app/templates/app/models/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/app/models/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru index fcfbc6b07a..fcfbc6b07a 100644 --- a/railties/lib/generators/rails/app/templates/config.ru +++ b/railties/lib/rails/generators/rails/app/templates/config.ru diff --git a/railties/lib/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index dc20ffb2fa..dc20ffb2fa 100644 --- a/railties/lib/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb diff --git a/railties/lib/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 3cb561d41f..3cb561d41f 100644 --- a/railties/lib/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb diff --git a/railties/lib/generators/rails/app/templates/config/databases/frontbase.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml index c0c3588be1..c0c3588be1 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/frontbase.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml diff --git a/railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml index 2784a949fb..2784a949fb 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml diff --git a/railties/lib/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml index 6bf2f7b1fd..6bf2f7b1fd 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml diff --git a/railties/lib/generators/rails/app/templates/config/databases/oracle.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml index a1883f6256..a1883f6256 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/oracle.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml diff --git a/railties/lib/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index f600e054cf..f600e054cf 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml diff --git a/railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml index 025d62a8d8..025d62a8d8 100644 --- a/railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml diff --git a/railties/lib/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb index 1684986a59..1684986a59 100644 --- a/railties/lib/generators/rails/app/templates/config/environment.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb diff --git a/railties/lib/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index f0e917dd96..f0e917dd96 100644 --- a/railties/lib/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt diff --git a/railties/lib/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 917052c3df..f902120453 100644 --- a/railties/lib/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -9,6 +9,15 @@ config.consider_all_requests_local = false config.action_controller.perform_caching = true + # Specifies the header that your server uses for sending files + config.action_dispatch.x_sendfile_header = "X-Sendfile" + + # For nginx: + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' + + # If you have no front-end server that supports something like X-Sendfile, + # just comment this out and Rails will serve the files + # See everything in the log (default is :info) # config.log_level = :debug diff --git a/railties/lib/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 0b87b241ec..0b87b241ec 100644 --- a/railties/lib/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt diff --git a/railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb index 59385cdf37..59385cdf37 100644 --- a/railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb diff --git a/railties/lib/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt index be627fbbcc..be627fbbcc 100644 --- a/railties/lib/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt diff --git a/railties/lib/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb index d531b8bb82..d531b8bb82 100644 --- a/railties/lib/generators/rails/app/templates/config/initializers/inflections.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb diff --git a/railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb index 72aca7e441..72aca7e441 100644 --- a/railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb diff --git a/railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt index 9e32fb930e..9e32fb930e 100644 --- a/railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt diff --git a/railties/lib/generators/rails/app/templates/config/locales/en.yml b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml index a747bfa698..a747bfa698 100644 --- a/railties/lib/generators/rails/app/templates/config/locales/en.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml diff --git a/railties/lib/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index d6c0365c04..d6c0365c04 100644 --- a/railties/lib/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb diff --git a/railties/lib/generators/rails/app/templates/db/seeds.rb b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb index 664d8c74c8..664d8c74c8 100644 --- a/railties/lib/generators/rails/app/templates/db/seeds.rb +++ b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb diff --git a/railties/lib/generators/rails/app/templates/doc/README_FOR_APP b/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP index fe41f5cc24..fe41f5cc24 100644 --- a/railties/lib/generators/rails/app/templates/doc/README_FOR_APP +++ b/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP diff --git a/railties/lib/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index af64fae5e7..af64fae5e7 100644 --- a/railties/lib/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore diff --git a/railties/lib/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index 9a48320a5f..9a48320a5f 100644 --- a/railties/lib/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html diff --git a/railties/lib/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index 83660ab187..83660ab187 100644 --- a/railties/lib/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html diff --git a/railties/lib/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index b80307fc16..b80307fc16 100644 --- a/railties/lib/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html diff --git a/railties/lib/generators/rails/app/templates/public/favicon.ico b/railties/lib/rails/generators/rails/app/templates/public/favicon.ico index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/public/favicon.ico +++ b/railties/lib/rails/generators/rails/app/templates/public/favicon.ico diff --git a/railties/lib/generators/rails/app/templates/public/images/rails.png b/railties/lib/rails/generators/rails/app/templates/public/images/rails.png Binary files differindex d5edc04e65..d5edc04e65 100644 --- a/railties/lib/generators/rails/app/templates/public/images/rails.png +++ b/railties/lib/rails/generators/rails/app/templates/public/images/rails.png diff --git a/railties/lib/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html index 836da1b689..836da1b689 100644 --- a/railties/lib/generators/rails/app/templates/public/index.html +++ b/railties/lib/rails/generators/rails/app/templates/public/index.html diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/application.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/application.js index fe4577696b..fe4577696b 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/application.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/application.js diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/controls.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/controls.js index 7392fb664c..7392fb664c 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/controls.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/controls.js diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js index 15c6dbca68..15c6dbca68 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/effects.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/effects.js index 066ee5909c..066ee5909c 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/effects.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/effects.js diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/prototype.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js index 9fe6e1243b..9fe6e1243b 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/prototype.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/rails.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js index f7ddba390a..7342e1b830 100644 --- a/railties/lib/generators/rails/app/templates/public/javascripts/rails.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js @@ -15,8 +15,7 @@ document.observe("dom:loaded", function() { params = element.serialize(true); } else { method = element.readAttribute('data-method') || 'get'; - // TODO: data-url support is going away, just use href - url = element.readAttribute('data-url') || element.readAttribute('href'); + url = element.readAttribute('href'); params = {}; } diff --git a/railties/lib/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 085187fa58..085187fa58 100644 --- a/railties/lib/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt diff --git a/railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/script/rails b/railties/lib/rails/generators/rails/app/templates/script/rails index b01d1ee183..b01d1ee183 100644 --- a/railties/lib/generators/rails/app/templates/script/rails +++ b/railties/lib/rails/generators/rails/app/templates/script/rails diff --git a/railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/test/functional/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/test/functional/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/test/integration/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/test/integration/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory diff --git a/railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb index a3dc38d9e4..a3dc38d9e4 100644 --- a/railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb diff --git a/railties/lib/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 8bf1192ffe..8bf1192ffe 100644 --- a/railties/lib/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb diff --git a/railties/lib/generators/rails/app/templates/test/unit/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/app/templates/test/unit/.empty_directory +++ b/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory diff --git a/railties/lib/generators/rails/controller/USAGE b/railties/lib/rails/generators/rails/controller/USAGE index 70618a3906..70618a3906 100644 --- a/railties/lib/generators/rails/controller/USAGE +++ b/railties/lib/rails/generators/rails/controller/USAGE diff --git a/railties/lib/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 91470be833..9788c0d0bc 100644 --- a/railties/lib/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -8,6 +8,12 @@ module Rails template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb") end + def add_routes + actions.reverse.each do |action| + route %{get "#{file_name}/#{action}"} + end + end + hook_for :template_engine, :test_framework, :helper end end diff --git a/railties/lib/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb index cda2659e69..cda2659e69 100644 --- a/railties/lib/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb diff --git a/railties/lib/generators/rails/generator/USAGE b/railties/lib/rails/generators/rails/generator/USAGE index d8c3f7f634..d8c3f7f634 100644 --- a/railties/lib/generators/rails/generator/USAGE +++ b/railties/lib/rails/generators/rails/generator/USAGE diff --git a/railties/lib/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 5b5d1884bc..5b5d1884bc 100644 --- a/railties/lib/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb diff --git a/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt index d8757460e4..d8757460e4 100644 --- a/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt +++ b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt diff --git a/railties/lib/generators/rails/generator/templates/USAGE.tt b/railties/lib/rails/generators/rails/generator/templates/USAGE.tt index 1bb8df840d..1bb8df840d 100644 --- a/railties/lib/generators/rails/generator/templates/USAGE.tt +++ b/railties/lib/rails/generators/rails/generator/templates/USAGE.tt diff --git a/railties/lib/generators/rails/generator/templates/templates/.empty_directory b/railties/lib/rails/generators/rails/generator/templates/templates/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/generators/rails/generator/templates/templates/.empty_directory +++ b/railties/lib/rails/generators/rails/generator/templates/templates/.empty_directory diff --git a/railties/lib/generators/rails/helper/USAGE b/railties/lib/rails/generators/rails/helper/USAGE index c0ddb0f606..c0ddb0f606 100644 --- a/railties/lib/generators/rails/helper/USAGE +++ b/railties/lib/rails/generators/rails/helper/USAGE diff --git a/railties/lib/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb index ad66388591..ad66388591 100644 --- a/railties/lib/generators/rails/helper/helper_generator.rb +++ b/railties/lib/rails/generators/rails/helper/helper_generator.rb diff --git a/railties/lib/generators/rails/helper/templates/helper.rb b/railties/lib/rails/generators/rails/helper/templates/helper.rb index 3fe2ecdc74..3fe2ecdc74 100644 --- a/railties/lib/generators/rails/helper/templates/helper.rb +++ b/railties/lib/rails/generators/rails/helper/templates/helper.rb diff --git a/railties/lib/generators/rails/integration_test/USAGE b/railties/lib/rails/generators/rails/integration_test/USAGE index 57ee3543e6..57ee3543e6 100644 --- a/railties/lib/generators/rails/integration_test/USAGE +++ b/railties/lib/rails/generators/rails/integration_test/USAGE diff --git a/railties/lib/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb index 363a327fcb..363a327fcb 100644 --- a/railties/lib/generators/rails/integration_test/integration_test_generator.rb +++ b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb diff --git a/railties/lib/generators/rails/mailer/USAGE b/railties/lib/rails/generators/rails/mailer/USAGE index a08d459739..a08d459739 100644 --- a/railties/lib/generators/rails/mailer/USAGE +++ b/railties/lib/rails/generators/rails/mailer/USAGE diff --git a/railties/lib/generators/rails/mailer/mailer_generator.rb b/railties/lib/rails/generators/rails/mailer/mailer_generator.rb index 8993181d79..8993181d79 100644 --- a/railties/lib/generators/rails/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/rails/mailer/mailer_generator.rb diff --git a/railties/lib/generators/rails/mailer/templates/mailer.rb b/railties/lib/rails/generators/rails/mailer/templates/mailer.rb index 7343eb28b3..7343eb28b3 100644 --- a/railties/lib/generators/rails/mailer/templates/mailer.rb +++ b/railties/lib/rails/generators/rails/mailer/templates/mailer.rb diff --git a/railties/lib/generators/rails/metal/USAGE b/railties/lib/rails/generators/rails/metal/USAGE index c88325a444..c88325a444 100644 --- a/railties/lib/generators/rails/metal/USAGE +++ b/railties/lib/rails/generators/rails/metal/USAGE diff --git a/railties/lib/generators/rails/metal/metal_generator.rb b/railties/lib/rails/generators/rails/metal/metal_generator.rb index fe4f945cad..fe4f945cad 100644 --- a/railties/lib/generators/rails/metal/metal_generator.rb +++ b/railties/lib/rails/generators/rails/metal/metal_generator.rb diff --git a/railties/lib/generators/rails/metal/templates/metal.rb b/railties/lib/rails/generators/rails/metal/templates/metal.rb index 8cc3f1f258..8cc3f1f258 100644 --- a/railties/lib/generators/rails/metal/templates/metal.rb +++ b/railties/lib/rails/generators/rails/metal/templates/metal.rb diff --git a/railties/lib/generators/rails/migration/USAGE b/railties/lib/rails/generators/rails/migration/USAGE index d21c81b760..d21c81b760 100644 --- a/railties/lib/generators/rails/migration/USAGE +++ b/railties/lib/rails/generators/rails/migration/USAGE diff --git a/railties/lib/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb index 39fa5b63b1..39fa5b63b1 100644 --- a/railties/lib/generators/rails/migration/migration_generator.rb +++ b/railties/lib/rails/generators/rails/migration/migration_generator.rb diff --git a/railties/lib/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index d97e9ac103..d97e9ac103 100644 --- a/railties/lib/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE diff --git a/railties/lib/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index 629d5eed3f..629d5eed3f 100644 --- a/railties/lib/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb diff --git a/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb b/railties/lib/rails/generators/rails/model_subclass/model_subclass_generator.rb index 99fd2f45bc..99fd2f45bc 100644 --- a/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb +++ b/railties/lib/rails/generators/rails/model_subclass/model_subclass_generator.rb diff --git a/railties/lib/generators/rails/observer/USAGE b/railties/lib/rails/generators/rails/observer/USAGE index d8f32a6a48..d8f32a6a48 100644 --- a/railties/lib/generators/rails/observer/USAGE +++ b/railties/lib/rails/generators/rails/observer/USAGE diff --git a/railties/lib/generators/rails/observer/observer_generator.rb b/railties/lib/rails/generators/rails/observer/observer_generator.rb index f5cedee91f..f5cedee91f 100644 --- a/railties/lib/generators/rails/observer/observer_generator.rb +++ b/railties/lib/rails/generators/rails/observer/observer_generator.rb diff --git a/railties/lib/generators/rails/performance_test/USAGE b/railties/lib/rails/generators/rails/performance_test/USAGE index 9dc799559c..9dc799559c 100644 --- a/railties/lib/generators/rails/performance_test/USAGE +++ b/railties/lib/rails/generators/rails/performance_test/USAGE diff --git a/railties/lib/generators/rails/performance_test/performance_test_generator.rb b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb index d1c71ab8ed..d1c71ab8ed 100644 --- a/railties/lib/generators/rails/performance_test/performance_test_generator.rb +++ b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb diff --git a/railties/lib/generators/rails/plugin/USAGE b/railties/lib/rails/generators/rails/plugin/USAGE index 00a429c585..00a429c585 100644 --- a/railties/lib/generators/rails/plugin/USAGE +++ b/railties/lib/rails/generators/rails/plugin/USAGE diff --git a/railties/lib/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 8f01dcd589..40ed2062d3 100644 --- a/railties/lib/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -1,4 +1,4 @@ -require 'generators/rails/generator/generator_generator' +require 'rails/generators/rails/generator/generator_generator' module Rails module Generators diff --git a/railties/lib/generators/rails/plugin/templates/MIT-LICENSE.tt b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt index 8717df053d..8717df053d 100644 --- a/railties/lib/generators/rails/plugin/templates/MIT-LICENSE.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt diff --git a/railties/lib/generators/rails/plugin/templates/README.tt b/railties/lib/rails/generators/rails/plugin/templates/README.tt index 702db07cb1..702db07cb1 100644 --- a/railties/lib/generators/rails/plugin/templates/README.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/README.tt diff --git a/railties/lib/generators/rails/plugin/templates/Rakefile.tt b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt index e94c0bfc77..e94c0bfc77 100644 --- a/railties/lib/generators/rails/plugin/templates/Rakefile.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt diff --git a/railties/lib/generators/rails/plugin/templates/init.rb b/railties/lib/rails/generators/rails/plugin/templates/init.rb index 3c19a743c9..3c19a743c9 100644 --- a/railties/lib/generators/rails/plugin/templates/init.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/init.rb diff --git a/railties/lib/generators/rails/plugin/templates/install.rb b/railties/lib/rails/generators/rails/plugin/templates/install.rb index f7732d3796..f7732d3796 100644 --- a/railties/lib/generators/rails/plugin/templates/install.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/install.rb diff --git a/railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/%file_name%.rb.tt index d8d908a959..d8d908a959 100644 --- a/railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%file_name%.rb.tt diff --git a/railties/lib/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt index 72920a9d3a..72920a9d3a 100644 --- a/railties/lib/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt diff --git a/railties/lib/generators/rails/plugin/templates/uninstall.rb b/railties/lib/rails/generators/rails/plugin/templates/uninstall.rb index 9738333463..9738333463 100644 --- a/railties/lib/generators/rails/plugin/templates/uninstall.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/uninstall.rb diff --git a/railties/lib/generators/rails/resource/USAGE b/railties/lib/rails/generators/rails/resource/USAGE index e359cd574f..e359cd574f 100644 --- a/railties/lib/generators/rails/resource/USAGE +++ b/railties/lib/rails/generators/rails/resource/USAGE diff --git a/railties/lib/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 5acb839f39..1e78945a7e 100644 --- a/railties/lib/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -1,5 +1,5 @@ require 'rails/generators/resource_helpers' -require 'generators/rails/model/model_generator' +require 'rails/generators/rails/model/model_generator' module Rails module Generators @@ -16,6 +16,7 @@ module Rails class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller" def add_resource_route + return if options[:actions].present? route "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}" end diff --git a/railties/lib/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE index be1d113ed8..be1d113ed8 100644 --- a/railties/lib/generators/rails/scaffold/USAGE +++ b/railties/lib/rails/generators/rails/scaffold/USAGE diff --git a/railties/lib/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index fdea5bf52b..779f933785 100644 --- a/railties/lib/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -1,4 +1,4 @@ -require 'generators/rails/resource/resource_generator' +require 'rails/generators/rails/resource/resource_generator' module Rails module Generators diff --git a/railties/lib/generators/rails/scaffold_controller/USAGE b/railties/lib/rails/generators/rails/scaffold_controller/USAGE index 673f69bc81..673f69bc81 100644 --- a/railties/lib/generators/rails/scaffold_controller/USAGE +++ b/railties/lib/rails/generators/rails/scaffold_controller/USAGE diff --git a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index 49af2974cd..49af2974cd 100644 --- a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb diff --git a/railties/lib/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 874e96a2b4..bbdce669dc 100644 --- a/railties/lib/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -46,7 +46,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.save %> - format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') } + format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully created.') } format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } else format.html { render :action => "new" } @@ -62,7 +62,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.update_attributes("params[:#{file_name}]") %> - format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') } + format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully updated.') } format.xml { head :ok } else format.html { render :action => "edit" } diff --git a/railties/lib/generators/rails/session_migration/USAGE b/railties/lib/rails/generators/rails/session_migration/USAGE index 564d1ffd78..564d1ffd78 100644 --- a/railties/lib/generators/rails/session_migration/USAGE +++ b/railties/lib/rails/generators/rails/session_migration/USAGE diff --git a/railties/lib/generators/rails/session_migration/session_migration_generator.rb b/railties/lib/rails/generators/rails/session_migration/session_migration_generator.rb index 258cc5b4a0..258cc5b4a0 100644 --- a/railties/lib/generators/rails/session_migration/session_migration_generator.rb +++ b/railties/lib/rails/generators/rails/session_migration/session_migration_generator.rb diff --git a/railties/lib/generators/rails/stylesheets/USAGE b/railties/lib/rails/generators/rails/stylesheets/USAGE index 59e5495d0b..59e5495d0b 100644 --- a/railties/lib/generators/rails/stylesheets/USAGE +++ b/railties/lib/rails/generators/rails/stylesheets/USAGE diff --git a/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb b/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb index ce68443c39..ce68443c39 100644 --- a/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb +++ b/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb diff --git a/railties/lib/generators/rails/stylesheets/templates/scaffold.css b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css index ea3dc9b8b5..ea3dc9b8b5 100644 --- a/railties/lib/generators/rails/stylesheets/templates/scaffold.css +++ b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css diff --git a/railties/lib/generators/test_unit.rb b/railties/lib/rails/generators/test_unit.rb index 62b9afaa2c..62b9afaa2c 100644 --- a/railties/lib/generators/test_unit.rb +++ b/railties/lib/rails/generators/test_unit.rb diff --git a/railties/lib/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb index b57a6e794f..20f3bd8965 100644 --- a/railties/lib/generators/test_unit/controller/controller_generator.rb +++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb @@ -1,8 +1,9 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators class ControllerGenerator < Base + argument :actions, :type => :array, :default => [], :banner => "action action" check_class_collision :suffix => "ControllerTest" def create_test_files diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb new file mode 100644 index 0000000000..0d4185846d --- /dev/null +++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb @@ -0,0 +1,18 @@ +require 'test_helper' + +class <%= class_name %>ControllerTest < ActionController::TestCase +<% if actions.empty? -%> + # Replace this with your real tests. + test "the truth" do + assert true + end +<% else -%> +<% for action in actions -%> + test "should get <%= action %>" do + get :<%= action %> + assert_response :success + end + +<% end -%> +<% end -%> +end diff --git a/railties/lib/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb index 9ecfaa45ab..4ea80bf7be 100644 --- a/railties/lib/generators/test_unit/helper/helper_generator.rb +++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/helper/templates/helper_test.rb b/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb index 591e40900e..591e40900e 100644 --- a/railties/lib/generators/test_unit/helper/templates/helper_test.rb +++ b/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb diff --git a/railties/lib/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb index d9d9b3bf1d..32d0fac029 100644 --- a/railties/lib/generators/test_unit/integration/integration_generator.rb +++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/integration/templates/integration_test.rb b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb index 2c57158b1c..2c57158b1c 100644 --- a/railties/lib/generators/test_unit/integration/templates/integration_test.rb +++ b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb diff --git a/railties/lib/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb index a0d73db1b0..1a49286d41 100644 --- a/railties/lib/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators @@ -9,13 +9,6 @@ module TestUnit def create_test_files template "functional_test.rb", File.join('test/functional', class_path, "#{file_name}_test.rb") end - - def create_fixtures_files - actions.each do |action| - @action, @path = action, File.join(file_path, action) - template "fixture", File.join("test/fixtures", @path) - end - end end end end diff --git a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb index a2b1f1ed05..80ac7f0feb 100644 --- a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb @@ -3,12 +3,11 @@ require 'test_helper' class <%= class_name %>Test < ActionMailer::TestCase <% for action in actions -%> test "<%= action %>" do - @expected.subject = <%= action.to_s.humanize.inspect %> - @expected.to = "to@example.org" - @expected.from = "from@example.com" - @expected.body = read_fixture("<%= action %>") - - assert_equal @expected, <%= class_name %>.<%= action %> + mail = <%= class_name %>.<%= action %> + assert_equal <%= action.to_s.humanize.inspect %>, mail.subject + assert_equal ["to@example.org"], mail.to + assert_equal ["from@example.com"], mail.from + assert_match "Hi", mail.body.encoded end <% end -%> diff --git a/railties/lib/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb index 469306e6c5..609b815683 100644 --- a/railties/lib/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index a30132bc99..a30132bc99 100644 --- a/railties/lib/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml diff --git a/railties/lib/generators/test_unit/model/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb index 3e0bc29d3a..3e0bc29d3a 100644 --- a/railties/lib/generators/test_unit/model/templates/unit_test.rb +++ b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb diff --git a/railties/lib/generators/test_unit/observer/observer_generator.rb b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb index 14181f4e49..6cc1158c21 100644 --- a/railties/lib/generators/test_unit/observer/observer_generator.rb +++ b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/observer/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb index 03f6d5666e..03f6d5666e 100644 --- a/railties/lib/generators/test_unit/observer/templates/unit_test.rb +++ b/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb diff --git a/railties/lib/generators/test_unit/performance/performance_generator.rb b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb index 0d9c646b26..99edda5461 100644 --- a/railties/lib/generators/test_unit/performance/performance_generator.rb +++ b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/performance/templates/performance_test.rb b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb index 362e3dc09f..362e3dc09f 100644 --- a/railties/lib/generators/test_unit/performance/templates/performance_test.rb +++ b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb diff --git a/railties/lib/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb index 05adf58c4f..4d65cd7d89 100644 --- a/railties/lib/generators/test_unit/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' module TestUnit module Generators diff --git a/railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt b/railties/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt index 3e0bc29d3a..3e0bc29d3a 100644 --- a/railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +++ b/railties/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt diff --git a/railties/lib/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb index 2ca36a1e44..2ca36a1e44 100644 --- a/railties/lib/generators/test_unit/plugin/templates/test_helper.rb +++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb diff --git a/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index a95916ae13..c0315c7fe6 100644 --- a/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -1,4 +1,4 @@ -require 'generators/test_unit' +require 'rails/generators/test_unit' require 'rails/generators/resource_helpers' module TestUnit diff --git a/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 9380aa49b6..4f8ddbffcf 100644 --- a/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -1,6 +1,10 @@ require 'test_helper' class <%= controller_class_name %>ControllerTest < ActionController::TestCase + setup do + @<%= file_name %> = <%= table_name %>(:one) + end + <% unless options[:singleton] -%> test "should get index" do get :index @@ -16,30 +20,30 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase test "should create <%= file_name %>" do assert_difference('<%= class_name %>.count') do - post :create, :<%= file_name %> => <%= table_name %>(:one).attributes + post :create, :<%= file_name %> => @<%= file_name %>.attributes end assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) end test "should show <%= file_name %>" do - get :show, :id => <%= table_name %>(:one).to_param + get :show, :id => @<%= file_name %>.to_param assert_response :success end test "should get edit" do - get :edit, :id => <%= table_name %>(:one).to_param + get :edit, :id => @<%= file_name %>.to_param assert_response :success end test "should update <%= file_name %>" do - put :update, :id => <%= table_name %>(:one).to_param, :<%= file_name %> => <%= table_name %>(:one).attributes + put :update, :id => @<%= file_name %>.to_param, :<%= file_name %> => @<%= file_name %>.attributes assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) end test "should destroy <%= file_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete :destroy, :id => <%= table_name %>(:one).to_param + delete :destroy, :id => @<%= file_name %>.to_param end assert_redirected_to <%= table_name %>_path diff --git a/railties/builtin/rails_info/rails/info.rb b/railties/lib/rails/info.rb index 5a496f6536..5a496f6536 100644 --- a/railties/builtin/rails_info/rails/info.rb +++ b/railties/lib/rails/info.rb diff --git a/railties/builtin/rails_info/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 196eeb4a6c..196eeb4a6c 100644 --- a/railties/builtin/rails_info/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb diff --git a/railties/builtin/routes.rb b/railties/lib/rails/info_routes.rb index bd58034d8f..bd58034d8f 100644 --- a/railties/builtin/routes.rb +++ b/railties/lib/rails/info_routes.rb diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 96a07844e5..0d68abb323 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -179,7 +179,7 @@ module Rails include Initializable - ABSTRACT_RAILTIES = %w(Rails::Plugin Rails::Engine Rails::Application) + ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Plugin Rails::Engine Rails::Application) class << self def subclasses @@ -187,23 +187,18 @@ module Rails end def inherited(base) - unless abstract_railtie?(base) + unless base.abstract_railtie? base.send(:include, self::Configurable) subclasses << base end end - def railtie_name(railtie_name = nil) - @railtie_name = railtie_name if railtie_name - @railtie_name ||= default_name + def railtie_name(*) + ActiveSupport::Deprecation.warn "railtie_name is deprecated and has no effect", caller end - def railtie_names - subclasses.map { |p| p.railtie_name } - end - - def log_subscriber(log_subscriber) - Rails::LogSubscriber.add(railtie_name, log_subscriber) + def log_subscriber(name, log_subscriber) + Rails::LogSubscriber.add(name, log_subscriber) end def rake_tasks(&blk) @@ -218,14 +213,8 @@ module Rails @generators end - protected - - def abstract_railtie?(base) - ABSTRACT_RAILTIES.include?(base.name) - end - - def default_name - ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name)) + def abstract_railtie? + ABSTRACT_RAILTIES.include?(name) end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 828ccec3d0..16eccaccc4 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -3,11 +3,8 @@ require 'rails/configuration' module Rails class Railtie class Configuration - attr_accessor :cookie_secret - def initialize - @session_store = :cookie_store - @session_options = {} + @@options ||= {} end # Holds generators configuration: @@ -48,76 +45,18 @@ module Rails end def respond_to?(name) - super || name.to_s =~ config_key_regexp - end - - def metal_loader - @metal_loader ||= Rails::Application::MetalLoader.new - end - - def session_store(*args) - if args.empty? - case @session_store - when :disabled - nil - when :active_record_store - ActiveRecord::SessionStore - when Symbol - ActionDispatch::Session.const_get(@session_store.to_s.camelize) - else - @session_store - end - else - @session_store = args.shift - @session_options = args.shift || {} - end + super || @@options.key?(name.to_sym) end private def method_missing(name, *args, &blk) - if name.to_s =~ config_key_regexp - return $2 == '=' ? options[$1] = args.first : options[$1] - end - super - end - - def session_options - return @session_options unless @session_store == :cookie_store - @session_options.merge(:secret => @cookie_secret) - end - - def config_key_regexp - bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|') - /^(#{bits})(?:=)?$/ - end - - def config_keys - (Railtie.railtie_names + Engine.engine_names).map { |n| n.to_s }.uniq - end - - def options - @@options ||= Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new } - end - - def default_middleware - require 'action_dispatch' - ActionDispatch::MiddlewareStack.new.tap do |middleware| - middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets }) - middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency }) - middleware.use('::Rack::Runtime') - middleware.use('::Rails::Rack::Logger') - middleware.use('::ActionDispatch::ShowExceptions', lambda { consider_all_requests_local }) - middleware.use("::ActionDispatch::RemoteIp", lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies }) - middleware.use('::Rack::Sendfile', lambda { action_dispatch.x_sendfile_header }) - middleware.use('::ActionDispatch::Callbacks', lambda { !cache_classes }) - middleware.use('::ActionDispatch::Cookies') - middleware.use(lambda { session_store }, lambda { session_options }) - middleware.use('::ActionDispatch::Flash', :if => lambda { session_store }) - middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? }) - middleware.use('ActionDispatch::ParamsParser') - middleware.use('::Rack::MethodOverride') - middleware.use('::ActionDispatch::Head') + if name.to_s =~ /=$/ + @@options[$`.to_sym] = args.first + elsif @@options.key?(name) + @@options[name] + else + super end end end diff --git a/railties/lib/rails/railties_path.rb b/railties/lib/rails/railties_path.rb deleted file mode 100644 index e291fc23ea..0000000000 --- a/railties/lib/rails/railties_path.rb +++ /dev/null @@ -1 +0,0 @@ -RAILTIES_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')) diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index abf9b33ae5..f2fee45594 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -66,13 +66,14 @@ namespace :doc do task :plugins => plugins.collect { |plugin| "doc:plugins:#{plugin}" } desc "Remove plugin documentation" - task :clobber_plugins do + task :clobber_plugins do rm_rf 'doc/plugins' rescue nil end desc "Generate Rails guides" task :guides do - require File.join(RAILTIES_PATH, "guides/rails_guides") + # FIXME: Reaching outside lib directory is a bad idea + require File.expand_path('../../../../guides/rails_guides', __FILE__) RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate end @@ -92,7 +93,7 @@ namespace :doc do files.include("#{plugin_base}/lib/**/*.rb") if File.exist?("#{plugin_base}/README") - files.include("#{plugin_base}/README") + files.include("#{plugin_base}/README") options << "--main '#{plugin_base}/README'" end files.include("#{plugin_base}/CHANGELOG") if File.exist?("#{plugin_base}/CHANGELOG") diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index dbe2ac54ed..738f7f5301 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -2,18 +2,18 @@ namespace :rails do namespace :freeze do desc "The rails:freeze:gems is deprecated, please use bundle install instead" task :gems do - puts "The rails:freeze:gems is deprecated, please use bundle install instead" + abort "The rails:freeze:gems is deprecated, please use bundle install instead" end desc 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install' task :edge do - puts 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install' + abort 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install' end end desc 'The unfreeze command has been deprecated, please use bundler commands instead' task :unfreeze do - puts 'The unfreeze command has been deprecated, please use bundler commands instead' + abort 'The unfreeze command has been deprecated, please use bundler commands instead' end desc "Update both configs, scripts and public/javascripts from Rails" @@ -25,7 +25,7 @@ namespace :rails do template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} require 'rails/generators' - require 'generators/rails/app/app_generator' + require 'rails/generators/rails/app/app_generator' generator = Rails::Generators::AppGenerator.new [ Rails.root ], {}, :destination_root => Rails.root generator.apply template, :verbose => false end @@ -38,10 +38,11 @@ namespace :rails do def app_generator @app_generator ||= begin require 'rails/generators' - require 'generators/rails/app/app_generator' + require 'rails/generators/rails/app/app_generator' gen = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, :destination_root => Rails.root - gen.send(:valid_app_const?) + File.exists?(Rails.root.join("config", "application.rb")) ? + gen.send(:app_const) : gen.send(:valid_app_const?) gen end end diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index 48fce92215..0926707a04 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -15,8 +15,6 @@ end desc 'Explain the current environment' task :about do - $LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info" - require 'rails/info' puts Rails::Info end @@ -26,12 +24,12 @@ namespace :time do task :all do build_time_zone_list(:all) end - + desc 'Displays names of US time zones recognized by the Rails TimeZone class, grouped by offset. Results can be filtered with optional OFFSET parameter, e.g., OFFSET=-6' task :us do build_time_zone_list(:us_zones) end - + desc 'Displays names of time zones recognized by the Rails TimeZone class with the same offset as the system local time' task :local do require 'active_support' @@ -41,7 +39,7 @@ namespace :time do offset = jan_offset < jul_offset ? jan_offset : jul_offset build_time_zone_list(:all, offset) end - + # to find UTC -06:00 zones, OFFSET can be set to either -6, -6:00 or 21600 def build_time_zone_list(method, offset = ENV['OFFSET']) require 'active_support' diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 2ed5353755..6522c94ad6 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -4,14 +4,18 @@ abort("Abort testing: Your Rails environment is not running in test mode!") unle require 'test/unit' require 'active_support/core_ext/kernel/requires' +require 'active_support/test_case' +require 'action_controller/test_case' +require 'action_dispatch/testing/integration' -# TODO: Figure out how to get the Rails::BacktraceFilter into minitest/unit if defined?(Test::Unit::Util::BacktraceFilter) && ENV['BACKTRACE'].nil? require 'rails/backtrace_cleaner' Test::Unit::Util::BacktraceFilter.module_eval { include Rails::BacktraceFilterForTestUnit } end if defined?(ActiveRecord) + require 'active_record/test_case' + class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index d99325a6d8..e3fafc4b9d 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,7 +1,5 @@ module Rails class TestUnitRailtie < Rails::Railtie - railtie_name :test_unit - config.generators do |c| c.test_framework :test_unit, :fixture => true, :fixture_replacement => nil diff --git a/railties/railties.gemspec b/railties/railties.gemspec index b9d2739539..aea07efe96 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |s| s.homepage = 'http://www.rubyonrails.org' s.rubyforge_project = 'rails' - s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'builtin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}'] + s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}'] s.require_path = 'lib' s.bindir = 'bin' s.executables = ['rails'] diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index aa66dbb9be..d04a2aa1f3 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -1,7 +1,6 @@ ORIG_ARGV = ARGV.dup require File.expand_path("../../../load_paths", __FILE__) -$:.unshift File.expand_path("../../builtin/rails_info", __FILE__) require 'stringio' require 'test/unit' diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 54cd751f4e..68ca2acaad 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -140,7 +140,7 @@ module ApplicationTests require "#{app_path}/config/environment" end end - + test "filter_parameters should be able to set via config.filter_parameters" do add_to_config <<-RUBY config.filter_parameters += [ :foo, 'bar', lambda { |key, value| @@ -172,16 +172,27 @@ module ApplicationTests assert $prepared end - test "config.action_dispatch.x_sendfile_header defaults to X-Sendfile" do + def make_basic_app require "rails" require "action_controller/railtie" - class MyApp < Rails::Application - config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4" - config.session_store :cookie_store, :key => "_myapp_session" + app = Class.new(Rails::Application) + + yield app if block_given? + + app.config.session_store :disabled + app.initialize! + + app.routes.draw do + match "/" => "omg#index" end - MyApp.initialize! + require 'rack/test' + extend Rack::Test::Methods + end + + test "config.action_dispatch.x_sendfile_header defaults to ''" do + make_basic_app class ::OmgController < ActionController::Base def index @@ -189,44 +200,53 @@ module ApplicationTests end end - MyApp.routes.draw do - match "/" => "omg#index" + get "/" + assert_equal File.read(__FILE__), last_response.body + end + + test "config.action_dispatch.x_sendfile_header can be set" do + make_basic_app do |app| + app.config.action_dispatch.x_sendfile_header = "X-Sendfile" end - require 'rack/test' - extend Rack::Test::Methods + class ::OmgController < ActionController::Base + def index + send_file __FILE__ + end + end get "/" assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"] end test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do - require "rails" - require "action_controller/railtie" - - class MyApp < Rails::Application - config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4" - config.session_store :cookie_store, :key => "_myapp_session" - config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File' + make_basic_app do |app| + app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File' end - MyApp.initialize! - class ::OmgController < ActionController::Base def index send_file __FILE__ end end - MyApp.routes.draw do - match "/" => "omg#index" - end + get "/" + assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"] + end - require 'rack/test' - extend Rack::Test::Methods + test "protect from forgery is the default in a new app" do + make_basic_app + + class ::OmgController < ActionController::Base + protect_from_forgery + + def index + render :inline => "<%= csrf_meta_tag %>" + end + end get "/" - assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"] + assert last_response.body =~ /csrf\-param/ end end end diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb index 511b8b629a..589e515d05 100644 --- a/railties/test/application/paths_test.rb +++ b/railties/test/application/paths_test.rb @@ -51,8 +51,6 @@ module ApplicationTests assert_path @paths.config.environment, "config", "environments", "development.rb" assert_equal root("app", "controllers"), @paths.app.controllers.to_a.first - assert_equal Pathname.new(File.dirname(__FILE__)).join("..", "..", "builtin", "rails_info").expand_path, - Pathname.new(@paths.app.controllers.to_a[1]).expand_path end test "booting up Rails yields a list of paths that are eager" do @@ -80,21 +78,5 @@ module ApplicationTests assert_not_in_load_path "tmp" assert_not_in_load_path "tmp", "cache" end - - test "controller paths include builtin in development mode" do - Rails.env.replace "development" - assert Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ } - end - - test "controller paths does not have builtin_directories in test mode" do - Rails.env.replace "test" - assert !Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ } - end - - test "controller paths does not have builtin_directories in production mode" do - Rails.env.replace "production" - assert !Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ } - end - end end diff --git a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb index 7a4edb8bcb..a7d079a1bc 100644 --- a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb +++ b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb @@ -1,4 +1,4 @@ -require 'generators/active_record' +require 'rails/generators/active_record' module ActiveRecord module Generators diff --git a/railties/test/fixtures/lib/rails_generators/foobar/foobar_generator.rb b/railties/test/fixtures/lib/rails/generators/foobar/foobar_generator.rb index d1de8c56fa..d1de8c56fa 100644 --- a/railties/test/fixtures/lib/rails_generators/foobar/foobar_generator.rb +++ b/railties/test/fixtures/lib/rails/generators/foobar/foobar_generator.rb diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 3585e6e7c0..44e0640552 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -1,8 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/app/app_generator' - -# TODO This line shouldn't be required -require 'generators/rails/model/model_generator' +require 'rails/generators/rails/app/app_generator' class ActionsTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 4fc26563ff..95ca2acf2c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -1,6 +1,6 @@ require 'abstract_unit' require 'generators/generators_test_helper' -require 'generators/rails/app/app_generator' +require 'rails/generators/rails/app/app_generator' class AppGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 79a4e5bf17..be99dc068d 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -1,10 +1,12 @@ require 'generators/generators_test_helper' -require 'generators/rails/controller/controller_generator' +require 'rails/generators/rails/controller/controller_generator' class ControllerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(Account foo bar) + setup :copy_routes + def test_help_does_not_show_invoked_generators_options_if_they_already_exist content = run_generator ["--help"] assert_no_match /Helper options\:/, content @@ -23,8 +25,6 @@ class ControllerGeneratorTest < Rails::Generators::TestCase Object.send :remove_const, :ObjectController end - # No need to spec content since it's already spec'ed on helper generator. - # def test_invokes_helper run_generator assert_file "app/helpers/account_helper.rb" @@ -49,8 +49,13 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_invokes_default_template_engine run_generator - assert_file "app/views/account/foo.html.erb", /app\/views\/account\/foo/ - assert_file "app/views/account/bar.html.erb", /app\/views\/account\/bar/ + assert_file "app/views/account/foo.html.erb", %r(app/views/account/foo\.html\.erb) + assert_file "app/views/account/bar.html.erb", %r(app/views/account/bar\.html\.erb) + end + + def test_add_routes + run_generator + assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/ end def test_invokes_default_template_engine_even_with_no_action diff --git a/railties/test/generators/generator_generator_test.rb b/railties/test/generators/generator_generator_test.rb index f3fd688e4f..26f975a191 100644 --- a/railties/test/generators/generator_generator_test.rb +++ b/railties/test/generators/generator_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/generator/generator_generator' +require 'rails/generators/rails/generator/generator_generator' class GeneratorGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 32be99b144..d8bdb344f2 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -26,4 +26,11 @@ module GeneratorsTestHelper end end end + + def copy_routes + routes = File.expand_path("../../../lib/rails/generators/rails/app/templates/config/routes.rb", __FILE__) + destination = File.join(destination_root, "config") + FileUtils.mkdir_p(destination) + FileUtils.cp File.expand_path(routes), destination + end end
\ No newline at end of file diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb index 6d7168738e..f0bfebd57f 100644 --- a/railties/test/generators/helper_generator_test.rb +++ b/railties/test/generators/helper_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/helper/helper_generator' +require 'rails/generators/rails/helper/helper_generator' ObjectHelper = Class.new AnotherObjectHelperTest = Class.new diff --git a/railties/test/generators/integration_test_generator_test.rb b/railties/test/generators/integration_test_generator_test.rb index d7fc324c88..cf282a0911 100644 --- a/railties/test/generators/integration_test_generator_test.rb +++ b/railties/test/generators/integration_test_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/integration_test/integration_test_generator' +require 'rails/generators/rails/integration_test/integration_test_generator' class IntegrationTestGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index e6fc1bbb5c..81d6afa221 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/mailer/mailer_generator' +require 'rails/generators/rails/mailer/mailer_generator' class MailerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -28,20 +28,22 @@ class MailerGeneratorTest < Rails::Generators::TestCase def test_invokes_default_test_framework run_generator - assert_file "test/functional/notifier_test.rb", /class NotifierTest < ActionMailer::TestCase/ - assert_file "test/fixtures/notifier/foo", /app\/views\/notifier\/foo/ - assert_file "test/fixtures/notifier/bar", /app\/views\/notifier\/bar/ + assert_file "test/functional/notifier_test.rb" do |test| + assert_match /class NotifierTest < ActionMailer::TestCase/, test + assert_match /test "foo"/, test + assert_match /test "bar"/, test + end end def test_invokes_default_template_engine run_generator assert_file "app/views/notifier/foo.text.erb" do |view| - assert_match /app\/views\/notifier\/foo/, view + assert_match %r(app/views/notifier/foo\.text\.erb), view assert_match /<%= @greeting %>/, view end assert_file "app/views/notifier/bar.text.erb" do |view| - assert_match /app\/views\/notifier\/bar/, view + assert_match %r(app/views/notifier/bar\.text\.erb), view assert_match /<%= @greeting %>/, view end end diff --git a/railties/test/generators/metal_generator_test.rb b/railties/test/generators/metal_generator_test.rb index e3a2384885..615122c882 100644 --- a/railties/test/generators/metal_generator_test.rb +++ b/railties/test/generators/metal_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/metal/metal_generator' +require 'rails/generators/rails/metal/metal_generator' class MetalGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 811a712fd5..762f84d579 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/migration/migration_generator' +require 'rails/generators/rails/migration/migration_generator' class MigrationGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 79ce9a2a7b..f5cfd8eeca 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/model/model_generator' +require 'rails/generators/rails/model/model_generator' class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index f327fb1282..e73dd237fb 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/scaffold_controller/scaffold_controller_generator' +require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' # Mock out what we need from AR::Base. module ActiveRecord @@ -15,6 +15,20 @@ class NamedBaseTest < Rails::Generators::TestCase include GeneratorsTestHelper tests Rails::Generators::ScaffoldControllerGenerator + def test_named_generator_with_underscore + g = generator ['line_item'] + assert_name g, 'line_item', :name + assert_name g, %w(), :class_path + assert_name g, 'LineItem', :class_name + assert_name g, 'line_item', :file_path + assert_name g, 'line_item', :file_name + assert_name g, 'Line item', :human_name + assert_name g, 'line_item', :singular_name + assert_name g, 'line_items', :plural_name + assert_name g, 'line_item', :i18n_scope + assert_name g, 'line_items', :table_name + end + def test_named_generator_attributes g = generator ['admin/foo'] assert_name g, 'admin/foo', :name @@ -22,6 +36,7 @@ class NamedBaseTest < Rails::Generators::TestCase assert_name g, 'Admin::Foo', :class_name assert_name g, 'admin/foo', :file_path assert_name g, 'foo', :file_name + assert_name g, 'Foo', :human_name assert_name g, 'foo', :singular_name assert_name g, 'foos', :plural_name assert_name g, 'admin.foo', :i18n_scope @@ -36,6 +51,7 @@ class NamedBaseTest < Rails::Generators::TestCase assert_name g, 'admin/foo', :file_path assert_name g, 'foo', :file_name assert_name g, 'foo', :singular_name + assert_name g, 'Foo', :human_name assert_name g, 'foos', :plural_name assert_name g, 'admin.foo', :i18n_scope assert_name g, 'admin_foos', :table_name @@ -45,6 +61,8 @@ class NamedBaseTest < Rails::Generators::TestCase ActiveRecord::Base.pluralize_table_names = false g = generator ['admin/foo'] assert_name g, 'admin_foo', :table_name + ensure + ActiveRecord::Base.pluralize_table_names = true end def test_scaffold_plural_names diff --git a/railties/test/generators/observer_generator_test.rb b/railties/test/generators/observer_generator_test.rb index 058a19228d..45fe8dfbd3 100644 --- a/railties/test/generators/observer_generator_test.rb +++ b/railties/test/generators/observer_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/observer/observer_generator' +require 'rails/generators/rails/observer/observer_generator' class ObserverGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/performance_test_generator_test.rb b/railties/test/generators/performance_test_generator_test.rb index c95063a127..8fda83b36f 100644 --- a/railties/test/generators/performance_test_generator_test.rb +++ b/railties/test/generators/performance_test_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/performance_test/performance_test_generator' +require 'rails/generators/rails/performance_test/performance_test_generator' class PerformanceTestGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 065dbe1423..c1f646f7c1 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/plugin/plugin_generator' +require 'rails/generators/rails/plugin/plugin_generator' class PluginGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 959934bd71..96fd7a0a72 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -1,19 +1,11 @@ require 'generators/generators_test_helper' -require 'generators/rails/resource/resource_generator' +require 'rails/generators/rails/resource/resource_generator' class ResourceGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(account) - def setup - super - routes = Rails::Generators::ResourceGenerator.source_root - routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb") - destination = File.join(destination_root, "config") - - FileUtils.mkdir_p(destination) - FileUtils.cp File.expand_path(routes), destination - end + setup :copy_routes def test_help_with_inherited_options content = run_generator ["--help"] diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index f971598d18..77ed63b1bb 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/scaffold_controller/scaffold_controller_generator' +require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' module Unknown module Generators diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index a7e9c8a231..6cf2efca45 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -1,19 +1,11 @@ require 'generators/generators_test_helper' -require 'generators/rails/scaffold/scaffold_generator' +require 'rails/generators/rails/scaffold/scaffold_generator' class ScaffoldGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(product_line title:string price:integer) - def setup - super - routes = Rails::Generators::ResourceGenerator.source_root - routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb") - destination = File.join(destination_root, "config") - - FileUtils.mkdir_p(destination) - FileUtils.cp File.expand_path(routes), destination - end + setup :copy_routes def test_scaffold_on_invoke run_generator diff --git a/railties/test/generators/session_migration_generator_test.rb b/railties/test/generators/session_migration_generator_test.rb index de28b4c75b..9fee948d7c 100644 --- a/railties/test/generators/session_migration_generator_test.rb +++ b/railties/test/generators/session_migration_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/session_migration/session_migration_generator' +require 'rails/generators/rails/session_migration/session_migration_generator' class SessionMigrationGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/stylesheets_generator_test.rb b/railties/test/generators/stylesheets_generator_test.rb index 718fcb1fa7..aaeb686daa 100644 --- a/railties/test/generators/stylesheets_generator_test.rb +++ b/railties/test/generators/stylesheets_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'generators/rails/stylesheets/stylesheets_generator' +require 'rails/generators/rails/stylesheets/stylesheets_generator' class StylesheetsGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 2975e3e3ef..16f8f43b99 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -1,6 +1,6 @@ require 'generators/generators_test_helper' -require 'generators/rails/model/model_generator' -require 'generators/test_unit/model/model_generator' +require 'rails/generators/rails/model/model_generator' +require 'rails/generators/test_unit/model/model_generator' require 'mocha' class GeneratorsTest < Rails::Generators::TestCase diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index d904d7b461..05ec359f61 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,9 +1,6 @@ require 'abstract_unit' require 'action_controller' -require 'rails/info' -require 'rails/info_controller' - module ActionController class Base include ActionController::Testing diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 9fefb285b4..546bf5e143 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -32,28 +32,25 @@ module RailtiesTest end test "config name is available for the railtie" do - class Foo < Rails::Railtie ; config.foo.greetings = "hello" ; end + class Foo < Rails::Railtie + config.foo = ActiveSupport::OrderedOptions.new + config.foo.greetings = "hello" + end assert_equal "hello", Foo.config.foo.greetings end test "railtie configurations are available in the application" do - class Foo < Rails::Railtie ; config.foo.greetings = "hello" ; end + class Foo < Rails::Railtie + config.foo = ActiveSupport::OrderedOptions.new + config.foo.greetings = "hello" + end require "#{app_path}/config/application" assert_equal "hello", AppTemplate::Application.config.foo.greetings end - test "railtie config merges are deep" do - class Foo < Rails::Railtie ; config.foo.greetings = 'hello' ; end - class Bar < Rails::Railtie - config.foo.bar = "bar" - end - assert_equal "hello", Bar.config.foo.greetings - assert_equal "bar", Bar.config.foo.bar - end - test "railtie can add log subscribers" do begin - class Foo < Rails::Railtie ; log_subscriber(Rails::LogSubscriber.new) ; end + class Foo < Rails::Railtie ; log_subscriber(:foo, Rails::LogSubscriber.new) ; end assert_kind_of Rails::LogSubscriber, Rails::LogSubscriber.log_subscribers[0] ensure Rails::LogSubscriber.log_subscribers.clear |