Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

script y comentario #6

Open
wants to merge 1 commit into
base: ruby-metaprogramming
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,45 @@ metodo.bind(Hijo.new).call #=> 'correr como padre'
~~~

Como vemos los Unbound Methods se escapan al metodo lookup.

##### Controles sobre unbound methods

Si bien los Unbound methods se escapan al metodo lookup, cuando se hace el bind se hace previamente un chequeo de que la jerarquia a la que se bindea un unbound method debe ser del mismo tipo al de la clase que pertenecia o bien un tipo de la misma jerarquia, por ejemplo tomando lo que vimos ants tratemos de bindear un metodo a una clase que no es de la jerarquia de Padre/Hijo

```ruby
class A
end

metodo = Padre.instance_method(:correr)

metodo.bind(A.new).call # TypeError (bind argument must be an instance of Padre)
```

por lo que solo podremos bindear el UnboundMethod de correr perteneciente a la clase Padre a una instancia de Padre o de una subclase, por lo que se ajusta a lo que nos devuelve `kind_of?`

```ruby
Hijo.new.kind_of? Padre # verdadero
Padre.new.kind_of? Padre # verdadero
A.new.kind_of? Padre # falso
```

Es lo mismo que nos dide la documentacion en https://ruby-doc.org/core-2.6.1/UnboundMethod.html

Incluso este control es algo que no podemos sobreescribir ya que es un control hecho en la implementacion de MRi de Ruby:

https://github.com/ruby/ruby/blob/dd81af7b6a7539473b6d7a7e35637b4a7d986523/proc.c#L2403

y que finalmente llama al metodo `convert_umethod_to_method_components`

https://github.com/ruby/ruby/blob/dd81af7b6a7539473b6d7a7e35637b4a7d986523/proc.c#L2328

Por lo que una instancia de UnboundMethod, al menos en MRi no podremos bindearlo en cualquier otro metodo, siempre hay algunas restricciones...

Sigamos....

Tambien podemos preguntarle cosas a los metodos.


~~~ruby
metodo = atila.method(:atacar) #=> #<Method: Guerrero(Atacante)#atacar>
metodo.arity #=> 1
Expand Down
146 changes: 146 additions & 0 deletions script.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
require_relative 'age'
atila = Guerrero.new
atila.class
atila.class.superclass

atila.methods
Guerrero.instance_methods
Guerrero.instance_methods(false)

# Envio de mensajes

atila.send(:potencial_ofensivo) #=> 20
atila.send(:descansar) #=> 110

# con send no existen los metodos privados, la seguridad es una sensacion
class A
private
def metodo_privado
'cosa privada, no te metas'
end
end
objeto = A.new
objeto.metodo_privado #=> NoMethodError: private method `metodo_privado' called for #<A:direccion en memoria del objeto>
objeto.send(:metodo_privado) #=> "cosa privada, no te metas"

# bound/unbound method

metodo = atila.method(:potencial_ofensivo)
metodo.call

class Padre
def correr
'correr como padre'
end
end

class Hijo < Padre
def correr
'correr como hijo'
end
end
metodo = Padre.instance_method(:correr) #=>#<UnboundMethod: Padre#correr>
metodo.bind(Hijo.new).call #=> 'correr como padre'

metodo = atila.method(:atacar)
metodo.arity
metodo.parameters
metodo.owner

# variables

atila.instance_variables
atila.instance_variable_get(:@energia)
atila.instance_variable_set(:@energia, 50)
atila.instance_variable_get(:@energia)
atila

# Open Classes

class String
def importante
self + '!'
end
end
'aprobe'.importante #=> "aprobe!"

#Cambiar métodos
class Fixnum
def +(x)
123
end
end
2+2

#define method

Guerrero.send(:define_method, :saluda) {
'Hola'
}
Guerrero.new.saluda #=> "Hola"

# define singleton method

atila.define_singleton_method(:saluda) {
'Hola soy Atila'
}
atila.saluda
Guerrero.new.saluda


#### Segunda parte......

zorro = Espadachin.new(Espada.new(123))

# Eigenclasses

Peloton.cobarde([])

Peloton.methods.include? :cobarde #=> true
Peloton.class.instance_methods.include? :new #=> true
Peloton.class.instance_methods.include? :cobarde #=> false

Peloton.singleton_class.instance_methods(false) #=> [:cobarde, :descansador]

module W
def m
123
end
end

a = Guerrero.new
a.singleton_class.include W
a.m #=> 123
b = Guerrero.new
b.extend W
b.m #=>123

##

atila = Guerrero.new
atila.singleton_class.send(:define_method, :comerse_un_pollo, proc { @energia += 20 })
atila.energia
atila.comerse_un_pollo
atila.energia
Guerrero.new.comerse_un_pollo # NoMethodError

##

atila.singleton_class.send(:attr_accessor, :edad)
atila.edad = 5
atila.edad #=> 5
Guerrero.new.edad #=> NoMethodError

Guerrero.ancestors #=> [Guerrero, Defensor, Atacante, Object, PP::ObjectMixin, Kernel, BasicObject]
Guerrero.new.singleton_class.ancestors

class Guerrero
def self.gritar
   'haaaa'
end
end

atila.gritar #=> NoMethodError
Guerrero.gritar #=> haaaa

Espadachin.gritar #=>haaaa