Browse files

TimeWithZone#advance: use #any? instead of #detect

  • Loading branch information...
1 parent 887434f commit 5120429c3138d46490a1c4a611ebd93410f4f885 @gbuesing gbuesing committed Feb 9, 2009
Showing with 1 addition and 1 deletion.
  1. +1 −1 activesupport/lib/active_support/time_with_zone.rb
@@ -230,7 +230,7 @@ def ago(other)
def advance(options)
# If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
# otherwise advance from #utc, for accuracy when moving across DST boundaries
- if options.detect {|k,v| [:years, :weeks, :months, :days].include? k}
+ if options.any? {|k,v| [:years, :weeks, :months, :days].include? k}
method_missing(:advance, options)

10 comments on commit 5120429

nate commented on 5120429 Feb 9, 2009

Why any? over detect?


@nate: detect returns the object found, any? returns a boolean, which is all that’s needed here.


Enumerations are excessive when there is a clearer way to express what you mean:

unless (options.keys & [:years, :weeks, :months, :days]).empty?

(Or change unless to if and reverse the if and else clauses.)

Roman2K commented on 5120429 Feb 9, 2009

Josh: +1

Except that when there’s an else clause, I prefer using if instead of unless. In this case:

if (options.keys & [:years, :weeks, :months, :days]).any?

Even with no else clause, I find if foo.any? to be more obvious than unless foo.empty? which I consider a double negative.


How using a guard clause? Something like:

[:year, :weeks, :months, :days].each do |each|
  return method_missing(:advance, options) if options.has_key?(each)

Or coerce the options into a duration and let the duration decide.

raggi commented on 5120429 Feb 9, 2009
options.values_at(:year, :weeks, :months, :days).compact.empty?
raggi commented on 5120429 Feb 9, 2009

still, +1 on josh

Roman2K commented on 5120429 Feb 9, 2009

raggi: +1 for values_at! Plus, since any? returns true if any element is non-nil, your line can be simplified as (when using the if form):

options.values_at(:year, :weeks, :months, :days).any?

Productive conversation thread. I took the suggestion above, so now this line reads:

if options.values_at(:years, :weeks, :months, :days).any?

because it looked a little cleaner than the block syntax, and read nicely, i.e., “if any values at years, weeks, months, days, then …”

As a nice-to-have, it seems a bit faster — I did a simple benchmark, the results are kind of interesting:

Array#empty? looks to be faster than #any? (at least for this example), but it didn’t seem worth flipping around the logic of the if clause just to chase those extra few cycles.


Nice, I like the values_at trick to avoid the call to keys. Thanks for doing the benchmarks.

Please sign in to comment.