2013-07-01 12 views
9

Desidero avere accesso ai binding del chiamante. Cosa c'è che non va qui?Come chiamare un blocco rubino per accedere ai collegamenti del chiamante

require 'test/unit' 

class BlocksTest < Test::Unit::TestCase 

    class Blocks 
    def initialize(&block); @block = block; end 
    def run; instance_eval { @block.call }; end 

    def foo; 'foo'; end 
    end 

    def test_say_foo_via_string 
    assert_equal('foo', Blocks.new{ 'foo' }.run) 
    end 
    # => successful 

    def test_say_foo_via_caller_method 
    assert_equal('foo', Blocks.new{ foo }.run) 
    end 
    # => NameError: undefined local variable or method `foo' 

end 

Perché non ho accesso all'istanza del chiamante all'interno del blocco specificato?

+0

Caro Downvoter! Sono relativamente nuovo qui e sarebbe bello ricevere alcuni consigli se la mia domanda non è utile. :-) Ho cambiato il codice della domanda in una classe di test completa 'BlocksTest'. Ho anche cambiato la chiamata di blocco nel metodo 'run' da' @ block.call' a 'instance_eval {@ block.call}' che solleva lo stesso errore. – sschmeck

risposta

4

All'interno del blocco non si è nel campo di applicazione della istanza Blocks, quindi foo non è visibile. Si deve passare l'oggetto al blocco, se si vuole avere accesso ad esso:

class Blocks 
    # ... 
    def run 
    @block.call(self) 
    end 
    # ... 
end 

blk = Blocks.new { |b| b.foo } 
blk.run 
# => "foo" 

In alternativa si può passare il blocco instance_eval:

class Blocks 
    # ... 
    def run 
    instance_eval(&@block) 
    end 
    # ... 
end 

blk = Blocks.new { foo } 
blk.run 
# => "foo" 
+0

Per la differenza tra un proc e un blocco vedere [questo] (http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/) e [questo] (http : //net.tutsplus.com/tutorials/ruby/ruby-on-rails-study-guide-blocks-procs-and-lambdas/). – toro2k

+0

Grazie! Ho provato la seconda soluzione prima di porre la domanda, ma senza l'operatore '&'. 'instance_eval {@ block.call};' solleva lo stesso errore. Qual è la differenza tra il blocco e la sintassi Proc? – sschmeck

+0

Grazie per i collegamenti. Non ho trovato una spiegazione per la differenza tra 'instance_eval (& block)' e 'instance_eval {block.call}'. Il primo modo converte il Proc in un blocco e il secondo crea un nuovo blocco ed esegue il Proc. Non ho ancora idea del perché i collegamenti/gli ambiti degli approcci differiscano. : - / – sschmeck

0

provato a riprodurla:

3.times.map{ foo } 
#~> undefined local variable or method `foo' for main:Object (NameError) 

All'interno { } o all'esterno di {}, foo non è stato definito come un method o varable. Quindi il parser di Ruby si è confuso e genera errori.

ora vedere:

foo = 12 
3.times.map{ foo } 
# => [12, 12, 12] 

Prova:

test "say method_foo" do 
    assert_equal('foo', Blocks.new{|i| i.foo }.run) 
end 
0

provare questo

class Blocks 
    def initialize(&block); @block = block; end 
    def run; instance_eval &@block; end 

    def foo; 'foo'; end 
end