Hacking on ruby-duckdb

This document describes internal conventions for contributors working on the C extension in ext/duckdb/.


C Function Naming Rules

1. rb_define_method — static function name: classname_methodname

The C function must be named <classname>_<methodname>, where classname is the lowercase file name (without .c) and methodname is the Ruby method name.

rb_define_method(cDuckDBDatabase, "close", database_close, 0);             // OK
rb_define_method(cDuckDBDatabase, "close", duckdb_database_close, 0);      // NG — looks like DuckDB C API
rb_define_method(cDuckDBDatabase, "close", rbduckdb_database_close, 0);    // NG — rbduckdb_ is for externs only

2. rb_define_private_method — static function name: classname__methodname

The Ruby method name must start with _. The C function uses a double underscore naturally: classname + _ separator + _methodname.

rb_define_private_method(cDuckDBDatabase, "_connect", database__connect, 0);    // OK
rb_define_private_method(cDuckDBDatabase, "_connect", database_connect, 0);     // NG — single underscore
rb_define_private_method(cDuckDBDatabase, "_connect", rbduckdb_database_connect, 0); // NG
rb_define_private_method(cDuckDBDatabase, "connect",  database_connect, 0);     // NG — Ruby name must start with '_'

Note: private _initialize methods produce C function names like foo__initialize. The double underscore is intentional and consistent with this rule.

rb_define_private_method(cDuckDBFoo, "_initialize", foo__initialize, 2);  // OK — double underscore is intentional

3. rb_define_alloc_func — static function name: allocate

rb_define_alloc_func(cDuckDBDatabase, allocate);           // OK
rb_define_alloc_func(cDuckDBDatabase, database_allocate);  // NG

4. Memory release — static function name: deallocate

static void deallocate(void *ctx) { ... }    // OK
static void database_free(void *ctx) { ... } // NG

5. Memory size — static function name: memsize

static size_t memsize(const void *p) { ... }          // OK
static size_t database_memsize(const void *p) { ... } // NG

6. Other static functions

No fixed naming rule, but the name must be meaningful and must not clash with any DuckDB C API symbol. A verb_noun or classname_verb_noun pattern is recommended for non-registered internal helpers.

7. Method name character transformations

Special Ruby method name characters map to C identifiers as follows:

Ruby method C function suffix Example
finished? finished_p pending_result_finished_p
name= set_name scalar_function_set_name
method! method_bang (if needed)

Using set_ prefix for = setters avoids a naming conflict with a getter of the same base name (e.g., name getter → foo_name, name= setter →foo_set_name).

8. rb_define_singleton_method — static function name: classname_s_methodname

The s_ prefix distinguishes singleton (class) methods from instance methods.

rb_define_singleton_method(cDuckDBDatabase, "open", database_s_open, 1);  // OK

9. Public Ruby methods must not start with _

Public Ruby methods registered via rb_define_method must not have a _ prefix in their Ruby name. The _ prefix is reserved for the private-via-wrapper pattern. If a method is private, use rb_define_private_method with a _-prefixed name.

rb_define_method(cDuckDBFoo, "_internal_type", foo__internal_type, 0);          // NG — public method with _ prefix
rb_define_private_method(cDuckDBFoo, "_internal_type", foo__internal_type, 0);  // OK

10. rbduckdb_init_* function naming — no redundant duckdb_

Class-init extern functions must not include a redundant duckdb_ segment.

void rbduckdb_init_database(void);         // OK
void rbduckdb_init_duckdb_database(void);  // NG — redundant duckdb_

11. Extern functions — prefix: rbduckdb_

All functions with external linkage (declared in .h files, called from other .c files) must start with rbduckdb_.

rubyDuckDB *rbduckdb_get_struct_database(VALUE obj);   // OK
rubyDuckDB *duckdb_get_struct_database(VALUE obj);     // NG — looks like DuckDB C API
rubyDuckDB *get_struct_database(VALUE obj);            // NG — no namespace