rice 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTORS.md +2 -0
- data/include/rice/rice.hpp +77 -6
- data/include/rice/stl.hpp +69 -11
- data/lib/version.rb +1 -1
- data/rice/detail/NativeFunction.hpp +4 -1
- data/rice/detail/NativeFunction.ipp +37 -3
- data/rice/detail/Wrapper.ipp +1 -1
- data/sample/callbacks/extconf.rb +0 -1
- data/sample/enum/extconf.rb +0 -1
- data/sample/inheritance/extconf.rb +0 -1
- data/sample/map/extconf.rb +0 -1
- data/test/embed_ruby.cpp +6 -0
- data/test/ext/t1/extconf.rb +0 -1
- data/test/ext/t2/extconf.rb +0 -1
- data/test/extconf.rb +0 -1
- data/test/test_Attribute.cpp +6 -6
- data/test/test_Keep_Alive_No_Wrapper.cpp +80 -0
- data/test/test_Object.cpp +15 -6
- data/test/test_Stl_SmartPointer.cpp +44 -4
- data/test/test_Stl_String.cpp +5 -2
- data/test/test_Stl_Variant.cpp +49 -4
- data/test/test_To_From_Ruby.cpp +2 -2
- data/test/unittest.hpp +9 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1971d90148d0c032df2e58c7e251b57c69ad2a4ddd76d6835048b266f243e966
|
4
|
+
data.tar.gz: '0933de85d9bb135813adb756ac365dfbb333bc4ddf4575614f2200af1a78c1f4'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47bbbb4ddfacf6f67fc47fdf3b1bc81b2b5a1d8c889238ef1fba751b3866598a41e82609637c294609ceb0f7d3728bde3328cc3b4110af5f676b7b293fded1e9
|
7
|
+
data.tar.gz: 609458d567c204fa4156520523715e9415ac2e79bee6ddf266568408b1cb7203be68a3e216022c2dab0988d73a06c757ec63a8169d37eb0c14d80883785a708b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## Unreleased (4.2)
|
2
|
+
|
3
|
+
* Support Ruby 3.3.0.
|
4
|
+
* Split Object.call to an explicit Object.call_kw for calling methods expecting keyword arguments.
|
5
|
+
* 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)
|
6
|
+
* Fix wrapping of std::shared_ptr to properly take default arguments into account.
|
7
|
+
|
1
8
|
## 4.1
|
2
9
|
|
3
10
|
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:
|
data/CONTRIBUTORS.md
CHANGED
@@ -17,3 +17,5 @@ I'd like to thank the following people for their help in making Rice what it is
|
|
17
17
|
* [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.
|
18
18
|
* [Atsushi Tatsuma (yoshoku)](https://github.com/yoshoku) for [#135](https://github.com/jasonroelofs/rice/pull/135)
|
19
19
|
* [Andrew Kane (ankane)](https://github.com/ankane) for helping [test Rice 4](https://github.com/jasonroelofs/rice/issues/149).
|
20
|
+
* [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)
|
21
|
+
* [kvtb](https://github.com/kvtb) for [#191](https://github.com/jasonroelofs/rice/issues/191)
|
data/include/rice/rice.hpp
CHANGED
@@ -1531,7 +1531,7 @@ namespace Rice::detail
|
|
1531
1531
|
#pragma GCC diagnostic push
|
1532
1532
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
1533
1533
|
#endif
|
1534
|
-
return static_cast<Wrapper*>(RTYPEDDATA_DATA(value));
|
1534
|
+
return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
|
1535
1535
|
#ifdef __GNUC__
|
1536
1536
|
#pragma GCC diagnostic pop
|
1537
1537
|
#endif
|
@@ -4052,6 +4052,9 @@ namespace Rice::detail
|
|
4052
4052
|
// Figure out what self is
|
4053
4053
|
Class_T getReceiver(VALUE self);
|
4054
4054
|
|
4055
|
+
// Throw an exception when wrapper cannot be extracted
|
4056
|
+
[[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
|
4057
|
+
|
4055
4058
|
// Do we need to keep alive any arguments?
|
4056
4059
|
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
|
4057
4060
|
|
@@ -4073,6 +4076,7 @@ namespace Rice::detail
|
|
4073
4076
|
#include <array>
|
4074
4077
|
#include <algorithm>
|
4075
4078
|
#include <stdexcept>
|
4079
|
+
#include <sstream>
|
4076
4080
|
|
4077
4081
|
|
4078
4082
|
namespace Rice::detail
|
@@ -4107,7 +4111,7 @@ namespace Rice::detail
|
|
4107
4111
|
NativeFunction<From_Ruby_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
4108
4112
|
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
4109
4113
|
{
|
4110
|
-
|
4114
|
+
// Create a tuple of NativeArgs that will convert the Ruby values to native values. For
|
4111
4115
|
// builtin types NativeArgs will keep a copy of the native value so that it
|
4112
4116
|
// can be passed by reference or pointer to the native function. For non-builtin types
|
4113
4117
|
// it will just pass the value through.
|
@@ -4233,7 +4237,7 @@ namespace Rice::detail
|
|
4233
4237
|
{
|
4234
4238
|
// Call the native method and get the result
|
4235
4239
|
Return_T nativeResult = std::apply(this->function_, nativeArgs);
|
4236
|
-
|
4240
|
+
|
4237
4241
|
// Return the result
|
4238
4242
|
return this->toRuby_.convert(nativeResult);
|
4239
4243
|
}
|
@@ -4284,15 +4288,38 @@ namespace Rice::detail
|
|
4284
4288
|
}
|
4285
4289
|
}
|
4286
4290
|
|
4291
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
4292
|
+
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::noWrapper(const VALUE klass, const std::string& wrapper)
|
4293
|
+
{
|
4294
|
+
std::stringstream message;
|
4295
|
+
|
4296
|
+
message << "When calling the method `";
|
4297
|
+
message << this->method_name_;
|
4298
|
+
message << "' we could not find the wrapper for the '";
|
4299
|
+
message << rb_obj_classname(klass);
|
4300
|
+
message << "' ";
|
4301
|
+
message << wrapper;
|
4302
|
+
message << " type. You should not use keepAlive() on a Return or Arg that is a builtin Rice type.";
|
4303
|
+
|
4304
|
+
throw std::runtime_error(message.str());
|
4305
|
+
}
|
4306
|
+
|
4287
4307
|
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
4288
4308
|
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
|
4289
4309
|
{
|
4290
|
-
//
|
4310
|
+
// selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
|
4311
|
+
// it is highly unlikely that keepAlive is used in this case but we check anyway
|
4291
4312
|
Wrapper* selfWrapper = getWrapper(self);
|
4313
|
+
|
4314
|
+
// Check function arguments
|
4292
4315
|
for (const Arg& arg : (*this->methodInfo_))
|
4293
4316
|
{
|
4294
4317
|
if (arg.isKeepAlive())
|
4295
4318
|
{
|
4319
|
+
if (selfWrapper == nullptr)
|
4320
|
+
{
|
4321
|
+
noWrapper(self, "self");
|
4322
|
+
}
|
4296
4323
|
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
4297
4324
|
}
|
4298
4325
|
}
|
@@ -4300,7 +4327,17 @@ namespace Rice::detail
|
|
4300
4327
|
// Check return value
|
4301
4328
|
if (this->methodInfo_->returnInfo.isKeepAlive())
|
4302
4329
|
{
|
4330
|
+
if (selfWrapper == nullptr)
|
4331
|
+
{
|
4332
|
+
noWrapper(self, "self");
|
4333
|
+
}
|
4334
|
+
|
4335
|
+
// returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
|
4303
4336
|
Wrapper* returnWrapper = getWrapper(returnValue);
|
4337
|
+
if (returnWrapper == nullptr)
|
4338
|
+
{
|
4339
|
+
noWrapper(returnValue, "return");
|
4340
|
+
}
|
4304
4341
|
returnWrapper->addKeepAlive(self);
|
4305
4342
|
}
|
4306
4343
|
}
|
@@ -4672,7 +4709,8 @@ namespace Rice
|
|
4672
4709
|
|
4673
4710
|
//! Call the Ruby method specified by 'id' on object 'obj'.
|
4674
4711
|
/*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to
|
4675
|
-
* Ruby objects with to_ruby<>.
|
4712
|
+
* Ruby objects with to_ruby<>. To call methods expecting keyword arguments,
|
4713
|
+
* use call_kw.
|
4676
4714
|
*
|
4677
4715
|
* E.g.:
|
4678
4716
|
* \code
|
@@ -4690,6 +4728,29 @@ namespace Rice
|
|
4690
4728
|
template<typename ...Arg_Ts>
|
4691
4729
|
Object call(Identifier id, Arg_Ts... args) const;
|
4692
4730
|
|
4731
|
+
//! Call the Ruby method specified by 'id' on object 'obj'.
|
4732
|
+
/*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to
|
4733
|
+
* Ruby objects with to_ruby<>. The final argument must be a Hash and will be treated
|
4734
|
+
* as keyword arguments to the function.
|
4735
|
+
*
|
4736
|
+
* E.g.:
|
4737
|
+
* \code
|
4738
|
+
* Rice::Hash kw;
|
4739
|
+
* kw[":argument"] = String("one")
|
4740
|
+
* Rice::Object obj = x.call_kw("foo", kw);
|
4741
|
+
* \endcode
|
4742
|
+
*
|
4743
|
+
* If a return type is specified, the return value will automatically be
|
4744
|
+
* converted to that type as long as 'from_ruby' exists for that type.
|
4745
|
+
*
|
4746
|
+
* E.g.:
|
4747
|
+
* \code
|
4748
|
+
* float ret = x.call_kw<float>("foo", kw);
|
4749
|
+
* \endcode
|
4750
|
+
*/
|
4751
|
+
template<typename ...Arg_Ts>
|
4752
|
+
Object call_kw(Identifier id, Arg_Ts... args) const;
|
4753
|
+
|
4693
4754
|
//! Vectorized call.
|
4694
4755
|
/*! Calls the method identified by id with the list of arguments
|
4695
4756
|
* identified by args.
|
@@ -4753,6 +4814,7 @@ namespace Rice
|
|
4753
4814
|
} // namespace Rice
|
4754
4815
|
|
4755
4816
|
#endif // Rice__Object_defn__hpp_
|
4817
|
+
|
4756
4818
|
// --------- Object.ipp ---------
|
4757
4819
|
#ifndef Rice__Object__ipp_
|
4758
4820
|
#define Rice__Object__ipp_
|
@@ -4797,7 +4859,15 @@ namespace Rice
|
|
4797
4859
|
easy to duplicate by setting GC.stress to true and calling a constructor
|
4798
4860
|
that takes multiple values like a std::pair wrapper. */
|
4799
4861
|
std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>().convert(args)... };
|
4800
|
-
return detail::protect(
|
4862
|
+
return detail::protect(rb_funcallv, value(), id.id(), (int)values.size(), (const VALUE*)values.data());
|
4863
|
+
}
|
4864
|
+
|
4865
|
+
template<typename ...Arg_Ts>
|
4866
|
+
inline Object Object::call_kw(Identifier id, Arg_Ts... args) const
|
4867
|
+
{
|
4868
|
+
/* IMPORTANT - See call() above */
|
4869
|
+
std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>().convert(args)... };
|
4870
|
+
return detail::protect(rb_funcallv_kw, value(), id.id(), (int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
|
4801
4871
|
}
|
4802
4872
|
|
4803
4873
|
template<typename T>
|
@@ -4975,6 +5045,7 @@ namespace Rice::detail
|
|
4975
5045
|
#endif // Rice__Object__ipp_
|
4976
5046
|
|
4977
5047
|
|
5048
|
+
|
4978
5049
|
// ========= Builtin_Object.hpp =========
|
4979
5050
|
|
4980
5051
|
|
data/include/rice/stl.hpp
CHANGED
@@ -168,6 +168,11 @@ namespace Rice::detail
|
|
168
168
|
|
169
169
|
return std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
|
170
170
|
}
|
171
|
+
|
172
|
+
bool is_convertible(VALUE value)
|
173
|
+
{
|
174
|
+
return rb_type(value) == RUBY_T_COMPLEX;
|
175
|
+
}
|
171
176
|
};
|
172
177
|
|
173
178
|
template<typename T>
|
@@ -183,11 +188,17 @@ namespace Rice::detail
|
|
183
188
|
return this->converted_;
|
184
189
|
}
|
185
190
|
|
191
|
+
bool is_convertible(VALUE value)
|
192
|
+
{
|
193
|
+
return rb_type(value) == RUBY_T_COMPLEX;
|
194
|
+
}
|
195
|
+
|
186
196
|
private:
|
187
197
|
std::complex<T> converted_;
|
188
198
|
};
|
189
199
|
}
|
190
200
|
|
201
|
+
|
191
202
|
// ========= optional.hpp =========
|
192
203
|
|
193
204
|
|
@@ -219,7 +230,7 @@ namespace Rice::detail
|
|
219
230
|
class To_Ruby<std::optional<T>>
|
220
231
|
{
|
221
232
|
public:
|
222
|
-
static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
|
233
|
+
static VALUE convert(const std::optional<T>& data, bool takeOwnership = false)
|
223
234
|
{
|
224
235
|
if (data.has_value())
|
225
236
|
{
|
@@ -236,7 +247,7 @@ namespace Rice::detail
|
|
236
247
|
class To_Ruby<std::optional<T>&>
|
237
248
|
{
|
238
249
|
public:
|
239
|
-
static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
|
250
|
+
static VALUE convert(const std::optional<T>& data, bool takeOwnership = false)
|
240
251
|
{
|
241
252
|
if (data.has_value())
|
242
253
|
{
|
@@ -288,6 +299,7 @@ namespace Rice::detail
|
|
288
299
|
};
|
289
300
|
}
|
290
301
|
|
302
|
+
|
291
303
|
// ========= reference_wrapper.hpp =========
|
292
304
|
|
293
305
|
|
@@ -309,7 +321,7 @@ namespace Rice::detail
|
|
309
321
|
class To_Ruby<std::reference_wrapper<T>>
|
310
322
|
{
|
311
323
|
public:
|
312
|
-
VALUE convert(std::reference_wrapper<T>& data, bool takeOwnership = false)
|
324
|
+
VALUE convert(const std::reference_wrapper<T>& data, bool takeOwnership = false)
|
313
325
|
{
|
314
326
|
return To_Ruby<T&>().convert(data.get());
|
315
327
|
}
|
@@ -334,6 +346,7 @@ namespace Rice::detail
|
|
334
346
|
};
|
335
347
|
}
|
336
348
|
|
349
|
+
|
337
350
|
// ========= smart_ptr.hpp =========
|
338
351
|
|
339
352
|
|
@@ -448,8 +461,18 @@ namespace Rice::detail
|
|
448
461
|
class From_Ruby<std::shared_ptr<T>>
|
449
462
|
{
|
450
463
|
public:
|
464
|
+
From_Ruby() = default;
|
465
|
+
|
466
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
467
|
+
{
|
468
|
+
}
|
469
|
+
|
451
470
|
std::shared_ptr<T> convert(VALUE value)
|
452
471
|
{
|
472
|
+
if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
|
473
|
+
return this->arg_->template defaultValue<std::shared_ptr<T>>();
|
474
|
+
}
|
475
|
+
|
453
476
|
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
454
477
|
|
455
478
|
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
@@ -461,14 +484,27 @@ namespace Rice::detail
|
|
461
484
|
}
|
462
485
|
return smartWrapper->data();
|
463
486
|
}
|
487
|
+
|
488
|
+
private:
|
489
|
+
Arg* arg_ = nullptr;
|
464
490
|
};
|
465
491
|
|
466
492
|
template <typename T>
|
467
493
|
class From_Ruby<std::shared_ptr<T>&>
|
468
494
|
{
|
469
495
|
public:
|
496
|
+
From_Ruby() = default;
|
497
|
+
|
498
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
499
|
+
{
|
500
|
+
}
|
501
|
+
|
470
502
|
std::shared_ptr<T>& convert(VALUE value)
|
471
503
|
{
|
504
|
+
if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
|
505
|
+
return this->arg_->template defaultValue<std::shared_ptr<T>>();
|
506
|
+
}
|
507
|
+
|
472
508
|
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
473
509
|
|
474
510
|
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
@@ -480,6 +516,9 @@ namespace Rice::detail
|
|
480
516
|
}
|
481
517
|
return smartWrapper->data();
|
482
518
|
}
|
519
|
+
|
520
|
+
private:
|
521
|
+
Arg* arg_ = nullptr;
|
483
522
|
};
|
484
523
|
|
485
524
|
template<typename T>
|
@@ -492,6 +531,7 @@ namespace Rice::detail
|
|
492
531
|
};
|
493
532
|
}
|
494
533
|
|
534
|
+
|
495
535
|
// ========= monostate.hpp =========
|
496
536
|
|
497
537
|
|
@@ -513,7 +553,7 @@ namespace Rice::detail
|
|
513
553
|
class To_Ruby<std::monostate>
|
514
554
|
{
|
515
555
|
public:
|
516
|
-
VALUE convert(std::monostate& _)
|
556
|
+
VALUE convert(const std::monostate& _)
|
517
557
|
{
|
518
558
|
return Qnil;
|
519
559
|
}
|
@@ -523,7 +563,7 @@ namespace Rice::detail
|
|
523
563
|
class To_Ruby<std::monostate&>
|
524
564
|
{
|
525
565
|
public:
|
526
|
-
static VALUE convert(std::monostate& data, bool takeOwnership = false)
|
566
|
+
static VALUE convert(const std::monostate& data, bool takeOwnership = false)
|
527
567
|
{
|
528
568
|
return Qnil;
|
529
569
|
}
|
@@ -563,6 +603,7 @@ namespace Rice::detail
|
|
563
603
|
};
|
564
604
|
}
|
565
605
|
|
606
|
+
|
566
607
|
// ========= variant.hpp =========
|
567
608
|
|
568
609
|
|
@@ -596,13 +637,13 @@ namespace Rice::detail
|
|
596
637
|
public:
|
597
638
|
|
598
639
|
template<typename T>
|
599
|
-
static VALUE convertElement(std::variant<Types...>& data, bool takeOwnership)
|
640
|
+
static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
|
600
641
|
{
|
601
642
|
return To_Ruby<T>().convert(std::get<T>(data));
|
602
643
|
}
|
603
644
|
|
604
645
|
template<std::size_t... I>
|
605
|
-
static VALUE convertIterator(std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
646
|
+
static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
606
647
|
{
|
607
648
|
// Create a tuple of the variant types so we can look over the tuple's types
|
608
649
|
using Tuple_T = std::tuple<Types...>;
|
@@ -634,7 +675,7 @@ namespace Rice::detail
|
|
634
675
|
return result;
|
635
676
|
}
|
636
677
|
|
637
|
-
static VALUE convert(std::variant<Types...>& data, bool takeOwnership = false)
|
678
|
+
static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
|
638
679
|
{
|
639
680
|
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
640
681
|
return convertIterator(data, takeOwnership, indices);
|
@@ -646,13 +687,13 @@ namespace Rice::detail
|
|
646
687
|
{
|
647
688
|
public:
|
648
689
|
template<typename T>
|
649
|
-
static VALUE convertElement(std::variant<Types...>& data, bool takeOwnership)
|
690
|
+
static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
|
650
691
|
{
|
651
692
|
return To_Ruby<T>().convert(std::get<T>(data));
|
652
693
|
}
|
653
694
|
|
654
695
|
template<std::size_t... I>
|
655
|
-
static VALUE convertIterator(std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
696
|
+
static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
656
697
|
{
|
657
698
|
// Create a tuple of the variant types so we can look over the tuple's types
|
658
699
|
using Tuple_T = std::tuple<Types...>;
|
@@ -665,7 +706,7 @@ namespace Rice::detail
|
|
665
706
|
return result;
|
666
707
|
}
|
667
708
|
|
668
|
-
static VALUE convert(std::variant<Types...>& data, bool takeOwnership = false)
|
709
|
+
static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
|
669
710
|
{
|
670
711
|
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
671
712
|
return convertIterator(data, takeOwnership, indices);
|
@@ -755,6 +796,7 @@ namespace Rice::detail
|
|
755
796
|
};
|
756
797
|
}
|
757
798
|
|
799
|
+
|
758
800
|
// ========= pair.hpp =========
|
759
801
|
|
760
802
|
|
@@ -2331,6 +2373,11 @@ namespace Rice
|
|
2331
2373
|
}
|
2332
2374
|
}
|
2333
2375
|
|
2376
|
+
bool is_convertible(VALUE value)
|
2377
|
+
{
|
2378
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2379
|
+
}
|
2380
|
+
|
2334
2381
|
private:
|
2335
2382
|
Arg* arg_ = nullptr;
|
2336
2383
|
};
|
@@ -2378,6 +2425,11 @@ namespace Rice
|
|
2378
2425
|
}
|
2379
2426
|
}
|
2380
2427
|
|
2428
|
+
bool is_convertible(VALUE value)
|
2429
|
+
{
|
2430
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2431
|
+
}
|
2432
|
+
|
2381
2433
|
private:
|
2382
2434
|
Arg* arg_ = nullptr;
|
2383
2435
|
std::vector<T> converted_;
|
@@ -2413,10 +2465,16 @@ namespace Rice
|
|
2413
2465
|
}
|
2414
2466
|
}
|
2415
2467
|
|
2468
|
+
bool is_convertible(VALUE value)
|
2469
|
+
{
|
2470
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2471
|
+
}
|
2472
|
+
|
2416
2473
|
private:
|
2417
2474
|
std::vector<T> converted_;
|
2418
2475
|
};
|
2419
2476
|
}
|
2420
2477
|
}
|
2421
2478
|
|
2479
|
+
|
2422
2480
|
#endif // Rice__stl__hpp_
|
data/lib/version.rb
CHANGED
@@ -95,6 +95,9 @@ namespace Rice::detail
|
|
95
95
|
// Figure out what self is
|
96
96
|
Class_T getReceiver(VALUE self);
|
97
97
|
|
98
|
+
// Throw an exception when wrapper cannot be extracted
|
99
|
+
[[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
|
100
|
+
|
98
101
|
// Do we need to keep alive any arguments?
|
99
102
|
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
|
100
103
|
|
@@ -113,4 +116,4 @@ namespace Rice::detail
|
|
113
116
|
}
|
114
117
|
#include "NativeFunction.ipp"
|
115
118
|
|
116
|
-
#endif // Rice__detail__Native_Function__hpp_
|
119
|
+
#endif // Rice__detail__Native_Function__hpp_
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#include <array>
|
2
2
|
#include <algorithm>
|
3
3
|
#include <stdexcept>
|
4
|
+
#include <sstream>
|
4
5
|
|
5
6
|
#include "cpp_protect.hpp"
|
6
7
|
#include "to_ruby_defn.hpp"
|
@@ -38,7 +39,7 @@ namespace Rice::detail
|
|
38
39
|
NativeFunction<From_Ruby_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
39
40
|
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
40
41
|
{
|
41
|
-
|
42
|
+
// Create a tuple of NativeArgs that will convert the Ruby values to native values. For
|
42
43
|
// builtin types NativeArgs will keep a copy of the native value so that it
|
43
44
|
// can be passed by reference or pointer to the native function. For non-builtin types
|
44
45
|
// it will just pass the value through.
|
@@ -164,7 +165,7 @@ namespace Rice::detail
|
|
164
165
|
{
|
165
166
|
// Call the native method and get the result
|
166
167
|
Return_T nativeResult = std::apply(this->function_, nativeArgs);
|
167
|
-
|
168
|
+
|
168
169
|
// Return the result
|
169
170
|
return this->toRuby_.convert(nativeResult);
|
170
171
|
}
|
@@ -215,15 +216,38 @@ namespace Rice::detail
|
|
215
216
|
}
|
216
217
|
}
|
217
218
|
|
219
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
220
|
+
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::noWrapper(const VALUE klass, const std::string& wrapper)
|
221
|
+
{
|
222
|
+
std::stringstream message;
|
223
|
+
|
224
|
+
message << "When calling the method `";
|
225
|
+
message << this->method_name_;
|
226
|
+
message << "' we could not find the wrapper for the '";
|
227
|
+
message << rb_obj_classname(klass);
|
228
|
+
message << "' ";
|
229
|
+
message << wrapper;
|
230
|
+
message << " type. You should not use keepAlive() on a Return or Arg that is a builtin Rice type.";
|
231
|
+
|
232
|
+
throw std::runtime_error(message.str());
|
233
|
+
}
|
234
|
+
|
218
235
|
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
219
236
|
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
|
220
237
|
{
|
221
|
-
//
|
238
|
+
// selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
|
239
|
+
// it is highly unlikely that keepAlive is used in this case but we check anyway
|
222
240
|
Wrapper* selfWrapper = getWrapper(self);
|
241
|
+
|
242
|
+
// Check function arguments
|
223
243
|
for (const Arg& arg : (*this->methodInfo_))
|
224
244
|
{
|
225
245
|
if (arg.isKeepAlive())
|
226
246
|
{
|
247
|
+
if (selfWrapper == nullptr)
|
248
|
+
{
|
249
|
+
noWrapper(self, "self");
|
250
|
+
}
|
227
251
|
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
228
252
|
}
|
229
253
|
}
|
@@ -231,7 +255,17 @@ namespace Rice::detail
|
|
231
255
|
// Check return value
|
232
256
|
if (this->methodInfo_->returnInfo.isKeepAlive())
|
233
257
|
{
|
258
|
+
if (selfWrapper == nullptr)
|
259
|
+
{
|
260
|
+
noWrapper(self, "self");
|
261
|
+
}
|
262
|
+
|
263
|
+
// returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
|
234
264
|
Wrapper* returnWrapper = getWrapper(returnValue);
|
265
|
+
if (returnWrapper == nullptr)
|
266
|
+
{
|
267
|
+
noWrapper(returnValue, "return");
|
268
|
+
}
|
235
269
|
returnWrapper->addKeepAlive(self);
|
236
270
|
}
|
237
271
|
}
|
data/rice/detail/Wrapper.ipp
CHANGED
@@ -193,7 +193,7 @@ namespace Rice::detail
|
|
193
193
|
#pragma GCC diagnostic push
|
194
194
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
195
195
|
#endif
|
196
|
-
return static_cast<Wrapper*>(RTYPEDDATA_DATA(value));
|
196
|
+
return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
|
197
197
|
#ifdef __GNUC__
|
198
198
|
#pragma GCC diagnostic pop
|
199
199
|
#endif
|
data/sample/callbacks/extconf.rb
CHANGED
data/sample/enum/extconf.rb
CHANGED
data/sample/map/extconf.rb
CHANGED
data/test/embed_ruby.cpp
CHANGED
@@ -15,6 +15,12 @@ void embed_ruby()
|
|
15
15
|
ruby_init();
|
16
16
|
ruby_init_loadpath();
|
17
17
|
|
18
|
+
#if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 3
|
19
|
+
// Force the prelude / builtins
|
20
|
+
char *opts[] = { "ruby", "-e;" };
|
21
|
+
ruby_options(2, opts);
|
22
|
+
#endif
|
23
|
+
|
18
24
|
initialized__ = true;
|
19
25
|
}
|
20
26
|
}
|
data/test/ext/t1/extconf.rb
CHANGED
data/test/ext/t2/extconf.rb
CHANGED
data/test/extconf.rb
CHANGED
data/test/test_Attribute.cpp
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#include <assert.h>
|
1
|
+
#include <assert.h>
|
2
2
|
|
3
3
|
#include "unittest.hpp"
|
4
4
|
#include "embed_ruby.hpp"
|
@@ -60,9 +60,9 @@ TESTCASE(attributes)
|
|
60
60
|
ASSERT_EXCEPTION_CHECK(
|
61
61
|
Exception,
|
62
62
|
o.call("read_char=", "some text"),
|
63
|
-
|
63
|
+
ASSERT(std::string(ex.what()).find("undefined method `read_char='") == 0)
|
64
64
|
);
|
65
|
-
|
65
|
+
|
66
66
|
// Test writeonly attribute
|
67
67
|
result = o.call("write_int=", 5);
|
68
68
|
ASSERT_EQUAL(5, detail::From_Ruby<int>().convert(result.value()));
|
@@ -70,7 +70,7 @@ TESTCASE(attributes)
|
|
70
70
|
ASSERT_EXCEPTION_CHECK(
|
71
71
|
Exception,
|
72
72
|
o.call("write_int", 3),
|
73
|
-
|
73
|
+
ASSERT(std::string(ex.what()).find("undefined method `write_int'") == 0)
|
74
74
|
);
|
75
75
|
|
76
76
|
// Test readwrite attribute
|
@@ -101,7 +101,7 @@ TESTCASE(static_attributes)
|
|
101
101
|
ASSERT_EXCEPTION_CHECK(
|
102
102
|
Exception,
|
103
103
|
c.call("static_string=", true),
|
104
|
-
|
104
|
+
ASSERT(std::string(ex.what()).find("undefined method `static_string='") == 0)
|
105
105
|
);
|
106
106
|
}
|
107
107
|
|
@@ -127,7 +127,7 @@ TESTCASE(not_defined)
|
|
127
127
|
{
|
128
128
|
Data_Type<DataStruct> c = define_class<DataStruct>("DataStruct");
|
129
129
|
|
130
|
-
#ifdef _MSC_VER
|
130
|
+
#ifdef _MSC_VER
|
131
131
|
const char* message = "Type is not defined with Rice: class `anonymous namespace'::SomeClass";
|
132
132
|
#else
|
133
133
|
const char* message = "Type is not defined with Rice: (anonymous namespace)::SomeClass";
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#include "unittest.hpp"
|
2
|
+
#include "embed_ruby.hpp"
|
3
|
+
#include <rice/rice.hpp>
|
4
|
+
#include <rice/stl.hpp>
|
5
|
+
|
6
|
+
using namespace Rice;
|
7
|
+
|
8
|
+
TESTSUITE(Keep_Alive_No_Wrapper);
|
9
|
+
|
10
|
+
namespace
|
11
|
+
{
|
12
|
+
class Animal
|
13
|
+
{
|
14
|
+
public:
|
15
|
+
Animal(char const * name) : name_(name) {}
|
16
|
+
char const * getName() { return name_; }
|
17
|
+
virtual ~Animal() = default;
|
18
|
+
private:
|
19
|
+
char const * name_;
|
20
|
+
};
|
21
|
+
|
22
|
+
class Zoo
|
23
|
+
{
|
24
|
+
public:
|
25
|
+
Zoo(void)
|
26
|
+
{
|
27
|
+
pets_.push_back(new Animal("Bear"));
|
28
|
+
pets_.push_back(new Animal("Tiger"));
|
29
|
+
pets_.push_back(new Animal("Lion"));
|
30
|
+
}
|
31
|
+
|
32
|
+
~Zoo()
|
33
|
+
{
|
34
|
+
for(auto pet : pets_)
|
35
|
+
{
|
36
|
+
delete pet;
|
37
|
+
}
|
38
|
+
pets_.clear();
|
39
|
+
}
|
40
|
+
|
41
|
+
Object getPets(void) {
|
42
|
+
Array pets;
|
43
|
+
for(auto p: pets_) {
|
44
|
+
pets.push(p);
|
45
|
+
}
|
46
|
+
return pets;
|
47
|
+
}
|
48
|
+
|
49
|
+
private:
|
50
|
+
std::vector<Animal*> pets_;
|
51
|
+
};
|
52
|
+
}
|
53
|
+
|
54
|
+
SETUP(Keep_Alive_No_Wrapper)
|
55
|
+
{
|
56
|
+
embed_ruby();
|
57
|
+
}
|
58
|
+
|
59
|
+
TESTCASE(test_keep_alive_no_wrapper)
|
60
|
+
{
|
61
|
+
define_class<Animal>("Animal")
|
62
|
+
.define_constructor(Constructor<Animal, char const *>())
|
63
|
+
.define_method("get_name", &Animal::getName);
|
64
|
+
|
65
|
+
define_class<Zoo>("Zoo")
|
66
|
+
.define_constructor(Constructor<Zoo>())
|
67
|
+
.define_method("get_pets", &Zoo::getPets, Return().keepAlive());
|
68
|
+
|
69
|
+
Module m = define_module("TestingModule");
|
70
|
+
Object zoo = m.module_eval("@zoo = Zoo.new");
|
71
|
+
|
72
|
+
// get_pets returns an Array (builtin type) so Return().keepAlive()
|
73
|
+
// shall result in std::runtime_error
|
74
|
+
ASSERT_EXCEPTION_CHECK(
|
75
|
+
Exception,
|
76
|
+
m.module_eval("@zoo.get_pets.each do |pet| puts pet.name; end"),
|
77
|
+
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.",
|
78
|
+
ex.what())
|
79
|
+
);
|
80
|
+
}
|
data/test/test_Object.cpp
CHANGED
@@ -174,20 +174,29 @@ TESTCASE(call_return_rice_object)
|
|
174
174
|
|
175
175
|
TESTCASE(call_with_keywords)
|
176
176
|
{
|
177
|
-
Module
|
177
|
+
Module m(anonymous_module());
|
178
|
+
|
179
|
+
m.module_eval(R"(
|
180
|
+
def self.keywords_test(value, exception:)
|
181
|
+
if exception
|
182
|
+
raise "An exception!"
|
183
|
+
end
|
178
184
|
|
185
|
+
value
|
186
|
+
end
|
187
|
+
)");
|
179
188
|
|
180
189
|
Hash keywords;
|
181
190
|
keywords[":exception"] = false;
|
182
|
-
Object result =
|
183
|
-
ASSERT_EQUAL(
|
191
|
+
Object result = m.call_kw("keywords_test", "charlie", keywords);
|
192
|
+
ASSERT_EQUAL("charlie", detail::From_Ruby<const char*>().convert(result.value()));
|
184
193
|
|
185
194
|
keywords[":exception"] = true;
|
186
195
|
|
187
196
|
ASSERT_EXCEPTION_CHECK(
|
188
197
|
Exception,
|
189
|
-
|
190
|
-
ASSERT_EQUAL("
|
198
|
+
m.call_kw("keywords_test", "charlie", keywords),
|
199
|
+
ASSERT_EQUAL("An exception!", ex.what())
|
191
200
|
);
|
192
201
|
}
|
193
202
|
|
@@ -240,4 +249,4 @@ TESTCASE(test_mark)
|
|
240
249
|
Object o(INT2NUM(42));
|
241
250
|
rb_gc_start();
|
242
251
|
ASSERT_EQUAL(42, detail::From_Ruby<int>().convert(o.value()));
|
243
|
-
}
|
252
|
+
}
|
@@ -109,6 +109,11 @@ SETUP(SmartPointer)
|
|
109
109
|
define_global_function("extract_flag_unique_ptr_ref", &extractFlagUniquePtrRef);
|
110
110
|
define_global_function("extract_flag_shared_ptr", &extractFlagSharedPtr);
|
111
111
|
define_global_function("extract_flag_shared_ptr_ref", &extractFlagSharedPtrRef);
|
112
|
+
|
113
|
+
define_global_function("extract_flag_shared_ptr_with_default", &extractFlagSharedPtr,
|
114
|
+
Arg("myClass") = std::make_shared<MyClass>());
|
115
|
+
define_global_function("extract_flag_shared_ptr_ref_with_default", &extractFlagSharedPtrRef,
|
116
|
+
Arg("myClass") = std::make_shared<MyClass>());
|
112
117
|
}
|
113
118
|
|
114
119
|
TESTCASE(TransferOwnership)
|
@@ -169,6 +174,7 @@ TESTCASE(UniquePtrRefParameter)
|
|
169
174
|
extract_flag_unique_ptr_ref(my_class))";
|
170
175
|
|
171
176
|
Object result = m.module_eval(code);
|
177
|
+
ASSERT_EQUAL(7, detail::From_Ruby<int>().convert(result));
|
172
178
|
}
|
173
179
|
|
174
180
|
TESTCASE(SharedPtrParameter)
|
@@ -179,10 +185,11 @@ TESTCASE(SharedPtrParameter)
|
|
179
185
|
|
180
186
|
std::string code = R"(factory = Factory.new
|
181
187
|
my_class = factory.share
|
182
|
-
my_class.set_flag(
|
188
|
+
my_class.set_flag(8)
|
183
189
|
extract_flag_shared_ptr(my_class))";
|
184
|
-
|
190
|
+
|
185
191
|
Object result = m.module_eval(code);
|
192
|
+
ASSERT_EQUAL(8, detail::From_Ruby<int>().convert(result));
|
186
193
|
}
|
187
194
|
|
188
195
|
TESTCASE(SharedPtrRefParameter)
|
@@ -193,8 +200,41 @@ TESTCASE(SharedPtrRefParameter)
|
|
193
200
|
|
194
201
|
std::string code = R"(factory = Factory.new
|
195
202
|
my_class = factory.share
|
196
|
-
my_class.set_flag(
|
203
|
+
my_class.set_flag(9)
|
197
204
|
extract_flag_shared_ptr_ref(my_class))";
|
198
205
|
|
199
206
|
Object result = m.module_eval(code);
|
200
|
-
|
207
|
+
ASSERT_EQUAL(9, detail::From_Ruby<int>().convert(result));
|
208
|
+
}
|
209
|
+
|
210
|
+
TESTCASE(SharedPtrDefaultParameter)
|
211
|
+
{
|
212
|
+
MyClass::reset();
|
213
|
+
|
214
|
+
Module m = define_module("TestingModule");
|
215
|
+
|
216
|
+
std::string code = R"(factory = Factory.new
|
217
|
+
my_class = factory.share
|
218
|
+
my_class.set_flag(7)
|
219
|
+
extract_flag_shared_ptr_with_default())";
|
220
|
+
|
221
|
+
Object result = m.module_eval(code);
|
222
|
+
// The default value kicks in and ignores any previous pointer
|
223
|
+
ASSERT_EQUAL(0, detail::From_Ruby<int>().convert(result));
|
224
|
+
}
|
225
|
+
|
226
|
+
TESTCASE(SharedPtrRefDefaultParameter)
|
227
|
+
{
|
228
|
+
MyClass::reset();
|
229
|
+
|
230
|
+
Module m = define_module("TestingModule");
|
231
|
+
|
232
|
+
std::string code = R"(factory = Factory.new
|
233
|
+
my_class = factory.share
|
234
|
+
my_class.set_flag(7)
|
235
|
+
extract_flag_shared_ptr_ref_with_default())";
|
236
|
+
|
237
|
+
Object result = m.module_eval(code);
|
238
|
+
// The default value kicks in and ignores any previous pointer
|
239
|
+
ASSERT_EQUAL(0, detail::From_Ruby<int>().convert(result));
|
240
|
+
}
|
data/test/test_Stl_String.cpp
CHANGED
@@ -27,7 +27,10 @@ TESTCASE(std_string_to_ruby_encoding)
|
|
27
27
|
Object object(value);
|
28
28
|
Object encoding = object.call("encoding");
|
29
29
|
Object encodingName = encoding.call("name");
|
30
|
-
|
30
|
+
std::string result = detail::From_Ruby<std::string>().convert(encodingName);
|
31
|
+
if(result != "ASCII-8BIT" && result != "US-ASCII" && result != "UTF-8") {
|
32
|
+
FAIL("Encoding incorrect", "ASCII-8BIT, US-ASCII, or UTF-8 (Windows)", result);
|
33
|
+
}
|
31
34
|
}
|
32
35
|
|
33
36
|
TESTCASE(std_string_to_ruby_encoding_utf8)
|
@@ -71,4 +74,4 @@ TESTCASE(std_string_from_ruby_with_binary)
|
|
71
74
|
std::string got = detail::From_Ruby<std::string>().convert(rb_str_new("\000test", 5));
|
72
75
|
ASSERT_EQUAL(5ul, got.length());
|
73
76
|
ASSERT_EQUAL(std::string("\000test", 5), got);
|
74
|
-
}
|
77
|
+
}
|
data/test/test_Stl_Variant.cpp
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#include <rice/stl.hpp>
|
5
5
|
|
6
6
|
#include <variant>
|
7
|
+
#include <complex>
|
7
8
|
|
8
9
|
using namespace Rice;
|
9
10
|
|
@@ -11,7 +12,14 @@ TESTSUITE(Variant);
|
|
11
12
|
|
12
13
|
namespace
|
13
14
|
{
|
14
|
-
using Intrinsic_Variant_T = std::variant<
|
15
|
+
using Intrinsic_Variant_T = std::variant<
|
16
|
+
std::string,
|
17
|
+
std::complex<double>,
|
18
|
+
std::vector<int>,
|
19
|
+
double,
|
20
|
+
bool,
|
21
|
+
int
|
22
|
+
>;
|
15
23
|
|
16
24
|
inline std::ostream& operator<<(std::ostream& stream, Intrinsic_Variant_T const& variant)
|
17
25
|
{
|
@@ -30,6 +38,19 @@ namespace
|
|
30
38
|
return result;
|
31
39
|
}
|
32
40
|
|
41
|
+
Intrinsic_Variant_T variantComplex()
|
42
|
+
{
|
43
|
+
using namespace std::complex_literals;
|
44
|
+
Intrinsic_Variant_T result { 1i };
|
45
|
+
return result;
|
46
|
+
}
|
47
|
+
|
48
|
+
Intrinsic_Variant_T variantVector()
|
49
|
+
{
|
50
|
+
Intrinsic_Variant_T result { std::vector<int>{1, 2, 3} };
|
51
|
+
return result;
|
52
|
+
}
|
53
|
+
|
33
54
|
Intrinsic_Variant_T variantDouble()
|
34
55
|
{
|
35
56
|
Intrinsic_Variant_T result { 3.3 };
|
@@ -73,6 +94,8 @@ void makeIntrinsicVariant()
|
|
73
94
|
define_class<MyClass>("MyClass").
|
74
95
|
define_constructor(Constructor<MyClass>()).
|
75
96
|
define_method("variant_string", &MyClass::variantString).
|
97
|
+
define_method("variant_complex", &MyClass::variantComplex).
|
98
|
+
define_method("variant_vector", &MyClass::variantVector).
|
76
99
|
define_method("variant_double", &MyClass::variantDouble).
|
77
100
|
define_method("variant_bool_true", &MyClass::variantBoolTrue).
|
78
101
|
define_method("variant_bool_false", &MyClass::variantBoolFalse).
|
@@ -83,12 +106,21 @@ void makeIntrinsicVariant()
|
|
83
106
|
|
84
107
|
TESTCASE(IntrinsicReturns)
|
85
108
|
{
|
109
|
+
using namespace std::complex_literals;
|
110
|
+
|
86
111
|
Module m = define_module("Testing");
|
87
112
|
Object myClass = m.module_eval("MyClass.new");
|
88
113
|
|
89
114
|
Object result = myClass.call("variant_string");
|
90
115
|
ASSERT_EQUAL("a string", detail::From_Ruby<std::string>().convert(result));
|
91
|
-
|
116
|
+
|
117
|
+
result = myClass.call("variant_complex");
|
118
|
+
ASSERT_EQUAL(1i, detail::From_Ruby<std::complex<double>>().convert(result));
|
119
|
+
|
120
|
+
result = myClass.call("variant_vector");
|
121
|
+
std::vector<int> converted = detail::From_Ruby<std::vector<int>>().convert(result);
|
122
|
+
ASSERT_EQUAL(3, converted.size());
|
123
|
+
|
92
124
|
result = myClass.call("variant_double");
|
93
125
|
ASSERT_EQUAL(3.3, detail::From_Ruby<double>().convert(result));
|
94
126
|
|
@@ -104,6 +136,8 @@ TESTCASE(IntrinsicReturns)
|
|
104
136
|
|
105
137
|
TESTCASE(IntrinsicRoundtrip)
|
106
138
|
{
|
139
|
+
using namespace std::complex_literals;
|
140
|
+
|
107
141
|
Module m = define_module("Testing");
|
108
142
|
Object myClass = m.module_eval("MyClass.new");
|
109
143
|
|
@@ -112,6 +146,17 @@ TESTCASE(IntrinsicRoundtrip)
|
|
112
146
|
Object result = m.module_eval(code);
|
113
147
|
ASSERT_EQUAL("roundtrip string", detail::From_Ruby<std::string>().convert(result));
|
114
148
|
|
149
|
+
code = R"(my_class = MyClass.new
|
150
|
+
my_class.roundtrip(Complex(2, 3)))";
|
151
|
+
result = m.module_eval(code);
|
152
|
+
ASSERT_EQUAL((2.0 + 3i), detail::From_Ruby<std::complex<double>>().convert(result));
|
153
|
+
|
154
|
+
code = R"(my_class = MyClass.new
|
155
|
+
my_class.roundtrip([1, 2, 3]))";
|
156
|
+
result = m.module_eval(code);
|
157
|
+
std::vector<int> expected = {1, 2, 3};
|
158
|
+
ASSERT_EQUAL(expected, detail::From_Ruby<std::vector<int>>().convert(result));
|
159
|
+
|
115
160
|
code = R"(my_class = MyClass.new
|
116
161
|
my_class.roundtrip(44.4))";
|
117
162
|
result = m.module_eval(code);
|
@@ -150,7 +195,7 @@ TESTCASE(VariantAttribute)
|
|
150
195
|
ASSERT_EQUAL(77.7, detail::From_Ruby<double>().convert(result));
|
151
196
|
result = myClass.call("variant_attr");
|
152
197
|
ASSERT_EQUAL(77.7, detail::From_Ruby<double>().convert(result));
|
153
|
-
|
198
|
+
|
154
199
|
result = myClass.call("variant_attr=", true);
|
155
200
|
ASSERT(detail::From_Ruby<bool>().convert(result));
|
156
201
|
result = myClass.call("variant_attr");
|
@@ -298,4 +343,4 @@ TESTCASE(ClassRoundtripRef)
|
|
298
343
|
hello = instance2.call("say_hello");
|
299
344
|
ASSERT_EQUAL("Hi from MyClass2", detail::From_Ruby<std::string>().convert(hello));
|
300
345
|
}
|
301
|
-
#endif
|
346
|
+
#endif
|
data/test/test_To_From_Ruby.cpp
CHANGED
@@ -229,7 +229,7 @@ TESTCASE(unsigned_long_long_from_ruby)
|
|
229
229
|
ASSERT_EXCEPTION_CHECK(
|
230
230
|
Exception,
|
231
231
|
detail::From_Ruby<unsigned long long>().convert(rb_str_new2("bad value")),
|
232
|
-
|
232
|
+
ASSERT(std::string(ex.what()).find("no implicit conversion") == 0)
|
233
233
|
);
|
234
234
|
}
|
235
235
|
|
@@ -396,4 +396,4 @@ TESTCASE(char_star_from_ruby)
|
|
396
396
|
detail::From_Ruby<const char*>().convert(rb_float_new(11.11)),
|
397
397
|
ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
|
398
398
|
);
|
399
|
-
}
|
399
|
+
}
|
data/test/unittest.hpp
CHANGED
@@ -236,7 +236,7 @@ void assert_equal(
|
|
236
236
|
|
237
237
|
if constexpr (is_streamable<std::stringstream, T>::value && is_streamable<std::stringstream, U>::value)
|
238
238
|
{
|
239
|
-
strm << s_t << " != " << s_u;
|
239
|
+
strm << s_t << " != " << s_u << " (" << u << ") ";
|
240
240
|
}
|
241
241
|
strm << " at " << file << ":" << line;
|
242
242
|
throw Assertion_Failed(strm.str());
|
@@ -263,6 +263,14 @@ void assert_not_equal(
|
|
263
263
|
}
|
264
264
|
}
|
265
265
|
|
266
|
+
#define FAIL(message, expect, got) \
|
267
|
+
do \
|
268
|
+
{ \
|
269
|
+
std::stringstream strm; \
|
270
|
+
strm << message << " expected: " << (expect) << " got: " << (got); \
|
271
|
+
throw Assertion_Failed(strm.str()); \
|
272
|
+
} while(0)
|
273
|
+
|
266
274
|
#define ASSERT_EQUAL(x, y) \
|
267
275
|
do \
|
268
276
|
{ \
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Brannan
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2024-01-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -185,6 +185,7 @@ files:
|
|
185
185
|
- test/test_Iterator.cpp
|
186
186
|
- test/test_Jump_Tag.cpp
|
187
187
|
- test/test_Keep_Alive.cpp
|
188
|
+
- test/test_Keep_Alive_No_Wrapper.cpp
|
188
189
|
- test/test_Memory_Management.cpp
|
189
190
|
- test/test_Module.cpp
|
190
191
|
- test/test_Object.cpp
|
@@ -230,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
231
|
- !ruby/object:Gem::Version
|
231
232
|
version: '0'
|
232
233
|
requirements: []
|
233
|
-
rubygems_version: 3.
|
234
|
+
rubygems_version: 3.5.3
|
234
235
|
signing_key:
|
235
236
|
specification_version: 4
|
236
237
|
summary: Ruby Interface for C++ Extensions
|