METAPROGRAMMING
THE BASICS
class Developer def self.backend "I am backend developer" end def frontend "I am frontend developer" end end
p Developer.class # Class p Class.superclass # Module p Module.superclass # Object p Object.superclass # BasicObject
class Developer p self end # Developer
class Developer def frontend self end end p Developer.new.frontend # #<Developer:0x2c8a148>
class Developer def self.backend self end end p Developer.backend # Developer
METACLASSES
example = "I'm a string object" def example.something self.upcase end p example.something # I'M A STRING OBJECT
example = "I'm a string object" class << example def example.something self.upcase end end
class Developer def self.backend "I am backend developer" end end
def Developer.backend "I am backend developer" end
class Developer class << self def backend "I am backend developer" end end end
class << Developer def backend "I am backend developer" end end
class Object def metaclass_example class << self self end end end
class Developer def frontend p "inside instance method, self is: " + self.to_s end class << self def backend p "inside class method, self is: " + self.to_s end end end developer = Developer.new developer.frontend # "inside instance method, self is: #<Developer:0x2ced3b8>" Developer.backend # "inside class method, self is: Developer" p "inside metaclass, self is: " + developer.metaclass_example.to_s # "inside metaclass, self is: #<Class:#<Developer:0x2ced3b8>>"
p developer.class.instance_methods false # [:frontend] p developer.class.metaclass_example.instance_methods false # [:backend]
p developer.class.singleton_class.instance_methods false # [:backend]
DEFINING METHODS USING CLASS_EVAL AND INSTANCE_EVAL
class Developer end Developer.instance_eval do p "instance_eval - self is: " + self.to_s def backend p "inside a method self is: " + self.to_s end end # "instance_eval - self is: Developer" Developer.backend # "inside a method self is: Developer"
Developer.class_eval do p "class_eval - self is: " + self.to_s def frontend p "inside a method self is: " + self.to_s end end # "class_eval - self is: Developer" p developer = Developer.new # #<Developer:0x2c5d640> developer.frontend # "inside a method self is: #<Developer:0x2c5d640>"
DEFINING MISSING METHODS ON THE FLY
class Developer define_method :frontend do |*my_arg| my_arg.inject(1, :*) end class << self def create_backend singleton_class.send(:define_method, "backend") do "Born from the ashes!" end end end end developer = Developer.new p developer.frontend(2, 5, 10) # => 100 p Developer.backend # undefined method 'backend' for Developer:Class (NoMethodError) Developer.create_backend p Developer.backend # "Born from the ashes!"
class Developer def coding_frontend p "writing frontend" end def coding_backend p "writing backend" end end developer = Developer.new developer.coding_frontend # "writing frontend" developer.coding_backend # "writing backend"
class Developer ["frontend", "backend"].each do |method| define_method "coding_#{method}" do p "writing " + method.to_s end end end developer = Developer.new developer.coding_frontend # "writing frontend" developer.coding_backend # "writing backend"
class Developer def method_missing method, *args, &block return super method, *args, &block unless method.to_s =~ /^coding_\w+/ self.class.send(:define_method, method) do p "writing " + method.to_s.gsub(/^coding_/, '').to_s end self.send method, *args, &block end end developer = Developer.new developer.coding_frontend developer.coding_backend developer.coding_debug