Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rubygem-rice for openSUSE:Factory 
checked in at 2024-02-26 19:49:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-rice (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-rice.new.1770 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-rice"

Mon Feb 26 19:49:06 2024 rev:11 rq:1151748 version:4.2.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-rice/rubygem-rice.changes        
2023-11-15 21:08:07.931244809 +0100
+++ /work/SRC/openSUSE:Factory/.rubygem-rice.new.1770/rubygem-rice.changes      
2024-02-26 19:50:20.700654678 +0100
@@ -1,0 +2,15 @@
+Mon Jan 29 14:29:16 UTC 2024 - Dan Čermák <dan.cer...@posteo.net>
+
+- ## 4.2.1
+
+* Support systems who use `#include <experimental/filesystem>` over 
`#include<filesystem>`. See 
[#197](https://github.com/jasonroelofs/rice/issues/197) and 
[#201](https://github.com/jasonroelofs/rice/pull/201)
+
+## 4.2
+
+* Support Ruby 3.3.0.
+* Split Object.call to an explicit Object.call_kw for calling methods 
expecting keyword arguments.
+* Previously, if a wrapper used `keepAlive` on an argument or return value 
that was itself a Rice type, calling said method would segfault. We've now 
added an explicit exception to be thrown in this case, prevending the segfault 
and providing guidance on what was wrong and how to fix it. See 
[#193](https://github.com/jasonroelofs/rice/pull/193) and 
[#194](https://github.com/jasonroelofs/rice/pull/194)
+* Fix wrapping of std::shared_ptr to properly take default arguments into 
account.
+
+
+-------------------------------------------------------------------

Old:
----
  rice-4.1.0.gem

New:
----
  rice-4.2.1.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-rice.spec ++++++
--- /var/tmp/diff_new_pack.ItIwdV/_old  2024-02-26 19:50:21.236674056 +0100
+++ /var/tmp/diff_new_pack.ItIwdV/_new  2024-02-26 19:50:21.236674056 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-rice
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-rice
-Version:        4.1.0
+Version:        4.2.1
 Release:        0
 %define mod_name rice
 %define mod_full_name %{mod_name}-%{version}

++++++ rice-4.1.0.gem -> rice-4.2.1.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md    2023-04-23 02:19:48.000000000 +0200
+++ new/CHANGELOG.md    2024-01-20 14:53:39.000000000 +0100
@@ -1,3 +1,14 @@
+## 4.2.1
+
+* Support systems who use `#include <experimental/filesystem>` over 
`#include<filesystem>`. See 
[#197](https://github.com/jasonroelofs/rice/issues/197) and 
[#201](https://github.com/jasonroelofs/rice/pull/201)
+
+## 4.2
+
+* Support Ruby 3.3.0.
+* Split Object.call to an explicit Object.call_kw for calling methods 
expecting keyword arguments.
+* Previously, if a wrapper used `keepAlive` on an argument or return value 
that was itself a Rice type, calling said method would segfault. We've now 
added an explicit exception to be thrown in this case, prevending the segfault 
and providing guidance on what was wrong and how to fix it. See 
[#193](https://github.com/jasonroelofs/rice/pull/193) and 
[#194](https://github.com/jasonroelofs/rice/pull/194)
+* Fix wrapping of std::shared_ptr to properly take default arguments into 
account.
+
 ## 4.1
 
 Rice 4.1 builds on the 4.0 release and has a number of improvements that both 
polish Rice and extend its functionality. However, there are three 
incompatibilities to know about:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CONTRIBUTORS.md new/CONTRIBUTORS.md
--- old/CONTRIBUTORS.md 2023-04-23 02:19:48.000000000 +0200
+++ new/CONTRIBUTORS.md 2024-01-20 14:53:39.000000000 +0100
@@ -17,3 +17,6 @@
 * [Charlie Savage (cfis)](https://github.com/cfis) for multiple improvements 
and modernizations: [#130](https://github.com/jasonroelofs/rice/pull/130), 
[#131](https://github.com/jasonroelofs/rice/pull/131), 
[#133](https://github.com/jasonroelofs/rice/pull/133), 
[#134](https://github.com/jasonroelofs/rice/pull/134), 
[#136](https://github.com/jasonroelofs/rice/pull/136), 
[#137](https://github.com/jasonroelofs/rice/pull/137), 
[#140](https://github.com/jasonroelofs/rice/pull/140), 
[#141](https://github.com/jasonroelofs/rice/pull/141) and many others, 
including the work to make Rice header-only.
 * [Atsushi Tatsuma (yoshoku)](https://github.com/yoshoku) for 
[#135](https://github.com/jasonroelofs/rice/pull/135)
 * [Andrew Kane (ankane)](https://github.com/ankane) for helping [test Rice 
4](https://github.com/jasonroelofs/rice/issues/149).
+* [Maxim Samsonov (maxirmx)](https://github.com/maxirmx) for 
[#193](https://github.com/jasonroelofs/rice/issues/193) and 
[#194](https://github.com/jasonroelofs/rice/pull/194)
+* [kvtb](https://github.com/kvtb) for 
[#191](https://github.com/jasonroelofs/rice/issues/191)
+* [thekendalmiller](https://github.com/thekendalmiller) for 
[#201](https://github.com/jasonroelofs/rice/pull/201)
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/include/rice/rice.hpp new/include/rice/rice.hpp
--- old/include/rice/rice.hpp   2023-04-23 02:19:48.000000000 +0200
+++ new/include/rice/rice.hpp   2024-01-20 14:53:39.000000000 +0100
@@ -1205,9 +1205,18 @@
 // =========   cpp_protect.hpp   =========
 
 #include <regex>
-#include <filesystem>
 #include <stdexcept>
 
+#if __has_include(<filesystem>)
+  #include <filesystem>
+  namespace fs = std::filesystem;
+#elif __has_include(<experimental/filesystem>)
+  #include <experimental/filesystem>
+  namespace fs = std::experimental::filesystem;
+#else
+  #error "no filesystem include found :'("
+#endif
+
 
 namespace Rice::detail
 {
@@ -1247,7 +1256,7 @@
       {
         rb_exc_raise(rb_exc_new2(rb_eArgError, ex.what()));
       }
-      catch (std::filesystem::filesystem_error const& ex)
+      catch (fs::filesystem_error const& ex)
       {
         rb_exc_raise(rb_exc_new2(rb_eIOError, ex.what()));
       }
@@ -1531,7 +1540,7 @@
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Warray-bounds"
 #endif
-    return static_cast<Wrapper*>(RTYPEDDATA_DATA(value));
+    return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) 
: nullptr;
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif
@@ -4052,6 +4061,9 @@
     // Figure out what self is
     Class_T getReceiver(VALUE self);
 
+    // Throw an exception when wrapper cannot be extracted
+    [[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
+
     // Do we need to keep alive any arguments?
     void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& 
rubyValues);
 
@@ -4073,6 +4085,7 @@
 #include <array>
 #include <algorithm>
 #include <stdexcept>
+#include <sstream>
 
 
 namespace Rice::detail
@@ -4107,7 +4120,7 @@
   NativeFunction<From_Ruby_T, Function_T, IsMethod>::NativeFunction(VALUE 
klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
     : klass_(klass), method_name_(method_name), function_(function), 
methodInfo_(methodInfo)
   {
-   // Create a tuple of NativeArgs that will convert the Ruby values to native 
values. For 
+    // Create a tuple of NativeArgs that will convert the Ruby values to 
native values. For 
     // builtin types NativeArgs will keep a copy of the native value so that 
it 
     // can be passed by reference or pointer to the native function. For 
non-builtin types
     // it will just pass the value through.
@@ -4233,7 +4246,7 @@
     {
       // Call the native method and get the result
       Return_T nativeResult = std::apply(this->function_, nativeArgs);
-      
+
       // Return the result
       return this->toRuby_.convert(nativeResult);
     }
@@ -4285,14 +4298,37 @@
   }
 
   template<typename From_Ruby_T, typename Function_T, bool IsMethod>
+  void NativeFunction<From_Ruby_T, Function_T, IsMethod>::noWrapper(const 
VALUE klass, const std::string& wrapper)
+  {
+    std::stringstream message;
+
+    message << "When calling the method `";
+    message << this->method_name_;
+    message << "' we could not find the wrapper for the '";
+    message << rb_obj_classname(klass);
+    message << "' ";
+    message << wrapper;
+    message << " type. You should not use keepAlive() on a Return or Arg that 
is a builtin Rice type.";
+
+    throw std::runtime_error(message.str());
+  }
+
+  template<typename From_Ruby_T, typename Function_T, bool IsMethod>
   void NativeFunction<From_Ruby_T, Function_T, IsMethod>::checkKeepAlive(VALUE 
self, VALUE returnValue, std::vector<VALUE>& rubyValues)
   {
-    // Check function arguments
+    // selfWrapper will be nullptr if this(self) is a builtin type and not an 
external(wrapped) type
+    // it is highly unlikely that keepAlive is used in this case but we check 
anyway
     Wrapper* selfWrapper = getWrapper(self);
+
+    // Check function arguments
     for (const Arg& arg : (*this->methodInfo_))
     {
       if (arg.isKeepAlive())
       {
+        if (selfWrapper == nullptr)
+        {
+          noWrapper(self, "self");
+        }
         selfWrapper->addKeepAlive(rubyValues[arg.position]);
       }
     }
@@ -4300,7 +4336,17 @@
     // Check return value
     if (this->methodInfo_->returnInfo.isKeepAlive())
     {
+      if (selfWrapper == nullptr)
+      {
+        noWrapper(self, "self");
+      }
+
+      // returnWrapper will be nullptr if returnValue is a built-in type and 
not an external(wrapped) type
       Wrapper* returnWrapper = getWrapper(returnValue);
+      if (returnWrapper == nullptr)
+      {
+        noWrapper(returnValue, "return");
+      }
       returnWrapper->addKeepAlive(self);
     }
   }
@@ -4672,7 +4718,8 @@
 
     //! Call the Ruby method specified by 'id' on object 'obj'.
     /*! Pass in arguments (arg1, arg2, ...).  The arguments will be converted 
to
-    *  Ruby objects with to_ruby<>.
+    *  Ruby objects with to_ruby<>. To call methods expecting keyword 
arguments,
+    *  use call_kw.
     *
     *  E.g.:
     *  \code
@@ -4690,6 +4737,29 @@
     template<typename ...Arg_Ts>
     Object call(Identifier id, Arg_Ts... args) const;
 
+    //! Call the Ruby method specified by 'id' on object 'obj'.
+    /*! Pass in arguments (arg1, arg2, ...).  The arguments will be converted 
to
+    *  Ruby objects with to_ruby<>. The final argument must be a Hash and will 
be treated
+    *  as keyword arguments to the function.
+    *
+    *  E.g.:
+    *  \code
+    *    Rice::Hash kw;
+    *    kw[":argument"] = String("one")
+    *    Rice::Object obj = x.call_kw("foo", kw);
+    *  \endcode
+    *
+    *  If a return type is specified, the return value will automatically be
+    *  converted to that type as long as 'from_ruby' exists for that type.
+    *
+    *  E.g.:
+    *  \code
+    *    float ret = x.call_kw<float>("foo", kw);
+    *  \endcode
+    */
+    template<typename ...Arg_Ts>
+    Object call_kw(Identifier id, Arg_Ts... args) const;
+
     //! Vectorized call.
     /*! Calls the method identified by id with the list of arguments
      *  identified by args.
@@ -4753,6 +4823,7 @@
 } // namespace Rice
 
 #endif // Rice__Object_defn__hpp_
+
 // ---------   Object.ipp   ---------
 #ifndef Rice__Object__ipp_
 #define Rice__Object__ipp_
@@ -4797,7 +4868,15 @@
        easy to duplicate by setting GC.stress to true and calling a constructor
        that takes multiple values like a std::pair wrapper. */
     std::array<VALUE, sizeof...(Arg_Ts)> values = { 
detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>().convert(args)... };
-    return detail::protect(rb_funcallv_kw, value(), id.id(), 
(int)values.size(), (const VALUE*)values.data(), RB_PASS_CALLED_KEYWORDS);
+    return detail::protect(rb_funcallv, value(), id.id(), (int)values.size(), 
(const VALUE*)values.data());
+  }
+
+  template<typename ...Arg_Ts>
+  inline Object Object::call_kw(Identifier id, Arg_Ts... args) const
+  {
+    /* IMPORTANT - See call() above */
+    std::array<VALUE, sizeof...(Arg_Ts)> values = { 
detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>().convert(args)... };
+    return detail::protect(rb_funcallv_kw, value(), id.id(), 
(int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
   }
 
   template<typename T>
@@ -4975,6 +5054,7 @@
 #endif // Rice__Object__ipp_
 
 
+
 // =========   Builtin_Object.hpp   =========
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/include/rice/stl.hpp new/include/rice/stl.hpp
--- old/include/rice/stl.hpp    2023-04-23 02:19:48.000000000 +0200
+++ new/include/rice/stl.hpp    2024-01-20 14:53:39.000000000 +0100
@@ -168,6 +168,11 @@
 
       return std::complex<T>(From_Ruby<T>().convert(real), 
From_Ruby<T>().convert(imaginary));
     }
+
+    bool is_convertible(VALUE value)
+    {
+      return rb_type(value) == RUBY_T_COMPLEX;
+    }
   };
 
   template<typename T>
@@ -183,11 +188,17 @@
       return this->converted_;
     }
 
+    bool is_convertible(VALUE value)
+    {
+      return rb_type(value) == RUBY_T_COMPLEX;
+    }
+
   private:
     std::complex<T> converted_;
   };
 }
 
+
 // =========   optional.hpp   =========
 
 
@@ -219,7 +230,7 @@
   class To_Ruby<std::optional<T>>
   {
   public:
-    static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
+    static VALUE convert(const std::optional<T>& data, bool takeOwnership = 
false)
     {
       if (data.has_value())
       {
@@ -236,7 +247,7 @@
   class To_Ruby<std::optional<T>&>
   {
   public:
-    static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
+    static VALUE convert(const std::optional<T>& data, bool takeOwnership = 
false)
     {
       if (data.has_value())
       {
@@ -288,6 +299,7 @@
   };
 }
 
+
 // =========   reference_wrapper.hpp   =========
 
 
@@ -309,7 +321,7 @@
   class To_Ruby<std::reference_wrapper<T>>
   {
   public:
-    VALUE convert(std::reference_wrapper<T>& data, bool takeOwnership = false)
+    VALUE convert(const std::reference_wrapper<T>& data, bool takeOwnership = 
false)
     {
       return To_Ruby<T&>().convert(data.get());
     }
@@ -334,6 +346,7 @@
   };
 }
 
+
 // =========   smart_ptr.hpp   =========
 
 
@@ -448,8 +461,18 @@
   class From_Ruby<std::shared_ptr<T>>
   {
   public:
+    From_Ruby() = default;
+
+    explicit From_Ruby(Arg * arg) : arg_(arg)
+    {
+    }
+
     std::shared_ptr<T> convert(VALUE value)
     {
+      if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
+        return this->arg_->template defaultValue<std::shared_ptr<T>>();
+      }
+
       Wrapper* wrapper = detail::getWrapper(value, 
Data_Type<T>::ruby_data_type());
 
       using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
@@ -461,14 +484,27 @@
       }
       return smartWrapper->data();
     }
+
+  private:
+    Arg* arg_ = nullptr;
   };
 
   template <typename T>
   class From_Ruby<std::shared_ptr<T>&>
   {
   public:
+    From_Ruby() = default;
+
+    explicit From_Ruby(Arg * arg) : arg_(arg)
+    {
+    }
+
     std::shared_ptr<T>& convert(VALUE value)
     {
+      if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
+        return this->arg_->template defaultValue<std::shared_ptr<T>>();
+      }
+
       Wrapper* wrapper = detail::getWrapper(value, 
Data_Type<T>::ruby_data_type());
 
       using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
@@ -480,6 +516,9 @@
       }
       return smartWrapper->data();
     }
+
+  private:
+    Arg* arg_ = nullptr;
   };
 
   template<typename T>
@@ -492,6 +531,7 @@
   };
 }
 
+
 // =========   monostate.hpp   =========
 
 
@@ -513,7 +553,7 @@
   class To_Ruby<std::monostate>
   {
   public:
-    VALUE convert(std::monostate& _)
+    VALUE convert(const std::monostate& _)
     {
       return Qnil;
     }
@@ -523,7 +563,7 @@
   class To_Ruby<std::monostate&>
   {
   public:
-    static VALUE convert(std::monostate& data, bool takeOwnership = false)
+    static VALUE convert(const std::monostate& data, bool takeOwnership = 
false)
     {
       return Qnil;
     }
@@ -563,6 +603,7 @@
   };
 }
 
+
 // =========   variant.hpp   =========
 
 
@@ -596,13 +637,13 @@
   public:
 
     template<typename T>
-    static VALUE convertElement(std::variant<Types...>& data, bool 
takeOwnership)
+    static VALUE convertElement(const std::variant<Types...>& data, bool 
takeOwnership)
     {
       return To_Ruby<T>().convert(std::get<T>(data));
     }
 
     template<std::size_t... I>
-    static VALUE convertIterator(std::variant<Types...>& data, bool 
takeOwnership, std::index_sequence<I...>& indices)
+    static VALUE convertIterator(const std::variant<Types...>& data, bool 
takeOwnership, std::index_sequence<I...>& indices)
     {
       // Create a tuple of the variant types so we can look over the tuple's 
types
       using Tuple_T = std::tuple<Types...>;
@@ -634,7 +675,7 @@
       return result;
     }
 
-    static VALUE convert(std::variant<Types...>& data, bool takeOwnership = 
false)
+    static VALUE convert(const std::variant<Types...>& data, bool 
takeOwnership = false)
     {
       auto indices = 
std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
       return convertIterator(data, takeOwnership, indices);
@@ -646,13 +687,13 @@
   {
   public:
     template<typename T>
-    static VALUE convertElement(std::variant<Types...>& data, bool 
takeOwnership)
+    static VALUE convertElement(const std::variant<Types...>& data, bool 
takeOwnership)
     {
       return To_Ruby<T>().convert(std::get<T>(data));
     }
 
     template<std::size_t... I>
-    static VALUE convertIterator(std::variant<Types...>& data, bool 
takeOwnership, std::index_sequence<I...>& indices)
+    static VALUE convertIterator(const std::variant<Types...>& data, bool 
takeOwnership, std::index_sequence<I...>& indices)
     {
       // Create a tuple of the variant types so we can look over the tuple's 
types
       using Tuple_T = std::tuple<Types...>;
@@ -665,7 +706,7 @@
       return result;
     }
 
-    static VALUE convert(std::variant<Types...>& data, bool takeOwnership = 
false)
+    static VALUE convert(const std::variant<Types...>& data, bool 
takeOwnership = false)
     {
       auto indices = 
std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
       return convertIterator(data, takeOwnership, indices);
@@ -755,6 +796,7 @@
   };
 }
 
+
 // =========   pair.hpp   =========
 
 
@@ -2331,6 +2373,11 @@
         }
       }
 
+      bool is_convertible(VALUE value)
+      {
+        return rb_type(value) == RUBY_T_ARRAY;
+      }
+
     private:
       Arg* arg_ = nullptr;
     };
@@ -2378,6 +2425,11 @@
         }
       }
 
+      bool is_convertible(VALUE value)
+      {
+        return rb_type(value) == RUBY_T_ARRAY;
+      }
+
     private:
       Arg* arg_ = nullptr;
       std::vector<T> converted_;
@@ -2413,10 +2465,16 @@
         }
       }
 
+      bool is_convertible(VALUE value)
+      {
+        return rb_type(value) == RUBY_T_ARRAY;
+      }
+
     private:
       std::vector<T> converted_;
     };
   }
 }
 
+
 #endif // Rice__stl__hpp_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mkmf-rice.rb new/lib/mkmf-rice.rb
--- old/lib/mkmf-rice.rb        2023-04-23 02:19:48.000000000 +0200
+++ new/lib/mkmf-rice.rb        2024-01-20 14:53:39.000000000 +0100
@@ -126,5 +126,7 @@
 if IS_DARWIN
   have_library('c++')
 elsif !IS_MSWIN
-  have_library('stdc++')
+  if !have_library('stdc++fs')
+    have_library('stdc++')
+  end
 end
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/version.rb new/lib/version.rb
--- old/lib/version.rb  2023-04-23 02:19:48.000000000 +0200
+++ new/lib/version.rb  2024-01-20 14:53:39.000000000 +0100
@@ -1,3 +1,3 @@
 module Rice
-  VERSION = "4.1.0"
+  VERSION = "4.2.1"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2023-04-23 02:19:48.000000000 +0200
+++ new/metadata        2024-01-20 14:53:39.000000000 +0100
@@ -1,7 +1,7 @@
 --- !ruby/object:Gem::Specification
 name: rice
 version: !ruby/object:Gem::Version
-  version: 4.1.0
+  version: 4.2.1
 platform: ruby
 authors:
 - Paul Brannan
@@ -10,7 +10,7 @@
 autorequire:
 bindir: bin
 cert_chain: []
-date: 2023-04-23 00:00:00.000000000 Z
+date: 2024-01-20 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: bundler
@@ -185,6 +185,7 @@
 - test/test_Iterator.cpp
 - test/test_Jump_Tag.cpp
 - test/test_Keep_Alive.cpp
+- test/test_Keep_Alive_No_Wrapper.cpp
 - test/test_Memory_Management.cpp
 - test/test_Module.cpp
 - test/test_Object.cpp
@@ -230,7 +231,7 @@
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 3.4.12
+rubygems_version: 3.5.4
 signing_key:
 specification_version: 4
 summary: Ruby Interface for C++ Extensions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rice/detail/NativeFunction.hpp 
new/rice/detail/NativeFunction.hpp
--- old/rice/detail/NativeFunction.hpp  2023-04-23 02:19:48.000000000 +0200
+++ new/rice/detail/NativeFunction.hpp  2024-01-20 14:53:39.000000000 +0100
@@ -95,6 +95,9 @@
     // Figure out what self is
     Class_T getReceiver(VALUE self);
 
+    // Throw an exception when wrapper cannot be extracted
+    [[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
+
     // Do we need to keep alive any arguments?
     void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& 
rubyValues);
 
@@ -113,4 +116,4 @@
 }
 #include "NativeFunction.ipp"
 
-#endif // Rice__detail__Native_Function__hpp_
\ No newline at end of file
+#endif // Rice__detail__Native_Function__hpp_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rice/detail/NativeFunction.ipp 
new/rice/detail/NativeFunction.ipp
--- old/rice/detail/NativeFunction.ipp  2023-04-23 02:19:48.000000000 +0200
+++ new/rice/detail/NativeFunction.ipp  2024-01-20 14:53:39.000000000 +0100
@@ -1,6 +1,7 @@
 #include <array>
 #include <algorithm>
 #include <stdexcept>
+#include <sstream>
 
 #include "cpp_protect.hpp"
 #include "to_ruby_defn.hpp"
@@ -38,7 +39,7 @@
   NativeFunction<From_Ruby_T, Function_T, IsMethod>::NativeFunction(VALUE 
klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
     : klass_(klass), method_name_(method_name), function_(function), 
methodInfo_(methodInfo)
   {
-   // Create a tuple of NativeArgs that will convert the Ruby values to native 
values. For 
+    // Create a tuple of NativeArgs that will convert the Ruby values to 
native values. For 
     // builtin types NativeArgs will keep a copy of the native value so that 
it 
     // can be passed by reference or pointer to the native function. For 
non-builtin types
     // it will just pass the value through.
@@ -164,7 +165,7 @@
     {
       // Call the native method and get the result
       Return_T nativeResult = std::apply(this->function_, nativeArgs);
-      
+
       // Return the result
       return this->toRuby_.convert(nativeResult);
     }
@@ -216,14 +217,37 @@
   }
 
   template<typename From_Ruby_T, typename Function_T, bool IsMethod>
+  void NativeFunction<From_Ruby_T, Function_T, IsMethod>::noWrapper(const 
VALUE klass, const std::string& wrapper)
+  {
+    std::stringstream message;
+
+    message << "When calling the method `";
+    message << this->method_name_;
+    message << "' we could not find the wrapper for the '";
+    message << rb_obj_classname(klass);
+    message << "' ";
+    message << wrapper;
+    message << " type. You should not use keepAlive() on a Return or Arg that 
is a builtin Rice type.";
+
+    throw std::runtime_error(message.str());
+  }
+
+  template<typename From_Ruby_T, typename Function_T, bool IsMethod>
   void NativeFunction<From_Ruby_T, Function_T, IsMethod>::checkKeepAlive(VALUE 
self, VALUE returnValue, std::vector<VALUE>& rubyValues)
   {
-    // Check function arguments
+    // selfWrapper will be nullptr if this(self) is a builtin type and not an 
external(wrapped) type
+    // it is highly unlikely that keepAlive is used in this case but we check 
anyway
     Wrapper* selfWrapper = getWrapper(self);
+
+    // Check function arguments
     for (const Arg& arg : (*this->methodInfo_))
     {
       if (arg.isKeepAlive())
       {
+        if (selfWrapper == nullptr)
+        {
+          noWrapper(self, "self");
+        }
         selfWrapper->addKeepAlive(rubyValues[arg.position]);
       }
     }
@@ -231,7 +255,17 @@
     // Check return value
     if (this->methodInfo_->returnInfo.isKeepAlive())
     {
+      if (selfWrapper == nullptr)
+      {
+        noWrapper(self, "self");
+      }
+
+      // returnWrapper will be nullptr if returnValue is a built-in type and 
not an external(wrapped) type
       Wrapper* returnWrapper = getWrapper(returnValue);
+      if (returnWrapper == nullptr)
+      {
+        noWrapper(returnValue, "return");
+      }
       returnWrapper->addKeepAlive(self);
     }
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rice/detail/Wrapper.ipp new/rice/detail/Wrapper.ipp
--- old/rice/detail/Wrapper.ipp 2023-04-23 02:19:48.000000000 +0200
+++ new/rice/detail/Wrapper.ipp 2024-01-20 14:53:39.000000000 +0100
@@ -193,7 +193,7 @@
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Warray-bounds"
 #endif
-    return static_cast<Wrapper*>(RTYPEDDATA_DATA(value));
+    return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) 
: nullptr;
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rice/detail/cpp_protect.hpp 
new/rice/detail/cpp_protect.hpp
--- old/rice/detail/cpp_protect.hpp     2023-04-23 02:19:48.000000000 +0200
+++ new/rice/detail/cpp_protect.hpp     2024-01-20 14:53:39.000000000 +0100
@@ -2,9 +2,18 @@
 #define Rice__detail__cpp_protect__hpp_
 
 #include <regex>
-#include <filesystem>
 #include <stdexcept>
 
+#if __has_include(<filesystem>)
+  #include <filesystem>
+  namespace fs = std::filesystem;
+#elif __has_include(<experimental/filesystem>)
+  #include <experimental/filesystem>
+  namespace fs = std::experimental::filesystem;
+#else
+  #error "no filesystem include found :'("
+#endif
+
 #include "Jump_Tag.hpp"
 #include "../Exception_defn.hpp"
 
@@ -46,7 +55,7 @@
       {
         rb_exc_raise(rb_exc_new2(rb_eArgError, ex.what()));
       }
-      catch (std::filesystem::filesystem_error const& ex)
+      catch (fs::filesystem_error const& ex)
       {
         rb_exc_raise(rb_exc_new2(rb_eIOError, ex.what()));
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sample/callbacks/extconf.rb 
new/sample/callbacks/extconf.rb
--- old/sample/callbacks/extconf.rb     2023-04-23 02:19:48.000000000 +0200
+++ new/sample/callbacks/extconf.rb     2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('sample_callbacks')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sample/enum/extconf.rb new/sample/enum/extconf.rb
--- old/sample/enum/extconf.rb  2023-04-23 02:19:48.000000000 +0200
+++ new/sample/enum/extconf.rb  2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('sample_enum')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sample/inheritance/extconf.rb 
new/sample/inheritance/extconf.rb
--- old/sample/inheritance/extconf.rb   2023-04-23 02:19:48.000000000 +0200
+++ new/sample/inheritance/extconf.rb   2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('animals')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sample/map/extconf.rb new/sample/map/extconf.rb
--- old/sample/map/extconf.rb   2023-04-23 02:19:48.000000000 +0200
+++ new/sample/map/extconf.rb   2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('map')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/embed_ruby.cpp new/test/embed_ruby.cpp
--- old/test/embed_ruby.cpp     2023-04-23 02:19:48.000000000 +0200
+++ new/test/embed_ruby.cpp     2024-01-20 14:53:39.000000000 +0100
@@ -15,6 +15,12 @@
     ruby_init();
     ruby_init_loadpath();
 
+#if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 3
+    // Force the prelude / builtins
+    char *opts[] = { "ruby", "-e;" };
+    ruby_options(2, opts);
+#endif
+
     initialized__ = true;
   }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/ext/t1/extconf.rb new/test/ext/t1/extconf.rb
--- old/test/ext/t1/extconf.rb  2023-04-23 02:19:48.000000000 +0200
+++ new/test/ext/t1/extconf.rb  2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('t1')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/ext/t2/extconf.rb new/test/ext/t2/extconf.rb
--- old/test/ext/t2/extconf.rb  2023-04-23 02:19:48.000000000 +0200
+++ new/test/ext/t2/extconf.rb  2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 
 create_makefile('t2')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/extconf.rb new/test/extconf.rb
--- old/test/extconf.rb 2023-04-23 02:19:48.000000000 +0200
+++ new/test/extconf.rb 2024-01-20 14:53:39.000000000 +0100
@@ -1,5 +1,4 @@
 require 'bundler/setup'
-require 'rice'
 require 'mkmf-rice'
 require 'rbconfig'
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Attribute.cpp new/test/test_Attribute.cpp
--- old/test/test_Attribute.cpp 2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_Attribute.cpp 2024-01-20 14:53:39.000000000 +0100
@@ -1,4 +1,4 @@
-#include <assert.h> 
+#include <assert.h>
 
 #include "unittest.hpp"
 #include "embed_ruby.hpp"
@@ -60,9 +60,9 @@
   ASSERT_EXCEPTION_CHECK(
     Exception,
     o.call("read_char=", "some text"),
-    ASSERT_EQUAL("undefined method `read_char=' for :DataStruct", ex.what())
+    ASSERT(std::string(ex.what()).find("undefined method `read_char='") == 0)
   );
-  
+
   // Test writeonly attribute
   result = o.call("write_int=", 5);
   ASSERT_EQUAL(5, detail::From_Ruby<int>().convert(result.value()));
@@ -70,7 +70,7 @@
   ASSERT_EXCEPTION_CHECK(
     Exception,
     o.call("write_int", 3),
-    ASSERT_EQUAL("undefined method `write_int' for :DataStruct", ex.what())
+    ASSERT(std::string(ex.what()).find("undefined method `write_int'") == 0)
   );
 
   // Test readwrite attribute
@@ -101,7 +101,7 @@
   ASSERT_EXCEPTION_CHECK(
     Exception,
     c.call("static_string=", true),
-    ASSERT_EQUAL("undefined method `static_string=' for DataStruct:Class", 
ex.what())
+    ASSERT(std::string(ex.what()).find("undefined method `static_string='") == 
0)
   );
 }
 
@@ -127,7 +127,7 @@
 {
   Data_Type<DataStruct> c = define_class<DataStruct>("DataStruct");
 
-#ifdef _MSC_VER    
+#ifdef _MSC_VER
   const char* message = "Type is not defined with Rice: class `anonymous 
namespace'::SomeClass";
 #else
   const char* message = "Type is not defined with Rice: (anonymous 
namespace)::SomeClass";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Keep_Alive_No_Wrapper.cpp 
new/test/test_Keep_Alive_No_Wrapper.cpp
--- old/test/test_Keep_Alive_No_Wrapper.cpp     1970-01-01 01:00:00.000000000 
+0100
+++ new/test/test_Keep_Alive_No_Wrapper.cpp     2024-01-20 14:53:39.000000000 
+0100
@@ -0,0 +1,80 @@
+#include "unittest.hpp"
+#include "embed_ruby.hpp"
+#include <rice/rice.hpp>
+#include <rice/stl.hpp>
+
+using namespace Rice;
+
+TESTSUITE(Keep_Alive_No_Wrapper);
+
+namespace
+{
+  class Animal
+  {
+    public:
+      Animal(char const * name) : name_(name) {}
+      char const * getName() { return name_; }
+      virtual ~Animal() = default;
+    private:
+      char const * name_;
+  };
+
+  class Zoo
+  {
+    public:
+      Zoo(void)
+      {
+        pets_.push_back(new Animal("Bear"));
+        pets_.push_back(new Animal("Tiger"));
+        pets_.push_back(new Animal("Lion"));
+      }
+
+      ~Zoo()
+      {
+        for(auto pet : pets_)
+        {
+         delete pet;
+        }
+        pets_.clear();
+      }
+
+    Object getPets(void)    {
+      Array pets;
+      for(auto p: pets_) {
+        pets.push(p);
+      }
+      return pets;
+    }
+
+    private:
+      std::vector<Animal*> pets_;
+  };
+}
+
+SETUP(Keep_Alive_No_Wrapper)
+{
+  embed_ruby();
+}
+
+TESTCASE(test_keep_alive_no_wrapper)
+{
+  define_class<Animal>("Animal")
+    .define_constructor(Constructor<Animal, char const *>())
+    .define_method("get_name", &Animal::getName);
+
+  define_class<Zoo>("Zoo")
+    .define_constructor(Constructor<Zoo>())
+    .define_method("get_pets", &Zoo::getPets, Return().keepAlive());
+
+  Module m = define_module("TestingModule");
+  Object zoo = m.module_eval("@zoo = Zoo.new");
+
+  // get_pets returns an Array (builtin type) so Return().keepAlive()
+  // shall result in std::runtime_error
+  ASSERT_EXCEPTION_CHECK(
+    Exception,
+    m.module_eval("@zoo.get_pets.each do |pet| puts pet.name; end"),
+    ASSERT_EQUAL("When calling the method `get_pets' we could not find the 
wrapper for the 'Array' return type. You should not use keepAlive() on a Return 
or Arg that is a builtin Rice type.",
+                 ex.what())
+  );
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Object.cpp new/test/test_Object.cpp
--- old/test/test_Object.cpp    2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_Object.cpp    2024-01-20 14:53:39.000000000 +0100
@@ -174,20 +174,29 @@
 
 TESTCASE(call_with_keywords)
 {
-  Module kernel = Module("Kernel");
+  Module m(anonymous_module());
 
+  m.module_eval(R"(
+    def self.keywords_test(value, exception:)
+      if exception
+        raise "An exception!"
+      end
+
+      value
+    end
+  )");
 
   Hash keywords;
   keywords[":exception"] = false;
-  Object result = kernel.call("Integer", "charlie", keywords);
-  ASSERT_EQUAL(Qnil, result.value());
+  Object result = m.call_kw("keywords_test", "charlie", keywords);
+  ASSERT_EQUAL("charlie", detail::From_Ruby<const 
char*>().convert(result.value()));
 
   keywords[":exception"] = true;
 
   ASSERT_EXCEPTION_CHECK(
     Exception,
-    kernel.call("Integer", "charlie", keywords),
-    ASSERT_EQUAL("invalid value for Integer(): \"charlie\"", ex.what())
+    m.call_kw("keywords_test", "charlie", keywords),
+    ASSERT_EQUAL("An exception!", ex.what())
   );
 }
 
@@ -240,4 +249,4 @@
   Object o(INT2NUM(42));
   rb_gc_start();
   ASSERT_EQUAL(42, detail::From_Ruby<int>().convert(o.value()));
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Stl_SmartPointer.cpp 
new/test/test_Stl_SmartPointer.cpp
--- old/test/test_Stl_SmartPointer.cpp  2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_Stl_SmartPointer.cpp  2024-01-20 14:53:39.000000000 +0100
@@ -109,6 +109,11 @@
   define_global_function("extract_flag_unique_ptr_ref", 
&extractFlagUniquePtrRef);
   define_global_function("extract_flag_shared_ptr", &extractFlagSharedPtr);
   define_global_function("extract_flag_shared_ptr_ref", 
&extractFlagSharedPtrRef);
+
+  define_global_function("extract_flag_shared_ptr_with_default", 
&extractFlagSharedPtr,
+      Arg("myClass") = std::make_shared<MyClass>());
+  define_global_function("extract_flag_shared_ptr_ref_with_default", 
&extractFlagSharedPtrRef,
+      Arg("myClass") = std::make_shared<MyClass>());
 }
 
 TESTCASE(TransferOwnership)
@@ -169,6 +174,7 @@
                         extract_flag_unique_ptr_ref(my_class))";
 
   Object result = m.module_eval(code);
+  ASSERT_EQUAL(7, detail::From_Ruby<int>().convert(result));
 }
 
 TESTCASE(SharedPtrParameter)
@@ -179,10 +185,11 @@
 
   std::string code = R"(factory = Factory.new
                         my_class = factory.share
-                        my_class.set_flag(7)
+                        my_class.set_flag(8)
                         extract_flag_shared_ptr(my_class))";
- 
+
   Object result = m.module_eval(code);
+  ASSERT_EQUAL(8, detail::From_Ruby<int>().convert(result));
 }
 
 TESTCASE(SharedPtrRefParameter)
@@ -193,8 +200,41 @@
 
   std::string code = R"(factory = Factory.new
                         my_class = factory.share
-                        my_class.set_flag(7)
+                        my_class.set_flag(9)
                         extract_flag_shared_ptr_ref(my_class))";
 
   Object result = m.module_eval(code);
-}
\ No newline at end of file
+  ASSERT_EQUAL(9, detail::From_Ruby<int>().convert(result));
+}
+
+TESTCASE(SharedPtrDefaultParameter)
+{
+  MyClass::reset();
+
+  Module m = define_module("TestingModule");
+
+  std::string code = R"(factory = Factory.new
+                        my_class = factory.share
+                        my_class.set_flag(7)
+                        extract_flag_shared_ptr_with_default())";
+
+  Object result = m.module_eval(code);
+  // The default value kicks in and ignores any previous pointer
+  ASSERT_EQUAL(0, detail::From_Ruby<int>().convert(result));
+}
+
+TESTCASE(SharedPtrRefDefaultParameter)
+{
+  MyClass::reset();
+
+  Module m = define_module("TestingModule");
+
+  std::string code = R"(factory = Factory.new
+                        my_class = factory.share
+                        my_class.set_flag(7)
+                        extract_flag_shared_ptr_ref_with_default())";
+
+  Object result = m.module_eval(code);
+  // The default value kicks in and ignores any previous pointer
+  ASSERT_EQUAL(0, detail::From_Ruby<int>().convert(result));
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Stl_String.cpp new/test/test_Stl_String.cpp
--- old/test/test_Stl_String.cpp        2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_Stl_String.cpp        2024-01-20 14:53:39.000000000 +0100
@@ -27,7 +27,10 @@
   Object object(value);
   Object encoding = object.call("encoding");
   Object encodingName = encoding.call("name");
-  ASSERT_EQUAL("ASCII-8BIT", 
detail::From_Ruby<std::string>().convert(encodingName));
+  std::string result = detail::From_Ruby<std::string>().convert(encodingName);
+  if(result != "ASCII-8BIT" && result != "US-ASCII" && result != "UTF-8") {
+    FAIL("Encoding incorrect", "ASCII-8BIT, US-ASCII, or UTF-8 (Windows)", 
result);
+  }
 }
 
 TESTCASE(std_string_to_ruby_encoding_utf8)
@@ -71,4 +74,4 @@
   std::string got = 
detail::From_Ruby<std::string>().convert(rb_str_new("\000test", 5));
   ASSERT_EQUAL(5ul, got.length());
   ASSERT_EQUAL(std::string("\000test", 5), got);
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_Stl_Variant.cpp 
new/test/test_Stl_Variant.cpp
--- old/test/test_Stl_Variant.cpp       2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_Stl_Variant.cpp       2024-01-20 14:53:39.000000000 +0100
@@ -4,6 +4,7 @@
 #include <rice/stl.hpp>
 
 #include <variant>
+#include <complex>
 
 using namespace Rice;
 
@@ -11,7 +12,14 @@
 
 namespace
 {
-  using Intrinsic_Variant_T = std::variant<std::string, double, bool, int>;
+  using Intrinsic_Variant_T = std::variant<
+    std::string,
+    std::complex<double>,
+    std::vector<int>,
+    double,
+    bool,
+    int
+  >;
 
   inline std::ostream& operator<<(std::ostream& stream, Intrinsic_Variant_T 
const& variant)
   {
@@ -30,6 +38,19 @@
       return result;
     }
 
+    Intrinsic_Variant_T variantComplex()
+    {
+      using namespace std::complex_literals;
+      Intrinsic_Variant_T result { 1i };
+      return result;
+    }
+
+    Intrinsic_Variant_T variantVector()
+    {
+      Intrinsic_Variant_T result { std::vector<int>{1, 2, 3} };
+      return result;
+    }
+
     Intrinsic_Variant_T variantDouble()
     {
       Intrinsic_Variant_T result { 3.3 };
@@ -73,6 +94,8 @@
   define_class<MyClass>("MyClass").
     define_constructor(Constructor<MyClass>()).
     define_method("variant_string", &MyClass::variantString).
+    define_method("variant_complex", &MyClass::variantComplex).
+    define_method("variant_vector", &MyClass::variantVector).
     define_method("variant_double", &MyClass::variantDouble).
     define_method("variant_bool_true", &MyClass::variantBoolTrue).
     define_method("variant_bool_false", &MyClass::variantBoolFalse).
@@ -83,12 +106,21 @@
 
 TESTCASE(IntrinsicReturns)
 {
+  using namespace std::complex_literals;
+
   Module m = define_module("Testing");
   Object myClass = m.module_eval("MyClass.new");
 
   Object result = myClass.call("variant_string");
   ASSERT_EQUAL("a string", detail::From_Ruby<std::string>().convert(result));
-  
+
+  result = myClass.call("variant_complex");
+  ASSERT_EQUAL(1i, detail::From_Ruby<std::complex<double>>().convert(result));
+
+  result = myClass.call("variant_vector");
+  std::vector<int> converted = 
detail::From_Ruby<std::vector<int>>().convert(result);
+  ASSERT_EQUAL(3, converted.size());
+
   result = myClass.call("variant_double");
   ASSERT_EQUAL(3.3, detail::From_Ruby<double>().convert(result));
 
@@ -104,6 +136,8 @@
 
 TESTCASE(IntrinsicRoundtrip)
 {
+  using namespace std::complex_literals;
+
   Module m = define_module("Testing");
   Object myClass = m.module_eval("MyClass.new");
 
@@ -113,6 +147,17 @@
   ASSERT_EQUAL("roundtrip string", 
detail::From_Ruby<std::string>().convert(result));
 
   code = R"(my_class = MyClass.new
+                        my_class.roundtrip(Complex(2, 3)))";
+  result = m.module_eval(code);
+  ASSERT_EQUAL((2.0 + 3i), 
detail::From_Ruby<std::complex<double>>().convert(result));
+
+  code = R"(my_class = MyClass.new
+                        my_class.roundtrip([1, 2, 3]))";
+  result = m.module_eval(code);
+  std::vector<int> expected = {1, 2, 3};
+  ASSERT_EQUAL(expected, 
detail::From_Ruby<std::vector<int>>().convert(result));
+
+  code = R"(my_class = MyClass.new
             my_class.roundtrip(44.4))";
   result = m.module_eval(code);
   ASSERT_EQUAL(44.4, detail::From_Ruby<double>().convert(result));
@@ -150,7 +195,7 @@
   ASSERT_EQUAL(77.7, detail::From_Ruby<double>().convert(result));
   result = myClass.call("variant_attr");
   ASSERT_EQUAL(77.7, detail::From_Ruby<double>().convert(result));
-  
+
   result = myClass.call("variant_attr=", true);
   ASSERT(detail::From_Ruby<bool>().convert(result));
   result = myClass.call("variant_attr");
@@ -298,4 +343,4 @@
   hello = instance2.call("say_hello");
   ASSERT_EQUAL("Hi from MyClass2", 
detail::From_Ruby<std::string>().convert(hello));
 }
-#endif
\ No newline at end of file
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_To_From_Ruby.cpp 
new/test/test_To_From_Ruby.cpp
--- old/test/test_To_From_Ruby.cpp      2023-04-23 02:19:48.000000000 +0200
+++ new/test/test_To_From_Ruby.cpp      2024-01-20 14:53:39.000000000 +0100
@@ -229,7 +229,7 @@
   ASSERT_EXCEPTION_CHECK(
     Exception,
     detail::From_Ruby<unsigned long long>().convert(rb_str_new2("bad value")),
-    ASSERT_EQUAL("no implicit conversion from string", ex.what())
+    ASSERT(std::string(ex.what()).find("no implicit conversion") == 0)
   );
 }
 
@@ -396,4 +396,4 @@
     detail::From_Ruby<const char*>().convert(rb_float_new(11.11)),
     ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
   );
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/unittest.hpp new/test/unittest.hpp
--- old/test/unittest.hpp       2023-04-23 02:19:48.000000000 +0200
+++ new/test/unittest.hpp       2024-01-20 14:53:39.000000000 +0100
@@ -236,7 +236,7 @@
 
     if constexpr (is_streamable<std::stringstream, T>::value && 
is_streamable<std::stringstream, U>::value)
     {
-      strm << s_t << " != " << s_u;
+      strm << s_t << " != " << s_u << " (" << u << ") ";
     }
     strm << " at " << file << ":" << line;
     throw Assertion_Failed(strm.str());
@@ -263,6 +263,14 @@
   }
 }
 
+#define FAIL(message, expect, got) \
+  do \
+  { \
+    std::stringstream strm; \
+    strm << message << " expected: " << (expect) << " got: " << (got); \
+    throw Assertion_Failed(strm.str()); \
+  } while(0)
+
 #define ASSERT_EQUAL(x, y) \
   do \
   { \

Reply via email to