ruby-qt6-rice 2.1.0 → 6.1.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Rakefile +12 -1
  4. data/ext/qt6/rice/extconf.rb +5 -0
  5. data/ext/qt6/rice/rice-rb.cpp +10 -0
  6. data/ext/qt6/rice/rice-rb.hpp +3 -0
  7. data/include/bando/common.hpp +2 -1
  8. data/include/bando/qobject/qdbusabstractadaptor.hpp +13 -12
  9. data/include/bando/qobject/qdbusabstractinterface.hpp +2 -2
  10. data/include/bando/qobject/qitemdelegate.hpp +25 -24
  11. data/include/bando/qobject/qlayout.hpp +32 -31
  12. data/include/bando/qobject/qsortfilterproxymodel.hpp +132 -0
  13. data/include/bando/qobject/qwebenginepage.hpp +61 -46
  14. data/include/bando/qobject.hpp +1 -1
  15. data/include/bando/qwidget/qspinbox.hpp +27 -22
  16. data/include/bando/qwidget.hpp +1 -1
  17. data/include/rice/core/rice.hpp +1711 -1314
  18. data/include/rice/core/stl.hpp +562 -82
  19. data/include/rice/cxx/asserts.hpp +31 -0
  20. data/include/rice/cxx/concepts.hpp +31 -0
  21. data/include/rice/qt6/preludes/libqt6core.hpp +192 -0
  22. data/include/rice/qt6/preludes/libqt6gui.hpp +176 -0
  23. data/include/rice/qt6/preludes/libqt6multimedia.hpp +33 -0
  24. data/include/rice/qt6/preludes/libqt6qml.hpp +33 -0
  25. data/include/rice/qt6/preludes/libqt6quick.hpp +30 -0
  26. data/include/rice/qt6/preludes/libqt6webenginecore.hpp +30 -0
  27. data/include/rice/qt6/preludes/libqt6widgets.hpp +35 -0
  28. data/include/rice/qt6/preludes/qlass.hpp +63 -0
  29. data/include/rice/qt6/preludes/registries.hpp +52 -0
  30. data/include/rice/qt6/preludes.hpp +28 -0
  31. data/include/rice/qt6/qdbusreply.hpp +3 -3
  32. data/include/rice/qt6/qenum.hpp +1 -1
  33. data/include/rice/qt6/qflags.hpp +1 -1
  34. data/include/rice/qt6/qlist.hpp +17 -20
  35. data/include/rice/qt6/qmap.hpp +14 -11
  36. data/include/rice/qt6.hpp +3 -0
  37. data/lib/mkmf-rubyqt6.rb +24 -7
  38. data/lib/qt6/rice/version.rb +1 -1
  39. data/lib/qt6/rice.rb +1 -0
  40. metadata +19 -2
@@ -115,6 +115,114 @@ namespace Rice4RubyQt6::detail
115
115
  }
116
116
 
117
117
 
118
+ // ========= function.hpp =========
119
+
120
+ namespace Rice4RubyQt6
121
+ {
122
+ template<typename Signature_T>
123
+ Data_Type<std::function<Signature_T>> define_stl_function(std::string klassName = "");
124
+ }
125
+
126
+
127
+ // --------- function.ipp ---------
128
+ #include <functional>
129
+
130
+ namespace Rice4RubyQt6::stl
131
+ {
132
+ template<typename T>
133
+ class FunctionHelper
134
+ {
135
+ using Function_T = T;
136
+
137
+ public:
138
+ FunctionHelper(Data_Type<T> klass) : klass_(klass)
139
+ {
140
+ this->define_constructors();
141
+ this->define_methods();
142
+ }
143
+
144
+ private:
145
+ void define_constructors()
146
+ {
147
+ // Default constructor
148
+ klass_.define_constructor(Constructor<Function_T>());
149
+
150
+ // Constructor from Ruby callable
151
+ klass_.define_method("initialize", [](VALUE self, VALUE callable) -> void
152
+ {
153
+ // Create std::function that wraps the Ruby callable
154
+ Function_T* data = new Function_T([callable](auto... args)
155
+ {
156
+ Object result = Object(callable).call("call", args...);
157
+
158
+ using Return_T = typename Function_T::result_type;
159
+ if constexpr (!std::is_void_v<Return_T>)
160
+ {
161
+ return detail::From_Ruby<std::remove_cv_t<Return_T>>().convert(result);
162
+ }
163
+ });
164
+
165
+ // Wrap the function
166
+ detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data);
167
+ }, Arg("callable").setValue().keepAlive());
168
+ }
169
+
170
+ void define_methods()
171
+ {
172
+ klass_.define_method("call", &Function_T::operator());
173
+ klass_.define_method("callable?", [](const Function_T& func) -> bool
174
+ {
175
+ return static_cast<bool>(func);
176
+ });
177
+ }
178
+
179
+ Data_Type<T> klass_;
180
+ };
181
+ }
182
+
183
+ namespace Rice4RubyQt6
184
+ {
185
+ template<typename Signature_T>
186
+ Data_Type<std::function<Signature_T>> define_stl_function(std::string klassName)
187
+ {
188
+ using Function_T = std::function<Signature_T>;
189
+ using Data_Type_T = Data_Type<Function_T>;
190
+
191
+ if (klassName.empty())
192
+ {
193
+ detail::TypeDetail<Function_T> typeDetail;
194
+ klassName = typeDetail.rubyName();
195
+ }
196
+
197
+ Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
198
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
199
+ {
200
+ return Data_Type_T();
201
+ }
202
+
203
+ Identifier id(klassName);
204
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Function_T>>(rb_mStd, id);
205
+
206
+ stl::FunctionHelper helper(result);
207
+
208
+ return result;
209
+ }
210
+ }
211
+
212
+ namespace Rice4RubyQt6::detail
213
+ {
214
+ template<typename Signature_T>
215
+ struct Type<std::function<Signature_T>>
216
+ {
217
+ static bool verify()
218
+ {
219
+ define_stl_function<Signature_T>();
220
+ return true;
221
+ }
222
+ };
223
+ }
224
+
225
+
118
226
  // ========= string.hpp =========
119
227
 
120
228
 
@@ -735,8 +843,8 @@ namespace Rice4RubyQt6::detail
735
843
 
736
844
  static VALUE rubyKlass()
737
845
  {
738
- TypeMapper<T> typeMapper;
739
- return typeMapper.rubyKlass();
846
+ TypeDetail<T> typeDetail;
847
+ return typeDetail.rubyKlass();
740
848
  }
741
849
  };
742
850
 
@@ -902,71 +1010,266 @@ namespace Rice4RubyQt6::detail
902
1010
  }
903
1011
 
904
1012
 
905
- // ========= reference_wrapper.hpp =========
1013
+ // ========= ios_base.hpp =========
906
1014
 
1015
+ #include <ios>
907
1016
 
908
- // --------- reference_wrapper.ipp ---------
909
- #include <functional>
1017
+ namespace Rice4RubyQt6
1018
+ {
1019
+ Data_Type<std::ios_base> define_ios_base();
1020
+ }
910
1021
 
911
- namespace Rice4RubyQt6::detail
1022
+
1023
+ // --------- ios_base.ipp ---------
1024
+ #include <ios>
1025
+
1026
+ namespace Rice4RubyQt6
912
1027
  {
913
- template<typename T>
914
- struct Type<std::reference_wrapper<T>>
1028
+ inline Data_Type<std::ios_base> define_ios_base()
915
1029
  {
916
- constexpr static bool verify()
1030
+ Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
1031
+ if (Data_Type<std::ios_base>::check_defined("IOSBase", rb_mStd))
917
1032
  {
918
- return Type<T>::verify();
1033
+ return Data_Type<std::ios_base>();
919
1034
  }
920
1035
 
921
- static VALUE rubyKlass()
1036
+ Data_Type<std::ios_base> result = define_class_under<std::ios_base>(rb_mStd, "IOSBase");
1037
+
1038
+ result.const_set("GOODBIT", static_cast<int>(std::ios_base::goodbit));
1039
+ result.const_set("BADBIT", static_cast<int>(std::ios_base::badbit));
1040
+ result.const_set("FAILBIT", static_cast<int>(std::ios_base::failbit));
1041
+ result.const_set("EOFBIT", static_cast<int>(std::ios_base::eofbit));
1042
+
1043
+ return result;
1044
+ }
1045
+ }
1046
+
1047
+ namespace Rice4RubyQt6::detail
1048
+ {
1049
+ template<>
1050
+ struct Type<std::ios_base>
1051
+ {
1052
+ static bool verify()
922
1053
  {
923
- TypeMapper<T> typeMapper;
924
- return typeMapper.rubyKlass();
1054
+ if (!Data_Type<std::ios_base>::is_defined())
1055
+ {
1056
+ define_ios_base();
1057
+ }
1058
+ return true;
925
1059
  }
926
1060
  };
1061
+ }
927
1062
 
928
- template<typename T>
929
- class To_Ruby<std::reference_wrapper<T>>
1063
+
1064
+ // ========= ostream.hpp =========
1065
+
1066
+ namespace Rice4RubyQt6
1067
+ {
1068
+ Data_Type<std::ostream> define_ostream();
1069
+ Data_Type<std::ostringstream> define_ostringstream(std::string klassName = "");
1070
+ Data_Type<std::ofstream> define_ofstream(std::string klassName = "");
1071
+ }
1072
+
1073
+
1074
+ // --------- ostream.ipp ---------
1075
+ #include <sstream>
1076
+ #include <fstream>
1077
+ #include <iostream>
1078
+
1079
+ namespace Rice4RubyQt6::stl
1080
+ {
1081
+ class OStreamHelper
930
1082
  {
931
1083
  public:
932
- To_Ruby() = default;
1084
+ OStreamHelper(Data_Type<std::ostream> klass) : klass_(klass)
1085
+ {
1086
+ this->define_write_methods();
1087
+ this->define_state_methods();
1088
+ }
933
1089
 
934
- explicit To_Ruby(Arg* arg) : arg_(arg)
1090
+ private:
1091
+ void define_write_methods()
935
1092
  {
1093
+ klass_.define_method("write", [](std::ostream& stream, VALUE value) -> std::ostream&
1094
+ {
1095
+ stream << Object(value).to_s().c_str();
1096
+ return stream;
1097
+ }, Arg("value").setValue())
1098
+ .define_method<std::ostream& (std::ostream::*)()>("flush", &std::ostream::flush)
1099
+ .define_method("clear", [](std::ostream& stream, int state)
1100
+ {
1101
+ stream.clear(static_cast<std::ios_base::iostate>(state));
1102
+ }, Arg("state") = static_cast<int>(std::ios_base::goodbit));
1103
+
1104
+ rb_define_alias(klass_, "<<", "write");
936
1105
  }
937
1106
 
938
- VALUE convert(const std::reference_wrapper<T>& data)
1107
+ void define_state_methods()
939
1108
  {
940
- return To_Ruby<T&>().convert(data.get());
1109
+ klass_.define_method("good?", &std::ostream::good)
1110
+ .define_method("bad?", &std::ostream::bad)
1111
+ .define_method("fail?", &std::ostream::fail)
1112
+ .define_method("eof?", &std::ostream::eof);
941
1113
  }
942
1114
 
943
- private:
944
- Arg* arg_ = nullptr;
1115
+ Data_Type<std::ostream> klass_;
945
1116
  };
946
1117
 
947
- template<typename T>
948
- class From_Ruby<std::reference_wrapper<T>>
1118
+ class OStringStreamHelper
949
1119
  {
950
1120
  public:
951
- From_Ruby() = default;
1121
+ OStringStreamHelper(Data_Type<std::ostringstream> klass) : klass_(klass)
1122
+ {
1123
+ this->define_constructors();
1124
+ this->define_methods();
1125
+ }
952
1126
 
953
- explicit From_Ruby(Arg* arg) : arg_(arg)
1127
+ private:
1128
+ void define_constructors()
954
1129
  {
1130
+ klass_.define_constructor(Constructor<std::ostringstream>())
1131
+ .define_constructor(Constructor<std::ostringstream, const std::string&>(), Arg("str"));
955
1132
  }
956
1133
 
957
- double is_convertible(VALUE value)
1134
+ void define_methods()
958
1135
  {
959
- return this->converter_.is_convertible(value);
1136
+ klass_.define_method<std::string(std::ostringstream::*)() const>("str", &std::ostringstream::str)
1137
+ .define_method("str=", [](std::ostringstream& stream, const std::string& s) { stream.str(s); }, Arg("str"));
1138
+
1139
+ rb_define_alias(klass_, "to_s", "str");
960
1140
  }
961
1141
 
962
- std::reference_wrapper<T> convert(VALUE value)
1142
+ Data_Type<std::ostringstream> klass_;
1143
+ };
1144
+
1145
+ class OFStreamHelper
1146
+ {
1147
+ public:
1148
+ OFStreamHelper(Data_Type<std::ofstream> klass) : klass_(klass)
963
1149
  {
964
- return this->converter_.convert(value);
1150
+ this->define_constructors();
1151
+ this->define_methods();
965
1152
  }
966
1153
 
967
1154
  private:
968
- Arg* arg_ = nullptr;
969
- From_Ruby<T&> converter_;
1155
+ void define_constructors()
1156
+ {
1157
+ klass_.define_constructor(Constructor<std::ofstream>())
1158
+ .define_constructor(Constructor<std::ofstream, const std::string&>(), Arg("filename"));
1159
+ }
1160
+
1161
+ void define_methods()
1162
+ {
1163
+ klass_.define_method("open", [](std::ofstream& stream, const std::string& filename) { stream.open(filename); }, Arg("filename"))
1164
+ .define_method("close", &std::ofstream::close)
1165
+ .define_method<bool(std::ofstream::*)() const>("open?", &std::ofstream::is_open);
1166
+ }
1167
+
1168
+ Data_Type<std::ofstream> klass_;
1169
+ };
1170
+ }
1171
+
1172
+ namespace Rice4RubyQt6
1173
+ {
1174
+ inline Data_Type<std::ostream> define_ostream()
1175
+ {
1176
+ define_ios_base();
1177
+
1178
+ Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
1179
+ if (Data_Type<std::ostream>::check_defined("OStream", rb_mStd))
1180
+ {
1181
+ return Data_Type<std::ostream>();
1182
+ }
1183
+
1184
+ Data_Type<std::ostream> result = define_class_under<std::ostream>(rb_mStd, "OStream");
1185
+ stl::OStreamHelper helper(result);
1186
+
1187
+ rb_mStd.const_set("COUT", Data_Object<std::ostream>(&std::cout).value());
1188
+ rb_mStd.const_set("CERR", Data_Object<std::ostream>(&std::cerr).value());
1189
+
1190
+ return result;
1191
+ }
1192
+
1193
+ inline Data_Type<std::ostringstream> define_ostringstream(std::string klassName)
1194
+ {
1195
+ define_ostream();
1196
+
1197
+ if (klassName.empty())
1198
+ {
1199
+ klassName = "OStringStream";
1200
+ }
1201
+
1202
+ Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
1203
+ if (Data_Type<std::ostringstream>::check_defined(klassName, rb_mStd))
1204
+ {
1205
+ return Data_Type<std::ostringstream>();
1206
+ }
1207
+
1208
+ Data_Type<std::ostringstream> result = define_class_under<std::ostringstream, std::ostream>(rb_mStd, klassName.c_str());
1209
+ stl::OStringStreamHelper helper(result);
1210
+ return result;
1211
+ }
1212
+
1213
+ inline Data_Type<std::ofstream> define_ofstream(std::string klassName)
1214
+ {
1215
+ define_ostream();
1216
+
1217
+ if (klassName.empty())
1218
+ {
1219
+ klassName = "OFStream";
1220
+ }
1221
+
1222
+ Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
1223
+ if (Data_Type<std::ofstream>::check_defined(klassName, rb_mStd))
1224
+ {
1225
+ return Data_Type<std::ofstream>();
1226
+ }
1227
+
1228
+ Data_Type<std::ofstream> result = define_class_under<std::ofstream, std::ostream>(rb_mStd, klassName.c_str());
1229
+ stl::OFStreamHelper helper(result);
1230
+ return result;
1231
+ }
1232
+ }
1233
+
1234
+ namespace Rice4RubyQt6::detail
1235
+ {
1236
+ template<>
1237
+ struct Type<std::ostream>
1238
+ {
1239
+ static bool verify()
1240
+ {
1241
+ if (!Data_Type<std::ostream>::is_defined())
1242
+ {
1243
+ define_ostream();
1244
+ }
1245
+ return true;
1246
+ }
1247
+ };
1248
+
1249
+ template<>
1250
+ struct Type<std::ostringstream>
1251
+ {
1252
+ static bool verify()
1253
+ {
1254
+ if (!Data_Type<std::ostringstream>::is_defined())
1255
+ {
1256
+ define_ostringstream();
1257
+ }
1258
+ return true;
1259
+ }
1260
+ };
1261
+
1262
+ template<>
1263
+ struct Type<std::ofstream>
1264
+ {
1265
+ static bool verify()
1266
+ {
1267
+ if (!Data_Type<std::ofstream>::is_defined())
1268
+ {
1269
+ define_ofstream();
1270
+ }
1271
+ return true;
1272
+ }
970
1273
  };
971
1274
  }
972
1275
 
@@ -1071,8 +1374,8 @@ namespace Rice4RubyQt6
1071
1374
 
1072
1375
  if (klassName.empty())
1073
1376
  {
1074
- detail::TypeMapper<Pair_T> typeMapper;
1075
- klassName = typeMapper.rubyName();
1377
+ detail::TypeDetail<Pair_T> typeDetail;
1378
+ klassName = typeDetail.rubyName();
1076
1379
  }
1077
1380
 
1078
1381
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -1110,6 +1413,75 @@ namespace Rice4RubyQt6
1110
1413
 
1111
1414
 
1112
1415
 
1416
+ // ========= reference_wrapper.hpp =========
1417
+
1418
+
1419
+ // --------- reference_wrapper.ipp ---------
1420
+ #include <functional>
1421
+
1422
+ namespace Rice4RubyQt6::detail
1423
+ {
1424
+ template<typename T>
1425
+ struct Type<std::reference_wrapper<T>>
1426
+ {
1427
+ constexpr static bool verify()
1428
+ {
1429
+ return Type<T>::verify();
1430
+ }
1431
+
1432
+ static VALUE rubyKlass()
1433
+ {
1434
+ TypeDetail<T> typeDetail;
1435
+ return typeDetail.rubyKlass();
1436
+ }
1437
+ };
1438
+
1439
+ template<typename T>
1440
+ class To_Ruby<std::reference_wrapper<T>>
1441
+ {
1442
+ public:
1443
+ To_Ruby() = default;
1444
+
1445
+ explicit To_Ruby(Arg* arg) : arg_(arg)
1446
+ {
1447
+ }
1448
+
1449
+ VALUE convert(const std::reference_wrapper<T>& data)
1450
+ {
1451
+ return To_Ruby<T&>().convert(data.get());
1452
+ }
1453
+
1454
+ private:
1455
+ Arg* arg_ = nullptr;
1456
+ };
1457
+
1458
+ template<typename T>
1459
+ class From_Ruby<std::reference_wrapper<T>>
1460
+ {
1461
+ public:
1462
+ From_Ruby() = default;
1463
+
1464
+ explicit From_Ruby(Arg* arg) : arg_(arg)
1465
+ {
1466
+ }
1467
+
1468
+ double is_convertible(VALUE value)
1469
+ {
1470
+ return this->converter_.is_convertible(value);
1471
+ }
1472
+
1473
+ std::reference_wrapper<T> convert(VALUE value)
1474
+ {
1475
+ return this->converter_.convert(value);
1476
+ }
1477
+
1478
+ private:
1479
+ Arg* arg_ = nullptr;
1480
+ From_Ruby<T&> converter_;
1481
+ };
1482
+ }
1483
+
1484
+
1113
1485
  // ========= map.hpp =========
1114
1486
 
1115
1487
  namespace Rice4RubyQt6
@@ -1354,8 +1726,8 @@ namespace Rice4RubyQt6
1354
1726
 
1355
1727
  if (klassName.empty())
1356
1728
  {
1357
- detail::TypeMapper<Map_T> typeMapper;
1358
- klassName = typeMapper.rubyName();
1729
+ detail::TypeDetail<Map_T> typeDetail;
1730
+ klassName = typeDetail.rubyName();
1359
1731
  }
1360
1732
 
1361
1733
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -1903,8 +2275,8 @@ namespace Rice4RubyQt6
1903
2275
  auto iter = multimap.begin();
1904
2276
 
1905
2277
  std::stringstream stream;
1906
- detail::TypeMapper<T> typeMapper;
1907
- stream << "<" << typeMapper.rubyName() << ":";
2278
+ detail::TypeDetail<T> typeDetail;
2279
+ stream << "<" << typeDetail.rubyName() << ":";
1908
2280
  stream << "{";
1909
2281
 
1910
2282
  for (; iter != multimap.end(); iter++)
@@ -1942,8 +2314,8 @@ namespace Rice4RubyQt6
1942
2314
 
1943
2315
  if (klassName.empty())
1944
2316
  {
1945
- detail::TypeMapper<MultiMap_T> typeMapper;
1946
- klassName = typeMapper.rubyName();
2317
+ detail::TypeDetail<MultiMap_T> typeDetail;
2318
+ klassName = typeDetail.rubyName();
1947
2319
  }
1948
2320
 
1949
2321
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -2265,11 +2637,22 @@ namespace Rice4RubyQt6
2265
2637
  self.insert(value);
2266
2638
  return self;
2267
2639
  }, Arg("value").keepAlive())
2268
- .define_method("merge", [](T& self, T& other) -> T&
2640
+ .define_method("merge", [](VALUE self, VALUE source)
2269
2641
  {
2270
- self.merge(other);
2642
+ T* selfPtr = detail::unwrap<T>(self, Data_Type<T>::ruby_data_type(), false);
2643
+ T* sourcePtr = detail::unwrap<T>(source, Data_Type<T>::ruby_data_type(), false);
2644
+ selfPtr->merge(*sourcePtr);
2645
+
2646
+ // Merge moves elements from source to self, so copy keepAlive references.
2647
+ // This is conservative — duplicate elements that remain in source will also
2648
+ // have their keepAlive references copied, keeping them alive longer than
2649
+ // strictly necessary. This is safe (better than premature GC).
2650
+ detail::WrapperBase* selfWrapper = detail::getWrapper(self);
2651
+ detail::WrapperBase* sourceWrapper = detail::getWrapper(source);
2652
+ selfWrapper->setKeepAlive(sourceWrapper->getKeepAlive());
2653
+
2271
2654
  return self;
2272
- }, Arg("source"));
2655
+ }, Arg("self").setValue(), Arg("source").setValue());
2273
2656
 
2274
2657
  rb_define_alias(klass_, "erase", "delete");
2275
2658
  }
@@ -2381,8 +2764,8 @@ namespace Rice4RubyQt6
2381
2764
  auto finish = self.end();
2382
2765
 
2383
2766
  std::stringstream stream;
2384
- detail::TypeMapper<T> typeMapper;
2385
- stream << "<" << typeMapper.rubyName() << ":";
2767
+ detail::TypeDetail<T> typeDetail;
2768
+ stream << "<" << typeDetail.rubyName() << ":";
2386
2769
  stream << "{";
2387
2770
 
2388
2771
  for (; iter != finish; iter++)
@@ -2423,8 +2806,8 @@ namespace Rice4RubyQt6
2423
2806
 
2424
2807
  if (klassName.empty())
2425
2808
  {
2426
- detail::TypeMapper<Set_T> typeMapper;
2427
- klassName = typeMapper.rubyName();
2809
+ detail::TypeDetail<Set_T> typeDetail;
2810
+ klassName = typeDetail.rubyName();
2428
2811
  }
2429
2812
 
2430
2813
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -2498,8 +2881,17 @@ namespace Rice4RubyQt6
2498
2881
  switch (rb_type(value))
2499
2882
  {
2500
2883
  case RUBY_T_DATA:
2884
+ {
2885
+ #if RUBY_API_VERSION_MAJOR >= 4
2886
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
2887
+ {
2888
+ return Convertible::Exact;
2889
+ }
2890
+ #endif
2501
2891
  return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2502
2892
  break;
2893
+ }
2894
+ #if RUBY_API_VERSION_MAJOR < 4
2503
2895
  case RUBY_T_OBJECT:
2504
2896
  {
2505
2897
  Object object(value);
@@ -2508,6 +2900,7 @@ namespace Rice4RubyQt6
2508
2900
  return Convertible::Exact;
2509
2901
  }
2510
2902
  }
2903
+ #endif
2511
2904
  default:
2512
2905
  return Convertible::None;
2513
2906
  }
@@ -2519,9 +2912,19 @@ namespace Rice4RubyQt6
2519
2912
  {
2520
2913
  case RUBY_T_DATA:
2521
2914
  {
2522
- // This is a wrapped self (hopefully!)
2523
- return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2915
+ #if RUBY_API_VERSION_MAJOR >= 4
2916
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
2917
+ {
2918
+ return toSet<T>(value);
2919
+ }
2920
+ #endif
2921
+
2922
+ if (Data_Type<std::set<T>>::is_descendant(value))
2923
+ {
2924
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2925
+ }
2524
2926
  }
2927
+ #if RUBY_API_VERSION_MAJOR < 4
2525
2928
  case RUBY_T_OBJECT:
2526
2929
  {
2527
2930
  Object object(value);
@@ -2532,6 +2935,7 @@ namespace Rice4RubyQt6
2532
2935
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
2533
2936
  detail::protect(rb_obj_classname, value), "std::set");
2534
2937
  }
2938
+ #endif
2535
2939
  default:
2536
2940
  {
2537
2941
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
@@ -2562,8 +2966,15 @@ namespace Rice4RubyQt6
2562
2966
  switch (rb_type(value))
2563
2967
  {
2564
2968
  case RUBY_T_DATA:
2969
+ #if RUBY_API_VERSION_MAJOR >= 4
2970
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
2971
+ {
2972
+ return Convertible::Exact;
2973
+ }
2974
+ #endif
2565
2975
  return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2566
2976
  break;
2977
+ #if RUBY_API_VERSION_MAJOR < 4
2567
2978
  case RUBY_T_OBJECT:
2568
2979
  {
2569
2980
  Object object(value);
@@ -2572,6 +2983,7 @@ namespace Rice4RubyQt6
2572
2983
  return Convertible::Exact;
2573
2984
  }
2574
2985
  }
2986
+ #endif
2575
2987
  default:
2576
2988
  return Convertible::None;
2577
2989
  }
@@ -2583,9 +2995,24 @@ namespace Rice4RubyQt6
2583
2995
  {
2584
2996
  case RUBY_T_DATA:
2585
2997
  {
2586
- // This is a wrapped self (hopefully!)
2587
- return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2998
+ #if RUBY_API_VERSION_MAJOR >= 4
2999
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
3000
+ {
3001
+ // If this an Ruby array and the vector type is copyable
3002
+ if constexpr (std::is_default_constructible_v<T>)
3003
+ {
3004
+ this->converted_ = toSet<T>(value);
3005
+ return this->converted_;
3006
+ }
3007
+ }
3008
+ #endif
3009
+
3010
+ if (Data_Type<std::set<T>>::is_descendant(value))
3011
+ {
3012
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
3013
+ }
2588
3014
  }
3015
+ #if RUBY_API_VERSION_MAJOR < 4
2589
3016
  case RUBY_T_OBJECT:
2590
3017
  {
2591
3018
  Object object(value);
@@ -2601,6 +3028,7 @@ namespace Rice4RubyQt6
2601
3028
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
2602
3029
  detail::protect(rb_obj_classname, value), "std::set");
2603
3030
  }
3031
+ #endif
2604
3032
  default:
2605
3033
  {
2606
3034
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
@@ -2631,11 +3059,18 @@ namespace Rice4RubyQt6
2631
3059
  switch (rb_type(value))
2632
3060
  {
2633
3061
  case RUBY_T_DATA:
3062
+ #if RUBY_API_VERSION_MAJOR >= 4
3063
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
3064
+ {
3065
+ return Convertible::Exact;
3066
+ }
3067
+ #endif
2634
3068
  return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2635
3069
  break;
2636
3070
  case RUBY_T_NIL:
2637
3071
  return Convertible::Exact;
2638
3072
  break;
3073
+ #if RUBY_API_VERSION_MAJOR < 4
2639
3074
  case RUBY_T_OBJECT:
2640
3075
  {
2641
3076
  Object object(value);
@@ -2644,6 +3079,7 @@ namespace Rice4RubyQt6
2644
3079
  return Convertible::Exact;
2645
3080
  }
2646
3081
  }
3082
+ #endif
2647
3083
  default:
2648
3084
  return Convertible::None;
2649
3085
  }
@@ -2655,9 +3091,24 @@ namespace Rice4RubyQt6
2655
3091
  {
2656
3092
  case RUBY_T_DATA:
2657
3093
  {
2658
- // This is a wrapped self (hopefully!)
2659
- return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
3094
+ #if RUBY_API_VERSION_MAJOR >= 4
3095
+ if (detail::protect(rb_obj_is_instance_of, value, rb_cSet))
3096
+ {
3097
+ // If this an Ruby array and the vector type is copyable
3098
+ if constexpr (std::is_default_constructible_v<T>)
3099
+ {
3100
+ this->converted_ = toSet<T>(value);
3101
+ return &this->converted_;
3102
+ }
3103
+ }
3104
+ #endif
3105
+
3106
+ if (Data_Type<std::set<T>>::is_descendant(value))
3107
+ {
3108
+ return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
3109
+ }
2660
3110
  }
3111
+ #if RUBY_API_VERSION_MAJOR < 4
2661
3112
  case RUBY_T_OBJECT:
2662
3113
  {
2663
3114
  Object object(value);
@@ -2673,6 +3124,7 @@ namespace Rice4RubyQt6
2673
3124
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
2674
3125
  detail::protect(rb_obj_classname, value), "std::set");
2675
3126
  }
3127
+ #endif
2676
3128
  default:
2677
3129
  {
2678
3130
  throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
@@ -2727,8 +3179,8 @@ namespace Rice4RubyQt6
2727
3179
 
2728
3180
  if (klassName.empty())
2729
3181
  {
2730
- detail::TypeMapper<SharedPtr_T> typeMapper;
2731
- klassName = typeMapper.rubyName();
3182
+ detail::TypeDetail<SharedPtr_T> typeDetail;
3183
+ klassName = typeDetail.rubyName();
2732
3184
  }
2733
3185
 
2734
3186
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -2747,15 +3199,23 @@ namespace Rice4RubyQt6
2747
3199
  return !self;
2748
3200
  });
2749
3201
 
2750
- if constexpr (!std::is_void_v<T>)
3202
+ if constexpr (detail::is_complete_v<T> && !std::is_void_v<T>)
2751
3203
  {
2752
3204
  result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
2753
3205
  }
2754
3206
 
2755
- // Setup delegation to forward T's methods via get (only for non-fundamental, non-void types)
2756
- if constexpr (!std::is_void_v<T> && !std::is_fundamental_v<T>)
3207
+ // Forward methods to wrapped T
3208
+ if constexpr (detail::is_complete_v<T> && !std::is_void_v<T> && !std::is_fundamental_v<T>)
2757
3209
  {
2758
- detail::define_forwarding(result.klass(), Data_Type<T>::klass());
3210
+ result.instance_eval(R"(
3211
+ define_method(:method_missing) do |method_name, *args, &block|
3212
+ self.get.send(method_name, *args, &block)
3213
+ end
3214
+
3215
+ define_method(:respond_to_missing?) do |method_name, include_private = false|
3216
+ self.get.send(method_name, *args, &block)
3217
+ end
3218
+ )");
2759
3219
  }
2760
3220
 
2761
3221
  return result;
@@ -2824,10 +3284,8 @@ namespace Rice4RubyQt6::detail
2824
3284
  result = result && Type<T>::verify();
2825
3285
  }
2826
3286
 
2827
- if (result)
2828
- {
2829
- define_shared_ptr<T>();
2830
- }
3287
+ // We ALWAYS need to define the std::shared_ptr<T>, even if T is not bound, because it could be bound after this call
3288
+ define_shared_ptr<T>();
2831
3289
 
2832
3290
  return result;
2833
3291
  }
@@ -3400,8 +3858,8 @@ namespace Rice4RubyQt6
3400
3858
 
3401
3859
  if (klassName.empty())
3402
3860
  {
3403
- detail::TypeMapper<UniquePtr_T> typeMapper;
3404
- klassName = typeMapper.rubyName();
3861
+ detail::TypeDetail<UniquePtr_T> typeDetail;
3862
+ klassName = typeDetail.rubyName();
3405
3863
  }
3406
3864
 
3407
3865
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -3421,10 +3879,18 @@ namespace Rice4RubyQt6
3421
3879
  return !self;
3422
3880
  });
3423
3881
 
3424
- // Setup delegation to forward T's methods via get (only for non-fundamental, non-void types)
3882
+ // Forward methods to wrapped T
3425
3883
  if constexpr (!std::is_void_v<T> && !std::is_fundamental_v<T>)
3426
3884
  {
3427
- detail::define_forwarding(result.klass(), Data_Type<T>::klass());
3885
+ result.instance_eval(R"(
3886
+ define_method(:method_missing) do |method_name, *args, &block|
3887
+ self.get.send(method_name, *args, &block)
3888
+ end
3889
+
3890
+ define_method(:respond_to_missing?) do |method_name, include_private = false|
3891
+ self.get.send(method_name, *args, &block)
3892
+ end
3893
+ )");
3428
3894
  }
3429
3895
 
3430
3896
  return result;
@@ -3494,10 +3960,8 @@ namespace Rice4RubyQt6::detail
3494
3960
  result = result && Type<T>::verify();
3495
3961
  }
3496
3962
 
3497
- if (result)
3498
- {
3499
- define_unique_ptr<T>();
3500
- }
3963
+ // We ALWAYS need to define the std::unique_ptr<T>, even if T is not bound, because it could be bound after this call
3964
+ define_unique_ptr<T>();
3501
3965
 
3502
3966
  return result;
3503
3967
  }
@@ -3783,8 +4247,8 @@ namespace Rice4RubyQt6
3783
4247
 
3784
4248
  if (klassName.empty())
3785
4249
  {
3786
- detail::TypeMapper<UnorderedMap_T> typeMapper;
3787
- klassName = typeMapper.rubyName();
4250
+ detail::TypeDetail<UnorderedMap_T> typeDetail;
4251
+ klassName = typeDetail.rubyName();
3788
4252
  }
3789
4253
 
3790
4254
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");
@@ -4089,7 +4553,7 @@ namespace Rice4RubyQt6
4089
4553
  if constexpr (std::is_copy_constructible_v<Value_T>)
4090
4554
  {
4091
4555
  klass_.define_constructor(Constructor<T, const T&>(), Arg("other"))
4092
- .define_constructor(Constructor<T, Size_T, const Parameter_T>(), Arg("count"), Arg("value"));
4556
+ .define_constructor(Constructor<T, Size_T, const Parameter_T>(), Arg("count"), Arg("value").keepAlive());
4093
4557
  }
4094
4558
 
4095
4559
  if constexpr (std::is_default_constructible_v<Value_T>)
@@ -4155,7 +4619,7 @@ namespace Rice4RubyQt6
4155
4619
  if constexpr (!std::is_same_v<Value_T, bool>)
4156
4620
  {
4157
4621
  // Access methods
4158
- klass_.define_method("first", [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4622
+ auto first_func = [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4159
4623
  {
4160
4624
  if (vector.size() > 0)
4161
4625
  {
@@ -4165,8 +4629,9 @@ namespace Rice4RubyQt6
4165
4629
  {
4166
4630
  return std::nullopt;
4167
4631
  }
4168
- })
4169
- .define_method("last", [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4632
+ };
4633
+
4634
+ auto last_func = [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4170
4635
  {
4171
4636
  if (vector.size() > 0)
4172
4637
  {
@@ -4176,8 +4641,9 @@ namespace Rice4RubyQt6
4176
4641
  {
4177
4642
  return std::nullopt;
4178
4643
  }
4179
- })
4180
- .define_method("[]", [this](T& vector, Difference_T index) -> std::optional<std::reference_wrapper<Value_T>>
4644
+ };
4645
+
4646
+ auto index_func = [this](T& vector, Difference_T index) -> std::optional<std::reference_wrapper<Value_T>>
4181
4647
  {
4182
4648
  index = normalizeIndex(vector.size(), index);
4183
4649
  if (index < 0 || index >= (Difference_T)vector.size())
@@ -4188,8 +4654,22 @@ namespace Rice4RubyQt6
4188
4654
  {
4189
4655
  return vector[index];
4190
4656
  }
4191
- }, Arg("pos"))
4192
- .template define_method<Value_T*(T::*)()>("data", &T::data, ReturnBuffer());
4657
+ };
4658
+
4659
+ if constexpr (detail::is_wrapped_v<Value_T>)
4660
+ {
4661
+ klass_.define_method("first", first_func, Return().keepAlive())
4662
+ .define_method("last", last_func, Return().keepAlive())
4663
+ .define_method("[]", index_func, Arg("pos"), Return().keepAlive());
4664
+ }
4665
+ else
4666
+ {
4667
+ klass_.define_method("first", first_func)
4668
+ .define_method("last", last_func)
4669
+ .define_method("[]", index_func, Arg("pos"));
4670
+ }
4671
+
4672
+ klass_.template define_method<Value_T*(T::*)()>("data", &T::data, ReturnBuffer());
4193
4673
  }
4194
4674
  else
4195
4675
  {
@@ -4467,8 +4947,8 @@ namespace Rice4RubyQt6
4467
4947
 
4468
4948
  if (klassName.empty())
4469
4949
  {
4470
- detail::TypeMapper<Vector_T> typeMapper;
4471
- klassName = typeMapper.rubyName();
4950
+ detail::TypeDetail<Vector_T> typeDetail;
4951
+ klassName = typeDetail.rubyName();
4472
4952
  }
4473
4953
 
4474
4954
  Module rb_mStd = define_module_under(define_module("Rice4RubyQt6"), "Std");