Skip to content

Instantly share code, notes, and snippets.

@Telmo
Forked from wycats/personality.rb
Created April 18, 2012 19:48
Show Gist options
  • Save Telmo/2416067 to your computer and use it in GitHub Desktop.
Save Telmo/2416067 to your computer and use it in GitHub Desktop.
More technical details about the discussion at last nights meetup
# Just wanted to clarify my points at the meetup last night.
#
# There were two different issues intertwined:
# (1) Whether to use extend or "include as extend"
# (2) When using "include as extend", what is the simplest way to achieve the goal?
#
# My personal opinion is that the answer to (1) is "extend", not "include as extend", but that
# is just my personal opinion. My answer to (2) is a more empirical question.
# Using the "extend" approach. Again, I personally prefer the simplicity of this approach, but
# I can see why someone would want to abstract away the include vs. extend method from the users
# of the API.
module Personality
def watches(entertainment_source)
define_method("watch_#{entertainment_source}") do
puts "I'm watchin me some great #{entertainment_source}!"
end
end
def plays(game_type)
define_method("play_#{game_type}") do
puts "#{game_type} is fun!"
end
end
end
class Toddler
extend Personality
watches :octonauts
plays :dragonvale
end
# The instance_eval version of the "include as extend"
module Personality
# included hook
def self.included(base)
# use instance_eval to assign new methods to base
base.instance_eval do
# define the new methods inline
def watches(entertainment_source)
define_method("watch_#{entertainment_source}") do
puts "I'm watchin me some great #{entertainment_source}!"
end
end
def plays(game_type)
define_method("play_#{game_type}") do
puts "#{game_type} is fun!"
end
end
end
end
end
class Toddler
include Personality
watches :octonauts
plays :dragonvale
end
# The "extend ClassMethods" variant
module Personality
# included hook
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def watches(entertainment_source)
define_method("watch_#{entertainment_source}") do
puts "I'm watchin me some great #{entertainment_source}!"
end
end
def plays(game_type)
define_method("play_#{game_type}") do
puts "#{game_type} is fun!"
end
end
end
end
# API is identical to the "instance_eval" variant
class Toddler
include Personality
watches :octonauts
plays :dragonvale
end
# Also, my comments at the meetup were not about your part of the talk, but about an earlier, simpler
# demo. While I obviously prefer my approach (and use it in practice), I agree with you that the
# differences between my approach and the approach in your talk was largely stylistic.
#
# I appreciate your willingness to dive in and explore these approaches, as I agree with your thesis:
# the line between programming and metaprogramming in Ruby is pretty blurry, and understanding that
# Ruby code is almost entirely syntax around "self" context switches is a key insight to fully
# appreciating the beauty of the Ruby object model. I wrote a post about this a while ago, which talked
# about it a more technical, probably less approachable way:
# http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment