0% found this document useful (0 votes)
41 views26 pages

SL Unit Ii

The document discusses extending the Ruby programming language by integrating C or C++ tools, enabling performance improvements and access to existing libraries. It explains Ruby's object representation in C, memory management, and the creation of Ruby C extensions, including global variables and memory allocation techniques. Additionally, it outlines the steps to create a C extension for Ruby, demonstrating how to implement a simple addition function.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views26 pages

SL Unit Ii

The document discusses extending the Ruby programming language by integrating C or C++ tools, enabling performance improvements and access to existing libraries. It explains Ruby's object representation in C, memory management, and the creation of Ruby C extensions, including global variables and memory allocation techniques. Additionally, it outlines the steps to create a C extension for Ruby, demonstrating how to implement a simple addition function.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

UNIT - II

Extending Ruby:
Extending Ruby means adding extra powers to the Ruby programming language by
bringing in tools or capabilities from other languages like C or C++. This lets
programmers use existing software written in those languages directly within their
Ruby programs. For example, if there's a really fast and powerful tool written in C that
you want to use in your Ruby program, you can "extend" Ruby to include that tool's
abilities.This enables developers to leverage existing libraries, access low-level system
functionality, or improve performance for certain tasks.
Ruby Objects in C

Everything you interact with, from numbers and strings to actions (methods), is treated
as an object. When you work with these objects in C extensions for Ruby, you need to
understand how they are represented and accessed.
Most Ruby objects reside in memory, managed by pointers of type VALUE in C. These
pointers act like addresses, pointing to the object's location in memory where its actual
data is stored (like the value of a number or the characters in a string).
There's a special case for simple values like integers (Fixnums), symbols, true/false,
and nil. These are stored directly within the VALUE variable itself, forgoing the need for
separate memory allocation. This makes accessing and manipulating them faster.
VALUE acts as a container type in the Ruby C API, able to hold either pointers (for most
objects) or immediate values (simple values). The Ruby interpreter utilizes the object's
memory address to distinguish between the two:

❖ If the lower bits of the VALUE variable are zero (due to memory
alignment), it indicates a pointer.
❖ If the lower bits are not zero, it signifies an immediate value stored within
the VALUE variable itself.

Each object, whether a regular object accessed through a pointer or an immediate


value stored directly, has its own structure. This structure holds essential information:

➔ Regular objects:
◆ They have a table of instance variables to store their specific data, like
the value of an integer or the characters in a string.
◆ They also have information about their class (type) attached to them.
This tells the interpreter what kind of object it is (e.g., String, Array, Hash)
and allows it to access the appropriate methods defined for that class.
➔ Immediate values:
◆ Their value is directly stored within the VALUE variable itself.
◆ Class information might be attached in a different way, depending on the
specific type of immediate value.

Working With Immediate Objects:

When you're working with Ruby's internal data structures, some values are stored
directly in a special way. These include small numbers (Fixnums), symbols, true, false,
and nil.

For Fixnums, instead of storing them as they are, Ruby shifts them left by one bit and
sets the rightmost bit (bit 0) to 1. This special bit pattern helps distinguish them from
other types of data. So, if a value is used as a pointer to a Ruby structure, it always has
its rightmost bit set to 0.

To check if a value is a Fixnum, you just need to check if its rightmost bit is set to 1.
Ruby provides a macro called FIXNUM_P to do this check easily. Similarly, there are
similar checks for other immediate values like symbols, nil, and checking if a value is
neither nil nor false.

In C, these other immediate values (true, false, and nil) are represented by the
constants Qtrue, Qfalse, and Qnil respectively. You can directly test Ruby values
against these constants, or use conversion macros which handle the necessary
typecasting for you.

Similar tests let you check for other immediate values.

FIXNUM_P(value) → nonzero if value is a Fixnum


SYMBOL_P(value) → nonzero if value is a Symbol
NIL_P(value) → nonzero if value is nil
RTEST(value) → nonzero if value is neither nil nor false.

Working with Strings:

In C programming, we often handle strings as sequences of characters terminated by a


null character ('\0'). However, Ruby's strings are more flexible and can contain null
characters within them. To safely work with Ruby strings in C code, Ruby provides a
structure called RString, which contains both the length of the string and a pointer to
where the string is stored in memory.

To access these properties of a Ruby string in C code, we use the RSTRING macro. For
example, RSTRING(str)->len gives us the length of the string, and RSTRING(str)->ptr
gives us a pointer to where the string is stored.
For example, if we want to iterate over all the characters in a string, we would call
StringValue on the original object to ensure it's a string, then access its length and
pointer through the RSTRING macro.

If we just need the pointer to the string's contents and don't care about the length, we
can use the convenience method StringValuePtr, which resolves the string reference
and returns the C pointer to the contents directly.

SafeStringValue method works similarly to StringValue, which converts an object into a


string. However, SafeStringValue does an additional security check. If the string it
receives is tainted (meaning it's from an untrusted source), and the current security
level is higher than zero (indicating a restricted environment), it will throw an exception
rather than converting the string.

Working with Other Objects:

In Ruby, values are the fundamental building blocks that hold different kinds of
information. Think of them as multi-purpose containers. Some VALUEs directly store
data, like simple numbers or short text strings. Others are more like signposts – they
point to a specific location where a larger, more complex Ruby object is stored.

Each type of Ruby object, like strings, arrays, or numbers, has a predefined structure
behind the scenes. These structures are written in the C programming language and
are detailed within a file called ruby.h. It's like having architectural plans for different
kinds of objects. Ruby provides special helper functions (called macros) that start with
"RClassname" which allow you to access and work with these internal structures.

You can check the underlying structure of a VALUE by using the TYPE(obj) macro. This
is like checking the type of container a value is stored in. The Check_Type macro helps
ensure you're working with the right kind of object. It's a safety measure that prevents
you from accidentally trying to manipulate the wrong kind of data.

Let's use an array as an example. If you have a VALUE that represents an array, you can
use the RARRAY(arr) macro to access the array's internal structure. This lets you see
things like the length of the array (how many items it holds), its capacity (how much
space is allocated), and even a pointer to where the array's data is actually stored.

Global Variables

● In most cases, your C extensions use classes and objects to share data with
Ruby code. This is the recommended approach for organized and safe data
exchange.
● However, there might be situations where you need a single, global variable
accessible to both sides.
● Create a VALUE (Ruby object): This is a container that can hold various data
types in Ruby.
○ In this example, hardware_list is a VALUE that initially stores an empty
array.
● Bind the VALUE's address to a Ruby variable name:
○ The rb_define_variable function associates the address of hardware_list
with the Ruby variable $hardware.
○ The $ prefix is optional but commonly used to indicate a global variable.
● Fill the array with data:
○ rb_ary_push adds elements like "DVD", "CDPlayer1", and "CDPlayer2" to
the array.

Accessing the Global Variable:


● Now, the Ruby code can access the hardware_list using $hardware as if it were
a regular Ruby array.
● The example shows how to retrieve the list:
$hardware # => ["DVD", "CDPlayer1", "CDPlayer2"]
Hooked and virtual variables are more advanced techniques in Ruby extensions written
in C that go beyond simple global variables. Here's a breakdown to help you
understand them better:
Regular Global Variables:
Imagine a bulletin board outside a classroom with a section for announcements.
Anyone can add or remove notices from there. This is similar to a regular global
variable:
Value: Stored directly, like a written notice on the board.
Access: Anyone (Ruby or C code) can read or modify the value.
Hooked Variables:
Think of a bulletin board where someone has written "Check the teacher's desk for
today's assignment." This message tells you where to look for the actual information,
not the information itself. A hooked variable works similarly:
Value: Not directly stored. Instead, it has a named function (called a "hook") that
calculates the value when accessed.
Access: When Ruby code tries to access the hooked variable, the hook function
is called to generate the value on the fly. C code can also call the hook function
directly.
Virtual Variables:
Imagine a virtual bulletin board that only exists in your mind. When you look for an
announcement, you automatically recall a specific piece of information. A virtual
variable functions like this:
✔ Value: Never stored anywhere. It has a hook function that calculates the value
every time it's accessed.
✔ Access: Similar to hooked variables, the hook function is called when the virtual
variable is accessed in Ruby code or C code.

Memory Allocation:
In Ruby, sometimes you need to allocate memory for special purposes, like big images
or lots of small data. Ruby's garbage collector helps manage memory, but when you're
doing it yourself, use special tools provided by Ruby. These tools make sure that if you
can't allocate memory, the garbage collector tries to free up space. They're more
advanced than basic memory allocation functions like malloc.
For instance, if ALLOC_N determines that it cannot allocate the desired amount of
memory, it will invoke the garbage collector to try to reclaim some space. It will raise a
NoMemError if it can’t or if the requested amount of memory is invalid.
API: Memory Allocation
1. type * ALLOC_N( c-type, n ): This function is used in Ruby extensions for
allocating memory.
c-type: This is the first argument, and it represents the data type of the objects
you want to allocate memory for. It should be the actual name of the C data type,
like int, float, or a custom structure you defined.
n: This is the second argument, and it represents the number of objects you
want to allocate memory for. It should be an integer expression that evaluates
to a positive number.
Example: For example, if you call ALLOC_N(int, 10), it will allocate memory for
10 integer objects. Since each int takes 4 bytes, the total memory allocated will
be 40
2.type * ALLOC(c-type): type * ALLOC(c-type) is another specific function used in
Ruby extensions for memory allocation, but unlike ALLOC_N, it only allocates
memory for one object.
❖ Similar to ALLOC_N, it interacts with the Ruby garbage collector to ensure
efficient memory management.
❖ If there's not enough memory available even after the garbage collector cleans
up, ALLOC will raise an error called NoMemError.
❖ Unlike standard malloc in C, the ALLOC function automatically casts the
allocated memory to a pointer of the same type (c-type *). This means it returns
the starting address of the allocated memory location, allowing you to directly
access and modify the object's data.
3. REALLOC_N( var, c-type, n ): This function is used in Ruby extensions for resizing
previously allocated memory.
❖ var: This is the first argument, and it's a pointer variable of type c-type*. It points
to the memory location that you want to resize.
❖ c-type: This is the second argument, and it represents the data type of the
objects stored in the memory pointed to by var.
❖ n: This is the third argument, and it represents the new number of objects you
want to fit in the resized memory.
❖ This function attempts to resize the memory block pointed to by var to
accommodate n objects of type c-type.
❖ It considers two possibilities:
➔ Increasing size: If n is larger than the current number of objects,
REALLOC_N tries to expand the memory to hold n objects.
➔ Decreasing size: If n is smaller than the current number of objects,
REALLOC_N tries to shrink the memory to fit n objects and potentially
free up unused space.

4.type * ALLOCA_N( c-type, n ):

ALLOCA_N allocates memory on the stack for n objects of type c-type.

ALLOCA_N is a macro that allocates memory on the stack for an array of a

specified type and size. This memory is automatically freed when the function

called ALLOCA_N returns. It's useful for quickly allocating memory for small to

moderate-sized arrays within a function without needing to manually free it later.

However, it's best suited for small data structures due to stack space limitations.

For larger memory needs or data persistence beyond a function's scope, heap

allocation is more appropriate.

Ruby Type System

Duck typing means that when writing code, you're more concerned with what an

object can do (its behavior) rather than what specific type or class it belongs to.

Example:

Duck typing in Ruby can be illustrated with a classic example involving animals.
Imagine we have a function called make_sound that expects an object to respond to
a method called sound. Instead of checking if the object is specifically a "Duck", we
simply check if it responds to the sound method. If it does, we treat it as if it were a
duck, regardless of its actual type. For instance:
class Duck
def sound
puts "Quack!"
end
end
class Dog
def sound
puts "Woof!"
end
end
def make_sound(animal)
animal.sound
end
duck = Duck.new
dog = Dog.new
make_sound(duck) # Output: Quack!
make_sound(dog) # Output: Woof!

Creating an Extension
1. Create the C source code file(s) in a given directory.
2. Optionally create any supporting Ruby files in a lib subdirectory.
3. Create extconf.rb.
4. Run extconf.rb to create a Makefile for the C files in this directory.
5. Run make.
6. Run make install.
Suppose we want to create a C extension for Ruby that provides a function to add
two numbers together. Here's how we would do it:
Create the C source code file(s):
➔ Create a dedicated directory for your extension to organize the related files.
➔ Inside this directory, create a C source file (e.g., my_extension.c) that will
contain the C code implementing your extension's functionality.

Let's create a file named addition.c in our directory with the following content:
#include "ruby.h"
VALUE method_add(VALUE self, VALUE num1, VALUE num2) {
int result = NUM2INT(num1) + NUM2INT(num2);
return INT2NUM(result);
}
void Init_addition() {
VALUE MyClass = rb_define_class("MyClass", rb_cObject);
rb_define_method(MyClass, "add", method_add, 2);
}
Create supporting Ruby files:

If your extension requires additional Ruby code to interact with the C functionalities
or define helper methods, you can create a subdirectory named lib within your main
directory.
Place any relevant Ruby files (e.g., modules, classes) in this lib subdirectory for
better organization.
We won't create any supporting Ruby files for this example.

Create extconf.rb:

Create a file named extconf.rb in the main directory.


This file acts as a configuration script, providing instructions for building the
extension and specifying necessary information like the extension name.
Create a file named extconf.rb in the same directory with the following content:

require 'mkmf'
create_makefile('addition')
Run extconf.rb:

Open your terminal and navigate to the directory containing your extension files.
Run the command ruby extconf.rb in the terminal. This command processes your
extconf.rb file and creates a Makefile that defines the build process for your
extension.
Open your terminal, navigate to the directory containing your files, and run ruby
extconf.rb. This will generate a Makefile for your C files.

Run make:

Once the Makefile is generated, execute the command make in the terminal. This
command uses the instructions in the Makefile to compile the C code and create the
extension library.
After extconf.rb has generated the Makefile, run make in your terminal. This will
compile your C code into a shared library.

Run make install:

Finally, run the command make install in the terminal. This command installs the
compiled extension library into your Ruby environment, making it available for use in
your Ruby programs.
Finally, run make install. This will install your Ruby C extension, making it available
for use in Ruby scripts.

After following these steps, you can use your C extension in Ruby scripts like this:
require 'addition'
obj = MyClass.new
puts obj.add(3, 5) #=> 8

This will create an instance of MyClass and call the add method, which is defined in
the C code, to add the two numbers.
API: Defining Classes:
1.rb_define_class():

Syntax: VALUE rb_define_class( char *name, VALUE superclass )

Defines a new class at the top level with the given name and super-
class (for class Object, use rb_cObject).

Example:

rb_define_class("MyClass", rb_cObject);

MyClass is defined with rb_define_class. It will have Object as its superclass since
rb_cObject represents the Object class.

2.rb_define_module():

Syntax: VALUE rb_define_module( char *name )

Defines a new module at the top level with the given name.

Example: VALUE MyModule = rb_define_module("MyModule");

3.rb_define_class_under():

Syntax: VALUE rb_define_class_under( VALUE under, char *name, VALUE superclass )

Defines a nested class under the class or module under.

Example: VALUE my_class = rb_define_class_under(my_module, "MyClass",


rb_cObject);

4.rb_define_module_under():

Syntax:

VALUE rb_define_module_under( VALUE under, char *name )

Defines a nested module under the class or module under.

Example: VALUE my_submodule = rb_define_module_under(my_module,


"MySubmodule");

5.rb_include_module():

Syntax:void rb_include_module( VALUE parent, VALUE module )

Includes the given module into the class or module parent.

➔ parent: A VALUE representing a class or module to include module into.


➔ module: A VALUE representing the module to be included.
Example:
// Include MyModule into MyClass
rb_include_module(MyClass, MyModule);
API: Defining Structures
1.rb_struct_define():
Syntax: VALUE rb_struct_define( char *name, char *attribute..., NULL )
Defines a new structure with the given attributes.
Example:
VALUE MyStruct;
void Init_MyStruct() {
MyStruct = rb_struct_define("MyStruct", "name", "age", "city", NULL);
}
2.rb_struct_new():
Syntax: VALUE rb_struct_new( VALUE sClass, VALUE args..., NULL )
This function, part of the Ruby C API, creates a new instance (object) of a previously
defined structure (struct) in Ruby.
Example:
void Init_MyStruct() {
MyStruct = rb_struct_define("MyStruct", "name", "age", "city", NULL);
}
VALUE name_value = rb_str_new2("Alice");
VALUE age_value = rb_fixnum_new(30);
VALUE city_value = rb_str_new2("New York");
VALUE instance = rb_struct_new(MyStruct, name_value, age_value, city_value, NULL);
3.rb_struct_aref():
Syntax:VALUE rb_struct_aref( VALUE struct, VALUE idx )
It is used to access a member variable within a previously created structure instance
(struct).
Example:
VALUE instance = rb_struct_new(MyStruct, name_value, age_value, city_value, NULL);
// Accessing member variables using rb_struct_aref
VALUE name = rb_struct_aref(instance, 0);
VALUE age = rb_struct_aref(instance, 1);
4.rb_struct_aset():
Syntax: VALUE rb_struct_aset( VALUE struct, VALUE idx, VALUE val )
This function allows you to modify the value of a member variable within a previously
created structure instance (struct) in Ruby C extensions.It essentially sets the value at
a specific index (position) within the structure instance.
Example:
void Modify_Member_Variable() {
VALUE name_value = rb_str_new2("Alice");
VALUE age_value = rb_fixnum_new(30);
VALUE city_value = rb_str_new2("New York");
VALUE instance = rb_struct_new(MyStruct, name_value, age_value, city_value, NULL);
// Modify the 'age' member variable (index 1) to 35
rb_struct_aset(instance, 1, rb_fixnum_new(35));
}

API: Defining Methods


The parameter argc in these function definitions stands for "argument count". It tells
you how many arguments a specific Ruby method can take.
Think of a Ruby method like a function that can be called to perform a task. Arguments
are like inputs you provide to the function to tell it what to do or what data to work with.

1. Fixed number of arguments:


0..17 VALUE func(VALUE self, VALUE arg...)
This function can take 0 to 17 arguments (inclusive).self refers to the object on
which the method is called.arg... represents a variable number of arguments,
similar to variadic functions in C. These arguments are typically accessed using
indexing or iteration techniques within the C function.
2. Variable number of arguments (C-style):
-1= VALUE func(int argc, VALUE *argv, VALUE self)
This function can accept any number of arguments (similar to ... in the previous
example).argc holds the actual number of arguments passed.argv is a C-style
array of VALUE pointers, pointing to the individual arguments passed.self still
refers to the object.This variation uses C-style memory access for the
arguments, requiring more careful handling in C code.
3. Variable number of arguments (Ruby-style):
-2 VALUE func(VALUE self, VALUE args)
This function can also accept any number of arguments.self functions as usual.
args is a Ruby array containing all the arguments passed.This variation provides
a more Ruby-like way to access arguments using array methods without direct
memory manipulation.
Differences:
0..17 VALUE func(VALUE self, VALUE arg...): Arguments are accessed using
indexing or iteration techniques within the C function.
-1 VALUE func(int argc, VALUE *argv, VALUE self): Arguments are accessed
using C-style array indexing on the argv pointer array. This requires careful
memory management.
-2 VALUE func(VALUE self, VALUE args): Arguments are accessed using Ruby
array methods on the args object. This is more convenient and safer than C-
style access.

1.rb_define_method():
Defines a new instance method for a class or module in Ruby. It allows you to
extend the functionality of existing classes or create custom methods for new
classes.

Syntax:
void rb_define_method( VALUE classmod, char *name, VALUE(*func)(), int argc )
❖ VALUE classmod: Represents the class or module where the method will be
defined.
❖ char *name: A null-terminated string containing the name of the method to be
defined.
❖ VALUE(*func)(): A pointer to a C function that will implement the logic of the
method. This function takes the following arguments:
❖ int argc: An integer specifying the expected number of arguments for the Ruby
method. This helps ensure type safety and prevents unexpected behavior if the
number of arguments passed doesn't match the method's definition.
2.rb_define_alloc_func():
Defines an allocation function for a Ruby class or module.
This function is responsible for creating new instances of that class/module
when a call like MyClass.new is made in Ruby code.
Syntax: void rb_define_alloc_func( VALUE classmod, VALUE(*func)() )
❖ VALUE classmod: Represents the Ruby class or module for which the allocation
function is being defined.
❖ VALUE(*func)(): A pointer to a C function that will be responsible for allocating
memory and initializing new instances of the class/module. This function:
➢ Takes no arguments.
➢ Returns a VALUE which represents the newly allocated Ruby object.

3.rb_define_module_function():
Defines a function that can be called directly on the module itself using the
module name and dot notation (e.g., ModuleName.function_name). These
functions are private and cannot be called on instances of the module.
Syntax:
void rb_define_module_function( VALUE module, char *name, VALUE(*func)(),
int argc) )
4.rb_define_global_function():
Defines a global function in Ruby, accessible from anywhere in your Ruby code
without the need for an object or module prefix.These functions are similar to
built-in Ruby functions like puts or print, but they are defined in your C extension.
Syntax: void rb_define_global_function( char *name, VALUE(*func)(),int argc )
char *name: A null-terminated string containing the desired name for the global
function.
VALUE(*func)(): A pointer to a C function that implements the logic of the global
function. This function:

○ Takes an arbitrary number of VALUE arguments, which represent the


arguments passed to the global function when called in Ruby.

int argc: An integer specifying the expected number of arguments for the global
function.
5.rb_define_singleton_method():
Singleton methods defined with rb_define_singleton_method are specific to the
individual class or module instance on which they are defined. They are not
inherited by subclasses or instances created later.
Syntax:
void rb_define_singleton_method( VALUE classmod, char *name,
VALUE(*func)(), int argc )

API: Defining Variables and Constants


1.rb_define_const()
Defines a constant within a specified class or module.
Constants are immutable values accessible throughout your Ruby code using
the class or module name followed by a double colon (::) and the constant name.
Syntax:
void rb_define_const( VALUE classmod, char *name, VALUE value )
2.rb_define_global_const()
Constants defined with rb_define_global_const are accessible from anywhere in
your Ruby code, potentially across different files and modules.
Syntax:
void rb_define_global_const( char *name, VALUE value )
3.rb_define_variable()
The function rb_define_variable serves the purpose of defining variables within a
specific scope.
his variable becomes accessible within the current scope, which can be:
Global scope: If called directly in the extension's initialization code.
Module scope: If called within a module or class definition.
Method scope: If called within a C function defined in the extension.
4.rb_define_class_variable()
This variable is accessible to all instances of the class and the class itself.
Defines a class variable name (which must be specified with a @@
prefix) in the given class, initialized to value.
Syntax:
void rb_define_class_variable( VALUE class, const char *name,VALUE val )
API: Calling Methods
1.rb_class_new_instance():
This function belongs to Ruby's C extension API and is used to create a new
instance (object) of a Ruby class.
Syntax:VALUE rb_class_new_instance( (int argc, VALUE *argv, VALUE klass) )
This function takes three arguments:
Number of arguments: This specifies how many arguments were passed to the
function when it was called.
Arguments: This is an array containing the actual arguments passed to the
function.
Class: This identifies the specific Ruby class for which a new instance needs to
be created.
API: Exceptions:
1.rb_raise():
rb_raise is a function in Ruby's C API used to explicitly raise an exception during
program execution.
syntax:
void rb_raise( VALUE exception, const char *fmt, ... )
exception: This is a VALUE object representing the class of the exception you
want to raise. Ruby provides built-in error classes like rb_eRuntimeError or
rb_eArgError. You can also use custom exception classes defined in your C
extension.
fmt: This is a null-terminated C string that specifies the error message. It can
use C-style formatting similar to printf.
...: This represents optional variable arguments that are used for formatting the
error message with fmt.
Example:
int result = do_something_complex();
if (result == -1) {
rb_raise(rb_eRuntimeError, "Failed to perform complex operation!");
}
2.rb_fatal():
rb_fatal is a function in Ruby's C API used for reporting critical errors that halt
the Ruby interpreter immediately.Unlike rb_raise which throws an exception,
rb_fatal terminates the Ruby interpreter immediately. No further code execution
happens after calling rb_fatal.There's no guarantee that any cleanup code will be
run after rb_fatal.
Syntax:
void rb_fatal( const char *fmt, ... )
Example:
void *ptr = malloc(1024 * 1024);
if (ptr == NULL) {
rb_fatal("Failed to allocate memory!");
}
In this example, if malloc fails to allocate memory, rb_fatal is called with an error
message, and the Ruby interpreter terminates immediately.
3.rb_sys_fail()
In Ruby's C API, rb_sys_fail is a function used to report critical errors that have
severe consequences for the system. It's designed for situations where
continued execution is not possible or would lead to a highly unstable state.
Use Cases:
★ Out-of-memory conditions when memory allocation fails critically.
★ File system errors where essential files cannot be accessed or modified.
★ System call failures that indicate a fundamental issue with the platform.
Syntax:
4.void rb_sys_fail( const char *msg )
Example:
FILE *fp = fopen("important_data.txt", "w");
if (fp == NULL) {
rb_sys_fail("Failed to open critical data file!");
}
In this example, if fopen fails to open a crucial file, rb_sys_fail is called,
indicating a system-level issue. The program might still technically continue
execution, but reliable operation is compromised.
5.rb_rescue():
rb_rescue helps you write code that can gracefully handle exceptions and
provide alternative behavior.
The rescue function provides a way to recover from errors or provide default
values.
Consider using rb_ensure if you need code to always be executed, regardless of
exceptions.

Syntax:
VALUE rb_rescue( VALUE (*body)(), VALUE args, VALUE(*rescue)(), VALUE rargs)
API: Iterators:
Iterator:Ruby iterators provide a way to process elements in collections like
arrays or hashes. You typically use iterator blocks with methods like each, map,
reduce, etc. These methods call the block you provide once for each element in
the collection.
1.rb_iter_break( )
Purpose of rb_iter_break
Within an iterator block, if a certain condition is met for an element, you might
want to stop iterating altogether, even though there are more elements
remaining. rb_iter_break helps achieve this by signaling an immediate exit from
the loop.
Syntax:
void rb_iter_break( )
2.rb_each()
In Ruby's C API, rb_each is a function designed to iterate over elements in an
enumerable object (like an array, hash, string, etc.). However, it's important to
note that rb_each isn't directly available in Ruby code. It's an internal function
primarily used for implementing core Ruby methods like each and other iterators.
Syntax:
VALUE rb_each( VALUE obj )
3.rb_yield():
rb_yield(VALUE arg) is an internal function within Ruby's C API. It's not
something you'd use directly in everyday Ruby programming.
Executes a block of code associated with a method call in Ruby, but from C
code.
Primarily for extending Ruby or creating C extensions that interact with blocks in
a very specific way.
VALUE arg is a Ruby value that can potentially be passed to the block, but not
always.
Focus on using yield within Ruby methods to work with blocks. rb_yield is for
specialized C-level interactions.

4.rb_iterate():
The rb_iterate function is a C function provided by the Ruby C API. It's used for
iterating over a block of Ruby code, calling a given method with specified
arguments and potentially a block.
Syntax:
VALUE rb_iterate( VALUE (*method)(),VALUE args,VALUE (*block)(),VALUE arg2 )

Example:
#include "ruby.h"
VALUE my_method(VALUE arg) {
// Do something with the argument
return Qnil; // In this example, we return nil
}
VALUE my_block(VALUE arg) {
// Do something with the block argument
return Qnil; // In this example, we return nil
}
int main() {
// Initialize Ruby VM
ruby_init();
// Define arguments
VALUE args = ...; // Define your arguments
VALUE arg2 = ...; // Define your additional argument
// Call rb_iterate
rb_iterate(my_method, args, my_block, arg2);
// Clean up Ruby VM
ruby_cleanup(0);
return 0;
}
5.rb_catch():
➔ Implements exception handling using a non-standard mechanism.
➔ Temporarily intercepts exceptions (denoted by throw) within a block of code.
➔ Executes the designated code and returns a value based on whether an
exception is thrown.
Syntax:
VALUE rb_catch( const char *tag, VALUE (*proc)(), VALUE value )
Example:
def my_proc(value)
if value < 0
throw "neg_val", "Encountered negative value"
else
value * 2
end
end
result = rb_catch("neg_val") do
my_proc(-5)
end
puts result
API: Accessing Variables

1.rb_iv_get():

In Ruby, rb_iv_get( VALUE obj, char *name ) is a function used to retrieve the
value of an instance variable associated with a specific object.
❖ obj (VALUE): The Ruby object from which you want to retrieve the instance
variable.
❖ name (char *name): A C-style string representing the name of the instance
variable (without the leading @ symbol).
Example:
class Person
def initialize(name, age)
@name = name # Instance variable assignment (using `@`)
@age = age
end
def get_name
rb_iv_get(self, "@name") # Accessing instance variable using rb_iv_get
end
end
person = Person.new("Alice", 30)
name = person.get_name
puts name # Output: "Alice"
2.rb_ivar_get():
The difference lies in how the instance variable name is specified:
❖ rb_iv_get() requires you to specify the name of the instance variable as a
separate argument.
❖ rb_ivar_get() doesn't require you to specify the instance variable name explicitly;
it assumes that you want to access the instance variable with the same name
as the variable you're assigning the result to in your C code.
Syntax:
VALUE value = rb_ivar_get(obj);
3.rb_iv_set():
In Ruby, rb_iv_set( VALUE obj, char *name, VALUE value ) is a C function used to
assign a value to an instance variable associated with a specific object.
❖ Set or modify the value of an instance variable within a C extension.
Example:
#include <ruby.h>

VALUE set_name(VALUE self, VALUE new_name) {


rb_iv_set(self, "@name", new_name); // Set instance variable using rb_iv_set
return self; // Return the object itself (optional)
}
4.rb_gv_set():
In Ruby, rb_gv_set( const char *name, VALUE value ) is a C function used to set
or modify the value of a global variable.
❖ Assign a value to a global variable within a C extension.
❖ Global variables are accessible from anywhere within the Ruby program.
Example:
#include <ruby.h>
void set_global_count(VALUE count) {
rb_gv_set("global_count", count); // Set global variable using rb_gv_set
}
5.rb_gv_get()
In Ruby, rb_gv_get( const char *name ) is a C function used to retrieve the value
of a global variable within a C extension.
❖ Access the value of a global variable from a C extension.

Embedding a Ruby Interpreter:


Embedding : This refers to including code from one programming language or
environment within another.
Embedding a Ruby interpreter in your application means you can run Ruby code from
within a program written in another language, like C or C++. This allows your program
to use Ruby for scripting or other tasks.
There are two ways to do this
Using ruby_run:
When you use ruby_run to embed Ruby, you hand over control of your application to the
Ruby interpreter. This method initializes the interpreter, runs the Ruby script, and
interpreter never returns from a ruby_run call.
Example:
#include <ruby.h>
int main(int argc, char **argv) {
ruby_init();
ruby_init_loadpath();
rb_eval_string("puts 'Hello from Ruby!'");
ruby_run();
printf("This will not be printed.\n"); // this code will not be executed
return 0;
}
The second method of embedding the Ruby interpreter allows your C code to call
specific Ruby methods and get control back after those methods are executed. This
approach enables a more interactive exchange between C and Ruby code.
How It Works
1. Initialize the Ruby Interpreter: Start the Ruby interpreter as usual.
2. Call Specific Ruby Methods: Use Ruby C API functions to call Ruby methods
from your C code.
3. Handle Exceptions: Use rb_protect to handle exceptions that may be raised by
the Ruby code. This ensures your C program doesn't terminate unexpectedly.
Example:
#include <ruby.h>
// Function to call a Ruby method safely using rb_protect
VALUE call_ruby_method(VALUE arg) {
return rb_funcall(arg, rb_intern("upcase"), 0);
}
int main(int argc, char **argv) {
ruby_init();
ruby_init_loadpath();
const char *ruby_code = "'hello from ruby'";
VALUE result;
int state;
VALUE ruby_string = rb_eval_string_protect(ruby_code, &state);
if (state) {
printf("Error in evaluating Ruby code.\n");
ruby_cleanup(0);
return 1;
}
result = rb_protect(call_ruby_method, ruby_string, &state);
if (state) {
printf("Error in calling Ruby method.\n");
} else {
printf("Result from Ruby: %s\n", StringValueCStr(result));
}
ruby_cleanup(0);
return 0;
}

Creating Jukebox Extension:


The "Jukebox extension" in Ruby is often used as an example to demonstrate how to
extend Ruby with C code. This involves creating a Ruby extension that interacts with
external libraries or hardware using the Ruby C API. Here's a brief overview of what this
extension typically entails:

Purpose of the Jukebox Extension


The Jukebox extension is designed to:
- Control jukebox hardware (e.g., playing MP3 files or audio CDs).
- Interface Ruby with a C library provided by the hardware vendor.
- Demonstrate how to write Ruby extensions in C for performance-critical tasks or
hardware interaction.

Key Steps in Creating the Extension


1. Define the Ruby Class in C:
- Use `rb_define_class` to create a Ruby class (e.g., `Jukebox`).
- Define methods for the class using `rb_define_method`.

2. Implement Methods in C:
- Write C functions that perform specific tasks, such as playing a song or stopping
playback.
- Use Ruby's C API to interact with Ruby objects and call C functions.

3. Compile the Extension:


- Use a `extconf.rb` file to generate a Makefile for compiling the C code into a Ruby
extension.

4. Load the Extension in Ruby:


- Use `require` to load the compiled extension and use it like a regular Ruby library.

Example
Here's a simple example of what the C code for the Jukebox extension might look like:

#include "ruby.h"
// Example method to play a song
static VALUE play_song(VALUE self, VALUE song_name)
{
printf("Playing song: %s\n", StringValueCStr(song_name));
return Qnil;
}
// Initialization function
void Init_jukebox()
{
VALUE cJukebox = rb_define_class("Jukebox", rb_cObject);
rb_define_method(cJukebox, "play_song", play_song, 1);
}

Usage in Ruby
After compiling the extension, you can use it in Ruby as follows:

require './jukebox'
jukebox = Jukebox.new
jukebox.play_song("My Favorite Song")

This is a simplified example, but the actual Jukebox extension would include more
complex functionality, such as interacting with hardware or managing playlists.

You might also like