March #TMIL - Ruby class macros

My how the time flies. Still, I'd rather be late than abandon my New Year's resolution early! Here are some notes that have been sitting in this draft for the last two months.

Two quick tips

  • PC Keyboard Hack is a must-have extension for me. I find it's much nicer on your hands to avoid using the Return key on the right side of the keyboard. (You can make some remappings in the Keyboard->Modifier Keys panel in the OS X system preferences; however, Return is not an available choice for remapping Caps Lock.) 
  • Enable control-R backsearch in irb by adding this code to your ~/.editrc file :
    • bind "^R" em-inc-search-prev
    • Source

Class macros in Ruby

The explanation of class macros in Metaprogramming in Ruby by Paolo Perrotta really helped me understand the concept (and review and dive deep on many others - its explanation of the Ruby object model and coding idioms is great.). Let's say you manage the code for a death metal record label's applications, and the company decides to add folk rock artists to its roster. You'll need to make your code more generic, and warn developers that the method they called is now deprecated, then tell them what the new one is.

Perotta reminds the reader that although classes are typically thought of as containers for methods, when you open a class by creating a new instance (here, a Guitarist), other code will be executed. In this case, there is a direct call to the class method ::deprecate which then uses Module#define_method to dynamically add the deprecated methods to the class definition; the deprecated method then warns the user and calls the correct method. Another familiar class macro is attr_accessible in Rails 3, or Ruby's attr_accessor.

To begin making changes, the Guitarist class will now need a guitar, not an axe. The Guitarist will also play instead of shred. (Maybe you'll want more specific sub-classes for each genre, or add functionality with modules like Shreddable or Strummable, but that's a further step.)

class Guitarist
  def guitar

    # ...
  end

  def play(song)
    puts "Playing #{song}."
    # ...
  end

  def self.deprecate(old_method, new_method)
    define_method(old_method) do |*args, &block|
      warn "Warning: #{old_method}() is now deprecated. Use

            #{new_method}()."
      send(new_method, *args, &block)
    end
  end

  deprecate :axe, :guitar
  deprecate :shred, :play
end

g = Guitarist.new
g.shred(Song.new("Like a Rolling Stone")

# outputs the following:
# => "Warning: shred() is deprecated. Use play()."
# => "Playing Like a Rolling Stone."


That's all for this month, more to come.

Popular posts from this blog

Thinking About BIPA and Machine Learning

Changing PDF Metadata with Python

A New Serverless Look