Ben Scheirman

Menu

A Code Example of Ruby Metaprogramming

I’ll let the code speak for itself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class Animal
  def sound
    puts 'A non-descript sound is emitted from the animal'
  end
end

class Frog < Animal
  def sound
    puts 'Ribbit!'
  end
end

class Cat < Animal
  def sound
    puts 'Meow!'
  end
end

class Person
  attr_accessor :name
  def initialize(name)
    @injured = false
    @name = name
  end

  def injure!(by = nil)
    print "#{name}: Help I'm being attacked"
    print " by a #{by.class}" if by
    print '!'
    puts
    @injured = true
  end

  def injured?
    @injured
  end
end

module Aggression
  def self.apply_to_all_animals
    animal_classes = Module.constants.map { |x|
      Module.const_get(x) }.select { |x|
        x.respond_to?(:superclass) && x.superclass == Animal }
    animal_classes.each do |animal_class|
      animal_class.module_eval do
        include Aggression
      end
    end
  end

  def attack(person)
    sound
    puts "*Munch*"
    person.injure!(self)
    sound
    puts
  end
end

bonsai = Cat.new
brian = Frog.new
people = [Person.new('Ollie'), Person.new('manitoba98')]
begin
  bonsai.attack(people[0])
rescue => e
  puts 'Aww bonsai isn\'t capable of agressition. How cute'
end

begin
  brian.attack(people[0])
rescue => e
  puts 'Nor is brian awwww'
end
puts

# and then god said:
Aggression.apply_to_all_animals
bonsai.attack(people[0])
brian.attack(people[1])

Output:

Aww bonsai isn't capable of agressition. How cute
Nor is brian awwww
Meow!
*Munch*
Ollie: Help I'm being attacked by a Cat!
Meow!
Ribbit!
*Munch*
manitoba98: Help I'm being attacked by a Frog!
Ribbit!

Needless to say, I’m really enjoying Ruby.

Comments