I think I first discovered the joy of take
and drop
in my journeys through Haskell. But it appears that, since 2008 at least, we have had the pleasure of using them in Ruby too.
Need the first or last N
elements from an Enumerable
. Easy!
[sourcecode language=“ruby” light=“true”] ary = (1..100).to_a ary.take(5) # => [1, 2, 3, 4, 5] ary.drop(95) # => [96, 97, 98, 99, 100]
range = (1..100) range.take(5) # => [1, 2, 3, 4, 5] range.drop(95) # => [96, 97, 98, 99, 100]
hsh = {:foo => 1, :bar => 2, :baz => 3} hsh.take(1) # => [[:bar, 2]] hsh.drop(2) # => [[:foo, 1]] [/sourcecode]
The real magic is when you use take
along with other Enumerable
goodies like select
and map
. Here’s one of my personal favorites amongst the code I wrote in 2010:
[sourcecode language=“ruby” light=“true” highlight=“12,13,14”] class QueryTracer < ActiveSupport::LogSubscriber
ACCEPT = %r{^(app|config|lib)}.freeze FRAMES = 5 THRESHOLD = 300 # In ms
def sql(event) return unless event.duration > THRESHOLD callers = Rails. backtrace_cleaner. clean(caller). select { |f| f =~ ACCEPT }. take(FRAMES). map { |f| f.split(":").take(2).join(":") }. join(" | ")
# Shamelessly stolen from ActiveRecord::LogSubscriber
warning = color("SLOW QUERY", RED, true)
name = '%s (%.1fms)' % [event.payload[:name], event.duration]
sql = event.payload[:sql].squeeze(' ')
warn " #{warning}"
warn " #{name} #{sql}"
warn " Trace: #{callers}"
end
end
QueryTracer.attach_to :active_record [/sourcecode]
This little ditty is awesome because:
- It's super-practical. Drop this in your Rails 3 app, tail your production log, see the slow queries, go to the method in your app calling it, and fix it. Easy.
- It only activates itself when it's needed. Queries that execute quickly return immediately.
- No framework spelunking required. Rails 3's notification system handles all of it. Rails' backtace cleaner gizmo even makes the backtraces much nicer to read.
- It chains methods to make something that reads like a nice, concise functional program.
Enumerable
joy, read up on each_cons
.