Skip to content

Commit

Permalink
Support for unified Integer class in Ruby 2.4+
Browse files Browse the repository at this point in the history
Ruby 2.4 unifies Fixnum and Bignum into Integer: https://bugs.ruby-lang.org/issues/12005

* Forward compat with new unified Integer class in Ruby 2.4+.
* Backward compat with separate Fixnum/Bignum in Ruby 2.2 & 2.3.
* Drops needless Fixnum distinction in docs, preferring Integer.
  • Loading branch information
jeremy committed May 19, 2016
1 parent 1a4deb9 commit 89e2f7e
Show file tree
Hide file tree
Showing 43 changed files with 116 additions and 119 deletions.
4 changes: 2 additions & 2 deletions actionpack/lib/action_dispatch/routing/mapper.rb
Expand Up @@ -120,7 +120,7 @@ def initialize(set, ast, defaults, controller, default_action, modyoule, to, for

if options_constraints.is_a?(Hash)
@defaults = Hash[options_constraints.find_all { |key, default|
URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
URL_OPTIONS.include?(key) && (String === default || Integer === default)
}].merge @defaults
@blocks = blocks
constraints.merge! options_constraints
Expand Down Expand Up @@ -824,7 +824,7 @@ def scope(*args)

if options[:constraints].is_a?(Hash)
defaults = options[:constraints].select do |k, v|
URL_OPTIONS.include?(k) && (v.is_a?(String) || v.is_a?(Fixnum))
URL_OPTIONS.include?(k) && (v.is_a?(String) || v.is_a?(Integer))
end

options[:defaults] = defaults.merge(options[:defaults] || {})
Expand Down
16 changes: 6 additions & 10 deletions actionpack/lib/action_dispatch/testing/assertion_response.rb
@@ -1,14 +1,7 @@
module ActionDispatch
# This is a class that abstracts away an asserted response.
# It purposely does not inherit from Response, because it doesn't need it.
# That means it does not have headers or a body.
#
# As an input to the initializer, we take a Fixnum, a String, or a Symbol.
# If it's a Fixnum or String, we figure out what its symbolized name.
# If it's a Symbol, we figure out what its corresponding code is.
# The resulting code will be a Fixnum, for real HTTP codes, and it will
# be a String for the pseudo-HTTP codes, such as:
# :success, :missing, :redirect and :error
# This is a class that abstracts away an asserted response. It purposely
# does not inherit from Response because it doesn't need it. That means it
# does not have headers or a body.
class AssertionResponse
attr_reader :code, :name

Expand All @@ -19,6 +12,9 @@ class AssertionResponse
error: "5XX"
}

# Accepts a specific response status code as an Integer (404) or String
# ('404') or a response status range as a Symbol pseudo-code (:success,
# indicating any 200-299 status code).
def initialize(code_or_name)
if code_or_name.is_a?(Symbol)
@name = code_or_name
Expand Down
2 changes: 1 addition & 1 deletion actionpack/test/assertions/response_assertions_test.rb
Expand Up @@ -35,7 +35,7 @@ def test_assert_response_predicate_methods
end
end

def test_assert_response_fixnum
def test_assert_response_integer
@response = FakeResponse.new 400
assert_response 400

Expand Down
2 changes: 1 addition & 1 deletion actionpack/test/controller/routing_test.rb
Expand Up @@ -626,7 +626,7 @@ def test_backwards
assert_equal '/pages/boo', url_for(rs, { :controller => 'pages', :action => 'boo' })
end

def test_route_with_fixnum_default
def test_route_with_integer_default
rs.draw do
get 'page(/:id)' => 'content#show_page', :id => 1

Expand Down
4 changes: 2 additions & 2 deletions actionpack/test/controller/test_case_test.rb
Expand Up @@ -553,7 +553,7 @@ def test_kwarg_params_passing_with_session_and_flash
assert_equal 'created', flash[:notice]
end

def test_params_passing_with_fixnums
def test_params_passing_with_integer
get :test_params, params: {
page: { name: "Page name", month: 4, year: 2004, day: 6 }
}
Expand All @@ -565,7 +565,7 @@ def test_params_passing_with_fixnums
)
end

def test_params_passing_with_fixnums_when_not_html_request
def test_params_passing_with_integers_when_not_html_request
get :test_params, params: { format: 'json', count: 999 }
parsed_params = ::JSON.parse(@response.body)
assert_equal(
Expand Down
2 changes: 1 addition & 1 deletion actionview/test/template/form_options_helper_test.rb
Expand Up @@ -798,7 +798,7 @@ def test_required_select_with_multiple_option
)
end

def test_select_with_fixnum
def test_select_with_integer
@post = Post.new
@post.category = ""
assert_dom_equal(
Expand Down
5 changes: 3 additions & 2 deletions activejob/lib/active_job/arguments.rb
Expand Up @@ -24,7 +24,7 @@ def original_exception
end

# Raised when an unsupported argument type is set as a job argument. We
# currently support NilClass, Fixnum, Float, String, TrueClass, FalseClass,
# currently support NilClass, Integer, Fixnum, Float, String, TrueClass, FalseClass,
# Bignum, BigDecimal, and objects that can be represented as GlobalIDs (ex: Active Record).
# Raised if you set the key for a Hash something else than a string or
# a symbol. Also raised when trying to serialize an object which can't be
Expand All @@ -34,7 +34,8 @@ class SerializationError < ArgumentError; end
module Arguments
extend self
# :nodoc:
TYPE_WHITELIST = [ NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum, BigDecimal ]
# Calls #uniq since Integer, Fixnum, and Bignum are all the same class on Ruby 2.4+
TYPE_WHITELIST = [ NilClass, String, Integer, Fixnum, Bignum, Float, BigDecimal, TrueClass, FalseClass ].uniq

# Serializes a set of arguments. Whitelisted types are returned
# as-is. Arrays/Hashes are serialized element by element.
Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/numericality.rb
Expand Up @@ -120,7 +120,7 @@ module HelperMethods
# * <tt>:only_integer</tt> - Specifies whether the value has to be an
# integer, e.g. an integral value (default is +false+).
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
# +false+). Notice that for fixnum and float columns empty strings are
# +false+). Notice that for Integer and Float columns empty strings are
# converted to +nil+.
# * <tt>:greater_than</tt> - Specifies the value must be greater than the
# supplied value.
Expand Down
Expand Up @@ -355,7 +355,7 @@ def test_validates_length_of_with_symbol
assert_equal ["Your essay must be at least 5 words."], t.errors[:content]
end

def test_validates_length_of_for_fixnum
def test_validates_length_of_for_integer
Topic.validates_length_of(:approved, is: 4)

t = Topic.new("title" => "uhohuhoh", "content" => "whatever", approved: 1)
Expand Down
Expand Up @@ -283,7 +283,7 @@ def delete(*records)
_options = records.extract_options!
dependent = _options[:dependent] || options[:dependent]

records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
delete_or_destroy(records, dependent)
end

Expand All @@ -294,7 +294,7 @@ def delete(*records)
# +:dependent+ option.
def destroy(*records)
return if records.empty?
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
delete_or_destroy(records, :destroy)
end

Expand Down
Expand Up @@ -597,7 +597,7 @@ def destroy_all
# Pet.find(1)
# # => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=1
#
# You can pass +Fixnum+ or +String+ values, it finds the records
# You can pass +Integer+ or +String+ values, it finds the records
# responding to the +id+ and executes delete on them.
#
# class Person < ActiveRecord::Base
Expand Down Expand Up @@ -661,7 +661,7 @@ def delete(*records)
#
# Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
#
# You can pass +Fixnum+ or +String+ values, it finds the records
# You can pass +Integer+ or +String+ values, it finds the records
# responding to the +id+ and then deletes them from the database.
#
# person.pets.size # => 3
Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/attribute_assignment.rb
Expand Up @@ -38,7 +38,7 @@ def assign_nested_parameter_attributes(pairs)
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum and
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and
# f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
def assign_multiparameter_attributes(pairs)
execute_callstack_for_multiparameter_attributes(
Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/attribute_methods.rb
Expand Up @@ -360,7 +360,7 @@ def [](attr_name)
# person = Person.new
# person[:age] = '22'
# person[:age] # => 22
# person[:age] # => Fixnum
# person[:age].class # => Integer
def []=(attr_name, value)
write_attribute(attr_name, value)
end
Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/attribute_methods/write.rb
Expand Up @@ -26,7 +26,7 @@ def __temp__#{safe_name}=(value)
end

# Updates the attribute identified by <tt>attr_name</tt> with the
# specified +value+. Empty strings for fixnum and float columns are
# specified +value+. Empty strings for Integer and Float columns are
# turned into +nil+.
def write_attribute(attr_name, value)
write_attribute_with_type_cast(attr_name, value, true)
Expand Down
Expand Up @@ -707,7 +707,7 @@ def add_index_length(option_strings, column_names, options = {})
case length
when Hash
column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
when Fixnum
when Integer
column_names.each {|name| option_strings[name] += "(#{length})"}
end
end
Expand Down Expand Up @@ -832,7 +832,7 @@ def configure_connection

# Increase timeout so the server doesn't disconnect us.
wait_timeout = @config[:wait_timeout]
wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout)

defaults = [':default', :default].to_set
Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/relation/calculations.rb
Expand Up @@ -93,7 +93,7 @@ def sum(column_name = nil, &block)
#
# There are two basic forms of output:
#
# * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
# * Single aggregate value: The single value is type cast to Integer for COUNT, Float
# for AVG, and the given column's type for everything else.
#
# * Grouped values: This returns an ordered hash of the values and groups them. It
Expand Down
Expand Up @@ -1315,7 +1315,7 @@ def test_deleting_a_item_which_is_not_in_the_collection
assert_equal 2, summit.client_of
end

def test_deleting_by_fixnum_id
def test_deleting_by_integer_id
david = Developer.find(1)

assert_difference 'david.projects.count', -1 do
Expand Down Expand Up @@ -1352,7 +1352,7 @@ def test_destroying
assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
end

def test_destroying_by_fixnum_id
def test_destroying_by_integer_id
force_signal37_to_load_all_clients_of_firm

assert_difference "Client.count", -1 do
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/cases/associations/join_model_test.rb
Expand Up @@ -598,7 +598,7 @@ def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete(Object.new) }
end

def test_deleting_by_fixnum_id_from_has_many_through
def test_deleting_by_integer_id_from_has_many_through
post = posts(:thinking)

assert_difference 'post.tags.count', -1 do
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/cases/attributes_test.rb
Expand Up @@ -38,7 +38,7 @@ class CustomPropertiesTest < ActiveRecord::TestCase
data.reload

assert_equal 2, data.overloaded_float
assert_kind_of Fixnum, OverloadedType.last.overloaded_float
assert_kind_of Integer, OverloadedType.last.overloaded_float
assert_equal 2.0, UnoverloadedType.last.overloaded_float
assert_kind_of Float, UnoverloadedType.last.overloaded_float
end
Expand Down
4 changes: 2 additions & 2 deletions activerecord/test/cases/base_test.rb
Expand Up @@ -940,7 +940,7 @@ def test_numeric_fields
assert_kind_of Integer, m1.world_population
assert_equal 6000000000, m1.world_population

assert_kind_of Fixnum, m1.my_house_population
assert_kind_of Integer, m1.my_house_population
assert_equal 3, m1.my_house_population

assert_kind_of BigDecimal, m1.bank_balance
Expand Down Expand Up @@ -968,7 +968,7 @@ def test_numeric_fields_with_scale
assert_kind_of Integer, m1.world_population
assert_equal 6000000000, m1.world_population

assert_kind_of Fixnum, m1.my_house_population
assert_kind_of Integer, m1.my_house_population
assert_equal 3, m1.my_house_population

assert_kind_of BigDecimal, m1.bank_balance
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/cases/fixtures_test.rb
Expand Up @@ -857,7 +857,7 @@ def test_supports_label_string_interpolation
assert_equal("X marks the spot!", pirates(:mark).catchphrase)
end

def test_supports_label_interpolation_for_fixnum_label
def test_supports_label_interpolation_for_integer_label
assert_equal("#1 pirate!", pirates(1).catchphrase)
end

Expand Down
Expand Up @@ -154,7 +154,7 @@ def test_native_types
assert_equal String, bob.first_name.class
assert_equal String, bob.last_name.class
assert_equal String, bob.bio.class
assert_equal Fixnum, bob.age.class
assert_kind_of Integer, bob.age
assert_equal Time, bob.birthday.class

if current_adapter?(:OracleAdapter)
Expand Down
4 changes: 2 additions & 2 deletions activerecord/test/cases/migration_test.rb
Expand Up @@ -180,7 +180,7 @@ def test_add_table_with_decimals
# is_a?(Bignum)
assert_kind_of Integer, b.world_population
assert_equal 6000000000, b.world_population
assert_kind_of Fixnum, b.my_house_population
assert_kind_of Integer, b.my_house_population
assert_equal 3, b.my_house_population
assert_kind_of BigDecimal, b.bank_balance
assert_equal BigDecimal("1586.43"), b.bank_balance
Expand All @@ -204,7 +204,7 @@ def test_add_table_with_decimals
assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
else
# - SQL standard is an integer
assert_kind_of Fixnum, b.value_of_e
assert_kind_of Integer, b.value_of_e
assert_equal 2, b.value_of_e
end

Expand Down
5 changes: 2 additions & 3 deletions activerecord/test/cases/query_cache_test.rb
Expand Up @@ -144,13 +144,12 @@ def test_cache_is_flat

def test_cache_does_not_wrap_string_results_in_arrays
Task.cache do
# Oracle adapter returns count() as Fixnum or Float
# Oracle adapter returns count() as Integer or Float
if current_adapter?(:OracleAdapter)
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter)
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
else
assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
end
Expand Down
6 changes: 3 additions & 3 deletions activerecord/test/cases/quoting_test.rb
Expand Up @@ -102,9 +102,9 @@ def test_quote_float
assert_equal float.to_s, @quoter.quote(float, nil)
end

def test_quote_fixnum
fixnum = 1
assert_equal fixnum.to_s, @quoter.quote(fixnum, nil)
def test_quote_integer
integer = 1
assert_equal integer.to_s, @quoter.quote(integer, nil)
end

def test_quote_bignum
Expand Down
2 changes: 0 additions & 2 deletions activesupport/lib/active_support/core_ext/class/subclasses.rb
Expand Up @@ -26,8 +26,6 @@ def descendants # :nodoc:

# Returns an array with the direct children of +self+.
#
# Integer.subclasses # => [Fixnum, Bignum]
#
# class Foo; end
# class Bar < Foo; end
# class Baz < Bar; end
Expand Down
Expand Up @@ -55,8 +55,7 @@ class Hash
#
# XML_TYPE_NAMES = {
# "Symbol" => "symbol",
# "Fixnum" => "integer",
# "Bignum" => "integer",
# "Integer" => "integer",
# "BigDecimal" => "decimal",
# "Float" => "float",
# "TrueClass" => "boolean",
Expand Down
10 changes: 8 additions & 2 deletions activesupport/lib/active_support/core_ext/numeric/conversions.rb
Expand Up @@ -134,6 +134,12 @@ def to_formatted_s(*args)
deprecate to_formatted_s: :to_s
end

[Fixnum, Bignum, Float, BigDecimal].each do |klass|
klass.prepend(ActiveSupport::NumericWithFormat)
# Ruby 2.4+ unifies Fixnum & Bignum into Integer.
if Integer == Fixnum
Integer.prepend ActiveSupport::NumericWithFormat
else
Fixnum.prepend ActiveSupport::NumericWithFormat
Bignum.prepend ActiveSupport::NumericWithFormat
end
Float.prepend ActiveSupport::NumericWithFormat
BigDecimal.prepend ActiveSupport::NumericWithFormat
Expand Up @@ -70,7 +70,7 @@ class Numeric
# Numbers are not duplicable:
#
# 3.duplicable? # => false
# 3.dup # => TypeError: can't dup Fixnum
# 3.dup # => TypeError: can't dup Integer
def duplicable?
false
end
Expand Down
2 changes: 1 addition & 1 deletion activesupport/lib/active_support/core_ext/object/try.rb
Expand Up @@ -99,7 +99,7 @@ class Object
#
# "a".try!(:upcase) # => "A"
# nil.try!(:upcase) # => nil
# 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Fixnum
# 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer
end

class Delegator
Expand Down
2 changes: 1 addition & 1 deletion activesupport/lib/active_support/core_ext/string/access.rb
@@ -1,5 +1,5 @@
class String
# If you pass a single Fixnum, returns a substring of one character at that
# If you pass a single integer, returns a substring of one character at that
# position. The first character of the string is at position 0, the next at
# position 1, and so on. If a range is supplied, a substring containing
# characters at offsets given by the range is returned. In both cases, if an
Expand Down

0 comments on commit 89e2f7e

Please sign in to comment.