Last active
August 10, 2020 17:36
-
-
Save joalbertg/f7c8ef547828e2b61df1cdadc00508bc to your computer and use it in GitHub Desktop.
ruby: Metaprogramming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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