Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating ruby C++ extension

Tags:

c++

ruby

I created a sample ruby extension using C++ class. it works fine when i did not parse the value. but when i parse parameter it show an error. here is my code.

C++ header file

  #ifndef CIRCLE_H_
  #define CIRCLE_H_

class Circle {
    public:
        Circle(float radius):_radius(radius) {}
        float getArea() { return 3.14159 * _radius * _radius; }

    private:
        float _radius;

};

CPP file.

  #include<ruby.h>
  #include"Circle.h"

  VALUE method_test(VALUE y){
   double x= NUM2DBL(y);
   Circle *cir= new Circle(x);
   return DBL2NUM(cir->getArea());
  }

  extern "C" void Init_Test(){
   VALUE lemon = rb_define_module("Test");
   rb_define_method(lemon, "test", (VALUE(*)(ANYARGS))method_test,1);
  }

extconf.rb

    require 'mkmf'
    have_library( 'stdc++' );
    $CFLAGS << " -Wall"
    create_makefile( 'Test' );

run.rb

    require 'rubygems'

    require 'Test'

    include Test

    puts test(7)

when i execute run.rb it shows an error.

          run.rb:7:in `test': can't convert Object into Integer (TypeError)
          from run.rb:7:in `<main>'

please help me to solve this problem. thank you.

like image 978
Kelum Deshapriya Avatar asked Oct 20 '22 19:10

Kelum Deshapriya


1 Answers

The line

VALUE method_test(VALUE y) {

Should be

VALUE method_test(VALUE self, VALUE y) {

The error message is thrown by NUM2INT(y) because y is the root Object of the script in your code as-is. The root object is what you got because you mixed in your module at the top level of the script. If you had mixed in to another class, you would have got an instance of that class instead.

All native extension methods should take a self parameter (the first one if you have fixed number of params) which is the context that they are being called in (a Module, Class or instance of a Class). It is how you get foo into the extension when you call foo.test. This might seem odd when both Ruby and C++ do this automatically (self in Ruby, and this in C++): However it is necessary to have self appear as param because the Ruby internal API is written in C, which does not support OO directly - instead the Ruby API defined in ruby.h expects you to write and use C functions that take references to the current object as one of the params.

In addition you are making a call to Circle( int radius ) - which does not exist (although the compiler may be kind and coerce x for you automatically). You probably want to use double variables throughout and use NUM2DBL(y) and DBL2NUM( cir->getArea() )

like image 193
Neil Slater Avatar answered Oct 30 '22 15:10

Neil Slater