2013-02-27 3 views
32

対字句スコープは、これは、このオリジナルのSO質問続きです:元SOの質問でUsing "::" instead of "module ..." for Ruby namespacingルビー - 継承

、ここで私はまだトラブルの理解を抱え提示シナリオです:

FOO = 123 

module Foo 
    FOO = 555 
end 

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

puts Foo::Bar.new.baz # -> 555 
puts Foo::Bar.new.glorf # -> 123 

最初のコールが555を返す理由と、2番目のコールが123を返す理由を説明できる人がいますか?

+1

ウィルソン555を、割り当てられていましたか? Thanks – rainkinz

+0

ヒント:コードに2つのputsの後に "puts Module.nesting"を追加します。 これも参照してください:http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/ –

答えて

33

を見つけました。 Rubyが参照された名前の定義を探しているときは、現在のスコープ(メソッド、クラス、またはモジュール)を最初に探し、そこに見つからなければ "ゲートウェイ"と検索スコープ方法baz

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

のでFOOの値を決定しようとしたとき、最初のクラスBarがチェックされている、とBarFOOが含まれていないため、検索が上に移動として定義されているあなたの例では

class Barゲートウェイ」を通じて、包含範囲であるFooモジュールに転送します。 Fooには定数FOO(555)が含まれていますので、これが表示されます。

方法glorfは次のように定義される:ここ

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

「ゲートウェイ」FOOBar中に発見されていないときに「ゲートウェイ」はFooモジュールを通って真っ直ぐ最上位に入る、class Foo::Barあります表示されているものはFOO(123)です。class Foo::Barを使用して作成する方法

注単一Fooの範囲にわたってスキップし、「ゲートウェイ」が、module Foo; class Bar ...はその内=> [Foo, Module, Object, Kernel, BasicObject]

において、二つの別々の「ゲートウェイ」

+3

Btw。ゲートウェイ用語。 Rubyのソースには、スコープスタックと呼ばれるものがあるようです。したがって、 'class'または' module'を打つたびに、新しいスコープがこのスタックにプッシュされます。 Rubyが変数または定数を検索すると、このスタックを下から上に渡り、途中で変数が見つからなかった場合は最上位の 'main'で終わります。 'class Foo :: Bar'の場合、実際には2つのスコープをスタック(Foo'と' Bar'両方)にプッシュする必要がありますが、それは1つしかプッシュしないため、問題が発生します。 – Casper

+0

これは元の回答とどのように違いますか? – rainkinz

+1

@キャスパーそれは意味をなさない。何が起こっているのかを考える方法としてどこか(「残念なことにどこかを覚えていない」)「ゲートウェイ」アイデアについて読んだが、実装を見ていない。私は、この動作の説明の1つは、囲みスコープが干渉しないように心配することなく、ネストされたクラスを(猿パッチに)開くことができるということです。 – matt

5

よろしくお願いいたします。私が思いつくことができる最高の答えは、この場合、モジュールを使って名前空間を定義することです。

このうち

チェック:

FOO = 123 

module Foo 
    FOO = 555 
end 

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 

    def glorf3 
     puts ::FOO 
    end 
    end 
end 

class Foo::Bar 
    def glorf2 
    puts Foo::FOO 
    end 

    def glorf 
    puts FOO 
    end 
end 

puts Foo::Bar.new.baz # -> 555 
puts Foo::Bar.new.glorf # -> 123 
puts Foo::Bar.new.glorf2 # -> 555 
puts Foo::Bar.new.glorf3 # -> 123 

だから私の考えは、ユーザーが定義したときにということである。

module Foo 
    FOO = 555 
end 

をあなたはFooの名前空間にFOOを作成しています。したがって、ここで使用する場合:

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

あなたはFoo名前空間に属しています。あなたがそれを参照するときしかし、:

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

FOO::FOOによって示されるように)デフォルトの名前空間から来ています。

+0

例のおかげで!これは1つの点を除いて理にかなっています:Foo :: Barクラスを定義するとき、それをFooに名前を付けないのですか? "Foo :: Bar"の "Foo ::"部分は、あなたがそのクラスの名前空間を指定していることを暗示していませんか? – wmock

+0

Foo :: Bar.new.glorfが123を返すのは、Foo :: Bar.new.bazが555を返したときにわかりにくいです。 – wmock

+1

私はそれも考えましたが、起こっていることは名前空間のBarです(Fooの下で)Foo :: Barによって明示的に指定され、そのコンテキスト内の他のものはすべてデフォルトの名前空間から取り出されます。 – rainkinz

0

最初の呼び出し:

puts Foo::Bar.new.baz # -> 555 

版画クラスのインスタンスのメソッドバズを呼び出した結果はFoo ::バー

予告そのはFoo ::バー#のバズ定義は実際にはFOOのクロージャです。以下のRubyのスコープ規則:

  1. FOO
  2. FOOがで検索され、はFoo ::バー(クラス、インスタンスではなく)スコープ、でそれが見つからなかったために検索されます

    :範囲フー(我々は、モジュール定義の範囲内にあるので)、それがそこに発見された(555)

に第2の呼を囲みます0

puts Foo::Bar.new.glorf # -> 123 

今回もFOOに閉鎖されはFoo ::バー#1 glorf定義するクラスはFoo ::バー

通知のインスタンスの方法glorfを呼び出した結果を印刷私たちはRubyのスコープ規則に従っている場合ていますが、値は、この時間に閉じていることに気づくでしょうことはです::以下の方法でFOO(トップレベルのスコープFOO):

  1. FOOはFoo ::バー(クラス、インスタンスではなく)名前空間では、
  2. をFOOを囲むスコープ(「トップレベル」)で検索され見つからないために検索され、それはあなたが新しいスコープに「ゲートウェイ」としてmodule Somethingclass Somethingまたはdef somethingの各出現について考えることができるが(123)
0

glorfがFooクラスのメソッドであるが開きスコープ(すなわち、デフォルト/メインモジュールで)、FOOは123

モジュールfooが

module Foo 
    FOO = 555 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 
として定義され、割り当てられていますメソッドのバズが => [Bar, Foo, Object, Kernel, BasicObject]

とそのスコープのFOOのモジュールのFooのクラスバーに属する10

は以下答えるあなたは恵みの価値があると思います

+0

上記の 'main'はirbの成果物ですが、実際には 'FOO = 123'はObjectクラスに入る最上位メソッドです。 – aug2uag