diff --git a/CHANGES.current b/CHANGES.current index 0088599da..3e01822f5 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,5 +1,30 @@ Version 1.3.32 (in progress) ============================ + +05/05/2007: gga + [Ruby] + STL files have been upgraded to follow the new swig/python + Lib/std conventions. + This means std::vector, std::set, std::map, set::multimap, + std::multiset, std::deque and std::string are now properly + supported, including their iterators, support for containing + ruby objects (swig::GC_VALUE) and several other ruby + enhancements. + std::ios, std::iostream, std::iostreambuf and std::sstream + are now also supported. + std::wstring, std::wios, std::wiostream, std::wiostreambuf + and std::wsstream are supported verbatim with no unicode + conversion. + + std_vector.i now mimics the behavior of Ruby Arrays much more + closely, supporting slicing, shifting, unshifting, + multiple indexing and proper return values on assignment. + + COMPATABILITY NOTE: this changes the older api a little bit in + that improper indexing would previously (incorrectly) raise + exceptions. Now, nil is returned instead, following ruby's + standard Array behavior. + 05/01/2007: gga [Ruby] Improved the documentation to document the new features @@ -9,10 +34,35 @@ Version 1.3.32 (in progress) [Ruby] Added %initstack and %ignorestack directives for director functions. These allow you to control whether a director - function should re-init the ruby stack. + function should re-init the Ruby stack. This is sometimes needed for an embedded Ruby where the director method is used as a C++ callback and not called by the user from ruby code. + Explanation: + Ruby's GC needs to be aware of the running OS stack in order to + mark any VALUE (Ruby objects) it finds there to avoid collection + of them. This allows the ruby API to be very simple and allows + you to write code like "VALUE a = sth" anywhere without needing + to do things like refcounting like python. + By default, the start of the stack is set when ruby_init() is + called. If ruby is inited within main(), as it usually is the + case with the main ruby executable, ruby will be able to calculate + its stack properly. However, when this is not possible, as when + ruby is embedded as a plugin to an application where main is not + available, ruby_init() will be called in the wrong place, and + ruby will be incorrectly tracking the stack from the function + that called ruby_init() forwards only, which can lead to + all sorts of weird crashes or to ruby thinking it has run out of + stack space incorrectly. + To avoid this, director (callback) functions can now be tagged + to try to reset the ruby stack, which will solve the issues. + NOTE: ruby1.8.6 still contains a bug in it in that its function + to reset the stack will not always do so. This bug is triggered + very rarely, when ruby is called from two very distinct places + in memory, like a branch of main() and another dso. This bug + has now been reported to ruby-core and is pending further + investigation. + (bug #1700535 and patch #1702907) 04/30/2007: wsfulton Fix #1707582 - Restore building from read-only source directories. @@ -24,28 +74,15 @@ Version 1.3.32 (in progress) argument passed. (feature request #1699670) -04/30/2007: gga - [Ruby] - STL files have been upgraded to follow the new swig/python - Lib/std conventions. - std_vector.i now mimics the behavior of Ruby Arrays much more - closely, supporting slicing, shifting, unshifting, - multiple indexing and proper return values on assignment. - - COMPATABILITY NOTE: this changes the older api a little bit in - that improper indexing would previously (incorrectly) raise - exceptions. Now, nil is returned instead, following ruby's - standard Array behavior. - 04/30/2007: gga [Ruby] Ruby no longer creates the free_Class function if the class - containes its own user defined free function (%freefunc). + contains its own user defined free function (%freefunc). (bug #1702882) 04/30/2007: gga [Ruby] - Made directors raise a ruby expection for incorrect argout + Made directors raise a ruby exception for incorrect argout returned values if RUBY_EMBEDDED is set, instead of throwing an actual SwigDirector exception. This will prevent crashes when ruby is embedded and unaware @@ -91,7 +128,7 @@ Version 1.3.32 (in progress) %feature("numoutputs","0") added. This feature allows you to ignore the output of a function so - that it is not added to a list of outpus values + that it is not added to a list of output values ( ie. argouts ). This should also become a feature of %typemap(directorout) as "numoutputs"=0, just like "numinputs"=0 exists. @@ -101,15 +138,15 @@ Version 1.3.32 (in progress) %include %feature("numoutputs","0") { Class::member_function1 }; - %typemap(out) MStatus { // some code, like ignore mstatus - // and raise exception }; + %typemap(out) MStatus { // some code, like check mstatus + // and raise exception if wrong }; %inline %{ typedef int MStatus; class Class { // one argument returned, but director out code added - // MStatus is discarded. + // MStatus is discarded as a return (out) parameter. virtual MStatus member_function1( int& OUTPUT ); // two arguments returned, director out code added @@ -118,35 +155,6 @@ Version 1.3.32 (in progress) }; %} -04/29/2007: gga - [Ruby] - Directors will now try to reset the ruby stack on the first call - to them if the developer sets the define RUBY_EMBEDDED. - Explanation: - Ruby's GC needs to be aware of the running OS stack in order to - mark any VALUE (Ruby objects) it finds there to avoid collection - of them. This allows the ruby API to be very simple and allows - you to write code like "VALUE a = sth" anywhere without needing - to do things like refcounting like python. - By default, the start of the stack is set when ruby_init() is - called. If ruby is inited within main(), as it usually is - with the main ruby executable, ruby will be able to calculate - its stack properly. However, when this is not possible, as when - ruby is embedded as a plugin to an application where main is not - available, ruby_init() will be called in the wrong place, and - ruby will be incorrectly tracking the stack from the function - that called ruby_init() only, which can lead to - all sorts of weird crashes or to ruby thinking it has run out of - stack space incorrectly. - To avoid this, director (callback) functions can now be tagged - to try to reset the ruby stack, which will solve the issues. - NOTE: ruby1.8.6 still contains a bug in it in that its function - to reset the stack will not always do so. This bug is triggered - very rarely, when ruby is called from two very distinct places - in memory, like a branch of main() and another dso. This bug - has now been reported to ruby-core and is pending further - investigation. - (bug #1700535 and patch #1702907) 04/21/2007: olly Fix parsing of float constants with an exponent (e.g. 1e-02f) diff --git a/Examples/test-suite/ruby/li_std_map_runme.rb b/Examples/test-suite/ruby/li_std_map_runme.rb index b82b3bb68..7051f19e0 100755 --- a/Examples/test-suite/ruby/li_std_map_runme.rb +++ b/Examples/test-suite/ruby/li_std_map_runme.rb @@ -40,7 +40,7 @@ m["foo"] = "hello" pm = Li_std_map::LanguageMap.new m.each_key { |k| pm[k] = m[k] } -m.each_key { |k| swig_assert("#{pm[k].inspect} == #{m[k].inspect}") } +m.each_key { |k| swig_assert_equal("pm[#{k.inspect}]", "m[#{k.inspect}]", binding) } m = Li_std_map::MmapA.new m[0] = a1 @@ -49,7 +49,7 @@ m[0].size == 2 m.respond_to?(:each) == true m.respond_to?(:each_key) == true m.respond_to?(:each_value) == true - +m.values_at(0)[0] == m[0] EOF mii = Li_std_map::Mapii.new diff --git a/Lib/ruby/rubyclasses.swg b/Lib/ruby/rubyclasses.swg index 142b407bf..3aa6b7c34 100644 --- a/Lib/ruby/rubyclasses.swg +++ b/Lib/ruby/rubyclasses.swg @@ -125,6 +125,48 @@ namespace swig { typedef GC_VALUE LANGUAGE_OBJ; } + + +namespace std { + template <> + struct less< swig::GC_VALUE >: public binary_function< swig::GC_VALUE, + swig::GC_VALUE, bool > + { + static ID cmp_id; + static ID hash_id; + + bool + operator()( const swig::GC_VALUE& v, const swig::GC_VALUE& w ) const + { + // SWIG_RUBY_THREAD_BEGIN_BLOCK; + + VALUE ret = Qnil; + + // First, try to compare using the <=> operator if present + if ( rb_respond_to( v, cmp_id ) == Qtrue ) + { + ret = rb_funcall(VALUE(v), cmp_id, 1, VALUE(w)); + } + + bool res; + // If that fails, try to use the two object's hash function to compare. + if ( ret == Qnil ) { + VALUE a = rb_funcall( VALUE(v), hash_id, 0 ); + VALUE b = rb_funcall( VALUE(w), hash_id, 0 ); + res = a < b; // as shifted integers + } + else + { + res = NUM2INT( ret ) < 0; + } + // SWIG_RUBY_THREAD_END_BLOCK; + return res; + } + }; + + ID less< swig::GC_VALUE >::cmp_id = rb_intern("<=>"); + ID less< swig::GC_VALUE >::hash_id = rb_intern("hash"); +} %} diff --git a/Lib/ruby/rubycontainer.swg b/Lib/ruby/rubycontainer.swg index 5930631f1..83a06b867 100644 --- a/Lib/ruby/rubycontainer.swg +++ b/Lib/ruby/rubycontainer.swg @@ -71,26 +71,6 @@ namespace swig { { %#include -namespace std { - template <> - struct less< VALUE >: public binary_function< VALUE, VALUE, bool > - { - static ID id; - - bool - operator()( VALUE v, VALUE w ) const - { - // SWIG_RUBY_THREAD_BEGIN_BLOCK; - bool res = NUM2INT( rb_funcall(v, id, 1, w) ) < 0; - // SWIG_RUBY_THREAD_END_BLOCK; - return res; - } - }; - - ID less< VALUE >::id = rb_intern("<=>"); - -} - namespace swig { template < class T > @@ -652,6 +632,24 @@ namespace swig return self; } + %newobject select + Sequence* select() { + if ( !rb_block_given_p() ) + rb_raise( rb_eArgError, "no block given" ); + + Sequence* r = new Sequence; + Sequence::iterator i = self->begin(); + Sequence::iterator e = self->end(); + for ( ; i != e; ++i ) + { + VALUE v = swig::from(*i); + if ( RTEST( rb_yield(v) ) ) + $self->push_back(*i); + } + + return r; + } + %rename("reject!") reject_bang; %alias reject_bang "delete_if"; @@ -659,12 +657,11 @@ namespace swig if ( !rb_block_given_p() ) rb_raise( rb_eArgError, "no block given" ); - VALUE r; Sequence::iterator i = self->begin(); Sequence::iterator e = self->end(); for ( ; i != e; ) { - r = swig::from(*i); + VALUE r = swig::from(*i); if ( RTEST( rb_yield(r) ) ) $self->erase(i++); else diff --git a/Lib/ruby/std_map.i b/Lib/ruby/std_map.i index f458fb5fb..868bee0fc 100644 --- a/Lib/ruby/std_map.i +++ b/Lib/ruby/std_map.i @@ -194,6 +194,47 @@ return self; } + %newobject select; + Map* select() { + if ( !rb_block_given_p() ) + rb_raise( rb_eArgError, "no block given" ); + + Map* r = new Map; + Map::iterator i = $self->begin(); + Map::iterator e = $self->end(); + for ( ; i != e; ++i ) + { + VALUE k = swig::from(i->first); + VALUE v = swig::from(i->second); + if ( RTEST( rb_yield_values(2, k, v) ) ) + $self->insert(r->end(), *i); + } + + return r; + } + + %typemap(in) (int argc, VALUE* argv) { + $1 = argc; + $2 = argv; + } + + VALUE values_at(int argc, VALUE* argv, ...) { + + VALUE r = rb_ary_new(); + ID id = rb_intern("[]"); + swig_type_info* type = swig::type_info< Map >(); + VALUE me = SWIG_NewPointerObj( $self, type, 0 ); + for ( int i = 0; i < argc; ++i ) + { + VALUE key = argv[i]; + VALUE tmp = rb_funcall( me, id, 1, key ); + rb_ary_push( r, tmp ); + } + + return r; + } + + Map* each_key() { if ( !rb_block_given_p() )