How to call a ruby extension method when using ruby built in classes

194 views Asked by At

To follow up a question I asked already and kind of solved as far as I got the answer to my question despite the fact a new problem was borne from the solved one which is this:

The problem in using the Complex API is that it doesn't recognise the shape method from the NMatrix API:

So when I run the following spec code on my compiled C extension:

  it "Creates a new FFTW.r2c object and takes an a 1D NMatrix as its argument" do
    n = NMatrix.new([4], [3.10, 1.73, 1.04, 2.83])

    r = FFTW.Z(n)
    i = FFTW.Z(FFTW.r2c_one(r))
    #expect(fftw).to eq(fftw)
  end

There is an error because shape belongs to the nmatrix class.

 FFTW Creates a new FFTW.r2c object and takes an a 1D NMatrix as its argument
     Failure/Error: i = FFTW.Z(FFTW.r2c_one(r))
     NoMethodError:
       undefined method `shape' for NMatrix:Class
     # ./spec/fftw_spec.rb:26:in `r2c_one'
     # ./spec/fftw_spec.rb:26:in `block (2 levels) in <top (required)>'

Shape is called from the nmatrix class so I can understand why this has happened but not figure out how to get round it.

The result of

  it "Creates a new FFTW.r2c object and takes an a 1D NMatrix as its argument" do
    n = NMatrix.new([4], [3.10, 1.73, 1.04, 2.83])

    fftw = FFTW.Z(n)
    expect(fftw).to eq(fftw)
  end

is

/home/magpie/.rvm/rubies/ruby-2.1.2/bin/ruby -I/home/magpie/.rvm/gems/ruby-2.1.2/gems/rspec-core-3.0.4/lib:/home/magpie/.rvm/gems/ruby-2.1.2/gems/rspec-support-3.0.4/lib -S /home/magpie/.rvm/gems/ruby-2.1.2/gems/rspec-core-3.0.4/exe/rspec ./spec/fftw_spec.rb
./lib/fftw/fftw.so found!

FFTW
  creates an NMatrix object
  Fills dense with individual assignments
  Creates a new FFTW.r2c object and takes an a 1D NMatrix as its argument

Finished in 0.00091 seconds (files took 0.07199 seconds to load)
3 examples, 0 failures
1

There are 1 answers

3
acsmith On

I think the issue is this chunk of code in fftw.cpp

lines 51-56:

static VALUE
fftw_shape(VALUE self)
{
  // shape is a ruby array, e.g. [2, 2] for a 2x2 matrix
  return rb_funcall(cNMatrix, rb_intern("shape"), 0);
}

You're trying to call shape on the NMatrix class here. rb_funcall works like this:

rb_funcall(object_to_invoke_method, method_to_invoke, number_of_args, ...)

The problem is that you have cNMatrix in the first argument position, so it's trying to send the shape method to the NMatrix class rather than to the object. So you really want to be calling it on the nmatrix object like:

static VALUE
fftw_shape(VALUE self, VALUE nmatrix)
{
  // shape is a ruby array, e.g. [2, 2] for a 2x2 matrix
  return rb_funcall(nmatrix, rb_intern("shape"), 0);
}

and on line 82:

VALUE shape = fftw_shape(self, nmatrix);

Does that help? I think that the only issue is that you're calling shape on the class, but something else might crop up.