Continuing my recent theme of utilities and the like that I can’t do without…
For as long as I’ve been programming, I’ve built up a junk drawer of useful functions that I carry from project to project. The Ruby iteration of this is currently implemented as a Rails plugin that is one of the first things I add to each new project.
Here are a few of the utensils that I keep jammed in the back of the drawer.
One of the best pieces of advice I can give about keeping code clean within a method is to normalize the data first, then get on with the business of working with the data. The advantage is that it keeps the main line of your method from having all kinds of special case complications. I sometimes use this monkey-patch special to help within models.
class Integer
def to_active_record(ar_class)
ar_class.find(self)
end
def to_active_record_id
self
end
end
module ActiveRecord
class Base
def to_active_record(ar_class)
self
end
def to_active_record_id
self.id
end
end
endThis makes ActiveRecord::Base and Integer duck-type identical for to_active_record_id and
to_active_record (though I admit that requiring the class for to_active_record is a little bit ugly.
The main use case for this is in a model method that might get called from a controller with a parameter (which, come to think of it, might argue for a string version) or from elsewhere in the model with a full record. Typical use is like this (I realize there are other ways of doing this…):
def has_subscription_for(sub_or_id)
sub_id = sub_or_id.to_active_record_id
subscriptions.map(&:id).includes?(sub_id)
endMoving on… I do a lot of date processing, and use the excellent Chronic gem for a lot of it (makes for a nice client demo, when you type in “last Thursday” into a form and it works…). I use the following methods added to Date to cleanly integrate Chronic into Date parsing.
class Date
def self.parse_or_nil(string, comp = false)
parse(string, comp)
rescue ArgumentError
nil
end
def self.smart_parse(string, default = nil, comp = false)
default ||= Date.today
return default if string.blank?
date = Chronic.parse(string, :context => :past) ||
Chronic.parse(string.gsub(",", " "), :context => :past) ||
Date.parse_or_nil(string, comp) ||
default
return default if date.blank?
date.to_date
end
end
class String
def smart_to_date
Date.smart_parse(self)
end
endThe smart_parse method takes a default to return if the string doesn’t parse to a date. It calls Chronic first (the dual call to Chronic is a workaround for a bug in Chronic), then tries regular Date parsing. The string method is there for a slight readability boost.
Here’s a quickie that I wind up using a lot:
class Object
def in?(*enumerable)
enumerable.flatten.include?(self)
end
def not_in?(*enumerable)
!in?(*enumerable)
end
endUsage looks like foo.in?("a", "b", "c"). The flatten makes it flexible, but does adds some weirdness of the object is itself an array, which I’d consider an unusual case.
This one gets used from time to time:
class String
def is_true?
%w(true t 1 y yes).include?(self.to_s.downcase)
end
endI think I originally wrote this to convert from a legacy database which was giving me boolean true as “1″.
Finally, a test helper I wind up using a lot, this goes in the test_helper.rb file inside TestCase
def assert_methods(actual, expected = {})
expected.each do |key, value|
assert_equal(actual.send(key), value,
"Expected <#{value}> for #{key}, got <#{actual.send(key)}>")
end
endIt’s a good way to cover a lot of behavior at once, again, testing a data migration is a common use case, or when creating an entire object in the code — basically, it’s a flexible assert_equals. Usage is like this:
assert_entity(actual, :product => product, :date => product.date,
:description => product.description, :price => product.price)What’s in your junk drawer?


in has_subscription_for I would prefer to use
self.subscription_ids.include?(sub_or_id.to_active_record_id)
Works only if self object has many subscription asociation