From 3ff8d1e629dce7c0002179c66f59becd8e5620c0 Mon Sep 17 00:00:00 2001
From: Charlie Savage A better solution is to use the %alias directive (unique to
SWIG's Ruby module). The previous example could then be rewritten as: Multiple aliases can be associated with a method by providing a comma-separated
list of aliases to the %alias directive, e.g. From an end-user's standpoint, there's no functional difference between these
two approaches; i.e. they should get the same result from calling either MyArray#size or MyArray#length. However, when the %alias directive is
used, SWIG doesn't need to generate all of the wrapper code that's usually
@@ -1020,19 +1022,19 @@ $ ruby -e 'puts $:.join("\n")' A better solution is to use the %predicate directive (unique
to SWIG's Ruby module) to designate a method as a predicate method. For
the previous example, this would look like: This method would be invoked from Ruby code like this: The %predicate directive is implemented using SWIG's
"features" mechanism and so the same name matching rules used for other kinds
of features apply (see the chapter on "Customization
@@ -1055,6 +1057,35 @@ $ ruby -e 'puts $:.join("\n")' Often times a C++ library will expose properties through getter and setter methods. For example: By default, SWIG will expose these methods to Ruby as get_value and set_value. However, it more natural for these methods to be exposed in Ruby as value and value=. That allows the methods to be used like this: This can be done by using the %rename directive:
- The SWIG %exception directive can be used to define a user-definable
+ The SWIG %exception directive can be used to define a user-definable
exception handler that can convert C/C++ errors into Ruby exceptions. The
chapter on Customization Features
contains more details, but suppose you have a C++ class like the following :
Since several methods in this class can throw an exception for an out-of-bounds
@@ -1152,7 +1188,7 @@ $ ruby -e 'puts $:.join("\n")'
The exception handling code is inserted directly into generated wrapper
@@ -1165,7 +1201,7 @@ $ ruby -e 'puts $:.join("\n")'
In this case, the exception handler is only attached to methods and functions
@@ -1175,14 +1211,103 @@ $ ruby -e 'puts $:.join("\n")' When raising a Ruby exception from C/C++, use the rb_raise() function
- as shown above. The first argument passed to rb_raise() is the
- exception type. You can raise a custom exception type (like the cpperror
- example shown above) or one of the built-in Ruby exception types. For a list of
- the standard Ruby exception classes, consult a Ruby reference such as
- Programming Ruby.
- There are three ways to raise exceptions from C++ code to Ruby. The first way is to use SWIG_exception(int code, const char *msg). The following table shows the mappings from SWIG error codes to Ruby exceptions: The second way to raise errors is to use SWIG_Raise(obj, type, desc). Obj is a C++ instance of an exception class, type is a string specifying the type of exception (for example, "MyError") and desc is the SWIG description of the exception class. For example: %raise(SWIG_NewPointerObj(e, SWIGTYPE_p_AssertionFailedException, 0), ":AssertionFailedException", SWIGTYPE_p_AssertionFailedException); This is useful when you want to pass the current exception object directly to Ruby, particularly when the object is an instance of class marked as an %exceptionclass (see the next section for more information). Last, you can raise an exception by directly calling Ruby's C api. This is done by invoking the rb_raise() function. The first argument passed to rb_raise() is the
+ exception type. You can raise a custom exception type or one of the built-in Ruby exception types. Starting with SWIG 1.3.28, the Ruby module supports the %exceptionclass directive, which is used to identify C++ classes that are used as exceptions. Classes that are marked with the %exceptionclass directive are exposed in Ruby as child classes of rb_eRuntimeError. This alows C++ exceptions to be directly mapped to Ruby exceptions, providing for a more natural integration between C++ code and Ruby code. From Ruby you can now call this method like this:
+ For another example look at swig/Examples/ruby/exception_class.
@@ -1195,7 +1320,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1262,7 +1387,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1319,7 +1444,7 @@ $ ruby -e 'puts $:.join("\n")' $symname
@@ -1365,19 +1490,19 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1392,7 +1517,7 @@ $ ruby -e 'puts $:.join("\n")' RARRAY(arr)->ptr
@@ -1459,7 +1584,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1498,14 +1623,14 @@ $ ruby -e 'puts $:.join("\n")'
This section includes a few examples of typemaps. For more examples, you might
look at the examples in the Example/ruby directory.
@@ -1529,7 +1654,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1642,7 +1767,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1689,7 +1814,7 @@ $ ruby -e 'puts $:.join("\n")'
@@ -1710,34 +1835,17 @@ $ ruby -e 'puts $:.join("\n")'
- SWIG allows operator overloading with, by using the %extend or %rename
- commands in SWIG and the following operator names (derived from Python):
-
- Note that although SWIG supports the __eq__ magic method name for
- defining an equivalence operator, there is no separate method for handling inequality
- since Ruby parses the expression a != b as !(a == b).
-
- FIXME: This example is out of place here!
- Another use for macros and type maps is to create a Ruby array from a STL vector
+ FIXME: This example is out of place here! Another use for macros and type maps is to create a Ruby array from a STL vector
of pointers. In essence, copy of all the pointers in the vector into a Ruby
array. The use of the macro is to make the typemap so generic that any vector
with pointers can use the type map. The following is an example of how to
construct this type of macro/typemap and should give insight into constructing
similar typemaps for other STL structures:
-
+
@@ -989,18 +991,18 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
class MyArray {
-
public:
// Construct an empty array
MyArray();
// Return the size of this array
size_t length() const;
};
%extend MyArray {
// MyArray#size is an alias for MyArray#length
size_t size() const {
return self->length();
}
}
// MyArray#size is an alias for MyArray#length
-
%alias MyArray::length "size";
class MyArray {
public:
// Construct an empty array
MyArray();
// Return the size of this array
size_t length() const;
};
%alias MyArray::length "amount,quantity,size";
-
/usr/local/lib/ruby/site_ruby/1.6 /usr/
%rename("is_it_safe?") is_it_safe();
-
%typemap(out) int is_it_safe
"$result = ($1 != 0) ? Qtrue : Qfalse;";
int is_it_safe();
%predicate is_it_safe();
-
int is_it_safe();
irb(main):001:0> Example::is_it_safe?
-
true
/usr/local/lib/ruby/site_ruby/1.6 /usr/
"features" mechanism and so the same name matching rules used for other kinds
of features apply (see the chapter on "Customization
Features") for more details). 30.4.4 Getters and Setters
+
+
+ class Foo {
+ Foo() {}
+
+ int getValue() { return value_; }
+
+ void setValue(int value) { value_ = value; }
+
+private:
+ int value_;
+};
+ irb(main):001:0> foo = Foo.new()
+irb(main):002:0> foo.value = 5
+irb(main):003:0> puts foo.value
+ %rename("value") Foo::getValue();
+%rename("value=") Foo::setValue(int value);
+
+ 30.5 Input and output parameters
@@ -1134,17 +1165,22 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
r, c = Example.get_dimensions(m)
30.6 Simple exception handling
+30.6 Exception handling
- 30.6.1 Using the %exception directive
+
+
+ class DoubleArray {
+
private:
int n;
double *ptr;
public:
// Create a new array of fixed size
DoubleArray(int size) {
ptr = new double[size];
n = size;
}
// Destroy an array
~DoubleArray() {
delete ptr;
}
// Return the length of the array
int length() {
return n;
}
// Get an array item and perform bounds checking.
double getitem(int i) {
if ((i >= 0) && (i < n))
return ptr[i];
else
throw RangeError();
}
// Set an array item and perform bounds checking.
void setitem(int i, double val) {
if ((i >= 0) && (i < n))
ptr[i] = val;
else {
throw RangeError();
}
}
};class DoubleArray {
private:
int n;
double *ptr;
public:
// Create a new array of fixed size
DoubleArray(int size) {
ptr = new double[size];
n = size;
}
+
// Destroy an array
~DoubleArray() {
delete ptr;
}
+
// Return the length of the array
int length() {
return n;
}
// Get an array item and perform bounds checking.
double getitem(int i) {
if ((i >= 0) && (i < n))
return ptr[i];
else
throw RangeError();
}
+
// Set an array item and perform bounds checking.
void setitem(int i, double val) {
if ((i >= 0) && (i < n))
ptr[i] = val;
else {
throw RangeError();
}
}
};
/usr/local/lib/ruby/site_ruby/1.6 /usr/
following in an interface file:
%exception {
+
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error.");
}
}
class DoubleArray {
...
};%exception {
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error.");
}
}
class DoubleArray {
...
};
/usr/local/lib/ruby/site_ruby/1.6 /usr/
handler to only apply to specific methods like this:
%exception getitem {
+
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error in getitem.");
}
}
%exception setitem {
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error in setitem.");
}
}%exception getitem {
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error in getitem.");
}
}
%exception setitem {
try {
$action
}
catch (const RangeError&) {
static VALUE cpperror = rb_define_class("CPPError", rb_eStandardError);
rb_raise(cpperror, "Range error in setitem.");
}
}
/usr/local/lib/ruby/site_ruby/1.6 /usr/
exception handling. See the chapter on Customization
Features for more examples.
30.7 Typemaps
+30.6.2 Raising exceptions
+
+
+
+
+
+
+ SWIG_MemoryError
+ rb_eNoMemError
+
+
+ SWIG_IOError
+ rb_eIOError
+
+
+ SWIG_RuntimeError
+ rb_eRuntimeError
+
+
+ SWIG_IndexError
+ rb_eIndexError
+
+
+ SWIG_TypeError
+ rb_eTypeError
+
+
+ SWIG_DivisionByZero
+ rb_eZeroDivError
+
+
+ SWIG_OverflowError
+ rb_eRangeError
+
+
+ SWIG_SyntaxError
+ rb_eSyntaxError
+
+
+ SWIG_ValueError
+ rb_eArgError
+
+
+ SWIG_SystemError
+ rb_eFatal
+
+
+ SWIG_AttributeError
+ rb_eRuntimeError
+
+
+ SWIG_NullReferenceError
+ rb_eNullReferenceError*
+
+
+ SWIG_ObjectPreviouslyDeletedError
+ rb_eObjectPreviouslyDeleted*
+
+
+ SWIG_UnknownError
+ rb_eRuntimeError
+
+
+ * These error classes are created by SWIG and are not built-in Ruby exception classes
+ 30.6.3 Exception classes
+
+
+ %exceptionclass CustomError;
+
+ %inline %{
+ class CustomError { };
+
+ class Foo {
+
public:
void test() { throw CustomError; }
+ };
+ }
+foo = Foo.new
+begin
+ foo.test()
+rescue CustomError => e
+ puts "Caught custom error"
+end
+
+30.7 Typemaps
/usr/local/lib/ruby/site_ruby/1.6 /usr/
of using SWIG---the default wrapping behavior is enough in most cases. Typemaps
are only used if you want to change some aspect of the primitive C-Ruby
interface.30.7.1 What is a typemap?
+30.7.1 What is a typemap?
/usr/local/lib/ruby/site_ruby/1.6 /usr/
puts Example.count('o','Hello World')
230.7.2 Ruby typemaps
+30.7.2 Ruby typemaps
/usr/local/lib/ruby/site_ruby/1.6 /usr/
Examples of these typemaps appears in the section
on typemap examples
30.7.3 Typemap variables
+30.7.3 Typemap variables
Within a typemap, a number of special variables prefaced with a $ may
@@ -1355,7 +1480,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
30.7.4 Useful Functions
+30.7.4 Useful Functions
/usr/local/lib/ruby/site_ruby/1.6 /usr/
by David Thomas and Andrew Hunt.)
30.7.4.1 C Datatypes to Ruby Objects
+30.7.4.1 C Datatypes to Ruby Objects
INT2NUM(long or int) - int to Fixnum or Bignum
INT2FIX(long or int) - int to Fixnum (faster than INT2NUM)
CHR2FIX(char) - char to Fixnum
rb_str_new2(char*) - char* to String
rb_float_new(double) - double to Float30.7.4.2 Ruby Objects to C Datatypes
+30.7.4.2 Ruby Objects to C Datatypes
int NUM2INT(Numeric)
int FIX2INT(Numeric)
unsigned int NUM2UINT(Numeric)
unsigned int FIX2UINT(Numeric)
long NUM2LONG(Numeric)
long FIX2LONG(Numeric)
unsigned long FIX2ULONG(Numeric)
char NUM2CHR(Numeric or String)
char * STR2CSTR(String)
char * rb_str2cstr(String, int*length)
double NUM2DBL(Numeric)30.7.4.3 Macros for VALUE
+30.7.4.3 Macros for VALUE
/usr/local/lib/ruby/site_ruby/1.6 /usr/
30.7.4.4 Exceptions
+30.7.4.4 Exceptions
/usr/local/lib/ruby/site_ruby/1.6 /usr/
with the -w flag. The given format string fmt and remaining
arguments are interpreted as with printf().
-30.7.4.5 Iterators
+30.7.4.5 Iterators
/usr/local/lib/ruby/site_ruby/1.6 /usr/
30.7.5 Typemap Examples
+30.7.5 Typemap Examples
30.7.6 Converting a Ruby array to a char **
+30.7.6 Converting a Ruby array to a char **
/usr/local/lib/ruby/site_ruby/1.6 /usr/
allocation is used to allocate memory for the array, the "freearg" typemap is
used to later release this memory after the execution of the C function.
30.7.7 Collecting arguments in a hash
+30.7.7 Collecting arguments in a hash
/usr/local/lib/ruby/site_ruby/1.6 /usr/
the extension, can be found in the Examples/ruby/hashargs directory of
the SWIG distribution.
30.7.8 Pointer handling
+30.7.8 Pointer handling
/usr/local/lib/ruby/site_ruby/1.6 /usr/
%typemap(in) Foo * {
SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 1);
}30.7.8.1 Ruby Datatype Wrapping
+30.7.8.1 Ruby Datatype Wrapping
/usr/local/lib/ruby/site_ruby/1.6 /usr/
30.8 Operator overloading
+30.7.9 Example: STL Vector to Ruby Array
- General
-
__repr__ - inspect
__str__ - to_s
__cmp__ - <=>
__hash__ - hash
__nonzero__ - nonzero?
Callable
__call__ - call
Collection
__len__ - length
__getitem__ - []
__setitem__ - []=
Numeric
__add__ - +
__sub__ - -
__mul__ - *
__div__ - /
__mod__ - %
__divmod__ - divmod
__pow__ - **
__lshift__ - <<
__rshift__ - >>
__and__ - &
__xor__ - ^
__or__ - |
__neg__ - -@
__pos__ - +@
__abs__ - abs
__invert__ - ~
__int__ - to_i
__float__ - to_f
__coerce__ - coerce
Additions in 1.3.13
__lt__ - <
__le__ - <=
__eq__ - ==
__gt__ - >
__ge__ - >=30.8.1 Example: STL Vector to Ruby Array
-
-
-
%define PTR_VECTOR_TO_RUBY_ARRAY(vectorclassname, classname)
%typemap(out) vectorclassname &, const vectorclassname & {
VALUE arr = rb_ary_new2($1->size());
vectorclassname::iterator i = $1->begin(), iend = $1->end();
for ( ; i!=iend; i++ )
rb_ary_push(arr, Data_Wrap_Struct(c ## classname.klass, 0, 0, *i));
$result = arr;
}
%typemap(out) vectorclassname, const vectorclassname {
VALUE arr = rb_ary_new2($1.size());
vectorclassname::iterator i = $1.begin(), iend = $1.end();
for ( ; i!=iend; i++ )
rb_ary_push(arr, Data_Wrap_Struct(c ## classname.klass, 0, 0, *i));
$result = arr;
}
%enddef
%define VECTOR_TO_RUBY_ARRAY(vectorclassname, classname)
%typemap(out) vectorclassname &, const vectorclassname & {
VALUE arr = rb_ary_new2($1->size());
vectorclassname::iterator i = $1->begin(), iend = $1->end();
for ( ; i!=iend; i++ )
rb_ary_push(arr, Data_Wrap_Struct(c ## classname.klass, 0, 0, &(*i)));
$result = arr;
}
%typemap(out) vectorclassname, const vectorclassname {
VALUE arr = rb_ary_new2($1.size());
vectorclassname::iterator i = $1.begin(), iend = $1.end();
for ( ; i!=iend; i++ )
rb_ary_push(arr, Data_Wrap_Struct(c ## classname.klass, 0, 0, &(*i)));
$result = arr;
}
%enddef
+ SWIG allows operator overloading with, by using the %extend or %rename + commands in SWIG and the following operator names (derived from Python): +
+General+
__repr__ - inspect
__str__ - to_s
__cmp__ - <=>
__hash__ - hash
__nonzero__ - nonzero?
Callable
__call__ - call
Collection
__len__ - length
__getitem__ - []
__setitem__ - []=
Numeric
__add__ - +
__sub__ - -
__mul__ - *
__div__ - /
__mod__ - %
__divmod__ - divmod
__pow__ - **
__lshift__ - <<
__rshift__ - >>
__and__ - &
__xor__ - ^
__or__ - |
__neg__ - -@
__pos__ - +@
__abs__ - abs
__invert__ - ~
__int__ - to_i
__float__ - to_f
__coerce__ - coerce
Additions in 1.3.13
__lt__ - <
__le__ - <=
__eq__ - ==
__gt__ - >
__ge__ - >=
+ Note that although SWIG supports the __eq__ magic method name for + defining an equivalence operator, there is no separate method for handling inequality + since Ruby parses the expression a != b as !(a == b). +
+The chapter on Working with Modules discusses the basics of creating multi-module extensions with SWIG, and in particular the considerations for sharing runtime type information among the different modules. -
+As an example, consider one module's interface file (shape.i) that defines our base class:
@@ -1836,83 +1960,8 @@ $ ruby -e 'puts $:.join("\n")'$ irb
irb(main):001:0> require 'shape'
true
irb(main):002:0> require 'circle'
true
irb(main):003:0> c = Circle::Circle.new(5, 5, 20)
#<Circle::Circle:0xa097208>
irb(main):004:0> c.kind_of? Shape::Shape
true
irb(main):005:0> c.getX()
5.0
- It's a fairly common practice in the Ruby built-ins and standard library to - provide aliases for method names. For example, Array#size is an alias - for Array#length. If you'd like to provide an alias for one of your - class' instance methods, one approach is to use SWIG's %extend directive - to add a new method of the aliased name that calls the original function. For - example: -
-class MyArray {
public:
// Construct an empty array
MyArray();
// Return the size of this array
size_t length() const;
};
%extend MyArray {
// MyArray#size is an alias for MyArray#length
size_t size() const {
return self->length();
}
}
- - A better solution is to instead use the %alias directive (unique to - SWIG's Ruby module). The previous example could then be rewritten as: -
-// MyArray#size is an alias for MyArray#length-
%alias MyArray::length "size";
class MyArray {
public:
// Construct an empty array
MyArray();
// Return the size of this array
size_t length() const;
};
- Multiple aliases can be associated with a method by providing a comma-separated - list of aliases to the %alias directive, e.g. -
-%alias MyArray::length "amount,quantity,size";-
- From an end-user's standpoint, there's no functional difference between these - two approaches; i.e. they should get the same result from calling either MyArray#size - or MyArray#length. However, when the %alias directive is - used, SWIG doesn't need to generate all of the wrapper code that's usually - associated with added methods like our MyArray::size() example. -
-Note that the %alias directive is implemented using SWIG's "features" - mechanism and so the same name matching rules used for other kinds of features - apply (see the chapter on "Customization - Features") for more details).
-- Predicate methods in Ruby are those which return either true or false. - By convention, these methods' names end in a question mark; some examples from - built-in Ruby classes include Array#empty? (which returns true - for an array containing no elements) and Object#instance_of? (which - returns true if the object is an instance of the specified class). For - consistency with Ruby conventions you would also want your interface's - predicate methods' names to end in a question mark and return true or false. -
-One cumbersome solution to this problem is to rename the method (using SWIG's %rename - directive) and provide a custom typemap that converts the function's actual - return type to Ruby's true or false. For example: -
-%rename("is_it_safe?") is_it_safe();
%typemap(out) int is_it_safe
"$result = ($1 != 0) ? Qtrue : Qfalse;";
int is_it_safe();
- - A better solution is to instead use the %predicate directive (unique - to SWIG's Ruby module) to designate certain methods as predicate methods. For - the previous example, this would look like: -
-%predicate is_it_safe();-
int is_it_safe();
and to use this method from your Ruby code:
-irb(main):001:0> Example::is_it_safe?-
true
- Note that the %predicate directive is implemented using SWIG's - "features" mechanism and so the same name matching rules used for other kinds - of features apply (see the chapter on "Customization - Features") for more details). -
-
@@ -1953,7 +2002,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
apply (see the chapter on "Customization
Features") for more details).
One of the most common issues in generating SWIG bindings for Ruby is proper
@@ -1972,7 +2021,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
versa) depending on what function or methods are invoked. Clearly, developing a
SWIG wrapper requires a thorough understanding of how the underlying library
manages memory.
Ruby uses a mark and sweep garbage collector. When the garbage collector runs,
@@ -1998,7 +2047,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
allocated in creating the underlying C struct or C++ struct, then a "free"
function must be defined that deallocates this memory.
As described above, memory management depends on clearly defining who is
@@ -2073,7 +2122,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
This code can be seen in swig/examples/ruby/tracking.
The remaining parts of this section will use the class library shown below to
@@ -2142,7 +2191,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
implement your own free functions (see below) you may also have to call theSWIG_RubyRemoveTracking
and RubyUnlinkObjects methods.
With a bit more testing, we see that our class library still has problems. For
@@ -2184,7 +2233,7 @@ $ ruby -e 'puts $:.join("\n")'
/usr/local/lib/ruby/site_ruby/1.6 /usr/
This code can be seen in swig/examples/ruby/mark_function.
-By default, SWIG creates a "free" function that is called when a Ruby object is