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 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.3.2
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
@@ -1,7 +1,7 @@
1
+ $: << File.expand_path(File.dirname(__FILE__))
1
2
  require 'rake/gempackagetask'
2
3
  require 'rake/contrib/sshpublisher'
3
4
  require 'yaml'
4
- require 'rubyforge'
5
5
  require 'ruby/lib/version'
6
6
 
7
7
  PROJECT_NAME = "rice"
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 x86_64'"
33
+ env = "ARCHFLAGS='-arch #{arch}'"
32
34
  elsif RUBY_PLATFORM =~ /darwin9/
33
35
  env = "ARCHFLAGS='-arch #{`uname -p`.chomp}'"
34
36
  end
@@ -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("initialize", &Constructor_T::construct);
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
- int earliest = RARRAY_LEN(ancestors) + 1;
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_
@@ -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
 
@@ -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
- #define HAVE_ENV_H 1
5
+ /* #undef HAVE_ENV_H */
6
6
 
7
7
  /* Define to 1 if you have the <node.h> header file. */
8
- #define HAVE_NODE_H 1
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
- #define HAVE_RUBY_NODE_H 1
14
+ /* #undef HAVE_RUBY_NODE_H */
15
15
 
16
16
  /* Define to 1 if you have the <version.h> header file. */
17
- #define HAVE_VERSION_H 1
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
- #define REALLY_HAVE_RUBY_NODE_H
38
+ /* #undef REALLY_HAVE_RUBY_NODE_H */
39
39
 
40
40
  /* Version number of package */
41
41
  #define VERSION "1.1"
@@ -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
@@ -1,6 +1,6 @@
1
1
  #ifndef Rice__detail__ruby_version_code__hpp
2
2
  #define Rice__detail__ruby_version_code__hpp
3
3
 
4
- #define RICE__RUBY_VERSION_CODE 187
4
+ #define RICE__RUBY_VERSION_CODE 192
5
5
 
6
6
  #endif // Rice__detail__ruby_version_code__hpp
@@ -7,8 +7,7 @@ convert(T const & x)
7
7
  {
8
8
  if(Data_Type<T>::is_bound())
9
9
  {
10
- Data_Object<T> obj(&const_cast<T&>(x));
11
- return obj;
10
+ return Rice::Data_Object<T >(new T(x), Rice::Data_Type<T >::klass());
12
11
  }
13
12
  else
14
13
  {
@@ -6,7 +6,7 @@
6
6
  * the default behavior (which is to not mark any additional objects).
7
7
  */
8
8
  template<typename T>
9
- void ruby_mark(T * obj)
9
+ void ruby_mark(T * /* obj */)
10
10
  {
11
11
  }
12
12
 
@@ -190,7 +190,7 @@ class RiceMakefileCreator
190
190
  end
191
191
 
192
192
  def puts(*strings)
193
- print(*strings.map { |s| "#{s}\n" })
193
+ print(*strings.flatten.map { |s| "#{s}\n" })
194
194
  end
195
195
 
196
196
  def close
@@ -1,3 +1,3 @@
1
1
  module Rice
2
- VERSION = "1.3.2"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -1,3 +1,4 @@
1
+ $: << "."
1
2
  require 'sample_enum'
2
3
 
3
4
  Sample_Enum.each { |x| p x }
@@ -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 = \
@@ -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
- test_Module.$(OBJEXT) test_Object.$(OBJEXT) \
58
- test_String.$(OBJEXT) test_Struct.$(OBJEXT) \
59
- test_Symbol.$(OBJEXT) test_To_From_Ruby.$(OBJEXT) \
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
- $(RUBY_CPPFLAGS)
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:
@@ -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
- x_ = x;
77
- y_ = y;
78
- yes_ = yes;
79
+ withArgsX = x;
80
+ withArgsY = y;
81
+ withArgsYes = yes;
79
82
  }
83
+ };
80
84
 
81
- WithDefaultArgs(int x = 14) {
82
- x_ = x;
83
- y_ = 1.0;
84
- yes_ = false;
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
- Data_Object<WithDefaultArgs> obj;
106
-
107
- obj= klass.call("new", 4);
108
- ASSERT_EQUAL(4, obj->getX());
109
- ASSERT_EQUAL(2.0, obj->getY());
110
- ASSERT_EQUAL(false, obj->getYes());
111
-
112
- obj= klass.call("new", 5, 3.0);
113
- ASSERT_EQUAL(5, obj->getX());
114
- ASSERT_EQUAL(3.0, obj->getY());
115
- ASSERT_EQUAL(false, obj->getYes());
116
-
117
- obj= klass.call("new", 7, 12.0, true);
118
- ASSERT_EQUAL(7, obj->getX());
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
- */
@@ -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
- - 3
8
- - 2
9
- version: 1.3.2
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-05-06 00:00:00 -04:00
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.6
280
+ rubygems_version: 1.3.7
276
281
  signing_key:
277
282
  specification_version: 3
278
283
  summary: Ruby Interface for C++ Extensions