Ruby examples added.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@853 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Masaki Fukushima 2000-09-18 13:26:04 +00:00
commit 5df7c82b59
42 changed files with 1804 additions and 7 deletions

View file

@ -0,0 +1,19 @@
TOP = ../..
SWIG = $(TOP)/../swig
CXXSRCS = example.cxx
TARGET = example
INTERFACE = example.i
LIBS = -lm
all::
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby_cpp
static::
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_cpp_static
clean::
rm -f *_wrap* *.o *~ *.so myruby .~* core
check: all

View file

@ -0,0 +1,28 @@
/* File : example.c */
#include "example.h"
#include <math.h>
/* Move the shape to a new location */
void Shape::move(double dx, double dy) {
x += dx;
y += dy;
}
int Shape::nshapes = 0;
double Circle::area() {
return M_PI*radius*radius;
}
double Circle::perimeter() {
return 2*M_PI*radius;
}
double Square::area() {
return width*width;
}
double Square::perimeter() {
return 4*width;
}

View file

@ -0,0 +1,39 @@
/* File : example.h */
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
};
double x, y;
void move(double dx, double dy);
virtual double area() = 0;
virtual double perimeter() = 0;
static int nshapes;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { };
virtual double area();
virtual double perimeter();
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { };
virtual double area();
virtual double perimeter();
};

View file

@ -0,0 +1,10 @@
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"

View file

@ -0,0 +1,221 @@
<html>
<head>
<title>SWIG:Examples:ruby:class</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/ruby/class/</tt>
<hr>
<H2>Wrapping a simple C++ class</H2>
<tt>$Header$</tt><br>
<p>
This example illustrates C++ class wrapping performed by SWIG.
C++ classes are simply transformed into Ruby classes that provide methods to
access class members.
<h2>The C++ Code</h2>
Suppose you have some C++ classes described by the following (and admittedly lame)
header file:
<blockquote>
<pre>
/* File : example.h */
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
};
double x, y;
void move(double dx, double dy);
virtual double area() = 0;
virtual double perimeter() = 0;
static int nshapes;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { };
virtual double area();
virtual double perimeter();
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { };
virtual double area();
virtual double perimeter();
};
</pre>
</blockquote>
<h2>The SWIG interface</h2>
A simple SWIG interface for this can be built by simply grabbing the header file
like this:
<blockquote>
<pre>
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"
</pre>
</blockquote>
Note: when creating a C++ extension, you must run SWIG with the <tt>-c++</tt> option like this:
<blockquote>
<pre>
% swig -c++ -ruby example.i
</pre>
</blockquote>
<h2>A sample Ruby script</h2>
Click <a href="runme.rb">here</a> to see a script that calls the C++ functions from Ruby.
<h2>Key points</h2>
<ul>
<li>To create a new object, you call a constructor like this:
<blockquote>
<pre>
c = Example::Circle.new(10)
</pre>
</blockquote>
<p>
<li>To access member data, a pair of accessor methods are used.
For example:
<blockquote>
<pre>
c.x = 15 # Set member data
x = c.x # Get member data
</pre>
</blockquote>
<p>
<li>To invoke a member function, you simply do this
<blockquote>
<pre>
print "The area is ", c.area, "\n"
</pre>
</blockquote>
<p>
<li>When a instance of Ruby level wrapper class is garbage collected by
Ruby interpreter, the corresponding C++ destructor is automatically invoked.
(Note: destructors are currently not inherited. This might change later.
Until then, use <tt>-make_default</tt>).
<p>
<li>Static member variables are wrapped as Ruby class accessor methods.
For example:
<blockquote>
<pre>
n = Shape.nshapes # Get a static data member
Shapes.nshapes = 13 # Set a static data member
</pre>
</blockquote>
</ul>
<h2>General Comments</h2>
<ul>
<li>Ruby module of SWIG differs from other language modules in wrapping C++
interfaces. They provides lower-level interfaces and optional higher-level
interfaces know as shadow classes. Ruby module needs no such redundancy
due to Ruby's sophisticated extension API.
<p>
<li>SWIG *does* know how to properly perform upcasting of objects in
an inheritance hierarchy except for multiple inheritance.
<p>
<li>A wide variety of C++ features are not currently supported by SWIG. Here is the
short and incomplete list:
<p>
<ul>
<li>Overloaded methods and functions. SWIG wrappers don't know how to resolve name
conflicts so you must give an alternative name to any overloaded method name using the
%name directive like this:
<blockquote>
<pre>
void foo(int a);
%name(foo2) void foo(double a, double b);
</pre>
</blockquote>
<p>
<li>Overloaded operators. Not supported at all. The only workaround for this is
to write a helper function. For example:
<blockquote>
<pre>
%inline %{
Vector *vector_add(Vector *a, Vector *b) {
... whatever ...
}
%}
</pre>
</blockquote>
<p>
<li>Namespaces. Not supported at all. Won't be supported until SWIG2.0 (if at all).
<p>
<li>Templates. Not supported at all. SWIG throws out anything that looks like a template.
You can work around the problem by aliasing a template class behind a typedef however.
For example:
<blockquote>
<pre>
%{
typedef vector<int> IntVector;
%}
class IntVector {
public:
... methods ...
};
</pre>
</blockquote>
</ul>
<p>
<li>There is no guarantee that an extremely complex C++ application will be able to compile
as a Ruby extension. Sorry.
<p>
<li>Dave's snide remark: Like a large bottle of strong Tequilla, it's better to
use C++ in moderation.
</ul>
<hr>
</body>
</html>

View file

@ -0,0 +1,49 @@
# file: runme.rb
# This file illustrates the C++ interface created by SWIG.
# All of our C++ classes get converted into Ruby classes.
require 'example'
# ----- Object creation -----
print "Creating some objects:\n"
c = Example::Circle.new(10)
print " Created circle #{c}\n"
s = Example::Square.new(10)
print " Created square #{s}\n"
# ----- Access a static member -----
print "\nA total of #{Example::Shape.nshapes} shapes were created\n"
# ----- Member data access -----
# Set the location of the object
# Notice how we can do this using functions specific to
# the 'Circle' class.
c.x = 20
c.y = 30
# Now use the same functions in the base class
s.x = -10
s.y = 5
print "\nHere is their current position:\n"
print " Circle = (", c.x, ",", c.y, ")\n"
print " Square = (", s.x, ",", s.y, ")\n"
# ----- Call some methods -----
print "\nHere are some properties of the shapes:\n"
for o in [c, s]
print " #{o}\n"
print " area = ", o.area, "\n"
print " perimeter = ", o.perimeter, "\n"
end
# Notice how the Shape#area() and Shape#perimeter() functions really
# invoke the appropriate virtual method on each object.
print "\n", Example::Shape.nshapes," shapes remain\n"
print "Goodbye\n"