Entendiendo el ‘ yo ‘ en Ruby

Hoy me gustaría hablar de self. Si has estado programando Ruby por un tiempo, es probable que hayas interiorizado la idea de self. Cada vez que lees o escribes un programa, self está en el fondo de tu mente.

Pero para rubistas con menos experiencia, self puede ser desconcertante. Siempre está cambiando, pero nunca se muestra explícitamente en el código. Sólo se espera que lo sepas.

Muchos de los problemas a los que se enfrentan los principiantes son causados por no comprender self. Si alguna vez ha» perdido » una variable de instancia o se ha preguntado qué datos son visibles para un mixin, es porque no entendió self en ese contexto.

En esta publicación, vamos a ver self en una variedad de situaciones cotidianas.

¿Qué es self?

Es posible que haya escuchado a la gente decir que todo en Ruby es un objeto. Si eso es cierto, significa que cada pieza de código que escribes «pertenece» a algún objeto.

self es una variable especial que apunta al objeto que «posee» el código que se está ejecutando actualmente. Ruby usa self en todas partes:

  • Por ejemplo, variables: @myvar
  • Para buscar métodos y constantes
  • Al definir métodos, clases y módulos.

En teoría, self es bastante obvio. Pero en la práctica, es fácil que aparezcan situaciones complicadas. Por eso escribí este post.

Ejemplos de uno mismo

Vamos a pasar por varios ejemplos ahora. Si los primeros parecen demasiado básicos para ti, sigue leyendo. Se hacen más avanzados.

Dentro de un método de instancia

En el código siguiente, reflect es un método de instancia. Pertenece al objeto que creamos a través de Ghost.new. Así que self apunta a ese objeto.

class Ghost def reflect self endendg = Ghost.newg.reflect == g # => true

Dentro de un método de clase

Para este ejemplo, reflect es un método de clase de Ghost. Con los métodos de clase, la propia clase «posee» el método. self apunta a la clase.

class Ghost def self.reflect self endendGhost.reflect == Ghost # => true

Funciona de la misma manera con los métodos de» clase » dentro de los módulos. Por ejemplo:

module Ghost def self.reflect self endend Ghost.reflect == Ghost # => true

Recuerde, las clases y los módulos se tratan como objetos en Ruby. Así que este comportamiento no es tan diferente del comportamiento del método de instancia que vimos en el primer ejemplo.

Dentro de una definición de clase o módulo

Una característica de Ruby que lo hace tan adecuado para frameworks como Rails es que puede ejecutar código arbitrario dentro de definiciones de clase y módulo. Cuando pones código dentro de una definición de clase / módulo, se ejecuta como cualquier otro código Ruby. La única diferencia real es el valor de self.

Como puede ver a continuación, self apunta a la clase o módulo que se está definiendo.

class Ghost self == Ghost # => trueend module Mummy self == Mummy # => trueend 

Dentro de los métodos mixin

Los métodos mezclados se comportan igual que los métodos de clase o instancia» normales » cuando se trata de self. Esto tiene sentido. De lo contrario, el mixin no podría interactuar con la clase en la que lo mezclaste.

Métodos de instancia

Aunque el método reflect se definió en el módulo, su self es la instancia de la clase en la que se mezcló.

module Reflection def reflect self endend class Ghost include Reflectionendg = Ghost.newg.reflect == g # => true

Métodos de clase

Cuando extend una clase para mezclar en métodos de clase, self se comporta exactamente como lo hace en métodos de clase normales.

module Reflection def reflect self endend class Ghost extend ReflectionendGhost.reflect == Ghost # => true

Dentro de la metaclase

Es probable que haya visto este popular atajo para definir muchos métodos de clase a la vez.

class Ghost class << self def method1 end def method2 end endend

La sintaxis class << foo es bastante interesante. Le permite acceder a la metaclase de un objeto, que también se llama «clase singleton» o «clase propia».»Planeo cubrir las metaclases más profundamente en un futuro post. Pero por ahora, solo necesita saber que la metaclase es donde Ruby almacena métodos que son únicos para un objeto específico.

Si accede a self desde el bloque class << foo, obtiene la metaclase.

class << "test" puts self.inspectend# => #<Class:#<String:0x007f8de283bd88>

Fuera de cualquier clase

Si está ejecutando código fuera de cualquier clase, Ruby todavía proporciona self. Apunta a «principal», que es una instancia de Object:

puts self.inspect # => main