Skip to content

Instantly share code, notes, and snippets.

Created June 6, 2014 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/efca2c57968d65de20bd to your computer and use it in GitHub Desktop.
Save anonymous/efca2c57968d65de20bd to your computer and use it in GitHub Desktop.
Assigning random data for class vs metaclasses
class Animal
def initialize
@heads = rand(10)
@legs = rand(10)
end
end
# irb(main):001:0> Animal.new
# => #<Animal:0x88cf1b0 @heads=3, @legs=4>
# irb(main):002:0> Animal.new
# => #<Animal:0x8b8b0fc @heads=5, @legs=9>
class Metaid
def self.metaclass; class << self; self; end; end
def self.traits( *arr )
return @traits if arr.empty?
attr_accessor( *arr )
arr.each do |a|
metaclass.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
class_eval do
define_method( :initialize ) do
self.class.traits.each do |k,v|
instance_variable_set("@#{k}", v)
end
end
end
end
end
class Animal < Metaid
heads rand(10)
legs rand(10)
end
# irb(main):001:0> Animal.new
# => #<Human:0x8138370 @heads=8, @legs=2>
# irb(main):002:0> Animal.new
# => #<Human:0x83ee790 @heads=8, @legs=2>
@judofyr
Copy link

judofyr commented Jun 7, 2014

You need to be aware of when a method is called.

Let's look at this line:

class Animal < Metaid
  heads rand(10)   # THIS LINE
end

This line does this: Animal.heads(rand(10)). It's just a regular method call. In a method call, all arguments are evaluated first. So it will first call rand(10) (and let's say it returns 8) and then it will invoke the Animal.heads method with 8 as the first argument.

The method Animal.heads looks like this:

define_method ( a ) do |val| # a = :heads is this method
  @traits ||= {}
  @traits[a] = val
end

Let's look at the case for Animal.heads(8):

# This is the values that are set
a = :heads
val = 8

# This is the method body
@traits ||= {}
@traits[a] = val

# The result is thus:
@traits ||= {}
@traits[:heads] = 8

Notice how the information about rand(10) is completely "gone".

You can do this same exercise for the class which does rand(10) in the initializer to see why it behaves differently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment