Skip to content

Instantly share code, notes, and snippets.

@joalbertg
Last active August 10, 2020 17:36
Show Gist options
  • Save joalbertg/f7c8ef547828e2b61df1cdadc00508bc to your computer and use it in GitHub Desktop.
Save joalbertg/f7c8ef547828e2b61df1cdadc00508bc to your computer and use it in GitHub Desktop.
ruby: Metaprogramming
# https://medium.com/@hackvan/entendiendo-la-metaprogramaci%C3%B3n-con-ruby-7a0360ee67e7
=begin
# Class implementa algunos interesantes métodos de introspección como:
class # Retorna el objeto de clase a la que pertenece el objeto instanciado
superclass # Retorna el objeto de clase del cual hereda la clase del objeto instanciado
ancestors # Retorna un Array con el listado de la cadena de ancestros
instance_variables # Retorna un Array con el listado de las variables de instancia creadas
# en la clase del objeto.
instance_variable_get(name) # Retorna el valor de una variable de instancia creada en la clase
# del objeto.
class_variables # Retorna un Array con el listado de las variables de clase creadas en
# la clase del objeto.
methods # Retorna un Array con el listado de los metodos implementados dentro
# de la clase del objeto.
public_methods # Retorna un Array con el listado de los metodos publicos implementados
# dentro de la clase del objeto.
# Y de reflexión como:
instance_variable_set(name, value) # Nos permite definir y asignar un valor a una nueva variable
# de instancia.
define_method(name, &block) # Nos permite definir dentro de la clase un método de manera
# dinámica y en tiempo de ejecución.
method_missing(name, *args, &block) # Nos permite capturar y manejar la excepción que se dispara
# cuando llamamos un método no definido dentro de una clase.
=end
=begin
class Example
end
ex = Example.new
ex.instance_variables # => []
ex.instance_variable_set(:@x, 1) # => 1
ex.instance_variables # => ["@x"]
ex.instance_variable_defined?(:@x) # => true
ex.instance_variable_defined?(:@y) # => false
ex.instance_variable_get(:@x) # => 1
ex.x # => undefined method `x' for #<Example:0x000056174cbb0440 @x=1>
=end
=begin
## "Macros a nivel de clases"
class Example
attr_accessor :x
end
## Es equivalente a:
class Example
def x
@x
end
def x=(value)
@x = value
end
end
ex.x # => 1
Class.methods.select { |m| m =~ /attr/ } # [:attr, :attr_reader, :attr_writer, :attr_accessor]
=end
# Clase base con la definición de nuestra macro a nivel de clase:
class AttrCustom
def self.attr_custom(name)
define_method("#{name}=") do |value|
puts "Asignando #{value.inspect} a #{name}"
instance_variable_set("@#{name}", value)
end
define_method("#{name}") do
puts "Leyendo #{name}"
instance_variable_get("@#{name}")
end
end
end
# Clase con implementación por herencia de nuestra macro:
class AnotherExample < AttrCustom
attr_custom :z
end
ex = AnotherExample.new
ex.z = 5 # => Asignando 5 a z
ex.z # => Leyendo z
=begin
class Student
def method_missing(name)
puts "No fue encontrado el método #{name}"
end
end
student = Student.new
student.reflection
# No fue encontrado el método reflection
=end
=begin
class MethodCatcher
def method_missing(name, *args, &block)
puts "El nombre del método no encontrado es #{name}"
puts "los argumentos del método son #{args}"
puts "El cuerpo del método es #{block.inspect}"
end
end
catch = MethodCatcher.new
catch.some_method(1, 2) { puts "something" }
# El nombre del método no encontrado es some_method
# los argumentos del método son [1, 2]
# El cuerpo del método es #<Proc:0x0033...>
=end
=begin
class HTML
def self.method_missing(method_name, *args, &block)
tag(method_name, *args, &block)
end
def self.tag(tag_name, *args, &block)
"<#{tag_name}>#{args.last} #{yield if block_given?}</#{tag_name}>"
end
end
html = HTML.div do
HTML.header do
HTML.h1 "Titulo de la página"
end +
HTML.article do
HTML.p "Hola a todos"
end
end
# <div>
# <header>
# <h1>Titulo de la página</h1>
# </header>
# <article>
# <p>Hola a todos</p>
# </article>
# </div>
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment