aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2009-12-21 11:21:27 +0100
committerJosé Valim <jose.valim@gmail.com>2009-12-21 11:21:27 +0100
commit5f34421c77b4cd873baadbbca877a93de5a4d602 (patch)
tree8182bb1c53864ab06079e14116a61d66e9617f7d
parentcf7b94c013d4e824433a018001474e71ddd81a99 (diff)
parentf09ad263cabe2e781c1994b85375fee8deba4317 (diff)
downloadrails-5f34421c77b4cd873baadbbca877a93de5a4d602.tar.gz
rails-5f34421c77b4cd873baadbbca877a93de5a4d602.tar.bz2
rails-5f34421c77b4cd873baadbbca877a93de5a4d602.zip
Merge branch 'master' of git://github.com/rails/rails
-rw-r--r--Gemfile4
-rw-r--r--actionmailer/Rakefile1
-rw-r--r--actionmailer/lib/action_mailer.rb5
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionmailer/test/abstract_unit.rb7
-rw-r--r--actionpack/CHANGELOG14
-rw-r--r--actionpack/Rakefile2
-rw-r--r--actionpack/lib/abstract_controller.rb29
-rw-r--r--actionpack/lib/abstract_controller/base.rb7
-rw-r--r--actionpack/lib/abstract_controller/exceptions.rb12
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb2
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb2
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb (renamed from actionpack/lib/abstract_controller/rendering_controller.rb)26
-rw-r--r--actionpack/lib/action_controller.rb87
-rw-r--r--actionpack/lib/action_controller/base.rb77
-rw-r--r--actionpack/lib/action_controller/deprecated/integration_test.rb2
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb5
-rw-r--r--actionpack/lib/action_controller/metal.rb9
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/cookies.rb2
-rw-r--r--actionpack/lib/action_controller/metal/flash.rb42
-rw-r--r--actionpack/lib/action_controller/metal/head.rb7
-rw-r--r--actionpack/lib/action_controller/metal/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb (renamed from actionpack/lib/action_controller/metal/rack_convenience.rb)3
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb90
-rw-r--r--actionpack/lib/action_controller/metal/redirector.rb22
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb (renamed from actionpack/lib/action_controller/metal/render_options.rb)7
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb (renamed from actionpack/lib/action_controller/metal/rendering_controller.rb)4
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb32
-rw-r--r--actionpack/lib/action_controller/metal/session.rb15
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb2
-rw-r--r--actionpack/lib/action_controller/metal/verification.rb70
-rw-r--r--actionpack/lib/action_controller/test_case.rb4
-rw-r--r--actionpack/lib/action_controller/testing/process.rb111
-rw-r--r--actionpack/lib/action_dispatch.rb58
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb12
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb30
-rw-r--r--actionpack/lib/action_dispatch/http/status_codes.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/utils.rb20
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb46
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb24
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb92
-rw-r--r--actionpack/lib/action_dispatch/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb42
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb19
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb42
-rw-r--r--actionpack/lib/action_view.rb13
-rw-r--r--actionpack/lib/action_view/test_case.rb3
-rw-r--r--actionpack/test/abstract/abstract_controller_test.rb2
-rw-r--r--actionpack/test/abstract/helper_test.rb2
-rw-r--r--actionpack/test/abstract/layouts_test.rb2
-rw-r--r--actionpack/test/abstract/localized_cache_test.rb2
-rw-r--r--actionpack/test/abstract/render_test.rb2
-rw-r--r--actionpack/test/abstract_unit.rb17
-rw-r--r--actionpack/test/active_record_unit.rb8
-rw-r--r--actionpack/test/controller/dispatcher_test.rb13
-rw-r--r--actionpack/test/controller/flash_test.rb29
-rw-r--r--actionpack/test/controller/routing_test.rb72
-rw-r--r--actionpack/test/controller/test_test.rb8
-rw-r--r--actionpack/test/dispatch/response_test.rb121
-rw-r--r--actionpack/test/dispatch/routing_test.rb37
-rwxr-xr-xactivemodel/Rakefile1
-rw-r--r--activemodel/lib/active_model.rb5
-rw-r--r--activemodel/test/cases/helper.rb6
-rw-r--r--activerecord/lib/active_record.rb15
-rwxr-xr-xactiverecord/lib/active_record/associations.rb4
-rw-r--r--activerecord/lib/active_record/associations/association_proxy.rb8
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb9
-rw-r--r--activerecord/test/cases/associations_test.rb10
-rw-r--r--activerecord/test/cases/helper.rb6
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb11
-rw-r--r--activeresource/Rakefile3
-rw-r--r--activeresource/lib/active_resource.rb14
-rw-r--r--activeresource/lib/active_resource/base.rb140
-rw-r--r--activeresource/lib/active_resource/schema.rb55
-rw-r--r--activeresource/test/abstract_unit.rb8
-rw-r--r--activeresource/test/cases/base/schema_test.rb419
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/Rakefile1
-rw-r--r--activesupport/lib/active_support/core_ext/class/removal.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/object/extending.rb73
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb1
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb20
-rw-r--r--activesupport/lib/active_support/ruby/shim.rb1
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb5
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb6
-rw-r--r--activesupport/test/deprecation_test.rb2
-rwxr-xr-xrailties/bin/rails7
-rw-r--r--railties/lib/rails.rb5
-rw-r--r--railties/lib/rails/application.rb63
-rw-r--r--railties/lib/rails/configuration.rb84
-rw-r--r--railties/lib/rails/console_app.rb3
-rw-r--r--railties/lib/rails/generators.rb5
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/routes.rb10
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/model/templates/fixtures.yml14
-rw-r--r--railties/lib/rails/initializable.rb4
-rw-r--r--railties/lib/rails/plugin.rb25
-rw-r--r--railties/lib/rails/test_help.rb1
-rw-r--r--railties/test/application/configuration_test.rb21
-rw-r--r--railties/test/application/initializer_test.rb1
-rw-r--r--railties/test/application/routing_test.rb70
-rw-r--r--railties/test/plugins/configuration_test.rb36
114 files changed, 1820 insertions, 857 deletions
diff --git a/Gemfile b/Gemfile
index 87bf43b786..d979add5b3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,9 +1,9 @@
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
-gem "rails", "3.0.pre", :vendored_at => "railties"
+gem "rails", "3.0.pre", :path => "railties"
%w(activesupport activemodel actionpack actionmailer activerecord activeresource).each do |lib|
- gem lib, '3.0.pre', :vendored_at => lib
+ gem lib, '3.0.pre', :path => lib
end
# AR
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index 1a7ece5068..6c19371514 100644
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -23,7 +23,6 @@ task :default => [ :test ]
Rake::TestTask.new { |t|
t.libs << "test"
t.pattern = 'test/*_test.rb'
- t.verbose = true
t.warning = true
}
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index eec4040bcc..f439eb175c 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -21,8 +21,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-actionpack_path = "#{File.dirname(__FILE__)}/../../actionpack/lib"
-$:.unshift(actionpack_path) if File.directory?(actionpack_path)
+actionpack_path = File.expand_path('../../../actionpack/lib', __FILE__)
+$:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(actionpack_path)
+
require 'action_controller'
require 'action_view'
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index b5239ac0cd..a69838fe43 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -253,7 +253,7 @@ module ActionMailer #:nodoc:
class Base
include AdvAttrAccessor, PartContainer, Quoting, Utils
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
include AbstractController::Layouts
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index e84b3b0d23..af6f1bc92e 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -1,12 +1,9 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
- $:.unshift("#{root}/actionpack/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'rubygems'
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 30f3f31563..782b4229fb 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,19 @@
*Edge*
+* Added ActionDispatch::Request#authorization to access the http authentication header regardless of its proxy hiding [DHH]
+
+* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
+
+ flash[:notice] = 'Post was created'
+ redirect_to(@post)
+
+ ...becomes:
+
+ redirect_to(@post, :notice => 'Post was created')
+
+* Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH]
+
+
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
* Make sure javascript_include_tag/stylesheet_link_tag does not append ".js" or ".css" onto external urls. #1664 [Matthew Rudy Jacobs]
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 99bdcc95fa..863daa4b44 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -31,7 +31,6 @@ Rake::TestTask.new(:test_action_pack) do |t|
# this will not happen automatically and the tests (as a whole) will error
t.test_files = Dir.glob('test/{abstract,controller,dispatch,template}/**/*_test.rb').sort
- t.verbose = true
# t.warning = true
end
@@ -45,7 +44,6 @@ desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|
t.libs << 'test'
t.test_files = Dir.glob("test/activerecord/*_test.rb")
- t.verbose = true
end
# Genereate the RDoc documentation
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 688a2fe31c..c15a1da98a 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,21 +1,20 @@
-require "active_support/core_ext/module/attr_internal"
-require "active_support/core_ext/module/delegation"
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+require 'active_support/ruby/shim'
+require 'active_support/core_ext/module/attr_internal'
+require 'active_support/core_ext/module/delegation'
module AbstractController
extend ActiveSupport::Autoload
- autoload :Base
- autoload :Callbacks
- autoload :Helpers
- autoload :Layouts
- autoload :LocalizedCache
- autoload :Logger
- autoload :RenderingController
-
- # === Exceptions
- autoload_at "abstract_controller/exceptions" do
- autoload :ActionNotFound
- autoload :DoubleRenderError
- autoload :Error
+ deferrable do
+ autoload :Base
+ autoload :Callbacks
+ autoload :Helpers
+ autoload :Layouts
+ autoload :LocalizedCache
+ autoload :Logger
+ autoload :Rendering
end
end
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index f5b1c9e4d1..9d57c52429 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -1,8 +1,11 @@
module AbstractController
+ class Error < StandardError; end
+ class ActionNotFound < StandardError; end
class Base
attr_internal :response_body
attr_internal :action_name
+ attr_internal :formats
class << self
attr_reader :abstract
@@ -74,7 +77,7 @@ module AbstractController
abstract!
# Calls the action going through the entire action dispatch stack.
- #
+ #
# The actual method that is called is determined by calling
# #method_for_action. If no method can handle the action, then an
# ActionNotFound error is raised.
@@ -88,6 +91,8 @@ module AbstractController
raise ActionNotFound, "The action '#{action}' could not be found"
end
+ @_response_body = nil
+
process_action(action_name)
end
diff --git a/actionpack/lib/abstract_controller/exceptions.rb b/actionpack/lib/abstract_controller/exceptions.rb
deleted file mode 100644
index b671516de1..0000000000
--- a/actionpack/lib/abstract_controller/exceptions.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module AbstractController
- class Error < StandardError; end
- class ActionNotFound < StandardError; end
-
- class DoubleRenderError < Error
- DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-end
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index d3b492ad09..1d898d1a4c 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -4,7 +4,7 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
def self.next_serial
@helper_serial ||= 0
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index c71cef42b2..46760bba7c 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -2,7 +2,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering.rb
index 777e515d60..f4e1580977 100644
--- a/actionpack/lib/abstract_controller/rendering_controller.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,13 +1,21 @@
+require "abstract_controller/base"
require "abstract_controller/logger"
module AbstractController
- module RenderingController
+ class DoubleRenderError < Error
+ DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Rendering
extend ActiveSupport::Concern
include AbstractController::Logger
included do
- attr_internal :formats
extlib_inheritable_accessor :_view_paths
self._view_paths ||= ActionView::PathSet.new
end
@@ -21,7 +29,7 @@ module AbstractController
# 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] Create a new ActionView instance for a
+ # View.for_controller[controller] Create a new ActionView instance for a
# controller
# View#render_partial[options]
# - responsible for setting options[:_template]
@@ -71,7 +79,7 @@ module AbstractController
#
# :api: plugin
def render_to_string(options = {})
- AbstractController::RenderingController.body_to_s(render_to_body(options))
+ AbstractController::Rendering.body_to_s(render_to_body(options))
end
# Renders the template from an object.
@@ -152,12 +160,12 @@ module AbstractController
module ClassMethods
def clear_template_caches!
end
-
+
# Append a path to the list of view paths for this controller.
#
# ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def append_view_path(path)
self.view_paths << path
@@ -166,8 +174,8 @@ module AbstractController
# Prepend a path to the list of view paths for this controller.
#
# ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def prepend_view_path(path)
clear_template_caches!
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index f830223058..e31b795cd2 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -1,53 +1,58 @@
-require "active_support"
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
module ActionController
extend ActiveSupport::Autoload
- autoload :Base
- autoload :Caching
- autoload :PolymorphicRoutes
- autoload :RecordIdentifier
- autoload :UrlRewriter
- autoload :Translation
- autoload :Metal
- autoload :Middleware
+ deferrable do
+ autoload :Base
+ autoload :Caching
+ autoload :PolymorphicRoutes
+ autoload :Translation
+ autoload :Metal
+ autoload :Middleware
- autoload_under "metal" do
- autoload :Benchmarking
- autoload :ConditionalGet
- autoload :Configuration
- autoload :Head
- autoload :Helpers
- autoload :HideActions
- autoload :Layouts
- autoload :MimeResponds
- autoload :RackConvenience
- autoload :Compatibility
- autoload :Redirector
- autoload :RenderingController
- autoload :RenderOptions
- autoload :Rescue
- autoload :Responder
- autoload :Session
- autoload :SessionManagement
- autoload :UrlFor
- autoload :Verification
- autoload :Flash
- autoload :RequestForgeryProtection
- autoload :Streaming
- autoload :HttpAuthentication
- autoload :FilterParameterLogging
- autoload :Cookies
- end
+ autoload_under "metal" do
+ autoload :Benchmarking
+ autoload :ConditionalGet
+ autoload :Configuration
+ autoload :Head
+ autoload :Helpers
+ autoload :HideActions
+ autoload :Layouts
+ autoload :MimeResponds
+ autoload :RackDelegation
+ autoload :Compatibility
+ autoload :Redirecting
+ autoload :Rendering
+ autoload :Renderers
+ autoload :Rescue
+ autoload :Responder
+ autoload :SessionManagement
+ autoload :UrlFor
+ autoload :Verification
+ autoload :Flash
+ autoload :RequestForgeryProtection
+ autoload :Streaming
+ autoload :HttpAuthentication
+ autoload :FilterParameterLogging
+ autoload :Cookies
+ end
- autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
- autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
- autoload :Routing, 'action_controller/deprecated'
- autoload :Integration, 'action_controller/deprecated/integration_test'
- autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
+ autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
+ autoload :Routing, 'action_controller/deprecated'
+ autoload :Integration, 'action_controller/deprecated/integration_test'
+ autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
+ end
+ autoload :RecordIdentifier
+ autoload :UrlRewriter
autoload :UrlWriter, 'action_controller/url_rewriter'
+ # TODO: Don't autoload exceptions, setup explicit
+ # requires for files that need them
autoload_at "action_controller/metal/exceptions" do
autoload :ActionControllerError
autoload :RenderError
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 48bfbab215..452f0cd4f0 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -8,12 +8,12 @@ module ActionController
include ActionController::Helpers
include ActionController::HideActions
include ActionController::UrlFor
- include ActionController::Redirector
- include ActionController::RenderingController
- include ActionController::RenderOptions::All
+ include ActionController::Redirecting
+ include ActionController::Rendering
+ include ActionController::Renderers::All
include ActionController::Layouts
include ActionController::ConditionalGet
- include ActionController::RackConvenience
+ include ActionController::RackDelegation
include ActionController::Benchmarking
include ActionController::Configuration
@@ -26,7 +26,6 @@ module ActionController
include ActionController::Compatibility
include ActionController::Cookies
- include ActionController::Session
include ActionController::Flash
include ActionController::Verification
include ActionController::RequestForgeryProtection
@@ -90,7 +89,7 @@ module ActionController
end
if options[:status]
- options[:status] = _interpret_status(options[:status])
+ options[:status] = ActionDispatch::StatusCodes[options[:status]]
end
options[:update] = blk if block_given?
@@ -106,71 +105,5 @@ module ActionController
options = _normalize_options(action, options, &blk)
super(options)
end
-
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
- #
- # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
- # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
- # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
- # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
- # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
- # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
- #
- # Examples:
- # redirect_to :action => "show", :id => 5
- # redirect_to post
- # redirect_to "http://www.rubyonrails.org"
- # redirect_to "/images/screenshot.jpg"
- # redirect_to articles_url
- # redirect_to :back
- #
- # The redirection happens as a "302 Moved" header unless otherwise specified.
- #
- # Examples:
- # redirect_to post_url(@post), :status=>:found
- # redirect_to :action=>'atom', :status=>:moved_permanently
- # redirect_to post_url(@post), :status=>301
- # redirect_to :action=>'atom', :status=>302
- #
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
- # RedirectBackError will be raised. You may specify some fallback
- # behavior for this case by rescuing RedirectBackError.
- def redirect_to(options = {}, response_status = {}) #:doc:
- raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
-
- status = if options.is_a?(Hash) && options.key?(:status)
- _interpret_status(options.delete(:status))
- elsif response_status.key?(:status)
- _interpret_status(response_status[:status])
- else
- 302
- end
-
- url = case options
- # 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+.-]*:.*}
- options
- when String
- request.protocol + request.host_with_port + options
- when :back
- raise RedirectBackError unless refer = request.headers["Referer"]
- refer
- else
- url_for(options)
- end
-
- super(url, status)
- end
-
- private
- def _interpret_status(status)
- if status.is_a?(Symbol)
- (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500)
- else
- status.to_i
- end
- end
end
end
diff --git a/actionpack/lib/action_controller/deprecated/integration_test.rb b/actionpack/lib/action_controller/deprecated/integration_test.rb
index 05c8c0f156..86336b6bc4 100644
--- a/actionpack/lib/action_controller/deprecated/integration_test.rb
+++ b/actionpack/lib/action_controller/deprecated/integration_test.rb
@@ -1,4 +1,2 @@
-require "action_dispatch/testing/integration"
-
ActionController::Integration = ActionDispatch::Integration
ActionController::IntegrationTest = ActionDispatch::IntegrationTest
diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb
index e04da42637..cf02757cf6 100644
--- a/actionpack/lib/action_controller/dispatch/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -13,11 +13,6 @@ module ActionController
# Run prepare callbacks before every request in development mode
self.prepare_each_request = true
- # Development mode callbacks
- ActionDispatch::Callbacks.before_dispatch do |app|
- ActionController::Routing::Routes.reload
- end
-
ActionDispatch::Callbacks.after_dispatch do
# Cleanup the application before processing the current request.
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 60b3f9a89b..93a19f8f93 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -45,7 +45,7 @@ module ActionController
# The details below can be overridden to support a specific
# Request and Response object. The default ActionController::Base
- # implementation includes RackConvenience, which makes a request
+ # implementation includes RackDelegation, which makes a request
# and response object available. You might wish to control the
# environment and response manually for performance reasons.
@@ -57,7 +57,7 @@ module ActionController
end
# Basic implementations for content_type=, location=, and headers are
- # provided to reduce the dependency on the RackConvenience module
+ # provided to reduce the dependency on the RackDelegation module
# in Renderer and Redirector.
def content_type=(type)
@@ -68,6 +68,10 @@ module ActionController
headers["Location"] = url
end
+ def status=(status)
+ @_status = ActionDispatch::StatusCodes[status]
+ end
+
# :api: private
def dispatch(name, env)
@_env = env
@@ -92,6 +96,7 @@ module ActionController
def initialize(controller, action)
@controller, @action = controller, action
+ @_formats = [Mime::HTML]
end
def call(env)
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 5156fbc1d5..61e7ece90d 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -2,7 +2,7 @@ module ActionController
module ConditionalGet
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
include Head
# Sets the etag, last_modified, or both on the response and renders a
diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb
index 6855ca1478..e27374e4c4 100644
--- a/actionpack/lib/action_controller/metal/cookies.rb
+++ b/actionpack/lib/action_controller/metal/cookies.rb
@@ -46,7 +46,7 @@ module ActionController #:nodoc:
module Cookies
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
included do
helper_method :cookies
diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb
index b2d44c6c63..581ff6109e 100644
--- a/actionpack/lib/action_controller/metal/flash.rb
+++ b/actionpack/lib/action_controller/metal/flash.rb
@@ -28,7 +28,9 @@ module ActionController #:nodoc:
module Flash
extend ActiveSupport::Concern
- include Session
+ included do
+ helper_method :alert, :notice
+ end
class FlashNow #:nodoc:
def initialize(flash)
@@ -147,8 +149,30 @@ module ActionController #:nodoc:
@_flash
end
+ # Convenience accessor for flash[:alert]
+ def alert
+ flash[:alert]
+ end
+
+ # Convenience accessor for flash[:alert]=
+ def alert=(message)
+ flash[:alert] = message
+ end
+
+ # Convenience accessor for flash[:notice]
+ def notice
+ flash[:notice]
+ end
+
+ # Convenience accessor for flash[:notice]=
+ def notice=(message)
+ flash[:notice] = message
+ end
+
+
protected
def process_action(method_name)
+ @_flash = nil
super
@_flash.store(session) if @_flash
@_flash = nil
@@ -158,5 +182,21 @@ module ActionController #:nodoc:
super
@_flash = nil
end
+
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
+ if alert = response_status_and_flash.delete(:alert)
+ flash[:alert] = alert
+ end
+
+ if notice = response_status_and_flash.delete(:notice)
+ flash[:notice] = notice
+ end
+
+ if other_flashes = response_status_and_flash.delete(:flash)
+ flash.update(other_flashes)
+ end
+
+ super(options, response_status_and_flash)
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 68fa0a0402..c82d9cf369 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -1,5 +1,7 @@
module ActionController
module Head
+ include UrlFor
+
# Return a response that has no content (merely headers). The options
# argument is interpreted to be a hash of header names and values.
# This allows you to easily return a response that consists only of
@@ -21,7 +23,10 @@ module ActionController
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
end
- render :nothing => true, :status => status, :location => location
+ self.status = status
+ self.location = url_for(location) if location
+ self.content_type = Mime[formats.first]
+ self.response_body = " "
end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb
index cc7088248a..f44498a884 100644
--- a/actionpack/lib/action_controller/metal/layouts.rb
+++ b/actionpack/lib/action_controller/metal/layouts.rb
@@ -158,7 +158,7 @@ module ActionController
module Layouts
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
include AbstractController::Layouts
module ClassMethods
diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 131d20114d..5141918499 100644
--- a/actionpack/lib/action_controller/metal/rack_convenience.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -1,8 +1,9 @@
module ActionController
- module RackConvenience
+ module RackDelegation
extend ActiveSupport::Concern
included do
+ delegate :session, :reset_session, :to => "@_request"
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, :to => "@_response"
attr_internal :request
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
new file mode 100644
index 0000000000..39dc23024c
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -0,0 +1,90 @@
+module ActionController
+ class RedirectBackError < AbstractController::Error #:nodoc:
+ DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Redirecting
+ extend ActiveSupport::Concern
+ include AbstractController::Logger
+
+ # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ #
+ # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
+ # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
+ # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
+ #
+ # Examples:
+ # redirect_to :action => "show", :id => 5
+ # redirect_to post
+ # redirect_to "http://www.rubyonrails.org"
+ # redirect_to "/images/screenshot.jpg"
+ # redirect_to articles_url
+ # redirect_to :back
+ #
+ # The redirection happens as a "302 Moved" header unless otherwise specified.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :status => :found
+ # redirect_to :action=>'atom', :status => :moved_permanently
+ # redirect_to post_url(@post), :status => 301
+ # redirect_to :action=>'atom', :status => 302
+ #
+ # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
+ # +alert+ and +notice+ as well as a general purpose +flash+ bucket.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :alert => "Watch it, mister!"
+ # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
+ # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
+ # redirect_to { :action=>'atom' }, :alert => "Something serious happened"
+ #
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # RedirectBackError will be raised. You may specify some fallback
+ # behavior for this case by rescuing RedirectBackError.
+ def redirect_to(options = {}, response_status = {}) #:doc:
+ raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
+ raise AbstractController::DoubleRenderError if response_body
+
+ self.status = _extract_redirect_to_status(options, response_status)
+ self.location = _compute_redirect_to_location(options)
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
+
+ logger.info("Redirected to #{location}") if logger && logger.info?
+ end
+
+ private
+ def _extract_redirect_to_status(options, response_status)
+ status = if options.is_a?(Hash) && options.key?(:status)
+ ActionDispatch::StatusCodes[options.delete(:status)]
+ elsif response_status.key?(:status)
+ ActionDispatch::StatusCodes[response_status[:status]]
+ else
+ 302
+ end
+ end
+
+ def _compute_redirect_to_location(options)
+ case options
+ # 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+.-]*:.*}
+ options
+ when String
+ request.protocol + request.host_with_port + options
+ when :back
+ raise RedirectBackError unless refer = request.headers["Referer"]
+ refer
+ else
+ url_for(options)
+ end.gsub(/[\r\n]/, '')
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb
deleted file mode 100644
index b55f5e7bfc..0000000000
--- a/actionpack/lib/action_controller/metal/redirector.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module ActionController
- class RedirectBackError < AbstractController::Error #:nodoc:
- DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-
- module Redirector
- extend ActiveSupport::Concern
- include AbstractController::Logger
-
- def redirect_to(url, status) #:doc:
- raise AbstractController::DoubleRenderError if response_body
- logger.info("Redirected to #{url}") if logger && logger.info?
- self.status = status
- self.location = url.gsub(/[\r\n]/, '')
- self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(url)}\">redirected</a>.</body></html>"
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/render_options.rb b/actionpack/lib/action_controller/metal/renderers.rb
index b6a7ca0eda..c1ba47927a 100644
--- a/actionpack/lib/action_controller/metal/render_options.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -1,10 +1,9 @@
module ActionController
-
def self.add_renderer(key, &block)
- RenderOptions.add(key, &block)
+ Renderers.add(key, &block)
end
- module RenderOptions
+ module Renderers
extend ActiveSupport::Concern
included do
@@ -52,7 +51,7 @@ module ActionController
module All
extend ActiveSupport::Concern
- include RenderOptions
+ include Renderers
INCLUDED = []
included do
diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 237299cd30..20eb524e50 100644
--- a/actionpack/lib/action_controller/metal/rendering_controller.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -1,9 +1,9 @@
module ActionController
- module RenderingController
+ module Rendering
extend ActiveSupport::Concern
included do
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 173df79ee7..2826b1e34c 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -5,7 +5,7 @@ module ActionController #:nodoc:
module RequestForgeryProtection
extend ActiveSupport::Concern
- include AbstractController::Helpers, Session
+ include AbstractController::Helpers
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
@@ -19,31 +19,31 @@ module ActionController #:nodoc:
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
-
- # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
- # web application, not a forged link from another site, is done by embedding a token based on a random
+
+ # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
+ # web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
- # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
- # requests are checked, so this will not protect your XML API (presumably you'll have a different
- # authentication scheme there anyway). Also, GET requests are not protected as these should be
+ # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
+ # requests are checked, so this will not protect your XML API (presumably you'll have a different
+ # authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
- # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
+ # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
- # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
- # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
- # include a hidden field named like that and set its value to what is returned by
+ # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
+ # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
+ # include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
- # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
+ # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
- #
+ #
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
@@ -52,11 +52,11 @@ module ActionController #:nodoc:
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
- #
+ #
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
- # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
+ # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
module ClassMethods
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
def verified_request?
- !protect_against_forgery? || request.forgery_whitelisted? ||
+ !protect_against_forgery? || request.forgery_whitelisted? ||
form_authenticity_token == params[request_forgery_protection_token]
end
diff --git a/actionpack/lib/action_controller/metal/session.rb b/actionpack/lib/action_controller/metal/session.rb
deleted file mode 100644
index bcedd6e1c7..0000000000
--- a/actionpack/lib/action_controller/metal/session.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module ActionController
- module Session
- extend ActiveSupport::Concern
-
- include RackConvenience
-
- def session
- @_request.session
- end
-
- def reset_session
- @_request.reset_session
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 43c661bef4..288b5d7c99 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -4,7 +4,7 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index a4a1116d9e..c193a5eff4 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -2,7 +2,7 @@ module ActionController
module Testing
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# OMG MEGA HAX
def process_with_new_base_test(request, response)
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 14c6523045..8c3810ebcb 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -2,7 +2,7 @@ module ActionController
module UrlFor
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
# the form of a hash, just like the one you would use for url_for directly. Example:
diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb
index 500cced539..bce942b588 100644
--- a/actionpack/lib/action_controller/metal/verification.rb
+++ b/actionpack/lib/action_controller/metal/verification.rb
@@ -2,7 +2,7 @@ module ActionController #:nodoc:
module Verification #:nodoc:
extend ActiveSupport::Concern
- include AbstractController::Callbacks, Session, Flash, RenderingController
+ include AbstractController::Callbacks, Flash, Rendering
# This module provides a class-level method for specifying that certain
# actions are guarded against being called without certain prerequisites
@@ -35,7 +35,7 @@ module ActionController #:nodoc:
# :add_flash => { "alert" => "Failed to create your message" },
# :redirect_to => :category_url
#
- # Note that these prerequisites are not business rules. They do not examine
+ # Note that these prerequisites are not business rules. They do not examine
# the content of the session or the parameters. That level of validation should
# be encapsulated by your domain model or helper methods in the controller.
module ClassMethods
@@ -43,40 +43,40 @@ module ActionController #:nodoc:
# the user is redirected to a different action. The +options+ parameter
# is a hash consisting of the following key/value pairs:
#
- # <tt>:params</tt>::
- # a single key or an array of keys that must be in the <tt>params</tt>
+ # <tt>:params</tt>::
+ # a single key or an array of keys that must be in the <tt>params</tt>
# hash in order for the action(s) to be safely called.
- # <tt>:session</tt>::
- # a single key or an array of keys that must be in the <tt>session</tt>
+ # <tt>:session</tt>::
+ # a single key or an array of keys that must be in the <tt>session</tt>
# in order for the action(s) to be safely called.
- # <tt>:flash</tt>::
- # a single key or an array of keys that must be in the flash in order
+ # <tt>:flash</tt>::
+ # a single key or an array of keys that must be in the flash in order
# for the action(s) to be safely called.
- # <tt>:method</tt>::
- # a single key or an array of keys--any one of which must match the
- # current request method in order for the action(s) to be safely called.
- # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
+ # <tt>:method</tt>::
+ # a single key or an array of keys--any one of which must match the
+ # current request method in order for the action(s) to be safely called.
+ # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
# example.)
- # <tt>:xhr</tt>::
- # true/false option to ensure that the request is coming from an Ajax
- # call or not.
- # <tt>:add_flash</tt>::
- # a hash of name/value pairs that should be merged into the session's
+ # <tt>:xhr</tt>::
+ # true/false option to ensure that the request is coming from an Ajax
+ # call or not.
+ # <tt>:add_flash</tt>::
+ # a hash of name/value pairs that should be merged into the session's
# flash if the prerequisites cannot be satisfied.
- # <tt>:add_headers</tt>::
- # a hash of name/value pairs that should be merged into the response's
+ # <tt>:add_headers</tt>::
+ # a hash of name/value pairs that should be merged into the response's
# headers hash if the prerequisites cannot be satisfied.
- # <tt>:redirect_to</tt>::
- # the redirection parameters to be used when redirecting if the
- # prerequisites cannot be satisfied. You can redirect either to named
+ # <tt>:redirect_to</tt>::
+ # the redirection parameters to be used when redirecting if the
+ # prerequisites cannot be satisfied. You can redirect either to named
# route or to the action in some controller.
- # <tt>:render</tt>::
+ # <tt>:render</tt>::
# the render parameters to be used when the prerequisites cannot be satisfied.
- # <tt>:only</tt>::
- # only apply this verification to the actions specified in the associated
+ # <tt>:only</tt>::
+ # only apply this verification to the actions specified in the associated
# array (may also be a single value).
- # <tt>:except</tt>::
- # do not apply this verification to the actions specified in the associated
+ # <tt>:except</tt>::
+ # do not apply this verification to the actions specified in the associated
# array (may also be a single value).
def verify(options={})
before_filter :only => options[:only], :except => options[:except] do
@@ -94,31 +94,31 @@ module ActionController #:nodoc:
apply_remaining_actions(options) unless performed?
end
end
-
+
def prereqs_invalid?(options) # :nodoc:
- verify_presence_of_keys_in_hash_flash_or_params(options) ||
- verify_method(options) ||
+ verify_presence_of_keys_in_hash_flash_or_params(options) ||
+ verify_method(options) ||
verify_request_xhr_status(options)
end
-
+
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
[*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
[*options[:session]].find { |v| session[v].nil? } ||
[*options[:flash] ].find { |v| flash[v].nil? }
end
-
+
def verify_method(options) # :nodoc:
[*options[:method]].all? { |v| request.method != v.to_sym } if options[:method]
end
-
+
def verify_request_xhr_status(options) # :nodoc:
request.xhr? != options[:xhr] unless options[:xhr].nil?
end
-
+
def apply_redirect_to(redirect_to_option) # :nodoc:
(redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
end
-
+
def apply_remaining_actions(options) # :nodoc:
case
when options[:render] ; render(options[:render])
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 7533a22299..398ea52495 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -1,8 +1,6 @@
require 'active_support/test_case'
require 'rack/session/abstract/id'
require 'action_controller/metal/testing'
-require 'action_controller/testing/process'
-require 'action_dispatch/test_case'
module ActionController
class TestRequest < ActionDispatch::TestRequest #:nodoc:
@@ -183,7 +181,7 @@ module ActionController
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
- include TestProcess
+ include ActionDispatch::TestProcess
# 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_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb
deleted file mode 100644
index 323cce6a2f..0000000000
--- a/actionpack/lib/action_controller/testing/process.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require 'active_support/core_ext/object/conversions'
-require "rack/test"
-
-module ActionController #:nodoc:
- # Essentially generates a modified Tempfile object similar to the object
- # you'd get from the standard library CGI module in a multipart
- # request. This means you can use an ActionController::TestUploadedFile
- # object in the params of a test request in order to simulate
- # a file upload.
- #
- # Usage example, within a functional test:
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png')
- #
- # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
- TestUploadedFile = Rack::Test::UploadedFile
-
- module TestProcess
- def assigns(key = nil)
- assigns = {}
- @controller.instance_variable_names.each do |ivar|
- next if ActionController::Base.protected_instance_variables.include?(ivar)
- assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
- end
-
- key.nil? ? assigns : assigns[key.to_s]
- end
-
- def session
- @request.session
- end
-
- def flash
- @request.flash
- end
-
- def cookies
- @request.cookies.merge(@response.cookies)
- end
-
- def redirect_to_url
- @response.redirect_url
- end
-
- def html_document
- xml = @response.content_type =~ /xml$/
- @html_document ||= HTML::Document.new(@response.body, false, xml)
- end
-
- def find_tag(conditions)
- html_document.find(conditions)
- end
-
- def find_all_tag(conditions)
- html_document.find_all(conditions)
- end
-
- def method_missing(selector, *args, &block)
- if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
- @controller.send(selector, *args, &block)
- else
- super
- end
- end
-
- # Shortcut for <tt>ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
- #
- # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
- #
- # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
- # This will not affect other platforms:
- #
- # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
- def fixture_file_upload(path, mime_type = nil, binary = false)
- fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
- ActionController::TestUploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
- end
-
- # A helper to make it easier to test different route configurations.
- # This method temporarily replaces ActionController::Routing::Routes
- # with a new RouteSet instance.
- #
- # The new instance is yielded to the passed block. Typically the block
- # will create some routes using <tt>map.draw { map.connect ... }</tt>:
- #
- # with_routing do |set|
- # set.draw do |map|
- # map.connect ':controller/:action/:id'
- # assert_equal(
- # ['/content/10/show', {}],
- # map.generate(:controller => 'content', :id => 10, :action => 'show')
- # end
- # end
- # end
- #
- def with_routing
- real_routes = ActionController::Routing::Routes
- ActionController::Routing.module_eval { remove_const :Routes }
-
- temporary_routes = ActionController::Routing::RouteSet.new
- ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
-
- yield temporary_routes
- ensure
- if ActionController::Routing.const_defined? :Routes
- ActionController::Routing.module_eval { remove_const :Routes }
- end
- ActionController::Routing.const_set(:Routes, real_routes) if real_routes
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index e21dbc59cc..48b5652a89 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -21,6 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
+
require 'rack'
module Rack
@@ -30,42 +34,46 @@ end
module ActionDispatch
extend ActiveSupport::Autoload
- autoload_under "http" do
+ autoload_under 'http' do
autoload :Request
autoload :Response
autoload :StatusCodes
- autoload :Utils
end
- autoload_under "middleware" do
- autoload :Callbacks
- autoload :ParamsParser
- autoload :Rescue
- autoload :ShowExceptions
- autoload :Static
- autoload :StringCoercion
- end
+ deferrable do
+ autoload_under 'middleware' do
+ autoload :Callbacks
+ autoload :ParamsParser
+ autoload :Rescue
+ autoload :ShowExceptions
+ autoload :Static
+ autoload :StringCoercion
+ end
- autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
- autoload :Routing
+ autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
+ autoload :Routing
- autoload :HTML, 'action_controller/vendor/html-scanner'
+ module Http
+ autoload :Headers, 'action_dispatch/http/headers'
+ end
- module Http
- extend ActiveSupport::Autoload
+ module Session
+ autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
+ end
- autoload :Headers
+ autoload_under 'testing' do
+ autoload :Assertions
+ autoload :Integration
+ autoload :PerformanceTest
+ autoload :TestProcess
+ autoload :TestRequest
+ autoload :TestResponse
+ end
end
- module Session
- autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
- autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
- autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
- end
+ autoload :HTML, 'action_controller/vendor/html-scanner'
end
autoload :Mime, 'action_dispatch/http/mime_type'
-
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift activesupport_path if File.directory?(activesupport_path)
-require 'active_support'
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 6a52854961..bc17cadb38 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -6,6 +6,7 @@ require 'active_support/memoizable'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/string/access'
+require 'action_dispatch/http/headers'
module ActionDispatch
class Request < Rack::Request
@@ -117,7 +118,7 @@ module ActionDispatch
end
end
end
-
+
def if_modified_since
if since = env['HTTP_IF_MODIFIED_SINCE']
Time.rfc2822(since) rescue nil
@@ -464,6 +465,15 @@ EOM
session['flash'] || {}
end
+ # Returns the authorization header regardless of whether it was specified directly or through one of the
+ # proxy alternatives.
+ def authorization
+ @env['HTTP_AUTHORIZATION'] ||
+ @env['X-HTTP_AUTHORIZATION'] ||
+ @env['X_HTTP_AUTHORIZATION'] ||
+ @env['REDIRECT_X_HTTP_AUTHORIZATION']
+ end
+
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
#
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 4f35a00247..6dc563264f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -49,6 +49,9 @@ module ActionDispatch # :nodoc:
@body, @cookie = [], []
@sending_file = false
+ @blank = false
+ @etag = nil
+
yield self if block_given?
end
@@ -57,7 +60,7 @@ module ActionDispatch # :nodoc:
end
def status=(status)
- @status = status.to_i
+ @status = ActionDispatch::StatusCodes[status]
end
# The response code of the request
@@ -142,18 +145,6 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_charset) { "utf-8" }
- def assign_default_content_type_and_charset!
- return if headers[CONTENT_TYPE].present?
-
- @content_type ||= Mime::HTML
- @charset ||= self.class.default_charset
-
- type = @content_type.to_s.dup
- type << "; charset=#{@charset}" unless @sending_file
-
- headers[CONTENT_TYPE] = type
- end
-
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
@@ -256,6 +247,18 @@ module ActionDispatch # :nodoc:
!@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
end
+ def assign_default_content_type_and_charset!
+ return if headers[CONTENT_TYPE].present?
+
+ @content_type ||= Mime::HTML
+ @charset ||= self.class.default_charset
+
+ type = @content_type.to_s.dup
+ type << "; charset=#{@charset}" unless @sending_file
+
+ headers[CONTENT_TYPE] = type
+ end
+
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
def set_conditional_cache_control!
@@ -277,7 +280,6 @@ module ActionDispatch # :nodoc:
headers["Cache-Control"] = options.join(", ")
end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb
index ea1475e827..3d6ee685ea 100644
--- a/actionpack/lib/action_dispatch/http/status_codes.rb
+++ b/actionpack/lib/action_dispatch/http/status_codes.rb
@@ -14,6 +14,14 @@ module ActionDispatch
510 => "Not Extended"
}).freeze
+ def self.[](status)
+ if status.is_a?(Symbol)
+ SYMBOL_TO_STATUS_CODE[status] || 500
+ else
+ status.to_i
+ end
+ end
+
# Provides a symbol-to-fixnum lookup for converting a symbol (like
# :created or :not_implemented) into its corresponding HTTP status
# code (like 200 or 501).
diff --git a/actionpack/lib/action_dispatch/http/utils.rb b/actionpack/lib/action_dispatch/http/utils.rb
deleted file mode 100644
index e04a39935e..0000000000
--- a/actionpack/lib/action_dispatch/http/utils.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module ActionDispatch
- module Utils
- # TODO: Pull this into rack core
- # http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278
- def parse_config(config)
- if config =~ /\.ru$/
- cfgfile = ::File.read(config)
- if cfgfile[/^#\\(.*)/]
- opts.parse! $1.split(/\s+/)
- end
- inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
- nil, config
- else
- require config
- inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
- end
- end
- module_function :parse_config
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 32ccb5c931..8970ccaf07 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -31,41 +31,39 @@ module ActionDispatch
return false unless strategy
case strategy
- when Proc
- strategy.call(request.raw_post)
- when :xml_simple, :xml_node
- request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
- when :yaml
- YAML.load(request.body)
- when :json
- if request.body.size == 0
- {}
- else
- data = ActiveSupport::JSON.decode(request.body)
- data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
- end
+ when Proc
+ strategy.call(request.raw_post)
+ when :xml_simple, :xml_node
+ request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
+ when :yaml
+ YAML.load(request.body)
+ when :json
+ if request.body.size == 0
+ {}
else
- false
+ data = ActiveSupport::JSON.decode(request.body)
+ data = {:_json => data} unless data.is_a?(Hash)
+ data.with_indifferent_access
+ end
+ else
+ false
end
rescue Exception => e # YAML, XML or Ruby code block errors
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise
- { "body" => request.raw_post,
- "content_type" => request.content_type,
+ { "body" => request.raw_post,
+ "content_type" => request.content_type,
"content_length" => request.content_length,
- "exception" => "#{e.message} (#{e.class})",
- "backtrace" => e.backtrace }
+ "exception" => "#{e.message} (#{e.class})",
+ "backtrace" => e.backtrace }
end
def content_type_from_legacy_post_data_format_header(env)
if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
case x_post_format.to_s.downcase
- when 'yaml'
- return Mime::YAML
- when 'xml'
- return Mime::XML
+ when 'yaml' then return Mime::YAML
+ when 'xml' then return Mime::XML
end
end
@@ -76,4 +74,4 @@ module ActionDispatch
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 471d18491c..bd87764f5b 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -10,8 +10,7 @@ module ActionDispatch
@@rescue_responses = Hash.new(:internal_server_error)
@@rescue_responses.update({
'ActionController::RoutingError' => :not_found,
- # TODO: Clean this up after the switch
- ActionController::UnknownAction.name => :not_found,
+ 'AbstractController::ActionNotFound' => :not_found,
'ActiveRecord::RecordNotFound' => :not_found,
'ActiveRecord::StaleObjectError' => :conflict,
'ActiveRecord::RecordInvalid' => :unprocessable_entity,
@@ -26,7 +25,7 @@ module ActionDispatch
@@rescue_templates.update({
'ActionView::MissingTemplate' => 'missing_template',
'ActionController::RoutingError' => 'routing_error',
- ActionController::UnknownAction.name => 'unknown_action',
+ 'AbstractController::ActionNotFound' => 'unknown_action',
'ActionView::Template::Error' => 'template_error'
})
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index d480af876d..46163706c3 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -39,9 +39,13 @@ module ActionDispatch
end
def match(*args)
- options = args.extract_options!
-
- path = args.first
+ if args.one? && args.first.is_a?(Hash)
+ path = args.first.keys.first
+ options = { :to => args.first.values.first }
+ else
+ path = args.first
+ options = args.extract_options!
+ end
conditions, defaults = {}, {}
@@ -132,13 +136,19 @@ module ActionDispatch
map_method(:delete, *args, &block)
end
- def redirect(path, options = {})
+ def redirect(*args, &block)
+ options = args.last.is_a?(Hash) ? args.pop : {}
+
+ path = args.shift || block
+ path_proc = path.is_a?(Proc) ? path : proc {|params| path % params }
status = options[:status] || 301
- lambda { |env|
+
+ lambda do |env|
req = Rack::Request.new(env)
- url = req.scheme + '://' + req.host + path
+ params = path_proc.call(env["action_dispatch.request.path_parameters"])
+ url = req.scheme + '://' + req.host + params
[status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']]
- }
+ end
end
private
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 8afd42a293..bf2443c1be 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -203,20 +203,18 @@ module ActionDispatch
end
end
- attr_accessor :routes, :named_routes, :configuration_files, :controller_paths
+ attr_accessor :routes, :named_routes
+ attr_accessor :disable_clear_and_finalize
def initialize
- self.configuration_files = []
- self.controller_paths = []
-
self.routes = []
self.named_routes = NamedRouteCollection.new
- clear!
+ @disable_clear_and_finalize = false
end
def draw(&block)
- clear!
+ clear! unless @disable_clear_and_finalize
mapper = Mapper.new(self)
if block.arity == 1
@@ -225,12 +223,20 @@ module ActionDispatch
mapper.instance_exec(&block)
end
+ finalize! unless @disable_clear_and_finalize
+
+ nil
+ end
+
+ def finalize!
@set.add_route(NotFound)
install_helpers
@set.freeze
end
def clear!
+ # Clear the controller cache so we may discover new ones
+ @controller_constraints = nil
routes.clear
named_routes.clear
@set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY)
@@ -245,67 +251,6 @@ module ActionDispatch
routes.empty?
end
- def add_configuration_file(path)
- self.configuration_files << path
- end
-
- # Deprecated accessor
- def configuration_file=(path)
- add_configuration_file(path)
- end
-
- # Deprecated accessor
- def configuration_file
- configuration_files
- end
-
- def load!
- # Clear the controller cache so we may discover new ones
- @controller_constraints = nil
-
- load_routes!
- end
-
- # reload! will always force a reload whereas load checks the timestamp first
- alias reload! load!
-
- def reload
- if configuration_files.any? && @routes_last_modified
- if routes_changed_at == @routes_last_modified
- return # routes didn't change, don't reload
- else
- @routes_last_modified = routes_changed_at
- end
- end
-
- load!
- end
-
- def load_routes!
- if configuration_files.any?
- configuration_files.each { |config| load(config) }
- @routes_last_modified = routes_changed_at
- else
- draw do |map|
- map.connect ":controller/:action/:id"
- end
- end
- end
-
- def routes_changed_at
- routes_changed_at = nil
-
- configuration_files.each do |config|
- config_changed_at = File.stat(config).mtime
-
- if routes_changed_at.nil? || config_changed_at > routes_changed_at
- routes_changed_at = config_changed_at
- end
- end
-
- routes_changed_at
- end
-
CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/
def controller_constraints
@@ -325,11 +270,14 @@ module ActionDispatch
namespaces << controller_name.split('/')[0...-1].join('/')
end
- # Find namespaces in controllers/ directory
- controller_paths.each do |load_path|
- load_path = File.expand_path(load_path)
- Dir["#{load_path}/**/*_controller.rb"].collect do |path|
- namespaces << File.dirname(path).sub(/#{load_path}\/?/, '')
+ # TODO: Move this into Railties
+ if defined?(Rails.application)
+ # Find namespaces in controllers/ directory
+ Rails.application.configuration.controller_paths.each do |load_path|
+ load_path = File.expand_path(load_path)
+ Dir["#{load_path}/**/*_controller.rb"].collect do |path|
+ namespaces << File.dirname(path).sub(/#{load_path}\/?/, '')
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/test_case.rb b/actionpack/lib/action_dispatch/test_case.rb
deleted file mode 100644
index afd708f06f..0000000000
--- a/actionpack/lib/action_dispatch/test_case.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require "action_dispatch/testing/assertions"
-require "action_dispatch/testing/integration"
-require "action_dispatch/testing/performance_test"
-require "action_dispatch/testing/test_request"
-require "action_dispatch/testing/test_response"
-require "action_dispatch/testing/integration" \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 4bc5275e04..fc477afb17 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -46,7 +46,6 @@ module ActionDispatch
request_method = nil
end
- ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
request = recognized_request_for(path, request_method)
expected_options = expected_options.clone
@@ -80,7 +79,6 @@ module ActionDispatch
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
# Load routes.rb if it hasn't been loaded.
- ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults)
found_extras = options.reject {|k, v| ! extra_keys.include? k}
@@ -126,6 +124,46 @@ module ActionDispatch
assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message)
end
+ # A helper to make it easier to test different route configurations.
+ # This method temporarily replaces ActionController::Routing::Routes
+ # with a new RouteSet instance.
+ #
+ # The new instance is yielded to the passed block. Typically the block
+ # will create some routes using <tt>map.draw { map.connect ... }</tt>:
+ #
+ # with_routing do |set|
+ # set.draw do |map|
+ # map.connect ':controller/:action/:id'
+ # assert_equal(
+ # ['/content/10/show', {}],
+ # map.generate(:controller => 'content', :id => 10, :action => 'show')
+ # end
+ # end
+ # end
+ #
+ def with_routing
+ real_routes = ActionController::Routing::Routes
+ ActionController::Routing.module_eval { remove_const :Routes }
+
+ temporary_routes = ActionController::Routing::RouteSet.new
+ ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
+
+ yield temporary_routes
+ ensure
+ if ActionController::Routing.const_defined? :Routes
+ ActionController::Routing.module_eval { remove_const :Routes }
+ end
+ ActionController::Routing.const_set(:Routes, real_routes) if real_routes
+ end
+
+ def method_missing(selector, *args, &block)
+ if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
+ @controller.send(selector, *args, &block)
+ else
+ super
+ end
+ end
+
private
# Recognizes the route for a given path.
def recognized_request_for(path, request_method = nil)
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index ef6867576e..b74dcb1fe4 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -76,10 +76,10 @@ module ActionDispatch
# # Assert that there is a "span" containing between 2 and 4 "em" tags
# # as immediate children
# assert_tag :tag => "span",
- # :children => { :count => 2..4, :only => { :tag => "em" } }
+ # :children => { :count => 2..4, :only => { :tag => "em" } }
#
# # Get funky: assert that there is a "div", with an "ul" ancestor
- # # and an "li" parent (with "class" = "enum"), and containing a
+ # # and an "li" parent (with "class" = "enum"), and containing a
# # "span" descendant that contains text matching /hello world/
# assert_tag :tag => "div",
# :ancestor => { :tag => "ul" },
@@ -98,7 +98,7 @@ module ActionDispatch
tag = find_tag(opts)
assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}"
end
-
+
# Identical to +assert_tag+, but asserts that a matching tag does _not_
# exist. (See +assert_tag+ for a full discussion of the syntax.)
#
@@ -118,6 +118,19 @@ module ActionDispatch
tag = find_tag(opts)
assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}"
end
+
+ def find_tag(conditions)
+ html_document.find(conditions)
+ end
+
+ def find_all_tag(conditions)
+ html_document.find_all(conditions)
+ end
+
+ def html_document
+ xml = @response.content_type =~ /xml$/
+ @html_document ||= HTML::Document.new(@response.body, false, xml)
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 40d6f97b2a..5c127dfe37 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -2,9 +2,7 @@ require 'stringio'
require 'uri'
require 'active_support/test_case'
require 'active_support/core_ext/object/metaclass'
-
-# TODO: Remove circular dependency on ActionController
-require 'action_controller/testing/process'
+require 'rack/test'
module ActionDispatch
module Integration #:nodoc:
@@ -128,9 +126,7 @@ module ActionDispatch
DEFAULT_HOST = "www.example.com"
include Test::Unit::Assertions
- include ActionDispatch::Assertions
- include ActionController::TestProcess
- include RequestHelpers
+ include TestProcess, RequestHelpers, Assertions
%w( status status_message headers body redirect? ).each do |method|
delegate method, :to => :response, :allow_nil => true
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
new file mode 100644
index 0000000000..eae703e1b6
--- /dev/null
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -0,0 +1,42 @@
+module ActionDispatch
+ module TestProcess
+ def assigns(key = nil)
+ assigns = {}
+ @controller.instance_variable_names.each do |ivar|
+ next if ActionController::Base.protected_instance_variables.include?(ivar)
+ assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
+ end
+
+ key.nil? ? assigns : assigns[key.to_s]
+ end
+
+ def session
+ @request.session
+ end
+
+ def flash
+ @request.flash
+ end
+
+ def cookies
+ @request.cookies.merge(@response.cookies)
+ end
+
+ def redirect_to_url
+ @response.redirect_url
+ end
+
+ # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
+ #
+ # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
+ #
+ # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
+ # This will not affect other platforms:
+ #
+ # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
+ def fixture_file_upload(path, mime_type = nil, binary = false)
+ fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
+ Rack::Test::UploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
+ end
+ end
+end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 06238ca747..aabe8c4314 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,7 +21,12 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require File.join(File.dirname(__FILE__), "action_pack")
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'active_support/ruby/shim'
+require 'active_support/core_ext/class/attribute_accessors'
+
+require 'action_pack'
module ActionView
extend ActiveSupport::Autoload
@@ -51,10 +56,4 @@ end
require 'action_view/erb/util'
-
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
-
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift activesupport_path if File.directory?(activesupport_path)
-require 'active_support'
-require 'active_support/core_ext/class/attribute_accessors'
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index ab5bc49cf9..be9a2ed50d 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -39,8 +39,7 @@ module ActionView
end
end
- include ActionDispatch::Assertions
- include ActionController::TestProcess
+ include ActionDispatch::Assertions, ActionDispatch::TestProcess
include ActionView::Context
include ActionController::PolymorphicRoutes
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 524381509d..4ad87d9762 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -28,7 +28,7 @@ module AbstractController
# Test Render mixin
# ====
class RenderingController < AbstractController::Base
- include ::AbstractController::RenderingController
+ include ::AbstractController::Rendering
def _prefix() end
diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb
index efcd68e5c8..ade29140ba 100644
--- a/actionpack/test/abstract/helper_test.rb
+++ b/actionpack/test/abstract/helper_test.rb
@@ -6,7 +6,7 @@ module AbstractController
module Testing
class ControllerWithHelpers < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include Helpers
def with_module
diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb
index 5028c19b80..df73d948f0 100644
--- a/actionpack/test/abstract/layouts_test.rb
+++ b/actionpack/test/abstract/layouts_test.rb
@@ -6,7 +6,7 @@ module AbstractControllerTests
# Base controller for these tests
class Base < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::Layouts
self.view_paths = [ActionView::FixtureResolver.new(
diff --git a/actionpack/test/abstract/localized_cache_test.rb b/actionpack/test/abstract/localized_cache_test.rb
index 6f9bb693f7..8b0b0fff03 100644
--- a/actionpack/test/abstract/localized_cache_test.rb
+++ b/actionpack/test/abstract/localized_cache_test.rb
@@ -4,7 +4,7 @@ module AbstractController
module Testing
class CachedController < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
self.view_paths = [ActionView::FixtureResolver.new(
diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb
index 331cb6f769..be0478b638 100644
--- a/actionpack/test/abstract/render_test.rb
+++ b/actionpack/test/abstract/render_test.rb
@@ -4,7 +4,7 @@ module AbstractController
module Testing
class ControllerRenderer < AbstractController::Base
- include AbstractController::RenderingController
+ include AbstractController::Rendering
self.view_paths = [ActionView::FixtureResolver.new(
"default.erb" => "With Default",
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index eab9f8b83d..a9341b60df 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,12 +1,9 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift "#{root}/activesupport/lib"
- $:.unshift "#{root}/activemodel/lib"
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
$:.unshift(File.dirname(__FILE__) + '/lib')
@@ -16,18 +13,20 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')
require 'test/unit'
-require 'active_support'
-require 'active_support/test_case'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
require 'action_view/base'
require 'action_dispatch'
-require 'active_model'
require 'fixture_template'
+require 'active_support/test_case'
require 'action_view/test_case'
require 'active_support/dependencies'
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
+require 'active_model'
+
begin
require 'ruby-debug'
Debugger.settings[:autoeval] = true
@@ -198,7 +197,7 @@ module ActionController
Base.view_paths = FIXTURE_LOAD_PATH
class TestCase
- include TestProcess
+ include ActionDispatch::TestProcess
def assert_template(options = {}, message = nil)
validate_request!
diff --git a/actionpack/test/active_record_unit.rb b/actionpack/test/active_record_unit.rb
index 9e0c66055d..9a094cf66b 100644
--- a/actionpack/test/active_record_unit.rb
+++ b/actionpack/test/active_record_unit.rb
@@ -11,19 +11,15 @@ class ActiveRecordTestConnector
end
# Try to grab AR
-if defined?(ActiveRecord) && defined?(Fixtures)
- $stderr.puts 'Active Record is already loaded, running tests'
-else
- $stderr.print 'Attempting to load Active Record... '
+unless defined?(ActiveRecord) && defined?(Fixtures)
begin
PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib"
raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR)
$LOAD_PATH.unshift PATH_TO_AR
require 'active_record'
require 'active_record/fixtures'
- $stderr.puts 'success'
rescue LoadError => e
- $stderr.print "failed. Skipping Active Record assertion tests: #{e}"
+ $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}"
ActiveRecordTestConnector.able_to_connect = false
end
end
diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb
index 622d67287d..64f1ad7610 100644
--- a/actionpack/test/controller/dispatcher_test.rb
+++ b/actionpack/test/controller/dispatcher_test.rb
@@ -15,7 +15,6 @@ class DispatcherTest < Test::Unit::TestCase
ActionDispatch::Callbacks.reset_callbacks(:call)
ActionController::Routing::Routes.stubs(:call).returns([200, {}, 'response'])
- ActionController::Routing::Routes.stubs(:reload)
Dispatcher.stubs(:require_dependency)
end
@@ -28,18 +27,6 @@ class DispatcherTest < Test::Unit::TestCase
dispatch(false)
end
- def test_reloads_routes_before_dispatch_if_in_loading_mode
- ActionController::Routing::Routes.expects(:reload).once
- dispatch(false)
- end
-
- def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
- ActionController::Routing::Routes.expects(:reload).never
- ActiveSupport::Dependencies.expects(:clear).never
-
- dispatch
- end
-
def test_prepare_callbacks
a = b = c = nil
ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index c448f36cb3..1f5be431ac 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -72,6 +72,18 @@ class FlashTest < ActionController::TestCase
redirect_to :action => "std_action"
@flash_copy = {}.update(flash)
end
+
+ def redirect_with_alert
+ redirect_to '/nowhere', :alert => "Beware the nowheres!"
+ end
+
+ def redirect_with_notice
+ redirect_to '/somewhere', :notice => "Good luck in the somewheres!"
+ end
+
+ def redirect_with_other_flashes
+ redirect_to '/wonderland', :flash => { :joyride => "Horses!" }
+ end
end
tests TestController
@@ -160,4 +172,19 @@ class FlashTest < ActionController::TestCase
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep()) # nothing passed
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed
end
-end
+
+ def test_redirect_to_with_alert
+ get :redirect_with_alert
+ assert_equal "Beware the nowheres!", @controller.send(:flash)[:alert]
+ end
+
+ def test_redirect_to_with_notice
+ get :redirect_with_notice
+ assert_equal "Good luck in the somewheres!", @controller.send(:flash)[:notice]
+ end
+
+ def test_redirect_to_with_other_flashes
+ get :redirect_with_other_flashes
+ assert_equal "Horses!", @controller.send(:flash)[:joyride]
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index a9a970d67d..c15eaade58 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -1623,78 +1623,6 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
-class RouteLoadingTest < Test::Unit::TestCase
- def setup
- routes.instance_variable_set '@routes_last_modified', nil
- Object.remove_const(:RAILS_ROOT) if defined?(::RAILS_ROOT)
- Object.const_set :RAILS_ROOT, '.'
- routes.add_configuration_file(File.join(RAILS_ROOT, 'config', 'routes.rb'))
-
- @stat = stub_everything
- end
-
- def teardown
- ActionController::Routing::Routes.configuration_files.clear
- Object.send :remove_const, :RAILS_ROOT
- end
-
- def test_load
- File.expects(:stat).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/))
-
- routes.reload
- end
-
- def test_no_reload_when_not_modified
- @stat.expects(:mtime).times(2).returns(1)
- File.expects(:stat).times(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).at_most_once
-
- 2.times { routes.reload }
- end
-
- def test_reload_when_modified
- @stat.expects(:mtime).at_least(2).returns(1, 2)
- File.expects(:stat).at_least(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
-
- 2.times { routes.reload }
- end
-
- def test_bang_forces_reload
- @stat.expects(:mtime).at_least(2).returns(1)
- File.expects(:stat).at_least(2).returns(@stat)
- routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
-
- 2.times { routes.reload! }
- end
-
- def test_load_with_configuration
- routes.configuration_files.clear
- routes.add_configuration_file("foobarbaz")
- File.expects(:stat).returns(@stat)
- routes.expects(:load).with("foobarbaz")
-
- routes.reload
- end
-
- def test_load_multiple_configurations
- routes.add_configuration_file("engines.rb")
-
- File.expects(:stat).at_least_once.returns(@stat)
-
- routes.expects(:load).with('./config/routes.rb')
- routes.expects(:load).with('engines.rb')
-
- routes.reload
- end
-
- private
- def routes
- ActionController::Routing::Routes
- end
-end
-
class RackMountIntegrationTests < ActiveSupport::TestCase
Model = Struct.new(:to_param)
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index a788b2495e..0f074b32e6 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -563,7 +563,7 @@ XML
expected = File.read(path)
expected.force_encoding(Encoding::BINARY) if expected.respond_to?(:force_encoding)
- file = ActionController::TestUploadedFile.new(path, content_type)
+ file = Rack::Test::UploadedFile.new(path, content_type)
assert_equal filename, file.original_filename
assert_equal content_type, file.content_type
assert_equal file.path, file.local_path
@@ -580,10 +580,10 @@ XML
path = "#{FILES_DIR}/#{filename}"
content_type = 'image/png'
- binary_uploaded_file = ActionController::TestUploadedFile.new(path, content_type, :binary)
+ binary_uploaded_file = Rack::Test::UploadedFile.new(path, content_type, :binary)
assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read
- plain_uploaded_file = ActionController::TestUploadedFile.new(path, content_type)
+ plain_uploaded_file = Rack::Test::UploadedFile.new(path, content_type)
assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read
end
@@ -605,7 +605,7 @@ XML
end
def test_test_uploaded_file_exception_when_file_doesnt_exist
- assert_raise(RuntimeError) { ActionController::TestUploadedFile.new('non_existent_file') }
+ assert_raise(RuntimeError) { Rack::Test::UploadedFile.new('non_existent_file') }
end
def test_redirect_url_only_cares_about_location_header
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 256ed06a45..59ad2e48bd 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -7,7 +7,6 @@ class ResponseTest < ActiveSupport::TestCase
test "simple output" do
@response.body = "Hello, World!"
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -25,7 +24,6 @@ class ResponseTest < ActiveSupport::TestCase
test "utf8 output" do
@response.body = [1090, 1077, 1089, 1090].pack("U*")
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -41,7 +39,6 @@ class ResponseTest < ActiveSupport::TestCase
@response.body = Proc.new do |response, output|
5.times { |n| output.write(n) }
end
- @response.prepare!
status, headers, body = @response.to_a
assert_equal 200, status
@@ -59,14 +56,12 @@ class ResponseTest < ActiveSupport::TestCase
test "content type" do
[204, 304].each do |c|
@response.status = c.to_s
- @response.prepare!
status, headers, body = @response.to_a
assert !headers.has_key?("Content-Type"), "#{c} should not have Content-Type header"
end
[200, 302, 404, 500].each do |c|
@response.status = c.to_s
- @response.prepare!
status, headers, body = @response.to_a
assert headers.has_key?("Content-Type"), "#{c} did not have Content-Type header"
end
@@ -74,7 +69,6 @@ class ResponseTest < ActiveSupport::TestCase
test "does not include Status header" do
@response.status = "200 OK"
- @response.prepare!
status, headers, body = @response.to_a
assert !headers.has_key?('Status')
end
@@ -114,15 +108,126 @@ class ResponseTest < ActiveSupport::TestCase
test "cookies" do
@response.set_cookie("user_name", :value => "david", :path => "/")
- @response.prepare!
status, headers, body = @response.to_a
assert_equal "user_name=david; path=/", headers["Set-Cookie"]
assert_equal({"user_name" => "david"}, @response.cookies)
@response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5))
- @response.prepare!
status, headers, body = @response.to_a
assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", headers["Set-Cookie"]
assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies)
end
+
+ test "read cache control" do
+ resp = ActionDispatch::Response.new.tap { |resp|
+ resp.cache_control[:public] = true
+ resp.etag = '123'
+ resp.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('"202cb962ac59075b964b07152d234b70"', resp.etag)
+ assert_equal({:public => true}, resp.cache_control)
+
+ assert_equal('public', resp.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', resp.headers['ETag'])
+ end
+
+ test "read charset and content type" do
+ resp = ActionDispatch::Response.new.tap { |resp|
+ resp.charset = 'utf-16'
+ resp.content_type = Mime::XML
+ resp.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('utf-16', resp.charset)
+ assert_equal(Mime::XML, resp.content_type)
+
+ assert_equal('application/xml; charset=utf-16', resp.headers['Content-Type'])
+ end
+end
+
+class ResponseIntegrationTest < ActionDispatch::IntegrationTest
+ def app
+ @app
+ end
+
+ test "response cache control from railsish app" do
+ @app = lambda { |env|
+ ActionDispatch::Response.new.tap { |resp|
+ resp.cache_control[:public] = true
+ resp.etag = '123'
+ resp.body = 'Hello'
+ }.to_a
+ }
+
+ get '/'
+ assert_response :success
+
+ assert_equal('public', @response.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
+
+ pending do
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
+ end
+ end
+
+ test "response cache control from rackish app" do
+ @app = lambda { |env|
+ [200,
+ {'ETag' => '"202cb962ac59075b964b07152d234b70"',
+ 'Cache-Control' => 'public'}, 'Hello']
+ }
+
+ get '/'
+ assert_response :success
+
+ assert_equal('public', @response.headers['Cache-Control'])
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
+
+ pending do
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
+ end
+ end
+
+ test "response charset and content type from railsish app" do
+ @app = lambda { |env|
+ ActionDispatch::Response.new.tap { |resp|
+ resp.charset = 'utf-16'
+ resp.content_type = Mime::XML
+ resp.body = 'Hello'
+ }.to_a
+ }
+
+ get '/'
+ assert_response :success
+
+ pending do
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
+ end
+
+ assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
+ end
+
+ test "response charset and content type from rackish app" do
+ @app = lambda { |env|
+ [200,
+ {'Content-Type' => 'application/xml; charset=utf-16'},
+ 'Hello']
+ }
+
+ get '/'
+ assert_response :success
+
+ pending do
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
+ end
+
+ assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
+ end
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 425796b460..7058bc2ea0 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -22,8 +22,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
delete 'logout', :to => :destroy, :as => :logout
end
+ match 'account/logout' => redirect("/logout")
match 'account/login', :to => redirect("/login")
+ match 'account/modulo/:name', :to => redirect("/%{name}s")
+ match 'account/proc/:name', :to => redirect {|params| "/#{params[:name].pluralize}" }
+
match 'openid/login', :via => [:get, :post], :to => "openid#login"
controller(:global) do
@@ -34,11 +38,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
constraints(:ip => /192\.168\.1\.\d\d\d/) do
- get 'admin', :to => "queenbee#index"
+ get 'admin' => "queenbee#index"
end
constraints ::TestRoutingMapper::IpRestrictor do
- get 'admin/accounts', :to => "queenbee#accounts"
+ get 'admin/accounts' => "queenbee#accounts"
end
resources :projects, :controller => :project do
@@ -82,7 +86,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- match 'sprockets.js', :to => ::TestRoutingMapper::SprocketsApp
+ match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
match 'people/:id/update', :to => 'people#update', :as => :update_person
match '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
@@ -145,6 +149,33 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_logout_redirect_without_to
+ with_test_routes do
+ get '/account/logout'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/logout', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
+ def test_redirect_modulo
+ with_test_routes do
+ get '/account/modulo/name'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/names', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
+ def test_redirect_proc
+ with_test_routes do
+ get '/account/proc/person'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/people', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
def test_openid
with_test_routes do
get '/openid/login'
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 1f4a8466c9..f098ce0671 100755
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -15,7 +15,6 @@ task :default => :test
Rake::TestTask.new do |t|
t.libs << "#{dir}/test"
t.test_files = Dir.glob("#{dir}/test/cases/**/*_test.rb").sort
- t.verbose = true
t.warning = true
end
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index 8e14b6724f..e0de27b96d 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -21,10 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
require 'active_support'
+
module ActiveModel
extend ActiveSupport::Autoload
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 024f2378be..30193956ea 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -1,11 +1,9 @@
-root = File.expand_path('../../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
+lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'config'
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index f935d15526..2376bbd04a 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -21,11 +21,12 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
-activemodel_path = "#{File.dirname(__FILE__)}/../../activemodel/lib"
-$:.unshift(activemodel_path) if File.directory?(activemodel_path)
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
require 'active_support'
require 'active_model'
@@ -91,7 +92,7 @@ module ActiveRecord
module Type
extend ActiveSupport::Autoload
-
+
autoload :Number, 'active_record/types/number'
autoload :Object, 'active_record/types/object'
autoload :Serialize, 'active_record/types/serialize'
@@ -101,14 +102,14 @@ module ActiveRecord
module Locking
extend ActiveSupport::Autoload
-
+
autoload :Optimistic
autoload :Pessimistic
end
module ConnectionAdapters
extend ActiveSupport::Autoload
-
+
autoload :AbstractAdapter
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 0fcd288fc5..8dcb3a7711 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1325,7 +1325,7 @@ module ActiveRecord
if association.nil? || force_reload
association = association_proxy_class.new(self, reflection)
- retval = association.reload
+ retval = force_reload ? reflection.klass.uncached { association.reload } : association.reload
if retval.nil? and association_proxy_class == BelongsToAssociation
association_instance_set(reflection.name, nil)
return nil
@@ -1370,7 +1370,7 @@ module ActiveRecord
association_instance_set(reflection.name, association)
end
- association.reload if force_reload
+ reflection.klass.uncached { association.reload } if force_reload
association
end
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb
index 6ad1e06300..7d8f4670fa 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -200,14 +200,18 @@ module ActiveRecord
private
# Forwards any missing method call to the \target.
- def method_missing(method, *args, &block)
+ def method_missing(method, *args)
if load_target
unless @target.respond_to?(method)
message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}"
raise NoMethodError, message
end
- @target.send(method, *args, &block)
+ if block_given?
+ @target.send(method, *args) { |*block_args| yield(*block_args) }
+ else
+ @target.send(method, *args)
+ end
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 3c490c1eeb..ce7eedbb54 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1178,13 +1178,4 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
client = firm.clients_using_primary_key.create!(:name => 'test')
assert_equal firm.name, client.firm_name
end
-
- def test_normal_method_call_in_association_proxy
- assert_equal 'Welcome to the weblog', Comment.all.map { |comment| comment.post }.first.title
- end
-
- def test_instance_eval_in_association_proxy
- assert_equal 'Welcome to the weblog', Comment.all.map { |comment| comment.post }.first.instance_eval{title}
- end
end
-
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index e429c1d157..9bc34bd750 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -64,6 +64,16 @@ class AssociationsTest < ActiveRecord::TestCase
assert !firm.clients(true).empty?, "New firm should have reloaded client objects"
assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count"
end
+
+ def test_force_reload_is_uncached
+ firm = Firm.create!("name" => "A New Firm, Inc")
+ client = Client.create!("name" => "TheClient.com", :firm => firm)
+ ActiveRecord::Base.cache do
+ firm.clients.each {}
+ assert_queries(0) { assert_not_nil firm.clients.each {} }
+ assert_queries(1) { assert_not_nil firm.clients(true).each {} }
+ end
+ end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 25613da912..307320b964 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -1,11 +1,9 @@
-root = File.expand_path('../../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
+lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'config'
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
new file mode 100644
index 0000000000..f221def6b6
--- /dev/null
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -0,0 +1,11 @@
+require "cases/helper"
+require 'models/topic'
+
+class YamlSerializationTest < ActiveRecord::TestCase
+ def test_to_yaml_with_time_with_zone_should_not_raise_exception
+ Time.zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ topic = Topic.new(:written_on => DateTime.now)
+ assert_nothing_raised { topic.to_yaml }
+ end
+end
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 6566e84d4c..9fa1f86914 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -27,11 +27,8 @@ task :default => [ :test ]
# Run the unit tests
Rake::TestTask.new { |t|
- activesupport_path = "#{File.dirname(__FILE__)}/../activesupport/lib"
- t.libs << activesupport_path if File.directory?(activesupport_path)
t.libs << "test"
t.pattern = 'test/**/*_test.rb'
- t.verbose = true
t.warning = true
}
diff --git a/activeresource/lib/active_resource.rb b/activeresource/lib/active_resource.rb
index 9357dd852f..3e4a1dd4a1 100644
--- a/activeresource/lib/active_resource.rb
+++ b/activeresource/lib/active_resource.rb
@@ -21,12 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
-require 'active_support'
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-activemodel_path = "#{File.dirname(__FILE__)}/../../activemodel/lib"
-$:.unshift(activemodel_path) if File.directory?(activemodel_path)
+require 'active_support'
require 'active_model'
module ActiveResource
@@ -36,7 +37,8 @@ module ActiveResource
autoload :Connection
autoload :CustomMethods
autoload :Formats
+ autoload :HttpMock
autoload :Observing
+ autoload :Schema
autoload :Validations
- autoload :HttpMock
end
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 18105e8887..b833e9c8ce 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -241,6 +241,124 @@ module ActiveResource
cattr_accessor :logger
class << self
+ # Creates a schema for this resource - setting the attributes that are
+ # known prior to fetching an instance from the remote system.
+ #
+ # The schema helps define the set of <tt>known_attributes</tt> of the
+ # current resource.
+ #
+ # There is no need to specify a schema for your Active Resource. If
+ # you do not, the <tt>known_attributes</tt> will be guessed from the
+ # instance attributes returned when an instance is fetched from the
+ # remote system.
+ #
+ # example:
+ # class Person < ActiveResource::Base
+ # schema do
+ # # define each attribute separately
+ # attribute 'name', :string
+ #
+ # # or use the convenience methods and pass >=1 attribute names
+ # string 'eye_colour', 'hair_colour'
+ # integer 'age'
+ # float 'height', 'weight'
+ #
+ # # unsupported types should be left as strings
+ # # overload the accessor methods if you need to convert them
+ # attribute 'created_at', 'string'
+ # end
+ # end
+ #
+ # p = Person.new
+ # p.respond_to? :name # => true
+ # p.respond_to? :age # => true
+ # p.name # => nil
+ # p.age # => nil
+ #
+ # j = Person.find_by_name('John') # <person><name>John</name><age>34</age><num_children>3</num_children></person>
+ # j.respond_to? :name # => true
+ # j.respond_to? :age # => true
+ # j.name # => 'John'
+ # j.age # => '34' # note this is a string!
+ # j.num_children # => '3' # note this is a string!
+ #
+ # p.num_children # => NoMethodError
+ #
+ # Attribute-types must be one of:
+ # string, integer, float
+ #
+ # Note: at present the attribute-type doesn't do anything, but stay
+ # tuned...
+ # Shortly it will also *cast* the value of the returned attribute.
+ # ie:
+ # j.age # => 34 # cast to an integer
+ # j.weight # => '65' # still a string!
+ #
+ def schema(&block)
+ if block_given?
+ schema_definition = Schema.new
+ schema_definition.instance_eval(&block)
+
+ # skip out if we didn't define anything
+ return unless schema_definition.attrs.present?
+
+ @schema ||= {}.with_indifferent_access
+ @known_attributes ||= []
+
+ schema_definition.attrs.each do |k,v|
+ @schema[k] = v
+ @known_attributes << k
+ end
+
+ schema
+ else
+ @schema ||= nil
+ end
+ end
+
+ # Alternative, direct way to specify a <tt>schema</tt> for this
+ # Resource. <tt>schema</tt> is more flexible, but this is quick
+ # for a very simple schema.
+ #
+ # Pass the schema as a hash with the keys being the attribute-names
+ # and the value being one of the accepted attribute types (as defined
+ # in <tt>schema</tt>)
+ #
+ # example:
+ #
+ # class Person < ActiveResource::Base
+ # schema = {'name' => :string, 'age' => :integer }
+ # end
+ #
+ # The keys/values can be strings or symbols. They will be converted to
+ # strings.
+ #
+ def schema=(the_schema)
+ unless the_schema.present?
+ # purposefully nulling out the schema
+ @schema = nil
+ @known_attributes = []
+ return
+ end
+
+ raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash
+
+ schema do
+ the_schema.each {|k,v| attribute(k,v) }
+ end
+ end
+
+ # Returns the list of known attributes for this resource, gathered
+ # from the provided <tt>schema</tt>
+ # Attributes that are known will cause your resource to return 'true'
+ # when <tt>respond_to?</tt> is called on them. A known attribute will
+ # return nil if not set (rather than <t>MethodNotFound</tt>); thus
+ # known attributes can be used with <tt>validates_presence_of</tt>
+ # without a getter-method.
+ def known_attributes
+ @known_attributes ||= []
+ end
+
# Gets the URI of the REST resources to map for this class. The site variable is required for
# Active Resource's mapping to work.
def site
@@ -776,6 +894,21 @@ module ActiveResource
attr_accessor :attributes #:nodoc:
attr_accessor :prefix_options #:nodoc:
+ # If no schema has been defined for the class (see
+ # <tt>ActiveResource::schema=</tt>), the default automatic schema is
+ # generated from the current instance's attributes
+ def schema
+ self.class.schema || self.attributes
+ end
+
+ # This is a list of known attributes for this resource. Either
+ # gathered fromthe provided <tt>schema</tt>, or from the attributes
+ # set on this instance after it has been fetched from the remote system.
+ def known_attributes
+ self.class.known_attributes + self.attributes.keys.map(&:to_s)
+ end
+
+
# Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
# of attributes for the \new resource.
#
@@ -1157,7 +1290,7 @@ module ActiveResource
method_name = method.to_s
if attributes.nil?
super
- elsif attributes.has_key?(method_name)
+ elsif known_attributes.include?(method_name)
true
elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
true
@@ -1262,7 +1395,10 @@ module ActiveResource
attributes[$`]
end
else
- attributes.include?(method_name) ? attributes[method_name] : super
+ return attributes[method_name] if attributes.include?(method_name)
+ # not set right now but we know about it
+ return nil if known_attributes.include?(method_name)
+ super
end
end
end
diff --git a/activeresource/lib/active_resource/schema.rb b/activeresource/lib/active_resource/schema.rb
new file mode 100644
index 0000000000..8368b652c2
--- /dev/null
+++ b/activeresource/lib/active_resource/schema.rb
@@ -0,0 +1,55 @@
+require 'active_resource/exceptions'
+
+module ActiveResource # :nodoc:
+ class Schema # :nodoc:
+ # attributes can be known to be one of these types. They are easy to
+ # cast to/from.
+ KNOWN_ATTRIBUTE_TYPES = %w( string integer float )
+
+ # An array of attribute definitions, representing the attributes that
+ # have been defined.
+ attr_accessor :attrs
+
+ # The internals of an Active Resource Schema are very simple -
+ # unlike an Active Record TableDefinition (on which it is based).
+ # It provides a set of convenience methods for people to define their
+ # schema using the syntax:
+ # schema do
+ # string :foo
+ # integer :bar
+ # end
+ #
+ # The schema stores the name and type of each attribute. That is then
+ # read out by the schema method to populate the actual
+ # Resource's schema
+ def initialize
+ @attrs = {}
+ end
+
+ def attribute(name, type, options = {})
+ raise ArgumentError, "Unknown Attribute type: #{type.inspect} for key: #{name.inspect}" unless type.nil? || Schema::KNOWN_ATTRIBUTE_TYPES.include?(type.to_s)
+
+ the_type = type.to_s
+ # TODO: add defaults
+ #the_attr = [type.to_s]
+ #the_attr << options[:default] if options.has_key? :default
+ @attrs[name.to_s] = the_type
+ self
+ end
+
+ # The following are the attribute types supported by Active Resource
+ # migrations.
+ # TODO: We should eventually support all of these:
+ # %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |attr_type|
+ KNOWN_ATTRIBUTE_TYPES.each do |attr_type|
+ class_eval <<-EOV
+ def #{attr_type.to_s}(*args)
+ options = args.extract_options!
+ attr_names = args
+
+ attr_names.each { |name| attribute(name, '#{attr_type}', options) }
+ end
+ EOV
+ end
+ end
+end
diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb
index 3d684ff347..5fa6d3023b 100644
--- a/activeresource/test/abstract_unit.rb
+++ b/activeresource/test/abstract_unit.rb
@@ -1,18 +1,16 @@
-root = File.expand_path('../../..', __FILE__)
begin
- require "#{root}/vendor/gems/environment"
+ require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
- $:.unshift("#{root}/activesupport/lib")
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'rubygems'
require 'test/unit'
+require 'active_resource'
require 'active_support'
require 'active_support/test_case'
-require 'active_resource'
require 'active_model/test_case'
$:.unshift "#{File.dirname(__FILE__)}/../test"
diff --git a/activeresource/test/cases/base/schema_test.rb b/activeresource/test/cases/base/schema_test.rb
new file mode 100644
index 0000000000..d1afb9f439
--- /dev/null
+++ b/activeresource/test/cases/base/schema_test.rb
@@ -0,0 +1,419 @@
+require 'abstract_unit'
+require "fixtures/person"
+require "fixtures/street_address"
+
+########################################################################
+# Testing the schema of your Active Resource models
+########################################################################
+class SchemaTest < ActiveModel::TestCase
+ def setup
+ @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
+ @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
+ @greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
+ @addy = { :id => 1, :street => '12345 Street', :country => 'Australia' }.to_xml(:root => 'address')
+ @default_request_headers = { 'Content-Type' => 'application/xml' }
+ @rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
+ @people = [{ :id => 1, :name => 'Matz' }, { :id => 2, :name => 'David' }].to_xml(:root => 'people')
+ @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people')
+ @addresses = [{ :id => 1, :street => '12345 Street', :country => 'Australia' }].to_xml(:root => 'addresses')
+
+ ActiveResource::HttpMock.respond_to do |mock|
+ mock.get "/people/1.xml", {}, @matz
+ mock.get "/people/2.xml", {}, @david
+ mock.get "/people/Greg.xml", {}, @greg
+ mock.get "/people/4.xml", {'key' => 'value'}, nil, 404
+ mock.get "/people/5.xml", {}, @rick
+ mock.put "/people/1.xml", {}, nil, 204
+ mock.delete "/people/1.xml", {}, nil, 200
+ mock.delete "/people/2.xml", {}, nil, 400
+ mock.get "/people/99.xml", {}, nil, 404
+ mock.post "/people.xml", {}, @rick, 201, 'Location' => '/people/5.xml'
+ mock.get "/people.xml", {}, @people
+ mock.get "/people/1/addresses.xml", {}, @addresses
+ mock.get "/people/1/addresses/1.xml", {}, @addy
+ mock.get "/people/1/addresses/2.xml", {}, nil, 404
+ mock.get "/people/2/addresses/1.xml", {}, nil, 404
+ mock.get "/people/Greg/addresses/1.xml", {}, @addy
+ mock.put "/people/1/addresses/1.xml", {}, nil, 204
+ mock.delete "/people/1/addresses/1.xml", {}, nil, 200
+ mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5'
+ mock.get "/people//addresses.xml", {}, nil, 404
+ mock.get "/people//addresses/1.xml", {}, nil, 404
+ mock.put "/people//addressaddresseses/1.xml", {}, nil, 404
+ mock.delete "/people//addresses/1.xml", {}, nil, 404
+ mock.post "/people//addresses.xml", {}, nil, 404
+ mock.head "/people/1.xml", {}, nil, 200
+ mock.head "/people/Greg.xml", {}, nil, 200
+ mock.head "/people/99.xml", {}, nil, 404
+ mock.head "/people/1/addresses/1.xml", {}, nil, 200
+ mock.head "/people/1/addresses/2.xml", {}, nil, 404
+ mock.head "/people/2/addresses/1.xml", {}, nil, 404
+ mock.head "/people/Greg/addresses/1.xml", {}, nil, 200
+ end
+
+ Person.user = nil
+ Person.password = nil
+ end
+ def teardown
+ Person.schema = nil # hack to stop test bleedthrough...
+ end
+
+
+ #####################################################
+ # Passing in a schema directly and returning it
+ ####
+
+ test "schema on a new model should be empty" do
+ assert Person.schema.blank?, "should have a blank class schema"
+ assert Person.new.schema.blank?, "should have a blank instance schema"
+ end
+
+ test "schema should only accept a hash" do
+ ["blahblah", ['one','two'], [:age, :name], Person.new].each do |bad_schema|
+ assert_raises(ArgumentError,"should only accept a hash (or nil), but accepted: #{bad_schema.inspect}") do
+ Person.schema = bad_schema
+ end
+ end
+ end
+
+ test "schema should accept a simple hash" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema
+ end
+
+ test "schema should accept a hash with simple values" do
+ new_schema = {'age' => 'integer', 'name' => 'string', 'height' => 'float', 'mydatetime' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema
+ end
+
+ test "schema should accept all known attribute types as values" do
+ # I'd prefer to use here...
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ assert_nothing_raised("should have accepted #{the_type.inspect}"){ Person.schema = {'my_key' => the_type }}
+ end
+ end
+
+ test "schema should not accept unknown values" do
+ bad_values = [ :oogle, :blob, 'thing']
+
+ bad_values.each do |bad_value|
+ assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
+ Person.schema = {'key' => bad_value}
+ end
+ end
+ end
+
+ test "schema should accept nil and remove the schema" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+ assert_nothing_raised { Person.schema = new_schema }
+ assert_equal new_schema, Person.schema # sanity check
+
+
+ assert_nothing_raised { Person.schema = nil }
+ assert_nil Person.schema, "should have nulled out the schema, but still had: #{Person.schema.inspect}"
+ end
+
+
+ test "schema should be with indifferent access" do
+ new_schema = {:age => :integer, 'name' => 'string'}
+ new_schema_syms = new_schema.keys
+
+ assert_nothing_raised { Person.schema = new_schema }
+ new_schema_syms.each do |col|
+ assert Person.new.respond_to?(col.to_s), "should respond to the schema's string key, but failed on: #{col.to_s}"
+ assert Person.new.respond_to?(col.to_sym), "should respond to the schema's symbol key, but failed on: #{col.to_sym}"
+ end
+ end
+
+
+ test "schema on a fetched resource should return all the attributes of that model instance" do
+ p = Person.find(1)
+ s = p.schema
+
+ assert s.present?, "should have found a non-empty schema!"
+
+ p.attributes.each do |the_attr, val|
+ assert s.has_key?(the_attr), "should have found attr: #{the_attr} in schema, but only had: #{s.inspect}"
+ end
+ end
+
+ test "with two instances, default schema should match the attributes of the individual instances - even if they differ" do
+ matz = Person.find(1)
+ rick = Person.find(5)
+
+ m_attrs = matz.attributes.keys.sort
+ r_attrs = rick.attributes.keys.sort
+
+ assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
+
+ assert_not_equal matz.schema, rick.schema, "should have had different schemas too"
+ end
+
+ test "defining a schema should return it when asked" do
+ assert Person.schema.blank?, "should have a blank class schema"
+ new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
+ assert_nothing_raised {
+ Person.schema = new_schema
+ assert_equal new_schema, Person.schema, "should have saved the schema on the class"
+ assert_equal new_schema, Person.new.schema, "should have mde the schema available to every instance"
+ }
+ end
+
+ test "defining a schema, then fetching a model should still match the defined schema" do
+ # sanity checks
+ assert Person.schema.blank?, "should have a blank class schema"
+ new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
+
+ matz = Person.find(1)
+ assert !matz.schema.blank?, "should have some sort of schema on an instance variable"
+ assert_not_equal new_schema, matz.schema, "should not have the class-level schema until it's been added to the class!"
+
+ assert_nothing_raised {
+ Person.schema = new_schema
+ assert_equal new_schema, matz.schema, "class-level schema should override instance-level schema"
+ }
+ end
+
+
+ #####################################################
+ # Using the schema syntax
+ ####
+
+ test "should be able to use schema" do
+ assert Person.respond_to?(:schema), "should at least respond to the schema method"
+
+ assert_nothing_raised("Should allow the schema to take a block") do
+ Person.schema { }
+ end
+ end
+
+ test "schema definition should store and return attribute set" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ s = self
+ attribute :foo, :string
+ end
+ assert s.respond_to?(:attrs), "should return attributes in theory"
+ assert_equal({'foo' => 'string' }, s.attrs, "should return attributes in practice")
+ end
+ end
+
+ test "should be able to add attributes through schema" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ s = self
+ attribute('foo', 'string')
+ end
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name"
+ assert_equal 'string', s.attrs['foo'], "should have saved the attribute type"
+ end
+ end
+
+ test "should convert symbol attributes to strings" do
+ assert_nothing_raised do
+ s = nil
+ Person.schema do
+ attribute(:foo, :integer)
+ s = self
+ end
+
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name as a string"
+ assert_equal 'integer', s.attrs['foo'], "should have saved the attribute type as a string"
+ end
+ end
+
+ test "should be able to add all known attribute types" do
+ assert_nothing_raised do
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ s = nil
+ Person.schema do
+ s = self
+ attribute('foo', the_type)
+ end
+ assert s.attrs.has_key?('foo'), "should have saved the attribute name"
+ assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
+ end
+ end
+ end
+
+ test "attributes should not accept unknown values" do
+ bad_values = [ :oogle, :blob, 'thing']
+
+ bad_values.each do |bad_value|
+ s = nil
+ assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
+ Person.schema do
+ s = self
+ attribute 'key', bad_value
+ end
+ end
+ assert !self.respond_to?(bad_value), "should only respond to a known attribute type, but accepted: #{bad_value.inspect}"
+ assert_raises(NoMethodError,"should only have methods for known attribute types, but accepted: #{bad_value.inspect}") do
+ Person.schema do
+ send bad_value, 'key'
+ end
+ end
+ end
+ end
+
+
+ test "should accept attribute types as the type's name as the method" do
+ ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
+ s = nil
+ Person.schema do
+ s = self
+ send(the_type,'foo')
+ end
+ assert s.attrs.has_key?('foo'), "should now have saved the attribute name"
+ assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
+ end
+ end
+
+ test "should accept multiple attribute names for an attribute method" do
+ names = ['foo','bar','baz']
+ s = nil
+ Person.schema do
+ s = self
+ string(*names)
+ end
+ names.each do |the_name|
+ assert s.attrs.has_key?(the_name), "should now have saved the attribute name: #{the_name}"
+ assert_equal 'string', s.attrs[the_name], "should have saved the attribute as a string"
+ end
+ end
+
+ #####################################################
+ # What a schema does for us
+ ####
+
+ # respond_to?
+
+ test "should respond positively to attributes that are only in the schema" do
+ new_attr_name = :my_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
+ assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
+
+ assert_nothing_raised do
+ Person.schema = {new_attr_name.to_s => 'string'}
+ Person.schema { string new_attr_name_two }
+ end
+
+ assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ end
+
+ test "should not care about ordering of schema definitions" do
+ new_attr_name = :my_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
+ assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
+
+ assert_nothing_raised do
+ Person.schema { string new_attr_name_two }
+ Person.schema = {new_attr_name.to_s => 'string'}
+ end
+
+ assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ end
+
+ # method_missing effects
+
+ test "should not give method_missing for attribute only in schema" do
+ new_attr_name = :another_new_schema_attribute
+ new_attr_name_two = :another_new_schema_attribute
+
+ assert Person.schema.blank?, "sanity check - should have a blank class schema"
+
+ assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name} as a method") do
+ Person.new.send(new_attr_name)
+ end
+ assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name_two} as a method") do
+ Person.new.send(new_attr_name_two)
+ end
+
+ Person.schema = {new_attr_name.to_s => :float}
+ Person.schema { string new_attr_name_two }
+
+ assert_nothing_raised do
+ Person.new.send(new_attr_name)
+ Person.new.send(new_attr_name_two)
+ end
+ end
+
+
+ ########
+ # Known attributes
+ #
+ # Attributes can be known to be attributes even if they aren't actually
+ # 'set' on a particular instance.
+ # This will only differ from 'attributes' if a schema has been set.
+
+ test "new model should have no known attributes" do
+ assert Person.known_attributes.blank?, "should have no known attributes"
+ assert Person.new.known_attributes.blank?, "should have no known attributes on a new instance"
+ end
+
+ test "setting schema should set known attributes on class and instance" do
+ new_schema = {'age' => 'integer', 'name' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+
+ assert_equal new_schema.keys, Person.known_attributes
+ assert_equal new_schema.keys, Person.new.known_attributes
+ end
+
+ test "known attributes on a fetched resource should return all the attributes of the instance" do
+ p = Person.find(1)
+ attrs = p.known_attributes
+
+ assert attrs.present?, "should have found some attributes!"
+
+ p.attributes.each do |the_attr, val|
+ assert attrs.include?(the_attr), "should have found attr: #{the_attr} in known attributes, but only had: #{attrs.inspect}"
+ end
+ end
+
+ test "with two instances, known attributes should match the attributes of the individual instances - even if they differ" do
+ matz = Person.find(1)
+ rick = Person.find(5)
+
+ m_attrs = matz.attributes.keys.sort
+ r_attrs = rick.attributes.keys.sort
+
+ assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
+
+ assert_not_equal matz.known_attributes, rick.known_attributes, "should have had different known attributes too"
+ end
+
+ test "setting schema then fetching should add schema attributes to the intance attributes" do
+ # an attribute in common with fetched instance and one that isn't
+ new_schema = {'name' => 'string', 'my_strange_attribute' => 'string'}
+
+ assert_nothing_raised { Person.schema = new_schema }
+
+ matz = Person.find(1)
+ known_attrs = matz.known_attributes
+
+ matz.attributes.keys.each do |the_attr|
+ assert known_attrs.include?(the_attr), "should have found instance attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
+ end
+ new_schema.keys.each do |the_attr|
+ assert known_attrs.include?(the_attr), "should have found schema attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
+ end
+ end
+
+
+end
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 4edeadf10c..cc4a2ff90e 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Add Enumerable#exclude? to bring parity to Enumerable#include? and avoid if !x.include?/else calls [DHH]
+
* Update Edinburgh TimeZone to use "Europe/London" instead of "Europe/Dublin" #3310 [Phil Ross]
* Update bundled TZInfo to v0.3.15 [Geoff Buesing]
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 2ada91830f..08af1d6fca 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -18,7 +18,6 @@ task :default => :test
Rake::TestTask.new do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
- t.verbose = true
t.warning = true
end
diff --git a/activesupport/lib/active_support/core_ext/class/removal.rb b/activesupport/lib/active_support/core_ext/class/removal.rb
index 2dea3c24d5..652be4ed78 100644
--- a/activesupport/lib/active_support/core_ext/class/removal.rb
+++ b/activesupport/lib/active_support/core_ext/class/removal.rb
@@ -2,7 +2,11 @@ require 'active_support/core_ext/object/extending'
require 'active_support/core_ext/module/introspection'
class Class #:nodoc:
-
+
+ def reachable?
+ eval("defined?(::#{self}) && ::#{self}.equal?(self)")
+ end
+
# Unassociates the class with its subclasses and removes the subclasses
# themselves.
#
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 3dd61334d0..2b76b93153 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -1,3 +1,4 @@
+require 'date'
require 'active_support/duration'
require 'active_support/core_ext/time/zones'
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index f6c870035b..90ab1eb281 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -1,3 +1,4 @@
+require 'date'
require 'active_support/inflector'
class Date
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 5f01bc4fd6..47a31839a6 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -78,7 +78,18 @@ class DateTime
# Converts self to a floating-point number of seconds since the Unix epoch
def to_f
- days_since_unix_epoch = self - ::DateTime.civil(1970)
- (days_since_unix_epoch * 86_400).to_f
+ seconds_since_unix_epoch.to_f
+ end
+
+ # Converts self to an integer number of seconds since the Unix epoch
+ def to_i
+ seconds_since_unix_epoch.to_i
+ end
+
+ private
+
+ def seconds_since_unix_epoch
+ seconds_per_day = 86_400
+ (self - ::DateTime.civil(1970)) * seconds_per_day
end
end
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index b11c916f61..d0821a7c68 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -101,6 +101,11 @@ module Enumerable
size = block_given? ? select(&block).size : self.size
size > 1
end
+
+ # The negative of the Enumerable#include?. Returns true if the collection does not include the object.
+ def exclude?(object)
+ !include?(object)
+ end
end
class Range #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/object/extending.rb b/activesupport/lib/active_support/core_ext/object/extending.rb
index 0cc74c8298..de8121f274 100644
--- a/activesupport/lib/active_support/core_ext/object/extending.rb
+++ b/activesupport/lib/active_support/core_ext/object/extending.rb
@@ -1,46 +1,53 @@
-class Object
- def remove_subclasses_of(*superclasses) #:nodoc:
- Class.remove_class(*subclasses_of(*superclasses))
- end
-
- begin
- ObjectSpace.each_object(Class.new) {}
-
- # Exclude this class unless it's a subclass of our supers and is defined.
- # We check defined? in case we find a removed class that has yet to be
- # garbage collected. This also fails for anonymous classes -- please
- # submit a patch if you have a workaround.
- def subclasses_of(*superclasses) #:nodoc:
+class Class
+ # Rubinius
+ if defined?(Class.__subclasses__)
+ def descendents
subclasses = []
-
- superclasses.each do |sup|
- ObjectSpace.each_object(class << sup; self; end) do |k|
- if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
- subclasses << k
- end
- end
- end
-
+ __subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
subclasses
end
- rescue RuntimeError
- # JRuby and any implementations which cannot handle the objectspace traversal
- # above fall back to this implementation
- def subclasses_of(*superclasses) #:nodoc:
- subclasses = []
+ else
+ # MRI
+ begin
+ ObjectSpace.each_object(Class.new) {}
- superclasses.each do |sup|
+ def descendents
+ subclasses = []
+ ObjectSpace.each_object(class << self; self; end) do |k|
+ subclasses << k unless k == self
+ end
+ subclasses
+ end
+ # JRuby
+ rescue StandardError
+ def descendents
+ subclasses = []
ObjectSpace.each_object(Class) do |k|
- if superclasses.any? { |superclass| k < superclass } &&
- (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
- subclasses << k
- end
+ subclasses << k if k < self
end
subclasses.uniq!
+ subclasses
end
- subclasses
end
end
+end
+
+class Object
+ def remove_subclasses_of(*superclasses) #:nodoc:
+ Class.remove_class(*subclasses_of(*superclasses))
+ end
+
+ # Exclude this class unless it's a subclass of our supers and is defined.
+ # We check defined? in case we find a removed class that has yet to be
+ # garbage collected. This also fails for anonymous classes -- please
+ # submit a patch if you have a workaround.
+ def subclasses_of(*superclasses) #:nodoc:
+ subclasses = []
+ superclasses.each do |klass|
+ subclasses.concat klass.descendents.select {|k| k.name.blank? || k.reachable?}
+ end
+ subclasses
+ end
def extended_by #:nodoc:
ancestors = class << self; ancestors end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 4f4492f0fd..703b89ffd0 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -1,4 +1,5 @@
require 'active_support/duration'
+require 'active_support/core_ext/date/acts_like'
require 'active_support/core_ext/date/calculations'
class Time
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
index 973875f895..96ab04c61a 100644
--- a/activesupport/lib/active_support/dependencies/autoload.rb
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -2,16 +2,18 @@ require "active_support/inflector/methods"
module ActiveSupport
module Autoload
-
@@autoloads = {}
@@under_path = nil
@@at_path = nil
+ @@autoload_defer = false
def autoload(const_name, path = @@at_path)
full = [self.name, @@under_path, const_name.to_s, path].compact.join("::")
location = path || Inflector.underscore(full)
- @@autoloads[const_name] = location
+ unless @@autoload_defer
+ @@autoloads[const_name] = location
+ end
super const_name, location
end
@@ -29,9 +31,19 @@ module ActiveSupport
@@at_path = old_path
end
+ def deferrable
+ old_defer, @@autoload_defer = @@autoload_defer, true
+ yield
+ ensure
+ @@autoload_defer = old_defer
+ end
+
def self.eager_autoload!
- @@autoloads.values.each {|file| require file }
+ @@autoloads.values.each { |file| require file }
end
+ def autoloads
+ @@autoloads
+ end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb
index f811239077..1e49ccdade 100644
--- a/activesupport/lib/active_support/ruby/shim.rb
+++ b/activesupport/lib/active_support/ruby/shim.rb
@@ -14,5 +14,6 @@ require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/process/daemon'
require 'active_support/core_ext/string/conversions'
+require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/rexml'
require 'active_support/core_ext/time/conversions'
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 4341ead488..278c05797b 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -350,6 +350,10 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f
end
+ def test_to_i
+ assert_equal 946684800, DateTime.civil(2000).to_i
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 66f5f9fbde..4650b796b6 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -89,4 +89,9 @@ class EnumerableTests < Test::Unit::TestCase
assert ![ 1, 2 ].many? {|x| x > 1 }
assert [ 1, 2, 2 ].many? {|x| x > 1 }
end
+
+ def test_exclude?
+ assert [ 1 ].exclude?(2)
+ assert ![ 1 ].exclude?(1)
+ end
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index bb60968a4f..3a12100e86 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -284,6 +284,12 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 946684800, result
assert result.is_a?(Integer)
end
+
+ def test_to_i_with_wrapped_datetime
+ datetime = DateTime.civil(2000, 1, 1, 0)
+ twz = ActiveSupport::TimeWithZone.new(datetime, @time_zone)
+ assert_equal 946684800, twz.to_i
+ end
def test_to_time
assert_equal @twz, @twz.to_time
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index a3ae39d071..cf27357b32 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -62,7 +62,7 @@ class DeprecationTest < ActiveSupport::TestCase
end
def test_deprecate_class_method
- assert_deprecated(/none is deprecated.*test_deprecate_class_method at/) do
+ assert_deprecated(/none is deprecated.*test_deprecate_class_method/) do
assert_equal 1, @dtc.none
end
diff --git a/railties/bin/rails b/railties/bin/rails
index 808df97429..0f51d5739f 100755
--- a/railties/bin/rails
+++ b/railties/bin/rails
@@ -4,9 +4,10 @@ rescue LoadError
# If people are not using gems, the load path must still
# be correct.
# TODO: Remove the begin / rescue block somehow
- $:.unshift File.dirname(__FILE__) + '/../lib'
- $:.unshift File.dirname(__FILE__) + '/../../activesupport/lib'
- retry
+ $:.unshift File.expand_path('../../lib', __FILE__)
+ $:.unshift File.expand_path('../../../activesupport/lib', __FILE__)
+ $:.unshift File.expand_path('../../../actionpack/lib', __FILE__)
+ require 'rails/ruby_version_check'
end
Signal.trap("INT") { puts; exit }
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index b7cae9a9ac..85aeb4af24 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -3,9 +3,11 @@ require "pathname"
require 'active_support'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/logger'
+require 'action_dispatch'
require 'rails/initializable'
require 'rails/application'
+require 'rails/plugin'
require 'rails/railties_path'
require 'rails/version'
require 'rails/rack'
@@ -14,7 +16,6 @@ require 'rails/core'
require 'rails/configuration'
require 'rails/deprecation'
require 'rails/initializer'
-require 'rails/plugin'
require 'rails/ruby_version_check'
# For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
@@ -29,4 +30,4 @@ else
Encoding.default_external = Encoding::UTF_8
end
-RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV) \ No newline at end of file
+RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV)
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 110311558c..e65c20de2c 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -13,7 +13,11 @@ module Rails
end
def config
- @config ||= Configuration.new
+ @config ||= begin
+ config = Configuration.new
+ Plugin.plugins.each { |p| config.merge(p.config) }
+ config
+ end
end
# TODO: change the plugin loader to use config
@@ -42,8 +46,13 @@ module Rails
end
end
+ attr_reader :route_configuration_files
+
def initialize
Rails.application ||= self
+
+ @route_configuration_files = []
+
run_initializers(self)
end
@@ -65,6 +74,32 @@ module Rails
ActionController::Routing::Routes
end
+ def routes_changed_at
+ routes_changed_at = nil
+
+ route_configuration_files.each do |config|
+ config_changed_at = File.stat(config).mtime
+
+ if routes_changed_at.nil? || config_changed_at > routes_changed_at
+ routes_changed_at = config_changed_at
+ end
+ end
+
+ routes_changed_at
+ end
+
+ def reload_routes!
+ routes.disable_clear_and_finalize = true
+
+ routes.clear!
+ route_configuration_files.each { |config| load(config) }
+ routes.finalize!
+
+ nil
+ ensure
+ routes.disable_clear_and_finalize = false
+ end
+
def initializers
initializers = super
plugins.each { |p| initializers += p.initializers }
@@ -73,6 +108,8 @@ module Rails
def plugins
@plugins ||= begin
+ plugin_names = config.plugins || [:all]
+ Plugin.plugins.select { |p| plugin_names.include?(p.plugin_name) } +
Plugin::Vendored.all(config.plugins || [:all], config.paths.vendor.plugins)
end
end
@@ -173,9 +210,9 @@ module Rails
initializer :initialize_middleware_stack do
if config.frameworks.include?(:action_controller)
- config.middleware.use(::Rack::Lock) unless ActionController::Base.allow_concurrency
- config.middleware.use(ActionDispatch::ShowExceptions, ActionController::Base.consider_all_requests_local)
- config.middleware.use(ActionDispatch::Callbacks, ActionController::Dispatcher.prepare_each_request)
+ config.middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency })
+ config.middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local })
+ config.middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request })
config.middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
config.middleware.use(ActionDispatch::ParamsParser)
config.middleware.use(::Rack::MethodOverride)
@@ -359,6 +396,18 @@ module Rails
next unless configuration.frameworks.include?(:action_controller)
require 'rails/dispatcher' unless defined?(::Dispatcher)
Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
+
+ unless configuration.cache_classes
+ # Setup dev mode route reloading
+ routes_last_modified = routes_changed_at
+ reload_routes = lambda do
+ unless routes_changed_at == routes_last_modified
+ routes_last_modified = routes_changed_at
+ reload_routes!
+ end
+ end
+ ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call }
+ end
end
# Routing must be initialized after plugins to allow the former to extend the routes
@@ -368,10 +417,8 @@ module Rails
# loading module used to lazily load controllers (Configuration#controller_paths).
initializer :initialize_routing do
next unless configuration.frameworks.include?(:action_controller)
-
- ActionController::Routing::Routes.controller_paths += configuration.controller_paths
- ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
- ActionController::Routing::Routes.reload!
+ route_configuration_files << configuration.routes_configuration_file
+ reload_routes!
end
#
# # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index 3f43a48e2e..0fa42091dd 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -1,27 +1,71 @@
require 'active_support/ordered_options'
module Rails
- class Configuration
- attr_accessor :cache_classes, :load_paths, :load_once_paths, :after_initialize_blocks,
- :frameworks, :framework_root_path, :root, :gems, :plugins,
- :i18n, :gems, :whiny_nils, :consider_all_requests_local,
- :action_controller, :active_record, :action_view, :active_support,
- :action_mailer, :active_resource,
- :reload_plugins, :log_path, :log_level, :logger, :preload_frameworks,
- :database_configuration_file, :cache_store, :time_zone,
- :view_path, :metals, :controller_paths, :routes_configuration_file,
- :eager_load_paths, :dependency_loading, :paths, :serve_static_assets
+ # Temporarily separate the plugin configuration class from the main
+ # configuration class while this bit is being cleaned up.
+ class Plugin::Configuration
def initialize
+ @options = Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new }
+ end
+
+ def middleware
+ @middleware ||= ActionDispatch::MiddlewareStack.new
+ end
+
+ def respond_to?(name)
+ super || name.to_s =~ config_key_regexp
+ end
+
+ def merge(config)
+ @options = config.options.merge(@options)
+ end
+
+ protected
+
+ attr_reader :options
+
+ 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 config_key_regexp
+ bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|')
+ /^(#{bits})(?:=)?$/
+ end
+
+ def config_keys
+ ([ :active_support, :active_record, :action_controller,
+ :action_view, :action_mailer, :active_resource ] +
+ Plugin.plugin_names).map { |n| n.to_s }.uniq
+ end
+ end
+
+ class Configuration < Plugin::Configuration
+ attr_accessor :after_initialize_blocks, :cache_classes,
+ :consider_all_requests_local, :dependency_loading, :gems,
+ :load_once_paths, :logger, :metals, :plugins,
+ :preload_frameworks, :reload_plugins, :serve_static_assets,
+ :time_zone, :whiny_nils
+
+ attr_writer :cache_store, :controller_paths,
+ :database_configuration_file, :eager_load_paths,
+ :frameworks, :framework_root_path, :i18n, :load_paths,
+ :log_level, :log_path, :paths, :routes_configuration_file,
+ :view_path
+
+ def initialize
+ super
@load_once_paths = []
@after_initialize_blocks = []
@dependency_loading = true
@serve_static_assets = true
-
- for framework in frameworks
- self.send("#{framework}=", ActiveSupport::OrderedOptions.new)
- end
- self.active_support = ActiveSupport::OrderedOptions.new
end
def after_initialize(&blk)
@@ -80,7 +124,10 @@ module Rails
self.preload_frameworks = true
self.cache_classes = true
self.dependency_loading = false
- self.action_controller.allow_concurrency = true
+
+ if respond_to?(:action_controller)
+ action_controller.allow_concurrency = true
+ end
self
end
@@ -99,11 +146,6 @@ module Rails
defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root}/vendor/rails"
end
- def middleware
- require 'action_dispatch'
- @middleware ||= ActionDispatch::MiddlewareStack.new
- end
-
# Loads and returns the contents of the #database_configuration_file. The
# contents of the file are processed via ERB before being sent through
# YAML::load.
diff --git a/railties/lib/rails/console_app.rb b/railties/lib/rails/console_app.rb
index 9a51d594d3..2c4a7a51e8 100644
--- a/railties/lib/rails/console_app.rb
+++ b/railties/lib/rails/console_app.rb
@@ -1,7 +1,6 @@
require 'active_support/all'
require 'active_support/test_case'
require 'action_controller'
-require 'action_dispatch/test_case'
# work around the at_exit hook in test/unit, which kills IRB
Test::Unit.run = true if Test::Unit.respond_to?(:run=)
@@ -28,6 +27,6 @@ end
def reload!
puts "Reloading..."
ActionDispatch::Callbacks.new(lambda {}, true)
- ActionController::Routing::Routes.reload
+ Rails.application.reload_routes!
true
end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index ffb9cfe1cd..0e66c9f58f 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -1,5 +1,6 @@
-activesupport_path = "#{File.dirname(__FILE__)}/../../../activesupport/lib"
-$LOAD_PATH.unshift(activesupport_path) if File.directory?(activesupport_path)
+activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
require 'active_support'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/metaclass'
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
index 6460e5b599..51c4ad0e2e 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
@@ -7,7 +7,7 @@
</head>
<body>
-<p class="notice"><%%= flash[:notice] %></p>
+<p class="notice"><%%= notice %></p>
<%%= yield %>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
index 6635a3f487..e7991fff92 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
+++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
@@ -2,9 +2,7 @@
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
- helper :all # include all helpers, all the time
- protect_from_forgery # See ActionController::RequestForgeryProtection for details
-
- # Scrub sensitive parameters from your log
- # filter_parameter_logging :password
+ helper :all
+ protect_from_forgery
+ filter_parameter_logging :password, :password_confirmation
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
index e0f9ca8a12..0d1b6bab4f 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
@@ -3,7 +3,7 @@ ActionController::Routing::Routes.draw do |map|
# first created -> highest priority.
# Sample of regular route:
- # match 'products/:id', :to => 'catalog#view'
+ # match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
@@ -52,9 +52,7 @@ ActionController::Routing::Routes.draw do |map|
# See how all your routes lay out with "rake routes"
- # Install the default route as the lowest priority.
- # Note: The default route make all actions in every controller accessible
- # via GET requests. You should consider removing or commenting it out if
- # you're using named routes and resources.
- match ':controller(/:action(/:id(.:format)))'
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
+ # Note: This route will make all actions in every controller accessible via GET requests.
+ # match ':controller(/:action(/:id(.:format)))'
end
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
index 3cc8bbf8e7..874e96a2b4 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
@@ -46,8 +46,7 @@ class <%= controller_class_name %>Controller < ApplicationController
respond_to do |format|
if @<%= orm_instance.save %>
- flash[:notice] = '<%= class_name %> was successfully created.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') }
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
else
format.html { render :action => "new" }
@@ -63,8 +62,7 @@ class <%= controller_class_name %>Controller < ApplicationController
respond_to do |format|
if @<%= orm_instance.update_attributes("params[:#{file_name}]") %>
- flash[:notice] = '<%= class_name %> was successfully updated.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
index c21035113e..a30132bc99 100644
--- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
+++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
@@ -11,9 +11,13 @@ two:
<%= attribute.name %>: <%= attribute.default %>
<% end -%>
<% else -%>
-# one:
-# column: value
+# This model initially had no columns defined. If you add columns to the
+# model remove the '{}' from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
#
-# two:
-# column: value
-<% end -%>
+one: {}
+# column: value
+#
+two: {}
+# column: value
+<% end -%> \ No newline at end of file
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
index 96234739cf..add10bd207 100644
--- a/railties/lib/rails/initializable.rb
+++ b/railties/lib/rails/initializable.rb
@@ -5,7 +5,7 @@ module Rails
end
class Initializer
- attr_reader :name, :before, :after, :global, :block
+ attr_reader :name, :block
def initialize(name, context, options, &block)
@name, @context, @options, @block = name, context, options, block
@@ -62,7 +62,7 @@ module Rails
end
def run_initializers(*args)
- return if @ran
+ return if instance_variable_defined?(:@ran)
initializers.each do |initializer|
initializer.run(*args)
end
diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb
index 86bf032641..90dc1ad8dd 100644
--- a/railties/lib/rails/plugin.rb
+++ b/railties/lib/rails/plugin.rb
@@ -2,6 +2,27 @@ module Rails
class Plugin
include Initializable
+ def self.plugin_name
+ @plugin_name || name.demodulize.underscore
+ end
+
+ def self.inherited(klass)
+ @plugins ||= []
+ @plugins << klass unless klass == Vendored
+ end
+
+ def self.plugins
+ @plugins
+ end
+
+ def self.plugin_names
+ plugins.map { |p| p.plugin_name }
+ end
+
+ def self.config
+ @config ||= Configuration.new
+ end
+
class Vendored < Plugin
def self.all(list, paths)
plugins = []
@@ -55,8 +76,8 @@ module Rails
initializer :add_routing_file, :after => :initialize_routing do |app|
routing_file = "#{path}/config/routes.rb"
if File.exist?(routing_file)
- app.routes.add_configuration_file(routing_file)
- app.routes.reload!
+ app.route_configuration_files << routing_file
+ app.reload_routes!
end
end
end
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 0bf5f5c625..b89b7b5c27 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -12,7 +12,6 @@ require 'active_support/core_ext/kernel/requires'
# AP is always present
require 'action_controller/test_case'
require 'action_view/test_case'
-require 'action_dispatch/test_case'
require 'action_mailer/test_case' if defined?(ActionMailer)
require 'active_model/test_case' if defined?(ActiveModel)
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 1fcab8c651..89337b7f66 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -53,5 +53,26 @@ module ApplicationTests
assert_raises(NoMethodError) { 1.day }
end
end
+
+ test "marking the application as threadsafe sets the correct config variables" do
+ add_to_config <<-RUBY
+ config.threadsafe!
+ RUBY
+
+ require "#{app_path}/config/application"
+ assert AppTemplate.configuration.action_controller.allow_concurrency
+ end
+
+ test "the application can be marked as threadsafe when there are no frameworks" do
+ FileUtils.rm_rf("#{app_path}/config/environments")
+ add_to_config <<-RUBY
+ config.frameworks = []
+ config.threadsafe!
+ RUBY
+
+ assert_nothing_raised do
+ require "#{app_path}/config/application"
+ end
+ end
end
end
diff --git a/railties/test/application/initializer_test.rb b/railties/test/application/initializer_test.rb
index 56582c5772..fa00d287ca 100644
--- a/railties/test/application/initializer_test.rb
+++ b/railties/test/application/initializer_test.rb
@@ -6,6 +6,7 @@ module ApplicationTests
def setup
build_app
+ FileUtils.rm_rf("#{app_path}/config/environments")
boot_rails
require "rails"
end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index 1bfec3805b..decde056fd 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -81,5 +81,75 @@ module ApplicationTests
get '/admin/foo'
assert_equal 'admin::foo', last_response.body
end
+
+ test "merges with plugin routes" do
+ controller 'foo', <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ ActionController::Routing::Routes.draw do |map|
+ match 'foo', :to => 'foo#index'
+ end
+ RUBY
+
+ plugin 'bar', 'require File.dirname(__FILE__) + "/app/controllers/bar"' do |plugin|
+ plugin.write 'app/controllers/bar.rb', <<-RUBY
+ class BarController < ActionController::Base
+ def index
+ render :text => "bar"
+ end
+ end
+ RUBY
+
+ plugin.write 'config/routes.rb', <<-RUBY
+ ActionController::Routing::Routes.draw do |map|
+ match 'bar', :to => 'bar#index'
+ end
+ RUBY
+ end
+
+ get '/foo'
+ assert_equal 'foo', last_response.body
+
+ get '/bar'
+ assert_equal 'bar', last_response.body
+ end
+
+ test "reloads routes when configuration is changed" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def bar
+ render :text => "bar"
+ end
+
+ def baz
+ render :text => "baz"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ ActionController::Routing::Routes.draw do |map|
+ match 'foo', :to => 'foo#bar'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'bar', last_response.body
+
+ app_file 'config/routes.rb', <<-RUBY
+ ActionController::Routing::Routes.draw do |map|
+ match 'foo', :to => 'foo#baz'
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal 'baz', last_response.body
+ end
end
end
diff --git a/railties/test/plugins/configuration_test.rb b/railties/test/plugins/configuration_test.rb
new file mode 100644
index 0000000000..edf8bb37f5
--- /dev/null
+++ b/railties/test/plugins/configuration_test.rb
@@ -0,0 +1,36 @@
+require "isolation/abstract_unit"
+
+module PluginsTest
+ class ConfigurationTest < Test::Unit::TestCase
+ def setup
+ build_app
+ boot_rails
+ require "rails"
+ end
+
+ test "config is available to plugins" do
+ class Foo < Rails::Plugin ; end
+ assert_nil Foo.config.action_controller.foo
+ end
+
+ test "a config name is available for the plugin" do
+ class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
+ assert_equal "hello", Foo.config.foo.greetings
+ end
+
+ test "plugin configurations are available in the application" do
+ class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
+ require "#{app_path}/config/application"
+ assert_equal "hello", AppTemplate.config.foo.greetings
+ end
+
+ test "plugin config merges are deep" do
+ class Foo < Rails::Plugin ; config.foo.greetings = 'hello' ; end
+ class MyApp < Rails::Application
+ config.foo.bar = "bar"
+ end
+ assert_equal "hello", MyApp.config.foo.greetings
+ assert_equal "bar", MyApp.config.foo.bar
+ end
+ end
+end \ No newline at end of file