Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
The black magic of
Ruby
metaprogramming
I am Cristian…
Gawyn

@cristianplanas
… and this is the story of
how I fell in love with
Ruby
It was 2011, when I read
this awesome book

(the smart part of this talk is based on it)
I was so excited that I
created my first gem just to
play with metaprogramming.
Easyregexp
http://github.com/Gawyn/easyregexp
Easyregexp
It was a regular expressions generator.
It relied heavily in metaprogramming.

It was never much useful.
Anyway, I felt like this
I mean, people who use
metaprogramming do have
superpowers.
They even know mysterious,
incomprehensible spells!
Repeat with me
The superclass of the eigenclass of an
object is the object’s class.
The superclass of the eigenclass of a
...
Sorry, today we won’t talk
about eigenclasses.
We will focus on the most
down to earth part of
metaprogramming.
When I started using
metaprogramming in my
production code, I
remembered an old movie.
In it, Mickey Mouse is the hard-working
apprentice of a powerful sorcerer.
One day, the sorcerer leaves,
and Mickey can play with
magic…
So let’s learn some tricks!
Monkey patching
Monkey patching
Adding code to an already defined
class.
An example

class String
def say_hello
p “hello”
end
end
“an string”. say_hello
=> “hello”
This means that we can
extend any class with our
own methods.
You can also redefine an
already existing method!
Dynamic methods
Dynamic methods
Define methods with an algorythm in
runtime.
A typical example

Imagine a class full of boring,
repeating methods.
A typical example
class User
ROLES = [“user”, “admin”]
# scopes for each role
scope :user, where(role: “user”)
scope :admi...
A typical example

Now let’s add some more roles:
ROLES = [“guest”, “user”,
“confirmed_user”, “moderator”,
“manager”, “adm...
Damn!
A typical example

Metaprogramming to the rescue!
A typical example
class User
ROLES = [“guest”, “user”, “confirmed_user”, “moderator”,
“manager”, “admin”, “superadmin”]
RO...
Great!
Evaluating strings
as code
It does just that: run a string as if it was
code.
class_eval and instance_eval do the
same, just changing the context.
We...
An example

class Movie
attr_reader :title_en, :title_es, :title_it, :title_pt
def title
send(“title_#{I18n.locale}”)
end
...
An example
class Movie
translate :title, :overview
def translate(*attributes)
attributes.each do |attr|
define_method attr...
You can even define
new methods like this!

String.class_eval(“def say_hello; puts „hello‟; end”)
“a string”.say_hello
#=>...
method_missing
method_missing
It’s the method that gets executed
when the called method it’s not found.
We can monkey patch it!
An example
class MetalDetector
def method_missing(method, *args, &block)
if method =~ /metal/
puts “Metal detected!”
else
...
A pretty exemplary use of
method_missing use are
Rails’ dynamic finders
(deprecated in Rails 4)
Calling finding methods with any
combination of attributes will work.

User.find_by_name_and_surname(“Mickey”, “Mouse”)
Us...
So metaprogramming is
pretty cool, isn’t it?
It can get cooler
Let’s check how
ActiveRecord defines its
setter methods
(in an abbreviated version)
Defining setters
def method_missing(method, *args, &block)
unless self.class.attribute_methods_generated?
self.class.defin...
Finally it gets to something like this:
def define_write_method(attr_name)
method_definition = “def #{attr_name}=(new_valu...
To know more
Episode 8 of Metaprogramming Ruby: Inside ActiveRecord
https://github.com/rails/rails/blob/master/activerecor...
But in the end of the movie, all the
magic backslashes…
Metaprogramming has its dangers
Unexpected
method override
It happens when you rewrite an
existing method changing its behavior
without checking the consequences.
That means all the code that rely in the
old method behavior will fail.
class Fixnum
alias :old_minus :alias :- :+
alias :+ :old_minus
end

4+3
#=> 1
5–2
#=> 7
Dynamic methods like the ones of the
example can also accidentally monkey
patch critical methods!
Code injection
through evaluation
If you use any kind of eval, remember to
think in all possible cases, specially if
users are involved.
You don’t want to e...
Even if users should be able to evaluate
code in your server, there are ways to
protect you:

Clean Rooms
Ghost methods
Methods working from inside
method_missing don’t “really” exist for
Ruby.
class MetalDetector
def method_missing(method, *args)
if method =~ /metal/
puts “Metal detected!”
else
super
end
end
end
m...
There is a work-around: to monkey
patch the respond_to? method.
Feels kinda hacky.
And still, it can be hard to maintain.
If you want to know more about the dangers of
method_missing, Paolo Perrotta (the author of
Metaprogramming Ruby) has a fu...
Some final
thoughts
1. I look pretty cool with Superman trunks.
2. Metaprogramming is a name
for different techniques: you
can use some and avoid others.
Personally, I use plenty of
dynamic methods and avoid
method_missing.
3. Just be sure of what you do
when you use it.
The sorcerer won’t come to save you!
Thanks!
The Black Magic of Ruby Metaprogramming
Upcoming SlideShare
Loading in …5
×
Upcoming SlideShare
One graph to rule them all - Facebook
Next
Download to read offline and view in fullscreen.

8

Share

Download to read offline

The Black Magic of Ruby Metaprogramming

Download to read offline

What is metaprogramming is and how can we use it in our everyday code - by Cristian Planas, CTO at Playfulbet

Related Books

Free with a 30 day trial from Scribd

See all

The Black Magic of Ruby Metaprogramming

  1. 1. The black magic of Ruby metaprogramming
  2. 2. I am Cristian… Gawyn @cristianplanas
  3. 3. … and this is the story of how I fell in love with Ruby
  4. 4. It was 2011, when I read this awesome book (the smart part of this talk is based on it)
  5. 5. I was so excited that I created my first gem just to play with metaprogramming.
  6. 6. Easyregexp http://github.com/Gawyn/easyregexp
  7. 7. Easyregexp It was a regular expressions generator. It relied heavily in metaprogramming. It was never much useful.
  8. 8. Anyway, I felt like this
  9. 9. I mean, people who use metaprogramming do have superpowers.
  10. 10. They even know mysterious, incomprehensible spells!
  11. 11. Repeat with me The superclass of the eigenclass of an object is the object’s class. The superclass of the eigenclass of a class is the eigenclass of the class’s superclass.
  12. 12. Sorry, today we won’t talk about eigenclasses.
  13. 13. We will focus on the most down to earth part of metaprogramming.
  14. 14. When I started using metaprogramming in my production code, I remembered an old movie.
  15. 15. In it, Mickey Mouse is the hard-working apprentice of a powerful sorcerer.
  16. 16. One day, the sorcerer leaves, and Mickey can play with magic…
  17. 17. So let’s learn some tricks!
  18. 18. Monkey patching
  19. 19. Monkey patching Adding code to an already defined class.
  20. 20. An example class String def say_hello p “hello” end end “an string”. say_hello => “hello”
  21. 21. This means that we can extend any class with our own methods.
  22. 22. You can also redefine an already existing method!
  23. 23. Dynamic methods
  24. 24. Dynamic methods Define methods with an algorythm in runtime.
  25. 25. A typical example Imagine a class full of boring, repeating methods.
  26. 26. A typical example class User ROLES = [“user”, “admin”] # scopes for each role scope :user, where(role: “user”) scope :admin, where(role: “admin”) # Identifying methods for each role def user? role == “user” end def admin? role == “admin” end end
  27. 27. A typical example Now let’s add some more roles: ROLES = [“guest”, “user”, “confirmed_user”, “moderator”, “manager”, “admin”, “superadmin”]
  28. 28. Damn!
  29. 29. A typical example Metaprogramming to the rescue!
  30. 30. A typical example class User ROLES = [“guest”, “user”, “confirmed_user”, “moderator”, “manager”, “admin”, “superadmin”] ROLES.each do |user_role| scope user_role.to_sym, where(role: user_role) define_method “#{user_role}?” do role == user_role end end end
  31. 31. Great!
  32. 32. Evaluating strings as code
  33. 33. It does just that: run a string as if it was code. class_eval and instance_eval do the same, just changing the context. We can also use it on an object using send.
  34. 34. An example class Movie attr_reader :title_en, :title_es, :title_it, :title_pt def title send(“title_#{I18n.locale}”) end end
  35. 35. An example class Movie translate :title, :overview def translate(*attributes) attributes.each do |attr| define_method attr do send(“#{attr}_#{I18n.locale}”) end end end end
  36. 36. You can even define new methods like this! String.class_eval(“def say_hello; puts „hello‟; end”) “a string”.say_hello #=> “hello”
  37. 37. method_missing
  38. 38. method_missing It’s the method that gets executed when the called method it’s not found.
  39. 39. We can monkey patch it!
  40. 40. An example class MetalDetector def method_missing(method, *args, &block) if method =~ /metal/ puts “Metal detected!” else super end end end metal_detector = MetalDetector.new metal_detector.bringing_some_metal_with_me # => “Metal detected!”
  41. 41. A pretty exemplary use of method_missing use are Rails’ dynamic finders (deprecated in Rails 4)
  42. 42. Calling finding methods with any combination of attributes will work. User.find_by_name_and_surname(“Mickey”, “Mouse”) User.find_by_surname_and_movie(“Mouse”, “Fantasia”) User.find_by_movie_and_job_and_name(“Fantasia”, “sorcerer”, “Mickey”)
  43. 43. So metaprogramming is pretty cool, isn’t it?
  44. 44. It can get cooler
  45. 45. Let’s check how ActiveRecord defines its setter methods (in an abbreviated version)
  46. 46. Defining setters def method_missing(method, *args, &block) unless self.class.attribute_methods_generated? self.class.define_attribute_methods if respond_to_without_attributes?(method) send(method, *args, &block) else super end else super end end
  47. 47. Finally it gets to something like this: def define_write_method(attr_name) method_definition = “def #{attr_name}=(new_value); write_attribute(„#{attr_name}‟, new_value); end” class_eval(method_definition, __FILE__, __LINE) end (as told, it’s a pretty abbreviated version)
  48. 48. To know more Episode 8 of Metaprogramming Ruby: Inside ActiveRecord https://github.com/rails/rails/blob/master/activerecord/lib/active_r ecord/attribute_methods.rb https://github.com/rails/rails/blob/master/activemodel/lib/active_ model/attribute_methods.rb https://github.com/rails/rails/blob/master/activerecord/lib/active_r ecord/attribute_methods/write.rb
  49. 49. But in the end of the movie, all the magic backslashes…
  50. 50. Metaprogramming has its dangers
  51. 51. Unexpected method override
  52. 52. It happens when you rewrite an existing method changing its behavior without checking the consequences.
  53. 53. That means all the code that rely in the old method behavior will fail.
  54. 54. class Fixnum alias :old_minus :alias :- :+ alias :+ :old_minus end 4+3 #=> 1 5–2 #=> 7
  55. 55. Dynamic methods like the ones of the example can also accidentally monkey patch critical methods!
  56. 56. Code injection through evaluation
  57. 57. If you use any kind of eval, remember to think in all possible cases, specially if users are involved. You don’t want to evaluate “User.destroy_all” on your own application!
  58. 58. Even if users should be able to evaluate code in your server, there are ways to protect you: Clean Rooms
  59. 59. Ghost methods
  60. 60. Methods working from inside method_missing don’t “really” exist for Ruby.
  61. 61. class MetalDetector def method_missing(method, *args) if method =~ /metal/ puts “Metal detected!” else super end end end metal_detector = MetalDetector.new metal_detector.metal # => “Metal detected!” metal_detector.respond_to?(:metal) #=> false
  62. 62. There is a work-around: to monkey patch the respond_to? method. Feels kinda hacky. And still, it can be hard to maintain.
  63. 63. If you want to know more about the dangers of method_missing, Paolo Perrotta (the author of Metaprogramming Ruby) has a full presentation about it: The revenge of method_missing()
  64. 64. Some final thoughts
  65. 65. 1. I look pretty cool with Superman trunks.
  66. 66. 2. Metaprogramming is a name for different techniques: you can use some and avoid others.
  67. 67. Personally, I use plenty of dynamic methods and avoid method_missing.
  68. 68. 3. Just be sure of what you do when you use it.
  69. 69. The sorcerer won’t come to save you!
  70. 70. Thanks!
  • billyjin2

    Aug. 5, 2019
  • jnillo9

    Oct. 19, 2015
  • GuilongYang

    Jun. 23, 2015
  • theexperiences

    Mar. 7, 2015
  • JamesZhang6

    Jul. 25, 2014
  • freshonnet

    May. 18, 2014
  • jishin

    Mar. 16, 2014
  • gawyn1986

    Feb. 23, 2014

What is metaprogramming is and how can we use it in our everyday code - by Cristian Planas, CTO at Playfulbet

Views

Total views

6,509

On Slideshare

0

From embeds

0

Number of embeds

3,514

Actions

Downloads

33

Shares

0

Comments

0

Likes

8

×