aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2008-08-03 13:54:44 +0100
committerPratik Naik <pratiknaik@gmail.com>2008-08-03 13:54:44 +0100
commitf6124c2b09aed7b5951d0ac83438459c49757a36 (patch)
tree37ced4d11eafdb81f5173ae8b08e6124d3fee03c
parentacd0456fcf251d1e50cbf08311341dfd370dc1aa (diff)
parentcb21db1a334e6ca2695d4e7183b1bdce204b9eb3 (diff)
downloadrails-f6124c2b09aed7b5951d0ac83438459c49757a36.tar.gz
rails-f6124c2b09aed7b5951d0ac83438459c49757a36.tar.bz2
rails-f6124c2b09aed7b5951d0ac83438459c49757a36.zip
Merge commit 'mainstream/master'
-rw-r--r--[-rwxr-xr-x]actionmailer/README0
-rw-r--r--[-rwxr-xr-x]actionmailer/Rakefile0
-rw-r--r--[-rwxr-xr-x]actionmailer/lib/action_mailer.rb0
-rw-r--r--actionmailer/lib/action_mailer/base.rb19
-rw-r--r--[-rwxr-xr-x]actionmailer/test/mail_service_test.rb0
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_controller.rb0
-rw-r--r--actionpack/lib/action_controller/assertions/routing_assertions.rb44
-rw-r--r--actionpack/lib/action_controller/assertions/selector_assertions.rb26
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_controller/base.rb17
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb18
-rw-r--r--actionpack/lib/action_controller/integration.rb2
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_controller/request.rb0
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_controller/request_profiler.rb0
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_controller/response.rb0
-rw-r--r--actionpack/lib/action_controller/routing.rb58
-rw-r--r--actionpack/lib/action_controller/routing/builder.rb29
-rw-r--r--actionpack/lib/action_controller/routing/optimisations.rb23
-rw-r--r--actionpack/lib/action_controller/routing/recognition_optimisation.rb40
-rw-r--r--actionpack/lib/action_controller/routing/route.rb309
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb7
-rw-r--r--actionpack/lib/action_controller/routing/routing_ext.rb1
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb34
-rwxr-xr-x[-rw-r--r--]actionpack/lib/action_controller/session/drb_server.rb14
-rw-r--r--[-rwxr-xr-x]actionpack/lib/action_view/helpers/date_helper.rb0
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb186
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb2
-rw-r--r--actionpack/lib/action_view/locale/en-US.rb35
-rw-r--r--actionpack/lib/action_view/paths.rb2
-rw-r--r--[-rwxr-xr-x]actionpack/test/controller/cgi_test.rb0
-rw-r--r--[-rwxr-xr-x]actionpack/test/controller/redirect_test.rb0
-rw-r--r--actionpack/test/controller/routing_test.rb152
-rw-r--r--[-rwxr-xr-x]actionpack/test/controller/session/cookie_store_test.rb0
-rw-r--r--actionpack/test/controller/test_test.rb25
-rw-r--r--[-rwxr-xr-x]actionpack/test/template/date_helper_test.rb0
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb6
-rw-r--r--actionpack/test/template/number_helper_i18n_test.rb46
-rw-r--r--actionpack/test/template/number_helper_test.rb48
-rw-r--r--actionpack/test/template/prototype_helper_test.rb18
-rwxr-xr-x[-rw-r--r--]activemodel/Rakefile0
-rw-r--r--[-rwxr-xr-x]activerecord/README0
-rw-r--r--[-rwxr-xr-x]activerecord/Rakefile0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/associations.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/associations/belongs_to_association.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/associations/has_one_association.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/base.rb10
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/callbacks.rb0
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb4
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/connection_adapters/abstract_adapter.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/connection_adapters/mysql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb4
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/fixtures.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/lib/active_record/validations.rb46
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/associations/belongs_to_associations_test.rb0
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb9
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/associations/has_one_associations_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/associations_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/attribute_methods_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/base_test.rb8
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/deprecated_finder_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/fixtures_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/inheritance_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/lifecycle_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/readonly_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/unconnected_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/cases/validations_test.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/models/company.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/models/reply.rb0
-rw-r--r--[-rwxr-xr-x]activerecord/test/models/topic.rb0
-rw-r--r--activesupport/lib/active_support/basic_object.rb2
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/array/grouping.rb10
-rw-r--r--activesupport/lib/active_support/memoizable.rb7
-rwxr-xr-x[-rw-r--r--]activesupport/lib/active_support/multibyte/generators/generate_tables.rb0
-rw-r--r--activesupport/lib/active_support/testing/performance.rb4
-rw-r--r--railties/CHANGELOG2
-rwxr-xr-x[-rw-r--r--]railties/bin/about0
-rwxr-xr-x[-rw-r--r--]railties/bin/console0
-rwxr-xr-x[-rw-r--r--]railties/bin/destroy0
-rwxr-xr-x[-rw-r--r--]railties/bin/generate0
-rwxr-xr-x[-rw-r--r--]railties/bin/performance/benchmarker0
-rwxr-xr-x[-rw-r--r--]railties/bin/performance/profiler0
-rwxr-xr-x[-rw-r--r--]railties/bin/performance/request0
-rwxr-xr-x[-rw-r--r--]railties/bin/plugin0
-rwxr-xr-x[-rw-r--r--]railties/bin/process/inspector0
-rwxr-xr-x[-rw-r--r--]railties/bin/process/reaper0
-rwxr-xr-x[-rw-r--r--]railties/bin/process/spawner0
-rwxr-xr-x[-rw-r--r--]railties/bin/runner0
-rwxr-xr-x[-rw-r--r--]railties/bin/server0
-rw-r--r--[-rwxr-xr-x]railties/configs/apache.conf0
-rwxr-xr-xrailties/dispatches/dispatch.fcgi2
-rwxr-xr-xrailties/dispatches/dispatch.rb4
-rwxr-xr-x[-rw-r--r--]railties/dispatches/gateway.cgi4
-rw-r--r--railties/lib/commands/dbconsole.rb2
-rwxr-xr-x[-rw-r--r--]railties/lib/commands/ncgi/listener4
-rwxr-xr-x[-rw-r--r--]railties/lib/commands/ncgi/tracker4
-rw-r--r--railties/lib/initializer.rb10
-rw-r--r--[-rwxr-xr-x]railties/lib/rails_generator/generators/components/plugin/templates/Rakefile0
103 files changed, 743 insertions, 600 deletions
diff --git a/actionmailer/README b/actionmailer/README
index 0e16ea6ec6..0e16ea6ec6 100755..100644
--- a/actionmailer/README
+++ b/actionmailer/README
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index 612bd27774..612bd27774 100755..100644
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 2e324d4637..2e324d4637 100755..100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index a43296461b..fa29ae2446 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -250,7 +250,7 @@ module ActionMailer #:nodoc:
private_class_method :new #:nodoc:
- class_inheritable_accessor :template_root
+ class_inheritable_accessor :view_paths
cattr_accessor :logger
cattr_accessor :template_extensions
@@ -425,9 +425,12 @@ module ActionMailer #:nodoc:
template_extensions << extension
end
+ def template_root
+ self.view_paths && self.view_paths.first
+ end
+
def template_root=(root)
- root = ActionView::PathSet::Path.new(root) if root.is_a?(String)
- write_inheritable_attribute(:template_root, root)
+ self.view_paths = ActionView::Base.process_view_paths(root)
end
end
@@ -541,12 +544,20 @@ module ActionMailer #:nodoc:
initialize_template_class(body).render(opts)
end
+ def template_root
+ self.class.template_root
+ end
+
+ def template_root=(root)
+ self.class.template_root = root
+ end
+
def template_path
"#{template_root}/#{mailer_name}"
end
def initialize_template_class(assigns)
- ActionView::Base.new(template_root, assigns, self)
+ ActionView::Base.new(view_paths, assigns, self)
end
def sort_parts(parts, order = [])
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index e5ecb0e254..e5ecb0e254 100755..100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 03e011c75c..177c6a354e 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Added back ActionController::Base.allow_concurrency flag [Josh Peek]
+
* AbstractRequest.relative_url_root is no longer automatically configured by a HTTP header. It can now be set in your configuration environment with config.action_controller.relative_url_root [Josh Peek]
* Update Prototype to 1.6.0.2 #599 [Patrick Joyce]
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 3c4a339d50..3c4a339d50 100755..100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
diff --git a/actionpack/lib/action_controller/assertions/routing_assertions.rb b/actionpack/lib/action_controller/assertions/routing_assertions.rb
index 491b72d586..312b4e228b 100644
--- a/actionpack/lib/action_controller/assertions/routing_assertions.rb
+++ b/actionpack/lib/action_controller/assertions/routing_assertions.rb
@@ -2,7 +2,7 @@ module ActionController
module Assertions
# Suite of assertions to test routes generated by Rails and the handling of requests made to them.
module RoutingAssertions
- # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
+ # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
# match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+.
#
# Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes
@@ -14,16 +14,16 @@ module ActionController
#
# You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
# to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the
- # extras argument, appending the query string on the path directly will not work. For example:
+ # extras argument, appending the query string on the path directly will not work. For example:
#
# # assert that a path of '/items/list/1?view=print' returns the correct options
- # assert_recognizes({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })
+ # assert_recognizes({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })
#
- # The +message+ parameter allows you to pass in an error message that is displayed upon failure.
+ # The +message+ parameter allows you to pass in an error message that is displayed upon failure.
#
# ==== Examples
# # Check the default route (i.e., the index action)
- # assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
+ # assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
#
# # Test a specific action
# assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list')
@@ -44,16 +44,16 @@ module ActionController
request_method = nil
end
- clean_backtrace do
- ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
+ clean_backtrace do
+ ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
request = recognized_request_for(path, request_method)
-
+
expected_options = expected_options.clone
extras.each_key { |key| expected_options.delete key } unless extras.nil?
-
+
expected_options.stringify_keys!
routing_diff = expected_options.diff(request.path_parameters)
- msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
+ msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
request.path_parameters, expected_options, expected_options.diff(request.path_parameters))
assert_block(msg) { request.path_parameters == expected_options }
end
@@ -64,7 +64,7 @@ module ActionController
# a query string. The +message+ parameter allows you to specify a custom error message for assertion failures.
#
# The +defaults+ parameter is unused.
- #
+ #
# ==== Examples
# # Asserts that the default action is generated for a route with no action
# assert_generates("/items", :controller => "items", :action => "index")
@@ -73,34 +73,34 @@ module ActionController
# assert_generates("/items/list", :controller => "items", :action => "list")
#
# # Tests the generation of a route with a parameter
- # assert_generates("/items/list/1", { :controller => "items", :action => "list", :id => "1" })
+ # assert_generates("/items/list/1", { :controller => "items", :action => "list", :id => "1" })
#
# # Asserts that the generated route gives us our custom route
# assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
- clean_backtrace do
+ clean_backtrace do
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?
-
+ 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}
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
assert_block(msg) { found_extras == extras }
-
- msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
+
+ msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
expected_path)
assert_block(msg) { expected_path == generated_path }
end
end
- # Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
+ # Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
# <tt>options</tt> and then that <tt>options</tt> generates <tt>path</tt>. This essentially combines +assert_recognizes+
# and +assert_generates+ into one step.
#
# The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
- # +message+ parameter allows you to specify a custom error message to display upon failure.
+ # +message+ parameter allows you to specify a custom error message to display upon failure.
#
# ==== Examples
# # Assert a basic route: a controller with the default action (index)
@@ -119,12 +119,12 @@ module ActionController
# assert_routing({ :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" })
def assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_recognizes(options, path, extras, message)
-
- controller, default_controller = options[:controller], defaults[:controller]
+
+ controller, default_controller = options[:controller], defaults[:controller]
if controller && controller.include?(?/) && default_controller && default_controller.include?(?/)
options[:controller] = "/#{controller}"
end
-
+
assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message)
end
diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb
index 70b0ed53e7..9114894b1d 100644
--- a/actionpack/lib/action_controller/assertions/selector_assertions.rb
+++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb
@@ -407,6 +407,7 @@ module ActionController
if rjs_type == :insert
arg = args.shift
+ position = arg
insertion = "insert_#{arg}".to_sym
raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
statement = "(#{RJS_STATEMENTS[insertion]})"
@@ -418,6 +419,7 @@ module ActionController
else
statement = "#{RJS_STATEMENTS[:any]}"
end
+ position ||= Regexp.new(RJS_INSERTIONS.join('|'))
# Next argument we're looking for is the element identifier. If missing, we pick
# any element.
@@ -434,9 +436,14 @@ module ActionController
Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
when :remove, :show, :hide, :toggle
Regexp.new("#{statement}\\(\"#{id}\"\\)")
- else
- Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
- end
+ when :replace, :replace_html
+ Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)")
+ when :insert, :insert_html
+ Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);")
+ else
+ Regexp.union(Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)"),
+ Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);"))
+ end
# Duplicate the body since the next step involves destroying it.
matches = nil
@@ -445,7 +452,7 @@ module ActionController
matches = @response.body.match(pattern)
else
@response.body.gsub(pattern) do |match|
- html = unescape_rjs($2)
+ html = unescape_rjs(match)
matches ||= []
matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
""
@@ -585,17 +592,16 @@ module ActionController
:hide => /Element\.hide/,
:toggle => /Element\.toggle/
}
+ RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
+ RJS_PATTERN_HTML = /"((\\"|[^"])*)"/
RJS_INSERTIONS = [:top, :bottom, :before, :after]
RJS_INSERTIONS.each do |insertion|
- RJS_STATEMENTS["insert_#{insertion}".to_sym] = Regexp.new(Regexp.quote("new Insertion.#{insertion.to_s.camelize}"))
+ RJS_STATEMENTS["insert_#{insertion}".to_sym] = /Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/
end
- RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
RJS_STATEMENTS[:insert_html] = Regexp.new(RJS_INSERTIONS.collect do |insertion|
- Regexp.quote("new Insertion.#{insertion.to_s.camelize}")
+ /Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/
end.join('|'))
- RJS_PATTERN_HTML = /"((\\"|[^"])*)"/
- RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)",
- Regexp::MULTILINE)
+ RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 5f4a38dac0..5689a9825e 100755..100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -283,6 +283,14 @@ module ActionController #:nodoc:
@@debug_routes = true
cattr_accessor :debug_routes
+ # Indicates whether to allow concurrent action processing. Your
+ # controller actions and any other code they call must also behave well
+ # when called from concurrent threads. Turned off by default.
+ @@allow_concurrency = false
+ cattr_accessor :allow_concurrency
+
+ @@guard = Monitor.new
+
# Modern REST web services often need to submit complex data to the web application.
# The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the
# <tt>params</tt> hash. These handlers are invoked for POST and PUT requests.
@@ -537,7 +545,12 @@ module ActionController #:nodoc:
forget_variables_added_to_assigns
log_processing
- send(method, *arguments)
+
+ if @@allow_concurrency
+ send(method, *arguments)
+ else
+ @@guard.synchronize { send(method, *arguments) }
+ end
assign_default_content_type_and_charset
response.prepare! unless component_request?
@@ -1195,7 +1208,7 @@ module ActionController #:nodoc:
elsif template_exists? && template_public?
default_render
else
- raise UnknownAction, "No action responded to #{action_name}", caller
+ raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.to_a.sort.to_sentence}", caller
end
end
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index 7df987d525..835d8e834e 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -2,8 +2,6 @@ module ActionController
# Dispatches requests to the appropriate controller and takes care of
# reloading the app after each request when Dependencies.load? is true.
class Dispatcher
- @@guard = Mutex.new
-
class << self
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
@@ -101,15 +99,13 @@ module ActionController
end
def dispatch
- @@guard.synchronize do
- begin
- run_callbacks :before_dispatch
- handle_request
- rescue Exception => exception
- failsafe_rescue exception
- ensure
- run_callbacks :after_dispatch, :enumerator => :reverse_each
- end
+ begin
+ run_callbacks :before_dispatch
+ handle_request
+ rescue Exception => exception
+ failsafe_rescue exception
+ ensure
+ run_callbacks :after_dispatch, :enumerator => :reverse_each
end
end
diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb
index 43158ea412..1d2b81355c 100644
--- a/actionpack/lib/action_controller/integration.rb
+++ b/actionpack/lib/action_controller/integration.rb
@@ -507,7 +507,7 @@ EOF
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
reset! unless @integration_session
- returning @integration_session.send!(sym, *args, &block) do
+ returning @integration_session.__send__(sym, *args, &block) do
copy_session_variables!
end
end
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 60ff75fe2c..60ff75fe2c 100755..100644
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
diff --git a/actionpack/lib/action_controller/request_profiler.rb b/actionpack/lib/action_controller/request_profiler.rb
index a6471d0c08..a6471d0c08 100755..100644
--- a/actionpack/lib/action_controller/request_profiler.rb
+++ b/actionpack/lib/action_controller/request_profiler.rb
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb
index da352b6993..da352b6993 100755..100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_controller/response.rb
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index dfbaa53b7c..8d51e823a6 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -201,7 +201,7 @@ module ActionController
# With conditions you can define restrictions on routes. Currently the only valid condition is <tt>:method</tt>.
#
# * <tt>:method</tt> - Allows you to specify which method can access the route. Possible values are <tt>:post</tt>,
- # <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>. The default value is <tt>:any</tt>,
+ # <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>. The default value is <tt>:any</tt>,
# <tt>:any</tt> means that any method can access the route.
#
# Example:
@@ -213,7 +213,7 @@ module ActionController
#
# Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
# URL will route to the <tt>show</tt> action.
- #
+ #
# == Reloading routes
#
# You can reload routes if you feel you must:
@@ -281,9 +281,9 @@ module ActionController
end
class << self
- # Expects an array of controller names as the first argument.
- # Executes the passed block with only the named controllers named available.
- # This method is used in internal Rails testing.
+ # Expects an array of controller names as the first argument.
+ # Executes the passed block with only the named controllers named available.
+ # This method is used in internal Rails testing.
def with_controllers(names)
prior_controllers = @possible_controllers
use_controllers! names
@@ -292,10 +292,10 @@ module ActionController
use_controllers! prior_controllers
end
- # Returns an array of paths, cleaned of double-slashes and relative path references.
- # * "\\\" and "//" become "\\" or "/".
- # * "/foo/bar/../config" becomes "/foo/config".
- # The returned array is sorted by length, descending.
+ # Returns an array of paths, cleaned of double-slashes and relative path references.
+ # * "\\\" and "//" become "\\" or "/".
+ # * "/foo/bar/../config" becomes "/foo/config".
+ # The returned array is sorted by length, descending.
def normalize_paths(paths)
# do the hokey-pokey of path normalization...
paths = paths.collect do |path|
@@ -314,7 +314,7 @@ module ActionController
paths = paths.uniq.sort_by { |path| - path.length }
end
- # Returns the array of controller names currently available to ActionController::Routing.
+ # Returns the array of controller names currently available to ActionController::Routing.
def possible_controllers
unless @possible_controllers
@possible_controllers = []
@@ -339,28 +339,27 @@ module ActionController
@possible_controllers
end
- # Replaces the internal list of controllers available to ActionController::Routing with the passed argument.
- # ActionController::Routing.use_controllers!([ "posts", "comments", "admin/comments" ])
+ # Replaces the internal list of controllers available to ActionController::Routing with the passed argument.
+ # ActionController::Routing.use_controllers!([ "posts", "comments", "admin/comments" ])
def use_controllers!(controller_names)
@possible_controllers = controller_names
end
- # Returns a controller path for a new +controller+ based on a +previous+ controller path.
- # Handles 4 scenarios:
- #
- # * stay in the previous controller:
- # controller_relative_to( nil, "groups/discussion" ) # => "groups/discussion"
- #
- # * stay in the previous namespace:
- # controller_relative_to( "posts", "groups/discussion" ) # => "groups/posts"
- #
- # * forced move to the root namespace:
- # controller_relative_to( "/posts", "groups/discussion" ) # => "posts"
- #
- # * previous namespace is root:
- # controller_relative_to( "posts", "anything_with_no_slashes" ) # =>"posts"
- #
-
+ # Returns a controller path for a new +controller+ based on a +previous+ controller path.
+ # Handles 4 scenarios:
+ #
+ # * stay in the previous controller:
+ # controller_relative_to( nil, "groups/discussion" ) # => "groups/discussion"
+ #
+ # * stay in the previous namespace:
+ # controller_relative_to( "posts", "groups/discussion" ) # => "groups/posts"
+ #
+ # * forced move to the root namespace:
+ # controller_relative_to( "/posts", "groups/discussion" ) # => "posts"
+ #
+ # * previous namespace is root:
+ # controller_relative_to( "posts", "anything_with_no_slashes" ) # =>"posts"
+ #
def controller_relative_to(controller, previous)
if controller.nil? then previous
elsif controller[0] == ?/ then controller[1..-1]
@@ -369,12 +368,11 @@ module ActionController
end
end
end
-
Routes = RouteSet.new
ActiveSupport::Inflector.module_eval do
- # Ensures that routes are reloaded when Rails inflections are updated.
+ # Ensures that routes are reloaded when Rails inflections are updated.
def inflections_with_route_reloading(&block)
returning(inflections_without_route_reloading(&block)) {
ActionController::Routing::Routes.reload! if block_given?
diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb
index 912999d845..03427e41de 100644
--- a/actionpack/lib/action_controller/routing/builder.rb
+++ b/actionpack/lib/action_controller/routing/builder.rb
@@ -48,14 +48,10 @@ module ActionController
end
when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true)
when /\A\?(.*?)\?/
- returning segment = StaticSegment.new($1) do
- segment.is_optional = true
- end
+ StaticSegment.new($1, :optional => true)
when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1)
when Regexp.new(separator_pattern) then
- returning segment = DividerSegment.new($&) do
- segment.is_optional = (optional_separators.include? $&)
- end
+ DividerSegment.new($&, :optional => (optional_separators.include? $&))
end
[segment, $~.post_match]
end
@@ -176,29 +172,16 @@ module ActionController
defaults, requirements, conditions = divide_route_options(segments, options)
requirements = assign_route_options(segments, defaults, requirements)
- route = Route.new
-
- route.segments = segments
- route.requirements = requirements
- route.conditions = conditions
+ # TODO: Segments should be frozen on initialize
+ segments.each { |segment| segment.freeze }
- if !route.significant_keys.include?(:action) && !route.requirements[:action]
- route.requirements[:action] = "index"
- route.significant_keys << :action
- end
-
- # Routes cannot use the current string interpolation method
- # if there are user-supplied <tt>:requirements</tt> as the interpolation
- # code won't raise RoutingErrors when generating
- if options.key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION
- route.optimise = false
- end
+ route = Route.new(segments, requirements, conditions)
if !route.significant_keys.include?(:controller)
raise ArgumentError, "Illegal route: the :controller must be specified!"
end
- route
+ route.freeze
end
private
diff --git a/actionpack/lib/action_controller/routing/optimisations.rb b/actionpack/lib/action_controller/routing/optimisations.rb
index 4b70ea13f2..0fe836606c 100644
--- a/actionpack/lib/action_controller/routing/optimisations.rb
+++ b/actionpack/lib/action_controller/routing/optimisations.rb
@@ -1,14 +1,14 @@
module ActionController
module Routing
- # Much of the slow performance from routes comes from the
+ # Much of the slow performance from routes comes from the
# complexity of expiry, <tt>:requirements</tt> matching, defaults providing
- # and figuring out which url pattern to use. With named routes
- # we can avoid the expense of finding the right route. So if
+ # and figuring out which url pattern to use. With named routes
+ # we can avoid the expense of finding the right route. So if
# they've provided the right number of arguments, and have no
# <tt>:requirements</tt>, we can just build up a string and return it.
- #
- # To support building optimisations for other common cases, the
- # generation code is separated into several classes
+ #
+ # To support building optimisations for other common cases, the
+ # generation code is separated into several classes
module Optimisation
def generate_optimisation_block(route, kind)
return "" unless route.optimise?
@@ -20,6 +20,7 @@ module ActionController
class Optimiser
attr_reader :route, :kind
+
def initialize(route, kind)
@route = route
@kind = kind
@@ -53,12 +54,12 @@ module ActionController
# map.person '/people/:id'
#
# If the user calls <tt>person_url(@person)</tt>, we can simply
- # return a string like "/people/#{@person.to_param}"
+ # return a string like "/people/#{@person.to_param}"
# rather than triggering the expensive logic in +url_for+.
class PositionalArguments < Optimiser
def guard_condition
number_of_arguments = route.segment_keys.size
- # if they're using foo_url(:id=>2) it's one
+ # if they're using foo_url(:id=>2) it's one
# argument, but we don't want to generate /foos/id2
if number_of_arguments == 1
"(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
@@ -94,14 +95,14 @@ module ActionController
end
# This case is mostly the same as the positional arguments case
- # above, but it supports additional query parameters as the last
+ # above, but it supports additional query parameters as the last
# argument
class PositionalArgumentsWithAdditionalParams < PositionalArguments
def guard_condition
"(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
end
- # This case uses almost the same code as positional arguments,
+ # This case uses almost the same code as positional arguments,
# but add an args.last.to_query on the end
def generation_code
super.insert(-2, '?#{args.last.to_query}')
@@ -110,7 +111,7 @@ module ActionController
# To avoid generating "http://localhost/?host=foo.example.com" we
# can't use this optimisation on routes without any segments
def applicable?
- super && route.segment_keys.size > 0
+ super && route.segment_keys.size > 0
end
end
diff --git a/actionpack/lib/action_controller/routing/recognition_optimisation.rb b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
index cf8f5232c1..6d54d0334c 100644
--- a/actionpack/lib/action_controller/routing/recognition_optimisation.rb
+++ b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
@@ -51,7 +51,6 @@ module ActionController
# 3) segm test for /users/:id
# (jump to list index = 5)
# 4) full test for /users/:id => here we are!
-
class RouteSet
def recognize_path(path, environment={})
result = recognize_optimized(path, environment) and return result
@@ -68,28 +67,6 @@ module ActionController
end
end
- def recognize_optimized(path, env)
- write_recognize_optimized
- recognize_optimized(path, env)
- end
-
- def write_recognize_optimized
- tree = segment_tree(routes)
- body = generate_code(tree)
- instance_eval %{
- def recognize_optimized(path, env)
- segments = to_plain_segments(path)
- index = #{body}
- return nil unless index
- while index < routes.size
- result = routes[index].recognize(path, env) and return result
- index += 1
- end
- nil
- end
- }, __FILE__, __LINE__
- end
-
def segment_tree(routes)
tree = [0]
@@ -153,6 +130,23 @@ module ActionController
segments
end
+ private
+ def write_recognize_optimized!
+ tree = segment_tree(routes)
+ body = generate_code(tree)
+ instance_eval %{
+ def recognize_optimized(path, env)
+ segments = to_plain_segments(path)
+ index = #{body}
+ return nil unless index
+ while index < routes.size
+ result = routes[index].recognize(path, env) and return result
+ index += 1
+ end
+ nil
+ end
+ }, __FILE__, __LINE__
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb
index a0d108ba03..2106ac09e0 100644
--- a/actionpack/lib/action_controller/routing/route.rb
+++ b/actionpack/lib/action_controller/routing/route.rb
@@ -3,11 +3,25 @@ module ActionController
class Route #:nodoc:
attr_accessor :segments, :requirements, :conditions, :optimise
- def initialize
- @segments = []
- @requirements = {}
- @conditions = {}
- @optimise = true
+ def initialize(segments = [], requirements = {}, conditions = {})
+ @segments = segments
+ @requirements = requirements
+ @conditions = conditions
+
+ if !significant_keys.include?(:action) && !requirements[:action]
+ @requirements[:action] = "index"
+ @significant_keys << :action
+ end
+
+ # Routes cannot use the current string interpolation method
+ # if there are user-supplied <tt>:requirements</tt> as the interpolation
+ # code won't raise RoutingErrors when generating
+ has_requirements = @segments.detect { |segment| segment.respond_to?(:regexp) && segment.regexp }
+ if has_requirements || @requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION
+ @optimise = false
+ else
+ @optimise = true
+ end
end
# Indicates whether the routes should be optimised with the string interpolation
@@ -22,129 +36,6 @@ module ActionController
end.compact
end
- # Write and compile a +generate+ method for this Route.
- def write_generation
- # Build the main body of the generation
- body = "expired = false\n#{generation_extraction}\n#{generation_structure}"
-
- # If we have conditions that must be tested first, nest the body inside an if
- body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements
- args = "options, hash, expire_on = {}"
-
- # Nest the body inside of a def block, and then compile it.
- raw_method = method_decl = "def generate_raw(#{args})\npath = begin\n#{body}\nend\n[path, hash]\nend"
- instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
-
- # expire_on.keys == recall.keys; in other words, the keys in the expire_on hash
- # are the same as the keys that were recalled from the previous request. Thus,
- # we can use the expire_on.keys to determine which keys ought to be used to build
- # the query string. (Never use keys from the recalled request when building the
- # query string.)
-
- method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
- instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
-
- method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
- instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
- raw_method
- end
-
- # Build several lines of code that extract values from the options hash. If any
- # of the values are missing or rejected then a return will be executed.
- def generation_extraction
- segments.collect do |segment|
- segment.extraction_code
- end.compact * "\n"
- end
-
- # Produce a condition expression that will check the requirements of this route
- # upon generation.
- def generation_requirements
- requirement_conditions = requirements.collect do |key, req|
- if req.is_a? Regexp
- value_regexp = Regexp.new "\\A#{req.to_s}\\Z"
- "hash[:#{key}] && #{value_regexp.inspect} =~ options[:#{key}]"
- else
- "hash[:#{key}] == #{req.inspect}"
- end
- end
- requirement_conditions * ' && ' unless requirement_conditions.empty?
- end
-
- def generation_structure
- segments.last.string_structure segments[0..-2]
- end
-
- # Write and compile a +recognize+ method for this Route.
- def write_recognition
- # Create an if structure to extract the params from a match if it occurs.
- body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams"
- body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend"
-
- # Build the method declaration and compile it
- method_decl = "def recognize(path, env={})\n#{body}\nend"
- instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
- method_decl
- end
-
- # Plugins may override this method to add other conditions, like checks on
- # host, subdomain, and so forth. Note that changes here only affect route
- # recognition, not generation.
- def recognition_conditions
- result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
- result << "conditions[:method] === env[:method]" if conditions[:method]
- result
- end
-
- # Build the regular expression pattern that will match this route.
- def recognition_pattern(wrap = true)
- pattern = ''
- segments.reverse_each do |segment|
- pattern = segment.build_pattern pattern
- end
- wrap ? ("\\A" + pattern + "\\Z") : pattern
- end
-
- # Write the code to extract the parameters from a matched route.
- def recognition_extraction
- next_capture = 1
- extraction = segments.collect do |segment|
- x = segment.match_extraction(next_capture)
- next_capture += Regexp.new(segment.regexp_chunk).number_of_captures
- x
- end
- extraction.compact
- end
-
- # Write the real generation implementation and then resend the message.
- def generate(options, hash, expire_on = {})
- write_generation
- generate options, hash, expire_on
- end
-
- def generate_extras(options, hash, expire_on = {})
- write_generation
- generate_extras options, hash, expire_on
- end
-
- # Generate the query string with any extra keys in the hash and append
- # it to the given path, returning the new path.
- def append_query_string(path, hash, query_keys=nil)
- return nil unless path
- query_keys ||= extra_keys(hash)
- "#{path}#{build_query_string(hash, query_keys)}"
- end
-
- # Determine which keys in the given hash are "extra". Extra keys are
- # those that were not used to generate a particular route. The extra
- # keys also do not include those recalled from the prior request, nor
- # do they include any keys that were implied in the route (like a
- # <tt>:controller</tt> that is required, but not explicitly used in the
- # text of the route.)
- def extra_keys(hash, recall={})
- (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
- end
-
# Build a query string from the keys of the given hash. If +only_keys+
# is given (as an array), only the keys indicated will be used to build
# the query string. The query string will correctly build array parameter
@@ -161,12 +52,6 @@ module ActionController
elements.empty? ? '' : "?#{elements.sort * '&'}"
end
- # Write the real recognition implementation and then resend the message.
- def recognize(path, environment={})
- write_recognition
- recognize path, environment
- end
-
# A route's parameter shell contains parameter values that are not in the
# route's path, but should be placed in the recognized hash.
#
@@ -186,7 +71,7 @@ module ActionController
# includes keys that appear inside the path, and keys that have requirements
# placed upon them.
def significant_keys
- @significant_keys ||= returning [] do |sk|
+ @significant_keys ||= returning([]) do |sk|
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
sk.concat requirements.keys
sk.uniq!
@@ -209,12 +94,7 @@ module ActionController
end
def matches_controller_and_action?(controller, action)
- unless defined? @matching_prepared
- @controller_requirement = requirement_for(:controller)
- @action_requirement = requirement_for(:action)
- @matching_prepared = true
- end
-
+ prepare_matching!
(@controller_requirement.nil? || @controller_requirement === controller) &&
(@action_requirement.nil? || @action_requirement === action)
end
@@ -226,15 +106,150 @@ module ActionController
end
end
- protected
- def requirement_for(key)
- return requirements[key] if requirements.key? key
- segments.each do |segment|
- return segment.regexp if segment.respond_to?(:key) && segment.key == key
+ # TODO: Route should be prepared and frozen on initialize
+ def freeze
+ unless frozen?
+ write_generation!
+ write_recognition!
+ prepare_matching!
+
+ parameter_shell
+ significant_keys
+ defaults
+ to_s
end
- nil
+
+ super
end
+ private
+ def requirement_for(key)
+ return requirements[key] if requirements.key? key
+ segments.each do |segment|
+ return segment.regexp if segment.respond_to?(:key) && segment.key == key
+ end
+ nil
+ end
+
+ # Write and compile a +generate+ method for this Route.
+ def write_generation!
+ # Build the main body of the generation
+ body = "expired = false\n#{generation_extraction}\n#{generation_structure}"
+
+ # If we have conditions that must be tested first, nest the body inside an if
+ body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements
+ args = "options, hash, expire_on = {}"
+
+ # Nest the body inside of a def block, and then compile it.
+ raw_method = method_decl = "def generate_raw(#{args})\npath = begin\n#{body}\nend\n[path, hash]\nend"
+ instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
+
+ # expire_on.keys == recall.keys; in other words, the keys in the expire_on hash
+ # are the same as the keys that were recalled from the previous request. Thus,
+ # we can use the expire_on.keys to determine which keys ought to be used to build
+ # the query string. (Never use keys from the recalled request when building the
+ # query string.)
+
+ method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
+ instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
+
+ method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
+ instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
+ raw_method
+ end
+
+ # Build several lines of code that extract values from the options hash. If any
+ # of the values are missing or rejected then a return will be executed.
+ def generation_extraction
+ segments.collect do |segment|
+ segment.extraction_code
+ end.compact * "\n"
+ end
+
+ # Produce a condition expression that will check the requirements of this route
+ # upon generation.
+ def generation_requirements
+ requirement_conditions = requirements.collect do |key, req|
+ if req.is_a? Regexp
+ value_regexp = Regexp.new "\\A#{req.to_s}\\Z"
+ "hash[:#{key}] && #{value_regexp.inspect} =~ options[:#{key}]"
+ else
+ "hash[:#{key}] == #{req.inspect}"
+ end
+ end
+ requirement_conditions * ' && ' unless requirement_conditions.empty?
+ end
+
+ def generation_structure
+ segments.last.string_structure segments[0..-2]
+ end
+
+ # Write and compile a +recognize+ method for this Route.
+ def write_recognition!
+ # Create an if structure to extract the params from a match if it occurs.
+ body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams"
+ body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend"
+
+ # Build the method declaration and compile it
+ method_decl = "def recognize(path, env = {})\n#{body}\nend"
+ instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
+ method_decl
+ end
+
+ # Plugins may override this method to add other conditions, like checks on
+ # host, subdomain, and so forth. Note that changes here only affect route
+ # recognition, not generation.
+ def recognition_conditions
+ result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
+ result << "conditions[:method] === env[:method]" if conditions[:method]
+ result
+ end
+
+ # Build the regular expression pattern that will match this route.
+ def recognition_pattern(wrap = true)
+ pattern = ''
+ segments.reverse_each do |segment|
+ pattern = segment.build_pattern pattern
+ end
+ wrap ? ("\\A" + pattern + "\\Z") : pattern
+ end
+
+ # Write the code to extract the parameters from a matched route.
+ def recognition_extraction
+ next_capture = 1
+ extraction = segments.collect do |segment|
+ x = segment.match_extraction(next_capture)
+ next_capture += Regexp.new(segment.regexp_chunk).number_of_captures
+ x
+ end
+ extraction.compact
+ end
+
+ # Generate the query string with any extra keys in the hash and append
+ # it to the given path, returning the new path.
+ def append_query_string(path, hash, query_keys = nil)
+ return nil unless path
+ query_keys ||= extra_keys(hash)
+ "#{path}#{build_query_string(hash, query_keys)}"
+ end
+
+ # Determine which keys in the given hash are "extra". Extra keys are
+ # those that were not used to generate a particular route. The extra
+ # keys also do not include those recalled from the prior request, nor
+ # do they include any keys that were implied in the route (like a
+ # <tt>:controller</tt> that is required, but not explicitly used in the
+ # text of the route.)
+ def extra_keys(hash, recall = {})
+ (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
+ end
+
+ def prepare_matching!
+ unless defined? @matching_prepared
+ @controller_requirement = requirement_for(:controller)
+ @action_requirement = requirement_for(:action)
+ @matching_prepared = true
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index 5bc13cf268..8dfc22f94f 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -1,6 +1,6 @@
module ActionController
module Routing
- class RouteSet #:nodoc:
+ class RouteSet #:nodoc:
# Mapper instances are used to build routes. The object passed to the draw
# block in config/routes.rb is a Mapper instance.
#
@@ -194,6 +194,8 @@ module ActionController
def initialize
self.routes = []
self.named_routes = NamedRouteCollection.new
+
+ write_recognize_optimized!
end
# Subclasses and plugins may override this method to specify a different
@@ -231,7 +233,6 @@ module ActionController
Routing.use_controllers! nil # Clear the controller cache so we may discover new ones
clear!
load_routes!
- install_helpers
end
# reload! will always force a reload whereas load checks the timestamp first
@@ -432,4 +433,4 @@ module ActionController
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/routing/routing_ext.rb b/actionpack/lib/action_controller/routing/routing_ext.rb
index 2ad20ee699..5f4ba90d0c 100644
--- a/actionpack/lib/action_controller/routing/routing_ext.rb
+++ b/actionpack/lib/action_controller/routing/routing_ext.rb
@@ -1,4 +1,3 @@
-
class Object
def to_param
to_s
diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb
index f0ad066bad..75784c3b78 100644
--- a/actionpack/lib/action_controller/routing/segments.rb
+++ b/actionpack/lib/action_controller/routing/segments.rb
@@ -4,11 +4,12 @@ module ActionController
RESERVED_PCHAR = ':@&=+$,;'
UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze
+ # TODO: Convert :is_optional accessor to read only
attr_accessor :is_optional
alias_method :optional?, :is_optional
def initialize
- self.is_optional = false
+ @is_optional = false
end
def extraction_code
@@ -63,12 +64,14 @@ module ActionController
end
class StaticSegment < Segment #:nodoc:
- attr_accessor :value, :raw
+ attr_reader :value, :raw
alias_method :raw?, :raw
- def initialize(value = nil)
+ def initialize(value = nil, options = {})
super()
- self.value = value
+ @value = value
+ @raw = options[:raw] if options.key?(:raw)
+ @is_optional = options[:optional] if options.key?(:optional)
end
def interpolation_chunk
@@ -97,10 +100,8 @@ module ActionController
end
class DividerSegment < StaticSegment #:nodoc:
- def initialize(value = nil)
- super(value)
- self.raw = true
- self.is_optional = true
+ def initialize(value = nil, options = {})
+ super(value, {:raw => true, :optional => true}.merge(options))
end
def optionality_implied?
@@ -109,13 +110,17 @@ module ActionController
end
class DynamicSegment < Segment #:nodoc:
- attr_accessor :key, :default, :regexp
+ attr_reader :key
+
+ # TODO: Convert these accessors to read only
+ attr_accessor :default, :regexp
def initialize(key = nil, options = {})
super()
- self.key = key
- self.default = options[:default] if options.key? :default
- self.is_optional = true if options[:optional] || options.key?(:default)
+ @key = key
+ @default = options[:default] if options.key?(:default)
+ @regexp = options[:regexp] if options.key?(:regexp)
+ @is_optional = true if options[:optional] || options.key?(:default)
end
def to_s
@@ -130,6 +135,7 @@ module ActionController
def extract_value
"#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}"
end
+
def value_check
if default # Then we know it won't be nil
"#{value_regexp.inspect} =~ #{local_name}" if regexp
@@ -141,6 +147,7 @@ module ActionController
"#{local_name} #{"&& #{value_regexp.inspect} =~ #{local_name}" if regexp}"
end
end
+
def expiry_statement
"expired, hash = true, options if !expired && expire_on[:#{key}]"
end
@@ -175,7 +182,7 @@ module ActionController
end
def regexp_chunk
- if regexp
+ if regexp
if regexp_has_modifiers?
"(#{regexp.to_s})"
else
@@ -214,7 +221,6 @@ module ActionController
def regexp_has_modifiers?
regexp.options & (Regexp::IGNORECASE | Regexp::EXTENDED) != 0
end
-
end
class ControllerSegment < DynamicSegment #:nodoc:
diff --git a/actionpack/lib/action_controller/session/drb_server.rb b/actionpack/lib/action_controller/session/drb_server.rb
index 6f90db6747..2caa27f62a 100644..100755
--- a/actionpack/lib/action_controller/session/drb_server.rb
+++ b/actionpack/lib/action_controller/session/drb_server.rb
@@ -1,8 +1,8 @@
-#!/usr/local/bin/ruby -w
-
-# This is a really simple session storage daemon, basically just a hash,
+#!/usr/bin/env ruby
+
+# This is a really simple session storage daemon, basically just a hash,
# which is enabled for DRb access.
-
+
require 'drb'
session_hash = Hash.new
@@ -14,13 +14,13 @@ class <<session_hash
super(key, value)
end
end
-
+
def [](key)
@mutex.synchronize do
super(key)
end
end
-
+
def delete(key)
@mutex.synchronize do
super(key)
@@ -29,4 +29,4 @@ class <<session_hash
end
DRb.start_service('druby://127.0.0.1:9192', session_hash)
-DRb.thread.join \ No newline at end of file
+DRb.thread.join
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index c7a1d40ff2..c7a1d40ff2 100755..100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index bdfb2eebd7..e8ca02d760 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -129,7 +129,7 @@ module ActionView
# label_tag 'name', nil, :class => 'small_label'
# # => <label for="name" class="small_label">Name</label>
def label_tag(name, text = nil, options = {})
- content_tag :label, text || name.humanize, { "for" => name }.update(options.stringify_keys)
+ content_tag :label, text || name.to_s.humanize, { "for" => name }.update(options.stringify_keys)
end
# Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index c4ba7ccc8e..8c1dea2186 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -25,11 +25,11 @@ module ActionView
# => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
number = number.to_s.strip unless number.nil?
- options = options.stringify_keys
- area_code = options["area_code"] || nil
- delimiter = options["delimiter"] || "-"
- extension = options["extension"].to_s.strip || nil
- country_code = options["country_code"] || nil
+ options = options.symbolize_keys
+ area_code = options[:area_code] || nil
+ delimiter = options[:delimiter] || "-"
+ extension = options[:extension].to_s.strip || nil
+ country_code = options[:country_code] || nil
begin
str = ""
@@ -51,10 +51,10 @@ module ActionView
#
# ==== Options
# * <tt>:precision</tt> - Sets the level of precision (defaults to 2).
- # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
+ # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
# * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
- # * <tt>:format</tt> - Sets the format of the output string (defaults to "%u%n"). The field types are:
+ # * <tt>:format</tt> - Sets the format of the output string (defaults to "%u%n"). The field types are:
#
# %u The currency unit
# %n The number
@@ -69,8 +69,11 @@ module ActionView
# number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
- options = options.symbolize_keys
- defaults = I18n.translate(:'currency.format', :locale => options[:locale]) || {}
+ options.symbolize_keys!
+
+ defaults, currency = I18n.translate([:'number.format', :'number.currency.format'],
+ :locale => options[:locale]) || [{},{}]
+ defaults = defaults.merge(currency)
precision = options[:precision] || defaults[:precision]
unit = options[:unit] || defaults[:unit]
@@ -80,8 +83,11 @@ module ActionView
separator = '' if precision == 0
begin
- parts = number_with_precision(number, precision).split('.')
- format.gsub(/%n/, number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s).gsub(/%u/, unit)
+ format.gsub(/%n/, number_with_precision(number,
+ :precision => precision,
+ :delimiter => delimiter,
+ :separator => separator)
+ ).gsub(/%u/, unit)
rescue
number
end
@@ -93,26 +99,29 @@ module ActionView
# ==== Options
# * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
# * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
#
# ==== Examples
- # number_to_percentage(100) # => 100.000%
- # number_to_percentage(100, :precision => 0) # => 100%
- #
- # number_to_percentage(302.24398923423, :precision => 5)
- # # => 302.24399%
+ # number_to_percentage(100) # => 100.000%
+ # number_to_percentage(100, :precision => 0) # => 100%
+ # number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
+ # number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
def number_to_percentage(number, options = {})
- options = options.stringify_keys
- precision = options["precision"] || 3
- separator = options["separator"] || "."
+ options.symbolize_keys!
+
+ defaults, percentage = I18n.translate([:'number.format', :'number.percentage.format'],
+ :locale => options[:locale]) || [{},{}]
+ defaults = defaults.merge(percentage)
+
+ precision = options[:precision] || defaults[:precision]
+ separator = options[:separator] || defaults[:separator]
+ delimiter = options[:delimiter] || defaults[:delimiter]
begin
- number = number_with_precision(number, precision)
- parts = number.split('.')
- if parts.at(1).nil?
- parts[0] + "%"
- else
- parts[0] + separator + parts[1].to_s + "%"
- end
+ number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter) + "%"
rescue
number
end
@@ -136,87 +145,140 @@ module ActionView
# You can still use <tt>number_with_delimiter</tt> with the old API that accepts the
# +delimiter+ as its optional second and the +separator+ as its
# optional third parameter:
- # number_with_delimiter(12345678, " ") # => 12 345.678
- # number_with_delimiter(12345678.05, ".", ",") # => 12.345.678,05
+ # number_with_delimiter(12345678, " ") # => 12 345.678
+ # number_with_delimiter(12345678.05, ".", ",") # => 12.345.678,05
def number_with_delimiter(number, *args)
options = args.extract_options!
+ options.symbolize_keys!
+
+ defaults = I18n.translate(:'number.format', :locale => options[:locale]) || {}
+
unless args.empty?
- options[:delimiter] = args[0] || ","
- options[:separator] = args[1] || "."
+ ActiveSupport::Deprecation.warn('number_with_delimiter takes an option hash ' +
+ 'instead of separate delimiter and precision arguments.', caller)
+ delimiter = args[0] || defaults[:delimiter]
+ separator = args[1] || defaults[:separator]
end
- options.reverse_merge!(:delimiter => ",", :separator => ".")
+
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
+ separator ||= (options[:separator] || defaults[:separator])
begin
parts = number.to_s.split('.')
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
- parts.join options[:separator]
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
+ parts.join(separator)
rescue
number
end
end
# Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision of 2).
- # The default level of precision is 3.
+ # You can customize the format in the +options+ hash.
+ #
+ # ==== Options
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
#
# ==== Examples
# number_with_precision(111.2345) # => 111.235
# number_with_precision(111.2345, :precision => 2) # => 111.23
# number_with_precision(13, :precision => 5) # => 13.00000
# number_with_precision(389.32314, :precision => 0) # => 389
+ # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
+ # # => 1.111,23
#
# You can still use <tt>number_with_precision</tt> with the old API that accepts the
# +precision+ as its optional second parameter:
# number_with_precision(number_with_precision(111.2345, 2) # => 111.23
def number_with_precision(number, *args)
options = args.extract_options!
+ options.symbolize_keys!
+
+ defaults, precision_defaults = I18n.translate([:'number.format', :'number.precision.format'],
+ :locale => options[:locale]) || [{},{}]
+ defaults = defaults.merge(precision_defaults)
+
unless args.empty?
- options[:precision] = args[0] || 3
+ ActiveSupport::Deprecation.warn('number_with_precision takes an option hash ' +
+ 'instead of a separate precision argument.', caller)
+ precision = args[0] || defaults[:precision]
end
- options.reverse_merge!(:precision => 3)
- "%01.#{options[:precision]}f" %
- ((Float(number) * (10 ** options[:precision])).round.to_f / 10 ** options[:precision])
+
+ precision ||= (options[:precision] || defaults[:precision])
+ separator ||= (options[:separator] || defaults[:separator])
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
+
+ rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
+ number_with_delimiter("%01.#{precision}f" % rounded_number,
+ :separator => separator,
+ :delimiter => delimiter)
rescue
number
end
+ STORAGE_UNITS = %w( Bytes KB MB GB TB ).freeze
+
# Formats the bytes in +size+ into a more understandable representation
# (e.g., giving it 1500 yields 1.5 KB). This method is useful for
# reporting file sizes to users. This method returns nil if
- # +size+ cannot be converted into a number. You can change the default
- # precision of 1 using the precision parameter <tt>:precision</tt>.
+ # +size+ cannot be converted into a number. You can customize the
+ # format in the +options+ hash.
+ #
+ # ==== Options
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 1).
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
#
# ==== Examples
- # number_to_human_size(123) # => 123 Bytes
- # number_to_human_size(1234) # => 1.2 KB
- # number_to_human_size(12345) # => 12.1 KB
- # number_to_human_size(1234567) # => 1.2 MB
- # number_to_human_size(1234567890) # => 1.1 GB
- # number_to_human_size(1234567890123) # => 1.1 TB
- # number_to_human_size(1234567, :precision => 2) # => 1.18 MB
- # number_to_human_size(483989, :precision => 0) # => 473 KB
+ # number_to_human_size(123) # => 123 Bytes
+ # number_to_human_size(1234) # => 1.2 KB
+ # number_to_human_size(12345) # => 12.1 KB
+ # number_to_human_size(1234567) # => 1.2 MB
+ # number_to_human_size(1234567890) # => 1.1 GB
+ # number_to_human_size(1234567890123) # => 1.1 TB
+ # number_to_human_size(1234567, :precision => 2) # => 1.18 MB
+ # number_to_human_size(483989, :precision => 0) # => 473 KB
+ # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
#
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the
# +precision+ as its optional second parameter:
# number_to_human_size(1234567, 2) # => 1.18 MB
# number_to_human_size(483989, 0) # => 473 KB
- def number_to_human_size(size, *args)
+ def number_to_human_size(number, *args)
+ return number.nil? ? nil : pluralize(number.to_i, "Byte") if number.to_i < 1024
+
options = args.extract_options!
+ options.symbolize_keys!
+
+ defaults, human = I18n.translate([:'number.format', :'number.human.format'],
+ :locale => options[:locale]) || [{},{}]
+ defaults = defaults.merge(human)
+
unless args.empty?
- options[:precision] = args[0] || 1
+ ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' +
+ 'instead of a separate precision argument.', caller)
+ precision = args[0] || defaults[:precision]
end
- options.reverse_merge!(:precision => 1)
-
- size = Float(size)
- case
- when size.to_i == 1; "1 Byte"
- when size < 1.kilobyte; "%d Bytes" % size
- when size < 1.megabyte; "%.#{options[:precision]}f KB" % (size / 1.0.kilobyte)
- when size < 1.gigabyte; "%.#{options[:precision]}f MB" % (size / 1.0.megabyte)
- when size < 1.terabyte; "%.#{options[:precision]}f GB" % (size / 1.0.gigabyte)
- else "%.#{options[:precision]}f TB" % (size / 1.0.terabyte)
- end.sub(/([0-9]\.\d*?)0+ /, '\1 ' ).sub(/\. /,' ')
+
+ precision ||= (options[:precision] || defaults[:precision])
+ separator ||= (options[:separator] || defaults[:separator])
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
+
+ max_exp = STORAGE_UNITS.size - 1
+ number = Float(number)
+ exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
+ number /= 1024 ** exponent
+ unit = STORAGE_UNITS[exponent]
+
+ number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter
+ ).sub(/(\d)(#{Regexp.escape(separator)}[1-9]*)?0+\z/, '\1') + " #{unit}"
rescue
- nil
+ number
end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index cb4b53a9f7..4c3a8311a5 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -111,7 +111,7 @@ module ActionView
(100..599).to_a)
AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
:asynchronous, :method, :insertion, :position,
- :form, :with, :update, :script ]).merge(CALLBACKS)
+ :form, :with, :update, :script, :type ]).merge(CALLBACKS)
end
# Returns a link to a remote action defined by <tt>options[:url]</tt>
@@ -608,7 +608,7 @@ module ActionView
# Example:
#
# # Generates:
- # # new Insertion.Bottom("list", "<li>Some item</li>");
+ # # new Element.insert("list", { bottom: <li>Some item</li>" });
# # new Effect.Highlight("list");
# # ["status-indicator", "cancel-link"].each(Element.hide);
# update_page do |page|
@@ -741,16 +741,16 @@ module ActionView
#
# # Insert the rendered 'navigation' partial just before the DOM
# # element with ID 'content'.
- # # Generates: new Insertion.Before("content", "-- Contents of 'navigation' partial --");
+ # # Generates: Element.insert("content", { before: "-- Contents of 'navigation' partial --" });
# page.insert_html :before, 'content', :partial => 'navigation'
#
# # Add a list item to the bottom of the <ul> with ID 'list'.
- # # Generates: new Insertion.Bottom("list", "<li>Last item</li>");
+ # # Generates: Element.insert("list", { bottom: "<li>Last item</li>" });
# page.insert_html :bottom, 'list', '<li>Last item</li>'
#
def insert_html(position, id, *options_for_render)
- insertion = position.to_s.camelize
- call "new Insertion.#{insertion}", id, render(*options_for_render)
+ content = javascript_object_for(render(*options_for_render))
+ record "Element.insert(\"#{id}\", { #{position.to_s.downcase}: #{content} });"
end
# Replaces the inner HTML of the DOM element with the given +id+.
@@ -1054,7 +1054,7 @@ module ActionView
js_options['asynchronous'] = options[:type] != :synchronous
js_options['method'] = method_option_to_s(options[:method]) if options[:method]
- js_options['insertion'] = "Insertion.#{options[:position].to_s.camelize}" if options[:position]
+ js_options['insertion'] = options[:position].to_s.downcase if options[:position]
js_options['evalScripts'] = options[:script].nil? || options[:script]
if options[:form]
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 3c9f7230c3..022edf23c8 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -558,7 +558,7 @@ module ActionView
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
- (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))+)?)* # path
+ (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$])))*)* # path
(?:\?[\w\+@%&=.;-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
diff --git a/actionpack/lib/action_view/locale/en-US.rb b/actionpack/lib/action_view/locale/en-US.rb
index 3adb199681..2c3676dca8 100644
--- a/actionpack/lib/action_view/locale/en-US.rb
+++ b/actionpack/lib/action_view/locale/en-US.rb
@@ -14,19 +14,40 @@ I18n.backend.store_translations :'en-US', {
:over_x_years => ['over 1 year', 'over {{count}} years']
}
},
- :currency => {
+ :number => {
:format => {
- :unit => '$',
- :precision => 2,
+ :precision => 3,
:separator => '.',
- :delimiter => ',',
- :format => '%u%n',
+ :delimiter => ','
+ },
+ :currency => {
+ :format => {
+ :unit => '$',
+ :precision => 2,
+ :format => '%u%n'
+ }
+ },
+ :human => {
+ :format => {
+ :precision => 1,
+ :delimiter => ''
+ }
+ },
+ :percentage => {
+ :format => {
+ :delimiter => ''
+ }
+ },
+ :precision => {
+ :format => {
+ :delimiter => ''
+ }
}
},
:active_record => {
:error => {
:header_message => ["1 error prohibited this {{object_name}} from being saved", "{{count}} errors prohibited this {{object_name}} from being saved"],
:message => "There were problems with the following fields:"
- }
- }
+ }
+ }
}
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index a37706faee..d97f963540 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -42,6 +42,7 @@ module ActionView #:nodoc:
end
def [](path)
+ raise "Unloaded view path! #{@path}" unless @loaded
@paths[path]
end
@@ -51,6 +52,7 @@ module ActionView #:nodoc:
def load
reload! unless loaded?
+ self
end
# Rebuild load path directory cache
diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb
index 8ca70f8595..8ca70f8595 100755..100644
--- a/actionpack/test/controller/cgi_test.rb
+++ b/actionpack/test/controller/cgi_test.rb
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index 2f8bf7b6ee..2f8bf7b6ee 100755..100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 84996fd6b1..6cf134c26f 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -67,66 +67,56 @@ class SegmentTest < Test::Unit::TestCase
end
def test_interpolation_statement
- s = ROUTING::StaticSegment.new
- s.value = "Hello"
+ s = ROUTING::StaticSegment.new("Hello")
assert_equal "Hello", eval(s.interpolation_statement([]))
assert_equal "HelloHello", eval(s.interpolation_statement([s]))
- s2 = ROUTING::StaticSegment.new
- s2.value = "-"
+ s2 = ROUTING::StaticSegment.new("-")
assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2]))
- s3 = ROUTING::StaticSegment.new
- s3.value = "World"
+ s3 = ROUTING::StaticSegment.new("World")
assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2]))
end
end
class StaticSegmentTest < Test::Unit::TestCase
def test_interpolation_chunk_should_respect_raw
- s = ROUTING::StaticSegment.new
- s.value = 'Hello World'
- assert ! s.raw?
+ s = ROUTING::StaticSegment.new('Hello World')
+ assert !s.raw?
assert_equal 'Hello%20World', s.interpolation_chunk
- s.raw = true
+ s = ROUTING::StaticSegment.new('Hello World', :raw => true)
assert s.raw?
assert_equal 'Hello World', s.interpolation_chunk
end
def test_regexp_chunk_should_escape_specials
- s = ROUTING::StaticSegment.new
-
- s.value = 'Hello*World'
+ s = ROUTING::StaticSegment.new('Hello*World')
assert_equal 'Hello\*World', s.regexp_chunk
- s.value = 'HelloWorld'
+ s = ROUTING::StaticSegment.new('HelloWorld')
assert_equal 'HelloWorld', s.regexp_chunk
end
def test_regexp_chunk_should_add_question_mark_for_optionals
- s = ROUTING::StaticSegment.new
- s.value = "/"
- s.is_optional = true
+ s = ROUTING::StaticSegment.new("/", :optional => true)
assert_equal "/?", s.regexp_chunk
- s.value = "hello"
+ s = ROUTING::StaticSegment.new("hello", :optional => true)
assert_equal "(?:hello)?", s.regexp_chunk
end
end
class DynamicSegmentTest < Test::Unit::TestCase
- def segment
+ def segment(options = {})
unless @segment
- @segment = ROUTING::DynamicSegment.new
- @segment.key = :a
+ @segment = ROUTING::DynamicSegment.new(:a, options)
end
@segment
end
def test_extract_value
- s = ROUTING::DynamicSegment.new
- s.key = :a
+ s = ROUTING::DynamicSegment.new(:a)
hash = {:a => '10', :b => '20'}
assert_equal '10', eval(s.extract_value)
@@ -149,31 +139,31 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
def test_regexp_value_check_rejects_nil
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
+
a_value = nil
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
end
def test_optional_regexp_value_check_should_accept_nil
- segment.regexp = /\d+/
- segment.is_optional = true
+ segment = segment(:regexp => /\d+/, :optional => true)
+
a_value = nil
assert eval(segment.value_check)
end
def test_regexp_value_check_rejects_no_match
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
a_value = "Hello20World"
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
a_value = "20Hi"
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
end
def test_regexp_value_check_accepts_match
- segment.regexp = /\d+/
-
+ segment = segment(:regexp => /\d+/)
a_value = "30"
assert eval(segment.value_check)
end
@@ -184,14 +174,14 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
def test_optional_value_needs_no_check
- segment.is_optional = true
+ segment = segment(:optional => true)
+
a_value = nil
assert_equal nil, segment.value_check
end
def test_regexp_value_check_should_accept_match_with_default
- segment.regexp = /\d+/
- segment.default = '200'
+ segment = segment(:regexp => /\d+/, :default => '200')
a_value = '100'
assert eval(segment.value_check)
@@ -234,7 +224,7 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
def test_extraction_code_should_return_on_mismatch
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
hash = merged = {:a => 'Hi', :b => '3'}
options = {:b => '3'}
a_value = nil
@@ -292,7 +282,7 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
def test_value_regexp_should_match_exacly
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
assert_no_match segment.value_regexp, "Hello 10 World"
assert_no_match segment.value_regexp, "Hello 10"
assert_no_match segment.value_regexp, "10 World"
@@ -300,40 +290,36 @@ class DynamicSegmentTest < Test::Unit::TestCase
end
def test_regexp_chunk_should_return_string
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
assert_kind_of String, segment.regexp_chunk
end
def test_build_pattern_non_optional_with_no_captures
# Non optional
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /\d+/ #number_of_captures is 0
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /\d+/)
assert_equal "(\\d+)stuff", a_segment.build_pattern('stuff')
end
def test_build_pattern_non_optional_with_captures
# Non optional
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /(\d+)(.*?)/ #number_of_captures is 2
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /(\d+)(.*?)/)
assert_equal "((\\d+)(.*?))stuff", a_segment.build_pattern('stuff')
end
def test_optionality_implied
- a_segment = ROUTING::DynamicSegment.new
- a_segment.key = :id
+ a_segment = ROUTING::DynamicSegment.new(:id)
assert a_segment.optionality_implied?
- a_segment.key = :action
+ a_segment = ROUTING::DynamicSegment.new(:action)
assert a_segment.optionality_implied?
end
def test_modifiers_must_be_handled_sensibly
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /david|jamis/i
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/i)
assert_equal "((?i-mx:david|jamis))stuff", a_segment.build_pattern('stuff')
- a_segment.regexp = /david|jamis/x
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/x)
assert_equal "((?x-mi:david|jamis))stuff", a_segment.build_pattern('stuff')
- a_segment.regexp = /david|jamis/
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/)
assert_equal "(david|jamis)stuff", a_segment.build_pattern('stuff')
end
end
@@ -560,7 +546,7 @@ class RouteBuilderTest < Test::Unit::TestCase
action = segments[-4]
assert_equal :action, action.key
- action.regexp = /show|in/ # Use 'in' to check partial matches
+ segments[-4] = ROUTING::DynamicSegment.new(:action, :regexp => /show|in/)
builder.assign_default_route_options(segments)
@@ -661,10 +647,10 @@ class RoutingTest < Test::Unit::TestCase
ActionController::Routing.controller_paths = []
assert_equal [], ActionController::Routing.possible_controllers
- ActionController::Routing::Routes.load!
ActionController::Routing.controller_paths = [
root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib'
]
+ ActionController::Routing::Routes.load!
assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
ensure
@@ -834,6 +820,7 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
puts "#{1 / per_url} url/s\n\n"
end
end
+
def test_time_generation
n = 5000
if RunTimeTests
@@ -1373,34 +1360,20 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
end
def slash_segment(is_optional = false)
- returning ROUTING::DividerSegment.new('/') do |s|
- s.is_optional = is_optional
- end
+ ROUTING::DividerSegment.new('/', :optional => is_optional)
end
def default_route
unless defined?(@default_route)
- @default_route = ROUTING::Route.new
-
- @default_route.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :controller
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :action
- s.default = 'index'
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :id
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
+ segments = []
+ segments << ROUTING::StaticSegment.new('/', :raw => true)
+ segments << ROUTING::DynamicSegment.new(:controller)
+ segments << slash_segment(:optional)
+ segments << ROUTING::DynamicSegment.new(:action, :default => 'index', :optional => true)
+ segments << slash_segment(:optional)
+ segments << ROUTING::DynamicSegment.new(:id, :optional => true)
+ segments << slash_segment(:optional)
+ @default_route = ROUTING::Route.new(segments).freeze
end
@default_route
end
@@ -1488,29 +1461,16 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
end
def test_significant_keys
- user_url = ROUTING::Route.new
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = 'user'
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
-
- user_url.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :user
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
+ segments = []
+ segments << ROUTING::StaticSegment.new('/', :raw => true)
+ segments << ROUTING::StaticSegment.new('user')
+ segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true)
+ segments << ROUTING::DynamicSegment.new(:user)
+ segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true)
- user_url.requirements = {:controller => 'users', :action => 'show'}
+ requirements = {:controller => 'users', :action => 'show'}
+ user_url = ROUTING::Route.new(segments, requirements)
keys = user_url.significant_keys.sort_by { |k| k.to_s }
assert_equal [:action, :controller, :user], keys
end
diff --git a/actionpack/test/controller/session/cookie_store_test.rb b/actionpack/test/controller/session/cookie_store_test.rb
index 5adaeaf5c5..5adaeaf5c5 100755..100644
--- a/actionpack/test/controller/session/cookie_store_test.rb
+++ b/actionpack/test/controller/session/cookie_store_test.rb
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index b624005a57..58d9ca537f 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -64,7 +64,7 @@ class TestTest < Test::Unit::TestCase
</html>
HTML
end
-
+
def test_xml_output
response.content_type = "application/xml"
render :text => <<XML
@@ -117,8 +117,8 @@ XML
@controller = TestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
- ActionController::Routing::Routes.reload
ActionController::Routing.use_controllers! %w(content admin/user test_test/test)
+ ActionController::Routing::Routes.load_routes!
end
def teardown
@@ -366,7 +366,7 @@ XML
:children => { :count => 1,
:only => { :tag => "img" } } } }
end
-
+
def test_should_not_impose_childless_html_tags_in_xml
process :test_xml_output
@@ -412,7 +412,7 @@ XML
def test_assert_routing_with_method
with_routing do |set|
- set.draw { |map| map.resources(:content) }
+ set.draw { |map| map.resources(:content) }
assert_routing({ :method => 'post', :path => 'content' }, { :controller => 'content', :action => 'create' })
end
end
@@ -486,7 +486,7 @@ XML
assert_nil @request.env['HTTP_X_REQUESTED_WITH']
end
- def test_header_properly_reset_after_get_request
+ def test_header_properly_reset_after_get_request
get :test_params
@request.recycle!
assert_nil @request.instance_variable_get("@request_method")
@@ -532,15 +532,15 @@ XML
assert_equal file.path, file.local_path
assert_equal expected, file.read
end
-
+
def test_test_uploaded_file_with_binary
filename = 'mona_lisa.jpg'
path = "#{FILES_DIR}/#{filename}"
content_type = 'image/png'
-
+
binary_uploaded_file = ActionController::TestUploadedFile.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)
assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read
end
@@ -549,10 +549,10 @@ XML
filename = 'mona_lisa.jpg'
path = "#{FILES_DIR}/#{filename}"
content_type = 'image/jpg'
-
+
binary_file_upload = fixture_file_upload(path, content_type, :binary)
assert_equal File.open(path, READ_BINARY).read, binary_file_upload.read
-
+
plain_file_upload = fixture_file_upload(path, content_type)
assert_equal File.open(path, READ_PLAIN).read, plain_file_upload.read
end
@@ -584,7 +584,7 @@ XML
get :test_send_file
assert_nothing_raised(NoMethodError) { @response.binary_content }
end
-
+
protected
def with_foo_routing
with_routing do |set|
@@ -597,7 +597,6 @@ XML
end
end
-
class CleanBacktraceTest < Test::Unit::TestCase
def test_should_reraise_the_same_object
exception = Test::Unit::AssertionFailedError.new('message')
@@ -658,7 +657,7 @@ end
class NamedRoutesControllerTest < ActionController::TestCase
tests ContentController
-
+
def test_should_be_able_to_use_named_routes_before_a_request_is_done
with_routing do |set|
set.draw { |map| map.resources :contents }
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index d8c07e731b..d8c07e731b 100755..100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 4e4102aec7..9b41ff8179 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -190,6 +190,12 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
+ def test_label_tag_with_symbol
+ actual = label_tag :title
+ expected = %(<label for="title">Title</label>)
+ assert_dom_equal expected, actual
+ end
+
def test_label_tag_with_text
actual = label_tag "title", "My Title"
expected = %(<label for="title">My Title</label>)
diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb
index 50c20c3627..ce0da398cc 100644
--- a/actionpack/test/template/number_helper_i18n_test.rb
+++ b/actionpack/test/template/number_helper_i18n_test.rb
@@ -2,17 +2,53 @@ require 'abstract_unit'
class NumberHelperI18nTests < Test::Unit::TestCase
include ActionView::Helpers::NumberHelper
-
+
attr_reader :request
+
uses_mocha 'number_helper_i18n_tests' do
def setup
- @defaults = {:separator => ".", :unit => "$", :format => "%u%n", :delimiter => ",", :precision => 2}
- I18n.backend.store_translations 'en-US', :currency => {:format => @defaults}
+ @number_defaults = { :precision => 3, :delimiter => ',', :separator => '.' }
+ @currency_defaults = { :unit => '$', :format => '%u%n', :precision => 2 }
+ @human_defaults = { :precision => 1 }
+ @percentage_defaults = { :delimiter => '' }
+ @precision_defaults = { :delimiter => '' }
+
+ I18n.backend.store_translations 'en-US', :number => { :format => @number_defaults,
+ :currency => { :format => @currency_defaults }, :human => @human_defaults }
end
def test_number_to_currency_translates_currency_formats
- I18n.expects(:translate).with(:'currency.format', :locale => 'en-US').returns @defaults
+ I18n.expects(:translate).with(
+ [:'number.format', :'number.currency.format'], :locale => 'en-US'
+ ).returns([@number_defaults, @currency_defaults])
number_to_currency(1, :locale => 'en-US')
end
+
+ def test_number_with_precision_translates_number_formats
+ I18n.expects(:translate).with(
+ [:'number.format', :'number.precision.format'], :locale => 'en-US'
+ ).returns([@number_defaults, @precision_defaults])
+ number_with_precision(1, :locale => 'en-US')
+ end
+
+ def test_number_with_delimiter_translates_number_formats
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US').returns(@number_defaults)
+ number_with_delimiter(1, :locale => 'en-US')
+ end
+
+ def test_number_to_percentage_translates_number_formats
+ I18n.expects(:translate).with(
+ [:'number.format', :'number.percentage.format'], :locale => 'en-US'
+ ).returns([@number_defaults, @percentage_defaults])
+ number_to_percentage(1, :locale => 'en-US')
+ end
+
+ def test_number_to_human_size_translates_human_formats
+ I18n.expects(:translate).with(
+ [:'number.format', :'number.human.format'], :locale => 'en-US'
+ ).returns([@number_defaults, @human_defaults])
+ # can't be called with 1 because this directly returns without calling I18n.translate
+ number_to_human_size(1025, :locale => 'en-US')
+ end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index bff349a754..9c9f54936c 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -26,7 +26,8 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("&pound;1234567890,50", number_to_currency(1234567890.50, {:unit => "&pound;", :separator => ",", :delimiter => ""}))
assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50"))
assert_equal("1,234,567,890.50 K&#269;", number_to_currency("1234567890.50", {:unit => "K&#269;", :format => "%n %u"}))
- assert_equal("$x.", number_to_currency("x"))
+ #assert_equal("$x.", number_to_currency("x")) # fails due to API consolidation
+ assert_equal("$x", number_to_currency("x"))
assert_nil number_to_currency(nil)
end
@@ -35,7 +36,9 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("100%", number_to_percentage(100, {:precision => 0}))
assert_equal("302.06%", number_to_percentage(302.0574, {:precision => 2}))
assert_equal("100.000%", number_to_percentage("100"))
+ assert_equal("1000.000%", number_to_percentage("1000"))
assert_equal("x%", number_to_percentage("x"))
+ assert_equal("1.000,000%", number_to_percentage(1000, :delimiter => '.', :separator => ','))
assert_nil number_to_percentage(nil)
end
@@ -63,28 +66,22 @@ class NumberHelperTest < ActionView::TestCase
def test_number_with_precision
assert_equal("111.235", number_with_precision(111.2346))
- assert_equal("31.83", number_with_precision(31.825, 2))
- assert_equal("111.23", number_with_precision(111.2346, 2))
- assert_equal("111.00", number_with_precision(111, 2))
+ assert_equal("31.83", number_with_precision(31.825, :precision => 2))
+ assert_equal("111.23", number_with_precision(111.2346, :precision => 2))
+ assert_equal("111.00", number_with_precision(111, :precision => 2))
assert_equal("111.235", number_with_precision("111.2346"))
- assert_equal("31.83", number_with_precision("31.825", 2))
- assert_equal("112", number_with_precision(111.50, 0))
- assert_equal("1234567892", number_with_precision(1234567891.50, 0))
+ assert_equal("31.83", number_with_precision("31.825", :precision => 2))
+ assert_equal("112", number_with_precision(111.50, :precision => 0))
+ assert_equal("1234567892", number_with_precision(1234567891.50, :precision => 0))
# Return non-numeric params unchanged.
assert_equal("x", number_with_precision("x"))
assert_nil number_with_precision(nil)
end
- def test_number_with_precision_with_options_hash
- assert_equal '111.235', number_with_precision(111.2346)
- assert_equal '31.83', number_with_precision(31.825, :precision => 2)
- assert_equal '111.23', number_with_precision(111.2346, :precision => 2)
- assert_equal '111.00', number_with_precision(111, :precision => 2)
- assert_equal '111.235', number_with_precision("111.2346")
- assert_equal '31.83', number_with_precision("31.825", :precision => 2)
- assert_equal '112', number_with_precision(111.50, :precision => 0)
- assert_equal '1234567892', number_with_precision(1234567891.50, :precision => 0)
+ def test_number_with_precision_with_custom_delimiter_and_separator
+ assert_equal '31,83', number_with_precision(31.825, :precision => 2, :separator => ',')
+ assert_equal '1.231,83', number_with_precision(1231.825, :precision => 2, :separator => ',', :delimiter => '.')
end
def test_number_to_human_size
@@ -98,18 +95,19 @@ class NumberHelperTest < ActionView::TestCase
assert_equal '1.2 MB', number_to_human_size(1234567)
assert_equal '1.1 GB', number_to_human_size(1234567890)
assert_equal '1.1 TB', number_to_human_size(1234567890123)
+ assert_equal '1025 TB', number_to_human_size(1025.terabytes)
assert_equal '444 KB', number_to_human_size(444.kilobytes)
assert_equal '1023 MB', number_to_human_size(1023.megabytes)
assert_equal '3 TB', number_to_human_size(3.terabytes)
- assert_equal '1.18 MB', number_to_human_size(1234567, 2)
- assert_equal '3 Bytes', number_to_human_size(3.14159265, 4)
+ assert_equal '1.18 MB', number_to_human_size(1234567, :precision => 2)
+ assert_equal '3 Bytes', number_to_human_size(3.14159265, :precision => 4)
assert_equal("123 Bytes", number_to_human_size("123"))
- assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, 2)
- assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, 4)
- assert_equal '10 KB', number_to_human_size(10.000.kilobytes, 4)
+ assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2)
+ assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4)
+ assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4)
assert_equal '1 Byte', number_to_human_size(1.1)
assert_equal '10 Bytes', number_to_human_size(10)
- assert_nil number_to_human_size('x')
+ #assert_nil number_to_human_size('x') # fails due to API consolidation
assert_nil number_to_human_size(nil)
end
@@ -120,4 +118,10 @@ class NumberHelperTest < ActionView::TestCase
assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4)
assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4)
end
+
+ def test_number_to_human_size_with_custom_delimiter_and_separator
+ assert_equal '1,01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2, :separator => ',')
+ assert_equal '1,01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4, :separator => ',')
+ assert_equal '1.000,1 TB', number_to_human_size(1000.1.terabytes, :delimiter => '.', :separator => ',')
+ end
end
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index 92cc85703b..abc9f930dd 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -77,6 +77,8 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous)
end
def test_link_to_remote_html_options
@@ -287,13 +289,13 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
end
def test_insert_html_with_string
- assert_equal 'new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
+ assert_equal 'Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });',
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
- assert_equal 'new Insertion.Bottom("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
+ assert_equal 'Element.insert("element", { bottom: "\\u003Cp\u003EThis is a test\\u003C/p\u003E" });',
@generator.insert_html(:bottom, 'element', '<p>This is a test</p>')
- assert_equal 'new Insertion.Before("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
+ assert_equal 'Element.insert("element", { before: "\\u003Cp\u003EThis is a test\\u003C/p\u003E" });',
@generator.insert_html(:before, 'element', '<p>This is a test</p>')
- assert_equal 'new Insertion.After("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
+ assert_equal 'Element.insert("element", { after: "\\u003Cp\u003EThis is a test\\u003C/p\u003E" });',
@generator.insert_html(:after, 'element', '<p>This is a test</p>')
end
@@ -366,8 +368,8 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
@generator.replace_html('baz', '<p>This is a test</p>')
assert_equal <<-EOS.chomp, @generator.to_s
-new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
-new Insertion.Bottom("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
+Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });
+Element.insert("element", { bottom: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });
["foo", "bar"].each(Element.remove);
Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
EOS
@@ -429,6 +431,8 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
def test_sortable
assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
@generator.sortable('blah', :url => { :action => "order" })
+ assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:false, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
+ @generator.sortable('blah', :url => { :action => "order" }, :type => :synchronous)
end
def test_draggable
@@ -439,6 +443,8 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
def test_drop_receiving
assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
@generator.drop_receiving('blah', :url => { :action => "order" })
+ assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:false, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
+ @generator.drop_receiving('blah', :url => { :action => "order" }, :type => :synchronous)
end
def test_collection_first_and_last
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 4b60f8d682..4b60f8d682 100644..100755
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
diff --git a/activerecord/README b/activerecord/README
index d68eb28a64..d68eb28a64 100755..100644
--- a/activerecord/README
+++ b/activerecord/README
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 983528aff7..983528aff7 100755..100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 17a7949959..17a7949959 100755..100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 4e33dfe69f..4e33dfe69f 100755..100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 7c28cbdd07..7c28cbdd07 100755..100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
index d8146daa54..d8146daa54 100755..100644
--- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index fdc0fa52c9..fdc0fa52c9 100755..100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 9cb64223e2..29c2995334 100755..100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -122,6 +122,10 @@ module ActiveRecord #:nodoc:
class MissingAttributeError < NoMethodError
end
+ # Raised when unknown attributes are supplied via mass assignment.
+ class UnknownAttributeError < NoMethodError
+ end
+
# Raised when an error occurred while doing a mass assignment to an attribute through the
# <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
# offending attribute.
@@ -2400,7 +2404,11 @@ module ActiveRecord #:nodoc:
attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
attributes.each do |k, v|
- k.include?("(") ? multi_parameter_attributes << [ k, v ] : send(k + "=", v)
+ if k.include?("(")
+ multi_parameter_attributes << [ k, v ]
+ else
+ respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
+ end
end
assign_multiparameter_attributes(multi_parameter_attributes)
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index be2621fdb6..be2621fdb6 100755..100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 5358491cde..aaf9e2e73f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -149,6 +149,10 @@ module ActiveRecord
"INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
end
+ def case_sensitive_equality_operator
+ "="
+ end
+
protected
# Returns an array of record hashes with the column names as keys and
# column values as values.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 47dbf5a5f3..47dbf5a5f3 100755..100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 35b9ed4746..204ebaa2e2 100755..100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -511,6 +511,10 @@ module ActiveRecord
keys.length == 1 ? [keys.first, nil] : nil
end
+ def case_sensitive_equality_operator
+ "= BINARY"
+ end
+
private
def connect
@connection.reconnect = true if @connection.respond_to?(:reconnect=)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6a20f41a4b..856435517a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -182,8 +182,8 @@ module ActiveRecord
def self.extract_value_from_default(default)
case default
# Numeric types
- when /\A-?\d+(\.\d*)?\z/
- default
+ when /\A\(?(-?\d+(\.\d*)?\)?)\z/
+ $1
# Character types
when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
$1
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 622cfc3c3f..622cfc3c3f 100755..100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index b957ee3b9e..e7a9676394 100755..100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -625,13 +625,25 @@ module ActiveRecord
# class (which has a database table to query from).
finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? }
- if value.nil? || (configuration[:case_sensitive] || !finder_class.columns_hash[attr_name.to_s].text?)
- condition_sql = "#{record.class.quoted_table_name}.#{attr_name} #{attribute_condition(value)}"
+ is_text_column = finder_class.columns_hash[attr_name.to_s].text?
+
+ if value.nil?
+ comparison_operator = "IS ?"
+ else
+ comparison_operator = "#{connection.case_sensitive_equality_operator} ?"
+
+ if is_text_column
+ value = value.to_s
+ end
+ end
+
+ sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
+
+ if value.nil? || (configuration[:case_sensitive] || !is_text_column)
+ condition_sql = "#{sql_attribute} #{comparison_operator}"
condition_params = [value]
else
- # sqlite has case sensitive SELECT query, while MySQL/Postgresql don't.
- # Hence, this is needed only for sqlite.
- condition_sql = "LOWER(#{record.class.quoted_table_name}.#{attr_name}) #{attribute_condition(value)}"
+ condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
condition_params = [value.downcase]
end
@@ -648,28 +660,10 @@ module ActiveRecord
condition_params << record.send(:id)
end
- results = finder_class.with_exclusive_scope do
- connection.select_all(
- construct_finder_sql(
- :select => "#{connection.quote_column_name(attr_name)}",
- :from => "#{finder_class.quoted_table_name}",
- :conditions => [condition_sql, *condition_params]
- )
- )
- end
-
- unless results.length.zero?
- found = true
-
- # As MySQL/Postgres don't have case sensitive SELECT queries, we try to find duplicate
- # column in ruby when case sensitive option
- if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text?
- found = results.any? { |a| a[attr_name.to_s] == value.to_s }
- end
-
- if found
+ finder_class.with_exclusive_scope do
+ if finder_class.exists?([condition_sql, *condition_params])
message = record.errors.generate_message(attr_name, :taken, :default => configuration[:message])
- record.errors.add(attr_name, message)
+ record.errors.add(attr_name, message)
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 9c718c4fef..9c718c4fef 100755..100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index f8b8b1f96d..47e4b3527d 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1007,7 +1007,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm.clients.create({ :name => 'Some Client' })
stats = Namespaced::Firm.find(firm.id, {
- :select => "#{Namespaced::Firm.table_name}.*, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
+ :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
:joins => :clients,
:group => "#{Namespaced::Firm.table_name}.id"
})
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index be5170f830..d51a3c7e1c 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -2,15 +2,18 @@ require "cases/helper"
require 'models/post'
require 'models/person'
require 'models/reader'
+require 'models/comment'
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
- fixtures :posts, :readers, :people
+ fixtures :posts, :readers, :people, :comments
def test_associate_existing
assert_queries(2) { posts(:thinking);people(:david) }
-
+
+ posts(:thinking).people
+
assert_queries(1) do
- posts(:thinking).people << people(:david)
+ posts(:thinking).people << people(:david)
end
assert_queries(1) do
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 99639849a5..99639849a5 100755..100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 4904feeb7d..4904feeb7d 100755..100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 7999e29264..7999e29264 100755..100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 9e4f268db7..e6d1b5ddfd 100755..100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -904,6 +904,14 @@ class BasicsTest < ActiveRecord::TestCase
assert_nil keyboard.id
end
+ def test_mass_assigning_invalid_attribute
+ firm = Firm.new
+
+ assert_raises(ActiveRecord::UnknownAttributeError) do
+ firm.attributes = { "id" => 5, "type" => "Client", "i_dont_even_exist" => 20 }
+ end
+ end
+
def test_mass_assignment_protection_on_defaults
firm = Firm.new
firm.attributes = { "id" => 5, "type" => "Client" }
diff --git a/activerecord/test/cases/deprecated_finder_test.rb b/activerecord/test/cases/deprecated_finder_test.rb
index 2afc91b769..2afc91b769 100755..100644
--- a/activerecord/test/cases/deprecated_finder_test.rb
+++ b/activerecord/test/cases/deprecated_finder_test.rb
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 6ba7597f56..6ba7597f56 100755..100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 4fd38bfbc9..4fd38bfbc9 100755..100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb
index ab005c6b00..ab005c6b00 100755..100644
--- a/activerecord/test/cases/lifecycle_test.rb
+++ b/activerecord/test/cases/lifecycle_test.rb
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index b921cbdc9c..b921cbdc9c 100755..100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
diff --git a/activerecord/test/cases/unconnected_test.rb b/activerecord/test/cases/unconnected_test.rb
index 23ad10f3f9..23ad10f3f9 100755..100644
--- a/activerecord/test/cases/unconnected_test.rb
+++ b/activerecord/test/cases/unconnected_test.rb
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index 4b2d28c80b..4b2d28c80b 100755..100644
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index cd435948a1..cd435948a1 100755..100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb
index 812bc1f535..812bc1f535 100755..100644
--- a/activerecord/test/models/reply.rb
+++ b/activerecord/test/models/reply.rb
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index 39ca1bf42a..39ca1bf42a 100755..100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
diff --git a/activesupport/lib/active_support/basic_object.rb b/activesupport/lib/active_support/basic_object.rb
index e06da79d26..1f77209e7f 100644
--- a/activesupport/lib/active_support/basic_object.rb
+++ b/activesupport/lib/active_support/basic_object.rb
@@ -7,7 +7,7 @@
# barebones base class that emulates Builder::BlankSlate while still relying on
# Ruby 1.9's BasicObject in Ruby 1.9.
module ActiveSupport
- if RUBY_VERSION >= '1.9'
+ if defined? ::BasicObject
class BasicObject < ::BasicObject
undef_method :==
undef_method :equal?
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 67b0a580ea..cedc1afe7f 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -39,7 +39,7 @@ module ActiveSupport
@level = level
@buffer = []
@auto_flushing = 1
- @no_block = false
+ @guard = Mutex.new
if log.respond_to?(:write)
@log = log
@@ -54,19 +54,15 @@ module ActiveSupport
end
end
- def set_non_blocking_io
- if !RUBY_PLATFORM.match(/java|mswin/) && !(@log == STDOUT) && @log.respond_to?(:write_nonblock)
- @no_block = true
- end
- end
-
def add(severity, message = nil, progname = nil, &block)
return if @level > severity
message = (message || (block && block.call) || progname).to_s
# If a newline is necessary then create a new message ending with a newline.
# Ensures that the original message is not mutated.
message = "#{message}\n" unless message[-1] == ?\n
- buffer << message
+ @guard.synchronize do
+ buffer << message
+ end
auto_flush
message
end
@@ -98,11 +94,11 @@ module ActiveSupport
end
def flush
- unless buffer.empty?
- if @no_block
- @log.write_nonblock(buffer.slice!(0..-1).join)
- else
- @log.write(buffer.slice!(0..-1).join)
+ @guard.synchronize do
+ unless buffer.empty?
+ old_buffer = @buffer
+ @buffer = []
+ @log.write(old_buffer.join)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb
index df37afb053..dd1484f8fa 100644
--- a/activesupport/lib/active_support/core_ext/array/grouping.rb
+++ b/activesupport/lib/active_support/core_ext/array/grouping.rb
@@ -19,7 +19,7 @@ module ActiveSupport #:nodoc:
# %w(1 2 3).in_groups_of(2, false) {|g| p g}
# ["1", "2"]
# ["3"]
- def in_groups_of(number, fill_with = nil, &block)
+ def in_groups_of(number, fill_with = nil)
if fill_with == false
collection = self
else
@@ -31,7 +31,7 @@ module ActiveSupport #:nodoc:
end
if block_given?
- collection.each_slice(number, &block)
+ collection.each_slice(number) { |slice| yield(slice) }
else
returning [] do |groups|
collection.each_slice(number) { |group| groups << group }
@@ -87,11 +87,11 @@ module ActiveSupport #:nodoc:
#
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
- def split(value = nil, &block)
- block ||= Proc.new { |e| e == value }
+ def split(value = nil)
+ using_block = block_given?
inject([[]]) do |results, element|
- if block.call(element)
+ if (using_block && yield(element)) || (value == element)
results << []
else
results.last << element
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 21636b8af4..23dd96e4df 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -11,10 +11,9 @@ module ActiveSupport
def freeze_with_memoizable
methods.each do |method|
- if m = method.to_s.match(/^_unmemoized_(.*)/)
- send(m[1])
- end
- end
+ __send__($1) if method.to_s =~ /^_unmemoized_(.*)/
+ end unless frozen?
+
freeze_without_memoizable
end
end
diff --git a/activesupport/lib/active_support/multibyte/generators/generate_tables.rb b/activesupport/lib/active_support/multibyte/generators/generate_tables.rb
index 7f807585c5..7f807585c5 100644..100755
--- a/activesupport/lib/active_support/multibyte/generators/generate_tables.rb
+++ b/activesupport/lib/active_support/multibyte/generators/generate_tables.rb
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index 71d6f4d9c6..70a7f84023 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -72,13 +72,13 @@ module ActiveSupport
protected
def run_warmup
- 5.times { GC.start }
+ GC.start
time = Metrics::Time.new
run_test(time, :benchmark)
puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
- 5.times { GC.start }
+ GC.start
end
def run_profile(metric)
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 5ff1867568..6df7c568dc 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Turn cache_classes on by default [Josh Peek]
+
* Added configurable eager load paths. Defaults to app/models, app/controllers, and app/helpers [Josh Peek]
* Introduce simple internationalization support. [Ruby i18n team]
diff --git a/railties/bin/about b/railties/bin/about
index ed8deb0dfc..ed8deb0dfc 100644..100755
--- a/railties/bin/about
+++ b/railties/bin/about
diff --git a/railties/bin/console b/railties/bin/console
index 498077ab33..498077ab33 100644..100755
--- a/railties/bin/console
+++ b/railties/bin/console
diff --git a/railties/bin/destroy b/railties/bin/destroy
index a4df765a39..a4df765a39 100644..100755
--- a/railties/bin/destroy
+++ b/railties/bin/destroy
diff --git a/railties/bin/generate b/railties/bin/generate
index 173a9f147d..173a9f147d 100644..100755
--- a/railties/bin/generate
+++ b/railties/bin/generate
diff --git a/railties/bin/performance/benchmarker b/railties/bin/performance/benchmarker
index c842d35d33..c842d35d33 100644..100755
--- a/railties/bin/performance/benchmarker
+++ b/railties/bin/performance/benchmarker
diff --git a/railties/bin/performance/profiler b/railties/bin/performance/profiler
index d855ac8b13..d855ac8b13 100644..100755
--- a/railties/bin/performance/profiler
+++ b/railties/bin/performance/profiler
diff --git a/railties/bin/performance/request b/railties/bin/performance/request
index ae3f38c74b..ae3f38c74b 100644..100755
--- a/railties/bin/performance/request
+++ b/railties/bin/performance/request
diff --git a/railties/bin/plugin b/railties/bin/plugin
index 87cd2070fe..87cd2070fe 100644..100755
--- a/railties/bin/plugin
+++ b/railties/bin/plugin
diff --git a/railties/bin/process/inspector b/railties/bin/process/inspector
index bf25ad86d1..bf25ad86d1 100644..100755
--- a/railties/bin/process/inspector
+++ b/railties/bin/process/inspector
diff --git a/railties/bin/process/reaper b/railties/bin/process/reaper
index c77f04535f..c77f04535f 100644..100755
--- a/railties/bin/process/reaper
+++ b/railties/bin/process/reaper
diff --git a/railties/bin/process/spawner b/railties/bin/process/spawner
index 7118f3983c..7118f3983c 100644..100755
--- a/railties/bin/process/spawner
+++ b/railties/bin/process/spawner
diff --git a/railties/bin/runner b/railties/bin/runner
index a4a7cb25ba..a4a7cb25ba 100644..100755
--- a/railties/bin/runner
+++ b/railties/bin/runner
diff --git a/railties/bin/server b/railties/bin/server
index 3c67f39b69..3c67f39b69 100644..100755
--- a/railties/bin/server
+++ b/railties/bin/server
diff --git a/railties/configs/apache.conf b/railties/configs/apache.conf
index d9d211c058..d9d211c058 100755..100644
--- a/railties/configs/apache.conf
+++ b/railties/configs/apache.conf
diff --git a/railties/dispatches/dispatch.fcgi b/railties/dispatches/dispatch.fcgi
index 65188f380b..664dbbbee8 100755
--- a/railties/dispatches/dispatch.fcgi
+++ b/railties/dispatches/dispatch.fcgi
@@ -1,4 +1,4 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
#
# You may specify the path to the FastCGI crash log (a log of unhandled
# exceptions which forced the FastCGI instance to exit, great for debugging)
diff --git a/railties/dispatches/dispatch.rb b/railties/dispatches/dispatch.rb
index 9b5ae760ff..32fa3b2665 100755
--- a/railties/dispatches/dispatch.rb
+++ b/railties/dispatches/dispatch.rb
@@ -1,4 +1,4 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
@@ -7,4 +7,4 @@ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
-Dispatcher.dispatch \ No newline at end of file
+Dispatcher.dispatch
diff --git a/railties/dispatches/gateway.cgi b/railties/dispatches/gateway.cgi
index fb1fa22f04..0305b7f810 100644..100755
--- a/railties/dispatches/gateway.cgi
+++ b/railties/dispatches/gateway.cgi
@@ -1,4 +1,4 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require 'drb'
@@ -94,4 +94,4 @@ end
$stdout.write output
$stdout.flush
-$stdout.close \ No newline at end of file
+$stdout.close
diff --git a/railties/lib/commands/dbconsole.rb b/railties/lib/commands/dbconsole.rb
index 17acb7b68f..442526ae32 100644
--- a/railties/lib/commands/dbconsole.rb
+++ b/railties/lib/commands/dbconsole.rb
@@ -41,6 +41,8 @@ when "mysql"
if config['password'] && include_password
args << "--password=#{config['password']}"
+ elsif config['password'] && !config['password'].empty?
+ args << "-p"
end
args << config['database']
diff --git a/railties/lib/commands/ncgi/listener b/railties/lib/commands/ncgi/listener
index 421c453f23..7079ef78a6 100644..100755
--- a/railties/lib/commands/ncgi/listener
+++ b/railties/lib/commands/ncgi/listener
@@ -1,4 +1,4 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require 'stringio'
require 'fileutils'
@@ -83,4 +83,4 @@ end
socket_path = ARGV.shift
timeout = (ARGV.shift || 90).to_i
-Listener.new(timeout, socket_path) \ No newline at end of file
+Listener.new(timeout, socket_path)
diff --git a/railties/lib/commands/ncgi/tracker b/railties/lib/commands/ncgi/tracker
index 859c9fa0e0..4ca12d779b 100644..100755
--- a/railties/lib/commands/ncgi/tracker
+++ b/railties/lib/commands/ncgi/tracker
@@ -1,4 +1,4 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require 'drb'
require 'thread'
@@ -66,4 +66,4 @@ end
socket_path = ARGV.shift
instances = ARGV.shift.to_i
t = Tracker.new(instances, socket_path)
-t.background(ARGV.first ? ARGV.shift.to_i : 90) \ No newline at end of file
+t.background(ARGV.first ? ARGV.shift.to_i : 90)
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index 32411e8928..a2d08e2938 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -349,8 +349,9 @@ Run `rake gems:install` to install the missing gems.
def load_application_classes
if configuration.cache_classes
configuration.eager_load_paths.each do |load_path|
- Dir.glob("#{load_path}/*.rb").each do |file|
- require_dependency file
+ matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
+ Dir.glob("#{load_path}/**/*.rb").each do |file|
+ require_dependency file.sub(matcher, '\1')
end
end
end
@@ -408,7 +409,6 @@ Run `rake gems:install` to install the missing gems.
logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
if configuration.environment == "production"
logger.auto_flushing = false
- logger.set_non_blocking_io
end
rescue StandardError => e
logger = ActiveSupport::BufferedLogger.new(STDERR)
@@ -524,6 +524,7 @@ Run `rake gems:install` to install the missing gems.
end
def prepare_dispatcher
+ return unless configuration.frameworks.include?(:action_controller)
require 'dispatcher' unless defined?(::Dispatcher)
Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare_dispatch
@@ -767,6 +768,7 @@ Run `rake gems:install` to install the missing gems.
# contents of the file are processed via ERB before being sent through
# YAML::load.
def database_configuration
+ require 'erb'
YAML::load(ERB.new(IO.read(database_configuration_file)).result)
end
@@ -902,7 +904,7 @@ Run `rake gems:install` to install the missing gems.
end
def default_cache_classes
- false
+ true
end
def default_whiny_nils
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile b/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile
index 1824fb10fe..1824fb10fe 100755..100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile
+++ b/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile