💡 Extending Ruby with C
Extending Ruby means adding new features using C to make Ruby programs:
Run faster
Use less memory
Connect with system tools
Ruby is slow because it’s an interpreted language. Writing performance-critical parts in C can
significantly improve speed and efficiency.
🛠️Creating a Ruby C Extension (Step-by-Step with Example)
We’ll build a C extension that adds two numbers.
✅ Step 1: Create a New Directory
mkdir myext && cd myext
✅ Step 2: Write the C Extension Code
Create a file named myext.c:
#include <ruby.h>
// Function to add two numbers
VALUE add(VALUE self, VALUE num1, VALUE num2) {
int a = NUM2INT(num1); // Convert Ruby value to C integer
int b = NUM2INT(num2);
return INT2NUM(a + b); // Convert C integer back to Ruby value
}
// Initialize the extension
void Init_myext() {
VALUE MyExtension = rb_define_module("MyExtension");
rb_define_method(MyExtension, "add", RUBY_METHOD_FUNC(add), 2);
}
The function void Init_myext():
Defines a new Ruby module MyExtension.
Registers a method "add" in that module.
The add method maps to the C function add() and takes 2 Ruby arguments.
✅ Step 3: Create extconf.rb
This generates a Makefile to compile the extension:
require "mkmf"
create_makefile("myext")
✅ Step 4: Compile the Extension
ruby extconf.rb
make
➡️This generates myext.so (on Linux/macOS) or myext.dll (on Windows)
✅ Step 5: Test the Extension in Ruby
Create test.rb:
require "./myext"
include MyExtension
puts add(10, 20) # Output: 30
puts add(7, 5) # Output: 12
Run:
ruby test.rb
🖨️Output
30
12
🔷 Ruby Objects in C (Simplified Notes)
🔹 How Ruby Represents Data in C
In Ruby, everything is an object, and variables hold references to objects.
In C (inside the Ruby interpreter), all Ruby objects are represented using the type VALUE.
🔹 What Is VALUE?
VALUE is a C type used to represent any Ruby object.
Usually, it stores the address of the object in memory, not the actual object.
🔹 Exception: Immediate Objects
Some common values are stored directly inside the VALUE instead of using pointers, for speed
and memory efficiency.
These are called immediate values:
Fixnum (integers)
Symbol
true
false
nil
This avoids memory allocation and makes Ruby faster.
🔹 Checking Object Types with Macros
To identify the type stored in a VALUE, Ruby provides macros:
Macro Purpose
FIXNUM_P(val) Is the value a Fixnum?
SYMBOL_P(val) Is the value a Symbol?
NIL_P(val) Is the value nil?
RTEST(val) Is the value truthy? (not nil/false)
1. Converting Integers to Ruby Numbers
int num = 42; INT2NUM(num); // Converts int to Fixnum or Bignum
int num = 42; INT2FIX(num); // Converts int to Fixnum (faster)
(do the same for remaining data types)
int c_int = NUM2INT(INT2NUM(42));
printf("%d\n", c_int); // Output: 42
int c_fixnum = FIX2INT(INT2FIX(10));
printf("%d\n", c_fixnum); // Output: 10
Working with Ruby Strings in C
In C, strings are null-terminated, meaning they end with a special character '\0' to mark the
end of the string.
However, Ruby strings can contain null characters inside them, so C-style string handling
doesn’t work safely.
Ruby strings are stored in an RString structure, which includes:
RSTRING_LEN(str) → Gets the length of the Ruby string.
RSTRING_PTR(str) → Gets a pointer to the string’s data.
RSTRING_END(str) → Gets a pointer to the end of the string.
Working with Other Objects
Ruby objects in C have specific structures (e.g., RString, RArray). The following macros help
access these structures safely.
🎵 What Is the Jukebox Extension?
Imagine there's a C library from a company that controls a CD Jukebox.
You want to use that jukebox in Ruby, but Ruby can't understand C structures directly.
So we wrap the C structure (CDJukebox) inside a Ruby object using special tools Ruby gives us.
This is called creating a Ruby C extension.
🧱 What Are We Trying to Do?
We want to:
Wrap a C struct (CDJukebox *) in a Ruby object
Make it behave like a Ruby class
Let Ruby manage its memory safely
Support .new, .clone, etc.
🔧 Step-by-Step Breakdown
🔹 Step 1: Wrap C Structure as Ruby Object
Ruby gives us a macro:
Data_Wrap_Struct(klass, mark, free, pointer);
Example:
Data_Wrap_Struct(klass, 0, cd_free, jukebox);
What this does:
klass – the Ruby class (e.g., CDPlayer)
cd_free – function to clean up C memory when Ruby is done
jukebox – the C pointer we are wrapping
✅ It turns a C pointer into a Ruby object!
🔹 Step 2: Allocation Function
This function is called when you write CDPlayer.new in Ruby — before initialize is run.
static VALUE cd_alloc(VALUE klass) {
CDJukebox *jukebox = new_jukebox(); // C library call
return Data_Wrap_Struct(klass, 0, cd_free, jukebox);
}
✅ This creates the jukebox and wraps it as a Ruby object.
🔹 Step 3: Initialization Function
The initialize method is called after allocation to assign a unit ID to the jukebox.
Now Ruby calls initialize, and you can give values.
static VALUE cd_initialize(VALUE self, VALUE unit) {
CDJukebox *jb;
Data_Get_Struct(self, CDJukebox, jb); // Unwrap C pointer
assign_jukebox(jb, NUM2INT(unit)); // Set the ID
return self;
}
Data_Get_Struct gives you the original CDJukebox * from the Ruby object
assign_jukebox() sets its unit ID using the C library
🔹 Step 4: Garbage Collection (Free Memory)
When Ruby deletes the object, it must also clean the C memory.
static void cd_free(void *p) {
free_jukebox((CDJukebox *)p);
}
This is called automatically by Ruby when the object is garbage collected
It avoids memory leaks
🔹 Step 5: Support for .clone or .dup
If you write jukebox.clone, Ruby:
1. Allocates a new object
2. Copies variables
3. Calls initialize_copy
✅ This ensures cloned objects also get a proper copy of the jukebox struct.
Memory Allocation
When writing Ruby extensions in C, you might need to allocate memory manually, especially
for:
Large data structures (e.g., images, Bloom filters)
External C libraries
Don’t use malloc() directly!
Ruby has its own Garbage Collector (GC), and using regular C functions like malloc can
confuse it.
🧬 Ruby Type System
Ruby is both dynamically typed and duck-typed. This means Ruby doesn't care about an
object's type — only about whether it behaves the way we expect.
🔹 1. Dynamic Typing in Ruby
Ruby does not require type declarations. The type of a variable is decided at runtime, based
on the value you assign.
✅ Example: Dynamic Typing
x = 10 # Integer
x = "Hello" # Now it's a String
x = 3.14 # Now it's a Float
puts x # Output: 3.14
💬 Explanation:
xstarts as an integer, becomes a string, and then a float.
Ruby lets you reassign different types to the same variable.
🔸 2. Duck Typing
Duck typing is based on what an object can do, not what it is.
“If it looks like a duck, swims like a duck, and quacks like a duck — it’s probably a duck.”
This means: If an object has the methods you need, you can use it, regardless of its class.
✅ Example: Duck Typing
def display(duck)
duck.swim
duck.speak
end
class Duck
def swim
puts "can swim"
end
def speak
puts "Quack!"
end
end
class Person
def swim
puts "can swim"
end
def speak
puts "speaks"
end
end
d = Duck.new
p = Person.new
display(d)
display(p)
✅ Output:
can swim
Quack!
can swim
speaks
✅ Advantages of Duck Typing
Flexible: Any object with the required methods can be used.
Simple Code: No need to declare or check types.
Reusability: Same function works with different types of objects.
⚠️Disadvantages of Duck Typing
Runtime Errors: If a method is missing, error shows only while running.
Hard to Read: You can’t always tell what type of object is expected.
Maintenance Issues: In large codebases, it’s easy to lose track of required methods.
🔄 Embedding Ruby into Other Languages
Embedding Ruby means using the Ruby interpreter inside programs written in other languages
like C, C++, Java, Python, etc.
This allows these host programs to run Ruby code or scripts and use Ruby’s features within their
workflows.
🧬 Why Embed Ruby?
To add scripting support to your app
To allow customization using Ruby
To access Ruby's expressive syntax and dynamic features
To combine the power of compiled languages with Ruby's flexibility
🧩 Ruby’s Similarities with Other Languages
Ruby’s syntax and behavior are familiar to developers coming from other languages. Here's a
comparison:
🛠️C
Ruby has a close relationship with C (it's built in C!).
Similarities:
o Strings use double quotes: "Hello"
o Strings are mutable (can be modified)
o Embedding works easily via C functions like ruby_init(), rb_eval_string()
➕ C++
Ruby borrows object-oriented ideas from C++.
Similarities:
o Access control keywords: public, private, protected
o Exception handling is similar (but Ruby uses begin, rescue, ensure instead of
try, catch)
☕ Java
Java is fast, compiled, and has a rich ecosystem.
Switching from Java to Ruby:
o Code is shorter and quicker to write
o Prototypes can be built faster
Similarities:
o Automatic memory management via Garbage Collector
o Strongly typed objects
o Access modifiers (public, private, protected) behave similarly
🐪 Perl
Perl developers will feel at home with Ruby.
Similarities:
o Method calls don’t always need parentheses
o Strings are flexible and easy to manipulate
o Ruby has closures (blocks, procs, lambdas) — just like Perl
🐘 PHP
PHP is popular for web development; Ruby is too (thanks to Rails).
Ruby is considered cleaner and more structured.
Similarities:
o Both are dynamically typed — no need to declare variable types
o Used heavily in web apps
Ruby encourages a more elegant, framework-driven approach (e.g., Ruby on Rails)
🐍 Python
Python and Ruby are often compared for their simplicity and elegance.
Similarities:
o Multi-line strings are easy (e.g., triple quotes in Python, <<-HEREDOC in Ruby)
o Both are dynamically and strongly typed
Variables don’t need type declarations
But types are not automatically changed once assigned
o Both support functional programming:
Lambdas, closures, first-class functions
o Syntax is clean and readable
✅ Summary
Language Similarity with Ruby
C Mutable strings, double quotes, easy to embed
C++ Access control, exceptions
Language Similarity with Ruby
Java Garbage collection, OOP, faster prototyping in Ruby
Perl Optional parentheses, closures
PHP Dynamic typing, web development focus
Python Clean syntax, dynamic/strong typing, functional support
🔗 Embedding a Ruby Interpreter
Embedding Ruby means using the Ruby interpreter inside a C program.
This lets the C program run Ruby scripts, making the program more dynamic and scriptable.
📄 Ruby Script Example (add.rb)
# File: add.rb
a = 15
b = 25
sum = a + b
puts "Sum = #{sum}"
🛠️Steps to Embed Ruby in C
🔹 1. Include the Ruby Header
At the top of your C file:
#include <ruby.h>
🔹 2. Initialize the Ruby Interpreter
Before running any Ruby code:
ruby_init(); // Start the Ruby interpreter
ruby_init_loadpath(); // Set up Ruby's load path
🔹 3. Run Ruby Code
✅ Option 1: Run Ruby Code Inline
Use rb_eval_string() to run Ruby directly as a string:
rb_eval_string("puts 'Hello from Ruby!'");
rb_eval_string("puts 10 + 20");
✅ Option 2: Load a Ruby File
Use rb_load_file() and ruby_exec() to run a Ruby script file:
rb_load_file("add.rb"); // Load script
ruby_exec(); // Run script
🔹 4. Finalize the Interpreter
After running your Ruby code, shut the interpreter down cleanly:
ruby_finalize();
🧪 Example: C Program That Runs Ruby Script
#include <ruby.h>
int main() {
ruby_init();
ruby_init_loadpath();
rb_load_file("add.rb");
ruby_exec(); // Only needed in older Ruby versions
ruby_finalize();
return 0;
}
⚙️5. Compile and Run
Compile and run the program
✅ Output:
Sum = 40
🌍 Global Variables in Ruby (not a subtopic)
🔹 Definition:
A global variable is a variable that can be accessed and changed from anywhere in a Ruby
program — inside methods, classes, modules, or even outside them.
Global variables start with a $ (dollar sign).
👉 Examples: $count, $name, $total
🔑 Key Features
Feature Description
Scope Global — available throughout the entire program
Prefix Always starts with a $
Persistence Value remains until explicitly changed
Caution Can lead to bugs if overused or misused
⚠️Disadvantages of Global Variables
❌ Breaks encapsulation (everything can access/change it)
❌ Makes debugging harder (anyone can change the value)
❌ Reduces code readability and maintainability
❌ Best to avoid unless absolutely needed
✅ Simple Example
$greeting = "Hello"
def greet_user
puts $greeting + ", User!"
end
class Messenger
def change_greeting
$greeting = "Welcome"
end
end
greet_user # Output: Hello, User!
msg = Messenger.new
msg.change_greeting
greet_user # Output: Welcome, User!
🔗 Wrapping C Structures in Ruby (not a subtopic)
Wrapping C structures means turning a C struct into a Ruby object. This allows Ruby code
to access, store, and modify C-level data using Ruby-style objects.
🎯 Why Wrap C Structures?
✅ Improve performance (C is faster than Ruby)
✅ Reuse existing C libraries inside Ruby
✅ Expose custom data types to Ruby users
🧱 Main Functions Used for Wrapping
🔹 1. Data_Wrap_Struct
VALUE Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void
*ptr);
✅ What It Does:
Wraps a C pointer into a Ruby object.
Connects it with a Ruby class (klass).
Optionally registers:
o mark() – for Ruby GC (optional, use NULL if not needed).
o free() – called to clean up memory.
🔹 2. Data_Make_Struct
VALUE Data_Make_Struct(VALUE klass, c_type, mark, free, c_type *ptr);
✅ What It Does:
Shortcut for:
o ALLOC()
o memset()
o Data_Wrap_Struct()
Automatically allocates, zeroes, and wraps memory.
Also gives you direct access to the C pointer.
🔹 3. Data_Get_Struct
Data_Get_Struct(VALUE obj, c_type, c_type *ptr);
✅ What It Does:
Extracts the original C struct pointer from a Ruby object.
Lets you access and modify the struct inside the Ruby object.
🧱 Object Creation in Ruby (not a subtopic)
An object is an instance of a class. In Ruby, we create objects using the .new method.
✅ Syntax
object_name = ClassName.new
🐶 Example: Defining a Class and Creating an Object
class Dog
def initialize(name, breed)
@name = name
@breed = breed
end
def speak
puts "#{@name} says woof!"
end
def info
puts "Name: #{@name}, Breed: #{@breed}"
end
end
my_dog = Dog.new("Buddy", "Golden Retriever")
my_dog.speak # Output: Buddy says woof!
my_dog.info # Output: Name: Buddy, Breed: Golden Retriever
🔁 Cloning Objects in Ruby (not a subtopic)
Cloning creates a copy of an existing object. Ruby provides two methods:
1️⃣ dup
Creates a shallow copy of the object.
Does not copy:
o Singleton methods
o Frozen/tainted state (in older Ruby versions)
Keeps the object's class and instance variables.
2️⃣ clone
Also creates a shallow copy
Does copy:
o Singleton methods
o Frozen and tainted state
More complete than dup