My favorite ActiveSupport features

This is short and not so comprehensie list of my favorite ActiveSupport features.

Array#second

%i(a b) . second # => :b

Useful in ad-hoc scripts when you get primitive data from file or API. Together with map they give you some_array.map(&:second) to get what you want.

Array#extract_options

def options ( * args ) args . extract_options! end options ( 1 , 2 ) # => {} options ( 1 , 2 , a: :b ) # => {:a=>:b}

But with ruby 2.0 keyword arguments aka kwargs already present and ruby 1.9.3 support ending in February 2015 you should probably migrate to it:

def options ( * args , ** kwargs ) args kwargs end options ( 1 , 2 ) # => {} options ( 1 , 2 , a: :b ) # => {:a=>:b}

Array#in_groups_of and Array#in_groups

%w(1 2 3 4 5 6 7 8 9 10) . in_groups ( 3 ) { | group | p group } # ["1", "2", "3", "4"] # ["5", "6", "7", nil] # ["8", "9", "10", nil] %w(1 2 3 4 5 6 7 8 9 10) . in_groups_of ( 3 ) { | group | p group } # ["1", "2", "3"] # ["4", "5", "6"] # ["7", "8", "9"] # ["10", nil, nil]

Remember that you can add false as a second argument to avoid nil s in the arrays.

Array#wrap

Wraps its argument in an array unless it is already an array.

def method ( one_or_many ) Array . wrap ( one_or_many ). each ( & :do_something ) end method ( 1 ) method ([ 3 , 4 , 5 ])

Nicely explained in the documentation why it is better then usual ruby idioms

to_formatted_s on many types

BigDecimal . new ( "12.23" ). to_s #=> "0.1223E2" require 'active_support/all' BigDecimal . new ( "12.23" ). to_s #=> "12.23" BigDecimal . new ( "12.23" ). to_formatted_s #=> "12.23" Time :: DATE_FORMATS [ :w3c ] = "%Y-%m-%dT%H:%M:%S%:z" Time . now . to_s ( :w3c ) #=> "2015-02-25T17:51:53+00:00"

ActiveSupport overwrites to_s on my types to use its to_formatted_s version instead (especially when arguments provided)

#ago , #from_now

Time . now . ago ( 3 . months ) # => 2014-11-25 17:55:53 +0000 3 . months . ago # => 2014-11-25 17:56:00 +0000 3 . months . ago ( Time . now ) #=> 2014-11-25 17:56:03 +0000

beginning_of_... & end_of_...

%i( beginning_of_minute beginning_of_hour beginning_of_day beginning_of_week beginning_of_quarter beginning_of_month beginning_of_year end_of_minute end_of_hour end_of_day end_of_week end_of_month end_of_quarter end_of_year ) . each { | method | puts " #{ method } - #{ Time . now . public_send ( method ) } " } # beginning_of_minute - 2015-02-25 18:03:00 +0000 # beginning_of_hour - 2015-02-25 18:00:00 +0000 # beginning_of_day - 2015-02-25 00:00:00 +0000 # beginning_of_week - 2015-02-23 00:00:00 +0000 # beginning_of_quarter - 2015-01-01 00:00:00 +0000 # beginning_of_month - 2015-02-01 00:00:00 +0000 # beginning_of_year - 2015-01-01 00:00:00 +0000 # end_of_minute - 2015-02-25 18:03:59 +0000 # end_of_hour - 2015-02-25 18:59:59 +0000 # end_of_day - 2015-02-25 23:59:59 +0000 # end_of_week - 2015-03-01 23:59:59 +0000 # end_of_month - 2015-02-28 23:59:59 +0000 # end_of_quarter - 2015-03-31 23:59:59 +0000 # end_of_year - 2015-12-31 23:59:59 +0000

ActiveSupport::Duration

The class behind the little trick:

3 . seconds . class # => ActiveSupport::Duration

ActiveSupport::TimeWithZone

I hate time zones, but I love ActiveSupport::TimeWithZone . It is so easy to use.

Time . use_zone ( "Europe/Moscow" ){ Time . zone . now } # => Wed, 25 Feb 2015 21:09:12 MSK +03:00 Time . find_zone! ( "America/New_York" ). parse ( "2015-03-03 12:00:11" ) # => Tue, 03 Mar 2015 12:00:11 EST -05:00 Time . find_zone! ( "America/New_York" ). parse ( "2015-03-03 12:00:11" ). utc # => 2015-03-03 17:00:11 UTC Time . utc ( "2015-03-03 12:00:11" ). zone # => "UTC"

And I love that it can properly compare times from different timezones based on what moment of time they point to.

moment = Time . utc ( "2015-03-03 12:00:11" ) #=> 2015-01-01 00:00:00 UTC moment . in_time_zone ( "Europe/Warsaw" ) == moment . in_time_zone ( "America/Chicago" ) => true

Hash#except

Returns a hash that includes everything but the given keys.

hash = { a: true , b: false , c: nil } hash . except ( :c ) # => { a: true, b: false}

Except that I always think that this method is called #without .

Hash#slice

Slice a hash to include only the given keys.

{ a: 1 , b: 2 , c: 3 , d: 4 }. slice ( :a , :b ) # => {:a=>1, :b=>2}

If only I could remember that this method is not named #only :)

Hash#reverse_merge

options . reverse_merge ( size: 25 , velocity: 10 )

is equivalent to

{ size: 25 , velocity: 10 }. merge ( options )

This is particularly useful for default values.

Module#delegate

class Foo < ActiveRecord :: Base belongs_to :greeter delegate :hello , to: :greeter end

Reading this is way easier for me, compared to Forwardable#def_delegator .

With prefix and allow_nil options that you can use with it, it probably solves 95% of my delegation cases.

Object#blank? and Object#present? and Object#presence

nil . blank? # => true " " . blank? #=> true []. blank? => true title = commment [ :title ]. presence || "Missing title"

Never check for nil or empty string again.

Enumerable#sum

[ 2 , 3 , 5 ]. sum # => 10

ActiveSupport::Notifications

Too long for our short blogpost but check out instrumentation API

ActiveSupport::MessageVerifier

You can use it to generate and verify signed messages

@verifier = ActiveSupport :: MessageVerifier . new ( 's3Krit' , serializer: JSON ) @verifier . generate ( "private message" ) #=> "InByaXZhdGUgbWVzc2FnZSI=--43fc83190b28daf8df04c0b86ff2976931a6dcd2" @verifier . verify ( "InByaXZhdGUgbWVzc2FnZSI=--43fc83190b28daf8df04c0b86ff2976931a6dcd2" ) #=> "private message" @verifier . generate ( "a" => "private message" ) #=> "eyJhIjoicHJpdmF0ZSBtZXNzYWdlIn0=--b253af3e77622f743cf6804c870f4a95cbbd6f00" @verifier . verify ( "eyJhIjoicHJpdmF0ZSBtZXNzYWdlIn0=--b253af3e77622f743cf6804c870f4a95cbbd6f00" ) => { "a" => "private message" }

Summary

That’s it. You can browse entire ActiveSupport codebase quickly and easily at github

If you liked it, you may also enjoy Hidden features of Ruby you may not know about