Created
April 12, 2012 18:07
-
-
Save wycats/2369717 to your computer and use it in GitHub Desktop.
More technical details about the discussion at last nights meetup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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