rice 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5436 -3201
  9. data/include/rice/stl.hpp +2355 -1269
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +123 -0
  20. data/rice/Buffer.ipp +599 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +4 -5
  25. data/rice/Data_Type.ipp +42 -26
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +8 -2
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +8 -2
  64. data/rice/detail/NativeCallbackFFI.ipp +1 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +168 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyType.hpp +2 -5
  70. data/rice/detail/RubyType.ipp +50 -5
  71. data/rice/detail/Type.hpp +3 -1
  72. data/rice/detail/Type.ipp +61 -31
  73. data/rice/detail/Wrapper.hpp +68 -33
  74. data/rice/detail/Wrapper.ipp +103 -113
  75. data/rice/detail/from_ruby.hpp +5 -4
  76. data/rice/detail/from_ruby.ipp +737 -365
  77. data/rice/detail/to_ruby.ipp +1092 -186
  78. data/rice/global_function.ipp +1 -1
  79. data/rice/libc/file.hpp +11 -0
  80. data/rice/libc/file.ipp +32 -0
  81. data/rice/rice.hpp +23 -16
  82. data/rice/stl/complex.hpp +6 -0
  83. data/rice/stl/complex.ipp +93 -0
  84. data/rice/stl/exception.hpp +11 -0
  85. data/rice/stl/exception.ipp +29 -0
  86. data/rice/stl/exception_ptr.hpp +6 -0
  87. data/rice/stl/exception_ptr.ipp +27 -0
  88. data/rice/stl/map.hpp +12 -0
  89. data/rice/stl/map.ipp +469 -0
  90. data/rice/stl/monostate.hpp +6 -0
  91. data/rice/stl/monostate.ipp +80 -0
  92. data/rice/stl/multimap.hpp +14 -0
  93. data/rice/stl/multimap.ipp +448 -0
  94. data/rice/stl/optional.hpp +6 -0
  95. data/rice/stl/optional.ipp +118 -0
  96. data/rice/stl/pair.hpp +13 -0
  97. data/rice/stl/pair.ipp +155 -0
  98. data/rice/stl/reference_wrapper.hpp +6 -0
  99. data/rice/stl/reference_wrapper.ipp +41 -0
  100. data/rice/stl/set.hpp +12 -0
  101. data/rice/stl/set.ipp +495 -0
  102. data/rice/stl/shared_ptr.hpp +28 -0
  103. data/rice/stl/shared_ptr.ipp +224 -0
  104. data/rice/stl/string.hpp +6 -0
  105. data/rice/stl/string.ipp +158 -0
  106. data/rice/stl/string_view.hpp +6 -0
  107. data/rice/stl/string_view.ipp +65 -0
  108. data/rice/stl/tuple.hpp +6 -0
  109. data/rice/stl/tuple.ipp +128 -0
  110. data/rice/stl/type_index.hpp +6 -0
  111. data/rice/stl/type_index.ipp +30 -0
  112. data/rice/stl/type_info.hpp +6 -0
  113. data/rice/stl/type_info.ipp +29 -0
  114. data/rice/stl/unique_ptr.hpp +22 -0
  115. data/rice/stl/unique_ptr.ipp +139 -0
  116. data/rice/stl/unordered_map.hpp +12 -0
  117. data/rice/stl/unordered_map.ipp +469 -0
  118. data/rice/stl/variant.hpp +6 -0
  119. data/rice/stl/variant.ipp +242 -0
  120. data/rice/stl/vector.hpp +12 -0
  121. data/rice/stl/vector.ipp +590 -0
  122. data/rice/stl.hpp +7 -3
  123. data/rice/traits/attribute_traits.hpp +26 -0
  124. data/rice/traits/function_traits.hpp +95 -0
  125. data/rice/traits/method_traits.hpp +47 -0
  126. data/rice/traits/rice_traits.hpp +160 -0
  127. data/rice.gemspec +85 -0
  128. data/test/embed_ruby.cpp +3 -0
  129. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  130. data/test/test_Array.cpp +6 -3
  131. data/test/test_Attribute.cpp +34 -1
  132. data/test/test_Buffer.cpp +285 -0
  133. data/test/test_Callback.cpp +2 -3
  134. data/test/test_Data_Object.cpp +88 -34
  135. data/test/test_Data_Type.cpp +106 -65
  136. data/test/test_Director.cpp +7 -3
  137. data/test/test_Enum.cpp +5 -2
  138. data/test/test_File.cpp +1 -1
  139. data/test/test_From_Ruby.cpp +181 -114
  140. data/test/test_Iterator.cpp +1 -1
  141. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  142. data/test/test_Keep_Alive.cpp +7 -18
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  144. data/test/test_Module.cpp +13 -6
  145. data/test/test_Native_Registry.cpp +0 -1
  146. data/test/test_Overloads.cpp +180 -5
  147. data/test/test_Ownership.cpp +100 -57
  148. data/test/test_Proc.cpp +0 -1
  149. data/test/test_Self.cpp +4 -4
  150. data/test/test_Stl_Map.cpp +37 -39
  151. data/test/test_Stl_Multimap.cpp +693 -0
  152. data/test/test_Stl_Pair.cpp +8 -8
  153. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  154. data/test/test_Stl_Set.cpp +790 -0
  155. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  156. data/test/test_Stl_Tuple.cpp +116 -0
  157. data/test/test_Stl_Type.cpp +1 -1
  158. data/test/test_Stl_UniquePtr.cpp +202 -0
  159. data/test/test_Stl_Unordered_Map.cpp +28 -34
  160. data/test/test_Stl_Variant.cpp +217 -89
  161. data/test/test_Stl_Vector.cpp +209 -83
  162. data/test/test_To_Ruby.cpp +373 -1
  163. data/test/test_Type.cpp +85 -14
  164. data/test/test_global_functions.cpp +17 -4
  165. metadata +94 -10
  166. data/rice/detail/TupleIterator.hpp +0 -14
@@ -0,0 +1,113 @@
1
+ #ifndef Rice__ruby_struct__hpp_
2
+ #define Rice__ruby_struct__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ //! A wrapper for creating Struct classes.
7
+ /*! The Struct class is used for creating new Classes. Note that the
8
+ * notation used here differs slightly from the notation inside the
9
+ * interpreter.
10
+ *
11
+ * Inside the interpreter, calling Struct.new creates a new Class:
12
+ * \code
13
+ * irb(main):001:0> MyStruct = Struct.new(:a, :b, :c)
14
+ * => S
15
+ * irb(main):002:0> MyStruct.class
16
+ * => Class
17
+ * \endcode
18
+ *
19
+ * Instantiating that Class creates an instance of that Class:
20
+ * \code
21
+ * irb(main):003:0> mystruct_instance = MyStruct.new
22
+ * => #<struct MyStruct a=nil, b=nil, c=nil>
23
+ * irb(main):004:0> mystruct_instance.class
24
+ * => MyStruct
25
+ * irb(main):005:0> mystruct_instance.class.ancestors
26
+ * => [MyStruct, Struct, Enumerable, Object, Kernel]
27
+ * \endcode
28
+ *
29
+ * Thus, inside the interpreter, MyStruct is a Class which inherits
30
+ * from Struct, and mystruct_instance is an instance of MyStruct.
31
+ *
32
+ * At the C++ level, we might do this instead:
33
+ * \code
34
+ * Struct rb_cMyStruct = define_struct()
35
+ * .define_member("a")
36
+ * .define_member("b")
37
+ * .define_member("c")
38
+ * .initialize("MyStruct");
39
+ * Struct::Instance mystruct_instance(rb_cMyStruct.new_instance());
40
+ * \endcode
41
+ *
42
+ * Here rb_cMyStruct is an instance of Struct and that mystruct_instance
43
+ * is an instance of Struct::Instance.
44
+ */
45
+ class Struct : public Class
46
+ {
47
+ public:
48
+ //! Define a new Struct member.
49
+ /*! Defines a new member of the Struct. Must be called before the
50
+ * Struct is initialized.
51
+ * \return *this
52
+ */
53
+ Struct& define_member(Identifier name);
54
+
55
+ //! Initialize the Struct class.
56
+ /*! Must be called after all Struct members have been defined.
57
+ * \param module the module under which to define the Struct.
58
+ * \param name the name of the Class at the ruby level.
59
+ */
60
+ Struct& initialize(Module module, Identifier name);
61
+
62
+ //! Get the members in Struct.
63
+ Array members() const;
64
+
65
+ class Instance;
66
+ friend class Instance;
67
+ //friend Struct Rice::define_struct();
68
+
69
+ //! Create a new instance of the Struct
70
+ /*! \param args the arguments to the constructor.
71
+ * \return a new Struct::Instance
72
+ */
73
+ Instance new_instance(Array args = Array()) const;
74
+
75
+ private:
76
+ std::vector<Symbol> members_;
77
+ };
78
+
79
+ //! An instance of a Struct
80
+ //! \sa Struct
81
+ class Struct::Instance : public Builtin_Object<T_STRUCT>
82
+ {
83
+ public:
84
+ //! Create a new Instance of a Struct.
85
+ /*! \param type the Struct type to create.
86
+ * \param args the initial values for the objects of the instance.
87
+ */
88
+ Instance(Struct const& type,Array args = Array());
89
+
90
+ //! Encapsulate an existing Struct instance.
91
+ /*! \param type the Struct type to encapsulate.
92
+ * \param s the instance to encapsulate.
93
+ */
94
+ Instance(Struct const& type, Object s);
95
+
96
+ //! Get a member, given its offset.
97
+ /*! \param index the (integral) index into the Struct's internal
98
+ * array or its name (an Identifier or char const *)
99
+ * \return the member.
100
+ */
101
+ template<typename T>
102
+ Object operator[](T index);
103
+
104
+ private:
105
+ Struct type_;
106
+ };
107
+
108
+ //! Define a new Struct
109
+ Struct define_struct();
110
+
111
+ } // namespace Rice
112
+
113
+ #endif // Rice__ruby_struct__hpp_
@@ -0,0 +1,92 @@
1
+
2
+ namespace Rice
3
+ {
4
+ inline Struct& Struct::initialize(Module module, Identifier name)
5
+ {
6
+ Class struct_class(rb_cStruct);
7
+
8
+ Object type = struct_class.vcall("new", this->members());
9
+
10
+ set_value(type);
11
+ module.const_set(name, type);
12
+
13
+ return *this;
14
+ }
15
+
16
+ inline Struct& Struct::define_member(Identifier name)
17
+ {
18
+ if (value() != rb_cObject)
19
+ {
20
+ throw std::runtime_error("struct is already initialized");
21
+ }
22
+
23
+ members_.push_back(name.to_sym());
24
+
25
+ return *this;
26
+ }
27
+
28
+ inline Array Struct::members() const
29
+ {
30
+ if (value() == rb_cObject)
31
+ {
32
+ // Struct is not yet defined
33
+ return Array(members_.begin(), members_.end());
34
+ }
35
+ else
36
+ {
37
+ // Struct is defined, call Ruby API
38
+ return rb_struct_s_members(this->value());
39
+ }
40
+ }
41
+
42
+ inline Struct::Instance Struct::new_instance(Array args) const
43
+ {
44
+ Object instance = const_cast<Struct*>(this)->vcall("new", args);
45
+ return Instance(*this, instance);
46
+ }
47
+
48
+ inline Struct::Instance::Instance(Struct const& type, Array args) :
49
+ Builtin_Object<T_STRUCT>(type.new_instance(args)), type_(type)
50
+ {
51
+ }
52
+
53
+ inline Struct::Instance::Instance(Struct const& type, Object s) :
54
+ Builtin_Object<T_STRUCT>(s), type_(type)
55
+ {
56
+ }
57
+
58
+ inline Struct define_struct()
59
+ {
60
+ return Struct();
61
+ }
62
+
63
+ template<typename T>
64
+ inline Object Struct::Instance::operator[](T index)
65
+ {
66
+ return rb_struct_aref(value(), ULONG2NUM(index));
67
+ }
68
+
69
+ template<>
70
+ inline Object Struct::Instance::operator[]<Identifier>(Identifier member)
71
+ {
72
+ return rb_struct_aref(value(), Symbol(member));
73
+ }
74
+
75
+ template<>
76
+ inline Object Struct::Instance::operator[]<char const*>(char const* name)
77
+ {
78
+ return (*this)[Identifier(name)];
79
+ }
80
+ }
81
+
82
+ namespace Rice::detail
83
+ {
84
+ template<>
85
+ struct Type<Struct>
86
+ {
87
+ static bool verify()
88
+ {
89
+ return true;
90
+ }
91
+ };
92
+ }
@@ -0,0 +1,46 @@
1
+ #ifndef Rice__Symbol__hpp_
2
+ #define Rice__Symbol__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ //! A wrapper for ruby's Symbol class.
7
+ /*! Symbols are internal identifiers in ruby. They are singletons and
8
+ * can be thought of as frozen strings. They differ from an Identifier
9
+ * in that they are in fact real Objects, but they can be converted
10
+ * back and forth between Identifier and Symbol.
11
+ */
12
+ class Symbol
13
+ : public Object
14
+ {
15
+ public:
16
+ //! Wrap an existing symbol.
17
+ Symbol(VALUE v);
18
+
19
+ //! Wrap an existing symbol.
20
+ Symbol(Object v);
21
+
22
+ //! Construct a Symbol from an Identifier.
23
+ Symbol(Identifier id);
24
+
25
+ //! Construct a Symbol from a null-terminated C string.
26
+ Symbol(char const* s = "");
27
+
28
+ //! Construct a Symbol from an std::string.
29
+ Symbol(std::string const& s);
30
+
31
+ //! Construct a Symbol from an std::string_view.
32
+ Symbol(std::string_view const& s);
33
+
34
+ //! Return a string representation of the Symbol.
35
+ char const* c_str() const;
36
+
37
+ //! Return a string representation of the Symbol.
38
+ std::string str() const;
39
+
40
+ //! Return the Symbol as an Identifier.
41
+ Identifier to_id() const;
42
+ };
43
+ } // namespace Rice
44
+
45
+ #endif // Rice__Symbol__hpp_
46
+
@@ -0,0 +1,93 @@
1
+ namespace Rice
2
+ {
3
+ inline Symbol::Symbol(VALUE value) : Object(value)
4
+ {
5
+ detail::protect(rb_check_type, value, (int)T_SYMBOL);
6
+ }
7
+
8
+ inline Symbol::Symbol(Object value) : Object(value)
9
+ {
10
+ detail::protect(rb_check_type, value.value(), (int)T_SYMBOL);
11
+ }
12
+
13
+ inline Symbol::Symbol(char const* s)
14
+ : Object(detail::protect(rb_id2sym, detail::protect(rb_intern, s)))
15
+ {
16
+ }
17
+
18
+ inline Symbol::Symbol(std::string const& s)
19
+ : Object(detail::protect(rb_id2sym, detail::protect(rb_intern2, s.c_str(), (long)s.length())))
20
+ {
21
+ }
22
+
23
+ inline Symbol::Symbol(std::string_view const& view)
24
+ : Object(detail::protect(rb_id2sym, detail::protect(rb_intern2, view.data(), (long)view.length())))
25
+ {
26
+ }
27
+
28
+ inline Symbol::Symbol(Identifier id) : Object(detail::protect(rb_id2sym, id))
29
+ {
30
+ }
31
+
32
+ inline char const* Symbol::c_str() const
33
+ {
34
+ return to_id().c_str();
35
+ }
36
+
37
+ inline std::string Symbol::str() const
38
+ {
39
+ return to_id().str();
40
+ }
41
+
42
+ inline Identifier Symbol::to_id() const
43
+ {
44
+ return rb_to_id(value());
45
+ }
46
+ }
47
+
48
+ namespace Rice::detail
49
+ {
50
+ template<>
51
+ struct Type<Symbol>
52
+ {
53
+ static bool verify()
54
+ {
55
+ return true;
56
+ }
57
+ };
58
+
59
+ template<>
60
+ class To_Ruby<Symbol>
61
+ {
62
+ public:
63
+ VALUE convert(Symbol const& x)
64
+ {
65
+ return x.value();
66
+ }
67
+ };
68
+
69
+ template<>
70
+ class From_Ruby<Symbol>
71
+ {
72
+ public:
73
+ Convertible is_convertible(VALUE value)
74
+ {
75
+ switch (rb_type(value))
76
+ {
77
+ case RUBY_T_SYMBOL:
78
+ return Convertible::Exact;
79
+ break;
80
+ case RUBY_T_STRING:
81
+ return Convertible::Cast;
82
+ break;
83
+ default:
84
+ return Convertible::None;
85
+ }
86
+ }
87
+
88
+ Symbol convert(VALUE value)
89
+ {
90
+ return Symbol(value);
91
+ }
92
+ };
93
+ }
@@ -0,0 +1,134 @@
1
+ // Include these methods to call methods from Module but return
2
+ // an instance of the current classes. This is an alternative to
3
+ // using CRTP.
4
+
5
+
6
+ //! Include a module.
7
+ /*! \param inc the module to be included.
8
+ * \return *this
9
+ */
10
+ inline auto& include_module(Module const& inc)
11
+ {
12
+ detail::protect(rb_include_module, this->value(), inc.value());
13
+ return *this;
14
+ }
15
+
16
+ //! Define an instance method.
17
+ /*! The method's implementation can be a member function, plain function
18
+ * or lambda. The easiest case is a member function where the Ruby
19
+ * method maps one-to-one to the C++ method. In the case of a
20
+ * plain function or lambda, the first argument must be SELF - ie,
21
+ * the current object. If the type of the first argument is VALUE, then
22
+ * the current Ruby object is passed. If the type is a C++ class,
23
+ * then the C++ object is passed. If you don't want to include the
24
+ * SELF argument see define_function.
25
+ * Rice will automatically convert method parameters from Ruby to C++ and
26
+ * convert the return value from C++ to Ruby.
27
+ * \param name the name of the method
28
+ * \param func the implementation of the function, either a function
29
+ * pointer or a member function pointer.
30
+ * \param args a list of Arg instance used to define default parameters.
31
+ * \return *this
32
+ */
33
+ template<typename Function_T, typename...Arg_Ts>
34
+ inline auto& define_method(std::string name, Function_T&& func, const Arg_Ts&...args)
35
+ {
36
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, true>::arity, args...);
37
+ this->wrap_native_call<true>(this->value(), name, std::forward<Function_T>(func), methodInfo);
38
+ return *this;
39
+ }
40
+
41
+ //! Define a function.
42
+ /*! The function implementation is a plain function or a static
43
+ * member function.
44
+ * Rice will automatically convert method method from Ruby to C++ and
45
+ * then convert the return value from C++ to Ruby.
46
+ * \param name the name of the method
47
+ * \param func the implementation of the function, either a function
48
+ * pointer or a member function pointer.
49
+ * \param args a list of Arg instance used to define default parameters (optional)
50
+ * \return *this
51
+ */
52
+ template<typename Function_T, typename...Arg_Ts>
53
+ inline auto& define_function(std::string name, Function_T&& func, const Arg_Ts&...args)
54
+ {
55
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, false>::arity, args...);
56
+ this->wrap_native_call<false>(this->value(), name, std::forward<Function_T>(func), methodInfo);
57
+ return *this;
58
+ }
59
+
60
+ //! Define a singleton method.
61
+ /*! The method's implementation can be a static member function,
62
+ * plain function or lambda. In all cases the first argument
63
+ * must be SELF - ie, the current object. If it is specified as a VALUE, then
64
+ * the current Ruby object is passed. If it is specified as a C++ class,
65
+ * then the C++ object is passed. If you don't want to include the
66
+ * SELF argument see define_singleton_function.
67
+ * Rice will automatically convert method method from Ruby to C++ and
68
+ * then convert the return value from C++ to Ruby.
69
+ * \param name the name of the method
70
+ * \param func the implementation of the function, either a function
71
+ * pointer or a member function pointer.
72
+ * \param args a list of Arg instance used to define default parameters (optional)
73
+ * \return *this
74
+ */
75
+ template<typename Function_T, typename...Arg_Ts>
76
+ inline auto& define_singleton_method(std::string name, Function_T&& func, const Arg_Ts&...args)
77
+ {
78
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, true>::arity, args...);
79
+ this->wrap_native_call<true>(rb_singleton_class(*this), name, std::forward<Function_T>(func), methodInfo);
80
+ return *this;
81
+ }
82
+
83
+ //! Define a singleton method.
84
+ /*! The method's implementation can be a static member function, plain
85
+ * function or lambda. A wrapper will be generated which will convert the method
86
+ * from ruby types to C++ types before calling the function. The return
87
+ * value will be converted back to ruby.
88
+ * \param name the name of the method
89
+ * \param func the implementation of the function, either a function
90
+ * pointer or a member function pointer.
91
+ * \param args a list of Arg instance used to define default parameters (optional)
92
+ * \return *this
93
+ */
94
+ template<typename Function_T, typename...Arg_Ts>
95
+ inline auto& define_singleton_function(std::string name, Function_T&& func, const Arg_Ts& ...args)
96
+ {
97
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, false>::arity, args...);
98
+ this->wrap_native_call<false>(rb_singleton_class(*this), name, std::forward<Function_T>(func), methodInfo);
99
+ return *this;
100
+ }
101
+
102
+ //! Define a module function.
103
+ /*! A module function is a function that can be accessed either as a
104
+ * singleton method or as an instance method. It wrap a plain
105
+ * function, static member function or lambda.
106
+ * Rice will automatically convert method method from Ruby to C++ and
107
+ * then convert the return value from C++ to Ruby.
108
+ * \param name the name of the method
109
+ * \param func the implementation of the function, either a function
110
+ * pointer or a member function pointer.
111
+ * \param args a list of Arg instance used to define default parameters (optional)
112
+ * \return *this
113
+ */
114
+ template<typename Function_T, typename...Arg_Ts>
115
+ inline auto& define_module_function(std::string name, Function_T&& func, const Arg_Ts& ...args)
116
+ {
117
+ if (this->rb_type() != T_MODULE)
118
+ {
119
+ throw std::runtime_error("can only define module functions for modules");
120
+ }
121
+
122
+ define_function(name, std::forward<Function_T>(func), args...);
123
+ define_singleton_function(name, std::forward<Function_T>(func), args...);
124
+ return *this;
125
+ }
126
+
127
+ //! Define a constant
128
+ template<typename Constant_T>
129
+ inline auto& define_constant(std::string name, Constant_T value)
130
+ {
131
+ using Base_T = detail::remove_cv_recursive_t<Constant_T>;
132
+ detail::protect(rb_define_const, this->value(), name.c_str(), detail::To_Ruby<Base_T>().convert(value));
133
+ return *this;
134
+ }
@@ -13,12 +13,6 @@ namespace Rice
13
13
  template <typename...Arg_Ts>
14
14
  MethodInfo(size_t argCount, const Arg_Ts&...args);
15
15
 
16
- /**
17
- * Get the rb_scan_args format string for this
18
- * list of arguments.
19
- */
20
- std::string formatString();
21
-
22
16
  /**
23
17
  * Add a defined Arg to this list of Arguments
24
18
  */
@@ -34,9 +28,7 @@ namespace Rice
34
28
  */
35
29
  Arg* arg(std::string name);
36
30
 
37
- int requiredArgCount();
38
- int optionalArgCount();
39
- void verifyArgCount(int argc);
31
+ int argCount();
40
32
 
41
33
  // Iterator support
42
34
  std::vector<Arg>::iterator begin();
@@ -25,11 +25,13 @@ namespace Rice
25
25
  template <typename Arg_T>
26
26
  inline void MethodInfo::processArg(const Arg_T& arg)
27
27
  {
28
+ static_assert(std::is_same_v<Arg_T, Return> || std::is_same_v<Arg_T, Arg>, "Unknown argument type");
29
+
28
30
  if constexpr (std::is_same_v<Arg_T, Return>)
29
31
  {
30
32
  this->returnInfo = arg;
31
33
  }
32
- else
34
+ else if constexpr (std::is_same_v<Arg_T, Arg>)
33
35
  {
34
36
  this->addArg(arg);
35
37
  }
@@ -40,78 +42,9 @@ namespace Rice
40
42
  this->args_.push_back(arg);
41
43
  }
42
44
 
43
- inline int MethodInfo::requiredArgCount()
44
- {
45
- int result = 0;
46
-
47
- for (const Arg& arg : this->args_)
48
- {
49
- if (!arg.hasDefaultValue())
50
- {
51
- result++;
52
- }
53
- }
54
-
55
- return result;
56
- }
57
-
58
- inline int MethodInfo::optionalArgCount()
59
- {
60
- int result = 0;
61
-
62
- for (const Arg& arg : this->args_)
63
- {
64
- if (arg.hasDefaultValue())
65
- {
66
- result++;
67
- }
68
- }
69
-
70
- return result;
71
- }
72
-
73
- inline void MethodInfo::verifyArgCount(int argc)
45
+ inline int MethodInfo::argCount()
74
46
  {
75
- int requiredArgCount = this->requiredArgCount();
76
- int optionalArgCount = this->optionalArgCount();
77
-
78
- if (argc < requiredArgCount || argc > requiredArgCount + optionalArgCount)
79
- {
80
- std::string message;
81
-
82
- if (optionalArgCount > 0)
83
- {
84
- message = "wrong number of arguments (given " +
85
- std::to_string(argc) + ", expected " +
86
- std::to_string(requiredArgCount) + ".." + std::to_string(requiredArgCount + optionalArgCount) + ")";
87
- }
88
- else
89
- {
90
- message = "wrong number of arguments (given " +
91
- std::to_string(argc) + ", expected " + std::to_string(requiredArgCount) + ")";
92
- }
93
- throw std::invalid_argument(message);
94
- }
95
- }
96
-
97
- inline std::string MethodInfo::formatString()
98
- {
99
- size_t required = 0;
100
- size_t optional = 0;
101
-
102
- for (const Arg& arg : this->args_)
103
- {
104
- if (arg.hasDefaultValue())
105
- {
106
- optional++;
107
- }
108
- else
109
- {
110
- required++;
111
- }
112
- }
113
-
114
- return std::to_string(required) + std::to_string(optional);
47
+ return this->args_.size();
115
48
  }
116
49
 
117
50
  inline Arg* MethodInfo::arg(size_t pos)
@@ -24,8 +24,9 @@ namespace Rice::detail
24
24
  virtual ~Native() = default;
25
25
  VALUE call(int argc, VALUE* argv, VALUE self);
26
26
 
27
- virtual Resolved matches(int argc, const VALUE* argv, VALUE self) = 0;
28
- virtual VALUE operator()(int argc, const VALUE* argv, VALUE self) = 0;
27
+ virtual Resolved matches(size_t argc, const VALUE* argv, VALUE self) = 0;
28
+ virtual VALUE operator()(size_t argc, const VALUE* argv, VALUE self) = 0;
29
+ virtual std::string toString() = 0;
29
30
  };
30
31
  }
31
32
 
@@ -83,6 +83,8 @@ namespace Rice::detail
83
83
  }
84
84
  else
85
85
  {
86
+ Identifier identifier(methodId);
87
+
86
88
  // Loop over every native to see how well they match the Ruby parameters
87
89
  std::vector<Resolved> resolves;
88
90
  std::transform(natives.begin(), natives.end(),
@@ -95,9 +97,30 @@ namespace Rice::detail
95
97
  // Now sort from best to worst
96
98
  std::sort(resolves.begin(), resolves.end(), std::greater{});
97
99
 
98
- // Get the best one
100
+ // Get the first one
99
101
  Resolved resolved = resolves.front();
100
102
 
103
+ // Was there more than one match?
104
+ /*size_t count = std::count_if(resolves.begin(), resolves.end(),
105
+ [&resolved](Resolved& element)
106
+ {
107
+ return resolved.convertible == element.convertible;
108
+ });
109
+
110
+ if (count > 1)
111
+ {
112
+ std::ostringstream message;
113
+ message << "Could not resolve method call for %s#%s" << "\n"
114
+ << " %d overloaded functions matched based on the types of Ruby parameters provided:";
115
+
116
+ for (int i = 0; i < count; i++)
117
+ {
118
+ message << "\n " << resolves[i].native->toString();
119
+ }
120
+
121
+ rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), count);
122
+ }*/
123
+
101
124
  // Did it match?
102
125
  if (resolved.convertible != Convertible::None)
103
126
  {
@@ -107,7 +130,6 @@ namespace Rice::detail
107
130
  {
108
131
  // Special case == to make the RubyMine debugger work. It calls == with a Module as
109
132
  // the other argument, thus breaking if C++ operator== is implemented.
110
- Identifier identifier(methodId);
111
133
  if (identifier.str() == "==")
112
134
  {
113
135
  return detail::protect(rb_call_super, argc, argv);
@@ -116,8 +138,14 @@ namespace Rice::detail
116
138
  {
117
139
  std::ostringstream message;
118
140
  message << "Could not resolve method call for %s#%s" << "\n"
119
- << " %d overload(s) were evaluated based on the types of Ruby parameters provided.";
120
- rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
141
+ << " %d overload(s) were evaluated based on the types of Ruby parameters provided:";
142
+
143
+ for (Resolved& resolve: resolves)
144
+ {
145
+ message << "\n " << resolve.native->toString();
146
+ }
147
+
148
+ rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
121
149
  }
122
150
  }
123
151
  }
@@ -34,8 +34,9 @@ namespace Rice
34
34
  void operator=(const NativeAttribute_T&) = delete;
35
35
  void operator=(NativeAttribute_T&&) = delete;
36
36
 
37
- Resolved matches(int argc, const VALUE* argv, VALUE self) override;
38
- VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
37
+ Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
38
+ VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
39
+ std::string toString() override;
39
40
 
40
41
  protected:
41
42
  NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr);