Adventures with Ruby

3 times ActiveSupport 3

View Comments

Rails 3 is coming. All the big changes are spoken of elsewhere, so I’m going to mention some small changes. Here are 3 random new methods added to ActiveSupport:

presence

First up is Object#presence which is a shortcut for Object#present? && Object. It is a bit of a sanitizer. Empty strings and other blank values will return nil and any other value will return itself. Use this one and your code might be a tad cleaner.

"".presence # => nil
"foo".presence #=> "foo"

# without presence:
if params[:foo].present? && (foo = params[:foo])
  # ..
end

# with presence:
if foo = params[:foo].presence
  # ...
end

# The example Rails gives:
state   = params[:state]   if params[:state].present?
country = params[:country] if params[:country].present?
region  = state || country || 'US'
# ...becomes:
region = params[:state].presence || params[:country].presence || 'US'

I like this way of cleaning up you’re code. I guess it’s Rubyesque to feel the need to tidy and shorten your code like this.

uniq_by

Another funny one is Array.uniq_by (and it sister-with-a-bang-method). It works as select, but returns only the first element from the array that complies with the block you gave it. Here are some examples to illustrate that:

1, 2, 3, 4 ].uniq_by(&:odd?) # => [ 1, 2 ]

posts = %W"foo bar foo".map.with_index do |title, i|
  Post.create(:title => title, :index => i)
end
posts.uniq_by(&:title)
# => [ Post("foo", 0), Post("bar", 1) ] ( and not Post("foo", 2) )

some_array.uniq_by(&:object_id) # same as some_array.uniq

exclude?

And the final one for today is exclude? which is the opposite of include?. Nobody likes the exclamation mark before predicate methods.

# yuck:
!some_array.include?(some_value)
# better:
some_array.exclude?(some_value)

And it also works on strings:

# even more yuck:
!"The quick fox".include?("quick") # => false
# better:
"The quick fox".exclude?("quick") # => false

The full release notes of Rails 3 can be read here.

Written by Iain Hecker

February 3rd, 2010 at 10:42 am

Posted in iain.nl

  • http://zigzag.github.com zigzag

    [ 1, 2, 3, 4 ].uniq_by(&:odd?) # => [ 1, 2 ]

    Is it right?

    I checked the source code, it is written

    def uniq_by
    hash, array = {}, []
    each { |i| hash[yield(i)] ||= (array << i) }
    array
    end

    I think it should be:

    def uniq_by
    hash, array = {}, []
    each { |i| !yield(i) || hash[i] ||= (array << i) }
    array
    end

  • http://zigzag.github.com zigzag

    [ 1, 2, 3, 4 ].uniq_by(&:odd?) # => [ 1, 2 ]

    Is it right?

    I checked the source code, it is written

    def uniq_by
    hash, array = {}, []
    each { |i| hash[yield(i)] ||= (array << i) }
    array
    end

    I think it should be:

    def uniq_by
    hash, array = {}, []
    each { |i| !yield(i) || hash[i] ||= (array << i) }
    array
    end

  • http://zigzag.github.com zigzag

    or Maybe this version is more readable:


    def uniq_by
    hash, array = {}, []
    each { |i| hash[i] ||= (array << i) if yield(i)}
    array
    end

  • http://zigzag.github.com zigzag

    or Maybe this version is more readable:


    def uniq_by
    hash, array = {}, []
    each { |i| hash[i] ||= (array << i) if yield(i)}
    array
    end

  • http://caffeinedd.com/l33t-links/411-l33t-links-76 Caffeine Driven Development » Blog Archive » L33t Links #76

    [...] 3 times ActiveSupport 3, “3 random new methods added to ActiveSupport” [...]

  • http://iain.nl Iain Hecker

    @zigzag you’re wrong, because uniq_by isn’t just about it’s boolean value, but also other values, like string. For example:

    posts.uniq_by { |post| post.name.downcase }

    This is why the results of the block are used as keys in the temporary hash.

    I think the description in my post wasn’t really accurate. It’s not a select in that it’s not important if the block returns true or false. It will even treat false and nil differently:

    [ true, false, nil, 1, 2, nil, 2, false ].uniq_by { |x| x }
    #=> [ true, false, nil, 1, 2 ]
    
  • http://iain.nl Iain Hecker

    @zigzag you’re wrong, because uniq_by isn’t just about it’s boolean value, but also other values, like string. For example:

    posts.uniq_by { |post| post.name.downcase }

    This is why the results of the block are used as keys in the temporary hash.

    I think the description in my post wasn’t really accurate. It’s not a select in that it’s not important if the block returns true or false. It will even treat false and nil differently:

    [ true, false, nil, 1, 2, nil, 2, false ].uniq_by { |x| x }
    #=> [ true, false, nil, 1, 2 ]
    
  • http://zigzag.github.com zigzag

    @Iain Hecker
    Yes, you are right.

    I read it again, from the your “post name” example i figured out what the usage it is.
    Thanks.

  • http://zigzag.github.com zigzag

    @Iain Hecker
    Yes, you are right.

    I read it again, from the your “post name” example i figured out what the usage it is.
    Thanks.

  • http://codejoust.com/ CodeJoust – Iain

    Looks good – I know that rails 3.0beta1 is trunk, but any idea on when it will be released as a final release? Is it a good idea to start writing apps in it, or should I wait for the final release?
    I really like the changes, and it’ll be nicer to use more ruby to condense the code instead of relying on something else, along with shortcuts like present?, and various helper methods to replace ‘unless obj.nil? || obj.blank?’.

  • http://codejoust.com/ CodeJoust – Iain

    Looks good – I know that rails 3.0beta1 is trunk, but any idea on when it will be released as a final release? Is it a good idea to start writing apps in it, or should I wait for the final release?
    I really like the changes, and it’ll be nicer to use more ruby to condense the code instead of relying on something else, along with shortcuts like present?, and various helper methods to replace ‘unless obj.nil? || obj.blank?’.

  • http://iain.nl Iain Hecker

    You never have to rely on both obj.nil? and obj.blank? as blank? will check for nil? too…

    Anyway, there are a lot of plugins and gems still not working on Rails 3. I wouldn’t upgrade your app just yet. If you have plugins, please make sure they work and put a notice on http://railsplugins.org/

    I backport some of the useful ActiveSupport features from Rails 3 into existing Rails 2 apps.

  • http://iain.nl Iain Hecker

    You never have to rely on both obj.nil? and obj.blank? as blank? will check for nil? too…

    Anyway, there are a lot of plugins and gems still not working on Rails 3. I wouldn’t upgrade your app just yet. If you have plugins, please make sure they work and put a notice on http://railsplugins.org/

    I backport some of the useful ActiveSupport features from Rails 3 into existing Rails 2 apps.

  • http://iain.nl/2010/03/monkey-patch-of-the-month-group_by/ iain.nl » Monkey Patch of the Month: group_by

    [...] while back, I talked about new additions to ActiveSupport. And now, I have a confession to make: I like monkey patches! At least, as long as they’re [...]

  • http://freeforfree.info/freeforfree123/going-to-the-chapel-choosing-a-home-or-destination-wedding/ Going to the Chapel – Choosing a Home Or Destination Wedding

    [...] Couples today h&#1072&#957&#1077 many choices f&#959r wedding locations. Th&#1077&#1091 m&#965&#1109t &#1089h&#959&#959&#1109&#1077 between a community &#959r a destination wedding. More information: more info [...]

blog comments powered by Disqus
Fork me on GitHub