2016-12-01 23 views
6

Rubyでは、定数ルックアップはネストの影響を受け、メソッドはネストを保持します。例えばRubyでメソッドのネストを見つける方法を教えてください。

、私はこれらのモジュールがある場合:

module Foo 
    module ::A 
    Module.nesting #=> [A, Foo] 
    def Foo.a 
     X 
    end 
    end 
end 

Foo.a #=> 1 

そして[Foo, B]の入れ子を持つメソッドFoo.b

module A 
    X = 1 
end 

module B 
    X = 2 
end 

module Foo 
end 

を私は[A, Foo]の入れ子を持つメソッドFoo.aを定義することができます:

module B 
    module ::Foo 
    Module.nesting #=> [Foo, B] 
    def Foo.b 
     X 
    end 
    end 
end 

Foo.b #=> 2 
Foo::X = 3 

Foo.a #=> 1 <- still resolves to A::X 
Foo.b #=> 3 <- now resolves to Foo::X 

しかし、どのように私は、与えられたメソッドのネストを決定します:3210私はFoo::Xを定義した場合の違いが明らかになりましたか?

+0

正直言って、私はなぜ 'Foo.a'と' Foo.b'が定義されていてmainで利用できるのか不明です。 –

+0

@EricDuminil ':: Foo'のために、これはトップレベルの定数を参照しています。 – Stefan

+0

トップレベルのモジュールを他のモジュールにネストすることはできません。 – akuhn

答えて

4

これは動作します:

Foo.method(:a).to_proc.binding.eval('Module.nesting') 
#=> [A, Foo] 

Foo.method(:b).to_proc.binding.eval('Module.nesting') 
#=> [Foo, B] 

は、Ruby 2.2.1と2.3.1でテストされています。 Ruby 2.1.5では動作しません。

+1

はい、助けてくれてありがとう! – Stefan

+0

あなたは_「私は自分の電話でそれをテストすることはできません」と言っています_ - これは幸運な推測ですか、それともうまくいくかを知っていましたか? – Stefan

+2

Rubyの公式ドキュメントのおかげで、教育的な推測だったとしましょう。 –

2

あなたは間違った方法を考えています。 「メソッドの入れ子」などはありません。定数はどこかに入れ子になっています。ネスティングでは、モジュールとクラスの名前にパス解決が関連付けられています。メソッドはモジュール/クラス内に含まれます("normal"またはシングルトン)。


ここでは、方法は意味的です。 selfに似た概念があり、メソッドが定義される場所を決定します。これはdefaultdefというものです。そこにはキーワードがありませんが、それはほぼ同等だ:

定数が置かれ
kind_of?(Module) ? name : self.class.name 

/検索は純粋に構文れます。

DEEP_MIND = Object.new 

module Foo 
    X = 42 
end 

module Foo 
    module Bar 
    def DEEP_MIND.talk 
     p X 
    end 
    end 
end 

DEEP_MIND.talk # => 42 

module Foo::Bar 
    def DEEP_MIND.talk 
    p X 
    end 
end 

DEEP_MIND.talk # => uninitialized constant 

それが気にすべてはあなたのコードの行に何「現在のネストは」です:あなたはXを参照するとき、それはあなたがそれをする方法かどうかを置いた場合、少なくともビットを気にしません。それを参照しようとしました。あなたが実際に「メソッドの本体内の現在のネスト」を検索する場合


は今、あなたはあなたが実際に存在しているふりをするためにいくつかの方法が必要です。

悲しいことに、私は@Eric's answerに示された方法以外の方法はないとは思わない。 instance_eval/instance_execでブロックを使用すると、ブロックが定義されている場所の入れ子になります。

+0

_ "メソッドのネスト"のようなものはありません。_ _ - しかし、メソッドを評価するために、Rubyはそのネストを知っていなければなりません。私の例では、 'Foo.b'は最初に' B :: X'に、その後 'Foo :: X'に解決されます。静的に ':: B :: X'に解決するだけではなく、作成時点のネスト、つまり' [Foo、B] 'を尊重します。 – Stefan

+0

@Stefan * "しかし、メソッドを評価するために、Rubyはそのネストを知る必要があります。それは、呼び出されたオブジェクトを知る必要があります。定数はメソッドによって解決されません。これはコード内の現在のコンテキストによって解決されます。メソッドには、現在のコンテキスト/クロージャーを取得する便利な方法があります。 - #バインディング。メソッドがどこにあっても、現在のネストは 'Module.nesting'を介してアクセスできます。現在のバインディングを使用します。 'binding.eval( 'Module.nesting')'は別のバインディングを使用して別のコンテキストを持つとふりをします。 – ndn

+0

@Stefan、大丈夫です。メソッドはそれがバインディングであることを知っていると言うことができ、バインディング(メソッドがあるかどうかに関係なく)は現在のネストを知っています。その意味で、メソッドは定義されている場所の現在の入れ子を知っています。しかしそれは偶然であり、メソッドが定数と同じようにネストされているわけではありません。 – ndn

関連する問題