Fun with Ruby

This is why people love ruby so much… this is probably completely uneccesary but it was fun to figure out (off the clock… can’t really bill clients for crap like this if it takes you more than five minutes).

I needed to save a bunch of random boolean type settings for something on ActiveRain and the luddite in me almost just did some lame database solution (either joins or tons of columns) but I decided to play with ruby a bit instead.

Doing the whole bit mask thing in ruby and making it super easy to use in my code was pretty fun. I love this method_missing thing in Ruby. It allows you to do custom handle missing methods in your class and route them around to different methods.

Well, anyway, here’s the code – I’m sure it sucks… so tell me how to improve it.

class AgentSettings 

#doing the bitmask thing here... example
#   a = AgentSettings.new
#   puts a.blog_comments(5)
#   >true
#   puts a.bblog_comments(5)
#   >method missing error
#   puts a.blog_comments(16)
#   >false
#   puts a.blog_comments
#   >4  (2**2)
#
# We're using this to save settings like:
# agent.settings_email = blog_comments + associate_blocked = user wants emails on blog 
# comments and when someone blocks them

  #kind of like a default method for anthing in flags
  #  a = AgentSettings.new
  #  puts a.blog_comments     - 4
  #  puts a.blog_comments(5)  - true
  #  puts a.blog_comments(6)  - false
  
  def method_missing(method_symbol,value = nil)
    #convert the missing method symbol into a string
    w = method_symbol.id2name
    #we're only interested in this missing method if it exists in our flags array
    if !flags.index(w).nil?
      #if the value was missing with the missing method then return the flags value
      if value.nil?
        return bit_value(w)
      #otherwise do a check to see if the flag is in the value passed in
      else  
        return test(value,w)
      end
    end
    #throw an error as a last resort
    raise "Method #{w} not found because it's not in the flags list"
  end
  
  def flags
   #order is very imporant here - don't change it or you'll really screw up the values 
   #in the database - feel free to add to it though
   %w(email inbox blog_comments forum_comments 
       associate_added associate_blocked associate_unblocked 
       my_blog_comments contacts manual_score link_status)
  end

  #gets value for flag  
  def bit_value(word)
    return 2**(flags.index(word))
  end
  
  #tests agent.[email/inbox]_setting value against flag(s) to see if it's set
  #test(5,'blog_comments')
  #test(5,['blog_comments','associate_blocked'])
  def test(value,words)
    words.each do |w| 
      return false unless (value & (bit_value(w)) > 0)
    end
    return true
  end

  #convert everything to a friendly collection for use with check_box form helper
  def collection
    arr = Array.new
    flags.collect {|f| [f,bit_value(f)]}
  end  

 end