diff options
author | Brian Christian <brchristian@gmail.com> | 2016-02-09 16:02:08 -0800 |
---|---|---|
committer | Brian Christian <brchristian@gmail.com> | 2016-02-09 16:02:08 -0800 |
commit | c74045cf0771ab51dfeca94b30c447cab6193e60 (patch) | |
tree | 277b16c5e586866a7284b63ac753035a7f81dd3e | |
parent | b5eb2423b6e431ba53e3836d58449e7e810096b4 (diff) | |
download | rails-c74045cf0771ab51dfeca94b30c447cab6193e60.tar.gz rails-c74045cf0771ab51dfeca94b30c447cab6193e60.tar.bz2 rails-c74045cf0771ab51dfeca94b30c447cab6193e60.zip |
allow Array.penultimate and Array.antepenultiate access methods
8 files changed, 78 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 9f2c7292ea..6927f1fca3 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -136,6 +136,14 @@ module ActiveRecord first_nth_or_last(:forty_two, *args) end + def antepenultimate(*args) + first_nth_or_last(:antepenultimate, *args) + end + + def penultimate(*args) + first_nth_or_last(:penultimate, *args) + end + def last(*args) first_nth_or_last(:last, *args) end diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index fe693cfbb6..5f3d4c6735 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -197,6 +197,16 @@ module ActiveRecord @association.forty_two(*args) end + # Same as #first except returns only the third-to-last record. + def antepenultimate(*args) + @association.antepenultimate(*args) + end + + # Same as #first except returns only the second-to-last record. + def penultimate(*args) + @association.penultimate(*args) + end + # Returns the last record, or the last +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index 1f429cfd94..0a82832f56 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -1,7 +1,7 @@ module ActiveRecord module Querying delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, to: :all - delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, to: :all + delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, :antepenultimate, :antepenultimate!, :penultimate, :penultimate!, to: :all delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all delegate :find_by, :find_by!, to: :all diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index d48bcea28a..90e05dc340 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -242,6 +242,38 @@ module ActiveRecord find_nth! 41 end + # Find the third-to-last record. + # If no order is defined it will order by primary key. + # + # Person.antepenultimate # returns the third-to-last object fetched by SELECT * FROM people + # Person.offset(3).antepenultimate # returns the third-to-last object from OFFSET 3 + # Person.where(["user_name = :u", { u: user_name }]).antepenultimate + def antepenultimate + find_nth -3 + end + + # Same as #antepenultimate but raises ActiveRecord::RecordNotFound if no record + # is found. + def antepenultimate! + find_nth! -3 + end + + # Find the second-to-last record. + # If no order is defined it will order by primary key. + # + # Person.penultimate # returns the second-to-last object fetched by SELECT * FROM people + # Person.offset(3).penultimate # returns the second-to-last object from OFFSET 3 + # Person.where(["user_name = :u", { u: user_name }]).penultimate + def penultimate + find_nth -2 + end + + # Same as #penultimate but raises ActiveRecord::RecordNotFound if no record + # is found. + def penultimate! + find_nth! -2 + end + # Returns true if a record exists in the table that matches the +id+ or # conditions given, or false otherwise. The argument can take six forms: # diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index ecaa521283..4e9f7c330a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -408,6 +408,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end assert_no_queries do + bulbs.antepenultimate() + bulbs.antepenultimate({}) + end + + assert_no_queries do + bulbs.penultimate() + bulbs.penultimate({}) + end + + assert_no_queries do bulbs.last() bulbs.last({}) end diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index 3177d8498e..e413acddc5 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -73,4 +73,18 @@ class Array def forty_two self[41] end + + # Equal to <tt>self[-3]</tt>. + # + # %w( a b c d e ).antepenultimate # => "c" + def antepenultimate + self[-3] + end + + # Equal to <tt>self[-2]</tt>. + # + # %w( a b c d e ).penultimate # => "d" + def penultimate + self[-2] + end end diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index 3f1e0c4cb4..d7a3fb56c2 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -26,6 +26,8 @@ class AccessTest < ActiveSupport::TestCase assert_equal array[3], array.fourth assert_equal array[4], array.fifth assert_equal array[41], array.forty_two + assert_equal array[-3], array.antepenultimate + assert_equal array[-2], array.penultimate end def test_without diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 0aca6db9b6..91cf48a680 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2240,7 +2240,7 @@ Similarly, `from` returns the tail from the element at the passed index to the e [].from(0) # => [] ``` -The methods `second`, `third`, `fourth`, and `fifth` return the corresponding element (`first` is built-in). Thanks to social wisdom and positive constructiveness all around, `forty_two` is also available. +The methods `second`, `third`, `fourth`, and `fifth` return the corresponding element (`first` is built-in), while `penultimate` and `antepenultimate` return the second-to-last and third-to-last elements, respectively. Thanks to social wisdom and positive constructiveness all around, `forty_two` is also available. ```ruby %w(a b c d).third # => "c" |