rice 1.3.2 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Doxyfile +1 -1
- data/README +43 -0
- data/Rakefile +1 -1
- data/extconf.rb +3 -1
- data/rice/Data_Type.ipp +53 -3
- data/rice/Data_Type_defn.hpp +20 -5
- data/rice/config.hpp +5 -5
- data/rice/detail/Caster.hpp +40 -0
- data/rice/detail/ruby_version_code.hpp +1 -1
- data/rice/detail/to_ruby.ipp +1 -2
- data/rice/ruby_mark.hpp +1 -1
- data/ruby/lib/mkmf-rice.rb.in +1 -1
- data/ruby/lib/version.rb +1 -1
- data/sample/enum/test.rb +1 -0
- data/test/Makefile.am +2 -0
- data/test/Makefile.in +8 -5
- data/test/test_Constructor.cpp +39 -38
- data/test/test_Data_Type.cpp +227 -0
- data/test/test_Memory_Management.cpp +50 -0
- metadata +10 -5
data/Doxyfile
CHANGED
@@ -23,7 +23,7 @@ PROJECT_NAME = Rice
|
|
23
23
|
# This could be handy for archiving the generated documentation or
|
24
24
|
# if some version control system is used.
|
25
25
|
|
26
|
-
PROJECT_NUMBER = 1.
|
26
|
+
PROJECT_NUMBER = 1.4.0
|
27
27
|
|
28
28
|
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
29
29
|
# base path where the generated documentation will be put.
|
data/README
CHANGED
@@ -695,6 +695,12 @@ can be used as expected:
|
|
695
695
|
t.hello("goodnight", "moon")
|
696
696
|
\endcode
|
697
697
|
|
698
|
+
This will also work with Constructors:
|
699
|
+
|
700
|
+
\code
|
701
|
+
.define_constructor(Constructor<SomeClass, int, int>(),
|
702
|
+
( Arg("arg1") = 1, Arg("otherArg") = 12 );
|
703
|
+
\endcode
|
698
704
|
|
699
705
|
\section director Director
|
700
706
|
|
@@ -822,6 +828,43 @@ Rice::Data_Type::define_director, then define methods pointing to the proxy obje
|
|
822
828
|
You must use the Rice::Director proxy class in the Constructor line, this allows proper
|
823
829
|
object construction / destruction of the types in question.
|
824
830
|
|
831
|
+
\section implicit_cast Implicit Casting
|
832
|
+
|
833
|
+
There are times when a library exposes classes that while unrelated are
|
834
|
+
built to be interchangeable across the library. One example of this,
|
835
|
+
taken from Ogre, are the Degree and Radian classes. When a given method
|
836
|
+
takes a Radian, you're free to pass in a Degree, and vice versa.
|
837
|
+
|
838
|
+
Rice cannot automatically figure out if this kind of functionality is
|
839
|
+
possible in a given library but it does have a simple API for defining
|
840
|
+
these relationships: Rice::define_implicit_cast<From, To>().
|
841
|
+
|
842
|
+
\code
|
843
|
+
class Degree { ... };
|
844
|
+
class Radian { ... };
|
845
|
+
|
846
|
+
extern "C"
|
847
|
+
void Init_implicit() {
|
848
|
+
define_class<Degree>()
|
849
|
+
...;
|
850
|
+
define_class<Radian>()
|
851
|
+
...;
|
852
|
+
|
853
|
+
define_implicit_cast<Degree, Radian>();
|
854
|
+
define_implicit_cast<Radian, Degree>();
|
855
|
+
}
|
856
|
+
\endcode
|
857
|
+
|
858
|
+
This support is still being fleshed out and has a few requirements for
|
859
|
+
proper use:
|
860
|
+
|
861
|
+
\li The two types must be bound in Rice before defining the cast.
|
862
|
+
\li The classes must have constructors that take the other type.
|
863
|
+
\li This feature cannot be used with fundamental types yet.
|
864
|
+
|
865
|
+
To see a full example of this feature, please check out
|
866
|
+
test/test_Data_Type.cpp.
|
867
|
+
|
825
868
|
\section motivation Motivation
|
826
869
|
|
827
870
|
There are a number of common problems when writing C or C++ extensions
|
data/Rakefile
CHANGED
data/extconf.rb
CHANGED
@@ -26,9 +26,11 @@ with_ruby = File.join(Config::CONFIG["bindir"], Config::CONFIG["RUBY_INSTALL_NAM
|
|
26
26
|
other_opts = ""
|
27
27
|
env = ""
|
28
28
|
|
29
|
+
arch = Config::CONFIG["arch"].split("-")[0]
|
30
|
+
|
29
31
|
if RUBY_PLATFORM =~ /darwin10/
|
30
32
|
other_opts = "--disable-dependency-tracking"
|
31
|
-
env = "ARCHFLAGS='-arch
|
33
|
+
env = "ARCHFLAGS='-arch #{arch}'"
|
32
34
|
elsif RUBY_PLATFORM =~ /darwin9/
|
33
35
|
env = "ARCHFLAGS='-arch #{`uname -p`.chomp}'"
|
34
36
|
end
|
data/rice/Data_Type.ipp
CHANGED
@@ -121,7 +121,8 @@ template<typename T>
|
|
121
121
|
template<typename Constructor_T>
|
122
122
|
inline Rice::Data_Type<T> & Rice::Data_Type<T>::
|
123
123
|
define_constructor(
|
124
|
-
Constructor_T constructor
|
124
|
+
Constructor_T /* constructor */,
|
125
|
+
Arguments* arguments)
|
125
126
|
{
|
126
127
|
check_is_bound();
|
127
128
|
|
@@ -129,11 +130,28 @@ define_constructor(
|
|
129
130
|
rb_define_alloc_func(
|
130
131
|
static_cast<VALUE>(*this),
|
131
132
|
detail::default_allocation_func<T>);
|
132
|
-
define_method(
|
133
|
+
define_method(
|
134
|
+
"initialize",
|
135
|
+
&Constructor_T::construct,
|
136
|
+
arguments
|
137
|
+
);
|
133
138
|
|
134
139
|
return *this;
|
135
140
|
}
|
136
141
|
|
142
|
+
template<typename T>
|
143
|
+
template<typename Constructor_T>
|
144
|
+
inline Rice::Data_Type<T> & Rice::Data_Type<T>::
|
145
|
+
define_constructor(
|
146
|
+
Constructor_T constructor,
|
147
|
+
Arg const& arg)
|
148
|
+
{
|
149
|
+
Arguments* args = new Arguments();
|
150
|
+
args->add(arg);
|
151
|
+
return define_constructor(constructor, args);
|
152
|
+
}
|
153
|
+
|
154
|
+
|
137
155
|
template<typename T>
|
138
156
|
template<typename Director_T>
|
139
157
|
inline Rice::Data_Type<T>& Rice::Data_Type<T>::
|
@@ -177,7 +195,7 @@ from_ruby(Object x)
|
|
177
195
|
|
178
196
|
VALUE ancestors = rb_mod_ancestors(klass.value());
|
179
197
|
|
180
|
-
|
198
|
+
long earliest = RARRAY_LEN(ancestors) + 1;
|
181
199
|
|
182
200
|
int index;
|
183
201
|
VALUE indexFound;
|
@@ -312,4 +330,36 @@ define_class(
|
|
312
330
|
return Data_Type<T>::template bind<Base_T>(c);
|
313
331
|
}
|
314
332
|
|
333
|
+
template<typename From_T, typename To_T>
|
334
|
+
inline void
|
335
|
+
Rice::define_implicit_cast()
|
336
|
+
{
|
337
|
+
// As Rice currently expects only one entry into
|
338
|
+
// this list for a given klass VALUE, we need to get
|
339
|
+
// the current caster for From_T and insert in our
|
340
|
+
// new caster as the head of the caster list
|
341
|
+
|
342
|
+
Class from_class = Data_Type<From_T>::klass().value();
|
343
|
+
Class to_class = Data_Type<To_T>::klass().value();
|
344
|
+
|
345
|
+
detail::Abstract_Caster* from_caster =
|
346
|
+
Data_Type<From_T>::caster_.release();
|
347
|
+
|
348
|
+
detail::Abstract_Caster* new_caster =
|
349
|
+
new detail::Implicit_Caster<To_T, From_T>(from_caster, to_class);
|
350
|
+
|
351
|
+
// Insert our new caster into the list for the from class
|
352
|
+
Data_Type_Base::casters().erase(from_class);
|
353
|
+
Data_Type_Base::casters().insert(
|
354
|
+
std::make_pair(
|
355
|
+
from_class,
|
356
|
+
new_caster
|
357
|
+
)
|
358
|
+
);
|
359
|
+
|
360
|
+
// And make sure the from_class has direct access to the
|
361
|
+
// updated caster list
|
362
|
+
Data_Type<From_T>::caster_.reset(new_caster);
|
363
|
+
}
|
364
|
+
|
315
365
|
#endif // Rice__Data_Type__ipp_
|
data/rice/Data_Type_defn.hpp
CHANGED
@@ -39,7 +39,6 @@ public:
|
|
39
39
|
// Must be public to workaround gcc 3.3
|
40
40
|
typedef std::map<VALUE, detail::Abstract_Caster *> Casters;
|
41
41
|
|
42
|
-
protected:
|
43
42
|
virtual detail::Abstract_Caster * caster() const = 0;
|
44
43
|
|
45
44
|
static Casters & casters();
|
@@ -93,6 +92,15 @@ template<typename T, typename Base_T>
|
|
93
92
|
Rice::Data_Type<T> define_class(
|
94
93
|
char const * name);
|
95
94
|
|
95
|
+
//! Define an implicit conversion rule between two types.
|
96
|
+
/*! Given two types, which can be custom types already
|
97
|
+
* wrapped into Rice or fundamental C++ types, this
|
98
|
+
* tells Rice that the two types can be used interchangably.
|
99
|
+
* \param From_T The type to convert from
|
100
|
+
* \param To_T The type to convert to
|
101
|
+
*/
|
102
|
+
template<typename From_T, typename To_T>
|
103
|
+
void define_implicit_cast();
|
96
104
|
|
97
105
|
//! A mechanism for binding ruby types to C++ types.
|
98
106
|
/*! This class binds run-time types (Ruby VALUEs) to compile-time types
|
@@ -151,7 +159,13 @@ public:
|
|
151
159
|
*/
|
152
160
|
template<typename Constructor_T>
|
153
161
|
Data_Type<T> & define_constructor(
|
154
|
-
Constructor_T constructor
|
162
|
+
Constructor_T constructor,
|
163
|
+
Arguments * arguments = 0);
|
164
|
+
|
165
|
+
template<typename Constructor_T>
|
166
|
+
Data_Type<T> & define_constructor(
|
167
|
+
Constructor_T constructor,
|
168
|
+
Arg const& arg);
|
155
169
|
|
156
170
|
//! Register a Director class for this class.
|
157
171
|
/*! For any class that uses Rice::Director to enable polymorphism
|
@@ -188,6 +202,10 @@ public:
|
|
188
202
|
*/
|
189
203
|
static bool is_bound();
|
190
204
|
|
205
|
+
virtual detail::Abstract_Caster * caster() const;
|
206
|
+
|
207
|
+
static std::auto_ptr<detail::Abstract_Caster> caster_;
|
208
|
+
|
191
209
|
protected:
|
192
210
|
//! Bind a Data_Type to a VALUE.
|
193
211
|
/*! Throws an exception if the Data_Type is already bound to a
|
@@ -221,12 +239,9 @@ private:
|
|
221
239
|
template<typename T_>
|
222
240
|
friend class Data_Type;
|
223
241
|
|
224
|
-
virtual detail::Abstract_Caster * caster() const;
|
225
|
-
|
226
242
|
static void check_is_bound();
|
227
243
|
|
228
244
|
static VALUE klass_;
|
229
|
-
static std::auto_ptr<detail::Abstract_Caster> caster_;
|
230
245
|
|
231
246
|
typedef std::set<Data_Type<T> *> Instances;
|
232
247
|
|
data/rice/config.hpp
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
/* rice/config.hpp.in. Generated from configure.ac by autoheader. */
|
3
3
|
|
4
4
|
/* Define to 1 if you have the <env.h> header file. */
|
5
|
-
#
|
5
|
+
/* #undef HAVE_ENV_H */
|
6
6
|
|
7
7
|
/* Define to 1 if you have the <node.h> header file. */
|
8
|
-
#
|
8
|
+
/* #undef HAVE_NODE_H */
|
9
9
|
|
10
10
|
/* Define to 1 if you have the <ruby.h> header file. */
|
11
11
|
#define HAVE_RUBY_H 1
|
12
12
|
|
13
13
|
/* Define to 1 if you have the <ruby/node.h> header file. */
|
14
|
-
#
|
14
|
+
/* #undef HAVE_RUBY_NODE_H */
|
15
15
|
|
16
16
|
/* Define to 1 if you have the <version.h> header file. */
|
17
|
-
#
|
17
|
+
/* #undef HAVE_VERSION_H */
|
18
18
|
|
19
19
|
/* Name of package */
|
20
20
|
#define PACKAGE "rice"
|
@@ -35,7 +35,7 @@
|
|
35
35
|
#define PACKAGE_VERSION "1.1"
|
36
36
|
|
37
37
|
/* Define this macro to use ruby/node.h */
|
38
|
-
#
|
38
|
+
/* #undef REALLY_HAVE_RUBY_NODE_H */
|
39
39
|
|
40
40
|
/* Version number of package */
|
41
41
|
#define VERSION "1.1"
|
data/rice/detail/Caster.hpp
CHANGED
@@ -56,6 +56,46 @@ private:
|
|
56
56
|
Module type_;
|
57
57
|
};
|
58
58
|
|
59
|
+
template<typename To_T, typename From_T>
|
60
|
+
class Implicit_Caster
|
61
|
+
: public Abstract_Caster
|
62
|
+
{
|
63
|
+
public:
|
64
|
+
Implicit_Caster(Abstract_Caster * base_caster, Module type)
|
65
|
+
: base_caster_(base_caster)
|
66
|
+
, type_(type)
|
67
|
+
{
|
68
|
+
}
|
69
|
+
|
70
|
+
protected:
|
71
|
+
virtual void * cast_to_base(void * derived, Module type) const
|
72
|
+
{
|
73
|
+
if(type.value() == type_.value())
|
74
|
+
{
|
75
|
+
return new To_T( *static_cast<From_T*>(derived) );
|
76
|
+
}
|
77
|
+
else
|
78
|
+
{
|
79
|
+
if(base_caster_)
|
80
|
+
{
|
81
|
+
return base_caster_->cast_to_base(derived, type);
|
82
|
+
}
|
83
|
+
else
|
84
|
+
{
|
85
|
+
std::string s = "bad cast. No implicit caster found for ";
|
86
|
+
s += type_.name().str();
|
87
|
+
throw std::runtime_error(s);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
private:
|
93
|
+
Abstract_Caster * base_caster_;
|
94
|
+
Module type_;
|
95
|
+
};
|
96
|
+
|
97
|
+
|
98
|
+
|
59
99
|
} // detail
|
60
100
|
|
61
101
|
} // Rice
|
data/rice/detail/to_ruby.ipp
CHANGED
data/rice/ruby_mark.hpp
CHANGED
data/ruby/lib/mkmf-rice.rb.in
CHANGED
data/ruby/lib/version.rb
CHANGED
data/sample/enum/test.rb
CHANGED
data/test/Makefile.am
CHANGED
@@ -46,6 +46,7 @@ unittest_SOURCES = \
|
|
46
46
|
test_Hash.cpp \
|
47
47
|
test_Identifier.cpp \
|
48
48
|
test_Jump_Tag.cpp \
|
49
|
+
test_Memory_Management.cpp \
|
49
50
|
test_Module.cpp \
|
50
51
|
test_Object.cpp \
|
51
52
|
test_String.cpp \
|
@@ -60,6 +61,7 @@ vm_unittest_SOURCES = \
|
|
60
61
|
|
61
62
|
AM_CPPFLAGS = \
|
62
63
|
-I.. \
|
64
|
+
$(RUBY_CFLAGS)
|
63
65
|
$(RUBY_CPPFLAGS)
|
64
66
|
|
65
67
|
AM_CXXLAGS = \
|
data/test/Makefile.in
CHANGED
@@ -54,10 +54,10 @@ am_unittest_OBJECTS = unittest.$(OBJEXT) \
|
|
54
54
|
test_Director.$(OBJEXT) test_Enum.$(OBJEXT) \
|
55
55
|
test_Exception.$(OBJEXT) test_Hash.$(OBJEXT) \
|
56
56
|
test_Identifier.$(OBJEXT) test_Jump_Tag.$(OBJEXT) \
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
test_global_functions.$(OBJEXT)
|
57
|
+
test_Memory_Management.$(OBJEXT) test_Module.$(OBJEXT) \
|
58
|
+
test_Object.$(OBJEXT) test_String.$(OBJEXT) \
|
59
|
+
test_Struct.$(OBJEXT) test_Symbol.$(OBJEXT) \
|
60
|
+
test_To_From_Ruby.$(OBJEXT) test_global_functions.$(OBJEXT)
|
61
61
|
unittest_OBJECTS = $(am_unittest_OBJECTS)
|
62
62
|
unittest_LDADD = $(LDADD)
|
63
63
|
am_vm_unittest_OBJECTS = unittest.$(OBJEXT) test_VM.$(OBJEXT)
|
@@ -237,6 +237,7 @@ unittest_SOURCES = \
|
|
237
237
|
test_Hash.cpp \
|
238
238
|
test_Identifier.cpp \
|
239
239
|
test_Jump_Tag.cpp \
|
240
|
+
test_Memory_Management.cpp \
|
240
241
|
test_Module.cpp \
|
241
242
|
test_Object.cpp \
|
242
243
|
test_String.cpp \
|
@@ -251,7 +252,7 @@ vm_unittest_SOURCES = \
|
|
251
252
|
|
252
253
|
AM_CPPFLAGS = \
|
253
254
|
-I.. \
|
254
|
-
$(
|
255
|
+
$(RUBY_CFLAGS)
|
255
256
|
|
256
257
|
AM_CXXLAGS = \
|
257
258
|
$(RUBY_CXXFLAGS)
|
@@ -324,6 +325,7 @@ distclean-compile:
|
|
324
325
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Hash.Po@am__quote@
|
325
326
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Identifier.Po@am__quote@
|
326
327
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Jump_Tag.Po@am__quote@
|
328
|
+
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Memory_Management.Po@am__quote@
|
327
329
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Module.Po@am__quote@
|
328
330
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Object.Po@am__quote@
|
329
331
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_String.Po@am__quote@
|
@@ -720,6 +722,7 @@ check: run_multiple_extensions_same_class_test
|
|
720
722
|
|
721
723
|
run_multiple_extensions_same_class_test:
|
722
724
|
$(RUBY) test_multiple_extensions_same_class.rb
|
725
|
+
$(RUBY_CPPFLAGS)
|
723
726
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
724
727
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
725
728
|
.NOEXPORT:
|
data/test/test_Constructor.cpp
CHANGED
@@ -65,63 +65,64 @@ TESTCASE(non_default_constructor)
|
|
65
65
|
ASSERT_EQUAL(42, o->i());
|
66
66
|
}
|
67
67
|
|
68
|
-
/*
|
69
68
|
namespace
|
70
69
|
{
|
70
|
+
int withArgsX;
|
71
|
+
float withArgsY;
|
72
|
+
bool withArgsYes;
|
73
|
+
|
71
74
|
class WithDefaultArgs
|
72
75
|
{
|
73
76
|
public:
|
74
77
|
WithDefaultArgs(int x, float y = 2.0, bool yes = false)
|
75
78
|
{
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
+
withArgsX = x;
|
80
|
+
withArgsY = y;
|
81
|
+
withArgsYes = yes;
|
79
82
|
}
|
83
|
+
};
|
80
84
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
+
int withArgX;
|
86
|
+
class WithOneArg
|
87
|
+
{
|
88
|
+
public:
|
89
|
+
WithOneArg(int x = 14) {
|
90
|
+
withArgX = x;
|
85
91
|
}
|
86
|
-
|
87
|
-
int getX() { return x_; }
|
88
|
-
float getY() { return y_; }
|
89
|
-
bool getYes() { return yes_; }
|
90
|
-
|
91
|
-
private:
|
92
|
-
|
93
|
-
int x_;
|
94
|
-
float y_;
|
95
|
-
bool yes_;
|
96
92
|
};
|
97
93
|
}
|
98
94
|
|
99
95
|
TESTCASE(constructor_supports_default_arguments)
|
100
96
|
{
|
101
97
|
Class klass = define_class<WithDefaultArgs>("WithDefaultArgs").
|
102
|
-
define_constructor(Constructor<WithDefaultArgs, int, float, bool>(
|
103
|
-
( Arg("x"), Arg("y") = (float)2.0, Arg("yes") = (bool)false ))
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
ASSERT_EQUAL(
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
ASSERT_EQUAL(
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
ASSERT_EQUAL(
|
119
|
-
ASSERT_EQUAL(12.0, obj->getY());
|
120
|
-
ASSERT_EQUAL(true, obj->getYes());
|
98
|
+
define_constructor(Constructor<WithDefaultArgs, int, float, bool>(),
|
99
|
+
( Arg("x"), Arg("y") = (float)2.0, Arg("yes") = (bool)false ));
|
100
|
+
|
101
|
+
klass.call("new", 4);
|
102
|
+
ASSERT_EQUAL(4, withArgsX);
|
103
|
+
ASSERT_EQUAL(2.0, withArgsY);
|
104
|
+
ASSERT_EQUAL(false, withArgsYes);
|
105
|
+
|
106
|
+
klass.call("new", 5, 3.0);
|
107
|
+
ASSERT_EQUAL(5, withArgsX);
|
108
|
+
ASSERT_EQUAL(3.0, withArgsY);
|
109
|
+
ASSERT_EQUAL(false, withArgsYes);
|
110
|
+
|
111
|
+
klass.call("new", 7, 12.0, true);
|
112
|
+
ASSERT_EQUAL(7, withArgsX);
|
113
|
+
ASSERT_EQUAL(12.0, withArgsY);
|
114
|
+
ASSERT_EQUAL(true, withArgsYes);
|
121
115
|
}
|
122
116
|
|
123
117
|
TESTCASE(constructor_supports_single_default_argument)
|
124
118
|
{
|
119
|
+
Class klass = define_class<WithOneArg>("WithOneArg").
|
120
|
+
define_constructor(Constructor<WithOneArg, int>(),
|
121
|
+
( Arg("x") = 14 ));
|
122
|
+
|
123
|
+
klass.call("new");
|
124
|
+
ASSERT_EQUAL(14, withArgX);
|
125
125
|
|
126
|
+
klass.call("new", 6);
|
127
|
+
ASSERT_EQUAL(6, withArgX);
|
126
128
|
}
|
127
|
-
*/
|
data/test/test_Data_Type.cpp
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#include "rice/Data_Type.hpp"
|
3
3
|
#include "rice/Exception.hpp"
|
4
4
|
#include "rice/Constructor.hpp"
|
5
|
+
#include "rice/global_function.hpp"
|
5
6
|
|
6
7
|
using namespace Rice;
|
7
8
|
|
@@ -119,3 +120,229 @@ TESTCASE(no_super_in_constructor_still_works)
|
|
119
120
|
ASSERT_EQUAL(INT2NUM(8), handler.call("process").value());
|
120
121
|
}
|
121
122
|
*/
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Implicit Casting across unrelated types
|
126
|
+
*
|
127
|
+
* Two ways of defining if types are implicitly castable
|
128
|
+
*
|
129
|
+
* 1) operator
|
130
|
+
* 2) constructor
|
131
|
+
*/
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Examples here taken from Ogre's Math library.
|
135
|
+
* This uses the constructor method of casting types.
|
136
|
+
*/
|
137
|
+
namespace
|
138
|
+
{
|
139
|
+
const int degree2Radians = (3.14 / 180.0);
|
140
|
+
const int radian2Degrees = (180.0 / 3.14);
|
141
|
+
|
142
|
+
class Radian;
|
143
|
+
|
144
|
+
class Degree
|
145
|
+
{
|
146
|
+
public:
|
147
|
+
explicit Degree(float d) : val_(d) {}
|
148
|
+
Degree(const Radian& r);
|
149
|
+
|
150
|
+
float valueDegrees() const { return val_; }
|
151
|
+
float valueRadians() const { return val_ * degree2Radians; }
|
152
|
+
|
153
|
+
private:
|
154
|
+
float val_;
|
155
|
+
};
|
156
|
+
|
157
|
+
class Radian
|
158
|
+
{
|
159
|
+
public:
|
160
|
+
explicit Radian(float r) : val_(r) {}
|
161
|
+
Radian(const Degree& d) : val_(d.valueRadians()) {}
|
162
|
+
|
163
|
+
float valueRadians() const { return val_; }
|
164
|
+
float valueDegrees() const { return val_ * radian2Degrees; }
|
165
|
+
|
166
|
+
private:
|
167
|
+
float val_;
|
168
|
+
};
|
169
|
+
|
170
|
+
// Due to circular dependencies, need to define some
|
171
|
+
// methods down here
|
172
|
+
Degree::Degree(const Radian& r)
|
173
|
+
{
|
174
|
+
val_ = r.valueDegrees();
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* And now some methods that work w/ the above two classes
|
179
|
+
*/
|
180
|
+
bool isAcute(Degree degree) {
|
181
|
+
return degree.valueDegrees() < 90;
|
182
|
+
}
|
183
|
+
|
184
|
+
bool isObtuse(Radian radian) {
|
185
|
+
return radian.valueDegrees() > 90 && radian.valueDegrees() <= 180;
|
186
|
+
}
|
187
|
+
|
188
|
+
bool isRight(Degree* degree) {
|
189
|
+
return degree->valueDegrees() == 90;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
TESTCASE(can_define_implicit_type_conversions_across_wrapped_types)
|
194
|
+
{
|
195
|
+
define_class<Degree>("Degree")
|
196
|
+
.define_constructor(Constructor<Degree, float>());
|
197
|
+
|
198
|
+
define_class<Radian>("Radian")
|
199
|
+
.define_constructor(Constructor<Radian, float>());
|
200
|
+
|
201
|
+
define_implicit_cast<Degree, Radian>();
|
202
|
+
define_implicit_cast<Radian, Degree>();
|
203
|
+
|
204
|
+
define_global_function("is_acute", &isAcute);
|
205
|
+
define_global_function("is_obtuse", &isObtuse);
|
206
|
+
define_global_function("is_right", &isRight);
|
207
|
+
|
208
|
+
Module m = define_module("TestingModule");
|
209
|
+
Object result;
|
210
|
+
|
211
|
+
// ACUTE
|
212
|
+
result = m.instance_eval("is_acute(Degree.new(75))");
|
213
|
+
ASSERT(from_ruby<bool>(result.value()));
|
214
|
+
|
215
|
+
result = m.instance_eval("is_acute(Radian.new(2.0))");
|
216
|
+
ASSERT(!from_ruby<bool>(result.value()));
|
217
|
+
|
218
|
+
// OBTUSE
|
219
|
+
result = m.instance_eval("is_obtuse(Degree.new(75))");
|
220
|
+
ASSERT(!from_ruby<bool>(result.value()));
|
221
|
+
|
222
|
+
result = m.instance_eval("is_obtuse(Radian.new(2.0))");
|
223
|
+
ASSERT(from_ruby<bool>(result.value()));
|
224
|
+
|
225
|
+
// RIGHT
|
226
|
+
result = m.instance_eval("is_right(Degree.new(90))");
|
227
|
+
ASSERT(from_ruby<bool>(result.value()));
|
228
|
+
|
229
|
+
result = m.instance_eval("is_right(Radian.new(2.0))");
|
230
|
+
ASSERT(!from_ruby<bool>(result.value()));
|
231
|
+
}
|
232
|
+
|
233
|
+
namespace {
|
234
|
+
class Explicit
|
235
|
+
{
|
236
|
+
public:
|
237
|
+
Explicit(float v) {
|
238
|
+
value = v;
|
239
|
+
}
|
240
|
+
|
241
|
+
Explicit(const Degree &d) {
|
242
|
+
value = d.valueDegrees();
|
243
|
+
}
|
244
|
+
|
245
|
+
float getValue() { return value; }
|
246
|
+
|
247
|
+
private:
|
248
|
+
float value;
|
249
|
+
};
|
250
|
+
|
251
|
+
float getExplicitValue(Explicit* v) {
|
252
|
+
return v->getValue();
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
TESTCASE(supports_multiple_implicit_conversions_for_a_type)
|
257
|
+
{
|
258
|
+
define_class<Degree>("Degree")
|
259
|
+
.define_constructor(Constructor<Degree, float>());
|
260
|
+
|
261
|
+
define_class<Radian>("Radian")
|
262
|
+
.define_constructor(Constructor<Radian, float>());
|
263
|
+
|
264
|
+
define_class<Explicit>("Explicit")
|
265
|
+
.define_constructor(Constructor<Explicit, float>());
|
266
|
+
|
267
|
+
define_global_function("is_obtuse", &isObtuse);
|
268
|
+
define_global_function("explicit_value", &getExplicitValue);
|
269
|
+
|
270
|
+
define_implicit_cast<Radian, Degree>();
|
271
|
+
define_implicit_cast<Degree, Radian>();
|
272
|
+
define_implicit_cast<Degree, Explicit>();
|
273
|
+
|
274
|
+
Module m = define_module("TestingModule");
|
275
|
+
Object result;
|
276
|
+
|
277
|
+
result = m.instance_eval("is_obtuse(Degree.new(75))");
|
278
|
+
ASSERT(!from_ruby<bool>(result.value()));
|
279
|
+
|
280
|
+
result = m.instance_eval("explicit_value(Degree.new(75))");
|
281
|
+
ASSERT_EQUAL(75.0, from_ruby<float>(result.value()));
|
282
|
+
}
|
283
|
+
|
284
|
+
/**
|
285
|
+
* Sample taken and modified from boost::python::implicit:
|
286
|
+
* http://www.boost.org/doc/libs/1_41_0/libs/python/doc/v2/implicit.html
|
287
|
+
*
|
288
|
+
* This is the operator version of casting and shows that this works for
|
289
|
+
* base types as well as defined types
|
290
|
+
*/
|
291
|
+
/*
|
292
|
+
namespace {
|
293
|
+
struct Real
|
294
|
+
{
|
295
|
+
Real(int x)
|
296
|
+
: v(x)
|
297
|
+
{}
|
298
|
+
|
299
|
+
operator int() const
|
300
|
+
{
|
301
|
+
return v;
|
302
|
+
}
|
303
|
+
|
304
|
+
int v;
|
305
|
+
};
|
306
|
+
|
307
|
+
int realValue(Real const& x)
|
308
|
+
{
|
309
|
+
return x.v;
|
310
|
+
}
|
311
|
+
|
312
|
+
Real makeReal(int n)
|
313
|
+
{
|
314
|
+
return Real(n);
|
315
|
+
}
|
316
|
+
}
|
317
|
+
|
318
|
+
TESTCASE(can_define_implicit_type_conversions_to_base_types)
|
319
|
+
{
|
320
|
+
define_class<Real>("Real")
|
321
|
+
.define_constructor(Constructor<Real, int>());
|
322
|
+
|
323
|
+
// Define the conversion rules
|
324
|
+
define_implicit_cast<Real, int>();
|
325
|
+
define_implicit_cast<int, Real>();
|
326
|
+
|
327
|
+
define_global_function("real_value", &realValue);
|
328
|
+
define_global_function("make_real", &makeReal);
|
329
|
+
|
330
|
+
Module m = define_module("TestingModule");
|
331
|
+
|
332
|
+
// As Real object
|
333
|
+
Object result = m.instance_eval("real_value( Real.new(4) )");
|
334
|
+
ASSERT_EQUAL(4, from_ruby<int>(result.value()));
|
335
|
+
|
336
|
+
// As fixnum (int)
|
337
|
+
result = m.instance_eval("real_value(4)");
|
338
|
+
ASSERT_EQUAL(4, from_ruby<int>(result.value()));
|
339
|
+
|
340
|
+
// As Real object
|
341
|
+
result = m.instance_eval("r = make_real( Real.new(6) ); real_value(r)");
|
342
|
+
ASSERT_EQUAL(6, from_ruby<int>(result.value()));
|
343
|
+
|
344
|
+
// As fixnum (int)
|
345
|
+
result = m.instance_eval("r = make_real(6); real_value(r)");
|
346
|
+
ASSERT_EQUAL(6, from_ruby<int>(result.value()));
|
347
|
+
}
|
348
|
+
*/
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#include "unittest.hpp"
|
2
|
+
#include "rice/String.hpp"
|
3
|
+
#include "rice/Class.hpp"
|
4
|
+
#include "rice/global_function.hpp"
|
5
|
+
|
6
|
+
using namespace Rice;
|
7
|
+
|
8
|
+
TESTSUITE(Memory_Management);
|
9
|
+
|
10
|
+
SETUP(Memory_Management)
|
11
|
+
{
|
12
|
+
ruby_init();
|
13
|
+
}
|
14
|
+
|
15
|
+
namespace
|
16
|
+
{
|
17
|
+
class TestClass {
|
18
|
+
double tmp;
|
19
|
+
public:
|
20
|
+
TestClass() {tmp=0;}
|
21
|
+
|
22
|
+
double getTmp() {
|
23
|
+
return tmp;
|
24
|
+
}
|
25
|
+
|
26
|
+
void setTmp(double x) {
|
27
|
+
tmp = x;
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
TestClass returnTestClass() {
|
32
|
+
TestClass x = TestClass();
|
33
|
+
x.setTmp(8);
|
34
|
+
return x;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
TESTCASE(allows_copy_contructors_to_work)
|
39
|
+
{
|
40
|
+
define_class<TestClass>("TestClass")
|
41
|
+
.define_method("tmp=", &TestClass::setTmp)
|
42
|
+
.define_method("tmp", &TestClass::getTmp);
|
43
|
+
|
44
|
+
define_global_function("return_test_class", &returnTestClass);
|
45
|
+
|
46
|
+
Module m = define_module("TestingModule");
|
47
|
+
|
48
|
+
Object result = m.instance_eval("return_test_class.tmp");
|
49
|
+
ASSERT_EQUAL(8.0, from_ruby<double>(result.value()));
|
50
|
+
}
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 1.
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 1.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Paul Brannan
|
@@ -15,13 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-08-25 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: rubyforge
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
@@ -230,6 +231,7 @@ files:
|
|
230
231
|
- test/test_Hash.cpp
|
231
232
|
- test/test_Identifier.cpp
|
232
233
|
- test/test_Jump_Tag.cpp
|
234
|
+
- test/test_Memory_Management.cpp
|
233
235
|
- test/test_Module.cpp
|
234
236
|
- test/test_Object.cpp
|
235
237
|
- test/test_String.cpp
|
@@ -246,6 +248,7 @@ files:
|
|
246
248
|
- test/ext/t1/t1.cpp
|
247
249
|
- test/ext/t2/extconf.rb
|
248
250
|
- test/ext/t2/t2.cpp
|
251
|
+
- test/test_rice.rb
|
249
252
|
has_rdoc: true
|
250
253
|
homepage: http://rice.rubyforge.org/
|
251
254
|
licenses: []
|
@@ -256,6 +259,7 @@ rdoc_options: []
|
|
256
259
|
require_paths:
|
257
260
|
- ruby/lib
|
258
261
|
required_ruby_version: !ruby/object:Gem::Requirement
|
262
|
+
none: false
|
259
263
|
requirements:
|
260
264
|
- - ">="
|
261
265
|
- !ruby/object:Gem::Version
|
@@ -263,6 +267,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
263
267
|
- 0
|
264
268
|
version: "0"
|
265
269
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
270
|
+
none: false
|
266
271
|
requirements:
|
267
272
|
- - ">="
|
268
273
|
- !ruby/object:Gem::Version
|
@@ -272,7 +277,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
277
|
requirements: []
|
273
278
|
|
274
279
|
rubyforge_project: rice
|
275
|
-
rubygems_version: 1.3.
|
280
|
+
rubygems_version: 1.3.7
|
276
281
|
signing_key:
|
277
282
|
specification_version: 3
|
278
283
|
summary: Ruby Interface for C++ Extensions
|