2011-01-07 2 views
17

disclaimer: Code de la prise ruby koansRuby: cadrage explicite sur une définition de classe

Ceci est d'une discussion des constantes de cadrage au sein des classes. Voici la défintion d'un couple quelques classes:

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 

À ce stade, faire MyAnimals::Bird.new.legs_in_bird résultats dans 2 et je comprends pourquoi - recherche espace lexical de la constante avant l'héritage heirarchy.

Ensuite, cette classe est définie

class MyAnimals::Oyster < Animal 
    def legs_in_oyster 
    LEGS 
    end 
end 

Le tutoriel dit que l'appel maintenant MyAnimals::Oyster.new.legs_in_oyster résultats à 4 et je ne peux pas le comprendre. Il me semble qu'Oyster est une classe imbriquée dans MyAnimals et en tant que telle, je m'attendais à ce qu'elle se comporte de la même manière que la classe des Oiseaux. Il me manque des informations clés sur ce que déclare la classe Oyster avec des moyens explicites.

quelqu'un peut-il m'expliquer cela? J'ai trouvé des centaines de tutoriels de classe Ruby via Google, mais aucun d'entre eux abordent cette situation.

vous remercie à l'avance ...

+3

Il. Sont. QUATRE. Jambes!!! zetetic

+0

Quatre pattes bonnes, deux pattes mauvaises

+3

Est-ce que quelqu'un écrit le code qui dépendrait de la constante qui serait atteinte en premier? –

Répondre

17

Je pense que this example explique le mieux.Ruby cherche la définition constante dans cet ordre:

  1. La portée englobante
  2. Tous les champs externes (répéter jusqu'à ce que le niveau supérieur est atteint) Tous les champs extérieurs (jusqu'à mais hors niveau supérieur
  3. modules inclus
  4. superclasse (es)
  5. de haut niveau
  6. objet
  7. noyau

EDIT

Merci à Mark Amery pour remarquer cette erreur. Le niveau supérieur n'est atteint que dans le cas où il n'y a pas d'étendues englobantes et/ou de superclasses. L'exemple lié rend cela clair, malheureusement je l'ai mal lu.

Un exemple pour ce cas:

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 
+0

Qu'est-ce qui constitue le «niveau supérieur»? Si je fais 'FOO =' topoffile '; test de classe; FOO = 'insuperclasse'; fin; class Test2

+0

@MarkAmery bonne prise. – zetetic

5

Si vous définissez l'huître dans la définition de classe MyAnimals, alors vous obtenez la réponse que legs_in_oyster est 2.

Si vous définissez l'Oyster séparément - c'est , vous le définissez après que LEGS = 2 est hors de portée, vous obtenez la réponse de 4.

Cela me suggère que la classe imbriquée se comporte différemment d'un espace de noms, peut-être plus comme une fermeture.

--- EDIT ---

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 

Selon « Le langage de programmation Ruby », les constantes sont cherchés dans la portée lexicales du lieu où ils sont utilisés en premier lieu, et dans la hiérarchie de l'héritage deuxième . Alors, quelle est la portée lexicale de quelque chose qui hérite d'Animal? Animal lui-même, non? La classe MyAnimals redéfinit LEGS, donc tout ce qui utilise LEGS, et est défini à l'intérieur de MyAnimals, cherchera d'abord LEGS dans MyAnimals.

+0

Ah, je pensais que peu importe où vous avez défini la classe, l'acte de faire MyAnimals :: il en a fait une classe imbriquée et lui a donné accès à cette étendue ... – jaydel

Questions connexes