aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb5
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb67
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb9
-rw-r--r--actionpack/test/dispatch/routing_test.rb9
-rw-r--r--actionpack/test/journey/router_test.rb39
-rw-r--r--activerecord/lib/active_record/associations.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb79
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb71
-rw-r--r--activerecord/test/cases/column_test.rb159
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/cases/types_test.rb159
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb2
-rw-r--r--activesupport/lib/active_support/duration.rb3
-rw-r--r--activesupport/test/core_ext/array_ext_test.rb2
17 files changed, 297 insertions, 335 deletions
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 8b3081d8fe..6d58323789 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -132,11 +132,6 @@ module ActionDispatch
}
end
- # Returns +true+ if no missing keys are present, otherwise +false+.
- def verify_required_parts!(route, parts)
- missing_keys(route, parts).empty?
- end
-
def build_cache
root = { ___routes: [] }
routes.each_with_index do |route, i|
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index c34b44409e..2ead6a4eb3 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -20,61 +20,30 @@ module ActionDispatch
# :nodoc:
VERSION = '2.0.0'
- class NullReq # :nodoc:
- attr_reader :env
- attr_accessor :path_parameters
- def initialize(env)
- @env = env
- @path_parameters = {}
- end
-
- def request_method
- env['REQUEST_METHOD']
- end
-
- def path_info
- env['PATH_INFO']
- end
-
- def ip
- env['REMOTE_ADDR']
- end
-
- def [](k)
- env[k]
- end
- end
-
- attr_reader :request_class, :formatter
attr_accessor :routes
- def initialize(routes, options)
- @options = options
- @request_class = options[:request_class] || NullReq
- @routes = routes
+ def initialize(routes)
+ @routes = routes
end
- def call(env)
- env['PATH_INFO'] = Utils.normalize_path(env['PATH_INFO'])
-
- req = request_class.new(env)
-
- find_routes(env, req).each do |match, parameters, route|
- set_params = req.path_parameters
- script_name, path_info = env.values_at('SCRIPT_NAME', 'PATH_INFO')
+ def serve(req)
+ find_routes(req).each do |match, parameters, route|
+ set_params = req.path_parameters
+ path_info = req.path_info
+ script_name = req.script_name
unless route.path.anchored
- env['SCRIPT_NAME'] = (script_name.to_s + match.to_s).chomp('/')
- env['PATH_INFO'] = match.post_match
+ req.script_name = (script_name.to_s + match.to_s).chomp('/')
+ req.path_info = match.post_match
end
req.path_parameters = set_params.merge parameters
- status, headers, body = route.app.call(env)
+ status, headers, body = route.app.call(req.env)
if 'pass' == headers['X-Cascade']
- env['SCRIPT_NAME'] = script_name
- env['PATH_INFO'] = path_info
+ req.script_name = script_name
+ req.path_info = path_info
req.path_parameters = set_params
next
end
@@ -85,13 +54,11 @@ module ActionDispatch
return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
end
- def recognize(req)
- rails_req = request_class.new(req.env)
-
- find_routes(req.env, rails_req).each do |match, parameters, route|
+ def recognize(rails_req)
+ find_routes(rails_req).each do |match, parameters, route|
unless route.path.anchored
- req.env['SCRIPT_NAME'] = match.to_s
- req.env['PATH_INFO'] = match.post_match.sub(/^([^\/])/, '/\1')
+ rails_req.script_name = match.to_s
+ rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
end
yield(route, parameters)
@@ -128,7 +95,7 @@ module ActionDispatch
simulator.memos(path) { [] }
end
- def find_routes env, req
+ def find_routes req
routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
r.path.match(req.path_info)
}
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 8b4fd26ce2..e9fb712a61 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -302,8 +302,7 @@ module ActionDispatch
@finalized = false
@set = Journey::Routes.new
- @router = Journey::Router.new(@set, {
- :request_class => request_class})
+ @router = Journey::Router.new @set
@formatter = Journey::Formatter.new @set
end
@@ -683,7 +682,9 @@ module ActionDispatch
end
def call(env)
- @router.call(env)
+ req = request_class.new(env)
+ req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
+ @router.serve(req)
end
def recognize_path(path, environment = {})
@@ -697,7 +698,7 @@ module ActionDispatch
raise ActionController::RoutingError, e.message
end
- req = @request_class.new(env)
+ req = request_class.new(env)
@router.recognize(req) do |route, params|
params.merge!(extras)
params.each do |key, value|
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 051431ce26..a427113763 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3368,15 +3368,14 @@ end
class TestAltApp < ActionDispatch::IntegrationTest
class AltRequest
- attr_accessor :path_parameters
+ attr_accessor :path_parameters, :path_info, :script_name
+ attr_reader :env
def initialize(env)
@path_parameters = {}
@env = env
- end
-
- def path_info
- "/"
+ @path_info = "/"
+ @script_name = ""
end
def request_method
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index 9a8d644f7b..6252458861 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -12,16 +12,10 @@ module ActionDispatch
def setup
@app = StubDispatcher.new
@routes = Routes.new
- @router = Router.new(@routes, {})
+ @router = Router.new(@routes)
@formatter = Formatter.new(@routes)
end
- def test_request_class_reader
- klass = Object.new
- router = Router.new(routes, :request_class => klass)
- assert_equal klass, router.request_class
- end
-
class FakeRequestFeeler < Struct.new(:env, :called)
def new env
self.env = env
@@ -39,7 +33,7 @@ module ActionDispatch
end
def test_dashes
- router = Router.new(routes, {})
+ router = Router.new(routes)
exp = Router::Strexp.new '/foo-bar-baz', {}, ['/.?']
path = Path::Pattern.new exp
@@ -55,7 +49,7 @@ module ActionDispatch
end
def test_unicode
- router = Router.new(routes, {})
+ router = Router.new(routes)
#match the escaped version of /ほげ
exp = Router::Strexp.new '/%E3%81%BB%E3%81%92', {}, ['/.?']
@@ -73,7 +67,7 @@ module ActionDispatch
def test_request_class_and_requirements_success
klass = FakeRequestFeeler.new nil
- router = Router.new(routes, {:request_class => klass })
+ router = Router.new(routes)
requirements = { :hello => /world/ }
@@ -82,7 +76,7 @@ module ActionDispatch
routes.add_route nil, path, requirements, {:id => nil}, {}
- env = rails_env 'PATH_INFO' => '/foo/10'
+ env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
router.recognize(env) do |r, params|
assert_equal({:id => '10'}, params)
end
@@ -93,7 +87,7 @@ module ActionDispatch
def test_request_class_and_requirements_fail
klass = FakeRequestFeeler.new nil
- router = Router.new(routes, {:request_class => klass })
+ router = Router.new(routes)
requirements = { :hello => /mom/ }
@@ -102,7 +96,7 @@ module ActionDispatch
router.routes.add_route nil, path, requirements, {:id => nil}, {}
- env = rails_env 'PATH_INFO' => '/foo/10'
+ env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
router.recognize(env) do |r, params|
flunk 'route should not be found'
end
@@ -111,21 +105,26 @@ module ActionDispatch
assert_equal env.env, klass.env
end
- class CustomPathRequest < Router::NullReq
+ class CustomPathRequest < ActionDispatch::Request
def path_info
env['custom.path_info']
end
+
+ def path_info=(x)
+ env['custom.path_info'] = x
+ end
end
def test_request_class_overrides_path_info
- router = Router.new(routes, {:request_class => CustomPathRequest })
+ router = Router.new(routes)
exp = Router::Strexp.new '/bar', {}, ['/.?']
path = Path::Pattern.new exp
routes.add_route nil, path, {}, {}, {}
- env = rails_env 'PATH_INFO' => '/foo', 'custom.path_info' => '/bar'
+ env = rails_env({'PATH_INFO' => '/foo',
+ 'custom.path_info' => '/bar'}, CustomPathRequest)
recognized = false
router.recognize(env) do |r, params|
@@ -207,7 +206,7 @@ module ActionDispatch
def test_X_Cascade
add_routes @router, [ "/messages(.:format)" ]
- resp = @router.call({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' })
+ resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }))
assert_equal ['Not Found'], resp.last
assert_equal 'pass', resp[1]['X-Cascade']
assert_equal 404, resp.first
@@ -220,7 +219,7 @@ module ActionDispatch
@router.routes.add_route(app, path, {}, {}, {})
env = rack_env('SCRIPT_NAME' => '', 'PATH_INFO' => '/weblog')
- resp = @router.call(env)
+ resp = @router.serve rails_env env
assert_equal ['success!'], resp.last
assert_equal '', env['SCRIPT_NAME']
end
@@ -561,8 +560,8 @@ module ActionDispatch
RailsEnv = Struct.new(:env)
- def rails_env env
- RailsEnv.new rack_env env
+ def rails_env env, klass = ActionDispatch::Request
+ klass.new env
end
def rack_env env
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 727ee5f65f..8d77fad2d5 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -202,12 +202,13 @@ module ActiveRecord
# For instance, +attributes+ and +connection+ would be bad choices for association names.
#
# == Auto-generated methods
+ # See also Instance Public methods below for more details.
#
# === Singular associations (one-to-one)
# | | belongs_to |
# generated methods | belongs_to | :polymorphic | has_one
# ----------------------------------+------------+--------------+---------
- # other | X | X | X
+ # other(force_reload=false) | X | X | X
# other=(other) | X | X | X
# build_other(attributes={}) | X | | X
# create_other(attributes={}) | X | | X
@@ -217,7 +218,7 @@ module ActiveRecord
# | | | has_many
# generated methods | habtm | has_many | :through
# ----------------------------------+-------+----------+----------
- # others | X | X | X
+ # others(force_reload=false) | X | X | X
# others=(other,other,...) | X | X | X
# other_ids | X | X | X
# other_ids=(id,id,...) | X | X | X
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index 0cbedb0987..f7bad20f00 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -6,13 +6,6 @@ module ActiveRecord
"(#{point[0]},#{point[1]})"
end
- def string_to_point(string) # :nodoc:
- if string[0] == '(' && string[-1] == ')'
- string = string[1...-1]
- end
- string.split(',').map{ |v| Float(v) }
- end
-
def string_to_bit(value) # :nodoc:
case value
when /^0x/i
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index b55766bde0..9a5e2d05ef 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -6,18 +6,16 @@ module ActiveRecord
class PostgreSQLColumn < Column #:nodoc:
attr_accessor :array
- def initialize(name, default, cast_type, sql_type = nil, null = true)
- default_value = self.class.extract_value_from_default(default)
-
+ def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
if sql_type =~ /\[\]$/
@array = true
- super(name, default_value, cast_type, sql_type[0..sql_type.length - 3], null)
+ super(name, default, cast_type, sql_type[0..sql_type.length - 3], null)
else
@array = false
- super(name, default_value, cast_type, sql_type, null)
+ super(name, default, cast_type, sql_type, null)
end
- @default_function = default if has_default_function?(default_value, default)
+ @default_function = default_function
end
# :stopdoc:
@@ -38,78 +36,9 @@ module ActiveRecord
end
# :startdoc:
- # Extracts the value from a PostgreSQL column default definition.
- def self.extract_value_from_default(default)
- # This is a performance optimization for Ruby 1.9.2 in development.
- # If the value is nil, we return nil straight away without checking
- # the regular expressions. If we check each regular expression,
- # Regexp#=== will call NilClass#to_str, which will trigger
- # method_missing (defined by whiny nil in ActiveSupport) which
- # makes this method very very slow.
- return default unless default
-
- case default
- when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
- $1
- # Numeric types
- when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
- $1
- # Character types
- when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
- $1.gsub(/''/, "'")
- # Binary data types
- when /\A'(.*)'::bytea\z/m
- $1
- # Date/time types
- when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
- $1
- when /\A'(.*)'::interval\z/
- $1
- # Boolean type
- when 'true'
- true
- when 'false'
- false
- # Geometric types
- when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
- $1
- # Network address types
- when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
- $1
- # Bit string types
- when /\AB'(.*)'::"?bit(?: varying)?"?\z/
- $1
- # XML type
- when /\A'(.*)'::xml\z/m
- $1
- # Arrays
- when /\A'(.*)'::"?\D+"?\[\]\z/
- $1
- # Hstore
- when /\A'(.*)'::hstore\z/
- $1
- # JSON
- when /\A'(.*)'::json\z/
- $1
- # Object identifier types
- when /\A-?\d+\z/
- $1
- else
- # Anything else is blank, some user type, or some function
- # and we can't know the value of that, so return nil.
- nil
- end
- end
-
def accessor
cast_type.accessor
end
-
- private
-
- def has_default_function?(default_value, default)
- !default_value && (%r{\w+\(.*\)} === default)
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index 2769a8d3b4..f9531ddee3 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -5,7 +5,10 @@ module ActiveRecord
class Point < Type::String
def type_cast(value)
if ::String === value
- ConnectionAdapters::PostgreSQLColumn.string_to_point value
+ if value[0] == '(' && value[-1] == ')'
+ value = value[1...-1]
+ end
+ value.split(',').map{ |v| Float(v) }
else
value
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index c04a1d7178..9e53d10bb4 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -179,7 +179,9 @@ module ActiveRecord
# Limit, precision, and scale are all handled by the superclass.
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
oid = get_oid_type(oid.to_i, fmod.to_i, column_name, type)
- PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f')
+ default_value = extract_value_from_default(default)
+ default_function = extract_default_function(default_value, default)
+ PostgreSQLColumn.new(column_name, default_value, oid, type, notnull == 'f', default_function)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index e3a2422160..da2144bee7 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -637,6 +637,77 @@ module ActiveRecord
end
end
+ # Extracts the value from a PostgreSQL column default definition.
+ def extract_value_from_default(default)
+ # This is a performance optimization for Ruby 1.9.2 in development.
+ # If the value is nil, we return nil straight away without checking
+ # the regular expressions. If we check each regular expression,
+ # Regexp#=== will call NilClass#to_str, which will trigger
+ # method_missing (defined by whiny nil in ActiveSupport) which
+ # makes this method very very slow.
+ return default unless default
+
+ case default
+ when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
+ $1
+ # Numeric types
+ when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
+ $1
+ # Character types
+ when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
+ $1.gsub(/''/, "'")
+ # Binary data types
+ when /\A'(.*)'::bytea\z/m
+ $1
+ # Date/time types
+ when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
+ $1
+ when /\A'(.*)'::interval\z/
+ $1
+ # Boolean type
+ when 'true'
+ true
+ when 'false'
+ false
+ # Geometric types
+ when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
+ $1
+ # Network address types
+ when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
+ $1
+ # Bit string types
+ when /\AB'(.*)'::"?bit(?: varying)?"?\z/
+ $1
+ # XML type
+ when /\A'(.*)'::xml\z/m
+ $1
+ # Arrays
+ when /\A'(.*)'::"?\D+"?\[\]\z/
+ $1
+ # Hstore
+ when /\A'(.*)'::hstore\z/
+ $1
+ # JSON
+ when /\A'(.*)'::json\z/
+ $1
+ # Object identifier types
+ when /\A-?\d+\z/
+ $1
+ else
+ # Anything else is blank, some user type, or some function
+ # and we can't know the value of that, so return nil.
+ nil
+ end
+ end
+
+ def extract_default_function(default_value, default)
+ default if has_default_function?(default_value, default)
+ end
+
+ def has_default_function?(default_value, default)
+ !default_value && (%r{\w+\(.*\)} === default)
+ end
+
def load_additional_types(type_map, oids = nil)
if supports_ranges?
query = <<-SQL
diff --git a/activerecord/test/cases/column_test.rb b/activerecord/test/cases/column_test.rb
deleted file mode 100644
index 3257f5bed8..0000000000
--- a/activerecord/test/cases/column_test.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-require "cases/helper"
-require 'models/company'
-
-module ActiveRecord
- module ConnectionAdapters
- class ColumnTest < ActiveRecord::TestCase
- def test_type_cast_boolean
- column = Column.new("field", nil, Type::Boolean.new)
- assert column.type_cast('').nil?
- assert column.type_cast(nil).nil?
-
- assert column.type_cast(true)
- assert column.type_cast(1)
- assert column.type_cast('1')
- assert column.type_cast('t')
- assert column.type_cast('T')
- assert column.type_cast('true')
- assert column.type_cast('TRUE')
- assert column.type_cast('on')
- assert column.type_cast('ON')
-
- # explicitly check for false vs nil
- assert_equal false, column.type_cast(false)
- assert_equal false, column.type_cast(0)
- assert_equal false, column.type_cast('0')
- assert_equal false, column.type_cast('f')
- assert_equal false, column.type_cast('F')
- assert_equal false, column.type_cast('false')
- assert_equal false, column.type_cast('FALSE')
- assert_equal false, column.type_cast('off')
- assert_equal false, column.type_cast('OFF')
- assert_equal false, column.type_cast(' ')
- assert_equal false, column.type_cast("\u3000\r\n")
- assert_equal false, column.type_cast("\u0000")
- assert_equal false, column.type_cast('SOMETHING RANDOM')
- end
-
- def test_type_cast_string
- column = Column.new("field", nil, Type::String.new)
- assert_equal "1", column.type_cast(true)
- assert_equal "0", column.type_cast(false)
- assert_equal "123", column.type_cast(123)
- end
-
- def test_type_cast_integer
- column = Column.new("field", nil, Type::Integer.new)
- assert_equal 1, column.type_cast(1)
- assert_equal 1, column.type_cast('1')
- assert_equal 1, column.type_cast('1ignore')
- assert_equal 0, column.type_cast('bad1')
- assert_equal 0, column.type_cast('bad')
- assert_equal 1, column.type_cast(1.7)
- assert_equal 0, column.type_cast(false)
- assert_equal 1, column.type_cast(true)
- assert_nil column.type_cast(nil)
- end
-
- def test_type_cast_non_integer_to_integer
- column = Column.new("field", nil, Type::Integer.new)
- assert_nil column.type_cast([1,2])
- assert_nil column.type_cast({1 => 2})
- assert_nil column.type_cast((1..2))
- end
-
- def test_type_cast_activerecord_to_integer
- column = Column.new("field", nil, Type::Integer.new)
- firm = Firm.create(:name => 'Apple')
- assert_nil column.type_cast(firm)
- end
-
- def test_type_cast_object_without_to_i_to_integer
- column = Column.new("field", nil, Type::Integer.new)
- assert_nil column.type_cast(Object.new)
- end
-
- def test_type_cast_nan_and_infinity_to_integer
- column = Column.new("field", nil, Type::Integer.new)
- assert_nil column.type_cast(Float::NAN)
- assert_nil column.type_cast(1.0/0.0)
- end
-
- def test_type_cast_float
- column = Column.new("field", nil, Type::Float.new)
- assert_equal 1.0, column.type_cast("1")
- end
-
- def test_type_cast_decimal
- column = Column.new("field", nil, Type::Decimal.new)
- assert_equal BigDecimal.new("0"), column.type_cast(BigDecimal.new("0"))
- assert_equal BigDecimal.new("123"), column.type_cast(123.0)
- assert_equal BigDecimal.new("1"), column.type_cast(:"1")
- end
-
- def test_type_cast_binary
- column = Column.new("field", nil, Type::Binary.new)
- assert_equal nil, column.type_cast(nil)
- assert_equal "1", column.type_cast("1")
- assert_equal 1, column.type_cast(1)
- end
-
- def test_type_cast_time
- column = Column.new("field", nil, Type::Time.new)
- assert_equal nil, column.type_cast(nil)
- assert_equal nil, column.type_cast('')
- assert_equal nil, column.type_cast('ABC')
-
- time_string = Time.now.utc.strftime("%T")
- assert_equal time_string, column.type_cast(time_string).strftime("%T")
- end
-
- def test_type_cast_datetime_and_timestamp
- column = Column.new("field", nil, Type::DateTime.new)
- assert_equal nil, column.type_cast(nil)
- assert_equal nil, column.type_cast('')
- assert_equal nil, column.type_cast(' ')
- assert_equal nil, column.type_cast('ABC')
-
- datetime_string = Time.now.utc.strftime("%FT%T")
- assert_equal datetime_string, column.type_cast(datetime_string).strftime("%FT%T")
- end
-
- def test_type_cast_date
- column = Column.new("field", nil, Type::Date.new)
- assert_equal nil, column.type_cast(nil)
- assert_equal nil, column.type_cast('')
- assert_equal nil, column.type_cast(' ')
- assert_equal nil, column.type_cast('ABC')
-
- date_string = Time.now.utc.strftime("%F")
- assert_equal date_string, column.type_cast(date_string).strftime("%F")
- end
-
- def test_type_cast_duration_to_integer
- column = Column.new("field", nil, Type::Integer.new)
- assert_equal 1800, column.type_cast(30.minutes)
- assert_equal 7200, column.type_cast(2.hours)
- end
-
- def test_string_to_time_with_timezone
- [:utc, :local].each do |zone|
- with_timezone_config default: zone do
- column = Column.new("field", nil, Type::DateTime.new)
- assert_equal Time.utc(2013, 9, 4, 0, 0, 0), column.type_cast("Wed, 04 Sep 2013 03:00:00 EAT")
- end
- end
- end
-
- if current_adapter?(:SQLite3Adapter)
- def test_binary_encoding
- column = Column.new("field", nil, SQLite3Binary.new)
- utf8_string = "a string".encode(Encoding::UTF_8)
- type_cast = column.type_cast(utf8_string)
-
- assert_equal Encoding::ASCII_8BIT, type_cast.encoding
- end
- end
- end
- end
-end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 61bca976f7..9602252b2e 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -1,10 +1,8 @@
require "cases/helper"
class SchemaDumperTest < ActiveRecord::TestCase
- def setup
- super
+ setup do
ActiveRecord::SchemaMigration.create_table
- @stream = StringIO.new
end
def standard_dump
@@ -25,7 +23,8 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
def test_magic_comment
- assert_match "# encoding: #{@stream.external_encoding.name}", standard_dump
+ output = standard_dump
+ assert_match "# encoding: #{@stream.external_encoding.name}", output
end
def test_schema_dump
diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb
new file mode 100644
index 0000000000..5d5f442d3a
--- /dev/null
+++ b/activerecord/test/cases/types_test.rb
@@ -0,0 +1,159 @@
+require "cases/helper"
+require 'models/company'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class TypesTest < ActiveRecord::TestCase
+ def test_type_cast_boolean
+ type = Type::Boolean.new
+ assert type.type_cast('').nil?
+ assert type.type_cast(nil).nil?
+
+ assert type.type_cast(true)
+ assert type.type_cast(1)
+ assert type.type_cast('1')
+ assert type.type_cast('t')
+ assert type.type_cast('T')
+ assert type.type_cast('true')
+ assert type.type_cast('TRUE')
+ assert type.type_cast('on')
+ assert type.type_cast('ON')
+
+ # explicitly check for false vs nil
+ assert_equal false, type.type_cast(false)
+ assert_equal false, type.type_cast(0)
+ assert_equal false, type.type_cast('0')
+ assert_equal false, type.type_cast('f')
+ assert_equal false, type.type_cast('F')
+ assert_equal false, type.type_cast('false')
+ assert_equal false, type.type_cast('FALSE')
+ assert_equal false, type.type_cast('off')
+ assert_equal false, type.type_cast('OFF')
+ assert_equal false, type.type_cast(' ')
+ assert_equal false, type.type_cast("\u3000\r\n")
+ assert_equal false, type.type_cast("\u0000")
+ assert_equal false, type.type_cast('SOMETHING RANDOM')
+ end
+
+ def test_type_cast_string
+ type = Type::String.new
+ assert_equal "1", type.type_cast(true)
+ assert_equal "0", type.type_cast(false)
+ assert_equal "123", type.type_cast(123)
+ end
+
+ def test_type_cast_integer
+ type = Type::Integer.new
+ assert_equal 1, type.type_cast(1)
+ assert_equal 1, type.type_cast('1')
+ assert_equal 1, type.type_cast('1ignore')
+ assert_equal 0, type.type_cast('bad1')
+ assert_equal 0, type.type_cast('bad')
+ assert_equal 1, type.type_cast(1.7)
+ assert_equal 0, type.type_cast(false)
+ assert_equal 1, type.type_cast(true)
+ assert_nil type.type_cast(nil)
+ end
+
+ def test_type_cast_non_integer_to_integer
+ type = Type::Integer.new
+ assert_nil type.type_cast([1,2])
+ assert_nil type.type_cast({1 => 2})
+ assert_nil type.type_cast((1..2))
+ end
+
+ def test_type_cast_activerecord_to_integer
+ type = Type::Integer.new
+ firm = Firm.create(:name => 'Apple')
+ assert_nil type.type_cast(firm)
+ end
+
+ def test_type_cast_object_without_to_i_to_integer
+ type = Type::Integer.new
+ assert_nil type.type_cast(Object.new)
+ end
+
+ def test_type_cast_nan_and_infinity_to_integer
+ type = Type::Integer.new
+ assert_nil type.type_cast(Float::NAN)
+ assert_nil type.type_cast(1.0/0.0)
+ end
+
+ def test_type_cast_float
+ type = Type::Float.new
+ assert_equal 1.0, type.type_cast("1")
+ end
+
+ def test_type_cast_decimal
+ type = Type::Decimal.new
+ assert_equal BigDecimal.new("0"), type.type_cast(BigDecimal.new("0"))
+ assert_equal BigDecimal.new("123"), type.type_cast(123.0)
+ assert_equal BigDecimal.new("1"), type.type_cast(:"1")
+ end
+
+ def test_type_cast_binary
+ type = Type::Binary.new
+ assert_equal nil, type.type_cast(nil)
+ assert_equal "1", type.type_cast("1")
+ assert_equal 1, type.type_cast(1)
+ end
+
+ def test_type_cast_time
+ type = Type::Time.new
+ assert_equal nil, type.type_cast(nil)
+ assert_equal nil, type.type_cast('')
+ assert_equal nil, type.type_cast('ABC')
+
+ time_string = Time.now.utc.strftime("%T")
+ assert_equal time_string, type.type_cast(time_string).strftime("%T")
+ end
+
+ def test_type_cast_datetime_and_timestamp
+ type = Type::DateTime.new
+ assert_equal nil, type.type_cast(nil)
+ assert_equal nil, type.type_cast('')
+ assert_equal nil, type.type_cast(' ')
+ assert_equal nil, type.type_cast('ABC')
+
+ datetime_string = Time.now.utc.strftime("%FT%T")
+ assert_equal datetime_string, type.type_cast(datetime_string).strftime("%FT%T")
+ end
+
+ def test_type_cast_date
+ type = Type::Date.new
+ assert_equal nil, type.type_cast(nil)
+ assert_equal nil, type.type_cast('')
+ assert_equal nil, type.type_cast(' ')
+ assert_equal nil, type.type_cast('ABC')
+
+ date_string = Time.now.utc.strftime("%F")
+ assert_equal date_string, type.type_cast(date_string).strftime("%F")
+ end
+
+ def test_type_cast_duration_to_integer
+ type = Type::Integer.new
+ assert_equal 1800, type.type_cast(30.minutes)
+ assert_equal 7200, type.type_cast(2.hours)
+ end
+
+ def test_string_to_time_with_timezone
+ [:utc, :local].each do |zone|
+ with_timezone_config default: zone do
+ type = Type::DateTime.new
+ assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast("Wed, 04 Sep 2013 03:00:00 EAT")
+ end
+ end
+ end
+
+ if current_adapter?(:SQLite3Adapter)
+ def test_binary_encoding
+ type = SQLite3Binary.new
+ utf8_string = "a string".encode(Encoding::UTF_8)
+ type_cast = type.type_cast(utf8_string)
+
+ assert_equal Encoding::ASCII_8BIT, type_cast.encoding
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index 3f65f97524..caa499dfa2 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -5,6 +5,8 @@ class Array
# %w( a b c d ).from(2) # => ["c", "d"]
# %w( a b c d ).from(10) # => []
# %w().from(0) # => []
+ # %w( a b c d ).from(-2) # => ["c", "d"]
+ # %w( a b c ).from(-10) # => []
def from(position)
self[position, length] || []
end
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 09eb732ef7..0ae641d05b 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -105,8 +105,7 @@ module ActiveSupport
# We define it as a workaround to Ruby 2.0.0-p353 bug.
# For more information, check rails/rails#13055.
- # It should be dropped once a new Ruby patch-level
- # release after 2.0.0-p353 happens.
+ # Remove it when we drop support for 2.0.0-p353.
def ===(other) #:nodoc:
value === other
end
diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb
index 789a490831..bd1b818717 100644
--- a/activesupport/test/core_ext/array_ext_test.rb
+++ b/activesupport/test/core_ext/array_ext_test.rb
@@ -10,6 +10,8 @@ class ArrayExtAccessTests < ActiveSupport::TestCase
assert_equal %w( a b c d ), %w( a b c d ).from(0)
assert_equal %w( c d ), %w( a b c d ).from(2)
assert_equal %w(), %w( a b c d ).from(10)
+ assert_equal %w( d e ), %w( a b c d e ).from(-2)
+ assert_equal %w(), %w( a b c d e ).from(-10)
end
def test_to