manejo - Ruby: alcance explícito en una definición de clase
manejo de clases en ruby (2)
descargo de responsabilidad: Código tomado de los ruby koans
Esto es de una discusión de las constantes de alcance dentro de las clases. Aquí está la definición de un par de clases:
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
end
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
En este punto, al hacer MyAnimals::Bird.new.legs_in_bird
obtienen 2 y entiendo por qué: buscar en el espacio léxico la constante anterior a la jerarquía de herencia.
Entonces esta clase se define:
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
El tutorial dice que ahora llamar a MyAnimals::Oyster.new.legs_in_oyster
da MyAnimals::Oyster.new.legs_in_oyster
resultado 4 y no puedo entenderlo. Me parece que Oyster es una clase anidada en MyAnimals y, como tal, esperaba que se comportara de la misma manera que la clase Birds. Me falta información clave sobre lo que significa declarar la clase Oyster con alcance explícito.
¿Puede alguien explicarme esto? He encontrado cientos de tutoriales de ruby class a través de Google pero ninguno de ellos aborda esta situación.
gracias de antemano...
Creo que este ejemplo lo explica mejor. Ruby busca la definición constante en este orden:
- El ámbito de cierre.
-
Cualquier alcance externo (repita hasta que se alcance el nivel superior)Cualquier alcance externo (hasta el nivel superior sin incluirlo) - Módulos incluidos
- Superclase
- Nivel superior
- Objeto
- Núcleo
EDITAR
Gracias a Mark Amery por señalar este error. El nivel superior solo se alcanza en el caso de que no haya ámbitos y / o superclases adjuntos. El ejemplo vinculado realmente lo deja claro, lamentablemente lo leí mal.
Un ejemplo para este caso:
FOO = ''I pity the foo!''
module One
FOO = ''one''
class Two
FOO = ''two''
def self.foo
FOO
end
end
class Three < Two
def self.foo
FOO
end
end
end
class Four
class Five < Four
def self.foo
FOO
end
end
end
describe FOO do
it "depends where it is defined" do
expect(FOO).to eq ''I pity the foo!'' # top-level
expect(One::FOO).to eq ''one'' # module
expect(One::Two.foo).to eq ''two'' # class
expect(One::Three.foo).to eq ''one'' # outer scope (One) comes before superclass
expect(Four::Five.foo).to eq ''I pity the foo!'' # top-level
end
end
Si define Oyster INSIDE en la definición de la clase MyAnimals, obtendrá la respuesta que legs_in_oyster es 2.
Si define la Oyster por separado, es decir, la define después de que LEGS = 2 haya quedado fuera del alcance, obtendrá la respuesta de 4.
Esto me sugiere que la clase anidada se comporta de manera diferente a como lo hace un espacio de nombres, tal vez más como un cierre.
---EDITAR---
irb(main):076:0> class MyAnimals::RunningRoach < Animal; def using_legs; LEGS; end; end
=> nil
irb(main):077:0> MyAnimals::RunningRoach.new.kind_of?(MyAnimals)
=> false
irb(main):078:0> MyAnimals::RunningRoach.new.kind_of?(Animal)
=> true
irb(main):081:0> class MyAnimals::Mantis < MyAnimals; def killing_legs; LEGS; end; end
=> nil
irb(main):082:0> MyAnimals::Mantis.new.kind_of?(Animal)
=> false
irb(main):083:0> MyAnimals::Mantis.new.kind_of?(MyAnimals)
=> true
irb(main):084:0> MyAnimals::Mantis.new.killing_legs
=> 2
irb(main):085:0> MyAnimals::RunningRoach.new.using_legs
=> 4
De acuerdo con "The Ruby Programming Language", las constantes se buscan en el Ámbito Léxico del lugar donde se usan primero y en la jerarquía de herencia en segundo lugar. Entonces, ¿cuál es el alcance léxico de algo que hereda Animal? El animal en sí, ¿verdad? La clase MyAnimals redefine LEGS, por lo que cualquier cosa que use LEGS, y se define dentro de MyAnimals, buscará LEGS dentro de MyAnimals primero.