2009-08-31 9 views

Odpowiedz

15

Jest nie wbudowana w taki sposób, aby uzyskać połączenie z abonentem wywołującym ing w Rubim w 1.8.X lub 1.9.X.

Do pracy można używać https://github.com/banister/binding_of_caller.

W MRI 2.0 można użyć RubyVM :: DebugInspector patrz: https://github.com/banister/binding_of_caller/blob/master/lib/binding_of_caller/mri2.rb

próbka robocza w MRI 2,0:

require 'debug_inspector' 

def bar(symbol) 
    RubyVM::DebugInspector.open do |inspector| 
    val = eval(symbol.to_s, inspector.frame_binding(2)) 
    puts "#{symbol}: #{val}" 
    end 
end 

def foo 
    a = 100 
    bar(:a) 
end 

foo 
# a: 100 
+0

Oto przykład delikatnego sposobu użycia funkcji set_trace_func, aby to zrobić: http://stackoverflow.com/questions/1314592/how-can-i-get-the-binding-od-methodmissing/1315612#1315612 – rampion

+2

Powinien zawierać zastrzeżenie : Nie rób tego, chyba że * faktycznie * używasz go do jakiegoś debugowania. – tmandry

3

zobacz artykuł z Variable Bindings in Ruby

class Reference 
    def initialize(var_name, vars) 
    @getter = eval "lambda { #{var_name} }", vars 
    @setter = eval "lambda { |v| #{var_name} = v }", vars 
    end 
    def value 
    @getter.call 
    end 
    def value=(new_value) 
    @setter.call(new_value) 
    end 
end 

def ref(&block) 
    Reference.new(block.call, block.binding) 
end 

def bar(ref) 
    # magic code goes here, it outputs "a = 100" 
    p ref.value 
end 

def foo 
    a = 100 
    bar(ref{:a}) 
end 

foo 
+0

+1 wygląda bardzo interesująco Zastanawiam się, czy można to zrobić bez bloku ... –

+0

Nie sądzę, że można to zrobić bez bloku w rubinie 1.8. x. Nie znam Rubiego 1.9.x, więc może być inaczej. – neoneye

+0

W Ruby 2.1 nadal potrzebujesz bloku, ale implementacja 'Reference' może zostać zmieniona za pomocą wywołań do [' Binding # local_variable_get'] (http://www.ruby-doc.org/core-2.1.0/Binding. html # method-i-local_variable_get) i ['Binding # vars.local_variable_set'] (http://www.ruby-doc.org/core-2.1.0/Binding.html#method-i-local_variable_set). Chociaż obecna implementacja prawdopodobnie pozwala na wywoływanie metod czytnika i pisarza oprócz zmiennych lokalnych, podczas gdy nowa implementacja nie ... – Ajedi32

17

Trzeba zdać foo „s kontekst do bar:

def foo 
    a = 100 
    bar(:a, binding) 
end 
def bar(sym, b) 
    puts "#{sym} is #{eval(sym.to_s, b)}" 
end 
+3

@fotanus, uh nie. Zauważysz, że data mojej odpowiedzi poprzedza rubin 2 o 3,5 roku. –

+0

Przepraszam, masz rację. – fotanus

6

Wystarczy FYI, oto "hacky sposób". To jest mój (re-) realizacja znanego ppp.rb.

#!/usr/bin/ruby 
# 
# better ppp.rb 
# 

require 'continuation' if RUBY_VERSION >= '1.9.0' 

def ppp(*sym) 
    cc = nil 
    ok = false 

    set_trace_func lambda {|event, file, lineno, id, binding, klass| 
    if ok 
     set_trace_func nil 
     cc.call(binding) 
    else 
     ok = event == "return" 
    end 
    } 
    return unless bb = callcc{|c| cc = c; nil } 

    sym.map{|s| v = eval(s.to_s, bb); puts "#{s.inspect} = #{v}"; v } 
end 

a = 1 
s = "hello" 
ppp :a, :s 

exit 0 

ten obecnie nie powiedzie się z 1,9 [012] z powodu błędu w set_trace_func ruby.

+0

Bardzo interesujące! Zaadaptowałem go, aby zbudować [moją własną wersję caller_binding] (http://rubychallenger.blogspot.com/2011/07/caller-binding.html). Ale [co to jest ppp?] (Http://stackoverflow.com/questions/6884122/ruby-what-is-ppp-rb) –

7

Oto łatwiejsza składnia hack, stosując przekazywane w bloku oprawa:

def loginfo &block 
    what = yield.to_s 
    evaled = eval(what, block.binding) 
    Rails.logger.info "#{what} = #{evaled.inspect}" 
    end 

nazywa tak:

x = 1 
    loginfo{ :x } 

będzie wylogowanie:

x = 1 
+1

FYI zaktualizował moją odpowiedź –

Powiązane problemy