Good notes posted by Oleg

RSS feed
November 5, 2009
10 thanks

define_method with parameters

Just to be clear, you can do this:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something
end

This means same as:

def my_method(foo, bar)
  # do something
end

If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:

define_method(:my_method) do |foo, bar|
  bar ||= {}
  # do something
end
June 12, 2009
3 thanks

cattr_accessor_with_default

Class attribute assessors are neat if you want to set up modifiable constant-like varibles. This is how you’d normally set it up:

module MyPlugin
  class Conf
    @@awesome_level = 'huge'
    cattr_accessor :awesome_level
  end
end

Then you can call and modify it like this:

>> MyPlugin::Conf.awesome_level
=> 'huge'
>> MyPlugin::Conf.awesome_level = 'massive'
>> MyPlugin::Conf.awesome_level
=> 'massive'

If you have a pile of those accessors I’d do something like this (there might be a better way, but it works):

module MyPlugin
  class Conf
    def self.cattr_accessor_with_default(name, value = nil)
      cattr_accessor name
      self.send("#{name}=", value) if value
    end

    cattr_accessor_with_default :awesome_level, 'huge'
    cattr_accessor_with_default :speed_level, 'insane'
    cattr_accessor_with_default :indifferent_level
    cattr_accessor_with_default :craziness_level, 'nuts'
  end
end

This way you declare accessor and it’s optional default value on the same line

April 23, 2009
5 thanks

Handy shorthand for array manipulation

You may write something like this:

>> ['a', 'b', 'c'].collect{|letter| letter.capitalize}
=> ["A", "B", "C"]

But it looks so much nicer this way:

>> ['a', 'b', 'c'].collect(&:capitalize)
=> ["A", "B", "C"]
April 6, 2009
5 thanks

HTML entities in options

Unfortunately everything is escaped with ERB::Util#html_escape. Your only option is either manually construct options or compeletely overwrite this method.

April 6, 2009
6 thanks

Array clustering

Sometimes you don’t want to mangle sequence of an array and just want to group adjacent values. Here’s a nice method to do so (drop it in your initializers directory or something):

module Enumerable
  # clumps adjacent elements together
  # >> [2,2,2,3,3,4,2,2,1].cluster{|x| x}
  # => [[2, 2, 2], [3, 3], [4], [2, 2], [1]]
  def cluster
    cluster = []
    each do |element|
      if cluster.last && yield(cluster.last.last) == yield(element)
        cluster.last << element
      else
        cluster << [element]
      end
    end
    cluster
  end
end

Similarly you can do the clustering on more complex items. For instance you want to cluster Documents on creation date and their type:

Document.all.cluster{|document| [document.created_on, document.type]}
April 6, 2009
3 thanks

Take care when writing regex

When you want to validate a field for a continuous string you’d probably write something like this (if it’s really early in the morning and you didn’t have your coffee yet):

validates_format_of :something => /\w/

At the first sight it looks like it’s working because something = “blahblahblah” is valid. However, so is this: something = “blah meh 55”. It’s just that your regex matched a substring of the value and not the whole thing. The proper regex you’re looking for is actually:

validates_format_of :something => /^\w$/
March 5, 2009
7 thanks

String#match will match single token only

>> s = “{{person}} ate {{thing}}”

> “{{person}} ate {{thing}}”

>> r = /{{(.*?)}}/

> {{}}

>> s.match®.captures

> [“person”]

Using String#scan pulls out all tokens you were searching for:

>> s.scan®.flatten

> [“person”, “thing”]

February 9, 2009
5 thanks