Ruby scope es simple y complejo.
Primero debe recordar que todo es un objeto y que todo tiene un alcance.
Para responder a su pregunta directamente, main
es un objeto y por ejemplo cuando se escribe def x...
se está definiendo un método en el objeto main
bajo observación en pir/IRB:
# note the error describes
[1] pry(main)> main 'main:Object'
NameError: undefined local variable or method 'main' for main:Object
from (pry):1:in '<main>'
# self is the current object, which is main
[2] pry(main)> self
=> main
# note main is an object of type Object
[3] pry(main)> self.class
=> Object
# main has methods
[4] pry(main)> self.methods
=> [:to_s, :public, etc etc]
Así que cuando se escribir
ff = "ff"
def test
puts ff
end
lo que está haciendo en realidad es
class main
ff = "ff"
def test
puts ff
end
end
Lo cual no funciona porque ff
está fuera del alcance. Para solucionar esto, debe convertir ff
en una variable de instancia, así que anteponga su nombre con @
. El siguiente trabajo:
@ff = "ff"
def test
puts @ff
end
test
Tenga en cuenta que esto parece ser un caso especial para main
que las clases regulares, ver más abajo.
Si tenemos nuestra propia clase de prueba:
class Test1
ff = "ff"
def test
puts ff
end
end
Test1.new.test # undefined variable/method 'ff' error
Esta falla porque ff
no está definido en el ámbito correcto como se esperaría. En su lugar, se establece el alcance cuando el analizador está ejecutando nuestra declaración de clase.
Así que vamos a tratar la revisión anterior:
class Test1Fixed
@ff = "ff"
def test
puts @ff
end
end
Test1Fixed.new.test # results in blank line
Eso es raro.
vamos a añadir este método:
def ff?
puts "ff is: #{@ff.nil? ? "nil" : "not nill"}"
end
Test1Fixed.new.ff? # => ff is: nil
¿Por qué es @ff nula?
El siguiente podría hacer esto más claro:
class Test2
puts "Where am i?"
@instance = "instance"
def initialize
puts "Initalize"
end
puts "pants on"
def test
puts "This will NOT output 'instance': #{@instance}"
end
def self.class_test
puts "This WILL output 'instance': #{@instance}"
end
end
puts "Creating new Test2 Object"
t = Test2.new
puts "Calling test on Test2 Object"
t.test
puts "Calling class_test on Test2 Class object"
Test2.class_test
La ejecución de este obtenemos el siguiente resultado:
$ ruby scope.rb
Where am i?
pants on
Creating new Test2 Object
Initalize
Calling test on Test2 Object
This will NOT output 'instance':
Calling class_test on Test2 Class object
This WILL output 'instance': instance
Como se puede ver, el interperter corre sobre nuestra declaración de la clase con el fin, justo como en cualquier otro lugar y da salida a nuestras declaraciones puts
. Esto se vuelve más interesante cuando comenzamos a llamar a los métodos.Escribir @instance = ...
es lo mismo que escribir self.instance = ...
, así que ¿puedes adivinar dónde hemos definido la instancia? Sí, en el objeto de clase Test2 (no en un objeto Test2).
Por eso, cuando llamamos test
, nada se outputed, porque dentro test
, self
se refiere a la Test2
objeto instanciado, no el Test2 class object
(que es donde nos propusimos @instance a ser cualquier cosa!). Es por eso que configura sus variables de instancia dentro de initialize
, donde self
apuntará al objeto real.
Se puede ver cuando definimos un método de clase a través self.class_test
y luego llamar a ese método en la clase de objeto Prueba2 (Test2.class_test
), obtenemos el resultado esperado, ya que en ese ámbito, @instance
se definió.
Espero que esto tenga algún sentido.
La sección de alcance http://rubykoans.com/ puede ayudar a consolidar parte de este conocimiento.
Gracias por esto. Entiendo cómo funciona main ahora. ¡Qué bien que 'MyObject.new .__ send __ (: test)' funcione! (Aunque tal vez no sea útil). Re: 'Test1Fixed' Pensé que sí explique que la varilla' @ ff' es un miembro de la clase, de ahí que sea nula, 'Test2' se suponía que explicara esto por su salida (" 'will/NO emitirá 'instance'' "dependiendo de si llama a' test' o 'class_test') pero quizás no estaba particularmente claro. Además, si escribiste/empezaste a hacer palanca, ¡es genial hermano! – Soup
@soup actualizó la respuesta para reflejar que usted explicó correctamente '@ ff', lo siento :) Thx re pry, me alegro de que le guste :) – horseyguy