Skip to content

Instantly share code, notes, and snippets.

@dissolved
Forked from bokmann/no_such_thing.rb
Created February 23, 2012 16:21
Show Gist options
  • Save dissolved/1893514 to your computer and use it in GitHub Desktop.
Save dissolved/1893514 to your computer and use it in GitHub Desktop.
The code of the talk from my Feb 22nd Arlington Ruby talk 'There is No Such Thing as Metaprogramming'.
# This is the code from my 'There is No Such Thing as Metaprogramming' talk,
# which premiered at the Arlington, VA Ruby Users Group on Feb 22nd.
# Without the deliver and walk-through to the solution below this example
# will be missing quite an important bit of content (mainly the tracking of
# 'self' while developing the solution, but it still a useful read.
# Here is the Toddler with no metajuju. Note that the developer, as well as
# the code, is completely unuaware of the interpreter. A developer with a
# background in compiled languages would be comfortable looking at this.
class Toddler
def play_dragonvale
puts "Dragonvale is fun!"
end
def watch_octonauts
puts "I'm watchin me some great Octonauts"
end
end
anthony = Toddler.new
anthony.play_peek_a_boo
anthony.watch_dora_the_explorer
#Now lets execute this line:
anthony.public_methods.sort
# is THAT metaprogramming? No, but it is code that is starting to reason
# about its own existence...
# In this example, are we metaprogramming yet? I don't think this is 'code
# that writes code' any more than the above example is, but it is 'code that is
# aware of the interpreter interpreting it'. A compile-driven developer would
# have a hard time reading this, but to the interpreter it is pretty much the
# same thing as above.
Object.const_set(:Toddler, Class.new).class_eval do
define_method("play_dragonvale") do
puts "Dragonvale is fun!"
end
define_method("watch_octonauts") do
puts "I'm watchin me some great Octonauts!"
end
end
anthony = Toddler.new
anthony.play_peek_a_boo
anthony.watch_dora_the_explorer
# and in the ~15 minutes of the talk, we work towards this solution. Notice that
# the end result of the Toddler class is compatible with the example above. This
# example by itself is the end result of the talk, but the important part of my
# talk is the journey getting here. The Nerd, Jock, and Toddler class have been
# written in a style sometimes called 'declarative programming' or an 'internal
# domain specific language'.
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 Nerd
extend Personality
watches :star_trek
watches :stargate
plays :minecraft
end
class Jock
extend Personality
watches :football
plays :football
plays :beer_pong
end
class Toddler
extend Personality
watches :octonauts
plays :dragonvale
end
dave = Nerd.new
dave.watch_star_trek
# I'm watching me some great star_trek!
dave.play_minecraft
# Minecraft is fun!
peter = Jock.new
peter.watch_football
# I'm watchin me some great football!
peter.play_beer_pong
#Beer Pong is fun!
anthony = Toddler.new
anthony.play_dragonvale
anthony.watch_octonauts
# as your own exercise, write a 'tells' method in personality so we can say
# things like:
tells :knock_knock_joke
tells :dirty_joke
tells :blonde_joke
# My major assertion of this talk is that people define Metaprogramming as 'code
# that writes code'. I assert that in Ruby, because we have the interpreter, all
# our code does that. In the first Toddler example, neither the code nor the
# developer is aware of that. In the second toddler example the code is aware of
# it, and in the Personality module we are using that knowledge of
# interpretation to our advantage. In Ruby, its not such much that we can 'write
# code that can write code', but that we can 'write code that reasons about its
# own interpretation'. This isn't metaprogramming, its just 'Ruby programming'.
# The term 'metaprogramming' is the lie that lets people see the truth - but it
# also sets up a barrier that people need to tear down, otherwise they are just
# compiler-driven developers in an interpreted language.
#
# Finally, we draw a lot of observations from the process of writing this
# code... notice that we have taken some complexity that was spread out amongst
# the original Toddler class and concentrated it into a module, leaving the new
# Toddler class very simple and self-descriptive. This technique for bundling up
# reusable code is powerful, and Rails itself is a great example of that. How
# many people, as they were learning Rails, didn't know or care whether
# 'has_many' or 'validates_presence_of' was a language keyword or a method call?
# The tradeoff: we are lowering the bar of our API users and raising the bar of
# our library maintainers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment