Refactor to use Ruby standard library

18 Sep 2013

Updates:

Sometimes I see code that does some unnecessary computation simply because it doesn't use the Ruby standard library effectively:

widgits = get_widgits.select {|w| w.cromulent? }.first

This can be replaced with:

widgits = get_widgits.detect {|w| w.cromulent? }

Not a big deal, but it saves a few opcodes and more clearly shows the intent. Of course, this refactoring only works if the cromulent? method that's called in the block doesn't have side effects.

I'm trying to think of more cases like this. Maybe they're called "ruby standard library micro antipatterns" or "ruby un-idioms" or something. A difficulty is that there are so many ways to write code that doesn't fully take advantage of the standard library (which, as Michael Evans noted, is harder in Ruby because you actually have to read the docs rather than relying on typing a dot and waiting for the method list to pop up). So I'm having trouble zeroing in on a set of common instances.

There are control flow antipatterns like this one described by Stephen Chen, where the code can be simplified:

# replace this with:
# return foo && bar
if foo && bar
  true
else
  false
end

That sort of thing could be detected with static analysis. But I'm more interested in library misuse, not language misuse. Here's an actual bug; this is not quite what I'm looking for, but closer:

x = [1,2,3]
x.reject {|y| y > 2 } # oops meant to use reject!
here_are_some_small_numbers(x)

This is "discarded return value" and we could catch it with static analysis. Along the same lines, in the example below the return value of strip! is being used unnecessarily:

x = "foo "
x = x.strip!  # can simplify by removing the assignment

This is still closer to what I'm aiming for.

Can you think of any more? Send them to @tcopeland.