1. The Jukebox Controller

The Ruby interpreter and most of its libraries are written in C. To facilitate this, the Ruby developers defined a set of functions and development practices for writing Ruby extensions in C.

In Chapter 21 of Programming Ruby, Dave Thomas described this extension process in detail. As an example, he used Ruby’s C-level interface to wrap a hypothetical library that controlled a CD jukebox.

For comparison, we’ll use the same example and see how we can talk to Dave’s jukebox controller using RubyCocoa.

Here’s the header file for the jukebox library. It’s the same code that you’ll find on the Pragmatic Programmers’ website. We’ll call it cdjukebox.h.

cdjukebox.h [C]
// Sample code from Programing Ruby, page 284
typedef struct _cdjb {
  int   statusf;
  int   request;
  void *data;
  char  pending;
  int   unit_id;
  void *stats;
} CDJukebox;

// Allocate a new CDJukebox structure
CDJukebox *new_jukebox(void);

// Assign the Jukebox to a player
void assign_jukebox(CDJukebox *jb, int unit_id);

// Deallocate when done (and take offline)
void free_jukebox(CDJukebox *jb);

// Seek to a disc, track and notify progress
void jukebox_seek(CDJukebox *jb, 
                  int disc, 
                  int track,
                  void (*done)(CDJukebox *jb, int percent));
// ... others...

// Report a statistic
double get_avg_seek_time(CDJukebox *jb);

To test our extension, we’ll need a dummy implementation of the library. Here’s one that I wrote for this guide.

cdjukebox.c [C]
#include <stdio.h>
#include <stdlib.h>
#include "cdjukebox.h"

// Allocate a new CDJukebox structure
CDJukebox *new_jukebox(void) {
    printf("allocating jukebox\n");
    CDJukebox *jukebox = (CDJukebox *) malloc (sizeof (CDJukebox));
    return jukebox;
}

// Assign the Jukebox to a player
void assign_jukebox(CDJukebox *jb, int unit_id) {
    printf("assigning jukebox to unit %d\n", unit_id);
    jb->unit_id = unit_id;
}

// Deallocate when done (and take offline)
void free_jukebox(CDJukebox *jb) {
    printf("disposing of jukebox with unit id %d\n", jb->unit_id);
    free(jb);
}

// Seek to a disc, track and notify progress
void jukebox_seek(CDJukebox *jb, 
                  int disc, 
                  int track,
                  void (*done)(CDJukebox *jb, int percent)) {
        printf("seeking disc %d and track %d for player %d\n", disc, track, jb->unit_id);
}

// ... others...

// Report a statistic
double get_avg_seek_time(CDJukebox *jb) {
    printf("getting seek time for unit %d\n", jb->unit_id);
    return 54.321;
}

Did you find an error? Is something missing? Post your comment or suggestion below!

Comments (0) post