How do I create a Date object in a Ruby C extension?

437 views Asked by At

I'm trying to do something like this but I'm having trouble understanding how to use Ruby internals in my C code.

static VALUE func_get_date_object(VALUE self, VALUE vdate){
VALUE rb_date;
VALUE date;
rb_date = rb_funcall(rb_intern("Date"), rb_intern("new"), 0);;
date = rb_funcall(rb_date, rb_intern("parse"), 0);
return date;
}

What I want to do is pass in the vdate as a string like you would for Date.parse('yyyy-mm-dd')

But first I think that I need to know how to create or instantiate a new Date class object in C for Ruby. How may I do this please?

I have a test written for that code that does this.

def test_date
  assert_equal('', @t.date(@t_date_str))
end

Output is

NoMethodError: undefined method `new' for 18709:Fixnum
2

There are 2 answers

4
matt On

rb_intern returns the internal ID for the name "Date". What you want is the actual class associated with this name, and you can get that with rb_const_get:

VALUE cDate = rb_const_get(rb_cObject, rb_intern("Date"));

You can then use this with rb_funcall to create a new instance of the Date class:

rb_date = rb_funcall(cDate, rb_intern("new"), 0);

Since it looks like you actually want to call the Date.parse class method, what you probably want to do is call parse directly on the class:

VALUE parsed = rb_funcall(cDate, rb_intern("parse"), 1, rb_str_new_cstr("2017-1-9"));
0
Douglas G. Allen On

Yes thanks to Matt I now have:

/*
* call-seq:
*  date('yyyy-mm-dd')
*
* convert input string to Date object.
*
*/
static VALUE func_get_date(VALUE self, VALUE vdate){
  VALUE cDate = rb_const_get(rb_cObject, rb_intern("Date"));
  VALUE parsed = rb_funcall(cDate, rb_intern("parse"), 1, vdate);
  return parsed;
}

And the test is:

class TestCalcSun300 < Test::Unit::TestCase # MiniTest::Test
  def setup
    @t = CalcSun.new
    @t_date_str = '2000-01-01'
    @t_date = Date.parse('2000-01-01')
  end

  def test_date
    assert_equal(@t_date, @t.date(@t_date_str))
  end
end

Works great as long as I require 'date' in my Ruby code. But without that I do not have any Date class initialized. :-( Oh well, I'm learning.

This is for a Ruby gem that is still in development but I'll share it in case someone wants to play around with it. The original gem is good but it does not have all the latest features. The name is the same on rubygems.org

calc_sun