2015-02-19 9 views

Odpowiedz

2

Oto co wymyśliłem:

static void d(VALUE v) { 
    ID sym_puts = rb_intern("puts"); 
    ID sym_inspect = rb_intern("inspect"); 
    rb_funcall(rb_mKernel, sym_puts, 1, 
     rb_funcall(v, sym_inspect, 0)); 
} 

Mając go w pliku C można wyjście VALUE s tak:

VALUE v; 
d(v); 

Mam pomysł zapożyczony z this article.

0

Znalazłem interesujący sposób, używając plików Natvis w Visual Studio.

Stworzyłem obiekty opakowujące C++ nad API Ruby C - to daje mi trochę więcej bezpieczeństwa typu, a składnia staje się bardziej podobna do pisania rzeczywistej Ruby.

Nie będę publikować całego kodu - za długo na to, planuję otwarcie go w przyszłości.

Ale sedno jest to:

class Object 
{ 
public: 
    Object(VALUE value) : value_(value) 
    { 
    assert(NIL_P(value_) || kind_of(rb_cObject)); 
    } 

    operator VALUE() const 
    { 
    return value_; 
    } 
    // [More code] ... 
} 

Następnie weźmy klasę String na przykład:

class String : public Object 
{ 
public: 
    String() : Object(GetVALUE("")) {} 
    String(VALUE value) : Object(value) 
    { 
    CheckTypeOfOrNil(value_, String::klass()); 
    } 
    String(std::string value) : Object(GetVALUE(value.c_str())) {} 
    String(const char* value) : Object(GetVALUE(value)) {} 


    operator std::string() 
    { 
    return StringValueCStr(value_); 
    } 

    operator std::string() const 
    { 
    return operator std::string(); 
    } 

    static VALUE klass() 
    { 
    return rb_cString; 
    } 

    // String.empty? 
    bool empty() 
    { 
    return length() == 0; 
    } 

    size_t length() const 
    { 
    return static_cast<size_t>(RSTRING_LEN(value_)); 
    } 

    size_t size() const 
    { 
    return length(); 
    }; 

}; 

więc - moi owijarki upewnij się, aby sprawdzić, czy VALUE one zawijać jest spodziewane wpisz lub Nil.

Potem napisał kilka natvis pliki do Visual Studio, które zapewnią pewną prawdziwe informacje debugowania czas dla moich przedmiotów owiniętych jak I krok poprzez kod:

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> 

<Type Name="SUbD::ruby::String"> 
    <DisplayString Condition="value_ == RUBY_Qnil">Ruby String: Nil</DisplayString> 
    <DisplayString Condition="value_ != RUBY_Qnil">Ruby String: {((struct RString*)value_)->as.heap.ptr,s}</DisplayString> 
    <StringView Condition="value_ != RUBY_Qnil">((struct RString*)value_)->as.heap.ptr,s</StringView> 
    <Expand> 
    <Item Name="[VALUE]">value_</Item> 
    <Item Name="[size]" Condition="value_ != RUBY_Qnil">((struct RString*)value_)->as.heap.len</Item> 
    <Item Name="[string]" Condition="value_ != RUBY_Qnil">((struct RString*)value_)->as.heap.ptr</Item> 
    <Item Name="[capacity]" Condition="value_ != RUBY_Qnil">((struct RString*)value_)->as.heap.aux.capa</Item> 
    </Expand> 
</Type> 

</AutoVisualizer> 

Zauważ, że to wszystko jest zakodowane w celu dokładnego wewnętrzna struktura Ruby 2.0. To nie zadziała w Rubim 1.8 lub 1.9 - nie próbowałem jeszcze z wersją 2.1 lub 2.2. Ponadto mogą istnieć mutacje dotyczące sposobu przechowywania String, których jeszcze nie dodałem. (Krótkie łańcuchy mogą być przechowywane jako wartości bezpośrednie.) (W rzeczywistości - natvis zamieszczony powyżej działa tylko dla wersji 32-bitowej - nie 64-bitowej.)

Ale raz to skonfiguruję, mogę przejrzeć kod i sprawdzić ciągi Ruby prawie jak są std::string:

Visual Studio displaying information about Ruby String class

dojazd do pracy, to wszystko nie jest trywialne. Jeśli zauważyłeś w moim natvis moich RUBY_Qnil odniesień - nie będzie działać, chyba że dodałem ten kawałek debugowania kodu do mojego projektu:

// Required in order to make them available to natvis files in Visual Studio. 
#ifdef _DEBUG 
const auto DEBUG_RUBY_Qnil    = RUBY_Qnil; 
const auto DEBUG_RUBY_FIXNUM_FLAG  = RUBY_FIXNUM_FLAG; 
const auto DEBUG_RUBY_T_MASK   = RUBY_T_MASK; 
const auto DEBUG_RUBY_T_FLOAT   = RUBY_T_FLOAT; 
const auto DEBUG_RARRAY_EMBED_FLAG  = RARRAY_EMBED_FLAG; 
const auto DEBUG_RARRAY_EMBED_LEN_SHIFT = RARRAY_EMBED_LEN_SHIFT; 
const auto DEBUG_RARRAY_EMBED_LEN_MASK = RARRAY_EMBED_LEN_MASK; 
#endif 

nie można korzystać z makr w natvis definicji niestety, więc dlatego musiałem ręcznie rozwiń wielu z nich do pliku natvis poprzez sprawdzenie samego źródła Ruby. (Ruby Cross Reference bardzo nam tu pomaga: http://rxr.whitequark.org/mri/ident?v=2.0.0-p247)

To wciąż WIP, ale już zaoszczędziło mi wielu kłopotów.Ostatecznie chcę wyodrębnić konfiguracji debugowania na GitHub: https://github.com/thomthom (Miej oko na tym rachunku, jeśli jesteś zainteresowany.)

5

Można zadzwonić p Ruby obiektów z funkcją C rb_p. Na przykład:

VALUE empty_array = rb_ary_new(); 
rb_p(empty_array); // prints out "[]" 
+0

Dziękuję, to zasługuje na więcej awansów! Wszelkie inne wskazówki lub zasoby do debugowania rozszerzeń c? – Schneems

Powiązane problemy