|
|||
Forrige < |
Innhold ^
|
Neste >
|
README.EXT
filen som følger med distribusjonen.
Dersom du planlegger å skrive en utvidelse til Ruby, bør du nok referere
til den filen for ytterlige detaljer i tillegg til de siste endringene.
]
VALUE
,
som enten er en peker til et Ruby objekt eller en umiddelbar verdi (slik som Fixnum
).
Det er slik Ruby implementerer objekt-orientert kode i C. Et Ruby-objekt er
en allokert struktur i minnet som inneholder en tabell over instansvariabler
og informasjon om klassen. Klassen er i seg selv et annet
objekt (en allokert struktur i minnet) som inneholder en tabell med
metodene definert for den klassen. Dette er fundamentet til alt i Ruby.
VALUE
er en peker, peker den på en av de definerte objekt
strukturene i Ruby---du kan ikke ha en VALUE
som peker til en
vilkårlig struktur. Strukturen til de innebygde klassene er definert i
``ruby.h
'' og har navn på formen R
Klassenavn,
slik som RString
og
RArray
.
Det finnes flere måter å sjekke hva slags type struktur en VALUE
peker til. Makroen TYPE(
obj
)
returnerer en konstant som representerer C typen av det gitte objekt:
T_OBJECT
, T_STRING
og så videre.
Konstantene for de innebygde klassene er definert i ``ruby.h
''.
Legg merke til at type her referer til en
implementasjonsdetalj---det er ikke det samme som klassen til et objekt.
Dersom du ønsker å være sikker på at en verdipeker (VALUE
peker)
inneholder en bestemt struktur, kan du bruke makroen
Check_Type
, som vil heve et
TypeError
unntak dersom value
ikke er av den forventede type (som er en av konstantene
T_STRING
, T_FLOAT
og så videre):
Check_Type(VALUE value, int type)Dersom hurtighet er viktig, finnes det raskere makroer som spesifikt sjekker for de umiddelbare verdiene
Fixnum
og nil
.
FIXNUM_P(value) -> ulik null hvis value er en Fixnum NIL_P(value) -> ulik null hvis value er nil RTEST(value) -> ulik null hvis value er hverken nil eller falseLegg nok en gang merke til at vi snaker om ``type'' som den C strukturen som representerer en spesifikk innebygd type. Klassen til et objekt er et helt annet beist. Klasseobjektene til de innebygde klassene er lagres i globale C variabler med navn på formen
rb_c
Klassenavn
(for eksempel rb_cObject
); moduler benevnes
rb_m
Modulnavn.
Det er ikke å anbefale å rote med data som finnes i disse strukturene direkte. Men, du kan se, men ikke røre, med mindre du er glad i avlusingsverktøy. Til vanlig bør du bare bruke de medfølgende C funksjonene for å manipulere Ruby data (vi kommer nærmere inn på dette om et øyeblikk).
Men i søken etter effektivitet kan du ha behov for å grave frem data fra disse
strukturene. For å kunne derefere medlemsvariablene i
disse C strukturene, må du omstøpe den generiske VALUE
til den
faktiske strukturtypen. I ruby.h
finner du mange makroer som gjør
denne omstøpingen for deg, slik at det er lettere å få tilgang til
medlemsvariable i strukturene. Disse makroene har navn på formen
RKLASSENAVN
, som i
RSTRING
eller RARRAY
.
For eksempel:
VALUE str, arr; RSTRING(str)->len -> lengden til Ruby strengen RSTRING(str)->ptr -> peker til hvor strengen lagres RARRAY(arr)->len -> lengden til tabellen RARRAY(arr)->capa -> kapasiteten til tabellen RARRAY(arr)->ptr -> peker til hvor tabellen lagres
Fixnum
, Symbol
, true
, false
,
og nil
er lagret direkte i VALUE
.
Fixnum
verdier lagres som 31-bit heltall[Eller 63-bit på
CPU arkitekter med bredere ordlengde.] som formes ved å bitvis
flytte det opprinnelige tallet 1 bit til venstre og deretter sette den
minst signifikante biten
(bit 0, kjent som LSB, som står for Least Significant Bit) til ``1''.
Når VALUE
brukes som en peker til en spesifikk Ruby struktur, er
den garantert å alltid ha en LSB som er null;
de andre umiddelbare verdiene har også null i LSB. Dermed kan en enkel
bit-test fortelle deg om du har en Fixnum
eller ikke.
Det finnes flere nyttige konverteringsmakroer for tall, så vel som andre standard datatyper, vist i tabell 17.1 på side 174(??).
De andre umiddelbare verdiene (true
, false
og nil
)
er representert i C som konstantene Qtrue
, Qfalse
og
Qnil
. Du kan sjekke VALUE
variabler opp mot disse
konstantene direkte, eller bruke konverteringsmakroene (som gjør den passende omstøpingen).
class Test def initialize @arr = Array.new end def add(anObject) @arr.push(anObject) end end |
#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); } |
ruby.h
'' for å få med oss
de nødvendige definisjonene.
Ta nå en titt på den siste funksjonen, Init_Test
.
Hver klasse eller modul definerer en global C funksjon med et navn på formen
Init_
Navn. Denne funksjonen vil bli kalt når fortolkeren
først laster inn utvidelsen Navn (eller på oppstart for statisk
lenkede utvidelser). Dette gjøres for å initialisere utvidelsen og innføre
den i Ruby sine omgivelser.
I dette tilfellet definerer vi en ny klasse kalt Test
,
som er en subklasse av Object
(representert av det eksterne symbolet
rb_cObject
; se i ``ruby.h
'' for flere).
Deretter setter vi opp to instansmetoder, add
og initialize
,
i klassen Test
. Kallene til rb_define_method
etablerer
en kobling mellom Ruby metodenavnet og C funksjonen som vil implementere den,
slik at et kall til add
metoden i Ruby vil kalle C funksjonen
t_add
med et argument.
Tilsvarende, når new
blir kalt på denne klassen, vil Ruby først
konstruere et enkelt objekt og deretter kalle initialize
, som
vi har definert her til å kalle C funksjonen t_init
uten
(Ruby) argumenter.
Flytt øynene tilbake på definisjonen til initialize
.
Selv om vi sa at den ikke skal ta noen argumenter, er det en parameter her!
I tillegg til eventuelle Ruby argumenter blir hver metodekall gitt et
første VALUE
argument som inneholder mottakeren til metodekallet (det vil si det tilsvarende til self
i Ruby kode).
Det første vi gjør i initialize
er å lage en Ruby tabell og setter
instansvariabelen @arr
til å peke på den. Akkurat som du forventet
når man skriver Ruby kode, blir instansvariabelen lagd når den referes til, dersom den ikke allerede eksisterer.
Dernest får t_add
funksjonen tak i instansvariabelen @arr
fra det nåværende objektet og kaller
Array#push
for å dytte den angitte parameteren inn i tabellen.
Når man tar tak i instansvariabler på denne måten, er
@
-prefikset obligatorisk---hvis ikke blir variabelen laget, men kan ikke refereres til i fra Ruby.
Til tross for all den kjeitete syntaksen som C påtvinger, så skriver du
fremdeles i Ruby---du kan manipulere objekter ved hjelp av alle de
metodekallene du har lært å kjenne og å elske, kombinert med den fordelen
at du kan skrive stram og kjapp kode ved behov.
ADVARSEL: Enhver C funksjon som kan kalles fra Ruby må
returnere en VALUE
, selv om det bare er Qnil
.
Dersom du glemmer dette, vil en core dump (eller en GPF) være en
sannsynlig konsekvens.
Vi kan bruke C versjonen av koden i Ruby ganske enkelt ved å kalle require
for å laste den inn dynamisk ved kjøretid (på de fleste plattformer).
require "code/ext/Test" t = Test.new t.add("Bill Chase") |
C/Ruby datatype konverteringsfunksjoner og -makroer
|
eval
. Anta at du har en samling
av objekter som trenger å få et flagg fjernet.
rb_eval_string("anObject.each{|x| x.clearFlag }"); |
eval
på en fullstendig streng) kan du bruke
rb_funcall(receiver, method_id, argc, ...) |
VALUE hardware_list; hardware_list = rb_ary_new(); rb_define_variable("$hardware", &hardware_list); ... rb_ary_push(hardware_list, rb_str_new2("DVD")); rb_ary_push(hardware_list, rb_str_new2("CDPlayer1")); rb_ary_push(hardware_list, rb_str_new2("CDPlayer2")); |
hardware_list
som
$hardware
:
$hardware
|
» |
["DVD", "CDPlayer1", "CDPlayer2"]
|
VALUE obj; obj = rb_ary_new(); rb_global_variable(obj); |
typedef struct _cdjb { int statusf; int request; void *data; char pending; int unit_id; void *stats; } CDJukebox; // Allocate a new CDPlayer structure and bring it online CDJukebox *CDPlayerNew(int unit_id); // Deallocate when done (and take offline) void CDPlayerDispose(CDJukebox *rec); // Seek to a disc, track and notify progress void CDPlayerSeek(CDJukebox *rec, int disc, int track, void (*done)(CDJukebox *rec, int percent)); // ... others... // Report a statistic double CDPlayerAvgSeekTime(CDJukebox *rec); |
CDJukeBox
strukturen betyr, men det
gjør ikke noe---vi kan bare behandle det som vilkårlig haug med bits. Leverandørens
kode vet hva som skal gjøres med dem, vi må bare drasse rundt på dem.
De gangene du har en ren C struktur som du ønsker å håndtere som et
Ruby objekt, bør du pakke den inn i en spesiell, intern Ruby-klasse som heter
DATA
(av typen T_DATA
).
Det finnes to makroer for å gjøre denne innpakkingen, samt en for å
hente strukturen din ut igjen.
Innpakking av C datatyper | |
---|---|
VALUE | Data_Wrap_Struct(VALUE class, void (*mark)(), void (*free)(), void *ptr") |
Pakker den gitte C datatypen ptr, registrerer de
to søppeltømmingsrutinene (se under), og returnerer en VALUE peker til et faktisk
Ruby-objekt. C typen til det resulterende objektet er T_DATA
og dens Ruby-klasse er class.
|
|
VALUE | Data_Make_Struct(VALUE class, c-type, void (*mark)(), void (*free)(), c-type *") |
Allokerer en struktur med den gitte typen først, deretter fortsetter på samme måte som
Data_Wrap_Struct . c-type er navnet på C datatypen du pakker inn,
ikke en variabel av den typen.
|
|
Data_Get_Struct(VALUE obj,c-type,c-type *") | |
Returnerer den opprinnelige pekeren. Denne makroen er en typesikker (type-safe)
innekapsling rundt makroen DATA_PTR(obj) , som finner selve verdien til pekeren.
|
Data_Wrap_Struct
lager er et vanlig Ruby-objekt,
med det en ekstra C datatype som man ikke får tak i fra Ruby.
Som du kan se i figur 17.1 på side 177(??), er denne C datatypen separat fra
alle instansvariablene til objektet.
Men siden den er en separat ting, hvordan blir vi kvitt den når
søppeltømmeren kommer og tar dette objektet? Hva hvis du må gi slipp
på en eller annen ressurs (lukke en fil, gi fra deg en lås, rydde opp i en IPC mekanisme osv)?
Figur 17.1: Pakker objekter rundt C datatyper |
void
-peker som referer til din struktur.
Rutinen mark kalles av søppeltømmeren under ``markeringsfasen''.
Dersom din struktur referer til andre Ruby objekter, må din mark funksjon
identifisere disse objektene ved å bruke
rb_gc_mark(value)
.
Hvis strukturen ikke referer til andre Ruby objekter, kan du ganske enkelt
gi inn 0
som funksjonspeker.
Når objektet behøver å fjernes, vil søppeltømmeren kalle free
rutinen. Hvis du har allokert noe minne på egenhånd (for eksempel ved hjelp
av Data_Make_Struct
), må du angi en free-funksjon---selv om
det bare er det vanlige C bibliotekets free
rutine.
For kompliserte strukturer du har allokert, kan free-funksjonen din ha
behov for å traversere structuren for å frigi alt allokert minne.
Først ser vi på et enkelt eksempel uten noe spesiell håndtering.
Gitt strukturdefinisjonen
typedef struct mp3info { char *title; char *artist; int genre; } MP3Info; |
MP3Info
struktur har et par char
pekere i seg. I vår kode
initialiserer vi dem fra to statiske strenger. Det betyr at vi
slipper å figi disse sammen med MP3Info
strukturen.
Dersom vi hadde allokert disse strengene dynamisk, måtte vi
ha skrevet en free-funksjon for å fjerne dem.
]
MP3Info *p; VALUE info; p = ALLOC(MP3Info); p->artist = "Maynard Ferguson"; p->title = "Chameleon"; ... info = Data_Wrap_Struct(cTest, 0, free, p); |
info
er av typen VALUE
, et faktisk Ruby objekt
av klassen Test
(representert i C ved den innebygde typen
T_DATA
). Du kan dytte den inn i en tabell, ha en referanse til
det i et annet objekt og så videre.
På et senere punkt i koden, kan vi ønske å hente ut denne strukturen
igjen utifra VALUE
verdien:
VALUE doit(VALUE info) { MP3Info *p; Data_Get_Struct(info, MP3Info, p); ... p->artist -> "Maynard Ferguson" p->title -> "Chameleon" ... } |
initialize
metode og en
``C-konstruktør.''
Hvis du skrev Ruby kode, ville du allokert og initisialisert et objekt
ved å kalle new
.
I C utvidelser er det tilsvarende kallet Data_Make_Struct
.
Men, selv om dette allokerer minne til objektet, kaller det
ikke en initialize
metode. Det må du gjøre selv:
info = Data_Make_Struct(cTest, MP3Info, 0, free, one); rb_obj_call_init(info, argc, argv); |
initialize
metoden i
klassen din. Fra innsiden av initialize
har du lov
(men det er ikke nødvendigvis å anbefale) å endre den eksisterende
datapekeren, som kan aksesseres direkte med DATA_PTR(obj)
.
Og til sist ønsker du kanskje å definere en ``C-konstruktør''---det
vil si, en globalt tilgjengelig C funksjon som lager objektet i
et enkelt kall. Du kan bruke denne funksjonen i din egen kode eller
tillate andre utvidelsesbiblioteker å bruke den.
Alle de innebygde klassene støtter denne ideen med funksjoner som
rb_str_new
, rb_ary_new
, og så videre.
Vi kan lage vår egen:
VALUE mp3_info_new() { VALUE info; MP3Info *one; info = Data_Make_Struct(cTest, MP3Info, 0, free, one); ... rb_obj_call_init(info, 0, 0); return info; } |
#include "ruby.h" #include "cdjukebox.h" VALUE cCDPlayer; static void cd_free(void *p) { CDPlayerDispose(p); } static void progress(CDJukebox *rec, int percent) { if (rb_block_given_p()) { if (percent > 100) percent = 100; if (percent < 0) percent = 0; rb_yield(INT2FIX(percent)); } } static VALUE cd_seek(VALUE self, VALUE disc, VALUE track) { CDJukebox *ptr; Data_Get_Struct(self, CDJukebox, ptr); CDPlayerSeek(ptr, NUM2INT(disc), NUM2INT(track), progress); return Qnil; } static VALUE cd_seekTime(VALUE self) { double tm; CDJukebox *ptr; Data_Get_Struct(self, CDJukebox, ptr); tm = CDPlayerAvgSeekTime(ptr); return rb_float_new(tm); } static VALUE cd_unit(VALUE self) { return rb_iv_get(self, "@unit"); } static VALUE cd_init(VALUE self, VALUE unit) { rb_iv_set(self, "@unit", unit); return self; } VALUE cd_new(VALUE class, VALUE unit) { VALUE argv[1]; CDJukebox *ptr = CDPlayerNew(NUM2INT(unit)); VALUE tdata = Data_Wrap_Struct(class, 0, cd_free, ptr); argv[0] = unit; rb_obj_call_init(tdata, 1, argv); return tdata; } void Init_CDJukebox() { cCDPlayer = rb_define_class("CDPlayer", rb_cObject); rb_define_singleton_method(cCDPlayer, "new", cd_new, 1); rb_define_method(cCDPlayer, "initialize", cd_init, 1); rb_define_method(cCDPlayer, "seek", cd_seek, 2); rb_define_method(cCDPlayer, "seekTime", cd_seekTime, 0); rb_define_method(cCDPlayer, "unit", cd_unit, 0); } |
require "code/ext/CDJukebox" p = CDPlayer.new(1) puts "Unit is #{p.unit}" p.seek(3, 16) {|x| puts "#{x}% done" } puts "Avg. time was #{p.seekTime} seconds" |
Unit is 1 26% done 79% done 100% done Avg. time was 1.2 seconds |
seek
.
I funksjonen progress
ser vi om det er en iterator
i den nåværende konteksten, og hvis så, kjør den med en prosentsats som
angir progresjon, som argument.
malloc
. For eksempel, dersom
ALLOC_N
finner ut at den ikke kan allokere den ønskede
mengden minne, vil den starte søppeltømmmeren for å prøve å få
frigitt litt plass. Den vil kaste et NoMemError
unntak dersom den ikke kan allokere minnet eller dersom den forespurte
mendgen er ugyldig.
Minneallokering | |
---|---|
type * | ALLOC_N(c-type, n") |
Allokerer n c-type objekter, hvor c-type er ordrett navnet på C typen, ikke en variabel av den typen. | |
type * | ALLOC(c-type") |
Allokerer en c-type og omstøper resultatet til en peker av den typen. | |
REALLOC_N(var, c-type, n") | |
Reallokerer n stykk c-typeer og tilordner resultatet til var, en peker til en c-type. | |
type * | ALLOCA_N(c-type, n") |
Allokerer minne for n objekter av typen c-type på stakken---dette minnet vil bli automatisk frigitt
når funksjonen som kaller ALLOCA_N returnerer.
|
extconf.rb
.
extconf.rb
for å konstruere en Makefile
for C filene som er i den katalogen.
make
.
make install
.
Figur 17.2: Kompilering og lenking av en utvidelse |
extconf.rb
programmet som du,
som en utvikler, skriver. I extconf.rb
skriver du et
enkelt program som finner ut hvilke fasiliteter som er tilgjengelig
på brukerens system og hvor disse er å finne.
Kjøring av extconf.rb
lager en skreddersydd
Makefile
tilpassed både din applikasjon og systemet
det blir kompilert på. Når du deretter kjører make
kommandoen med denne Makefile
-fila, blir utvidelsen din
kompilert, lenket og (eventuelt) installert.
Den enkleste extconf.rb
trenger ikke være lengre enn to linjer,
og for mange utvidelser holder det.
require 'mkmf' create_makefile("Test") |
mkmf
(dokumentasjon starter på side 451(??)). Den inneholder alle kommandoene
vi kommer til å bruke. Den andre linjen lager en Makefile
for en utvidelse kalt ``Test''. (Legg merke til at ``Test'' er navnet
på utvidelsen, make-fila vil alltids hete ``Makefile''.)
Test
vil bli bygget utifra alle de C kildekode filene som
er å den gjeldende katalogen.
La oss anta at vi kjører dette extconf.rb
programmet i en
katalog som inneholder en enkelt kildekodefil, main.c
.
Resultatet er en Makefile
som kompilerer og lenker vår utvidelse.
På vårt system inneholder den de følgende kommandoer.
gcc -fPIC -I/usr/local/lib/ruby/1.6/i686-linux -g -O2 \ -c main.c -o main.o gcc -shared -o Test.so main.o -lc |
Test.so
,
som kan lenkes inn i Ruby dynamisk ved kjøretid ved å bruke
``require
''. Legg merke til hvordan mkmf
kommandoene har lokalisert platformspesifikke biblioteker og tatt i bruk
kompilatorspesifikke opsjoner automatisk. Kjekt, eller hva?
Selv om dette grunnleggende programmet fungerer for mange enkle
utvidelser, må du kanskje gjøre mer arbeid dersom utvidelsen din
trenger header-filer eller bibliotek som ikke følger med som standard
i kompileringsmiljøet, eller du gjør betinget kompilering basert på
tilgjengeligheten av bibliotek og funksjoner.
En vanlig forutsetning for kompilering er å angi stien til
include-filer og bibliotek som ikke er innstallert på standard plasseringer.
Dette gjøres i to deler.
Først skal extconf.rb
inneholde en eller flere
dir_config
kommandoer.
Dette angir en merkelapp til et sett med kataloger. Deretter, når
du kjører extconf.rb
programmet, forteller du mkmf
hvor de tilsvarende fysiske katalogene er på det gjeldende systemet.
Dersom extconf.rb
inneholder linjen
dir_config(
navn
)
, så gir du
stien til de respektive katalogene med kommandoline-opsjoner:
--with-navn-include=directory
include
katalogen til kompileringskommandoen.
--with-navn-lib=directory
lib
katalogen til lenkekommandoen.
include
og lib
, (som også er vanlig) kan du ta en snarvei:
--with-navn-dir=directory
lib
og directory/include
til henholdsvis lenke- og kompileringskommandoen .
--with
opsjonene når du kjører extconf.rb
,
kan du også bruke de --with
som ble angitt når Ruby ble bygd for
din maskin. Dette betyr at du kan finne ut plasseringen til biblioteker
som Ruby selv bruker.
For å gjøre alt dette litt mer håndfast, la oss anta at du trenker
å bruke biblioteker og include-filer for CD jukeboksen som vi utvikler.
Din extconf.rb
fil kan da inneholde
require 'mkmf' dir_config('cdjukebox') # .. mer kode create_makefile("CDJukeBox") |
extconf.rb
omtrent slik:
% ruby extconf.rb --with-cdjukebox-dir=/usr/local/cdjb |
Makefile
vil anta at bibliotekene er å finne i
/usr/local/cdjb/lib
og include-filene i
/usr/local/cdjb/include
.
Kommandoen dir_config
legger til nye steder for å søke
etter biblioteker og include-filer. Men den lenker derimot ikke inn
disse bibliotekene inn i din applikasjon. For å gjøre det, vil du trenge
å bruke en eller flere kall til have_library
eller
find_library
.
Metoden have_library
leter etter et gitt inngangspunkt i et
navngitt bibliotek. Hvis den finner inngangspunktet, legger den
biblioteket til listen over de som skal linkes inn i din applikasjon.
Metoden find_library
oppfører seg lignende, men
tillater deg å spesifisere en liste med kataloger som man kan
søke etter biblioteket i.
require 'mkmf' dir_config('cdjukebox') have_library('cdjb', 'CDPlayerNew') create_makefile("CDJukeBox") |
find_library
vil søke i en angitt liste med kataloger
for å finne den riktige (dette er forskjellig fra have_library
,
som kun bruker konfigurasjonsinformasjon for å finne det).
For å lage en Makefile
som bruker både X Windows
og et JPEG bibliotek, kunne extconf.rb
for eksempel inneholde
require 'mkmf' if have_library("jpeg","jpeg_mem_init") and find_library("X11", "XOpenDisplay", "/usr/X11/lib", "/usr/X11R6/lib", "/usr/openwin/lib") then create_makefile("XThing") else puts "No X/JPEG support available" end |
mkmf
kommandoene returnerer false
dersom de
feiler. Det betyr at vi kan skrive en extconf.rb
som bare genererer
en Makefile
dersom alt som trengs er tilstede. Ruby distribusjonen
gjør dette slik at den vil bare prøve å kompilere de utvidelsene som er støttet
av systemet ditt.
Du har kanskje også behov for at utvidelsen din skal kunne konfigurere seg
i forhold til miljøet den kompileres for. Et eksempel kunne være at
vår CD jukeboks kunne brukt en MP3 dekoder med høy ytelse dersom brukeren
har en installert. Vi kan sjekke ved å lete etter dens header-fil.
require 'mkmf' dir_config('cdjukebox') have_library('cdjb', 'CDPlayerNew') have_header('hp_mp3.h') create_makefile("CDJukeBox") |
setpriority
metoden nyttig, men ikke alltids
tilgjengelig. Vi kan sjekke om den er tilgjengelig med:
require 'mkmf' dir_config('cdjukebox') have_func('setpriority') create_makefile("CDJukeBox") |
have_header
og have_func
definerer preprosesseringskonstanter dersom de finner
det som søkes etter. Navnene konstrueres ved å gjøre bokstavene
i det som søkes etter om til store bokstaver og å prefikse
med ``HAVE_''. Din C kode kan benytte seg av dette:
#if defined(HAVE_HP_MP3_H) # include <hp_mp3.h> #endif #if defined(HAVE_SETPRIORITY) err = setpriority(PRIOR_PROCESS, 0, -10) #endif |
mkmf
kommandoene, kan programmet ditt legge ting direkte inn
i de globale variablene $CFLAGS
og $LFLAGS
,
som sendes til henholdsvis kompilatoren og lenkeren.
ext/Setup
i distribusjonen
og legg din katalog til listen over utvidelser og så bygge Ruby på nytt.
Utvidelsene listet i Setup
vil bli statisk lenket inn
i Ruby sin kjørbare programfil. Hvis du ønsker å slå av
all dynamisk lenking og lenke alle utvidelser statisk, legg
til følgende opsjon i ext/Setup
.
option nodynamic |
#include "ruby.h" main() { /* ... our own application stuff ... */ ruby_init(); ruby_script("embedded"); rb_load_file("start.rb"); while (1) { if (need_to_do_ruby) { ruby_run(); } /* ... run our app stuff */ } } |
ruby_init()
.
Men på noen platformer kan du trenge å gå igjennom spesielle
steg først:
#if defined(NT) NtInitialize(&argc, &argv); #endif #if defined(__MACOS__) && defined(__MWERKS__) argc = ccommand(&argv); #endif |
main.c
som er å finne i Ruby distribusjonen for
andre spesifikke definisjoner eller oppsett som kreves for din platform.
Innebygd Ruby API | |
---|---|
void | ruby_init(") |
Gjør oppsett og initialisering av fortolkeren. Denne funksjonen bør kalles før noen andre Ruby-relaterte funksjoner. | |
void | ruby_options(int argc, char **argv") |
Gir kommandoline opsjonene videre til Ruby fortolkeren. | |
void | ruby_script(char *name") |
Setter navnet til Ruby skriptet (og $0 )
til name.
|
|
void | rb_load_file(char *file") |
Laster den angitte filen inn i fortolkeren. | |
void | ruby_run(") |
Kjører fortolkeren. |
rb_protect
, rb_rescue
, og relaterte
funksjoner er dokumentert på side 192(??).
Titt på eruby
for et eksempel av innebygging av en Ruby
fortolker inne i et annet program. Beskrivelsen starter på side 147(??).
ID
: du kan få tak i en ID
til en streng ved å bruke rb_intern
, samt rekonstruere
navnet fra en ID
ved å bruke rb_id2name
.
Siden mesteparten av disse C funksjonene tilsvarer Ruby
metoder som allerede er dokumenter andre steder i denne boka,
vil beskrivelsene her være korte.
Merk at den følgende listen ikke er fullstendig.
Det er mange andre funksjoner tilgjengelig---alt for mange til å kunne
dokumentere dem alle, viser det seg.
Hvis du trenger en metode du ikke finner her, ta en titt i
``ruby.h
'' eller ``intern.h
''.
I tillegg finner du ved eller nær bunnen av hver kildekodefil et
sett med metodedefinisjoner som beskriver bindingen fra Ruby metoder
til Cfunksjoner. Du kan kanskje kalle C funksjonen direkte eller
søke etter en innepakkende funksjon som kaller
funksjonen du er ute etter.
Følgende liste, basert på listen i README.EXT
, viser
de viktigste kildekodefilene i fortolkeren.
Definere objekter | |
---|---|
VALUE | rb_define_class(char *navn, VALUE superklasse") |
Definerer en ny klasse på toppnivå med det gitte navn og
superklasse (for klassen Object , bruk rb_cObject ).
|
|
VALUE | rb_define_module(char *navn") |
Definerer en my modul på toppnivå med det gitte navn. | |
VALUE | rb_define_class_under(VALUE under, char *name, VALUE superclass") |
Definerer en nøstet klasse under klassen eller modulen under. | |
VALUE | rb_define_module_under(VALUE under, char *name") |
Definerer en nøstet modul under klassen eller modulen under. | |
void | rb_include_module(VALUE forelder, VALUE modul") |
Inkluderer den gitte modul inn i klassen eller modulen forelder | |
void | rb_extend_object(VALUE obj, VALUE modul") |
Utvider obj med modul. | |
VALUE | rb_require(const char *name") |
Ekvivalent med ``require name.''
Returnerer Qtrue eller Qfalse .
|
argc | Funksjonsdeklarasjon | |||||||
0..17 |
VALUE func(VALUE self, VALUE arg...)
|
|||||||
C funksjonen vil kalles med så mange faktiske argumenter. | ||||||||
-1 |
VALUE func(int argc, VALUE *argv, VALUE self)
|
|||||||
C funksjonen vil bli gitt et varierende antall argumenter i form av en C tabell. | ||||||||
-2 |
VALUE func(VALUE self, VALUE args)
|
|||||||
C funksjonen vil bli gitt et varierende antall argumenter i form av en Ruby tabell. | ||||||||
rb_scan_args
for å
finne ut av ting (se under).
Definere metoder | ||
---|---|---|
void | rb_define_method(VALUE classmod, char *navn, VALUE(*func)(), int argc") | |
Definerer en instansmetode i klassen eller modulen classmod med det gitte navn, implementert av C funksjonen func og tar argc argumenter. | ||
void | rb_define_module_function(VALUE classmod, char *navn, VALUE(*func)(), int argc)") | |
Definerer en metode i klassen classmod med det gitte navn, implementert av C funksjonen func og tar argc argumenter. | ||
void | rb_define_global_function(char *navn, VALUE(*func)(), int argc") | |
Definerer en global funksjon (en privat metode i
Kernel med det gitte navn, implementert av
C funksjonen func og tar argc argumenter.
|
||
void | rb_define_singleton_method(VALUE classmod, char *name, VALUE(*func)(), int argc") | |
Definerer en singleton-metode i klassen classmod med det gitte navn, implementert av C funksjonen func og tar argc argumenter. | ||
int | rb_scan_args(int argcount, VALUE *argv, char *fmt, ...") | |
Går over argumentlisten og tilordner til variabler omtrent som
scanf : fmt er en streng som inneholder null, en eller
to sifre fulgt av noen flaggtegn. Det første sifferet angir antallet
obligatoriske argumenter. Det andre er antallet frivillige argumenter.
En ``*'' betyr at resten av argumentene skal pakkes inn i en Ruby tabell.
En ``&'' betyr at en assosiert kodeblokk vil tatt imot og tilordet til
den gitte variabelen.
(Hvis ingen kodeblokk ble gitt, vil variabelen inneholde Qnil )
Etter fmt strengen følger pekere (som med til scanf ) til VALUE strukturer som argumentene skal tilordnes til.
|
||
void | rb_undef_method(VALUE classmod, const char *name") | |
Fjerner definisjonen til den gitte metoden name i den gitte klassen eller modulen classmod. | ||
void | rb_define_alias(VALUE classmod, const char *newname, const char *oldname") | |
Definerer et alias for oldname i klasssen eller modulen classmod. |
Definere variabler og konstanter | ||
---|---|---|
void | rb_define_const(VALUE classmod, char *navn, VALUE verdi") | |
Definerer en konstant i klassen eller modulen classmod, med angitt navn og verdi. | ||
void | rb_define_global_const(char *name, VALUE value") | |
Definerer en global konstant med angitt navn og verdi. | ||
void | rb_define_variable(const char *navn, VALUE *objekt") | |
Eksporterer adressen til det gitte objekt som ble konstruert i C til Ruby sitt navnerom som navn. Fra Ruby vil dette være en global variabel, så navn bør begynne med et dollartegn. Sjekk at reglene for tillatte variabelnavn følger; variabler med ulovlige navn vil ikke være tilgjengelig fra Ruby. | ||
void | rb_define_class_variable(VALUE klasse, const char *navn, VALUE verdi") | |
Definerer en klassevariabel navn (som må spesifiseres med et
``@@ '' prefiks) i den gitte klasse, med initiell verdi.
|
||
void | rb_define_virtual_variable(const char *navn, VALUE(*getter)(), void(*setter)()") | |
Eksporterer en virtuell variabel til Ruby sitt navnerom som den
globale variablenen $navn.
Ingen reell lagringsplass for variabelen eksisterer. Forsøk på
å hente og sette variabelen vil kalle de gitte funksjonene med
prototypene:
|
||
void | rb_define_hooked_variable(const char *name, VALUE *variabel, VALUE(*getter)(), void(*setter)()") | |
Definerer funksjoner som skal kalles når det leses fra eller skrives til
variabel. Se også rb_define_virtual_variable .
|
||
void | rb_define_readonly_variable(const char *name, VALUE *value") | |
Samme som rb_define_variable , men virker skrivebeskyttet fra Ruby.
|
||
void | rb_define_attr(VALUE variabel, const char *navn, int read, int write") | |
Lager aksesseringsmetoder for den angitte variabel, med det gitte navn. Hvis read er ulik null, lages en lesemetode. Hvis write er ulik null, lages en skrivemetode. | ||
void | rb_global_variable(VALUE *obj") | |
Registrerer den angitte adressen hos søppeltømmeren. |
Kalle metoder | |
---|---|
VALUE | rb_funcall(VALUE recv, ID id, int argc, ...") |
Kaller metoden angitt ved id i objektet recv med argc antall argumenter, samt selve argumentene (potensielt ingen). | |
VALUE | rb_funcall2(VALUE recv, ID id, int argc, VALUE *args") |
Kaller metoden angitt ved i objektet recv med argc antall argumenter, samt selve argumentene gitt i C tabellen args. | |
VALUE | rb_funcall3(VALUE recv, ID id, int argc, VALUE *args") |
Samme som rb_funcall2 , men kaller ikke private metoder.
|
|
VALUE | rb_apply(VALUE recv, ID name, int argc, VALUE args") |
Kaller metoden angitt ved i objektet recv
med argc antall argumenter, samt selve argumentene gitt i et Ruby Array -objekt; args.
|
|
ID | rb_intern(char *navn") |
Returnerer en ID for et gitt navn. Hvis navnet ikke eksisterer,
blir det laget et symbol, og lagt til symboltabellen.
|
|
char * | rb_id2name(ID id") |
Returnerer navnet til den gitte id. | |
VALUE | rb_call_super(int argc, VALUE *args") |
Kaller den gjeldende metoden i superklassen til det gjeldende objekt. |
Exceptions | |
---|---|
void | rb_raise(VALUE exception, const char *fmt, ...") |
Hever en exception.
Den gitte strengen fmt og gjenværende argumenter blir fortolket som med printf .
|
|
void | rb_fatal(const char *fmt, ...") |
Heve et Fatal unntak, som terminerer prosessen.
Ingen rescue-blokker blir kalt, men ensure-blokker blir utført.
Den gitte strengen fmt og gjenværende argumenter blir fortolket som med printf .
|
|
void | rb_bug(const char *fmt, ...") |
Terminerer prosessen umiddelbart---ingen håndteringsmetoder av noen som helst type blir kalt.
Den gitte strengen fmt og gjenværende argumenter blir fortolket som med printf .
Du bør bare kalle denne funksjonen dersom en fatal bug har vist seg. Du skriver ikke fatale bugs, gjør du vel?
|
|
void | rb_sys_fail(const char *msg") |
Hever et platformspesifikt unntak tilsvarende til den siste kjente systemfeilen, med beskjeden msg. | |
VALUE | rb_rescue(VALUE (*body)(), VALUE args, VALUE(*rescue)(), VALUE rargs") |
Utfører body med de gitte argumentene args.
Hvis et StandardError unntak heves, vil
rescue bli utført med de gitte argumentene rargs.
|
|
VALUE | rb_ensure(VALUE(*body)(), VALUE args, VALUE(*ensure)(), VALUE eargs") |
Utfører body med de gitte argumentene args. Uansett om et unntak heves eller ikke, vil ensure bli utført med de gitte argumentene eargs. | |
VALUE | rb_protect(VALUE (*body)(), VALUE args, int *result") |
Utfører body med de gitte argumentene args og returnerer ikke-null i result dersom et unntak ble hevet. | |
void | rb_notimplement(") |
Hever et NotImpError unntak for å indikere at den omsluttende
funksjonen ikke er implementert ennå, eller ikke er tilgjengelig på denne platformen.
|
|
void | rb_exit(int status") |
Avslutter Ruby med den gitte status. Hever et SystemExit
unntak og kaller registrerte exit- og finalizer-funksjoner.
|
|
void | rb_warn(const char *fmt, ...") |
Sender en advarsel til standard feil-utput, uansett innstillinger.
Den gitte strengen fmt og gjenværende argumenter blir fortolket som med printf .
|
|
void | rb_warning(const char *fmt, ...") |
Sender en advarsel til standard feil-utput, forutsatt at Ruby ble kalt med -w flagget.
Den gitte strengen fmt og gjenværende argumenter blir fortolket som med printf .
|
Iteratorer | |
---|---|
void | rb_iter_break(") |
Bryter ut av den omliggende iterator blokken. | |
VALUE | rb_each(VALUE obj") |
Kaller each på det gitte objekt obj.
|
|
VALUE | rb_yield(VALUE arg") |
Kaller iterator blokken i den gjeldende kontekst, med arg som argument. Flere verdier kan sendes inn ved hjelp av en tabell. | |
int | rb_block_given_p(") |
Returnerer true hvis yield ville utført en kodeblokk i den
gjeldende kontekst---det vil si, hvis en kodeblokk ble sendt med den
nåværende metoden og er tilgjengelig for utføring.
|
|
VALUE | rb_iterate(VALUE (*method)(), VALUE args, VALUE (*block)(), VALUE arg2") |
Kaller method med argument args og en blokk, block.
En yield fra den metoden vil kalle block med argumentet gitt til
yield , og et ekstra argument, arg2.
|
|
VALUE | rb_catch(const char *tag, VALUE (*proc)(), VALUE value") |
Tilsvarer Ruby sin catch .
|
|
void | rb_throw(const char *tag , VALUE value") |
Tilsvarer Ruby sin throw .
|
Tilgang til variabler | |
---|---|
VALUE | rb_iv_get(VALUE obj, char *name") |
Returnerer instansvariabelen name (som må spesifiseres med et ``@ '' prefiks)
fra det gitte objekt, obj.
|
|
VALUE | rb_ivar_get(VALUE obj, ID name") |
Returnerer instansvariabelen name fra det gitte objekt, obj. | |
VALUE | rb_iv_set(VALUE obj, char *name, VALUE value") |
Setter instansvariabelen name (som må spesifiseres med et ``@ '' prefiks)
i det det gitte objekt, obj, til verdien value. Returnerer value.
|
|
VALUE | rb_ivar_set(VALUE obj, ID name, VALUE value") |
Setter instansvariabelen name i det det gitte objekt, obj, til verdien value. Returnerer value. | |
VALUE | rb_gv_set(const char *name, VALUE value") |
Setter den globale variabelen name (``$ '' prefikset er valgfritt)
til verdien value. Returnerer value.
|
|
VALUE | rb_gv_get(const char *name") |
Henter verdien til den globale variabelen name (``$ '' prefikset er valgfritt).
|
|
void | rb_cvar_set(VALUE class, ID name, VALUE val") |
Setter klassevariabelen name i klassen class til verdien value. | |
VALUE | rb_cvar_get(VALUE class, ID name") |
Returnerer klassevariabelen name fra klassen class. | |
int | rb_cvar_defined(VALUE class, ID name") |
Returnerer Qtrue hvis klassevariabelen name er definert for
klassen class. Hvis ikke, returneres Qfalse .
|
|
void | rb_cv_set(VALUE class, const char *name, VALUE val") |
Setter klassevariabelen name (som må spesifiseres med et ``@@ '' prefiks) i
klassen class til verdien value.
|
|
VALUE | rb_cv_get(VALUE class, const char *name") |
Returnerer klassevariabelen name (som må spesifiseres med et ``@@ '' prefiks)
fra klassen class.
|
Objekt status | |
---|---|
OBJ_TAINT(VALUE obj") | |
Markerer objektet obj som tainted. | |
int | OBJ_TAINTED(VALUE obj") |
Returnerer ikke-null hvis objektet obj er tainted. | |
OBJ_FREEZE(VALUE obj") | |
Markerer objektet obj som frosset. | |
int | OBJ_FROZEN(VALUE obj") |
Returnerer ikke-null hvis objektet obj er frosset. | |
Check_SafeStr(VALUE str") | |
Hever en SecurityError hvis det gjeldende
sikkerhetsnivå (safe level) er større enn null og
str er tainted, eller en TypeError
hvis str ikke er en T_STRING .
|
|
int | rb_safe_level(") |
Returnerer det gjeldende sikkerhetsnivå (safe level). | |
void | rb_secure(int level") |
Hever en SecurityError hvis level <=
gjeldende sikkerhetsnivå (safe level).
|
|
void | rb_set_safe_level(int newlevel") |
Setter sikkerhetsnivået til et nytt nivå, newlevel. |
Ofte brukte metoder | |
---|---|
VALUE | rb_ary_new(") |
Returnerer en ny Array med standard størrelse.
|
|
VALUE | rb_ary_new2(long length") |
Returnerer en ny Array med lengde length.
|
|
VALUE | rb_ary_new3(long length, ...") |
Returnerer en ny Array med lengde length
og fylt med de gjenværende argumentene.
|
|
VALUE | rb_ary_new4(long length, VALUE *values") |
Returnerer en ny Array med lengde length
og fylt med verdiene i C tabellen values.
|
|
void | rb_ary_store(VALUE self, long index, VALUE value") |
Lagrere verdien value på indeks index i tabellen self. | |
VALUE | rb_ary_push(VALUE self, VALUE value") |
Dytter value inn på slutten av tabellen self. Returnerer value. | |
VALUE | rb_ary_pop(VALUE self") |
Fjerner og returnerer siste element fra tabellen self. | |
VALUE | rb_ary_shift(VALUE self") |
Fjerner og returnerer første element fra tabellen self. | |
VALUE | rb_ary_unshift(VALUE self, VALUE value") |
Dytter value inn på begynnelsen av tabellen self. Returnerer value. | |
VALUE | rb_ary_entry(VALUE self, long index") |
Returnerer elementet i tabellen self som finnes på indeks index. | |
int | rb_respond_to(VALUE self, ID method") |
Returnerer ikke-null dersom self svarer på metoden method. | |
VALUE | rb_thread_create(VALUE (*func)(), void *data") |
Kjører func i en ny tråd, og sender inn data som et argument. | |
VALUE | rb_hash_new(") |
Returnerer en ny, tom Hash .
|
|
VALUE | rb_hash_aref(VALUE self, VALUE key") |
Returnerer elementet tilsvarende nøkkelen key i self. | |
VALUE | rb_hash_aset(VALUE self, VALUE key, VALUE value") |
Setter verdien for nøkkelen key til verdien value i self. Returnerer value. | |
VALUE | rb_obj_is_instance_of(VALUE obj, VALUE klass") |
Returnerer Qtrue hvis obj er en instans av
klass.
|
|
VALUE | rb_obj_is_kind_of(VALUE obj, VALUE klass") |
Returnerer Qtrue hvis
klass er klassen tilobj eller
klass
er en av superklassene til obj sin klasse.
|
|
VALUE | rb_str_new(const char *src, long length") |
Returnerer en ny String intialisert med
length tegn i fra src.
|
|
VALUE | rb_str_new2(const char *src") |
Returnerer en ny String intialisert med
den null-terminerte C strengen src.
|
|
VALUE | rb_str_dup(VALUE str") |
Returnerer et nytt String -objekt
som er en duplikat av str.
|
|
VALUE | rb_str_cat(VALUE self, const char *src, long length") |
Legger til (konkatenerer) length tegn fra src på
String -objektet self. Returnerer self.
|
|
VALUE | rb_str_concat(VALUE self, VALUE other") |
Legger til (konkatenerer) other på
String -objektet self. Returnerer self.
|
|
VALUE | rb_str_split(VALUE self, const char *delim") |
Returnerer en tabell av String -objekter laget ved
å dele opp self ved delim.
|
$Log: ext_ruby.xml,v $ Revision 1.22 2002/11/24 09:05:30 kent Første kladd ferdig. Revision 1.21 2002/11/23 13:46:54 kent Frem til iterators i den siste tabellen.
Forrige < |
Innhold ^
|
Neste >
|