diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index 6e6d057d7f57d784b054310ed7deec42d561d1e8..420011d6f0180a349f5057bad4a112694c3bf11c 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -18,7 +18,7 @@ def remember; self.class.remembered << self; end module ClassMethods def remembered; @@remembered ||= []; end - def random_element; @@remembered.random_element; end + def sample; @@remembered.sample; end end end @@ -82,14 +82,14 @@ def generate_test_object_graphs [Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!) end 1.upto(NUM_SIMPLE_OBJS) do - PaintColor.create!(:non_poly_one_id => NonPolyOne.random_element.id) - PaintTexture.create!(:non_poly_two_id => NonPolyTwo.random_element.id) + PaintColor.create!(:non_poly_one_id => NonPolyOne.sample.id) + PaintTexture.create!(:non_poly_two_id => NonPolyTwo.sample.id) end 1.upto(NUM_SHAPE_EXPRESSIONS) do - shape_type = [Circle, Square, Triangle].random_element - paint_type = [PaintColor, PaintTexture].random_element - ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.random_element.id, - :paint_type => paint_type.to_s, :paint_id => paint_type.random_element.id) + shape_type = [Circle, Square, Triangle].sample + paint_type = [PaintColor, PaintTexture].sample + ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.sample.id, + :paint_type => paint_type.to_s, :paint_id => paint_type.sample.id) end end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 51381739eb48dd46e4c8819d4d307b395262cb95..715f6343fd5cc7c99f21615f9c4568323c24830e 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -265,7 +265,7 @@ def test_find_all_should_behave_like_select end def test_rand_should_select_a_random_object_from_proxy - assert Topic.approved.random_element.is_a?(Topic) + assert Topic.approved.sample.is_a?(Topic) end def test_should_use_where_in_query_for_named_scope diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 978f9f5c4efb7d0a1ec0a508d150f6499d12a814..2633d3fc663d0c1e478fed2e4d67bbcacf8adbf5 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,6 +1,7 @@ *2.3.9 (unreleased)* -* ... +* Deprecates Array#random_element in favor of Array#sample, backported from Ruby 1.9, thanks to +Marc-Andre Lafortune. [fxn] *2.3.8 (May 24, 2010)* diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb index 2ec1144a34ad55987d150a3cf315ad8cf78d0e9d..a0ca89f763d03de7e6177a0857b54abfb5c93af7 100644 --- a/activesupport/lib/active_support/core_ext/array/random_access.rb +++ b/activesupport/lib/active_support/core_ext/array/random_access.rb @@ -8,14 +8,34 @@ module RandomAccess # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555 # def rand # :nodoc: - ActiveSupport::Deprecation.warn 'Array#rand is deprecated and will be removed in Rails 3. Use "random_element" instead', caller - random_element + ActiveSupport::Deprecation.warn 'Array#rand is deprecated and will be removed in Rails 3. Use Array#sample instead', caller + sample end # Returns a random element from the array. - def random_element - self[Kernel.rand(length)] + def random_element # :nodoc: + ActiveSupport::Deprecation.warn 'Array#random_element is deprecated and will be removed in Rails 3. Use Array#sample instead', caller + sample end + + # Backport of Array#sample based on Marc-Andre Lafortune's http://github.com/marcandre/backports/ + def sample(n=nil) + return self[Kernel.rand(size)] if n.nil? + n = n.to_int + rescue Exception => e + raise TypeError, "Coercion error: #{n.inspect}.to_int => Integer failed:\n(#{e.message})" + else + raise TypeError, "Coercion error: #{n}.to_int did NOT return an Integer (was #{n.class})" unless n.kind_of? ::Integer + raise ArgumentError, "negative array size" if n < 0 + n = size if n > size + result = ::Array.new(self) + n.times do |i| + r = i + Kernel.rand(size - i) + result[i], result[r] = result[r], result[i] + end + result[n..size] = [] + result + end unless method_defined? :sample end end end diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index b17f7000888fcaa40646b96d9bef63064c0d8487..0f041ab93aeead3313b34705e962e1d93b51302a 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -324,19 +324,39 @@ def test_extract_options end class ArrayExtRandomTests < ActiveSupport::TestCase - def test_random_element_from_array - assert_nil [].random_element - - Kernel.expects(:rand).with(1).returns(0) - assert_equal 'x', ['x'].random_element + def test_sample_from_array + assert_nil [].sample + assert_equal [], [].sample(5) + assert_equal 42, [42].sample + assert_equal [42], [42].sample(5) + + a = [:foo, :bar, 42] + s = a.sample(2) + assert_equal 2, s.size + assert_equal 1, (a-s).size + assert_equal [], a-(0..20).sum{a.sample(2)} + + o = Object.new + def o.to_int; 1; end + assert_equal [0], [0].sample(o) + + o = Object.new + assert_raises(TypeError) { [0].sample(o) } + + o = Object.new + def o.to_int; ''; end + assert_raises(TypeError) { [0].sample(o) } - Kernel.expects(:rand).with(3).returns(1) - assert_equal 2, [1, 2, 3].random_element + assert_raises(ArgumentError) { [0].sample(-7) } end def test_deprecated_rand_on_array assert_deprecated { [].rand } end + + def test_deprecated_random_element_on_array + assert_deprecated { [].random_element } + end end class ArrayWrapperTests < Test::Unit::TestCase