Każdy obiekt Ruby jest typu VALUE
w C. Jak mogę go wydrukować w czytelny sposób?Jak wydrukować wartości z rozszerzeń C?
Wszelkie inne wskazówki dotyczące debugowania rozszerzeń Ruby C są mile widziane.
Każdy obiekt Ruby jest typu VALUE
w C. Jak mogę go wydrukować w czytelny sposób?Jak wydrukować wartości z rozszerzeń C?
Wszelkie inne wskazówki dotyczące debugowania rozszerzeń Ruby C są mile widziane.
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.
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
:
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.)
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 "[]"
Dziękuję, to zasługuje na więcej awansów! Wszelkie inne wskazówki lub zasoby do debugowania rozszerzeń c? – Schneems