0% found this document useful (0 votes)
31 views33 pages

SL Unit-II

Gujhhhhhjjkk

Uploaded by

Appidi Balreddy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views33 pages

SL Unit-II

Gujhhhhhjjkk

Uploaded by

Appidi Balreddy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 33

Unit-II

Extending Ruby: Ruby Objects in C, the Jukebox


extension, Memory allocation, Ruby Type
System, Embedding Ruby to Other Languages,
Embedding a Ruby Interpreter
Extending Ruby
how to use code written in C from Ruby
This can be used to optimize performance sensitive parts of
your code or to create an interface between a C library and Ruby
This is done by creating extensions that wrap libraries written
in C.
Here are the basic steps for creating a Ruby extension in C:
•Setting up the Extension Directory Structure:
Create a directory for your extension.
Inside this directory, create your C source file (e.g.,
my_extension.c) and an extconf.rb file.

•Writing the C Code:


Write your C code, which will define the functionality you want to
expose to Ruby. This typically includes defining new classes,
methods, or functions.
Include the necessary header files for Ruby's C API (ruby.h).
Implement initialization functions for your extension.
• Defining Extension Initialization Function:
– In your C code, define an initialization function
using the prefix Init_ followed by your extension
name. This function will be called when the
extension is loaded into Ruby.

• Configuring Compilation with extconf.rb:


– Write an extconf.rb file to configure the compilation
process.
– Use create_makefile method from mkmf module to
generate a Makefile for building your extension.
• Compiling the Extension:
– Run ruby extconf.rb to generate the Makefile.
– Run make to compile your C code into a shared library.

• Loading the Extension in Ruby:


– Once compiled, you can load your extension in a Ruby
script using require.
– Your extension will typically be loaded with a line like
require 'my_extension'.
How to Write a Ruby C Extension
• Create a file named extconf.rb with these contents:

require 'mkmf‘
create_header
create_makefile
'foobar'

ruby extconf.rb
which will create a few files for you (Makefile & extconf.h)
Now create foobar.c, this name comes from the create_makefile line in extconf.rb.
You can change it if you want but it has to match your .c filename for this to work.
foobar.c

#include "ruby.h"
#include "extconf.h"

void Init_foobar()
{
// Your C code goes here
}
This is the basic skeleton of your C extension.

• You can compile this by running make, and what you get is a .so file which
you can load into your Ruby application using require
Writing A Ruby Method From C
• You can create c functions that you can call from
your Ruby code
• All the Ruby methods have to return a VALUE.
A VALUE is a Ruby object.
• Example:
VALUE rb_return_nil() { return Qnil; }
Now we need to attach this function to a Ruby
class or module. You can create a new class or
use an existing one.
• Here I’m creating a module:
void Init_foobar() {
VALUE mod = rb_define_module("RubyGuides");
Rb_define_method(mod, “print_hello”,
rb_print_hello,0);
}
• You can use the rb_define_method method to
attach the C function to this module.
The arguments are:

ARGUMENT DESCRIPTION

mod Module object

“Print_hello” Name of the Ruby method

rb_print_hello Name of the C function

0 Number of arguments this


method takes, use -1 for variable
arguments
• Running Our Extension

Now run make again to compile the extension, and try it like
this:
require 'foobar’
include RubyGuides
print_hello
Ruby objects in C
• When working with Ruby objects in C, you'll interact with Ruby's C

API to manipulate and utilize Ruby objects from within your C code.

• The C API provides functions and macros for creating, accessing,

and manipulating Ruby objects.

• Here's a basic overview of how you can work with Ruby objects in

C:

• Including Ruby Headers: Begin by including the necessary Ruby

headers in your C source file using #include "ruby.h". This provides


access to the Ruby C API.
• Creating Ruby Objects: You can create Ruby objects in C using functions
provided by the Ruby C API, such as rb_str_new_cstr for creating a new
Ruby string.
• Accessing Ruby Objects: Once you have a reference to a Ruby object,
you can access its attributes and call its methods using C API functions
like rb_funcall.

• Converting Between Ruby and C Types: You'll often need to convert

between Ruby and C types when interacting with Ruby objects in C.

– Ruby provides functions for converting between different types,

such as NUM2INT and INT2NUM for converting between Ruby

numbers and C integers.


• Memory Management: When working with Ruby objects in C,

you need to manage memory properly to avoid memory leaks

and crashes.
– Ruby's garbage collector handles memory management for Ruby objects,

but you may need to manually manage memory for any C objects you

create.

• Error Handling: Error handling is important when working with

Ruby objects in C.
– Many C API functions return special values to indicate errors, so you need

to check return values and handle errors appropriately.


Working With Immediate Objects
• Immediate values are not pointers: Fixnum, Symbol, true, false,
and nil are stored directly in VALUE
• Fixnum values are stored as 31-bit numbers that are formed by
shifting the original number left 1 bit and then setting the LSB, or
least significant bit (bit 0), to 1

• Tests of immediate values can be done using macros:


– 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

• Other immediate values (true, false, and nil) are represented in C as the
constants Qtrue, Qfalse, and Qnil, respectively
Working with strings
• Ruby String objects are actually references to an
RString structure, and the RString structure contains
both a length and a pointer field.
• we can access the structure via the RSTRING macro.
– VALUE str;
– RSTRING(str)->len → length of the Ruby string
– RSTRING(str)->ptr → pointer to string storage

String Value
• The String Value method checks to see if its operand
is a String. If not, it tries to invoke to_str on the
object, throwing a Type Error exception if it can’t.
Working with other objects
• When VALUEs are not immediate, they are pointers to one of
the defined Ruby object structures
• The structures for the basic built-in classes are defined in ruby.h
and are named RClassname: RArray, RBignum, RClass, RData,
RFile, RFloat, RHash, RObject, RRegexp, RString, and RStruct.
• To check a particular VALUE use the macro TYPE(obj) will return
a constant representing the C type of the given object:
T_OBJECT, T_STRING, and so on
Example
VALUE obj;

switch (TYPE(obj))
{
case T_NIL:
/* handle NilClass */
break;
case T_FIXNUM:
/* handle Fixnum */
break;
case T_STRING:
/* handle String */
break;
/* ... */
}
Array Example:

RARRAY
VALUE arr;
RARRAY(arr)->len
RARRAY(arr)->capacity
RARRAY(arr)->ptr
Writing Ruby In C
Ruby program
class Test
def initialize
@arr = Array.new
end
def add(anObject)
@arr.push(anObject)
end
end
The equivalent code in C should look somewhat familiar.
#include "ruby.h"
static VALUE t_init(VALUE self)
{
VALUE arr;
arr = rb_ary_new();
rb_iv_set(self, "@arr", arr);
return self;
}
static VALUE t_add(VALUE self, VALUE anObject)
{
VALUE arr;
arr = rb_iv_get(self, "@arr");
rb_ary_push(arr, anObject);
return arr;
VALUE cTest;
void Init_Test()
{
cTest = rb_define_class("Test", rb_cObject);
rb_define_method(cTest, "initialize", t_init, 0);
rb_define_method(cTest, "add", t_add, 1);
}
Juke Box Extension
Juke Box Extension Example
// jukebox.c
#include <ruby.h>
#include <stdio.h>

// C function to play a song


void play_song(char *song_name) {
printf("Playing: %s\n", song_name);
// Code to play the song using your chosen audio library
}

// Ruby wrapper for the play_song function


static VALUE rb_play_song(VALUE self, VALUE rb_song_name) {
Check_Type(rb_song_name, T_STRING);
play_song(StringValueCStr(rb_song_name));
return Qnil;
}

// Initialize the extension


void Init_jukebox() {
VALUE mJukebox = rb_define_module("Jukebox");
rb_define_method(mJukebox, "play_song", rb_play_song, 1);
}
# main . rb
require _ relative 'jukebox'

module Jukebox
extend self
def self. play(song _ name)
Jukebox . play _ song(song _name)
end
end

Jukebox . play("My Song.mp3")


`
MEMORY ALLOCATION
• To work correctly with the garbage collector, you
should use the following memory allocation
routines.
• These routines do a little bit more work than the
standard malloc.
– type * ALLOC_N( c-type, n )
– type * ALLOC( c-type )
– REALLOC_N( var , c-type, n)
– type * ALLOCA_N( c-type, n )
type * ALLOC_N( c-type, n )
– Allocates n c-type objects, where c-type is
the literal name of the C type, not a variable of
that type.
– 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 No Mem Error if it can't or if the
requested amount of memory is invalid.
REALLOC_N( var, c-type, n)
– Reallocates n c-types and assigns the result to var,
a pointer to a variable of type c-type.
type * ALLOC( c-type )
– Allocates a c-type and casts the result to a pointer
of that type.
type * ALLOCA_N( c-type, n )
– Allocates memory for n objects of c-type on the
stack—this memory will be automatically freed
when the function that invokes ALLOCA_N returns.
Ruby Type System
• Ruby is known for its dynamic and flexible type system,
which differs from statically typed languages like Java
or C++.
– Dynamic Typing : variables don't have predefined types. The
type of a variable is determined at runtime based on the
value it holds.
– Duck Typing :
– Strong Typing
– Open Classes
– Type Coercion
– Nil
– Dynamic Dispatch
– Type Annotations
# Define a method that takes an argument and prints its type
def print_type(arg)
puts "The type of #{arg.inspect} is #{arg.class}"
end

# Example 1: Integer
print_type(42) # Output: The type of 42 is Integer

# Example 2: String
print_type("Hello, world!") # Output: The type of "Hello, world!" is String

# Example 3: Array
print_type([1, 2, 3]) # Output: The type of [1, 2, 3] is Array

# Example 4: Hash
print_type({name: "Alice", age: 30}) # Output: The type of {:name=>"Alice", :age=>30} is Hash

# Example 5: Custom Class


class Person
attr_accessor :name, :age
end

person = Person.new
person.name = "Bob"
person.age = 25

print_type(person)

# Output: The type of #<Person:0x00007f972c023ba8 @name="Bob", @age=25> is Person


In Example,
• We define a method print _ type that takes an argument arg and
prints its type using the class method.
• We demonstrate various types in Ruby:
– Integers (42)
– Strings ("Hello, world!")
– Arrays ([1, 2, 3])
– Hashes ({name: "Alice", age: 30})
– Custom class instances (Person. new)
• The print_ type method works with different types of arguments
without modification, showcasing Ruby's dynamic typing.
• Each time print _ type is called with a different type of
argument, it prints the type of the argument dynamically using
arg. class.

You might also like