Merge branch 'master' of github.com:rails/rails

This commit is contained in:
wycats
2010-04-26 23:32:30 -07:00
89 changed files with 820 additions and 824 deletions

View File

@@ -866,7 +866,6 @@ EOF
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
assert_match(/#{regex}/, mail.encoded)
string = "Foo áëô îü"
string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
assert_match(string, mail.subject)
end
@@ -875,7 +874,6 @@ EOF
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
assert_match(/#{regex}/, mail.encoded)
string = "Foo áëô îü"
string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
assert_match(string, mail.subject)
end

View File

@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* Renamed the field error CSS class from fieldWithErrors to field_with_errors for consistency. [Jeremy Kemper]
* Add support for shorthand routes like /projects/status(.:format) #4423 [Diego Carrion]
* Changed translate helper so that it doesnt mark every translation as safe HTML. Only keys with a "_html" suffix and keys named "html" are considered to be safe HTML. All other translations are left untouched. [Craig Davey]

View File

@@ -12,7 +12,6 @@ require 'active_support/i18n'
module AbstractController
extend ActiveSupport::Autoload
autoload :Assigns
autoload :Base
autoload :Callbacks
autoload :Collector

View File

@@ -1,21 +0,0 @@
module AbstractController
module Assigns
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
# :api: public
def view_assigns
hash = {}
variables = instance_variable_names
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
variables.each { |name| hash[name] = instance_variable_get(name) }
hash
end
# This method assigns the hash specified in _assigns_hash to the given object.
# :api: private
# TODO Ideally, this should be done on AV::Base.new initialization.
def _evaluate_assigns(object)
view_assigns.each { |k,v| object.instance_variable_set(k, v) }
end
end
end

View File

@@ -1,4 +1,4 @@
require 'active_support/ordered_options'
require 'active_support/configurable'
module AbstractController
class Error < StandardError; end
@@ -8,6 +8,8 @@ module AbstractController
attr_internal :response_body
attr_internal :action_name
include ActiveSupport::Configurable
class << self
attr_reader :abstract
alias_method :abstract?, :abstract
@@ -29,14 +31,6 @@ module AbstractController
@descendants ||= []
end
def config
@config ||= ActiveSupport::InheritableOptions.new(superclass < Base ? superclass.config : {})
end
def configure
yield config
end
# A list of all internal methods for a controller. This finds the first
# abstract superclass of a controller, and gets a list of all public
# instance methods on that abstract class. Public instance methods of
@@ -99,10 +93,6 @@ module AbstractController
abstract!
def config
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
end
# Calls the action going through the entire action dispatch stack.
#
# The actual method that is called is determined by calling
@@ -133,6 +123,7 @@ module AbstractController
end
private
# Returns true if the name can be considered an action. This can
# be overridden in subclasses to modify the semantics of what
# can be considered an action.

View File

@@ -8,7 +8,6 @@ module AbstractController
included do
class_attribute :_helpers
delegate :_helpers, :to => :'self.class'
self._helpers = Module.new
end

View File

@@ -6,7 +6,7 @@ module AbstractController
extend ActiveSupport::Concern
included do
cattr_accessor :logger
config_accessor :logger
extend ActiveSupport::Benchmarkable
end
end

View File

@@ -65,8 +65,11 @@ module ActionController
@subclasses ||= []
end
# TODO Move this to the appropriate module
config_accessor :assets_dir, :asset_path, :javascripts_dir, :stylesheets_dir
ActiveSupport.run_load_hooks(:action_controller, self)
end
end
require "action_controller/deprecated/base"
require "action_controller/deprecated/base"

View File

@@ -63,12 +63,10 @@ module ActionController #:nodoc:
included do
extend ConfigMethods
delegate :perform_caching, :perform_caching=, :to => :config
singleton_class.delegate :perform_caching, :perform_caching=, :to => :config
self.perform_caching = true
config_accessor :perform_caching
self.perform_caching = true if perform_caching.nil?
end
def caching_allowed?
request.get? && response.status == 200
end

View File

@@ -44,8 +44,8 @@ module ActionController #:nodoc:
# For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>Rails.root + "/public"</tt>). Changing
# this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
# web server to look in the new location for cached files.
singleton_class.delegate :page_cache_directory, :page_cache_directory=, :to => :config
self.page_cache_directory = ''
config_accessor :page_cache_directory
self.page_cache_directory ||= ''
##
# :singleton-method:
@@ -53,8 +53,8 @@ module ActionController #:nodoc:
# order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
# If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
# extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
singleton_class.delegate :page_cache_extension, :page_cache_extension=, :to => :config
self.page_cache_extension = '.html'
config_accessor :page_cache_extension
self.page_cache_extension ||= '.html'
end
module ClassMethods

View File

@@ -1,33 +1,16 @@
module ActionController
class Base
class << self
def deprecated_config_accessor(option, message = nil)
deprecated_config_reader(option, message)
deprecated_config_writer(option, message)
# Deprecated methods. Wrap them in a module so they can be overwritten by plugins
# (like the verify method.)
module DeprecatedBehavior #:nodoc:
def relative_url_root
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root is ineffective. " <<
"Please stop using it.", caller
end
def deprecated_config_reader(option, message = nil)
message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \
"Please read it from config.#{option}"
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{option}
ActiveSupport::Deprecation.warn #{message.inspect}, caller
config.#{option}
end
RUBY
end
def deprecated_config_writer(option, message = nil)
message ||= "Setting #{option} directly on ActionController::Base is deprecated. " \
"Please set it on config.action_controller.#{option}"
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{option}=(val)
ActiveSupport::Deprecation.warn #{message.inspect}, caller
config.#{option} = val
end
RUBY
def relative_url_root=
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root= is ineffective. " <<
"Please stop using it.", caller
end
def consider_all_requests_local
@@ -125,9 +108,7 @@ module ActionController
def use_accept_header=(val)
use_accept_header
end
end
module DeprecatedBehavior
# This method has been moved to ActionDispatch::Request.filter_parameters
def filter_parameter_logging(*args, &block)
ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller)
@@ -146,17 +127,6 @@ module ActionController
extend DeprecatedBehavior
deprecated_config_writer :session_options
deprecated_config_writer :session_store
deprecated_config_accessor :assets_dir
deprecated_config_accessor :asset_path
deprecated_config_accessor :helpers_path
deprecated_config_accessor :javascripts_dir
deprecated_config_accessor :page_cache_directory
deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
deprecated_config_accessor :stylesheets_dir
delegate :consider_all_requests_local, :consider_all_requests_local=,
:allow_concurrency, :allow_concurrency=, :to => :"self.class"
end

View File

@@ -21,8 +21,8 @@ module ActionController
delegate :default_charset=, :to => "ActionDispatch::Response"
end
# cattr_reader :protected_instance_variables
cattr_accessor :protected_instance_variables
# TODO: Update protected instance variables list
config_accessor :protected_instance_variables
self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render
@variables_added @request_origin @url
@parent_controller @action_name

View File

@@ -52,8 +52,8 @@ module ActionController
include AbstractController::Helpers
included do
class_attribute :helpers_path
self.helpers_path = []
config_accessor :helpers_path
self.helpers_path ||= []
end
module ClassMethods

View File

@@ -79,12 +79,12 @@ module ActionController
add :js do |js, options|
self.content_type ||= Mime::JS
self.response_body = js.respond_to?(:to_js) ? js.to_js : js
self.response_body = js.respond_to?(:to_js) ? js.to_js(options) : js
end
add :xml do |xml, options|
self.content_type ||= Mime::XML
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
end
add :update do |proc, options|

View File

@@ -4,6 +4,45 @@ module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
# web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
# requests are checked, so this will not protect your XML API (presumably you'll have a different
# authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
# include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
#
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
# * http://isc.sans.org/diary.html?storyid=1750
# * http://en.wikipedia.org/wiki/Cross-site_request_forgery
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
#
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
module RequestForgeryProtection
extend ActiveSupport::Concern
@@ -12,54 +51,17 @@ module ActionController #:nodoc:
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
# sets it to <tt>:authenticity_token</tt> by default.
config.request_forgery_protection_token ||= :authenticity_token
config_accessor :request_forgery_protection_token
self.request_forgery_protection_token ||= :authenticity_token
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
config.allow_forgery_protection ||= true
config_accessor :allow_forgery_protection
self.allow_forgery_protection = true if allow_forgery_protection.nil?
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
# web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
# requests are checked, so this will not protect your XML API (presumably you'll have a different
# authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
# include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
#
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
# * http://isc.sans.org/diary.html?storyid=1750
# * http://en.wikipedia.org/wiki/Cross-site_request_forgery
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
#
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
module ClassMethods
# Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
#
@@ -79,22 +81,6 @@ module ActionController #:nodoc:
self.request_forgery_protection_token ||= :authenticity_token
before_filter :verify_authenticity_token, options
end
def request_forgery_protection_token
config.request_forgery_protection_token
end
def request_forgery_protection_token=(val)
config.request_forgery_protection_token = val
end
def allow_forgery_protection
config.allow_forgery_protection
end
def allow_forgery_protection=(val)
config.allow_forgery_protection = val
end
end
protected
@@ -104,22 +90,6 @@ module ActionController #:nodoc:
before_filter :verify_authenticity_token, options
end
def request_forgery_protection_token
config.request_forgery_protection_token
end
def request_forgery_protection_token=(val)
config.request_forgery_protection_token = val
end
def allow_forgery_protection
config.allow_forgery_protection
end
def allow_forgery_protection=(val)
config.allow_forgery_protection = val
end
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
verified_request? || raise(ActionController::InvalidAuthenticityToken)
@@ -146,7 +116,7 @@ module ActionController #:nodoc:
end
def protect_against_forgery?
config.allow_forgery_protection
allow_forgery_protection
end
end
end

View File

@@ -13,64 +13,51 @@ module ActionController
class Railtie < Rails::Railtie
config.action_controller = ActiveSupport::OrderedOptions.new
ad = config.action_dispatch
config.action_controller.singleton_class.send(:define_method, :session) do
ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
"renamed to config.action_dispatch.session.", caller
ad.session
end
config.action_controller.singleton_class.tap do |d|
d.send(:define_method, :session) do
ActiveSupport::Deprecation.warn "config.action_controller.session has been deprecated. " <<
"Please use Rails.application.config.session_store instead.", caller
end
config.action_controller.singleton_class.send(:define_method, :session=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
"renamed to config.action_dispatch.session.", caller
ad.session = val
end
d.send(:define_method, :session=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session= has been deprecated. " <<
"Please use config.session_store(name, options) instead.", caller
end
config.action_controller.singleton_class.send(:define_method, :session_store) do
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
"renamed to config.action_dispatch.session_store.", caller
ad.session_store
end
d.send(:define_method, :session_store) do
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been deprecated. " <<
"Please use Rails.application.config.session_store instead.", caller
end
config.action_controller.singleton_class.send(:define_method, :session_store=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
"renamed to config.action_dispatch.session_store.", caller
ad.session_store = val
d.send(:define_method, :session_store=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session_store= has been deprecated. " <<
"Please use config.session_store(name, options) instead.", caller
end
end
log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
initializer "action_controller.logger" do
ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
end
initializer "action_controller.page_cache_directory" do
ActiveSupport.on_load(:action_controller) do
self.page_cache_directory = Rails.public_path
end
end
initializer "action_controller.set_configs" do |app|
paths = app.config.paths
ac = app.config.action_controller
ac.assets_dir = paths.public.to_a.first
ac.javascripts_dir = paths.public.javascripts.to_a.first
ac.stylesheets_dir = paths.public.stylesheets.to_a.first
ac.assets_dir ||= paths.public.to_a.first
ac.javascripts_dir ||= paths.public.javascripts.to_a.first
ac.stylesheets_dir ||= paths.public.stylesheets.to_a.first
ac.page_cache_directory ||= paths.public.to_a.first
ac.helpers_path ||= paths.app.helpers.to_a
ActiveSupport.on_load(:action_controller) do
self.config.merge!(ac)
end
end
initializer "action_controller.initialize_framework_caches" do
ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
initializer "action_controller.logger" do
ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
end
initializer "action_controller.set_helpers_path" do |app|
ActiveSupport.on_load(:action_controller) do
self.helpers_path = app.config.paths.app.helpers.to_a
end
initializer "action_controller.initialize_framework_caches" do
ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
end
initializer "action_controller.url_helpers" do |app|

View File

@@ -36,6 +36,7 @@ module ActionController
end
def teardown_subscriptions
ActiveSupport::Notifications.unsubscribe("action_view.render_template")
ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
end
@@ -282,82 +283,161 @@ module ActionController
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
include ActionDispatch::TestProcess
include ActionController::TemplateAssertions
module Behavior
extend ActiveSupport::Concern
include ActionDispatch::TestProcess
attr_reader :response, :request
attr_reader :response, :request
# Executes a request simulating GET HTTP method and set/volley the response
def get(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "GET")
end
module ClassMethods
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "POST")
end
# Sets the controller class name. Useful if the name can't be inferred from test class.
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
def tests(controller_class)
self.controller_class = controller_class
end
def controller_class=(new_class)
prepare_controller_class(new_class) if new_class
write_inheritable_attribute(:controller_class, new_class)
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "PUT")
end
def controller_class
if current_controller_class = read_inheritable_attribute(:controller_class)
current_controller_class
else
self.controller_class = determine_default_controller_class(name)
end
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "DELETE")
end
def determine_default_controller_class(name)
name.sub(/Test$/, '').constantize
rescue NameError
nil
end
# Executes a request simulating HEAD HTTP method and set/volley the response
def head(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "HEAD")
end
def prepare_controller_class(new_class)
new_class.send :include, ActionController::TestCase::RaiseActionExceptions
end
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
returning __send__(request_method, action, parameters, session, flash) do
@request.env.delete 'HTTP_X_REQUESTED_WITH'
@request.env.delete 'HTTP_ACCEPT'
end
end
alias xhr :xml_http_request
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
# Sanity check for required instance variables so we can give an
# understandable error message.
%w(@routes @controller @request @response).each do |iv_name|
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
# Executes a request simulating GET HTTP method and set/volley the response
def get(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "DELETE")
end
# Executes a request simulating HEAD HTTP method and set/volley the response
def head(action, parameters = nil, session = nil, flash = nil)
process(action, parameters, session, flash, "HEAD")
end
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
returning __send__(request_method, action, parameters, session, flash) do
@request.env.delete 'HTTP_X_REQUESTED_WITH'
@request.env.delete 'HTTP_ACCEPT'
end
end
alias xhr :xml_http_request
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
# Sanity check for required instance variables so we can give an
# understandable error message.
%w(@routes @controller @request @response).each do |iv_name|
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
end
end
@request.recycle!
@response.recycle!
@controller.response_body = nil
@controller.formats = nil
@controller.params = nil
@html_document = nil
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = @request.flash.update(flash || {})
@request.session["flash"].sweep
@controller.request = @request
@controller.params.merge!(parameters)
build_request_uri(action, parameters)
Base.class_eval { include Testing }
@controller.process_with_new_base_test(@request, @response)
@request.session.delete('flash') if @request.session['flash'].blank?
@response
end
def setup_controller_request_and_response
@request = TestRequest.new
@response = TestResponse.new
if klass = self.class.controller_class
@controller ||= klass.new rescue nil
end
@request.env.delete('PATH_INFO')
if @controller
@controller.request = @request
@controller.params = {}
end
end
@request.recycle!
@response.recycle!
@controller.response_body = nil
@controller.formats = nil
@controller.params = nil
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
def rescue_action_in_public!
@request.remote_addr = '208.77.188.166' # example.com
end
@html_document = nil
@request.env['REQUEST_METHOD'] = http_method
included do
include ActionController::TemplateAssertions
include ActionDispatch::Assertions
setup :setup_controller_request_and_response
end
parameters ||= {}
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
private
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = @request.flash.update(flash || {})
@request.session["flash"].sweep
def build_request_uri(action, parameters)
unless @request.env["PATH_INFO"]
options = @controller.__send__(:url_options).merge(parameters)
options.update(
:only_path => true,
:action => action,
:relative_url_root => nil,
:_path_segments => @request.symbolized_path_parameters)
@controller.request = @request
@controller.params.merge!(parameters)
build_request_uri(action, parameters)
Base.class_eval { include Testing }
@controller.process_with_new_base_test(@request, @response)
@request.session.delete('flash') if @request.session['flash'].blank?
@response
url, query_string = @routes.url_for(options).split("?", 2)
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
@request.env["PATH_INFO"] = url
@request.env["QUERY_STRING"] = query_string || ""
end
end
end
include ActionDispatch::Assertions
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
# (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
@@ -384,78 +464,6 @@ module ActionController
end
end
setup :setup_controller_request_and_response
@@controller_class = nil
class << self
# Sets the controller class name. Useful if the name can't be inferred from test class.
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
def tests(controller_class)
self.controller_class = controller_class
end
def controller_class=(new_class)
prepare_controller_class(new_class) if new_class
write_inheritable_attribute(:controller_class, new_class)
end
def controller_class
if current_controller_class = read_inheritable_attribute(:controller_class)
current_controller_class
else
self.controller_class = determine_default_controller_class(name)
end
end
def determine_default_controller_class(name)
name.sub(/Test$/, '').constantize
rescue NameError
nil
end
def prepare_controller_class(new_class)
new_class.send :include, RaiseActionExceptions
end
end
def setup_controller_request_and_response
@request = TestRequest.new
@response = TestResponse.new
if klass = self.class.controller_class
@controller ||= klass.new rescue nil
end
@request.env.delete('PATH_INFO')
if @controller
@controller.request = @request
@controller.params = {}
end
end
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
def rescue_action_in_public!
@request.remote_addr = '208.77.188.166' # example.com
end
private
def build_request_uri(action, parameters)
unless @request.env["PATH_INFO"]
options = @controller.__send__(:url_options).merge(parameters)
options.update(
:only_path => true,
:action => action,
:relative_url_root => nil,
:_path_segments => @request.symbolized_path_parameters)
url, query_string = @routes.url_for(options).split("?", 2)
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
@request.env["PATH_INFO"] = url
@request.env["QUERY_STRING"] = query_string || ""
end
end
end
include Behavior
end
end

View File

@@ -128,7 +128,7 @@ module ActionDispatch
when String
options
when nil, Hash
_router.url_for(url_options.merge(options || {}))
_router.url_for(url_options.merge((options || {}).symbolize_keys))
else
polymorphic_url(options)
end

View File

@@ -6,7 +6,7 @@ require 'active_support/core_ext/object/blank'
module ActionView
ActiveSupport.on_load(:action_view) do
class ActionView::Base
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
cattr_accessor :field_error_proc
end
end

View File

@@ -102,7 +102,7 @@ module ActionView
escape = true
options
when Hash
options = { :only_path => options[:host].nil? }.update(options.to_hash.symbolize_keys)
options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
escape = options.key?(:escape) ? options.delete(:escape) : false
super
when :back

View File

@@ -31,8 +31,8 @@ module ActionView
include ActionController::PolymorphicRoutes
include ActionController::RecordIdentifier
include AbstractController::Helpers
include ActionView::Helpers
include ActionController::Helpers
class_inheritable_accessor :helper_class
attr_accessor :controller, :output_buffer, :rendered

View File

@@ -143,6 +143,12 @@ class BasicController
end
end
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
setup do
@routes = SharedTestRoutes
end
end
class ActionController::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
@@ -275,4 +281,4 @@ module ActionController
class Base
include SharedTestRoutes.url_helpers
end
end
end

View File

@@ -1,3 +1,4 @@
# encoding: utf-8
#--
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
# Under MIT and/or CC By license.
@@ -347,7 +348,6 @@ class AssertSelectTest < ActionController::TestCase
assert_select str, :text => "\343\203\201\343\202\261\343\203\203\343\203\210"
assert_select str, "\343\203\201\343\202\261\343\203\203\343\203\210"
if str.respond_to?(:force_encoding)
str.force_encoding(Encoding::UTF_8)
assert_select str, /\343\203\201..\343\203\210/u
assert_raise(Assertion) { assert_select str, /\343\203\201.\343\203\210/u }
else

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'rbconfig'
# The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
# method has access to the view_paths array when looking for a layout to automatically assign.
@@ -209,7 +210,7 @@ class LayoutStatusIsRenderedTest < ActionController::TestCase
end
end
unless RUBY_PLATFORM =~ /mswin|mingw/
unless Config::CONFIG['host_os'] =~ /mswin|mingw/
class LayoutSymlinkedTest < LayoutTest
layout "symlinked/symlinked_layout"
end

View File

@@ -3,6 +3,14 @@ require 'controller/fake_models'
require 'pathname'
class RenderJsonTest < ActionController::TestCase
class JsonRenderable
def as_json(options={})
hash = { :a => :b, :c => :d, :e => :f }
hash.except!(*options[:except]) if options[:except]
hash
end
end
class TestController < ActionController::Base
protect_from_forgery
@@ -37,6 +45,10 @@ class RenderJsonTest < ActionController::TestCase
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
def render_json_with_extra_options
render :json => JsonRenderable.new, :except => [:c, :e]
end
end
tests TestController
@@ -91,4 +103,10 @@ class RenderJsonTest < ActionController::TestCase
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_forwards_extra_options
get :render_json_with_extra_options
assert_equal '{"a":"b"}', @response.body
assert_equal 'application/json', @response.content_type
end
end

View File

@@ -3,6 +3,13 @@ require 'controller/fake_models'
require 'pathname'
class RenderXmlTest < ActionController::TestCase
class XmlRenderable
def to_xml(options)
options[:root] ||= "i-am-xml"
"<#{options[:root]}/>"
end
end
class TestController < ActionController::Base
protect_from_forgery
@@ -20,13 +27,7 @@ class RenderXmlTest < ActionController::TestCase
end
def render_with_to_xml
to_xmlable = Class.new do
def to_xml
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
render :xml => XmlRenderable.new
end
def formatted_xml_erb
@@ -35,6 +36,10 @@ class RenderXmlTest < ActionController::TestCase
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
def render_xml_with_custom_options
render :xml => XmlRenderable.new, :root => "i-am-THE-xml"
end
end
tests TestController
@@ -58,6 +63,11 @@ class RenderXmlTest < ActionController::TestCase
assert_equal "<i-am-xml/>", @response.body
end
def test_rendering_xml_should_call_to_xml_with_extra_options
get :render_xml_with_custom_options
assert_equal "<i-am-THE-xml/>", @response.body
end
def test_rendering_with_object_location_should_set_header_with_url_for
with_routing do |set|
set.draw do |map|

View File

@@ -25,7 +25,7 @@ class SendFileController < ActionController::Base
end
def multibyte_text_data
send_data("Кирилица\n祝您好運", options)
send_data("Кирилица\n祝您好運.", options)
end
end
@@ -128,7 +128,7 @@ class SendFileTest < ActionController::TestCase
assert_equal 'image/png', @controller.content_type
end
def test_send_file_headers_with_bad_symbol
options = {

View File

@@ -257,10 +257,24 @@ module AbstractController
assert_equal second_class.default_url_options[:host], second_host
end
def test_with_stringified_keys
assert_equal("/c", W.new.url_for('controller' => 'c', 'only_path' => true))
assert_equal("/c/a", W.new.url_for('controller' => 'c', 'action' => 'a', 'only_path' => true))
end
def test_with_hash_with_indifferent_access
W.default_url_options[:controller] = 'd'
W.default_url_options[:only_path] = false
assert_equal("/c", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'only_path' => true)))
W.default_url_options[:action] = 'b'
assert_equal("/c/a", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'action' => 'a', 'only_path' => true)))
end
private
def extract_params(url)
url.split('?', 2).last.split('&').sort
end
end
end
end
end

View File

@@ -237,8 +237,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
AltRoutes = ActionDispatch::Routing::RouteSet.new(AltRequest)
AltRoutes.draw do
get "/" => XHeader.new, :constraints => {:x_header => /HEADER/}
get "/" => AltApp.new
get "/" => TestRoutingMapper::TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/}
get "/" => TestRoutingMapper::TestAltApp::AltApp.new
end
def app
@@ -1000,6 +1000,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
def test_assert_recognizes_account_overview
with_test_routes do
assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview")
end
end
private
def with_test_routes
yield

View File

@@ -27,14 +27,14 @@ class ActiveModelHelperTest < ActionView::TestCase
def test_text_area_with_errors
assert_dom_equal(
%(<div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
%(<div class="field_with_errors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
text_area("post", "body")
)
end
def test_text_field_with_errors
assert_dom_equal(
%(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
text_field("post", "author_name")
)
end
@@ -42,11 +42,11 @@ class ActiveModelHelperTest < ActionView::TestCase
def test_field_error_proc
old_proc = ActionView::Base.field_error_proc
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
%(<div class=\"fieldWithErrors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
%(<div class=\"field_with_errors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
end
assert_dom_equal(
%(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
text_field("post", "author_name")
)
ensure

View File

@@ -3,9 +3,6 @@ require 'abstract_unit'
class FormTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormTagHelper
# include ActiveSupport::Configurable
# DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
def setup
super
@controller = BasicController.new

View File

@@ -1,3 +1,4 @@
# encoding: us-ascii
require 'abstract_unit'
require 'testing_sandbox'
begin

View File

@@ -17,6 +17,7 @@ en:
too_short: "is too short (minimum is {{count}} characters)"
wrong_length: "is the wrong length (should be {{count}} characters)"
not_a_number: "is not a number"
not_an_integer: "must be an integer"
greater_than: "must be greater than {{count}}"
greater_than_or_equal_to: "must be greater than or equal to {{count}}"
equal_to: "must be equal to {{count}}"

View File

@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/slice'
module ActiveModel
module Serializers
@@ -12,8 +13,10 @@ module ActiveModel
class Attribute #:nodoc:
attr_reader :name, :value, :type
def initialize(name, serializable)
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
@raw_value = raw_value || @serializable.send(name)
@type = compute_type
@value = compute_value
end
@@ -51,20 +54,17 @@ module ActiveModel
protected
def compute_type
value = @serializable.send(name)
type = Hash::XML_TYPE_NAMES[value.class.name]
type ||= :string if value.respond_to?(:to_str)
type = Hash::XML_TYPE_NAMES[@raw_value.class.name]
type ||= :string if @raw_value.respond_to?(:to_str)
type ||= :yaml
type
end
def compute_value
value = @serializable.send(name)
if formatter = Hash::XML_FORMATTING[type.to_s]
value ? formatter.call(value) : nil
@raw_value ? formatter.call(@raw_value) : nil
else
value
@raw_value
end
end
end
@@ -72,7 +72,7 @@ module ActiveModel
class MethodAttribute < Attribute #:nodoc:
protected
def compute_type
Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
Hash::XML_TYPE_NAMES[@raw_value.class.name] || :string
end
end
@@ -92,25 +92,24 @@ module ActiveModel
# then because <tt>:except</tt> is set to a default value, the second
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
def serializable_attribute_names
attribute_names = @serializable.attributes.keys.sort
def serializable_attributes_hash
attributes = @serializable.attributes
if options[:only].any?
attribute_names &= options[:only]
attributes.slice(*options[:only])
elsif options[:except].any?
attribute_names -= options[:except]
attributes.except(*options[:except])
else
attributes
end
attribute_names
end
def serializable_attributes
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
serializable_attributes_hash.map { |name, value| self.class::Attribute.new(name, @serializable, value) }
end
def serializable_method_attributes
Array.wrap(options[:methods]).inject([]) do |methods, name|
methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods
end
end

View File

@@ -25,11 +25,18 @@ module ActiveModel
return if options[:allow_nil] && raw_value.nil?
unless value = parse_raw_value(raw_value, options)
unless value = parse_raw_value_as_a_number(raw_value)
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
return
end
if options[:only_integer]
unless value = parse_raw_value_as_an_integer(raw_value)
record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message])
return
end
end
options.slice(*CHECKS.keys).each do |option, option_value|
case option
when :odd, :even
@@ -44,23 +51,23 @@ module ActiveModel
record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
end
end
end
end
end
protected
def parse_raw_value(raw_value, options)
if options[:only_integer]
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
else
begin
Kernel.Float(raw_value)
rescue ArgumentError, TypeError
nil
end
def parse_raw_value_as_a_number(raw_value)
begin
Kernel.Float(raw_value)
rescue ArgumentError, TypeError
nil
end
end
def parse_raw_value_as_an_integer(raw_value)
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
end
end
module ClassMethods

View File

@@ -217,15 +217,15 @@ class I18nValidationTest < ActiveModel::TestCase
def test_validates_numericality_of_only_integer_generates_message
Person.validates_numericality_of :title, :only_integer => true
@person.title = 'a'
@person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
@person.title = '0.0'
@person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil})
@person.valid?
end
def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message
Person.validates_numericality_of :title, :only_integer => true, :message => 'custom'
@person.title = 'a'
@person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
@person.title = '0.0'
@person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'})
@person.valid?
end
@@ -441,20 +441,20 @@ class I18nValidationTest < ActiveModel::TestCase
# validates_numericality_of with :only_integer w/o mocha
def test_validates_numericality_of_only_integer_finds_custom_model_key_translation
I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}}
I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_an_integer => 'custom message'}}}}}}
I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
Person.validates_numericality_of :title, :only_integer => true
@person.title = 'a'
@person.title = '1.0'
@person.valid?
assert_equal ['custom message'], @person.errors[:title]
end
def test_validates_numericality_of_only_integer_finds_global_default_translation
I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
Person.validates_numericality_of :title, :only_integer => true
@person.title = 'a'
@person.title = '1.0'
@person.valid?
assert_equal ['global message'], @person.errors[:title]
end

View File

@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* PostgreSQL: drop support for old postgres driver. Use pg 0.9.0 or later. [Jeremy Kemper]
* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]

View File

@@ -1844,8 +1844,7 @@ module ActiveRecord #:nodoc:
# user.is_admin? # => true
def attributes=(new_attributes, guard_protected_attributes = true)
return if new_attributes.nil?
attributes = new_attributes.dup
attributes.stringify_keys!
attributes = new_attributes.stringify_keys
multi_parameter_attributes = []
attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes

View File

@@ -13,12 +13,12 @@ module ActiveRecord
when String, ActiveSupport::Multibyte::Chars
value = value.to_s
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
"#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
elsif column && [:integer, :float].include?(column.type)
value = column.type == :integer ? value.to_i : value.to_f
value.to_s
else
"#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
"'#{quote_string(value)}'" # ' (for ruby-mode)
end
when NilClass then "NULL"
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
@@ -30,7 +30,7 @@ module ActiveRecord
if value.acts_like?(:date) || value.acts_like?(:time)
"'#{quoted_date(value)}'"
else
"#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
"'#{quote_string(value.to_yaml)}'"
end
end
end
@@ -67,10 +67,6 @@ module ActiveRecord
value
end.to_s(:db)
end
def quoted_string_prefix
''
end
end
end
end

View File

@@ -2,26 +2,12 @@ require 'active_record/connection_adapters/abstract_adapter'
require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/object/blank'
begin
require_library_or_gem 'pg'
rescue LoadError => e
begin
require_library_or_gem 'postgres'
class PGresult
alias_method :nfields, :num_fields unless self.method_defined?(:nfields)
alias_method :ntuples, :num_tuples unless self.method_defined?(:ntuples)
alias_method :ftype, :type unless self.method_defined?(:ftype)
alias_method :cmd_tuples, :cmdtuples unless self.method_defined?(:cmd_tuples)
end
rescue LoadError
raise e
end
end
module ActiveRecord
class Base
# Establishes a connection to the database that's used by all Active Record objects
def self.postgresql_connection(config) # :nodoc:
require 'pg'
config = config.symbolize_keys
host = config[:host]
port = config[:port] || 5432
@@ -277,20 +263,12 @@ module ActiveRecord
true
end
# Does PostgreSQL support standard conforming strings?
def supports_standard_conforming_strings?
# Temporarily set the client message level above error to prevent unintentional
# error messages in the logs when working on a PostgreSQL database server that
# does not support standard conforming strings.
client_min_messages_old = client_min_messages
self.client_min_messages = 'panic'
# postgres-pr does not raise an exception when client_min_messages is set higher
# than error and "SHOW standard_conforming_strings" fails, but returns an empty
# PGresult instead.
has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
self.client_min_messages = client_min_messages_old
has_support
# Enable standard-conforming strings if available.
def set_standard_conforming_strings
old, self.client_min_messages = client_min_messages, 'panic'
execute('SET standard_conforming_strings = on') rescue nil
ensure
self.client_min_messages = old
end
def supports_insert_with_returning?
@@ -314,85 +292,23 @@ module ActiveRecord
# QUOTING ==================================================
# Escapes binary strings for bytea input to the database.
def escape_bytea(original_value)
if @connection.respond_to?(:escape_bytea)
self.class.instance_eval do
define_method(:escape_bytea) do |value|
@connection.escape_bytea(value) if value
end
end
elsif PGconn.respond_to?(:escape_bytea)
self.class.instance_eval do
define_method(:escape_bytea) do |value|
PGconn.escape_bytea(value) if value
end
end
else
self.class.instance_eval do
define_method(:escape_bytea) do |value|
if value
result = ''
value.each_byte { |c| result << sprintf('\\\\%03o', c) }
result
end
end
end
end
escape_bytea(original_value)
def escape_bytea(value)
@connection.escape_bytea(value) if value
end
# Unescapes bytea output from a database to the binary string it represents.
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
# on escaped binary output from database drive.
def unescape_bytea(original_value)
# In each case, check if the value actually is escaped PostgreSQL bytea output
# or an unescaped Active Record attribute that was just written.
if PGconn.respond_to?(:unescape_bytea)
self.class.instance_eval do
define_method(:unescape_bytea) do |value|
if value =~ /\\\d{3}/
PGconn.unescape_bytea(value)
else
value
end
end
end
else
self.class.instance_eval do
define_method(:unescape_bytea) do |value|
if value =~ /\\\d{3}/
result = ''
i, max = 0, value.size
while i < max
char = value[i]
if char == ?\\
if value[i+1] == ?\\
char = ?\\
i += 1
else
char = value[i+1..i+3].oct
i += 3
end
end
result << char
i += 1
end
result
else
value
end
end
end
end
unescape_bytea(original_value)
def unescape_bytea(value)
@connection.unescape_bytea(value) if value
end
# Quotes PostgreSQL-specific data types for SQL input.
def quote(value, column = nil) #:nodoc:
if value.kind_of?(String) && column && column.type == :binary
"#{quoted_string_prefix}'#{escape_bytea(value)}'"
"'#{escape_bytea(value)}'"
elsif value.kind_of?(String) && column && column.sql_type == 'xml'
"xml E'#{quote_string(value)}'"
"xml '#{quote_string(value)}'"
elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
# Not truly string input, so doesn't require (or allow) escape string syntax.
"'#{value.to_s}'"
@@ -408,28 +324,9 @@ module ActiveRecord
end
end
# Quotes strings for use in SQL input in the postgres driver for better performance.
def quote_string(original_value) #:nodoc:
if @connection.respond_to?(:escape)
self.class.instance_eval do
define_method(:quote_string) do |s|
@connection.escape(s)
end
end
elsif PGconn.respond_to?(:escape)
self.class.instance_eval do
define_method(:quote_string) do |s|
PGconn.escape(s)
end
end
else
# There are some incorrectly compiled postgres drivers out there
# that don't define PGconn.escape.
self.class.instance_eval do
remove_method(:quote_string)
end
end
quote_string(original_value)
# Quotes strings for use in SQL input.
def quote_string(s) #:nodoc:
@connection.escape(s)
end
# Checks the following cases:
@@ -1005,22 +902,11 @@ module ActiveRecord
# Ignore async_exec and async_query when using postgres-pr.
@async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
# Use escape string syntax if available. We cannot do this lazily when encountering
# the first string, because that could then break any transactions in progress.
# See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
# If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
# support escape string syntax. Don't override the inherited quoted_string_prefix.
if supports_standard_conforming_strings?
self.class.instance_eval do
define_method(:quoted_string_prefix) { 'E' }
end
end
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
# should know about this but can't detect it there, so deal with it here.
PostgreSQLColumn.money_precision =
(postgresql_version >= 80300) ? 19 : 10
PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10
configure_connection
end
@@ -1036,7 +922,10 @@ module ActiveRecord
end
self.client_min_messages = @config[:min_messages] if @config[:min_messages]
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
set_standard_conforming_strings
# If using ActiveRecord's time zone support configure the connection to return
# TIMESTAMP WITH ZONE types in UTC.
execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc

View File

@@ -3,8 +3,9 @@ require 'yaml'
require 'csv'
require 'zlib'
require 'active_support/dependencies'
require 'active_support/core_ext/logger'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/logger'
if RUBY_VERSION < '1.9'
module YAML #:nodoc:
@@ -492,6 +493,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
table_names = [table_names].flatten.map { |n| n.to_s }
table_names.each { |n| class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/') }
connection = block_given? ? yield : ActiveRecord::Base.connection
table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
@@ -502,7 +504,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
fixtures_map = {}
fixtures = table_names_to_fetch.map do |table_name|
fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
fixtures_map[table_name] = Fixtures.new(connection, table_name.tr('/', '_'), class_names[table_name.tr('/', '_').to_sym], File.join(fixtures_directory, table_name))
end
all_loaded_fixtures.update(fixtures_map)
@@ -836,8 +838,8 @@ module ActiveRecord
def fixtures(*table_names)
if table_names.first == :all
table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
table_names = Dir["#{fixture_path}/**/*.{yml,csv}"]
table_names.map! { |f| f[(fixture_path.size + 1)..-5] }
else
table_names = table_names.flatten.map { |n| n.to_s }
end
@@ -868,9 +870,9 @@ module ActiveRecord
end
def setup_fixture_accessors(table_names = nil)
table_names = [table_names] if table_names && !table_names.respond_to?(:each)
(table_names || fixture_table_names).each do |table_name|
table_name = table_name.to_s.tr('.', '_')
table_names = Array.wrap(table_names || fixture_table_names)
table_names.each do |table_name|
table_name = table_name.to_s.tr('./', '_')
define_method(table_name) do |*fixtures|
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload

View File

@@ -258,8 +258,8 @@ namespace :db do
base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|
Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file|
Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5])
end
end

View File

@@ -182,17 +182,6 @@ module ActiveRecord #:nodoc:
options[:except] |= Array.wrap(@serializable.class.inheritance_column)
end
def serializable_attributes
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
end
def serializable_method_attributes
Array.wrap(options[:methods]).inject([]) do |method_attributes, name|
method_attributes << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
method_attributes
end
end
def add_associations(association, records, opts)
if records.is_a?(Enumerable)
tag = reformat_name(association.to_s)

View File

@@ -566,8 +566,8 @@ class FinderTest < ActiveRecord::TestCase
end
def test_string_sanitation
assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
end
def test_count

View File

@@ -16,6 +16,9 @@ require 'models/treasure'
require 'models/matey'
require 'models/ship'
require 'models/book'
require 'models/admin'
require 'models/admin/account'
require 'models/admin/user'
class FixturesTest < ActiveRecord::TestCase
self.use_instantiated_fixtures = true
@@ -507,7 +510,7 @@ class FasterFixturesTest < ActiveRecord::TestCase
end
class FoxyFixturesTest < ActiveRecord::TestCase
fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers
fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers, :"admin/accounts", :"admin/users"
def test_identifies_strings
assert_equal(Fixtures.identify("foo"), Fixtures.identify("foo"))
@@ -629,6 +632,11 @@ class FoxyFixturesTest < ActiveRecord::TestCase
assert_kind_of DeadParrot, parrots(:polly)
assert_equal pirates(:blackbeard), parrots(:polly).killer
end
def test_namespaced_models
assert admin_accounts(:signals37).users.include?(admin_users(:david))
assert_equal 2, admin_accounts(:signals37).users.size
end
end
class ActiveSupportSubclassWithFixturesTest < ActiveRecord::TestCase

View File

@@ -0,0 +1,2 @@
signals37:
name: 37signals

View File

@@ -0,0 +1,7 @@
david:
name: David
account: signals37
jamis:
name: Jamis
account: signals37

View File

@@ -0,0 +1,5 @@
module Admin
def self.table_name_prefix
'admin_'
end
end

View File

@@ -0,0 +1,3 @@
class Admin::Account < ActiveRecord::Base
has_many :users
end

View File

@@ -0,0 +1,3 @@
class Admin::User < ActiveRecord::Base
belongs_to :account
end

View File

@@ -26,6 +26,15 @@ ActiveRecord::Schema.define do
t.integer :credit_limit
end
create_table :admin_accounts, :force => true do |t|
t.string :name
end
create_table :admin_users, :force => true do |t|
t.string :name
t.references :account
end
create_table :audit_logs, :force => true do |t|
t.column :message, :string, :null=>false
t.column :developer_id, :integer, :null=>false

View File

@@ -1,3 +1,8 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. [Santiago Pastorino]
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
* No changes

View File

@@ -251,9 +251,6 @@ module ActiveResource
# The logger for diagnosing and tracing Active Resource calls.
cattr_accessor :logger
# Controls the top-level behavior of JSON serialization
cattr_accessor :include_root_in_json, :instance_writer => false
class << self
# Creates a schema for this resource - setting the attributes that are
# known prior to fetching an instance from the remote system.
@@ -1179,79 +1176,11 @@ module ActiveResource
!new? && self.class.exists?(to_param, :params => prefix_options)
end
# Converts the resource to an XML string representation.
#
# ==== Options
# The +options+ parameter is handed off to the +to_xml+ method on each
# attribute, so it has the same options as the +to_xml+ methods in
# Active Support.
#
# * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
# * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
# replace underscores with dashes (default is <tt>false</tt>).
# * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
# that generates the XML declaration (default is <tt>false</tt>).
#
# ==== Examples
# my_group = SubsidiaryGroup.find(:first)
# my_group.to_xml
# # => <?xml version="1.0" encoding="UTF-8"?>
# # <subsidiary_group> [...] </subsidiary_group>
#
# my_group.to_xml(:dasherize => true)
# # => <?xml version="1.0" encoding="UTF-8"?>
# # <subsidiary-group> [...] </subsidiary-group>
#
# my_group.to_xml(:skip_instruct => true)
# # => <subsidiary_group> [...] </subsidiary_group>
def to_xml(options={})
attributes.to_xml({:root => self.class.element_name}.merge(options))
end
# Coerces to a hash for JSON encoding.
#
# ==== Options
# The +options+ are passed to the +to_json+ method on each
# attribute, so the same options as the +to_json+ methods in
# Active Support.
#
# * <tt>:only</tt> - Only include the specified attribute or list of
# attributes in the serialized output. Attribute names must be specified
# as strings.
# * <tt>:except</tt> - Do not include the specified attribute or list of
# attributes in the serialized output. Attribute names must be specified
# as strings.
#
# ==== Examples
# person = Person.new(:first_name => "Jim", :last_name => "Smith")
# person.to_json
# # => {"first_name": "Jim", "last_name": "Smith"}
#
# person.to_json(:only => ["first_name"])
# # => {"first_name": "Jim"}
#
# person.to_json(:except => ["first_name"])
# # => {"last_name": "Smith"}
def as_json(options = nil)
attributes.as_json(options)
end
# Returns the serialized string representation of the resource in the configured
# serialization format specified in ActiveResource::Base.format. The options
# applicable depend on the configured encoding format.
def encode(options={})
case self.class.format
when ActiveResource::Formats::XmlFormat
self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
when ActiveResource::Formats::JsonFormat
if ActiveResource::Base.include_root_in_json
self.class.format.encode({self.class.element_name => attributes}, options)
else
self.class.format.encode(attributes, options)
end
else
self.class.format.encode(attributes, options)
end
send("to_#{self.class.format.extension}", options)
end
# A method to \reload the attributes of this object from the remote web service.
@@ -1475,5 +1404,7 @@ module ActiveResource
class Base
extend ActiveModel::Naming
include CustomMethods, Observing, Validations
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
end
end

View File

@@ -1015,8 +1015,7 @@ class BaseTest < Test::Unit::TestCase
assert xml.include?('<id type="integer">1</id>')
end
def test_to_json_including_root
def test_to_json
Person.include_root_in_json = true
Person.format = :json
joe = Person.find(6)

View File

@@ -1,5 +1,12 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* JSON: encode objects that don't have a native JSON representation using to_hash, if available, instead of instance_values (the old fallback) or to_s (other encoders' default). Encode BigDecimal and Regexp encode as strings to conform with other encoders. Try to transcode non-UTF-8 strings. [Jeremy Kemper]
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
* HashWithIndifferentAccess: remove inherited symbolize_keys! since its keys are always strings. [Santiago Pastorino]
* Improve transliteration quality. #4374 [Norman Clarke]
* Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke]

View File

@@ -1,35 +1,36 @@
require "active_support/concern"
require 'active_support/concern'
require 'active_support/ordered_options'
require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/module/delegation'
module ActiveSupport
module Configurable
extend ActiveSupport::Concern
module ClassMethods
def get_config
module_parts = name.split("::")
modules = [Object]
module_parts.each {|name| modules.push modules.last.const_get(name) }
modules.reverse_each do |mod|
return mod.const_get(:DEFAULT_CONFIG) if const_defined?(:DEFAULT_CONFIG)
end
{}
end
def config
self.config = get_config unless @config
@config
@config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
end
def config=(hash)
@config = ActiveSupport::OrderedOptions.new
hash.each do |key, value|
@config[key] = value
def configure
yield config
end
def config_accessor(*names)
names.each do |name|
code, line = <<-RUBY, __LINE__ + 1
def #{name}; config.#{name}; end
def #{name}=(value); config.#{name} = value; end
RUBY
singleton_class.class_eval code, __FILE__, line
class_eval code, __FILE__, line
end
end
end
def config
self.class.config
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
end
end
end

View File

@@ -1,3 +1,4 @@
require 'rbconfig'
module Kernel
# Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
#
@@ -37,7 +38,7 @@ module Kernel
# puts 'But this will'
def silence_stream(stream)
old_stream = stream.dup
stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
stream.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
stream.sync = true
yield
ensure

View File

@@ -1,8 +1,9 @@
# encoding: utf-8
if RUBY_VERSION >= '1.9'
require 'uri'
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding)
parser = URI::Parser.new
unless str == parser.unescape(parser.escape(str))

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/hash/keys'
# This class has dubious semantics and we only have it so that
# people can write params[:key] instead of params['key']
# and they get the same value for both keys.
@@ -112,7 +114,9 @@ module ActiveSupport
end
def stringify_keys!; self end
def symbolize_keys!; self end
def stringify_keys; dup end
undef :symbolize_keys!
def symbolize_keys; to_hash.symbolize_keys end
def to_options!; self end
# Convert to a Hash with String keys.

View File

@@ -1,4 +1,5 @@
# encoding: utf-8
require 'bigdecimal'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/slice'
@@ -102,7 +103,9 @@ module ActiveSupport
end
def escape(string)
string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding)
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, undef: :replace).force_encoding(::Encoding::BINARY)
end
json = string.
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
gsub(/([\xC0-\xDF][\x80-\xBF]|
@@ -110,7 +113,9 @@ module ActiveSupport
[\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
}
%("#{json}")
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
end
end
@@ -128,7 +133,13 @@ class Object
ActiveSupport::JSON.encode(self, options)
end
def as_json(options = nil) instance_values end #:nodoc:
def as_json(options = nil) #:nodoc:
if respond_to?(:to_hash)
to_hash
else
instance_values
end
end
end
# A string that returns itself as its JSON-encoded form.
@@ -166,9 +177,12 @@ class Numeric
def encode_json(encoder) to_s end #:nodoc:
end
class BigDecimal
def as_json(options = nil) to_s end #:nodoc:
end
class Regexp
def as_json(options = nil) self end #:nodoc:
def encode_json(encoder) inspect end #:nodoc:
def as_json(options = nil) to_s end #:nodoc:
end
module Enumerable

View File

@@ -72,8 +72,8 @@ module ActiveSupport #:nodoc:
def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
end
UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/
UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/
UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/u
UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/u
UTF8_PAT = ActiveSupport::Multibyte::VALID_CHARACTER['UTF-8']

View File

@@ -19,8 +19,8 @@ module ActiveSupport
end
def unsubscribe(subscriber)
@subscribers.delete(subscriber)
@listeners_for.clear
@subscribers.reject! {|s| s.matches?(subscriber)}
end
def publish(name, *args)
@@ -60,7 +60,7 @@ module ActiveSupport
end
def publish(*args)
return unless matches?(args.first)
return unless subscribed_to?(args.first)
push(*args)
true
end
@@ -69,10 +69,20 @@ module ActiveSupport
true
end
private
def matches?(name)
!@pattern || @pattern =~ name.to_s
def subscribed_to?(name)
!@pattern || @pattern =~ name.to_s
end
def matches?(subscriber_or_name)
case subscriber_or_name
when String
@pattern && @pattern =~ subscriber_or_name
when self
true
end
end
private
def push(*args)
@block.call(*args)

View File

@@ -1,3 +1,4 @@
require 'rbconfig'
module ActiveSupport
module Testing
class RemoteError < StandardError
@@ -33,7 +34,7 @@ module ActiveSupport
module Isolation
def self.forking_env?
!ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/
!ENV["NO_FORK"] && ((Config::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
end
def self.included(base)

View File

@@ -0,0 +1,42 @@
require 'abstract_unit'
require 'active_support/configurable'
class ConfigurableActiveSupport < ActiveSupport::TestCase
class Parent
include ActiveSupport::Configurable
config_accessor :foo
end
class Child < Parent
end
setup do
Parent.config.clear
Parent.config.foo = :bar
Child.config.clear
end
test "adds a configuration hash" do
assert_equal({ :foo => :bar }, Parent.config)
end
test "configuration hash is inheritable" do
assert_equal :bar, Child.config.foo
assert_equal :bar, Parent.config.foo
Child.config.foo = :baz
assert_equal :baz, Child.config.foo
assert_equal :bar, Parent.config.foo
end
test "configuration hash is available on instance" do
instance = Parent.new
assert_equal :bar, instance.config.foo
assert_equal :bar, Parent.config.foo
instance.config.foo = :baz
assert_equal :baz, instance.config.foo
assert_equal :bar, Parent.config.foo
end
end

View File

@@ -60,6 +60,43 @@ class HashExtTest < Test::Unit::TestCase
assert_equal @strings, @mixed.dup.stringify_keys!
end
def test_symbolize_keys_for_hash_with_indifferent_access
assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys
assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys
assert_equal @symbols, @strings.with_indifferent_access.symbolize_keys
assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys
end
def test_symbolize_keys_bang_for_hash_with_indifferent_access
assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! }
end
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }
end
def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! }
end
def test_stringify_keys_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys
assert_equal @strings, @symbols.with_indifferent_access.stringify_keys
assert_equal @strings, @strings.with_indifferent_access.stringify_keys
assert_equal @strings, @mixed.with_indifferent_access.stringify_keys
end
def test_stringify_keys_bang_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys!
assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys!
assert_equal @strings, @strings.with_indifferent_access.dup.stringify_keys!
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
end
def test_indifferent_assorted
@strings = @strings.with_indifferent_access
@symbols = @symbols.with_indifferent_access
@@ -213,11 +250,11 @@ class HashExtTest < Test::Unit::TestCase
def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash
h = HashWithIndifferentAccess.new
h[:first] = 1
h.stringify_keys!
h = h.stringify_keys
assert_equal 1, h['first']
h = HashWithIndifferentAccess.new
h['first'] = 1
h.symbolize_keys!
h = h.symbolize_keys
assert_equal 1, h[:first]
end

View File

@@ -1,3 +1,4 @@
# encoding: utf-8
require 'abstract_unit'
require 'uri'
require 'active_support/core_ext/uri'
@@ -5,7 +6,6 @@ require 'active_support/core_ext/uri'
class URIExtTest < Test::Unit::TestCase
def test_uri_decode_handle_multibyte
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding)
if URI.const_defined?(:Parser)
parser = URI::Parser.new

View File

@@ -9,6 +9,12 @@ class TestJSONEncoding < Test::Unit::TestCase
end
end
class Hashlike
def to_hash
{ :a => 1 }
end
end
class Custom
def as_json(options)
'custom'
@@ -19,7 +25,8 @@ class TestJSONEncoding < Test::Unit::TestCase
FalseTests = [[ false, %(false) ]]
NilTests = [[ nil, %(null) ]]
NumericTests = [[ 1, %(1) ],
[ 2.5, %(2.5) ]]
[ 2.5, %(2.5) ],
[ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]]
StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")],
[ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
@@ -35,11 +42,12 @@ class TestJSONEncoding < Test::Unit::TestCase
[ :"a b", %("a b") ]]
ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
HashlikeTests = [[ Hashlike.new, %({\"a\":1}) ]]
CustomTests = [[ Custom.new, '"custom"' ]]
VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'],
[ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']]
RegexpTests = [[ /^a/, '/^a/' ], [/^\w{1,2}[a-z]+/ix, '/^\\w{1,2}[a-z]+/ix']]
RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']]
DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]]
TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
@@ -91,6 +99,15 @@ class TestJSONEncoding < Test::Unit::TestCase
end
end
if '1.9'.respond_to?(:force_encoding)
def test_non_utf8_string_transcodes
s = '二'.encode('Shift_JIS')
result = ActiveSupport::JSON.encode(s)
assert_equal '"\\u4e8c"', result
assert_equal Encoding::UTF_8, result.encoding
end
end
def test_exception_raised_when_encoding_circular_reference
a = [1]
a << a

View File

@@ -105,7 +105,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase
@whitespace = "\n\t#{[32, 8195].pack('U*')}"
else
# Ruby 1.9 only supports basic whitespace
@whitespace = "\n\t ".force_encoding(Encoding::UTF_8)
@whitespace = "\n\t "
end
@byte_order_mark = [65279].pack('U')

View File

@@ -6,7 +6,9 @@ module Notifications
ActiveSupport::Notifications.notifier = nil
@notifier = ActiveSupport::Notifications.notifier
@events = []
@named_events = []
@subscription = @notifier.subscribe { |*args| @events << event(*args) }
@named_subscription = @notifier.subscribe("named.subscription") { |*args| @named_events << event(*args) }
end
private
@@ -30,6 +32,26 @@ module Notifications
assert_equal [[:foo]], @events
end
def test_unsubscribing_by_name_removes_a_subscription
@notifier.publish "named.subscription", :foo
@notifier.wait
assert_equal [["named.subscription", :foo]], @named_events
@notifier.unsubscribe("named.subscription")
@notifier.publish "named.subscription", :foo
@notifier.wait
assert_equal [["named.subscription", :foo]], @named_events
end
def test_unsubscribing_by_name_leaves_the_other_subscriptions
@notifier.publish "named.subscription", :foo
@notifier.wait
assert_equal [["named.subscription", :foo]], @events
@notifier.unsubscribe("named.subscription")
@notifier.publish "named.subscription", :foo
@notifier.wait
assert_equal [["named.subscription", :foo], ["named.subscription", :foo]], @events
end
private
def event(*args)
args

View File

@@ -6,6 +6,7 @@ require 'rake/gempackagetask'
require 'date'
require 'rbconfig'
task :default => :test
task :test => 'test:isolated'

View File

@@ -112,15 +112,15 @@ module Rails
def load_tasks
initialize_tasks
super
railties.all { |r| r.load_tasks }
super
self
end
def load_generators
initialize_generators
super
railties.all { |r| r.load_generators }
super
self
end

View File

@@ -128,13 +128,13 @@ module Rails
end
end
protected
def session_options
return @session_options unless @session_store == :cookie_store
@session_options.merge(:secret => @secret_token)
end
protected
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
middleware.use('::ActionDispatch::Static', lambda { paths.public.to_a.first }, :if => lambda { serve_static_assets })

View File

@@ -1,6 +1,7 @@
require 'erb'
require 'yaml'
require 'optparse'
require 'rbconfig'
module Rails
class DBConsole
@@ -41,7 +42,7 @@ module Rails
def find_cmd(*commands)
dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
commands += commands.map{|cmd| "#{cmd}.exe"} if RUBY_PLATFORM =~ /win32/
commands += commands.map{|cmd| "#{cmd}.exe"} if Config::CONFIG['host_os'] =~ /mswin|mingw/
full_path_command = nil
found = commands.detect do |cmd|

View File

@@ -1,4 +1,5 @@
require 'optparse'
require 'rbconfig'
options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
code_or_file = nil
@@ -18,7 +19,7 @@ ARGV.clone.options do |opts|
opts.on("-h", "--help",
"Show this help message.") { $stderr.puts opts; exit }
if RUBY_PLATFORM !~ /mswin|mingw/
if Config::CONFIG['host_os'] !~ /mswin|mingw/
opts.separator ""
opts.separator "You can also use runner as a shebang line for your scripts like this:"
opts.separator "-------------------------------------------------------------"

View File

@@ -1,6 +1,7 @@
require 'rails/railtie'
require 'active_support/core_ext/module/delegation'
require 'pathname'
require 'rbconfig'
module Rails
# Rails::Engine allows you to wrap a specific Rails application and share it accross
@@ -119,7 +120,7 @@ module Rails
root = File.exist?("#{root_path}/#{flag}") ? root_path : default
raise "Could not find root path for #{self}" unless root
RUBY_PLATFORM =~ /mswin|mingw/ ?
Config::CONFIG['host_os'] =~ /mswin|mingw/ ?
Pathname.new(root).expand_path : Pathname.new(root).realpath
end
end

View File

@@ -1,5 +1,6 @@
require 'open-uri'
require 'active_support/deprecation'
require 'rbconfig'
module Rails
module Generators
@@ -240,7 +241,7 @@ module Rails
def rake(command, options={})
log :rake, command
env = options[:env] || 'development'
sudo = options[:sudo] && RUBY_PLATFORM !~ /mswin|mingw/ ? 'sudo ' : ''
sudo = options[:sudo] && Config::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
end
@@ -307,7 +308,7 @@ module Rails
# Add an extension to the given name based on the platform.
#
def extify(name)
if RUBY_PLATFORM =~ /mswin|mingw/
if Config::CONFIG['host_os'] =~ /mswin|mingw/
"#{name}.bat"
else
name

View File

@@ -1,4 +1,4 @@
<p class="notice"><%%= notice %></p>
<p id="notice"><%%= notice %></p>
<% for attribute in attributes -%>
<p>

View File

@@ -1,6 +1,7 @@
require 'digest/md5'
require 'active_support/secure_random'
require 'rails/version' unless defined?(Rails::VERSION)
require 'rbconfig'
module Rails::Generators
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
@@ -265,7 +266,7 @@ module Rails::Generators
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /mswin|mingw/
].find { |f| File.exist?(f) } unless Config::CONFIG['host_os'] =~ /mswin|mingw/
end
def empty_directory_with_gitkeep(destination, config = {})

View File

@@ -2,9 +2,6 @@
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
Rails::Application.load_tasks

View File

@@ -20,15 +20,11 @@ div.field, div.actions {
margin-bottom: 10px;
}
.notice {
#notice {
color: green;
}
.alert {
color: red;
}
.fieldWithErrors {
.field_with_errors {
padding: 2px;
background-color: red;
display: table;

View File

@@ -1,3 +1,5 @@
require 'rake/rdoctask'
namespace :doc do
def gem_path(gem_name)
path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first

View File

@@ -35,7 +35,9 @@ class ActionController::TestCase
end
class ActionDispatch::IntegrationTest
include Rails.application.routes.url_helpers
setup do
@routes = Rails.application.routes
end
end
begin

View File

@@ -1,3 +1,5 @@
require 'rake/testtask'
TEST_CHANGES_SINCE = Time.now - 600
# Look up tests for recently modified sources.
@@ -30,7 +32,7 @@ end
module Kernel
def silence_stderr
old_stderr = STDERR.dup
STDERR.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
STDERR.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
STDERR.sync = true
yield
ensure

View File

@@ -109,7 +109,7 @@ module ApplicationTests
end
end
test "Frameworks are not preloaded by default" do
test "frameworks are not preloaded by default" do
require "#{app_path}/config/environment"
assert ActionController.autoload?(:RecordIdentifier)
@@ -193,71 +193,10 @@ module ApplicationTests
assert_equal File.join(app_path, "somewhere"), Rails.public_path
end
def make_basic_app
require "rails"
require "action_controller/railtie"
app = Class.new(Rails::Application)
yield app if block_given?
app.config.session_store :disabled
app.initialize!
app.routes.draw do
match "/" => "omg#index"
end
require 'rack/test'
extend Rack::Test::Methods
end
test "config.action_dispatch.x_sendfile_header defaults to ''" do
make_basic_app
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.read(__FILE__), last_response.body
end
test "config.action_dispatch.x_sendfile_header can be set" do
make_basic_app do |app|
app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
end
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"]
end
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
make_basic_app do |app|
app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
end
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
end
test "config.secret_token is sent in env" do
make_basic_app do |app|
app.config.secret_token = 'ThisIsASECRET123'
app.config.session_store :disabled
end
class ::OmgController < ActionController::Base
@@ -287,9 +226,9 @@ module ApplicationTests
end
test "config.action_controller.perform_caching = true" do
make_basic_app do |app|
app.config.action_controller.perform_caching = true
end
make_basic_app do |app|
app.config.action_controller.perform_caching = true
end
class ::OmgController < ActionController::Base
@@count = 0

View File

@@ -1,54 +0,0 @@
require 'isolation/abstract_unit'
class MiddlewareStackDefaultsTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
def setup
boot_rails
require "rails"
require "action_controller/railtie"
Object.const_set(:MyApplication, Class.new(Rails::Application))
MyApplication.class_eval do
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
config.session_store :cookie_store, :key => "_myapp_session"
end
end
def remote_ip(env = {})
remote_ip = nil
env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false)
endpoint = Proc.new do |e|
remote_ip = ActionDispatch::Request.new(e).remote_ip
[200, {}, ["Hello"]]
end
out = MyApplication.middleware.build(endpoint).call(env)
remote_ip
end
test "remote_ip works" do
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1")
end
test "checks IP spoofing by default" do
assert_raises(ActionDispatch::RemoteIp::IpSpoofAttackError) do
remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
end
end
test "can disable IP spoofing check" do
MyApplication.config.action_dispatch.ip_spoofing_check = false
assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do
assert_equal "1.1.1.2", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
end
end
test "the user can set trusted proxies" do
MyApplication.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1")
end
end

View File

@@ -10,6 +10,10 @@ module ApplicationTests
FileUtils.rm_rf "#{app_path}/config/environments"
end
def app
@app ||= Rails.application
end
test "default middleware stack" do
boot!
@@ -83,7 +87,83 @@ module ApplicationTests
assert middleware.include?("ActionDispatch::Cascade")
end
# x_sendfile_header middleware
test "config.action_dispatch.x_sendfile_header defaults to ''" do
make_basic_app
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.read(__FILE__), last_response.body
end
test "config.action_dispatch.x_sendfile_header can be set" do
make_basic_app do |app|
app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
end
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"]
end
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
make_basic_app do |app|
app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
end
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
end
# remote_ip tests
test "remote_ip works" do
make_basic_app
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1")
end
test "checks IP spoofing by default" do
make_basic_app
assert_raises(ActionDispatch::RemoteIp::IpSpoofAttackError) do
remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
end
end
test "can disable IP spoofing check" do
make_basic_app do |app|
app.config.action_dispatch.ip_spoofing_check = false
end
assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do
assert_equal "1.1.1.2", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
end
end
test "the user can set trusted proxies" do
make_basic_app do |app|
app.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/
end
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1")
end
private
def boot!
require "#{app_path}/config/environment"
end
@@ -91,5 +171,18 @@ module ApplicationTests
def middleware
AppTemplate::Application.middleware.active.map(&:klass).map(&:name)
end
def remote_ip(env = {})
remote_ip = nil
env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false)
endpoint = Proc.new do |e|
remote_ip = ActionDispatch::Request.new(e).remote_ip
[200, {}, ["Hello"]]
end
Rails.application.middleware.build(endpoint).call(env)
remote_ip
end
end
end

View File

@@ -0,0 +1,23 @@
require "isolation/abstract_unit"
module ApplicationTests
class RakeTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
def test_gems_tasks_are_loaded_first_than_application_ones
app_file "lib/tasks/app.rake", <<-RUBY
$task_loaded = Rake::Task.task_defined?("db:create:all")
RUBY
require "#{app_path}/config/environment"
::Rails.application.load_tasks
assert $task_loaded
end
end
end

View File

@@ -103,6 +103,25 @@ module TestHelpers
add_to_config 'config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"'
end
def make_basic_app
require "rails"
require "action_controller/railtie"
app = Class.new(Rails::Application)
app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
app.config.session_store :cookie_store, :key => "_myapp_session"
yield app if block_given?
app.initialize!
app.routes.draw do
match "/" => "omg#index"
end
require 'rack/test'
extend ::Rack::Test::Methods
end
class Bukkit
attr_reader :path

View File

@@ -13,6 +13,7 @@ Gem.source_index
require 'benchmark'
module RequireProfiler
private
def require(file, *args) RequireProfiler.profile(file) { super } end
def load(file, *args) RequireProfiler.profile(file) { super } end