Metaprogramming basics post code
require 'metaclass_mp'
class TheParent; end
class Child < TheParent
def Child.the_eigenclass_method
"Hi from #{self}"
end
def an_instance_method
"Hi from #{self}"
end
end
puts "Child's instance methods: #{Child.instance_methods(false)}"
puts "Child's object id: #{Child.object_id}"
puts "Child's class: #{Child.class}"
puts "Child's superclass: #{Child.superclass}"
puts "Child's ancestors: #{Child.ancestors.join(', ')}"
puts '-'*20
puts "Child's singleton methods: #{Child.singleton_methods(false)}"
puts '-'*20
puts "Child's metaclass instance_methods: #{Child.metaclass.instance_methods(false).join(', ')}"
puts "Child's metaclass object id: #{Child.metaclass.object_id}"
puts "Child's metaclass class: #{Child.metaclass.class}"
puts "Child's metaclass superclass: #{Child.metaclass.superclass}"
puts "Child's metaclass ancestors: #{Child.metaclass.ancestors.join(', ')}"
class Person
def Person.the_eigenclass_method
"Hi from #{self}"
end
def an_instance_method
"Hi from #{self}"
end
end
# Person instances will have the methods defined in
# SomeClass.instance_methods(false), remember, a false
# parameter means that you only want to see the methods
# defined in that Person class and not the inherited ones.
puts Person.instance_methods(false)
# With SomeClass.singleton_methods(false) you'll see the
# eigenclass methods. The false parameter indicates that
# you only want to see the singleton methods defined in that
# class.
puts Person.singleton_methods(false)
class AnotherPerson
end
puts %{AnotherPerson singleton methods BEFORE: #{AnotherPerson.singleton_methods.join(', ')}}
puts %{AnotherPerson responds to a singleton method called "greet"?: #{AnotherPerson.singleton_methods.include?(:greet)}}
def AnotherPerson.greet
end
puts %{AnotherPerson singleton methods AFTER: #{AnotherPerson.singleton_methods.join(', ')}}
puts %{AnotherPerson responds to a singleton method called "greet"?: #{AnotherPerson.singleton_methods.include?(:greet)}}
class Person1
def Person1.greet
"hi from #{self}"
end
end
puts Person1.greet
class Person2
def self.greet
"hi from #{self}"
end
end
puts Person2.greet
class Person3
class << self
def greet
"hi from #{self}"
end
end
end
puts Person3.greet
name = "maria"
puts "I don't have singleton methods look: [#{name.singleton_methods}]"
def name.jump
"I'm #{self.capitalize} and I'm jumping"
end
puts "I have one singleton method: [#{name.singleton_methods}]"
puts name.jump
# If we create another string instace it won't respond to jump
new_name = "maria"
puts "#{new_name} jumps?: #{new_name.respond_to?(:jump)}"
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
puts [__LINE__, self, self.class, "I'm at program beginning"]
puts
class Greeter
def initialize
puts [__LINE__, self, self.class, "This method is invoked on a Greeter instance."]
end
def greet
puts [__LINE__, self, self.class, "This method is instance on a Greeter instance."]
puts 'Hi from the greeter'
end
end
puts [__LINE__, self, self.class, "I'm still the same object. But things are about to change."]
greet = Greeter.new
puts [__LINE__, self, self.class, "I'm again the same object."]
date = Time.new
def date.day
puts [__LINE__, self, self.class, "I'm invoked on a Time instance."]
super
end
puts [__LINE__, self, self.class, "I'm still the same object. But things are about to change."]
puts date.day
puts [__LINE__, self, self.class, "I'm again the same object."]
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
puts [__LINE__, self, self.class, "I'm at program beginning"]
puts
class Greeter
puts [__LINE__, self, self.class, "Class begin. Changing because of a class definition."]
def initialize
puts [__LINE__, self, self.class, "This method is invoked on a Greeter instance."]
end
puts [__LINE__, self, self.class, "Changing because of a class definition."]
def greet
puts [__LINE__, self, self.class, "This method is instance on a Greeter instance."]
p 'Hi from the greeter'
end
puts [__LINE__, self, self.class, "Class end. Changing because of a class definition."]
end
puts
puts [__LINE__, self, self.class, "I'm still the same object. But things are about to change."]
greet = Greeter.new
puts [__LINE__, self, self.class, "I'm again the same object."]
puts
module TestModule
puts [__LINE__, self, self.class, "Module begin."]
class InnerClass
puts [__LINE__, self, self.class, "Inner class."]
end
puts [__LINE__, self, self.class, "Module middle."]
module InnerModule
puts [__LINE__, self, self.class, "InnerModule."]
end
puts [__LINE__, self, self.class, "Module end."]
end
puts
puts [__LINE__, self, self.class, "I'm again the same object."]
# My cheap pretty print is a 'puts' wrapper that strives to improve my examples
# output while reducing some puts duplicity. I know it isn't perfect, so feel free
# to send my any suggestions.
MESSAGE = "At line: [%d]. \n\tI'm self [%s] with class [%s]. \n\t\tNote that: '%s'"
DIVISION = '-'*50
COMMON_RESPONSE = '--Common response--> %s <--'
# Basically it means that when this file is included, 'puts' has only to
# purposes:
#
# 1 - If called without parameters it will print a diving line
# 2 - If called with exactly 4 parameters where first one is an integer line number,
# remaining parameters are strings.
# The output is the formatted message from MESSAGE constant
def puts(*args)
super MESSAGE % args[0] if args && args[0].is_a?(Array) && args[0].size == 4
super DIVISION unless args[0]
super COMMON_RESPONSE % args[0]
end
require 'metaclass_mp'
# Step 5
# If the was not method named "m" after completing the search, then a method named
# method_missing is invoked instead. In order to find an appropriate definition of
# this method, the name resolution algorithm starts over at step 1. The Kernel module
# provides a default implementation of method_missing, so this second pass of name
# resolution is guaranteed to succeed.
class StringParent < String; end
class MyString < StringParent
def method_missing(method, *params)
puts "The method #{method} was not found"
end
end
name = MyString.new("maria")
puts "#{name}'s jump: #{name.jump}"
require 'metaclass_mp'
# Step 4
# If the instance method "m" was not found in its class or in its modules, then the search
# moves up the inheritance hierarchy of the super class. Step 2 and 3 are repeated for
# each class in the inheritance hierarchy until each ancestor class and its included modules
# have been searched.
class StringParent < String
def jump
"I'm jumping"
end
end
class MyString < StringParent
end
name = MyString.new("maria")
puts "#{name}'s jump: #{name.jump}"
puts "Responds to :jump ?: [%s]" % name.respond_to?(:jump)
puts "Does name has any singleton methods?: [%s]" % !name.singleton_methods.empty?
MyString.ancestors.each do |ancestor|
puts "Is :jump stored in ancestor \"#{ancestor}\"?: [%s]" % ancestor.instance_methods(true).include?('jump')
end
require 'metaclass_mp'
# Step 3
# If the method "m" is not found in its class, Ruby searches the instance methods of any
# modules included by the "o"'s class. If there are modules included, they are searched in
# the reverse of the order in which they are included.
module Jumper
def jump
"I'm jumping"
end
end
class String
include Jumper
end
name = "maria"
puts "#{name}'s jump: #{name.jump}"
puts "Responds to :jump ?: [%s]" % name.respond_to?(:jump)
puts "Does name has any singleton methods?: [%s]" % !name.singleton_methods.empty?
puts "Is :jump stored in name's class?: [%s]" % String.instance_methods(true).include?('jump')
puts "What modules were included?: [%s]" % String.included_modules.join(', ')
require 'metaclass_mp'
# Step 2
# If the method named "m" is not found in the eigenclass, Ruby searches the in "o"'s class for an
# instance method name "m".
class String
def jump
"I'm jumping"
end
end
name = "maria"
puts "#{name}'s jump: #{name.jump}"
puts "Responds to :jump ?: [%s]" % name.respond_to?(:jump)
puts "Does name has any singleton methods?: [%s]" % !name.singleton_methods.empty?
puts "Is :jump stored in name's class?: [%s]" % String.instance_methods(true).include?('jump')
require 'metaclass_mp'
# Step 1
# As the first step, Ruby checks the eigenclass of "o" for singleton method named "m".
name = "Maria"
def name.jump
"I'm jumping"
end
puts "#{name}'s jump: #{name.jump}"
puts "Responds to :jump ?: [%s]" % name.respond_to?(:jump)
puts "Does name has any singleton methods?: [%s]" % !name.singleton_methods.empty?
puts "Is :jump stored in name's eigenclass?: [%s]" % name.metaclass.instance_methods(true).include?('jump')
puts "Is :jump stored in name's class?: [%s]" % String.instance_methods(true).include?('jump')
class Object
def metaclass
class << self
self
end
end
end
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
require 'metaclass_mp'
class Greeter
def initialize(name)
@name = name
end
def greet
puts [__LINE__, self, self.class, "Inside an greet instance method"]
"Hi"
end
end
greeter = Greeter.new('Juanito')
puts greeter.greet
greeter.instance_eval do
puts [__LINE__, self, self.class, "Inside an instance_eval"]
puts [__LINE__, self, self.class, "And name equals: #{@name}"]
end
puts "Does it has any singleton methods?: [%s]" % !greeter.singleton_methods.empty?
greeter.instance_eval do
def mexican_greet
"Hola compa"
end
end
puts "Responds to :mexican_greet ?: [%s]" % greeter.respond_to?(:mexican_greet)
puts "Does it has any singleton methods?: [%s]" % !greeter.singleton_methods.empty?
puts "Is :mexican_greet stored in greeter's eigenclass?: [%s]" % greeter.metaclass.instance_methods(true).include?('mexican_greet')
puts "Is :mexican_greet stored in greeter's class?: [%s]" % Greeter.instance_methods(true).include?('mexican_greet')
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
def greet
# the implicit receiver is the "Object instance" main object
puts [__LINE__, self, self.class, "I'm at the implicit receiver"]
'Hi there'
end
# the implicit receiver is the "Object instance" main object
puts [__LINE__, self, self.class, "I'm at the implicit receiver"]
puts greet
class Greeter
def initialize
# the implicit receiver will be the "Greeter instance" 'not yet created' greet object
puts [__LINE__, self, self.class, "I'm the implicit receiver at [#{__method__}] method"]
greet
end
def greet
# the implicit receiver will be the "Greeter instance" 'not yet created' greet object
puts [__LINE__, self, self.class, "I'm the implicit receiver at [#{__method__}] method"]
puts 'Hi from the greeter'
end
end
greet = Greeter.new
def out_greet
# Here the **implicit receiver** is the *main* object. It is an Object class instance
# and it receives a *p* message.
p 'Hi there'
end
# Here the **implicit receiver** is the *main* object again. It is an Object class instance
# and it receives a *out_greet* message.
out_greet
class Greeter
def initialize
# the implicit receiver will be the "Greeter instance" 'not yet created' greet object
# Here the **implicit receiver** will be the *greeter instance* not yet created. It will be
# a Greeter class instance and it will receive a *greet* message.
greet
end
def greet
# Here the **implicit receiver** is the *main* object. It is an Object class instance
# and it receives a *p* message.
p 'Hi from the greeter'
end
end
greet = Greeter.new
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
class Greeter
def greet
puts [__LINE__, self, self.class, "I'm the explicit receiver"]
'Hi there'
end
end
greeter = Greeter.new
# The explicit receiver is the "Greeter instance" greet object.
puts greeter.greet
person = 'Boni'
# The explicit receiver is the "String instance" person object.
def person.swapcase
puts [__LINE__, self, self.class, "I'm the explicit receiver"]
super
end
puts person.swapcase
date = Time.new
def date.day
puts [__LINE__, self, self.class, "I'm the explicit receiver]"]
super
end
# The explicit receiver is the "Time instance" date object.
puts date.day
class Greeter
def greet
p 'Hi there'
end
end
greeter = Greeter.new
# Here the **explicit receiver** is the *greeter* object. It is a Greeter class instance
# and it receives a *greet* message.
greeter.greet
person = 'Boni'
# Here the **explicit receiver** is the *person* object. It is a String class instance
# and it receives a *swapcase* message.
p person.swapcase
# Here the **explicit receiver** is the *date* object. It is a Time class instance
# and it receives a *day* message.
date = Time.new
p date.day
require 'my_cheap_pretty_print'
# If the 'puts' syntax confuses you please look at my cheap pretty print for some help
require 'metaclass_mp'
class Greeter
def initialize(name)
@name = name
end
def greet
puts [__LINE__, self, self.class, "Inside an greet instance method"]
"Hi"
end
end
greeter = Greeter.new('Juanito')
puts greeter.greet
greeter.instance_eval do
puts [__LINE__, self, self.class, "Inside an instance_eval"]
puts [__LINE__, self, self.class, "And name equals: #{@name}"]
end
puts "Does it has any singleton methods?: [%s]" % !greeter.singleton_methods.empty?
greeter.instance_eval do
def mexican_greet
"Hola compa"
end
end
puts "Responds to :mexican_greet ?: [%s]" % greeter.respond_to?(:mexican_greet)
puts "Does it has any singleton methods?: [%s]" % !greeter.singleton_methods.empty?
puts "Is :mexican_greet stored in greeter's eigenclass?: [%s]" % greeter.metaclass.instance_methods(true).include?('mexican_greet')
puts "Is :mexican_greet stored in greeter's class?: [%s]" % Greeter.instance_methods(true).include?('mexican_greet')
class A
end
puts "--" + A.instance_methods(false).join(', ')
class A
def otro
end
end
puts A.instance_methods(false).join(', ') + "---"
A.class_eval do
puts self
def meth1
"some"
end
end
puts A.instance_methods(false)