- •Programming Ruby The Pragmatic Programmer's Guide
- •Foreword
- •Preface
- •Ruby Sparkles
- •What Kind of Language Is Ruby?
- •Is Ruby for Me?
- •Why Did We Write This Book?
- •Ruby Versions
- •Installing Ruby
- •Building Ruby
- •Running Ruby
- •Interactive Ruby
- •Ruby Programs
- •Resources
- •Acknowledgments
- •Notation Conventions
- •Roadmap
- •Ruby.New
- •Ruby Is an Object-Oriented Language
- •Some Basic Ruby
- •Arrays and Hashes
- •Control Structures
- •Regular Expressions
- •Blocks and Iterators
- •Reading and 'Riting
- •Onward and Upward
- •Classes, Objects, and Variables
- •Inheritance and Messages
- •Inheritance and Mixins
- •Objects and Attributes
- •Writable Attributes
- •Virtual Attributes
- •Class Variables and Class Methods
- •Class Variables
- •Class Methods
- •Singletons and Other Constructors
- •Access Control
- •Specifying Access Control
- •Variables
- •Containers, Blocks, and Iterators
- •Containers
- •Implementing a SongList Container
- •Blocks and Iterators
- •Implementing Iterators
- •Blocks for Transactions
- •Blocks Can Be Closures
- •Standard Types
- •Numbers
- •Strings
- •Working with Strings
- •Ranges as Sequences
- •Ranges as Conditions
- •Ranges as Intervals
- •Regular Expressions
- •Patterns
- •Anchors
- •Character Classes
- •Repetition
- •Alternation
- •Grouping
- •Pattern-Based Substitution
- •Backslash Sequences in the Substitution
- •Object-Oriented Regular Expressions
- •More About Methods
- •Defining a Method
- •Variable-Length Argument Lists
- •Methods and Blocks
- •Calling a Method
- •Expanding Arrays in Method Calls
- •Making Blocks More Dynamic
- •Collecting Hash Arguments
- •Expressions
- •Operator Expressions
- •Miscellaneous Expressions
- •Command Expansion
- •Backquotes Are Soft
- •Assignment
- •Parallel Assignment
- •Nested Assignments
- •Other Forms of Assignment
- •Conditional Execution
- •Boolean Expressions
- •Defined?, And, Or, and Not
- •If and Unless Expressions
- •If and Unless Modifiers
- •Case Expressions
- •Iterators
- •Break, Redo, and Next
- •Variable Scope and Loops
- •Exceptions, Catch, and Throw
- •The Exception Class
- •Handling Exceptions
- •Tidying Up
- •Play It Again
- •Raising Exceptions
- •Adding Information to Exceptions
- •Catch and Throw
- •Modules
- •Namespaces
- •Instance Variables in Mixins
- •Iterators and the Enumerable Module
- •Including Other Files
- •Basic Input and Output
- •What Is an io Object?
- •Opening and Closing Files
- •Reading and Writing Files
- •Iterators for Reading
- •Writing to Files
- •Talking to Networks
- •Threads and Processes
- •Multithreading
- •Creating Ruby Threads
- •Manipulating Threads
- •Thread Variables
- •Threads and Exceptions
- •Controlling the Thread Scheduler
- •Mutual Exclusion
- •The Mutex Class
- •Condition Variables
- •Running Multiple Processes
- •Spawning New Processes
- •Independent Children
- •Blocks and Subprocesses
- •When Trouble Strikes
- •Ruby Debugger
- •Interactive Ruby
- •Editor Support
- •But It Doesn't Work!
- •But It's Too Slow!
- •Create Locals Outside Blocks
- •Use the Profiler
- •Ruby and Its World
- •Command-Line Arguments
- •Command-Line Options
- •Program Termination
- •Environment Variables
- •Writing to Environment Variables
- •Where Ruby Finds Its Modules
- •Build Environment
- •Ruby and the Web
- •Writing cgi Scripts
- •Using cgi.Rb
- •Quoting
- •Creating Forms and html
- •Cookies
- •Sessions
- •Embedding Ruby in html
- •Using eruby
- •Installing eruby in Apache
- •Improving Performance
- •Ruby Tk
- •Simple Tk Application
- •Widgets
- •Setting Widget Options
- •Getting Widget Data
- •Setting/Getting Options Dynamically
- •Sample Application
- •Binding Events
- •Scrolling
- •Just One More Thing
- •Translating from Perl/Tk Documentation
- •Object Creation
- •Running Ruby Under Windows
- •Windows Automation
- •Getting and Setting Properties
- •Named Arguments
- •For each
- •An Example
- •Optimizing
- •Extending Ruby
- •Ruby Objects in c
- •Value as a Pointer
- •Value as an Immediate Object
- •Writing Ruby in c
- •Evaluating Ruby Expressions in c
- •Sharing Data Between Ruby and c
- •Directly Sharing Variables
- •Wrapping c Structures
- •An Example
- •Memory Allocation
- •Creating an Extension
- •Creating a Makefile with extconf.Rb
- •Static Linking
- •Embedding a Ruby Interpreter
- •Bridging Ruby to Other Languages
- •Ruby c Language api
- •The Ruby Language
- •Source Layout
- •Begin and end Blocks
- •General Delimited Input
- •The Basic Types
- •Integer and Floating Point Numbers
- •Strings
- •Requirements for a Hash Key
- •Symbols
- •Regular Expressions
- •Regular Expression Options
- •Regular Expression Patterns
- •Substitutions
- •Extensions
- •Variable/Method Ambiguity
- •Variables and Constants
- •Scope of Constants and Variables
- •Predefined Variables
- •Exception Information
- •Pattern Matching Variables
- •Input/Output Variables
- •Execution Environment Variables
- •Standard Objects
- •Global Constants
- •Expressions Single Terms
- •Operator Expressions
- •More on Assignment
- •Parallel Assignment
- •Block Expressions
- •Boolean Expressions
- •Truth Values
- •And, Or, Not, and Defined?
- •Comparison Operators
- •Ranges in Boolean Expressions
- •Regular Expressions in Boolean Expressions
- •While and Until Modifiers
- •Break, Redo, Next, and Retry
- •Method Definition
- •Method Arguments
- •Invoking a Method
- •Class Definition
- •Creating Objects from Classes
- •Class Attribute Declarations
- •Module Definitions
- •Mixins---Including Modules
- •Module Functions
- •Access Control
- •Blocks, Closures, and Proc Objects
- •Proc Objects
- •Exceptions
- •Raising Exceptions
- •Handling Exceptions
- •Retrying a Block
- •Catch and Throw
- •Classes and Objects
- •How Classes and Objects Interact
- •Your Basic, Everyday Object
- •Object-Specific Classes
- •Mixin Modules
- •Extending Objects
- •Class and Module Definitions
- •Class Names Are Constants
- •Inheritance and Visibility
- •Freezing Objects
- •Locking Ruby in the Safe
- •Safe Levels
- •Tainted Objects
- •Reflection, ObjectSpace, and Distributed Ruby
- •Looking at Objects
- •Looking Inside Objects
- •Looking at Classes
- •Looking Inside Classes
- •Calling Methods Dynamically
- •Performance Considerations
- •System Hooks
- •Runtime Callbacks
- •Tracing Your Program's Execution
- •How Did We Get Here?
- •Marshaling and Distributed Ruby
- •Custom Serialization Strategy
- •Distributed Ruby
- •Compile Time? Runtime? Anytime!
- •Standard Library
Value as an Immediate Object
As we said above, immediate values are not pointers: Fixnum,Symbol,true,false, andnilare stored directly inVALUE.
Fixnumvalues are stored as 31-bit numbers[Or 63-bit on wider CPU architectures.]that are formed by shifting the original number left 1 bit and then setting the least significant bit (bit 0) to ``1.'' WhenVALUEis used as a pointer to a specific Ruby structure, it is guaranteed always to have an LSB of zero; the other immediate values also have LSBs of zero. Thus, a simple bit test can tell you whether or not you have aFixnum.
There are several useful conversion macros for numbers as well as other standard datatypes shown in Table 17.1 on page 174.
The other immediate values (true,false, andnil) are represented in C as the constantsQtrue,Qfalse, andQnil, respectively. You can testVALUEvariables against these constants directly, or use the conversion macros (which perform the proper casting).
Writing Ruby in c
One of the joys of Ruby is that you can write Ruby programs almost directly in C. That is, you can use the same methods and the same logic, but with slightly different syntax to accommodate C. For instance, here is a small, fairly boring test class written in Ruby.
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); } |
Let's go through this example in detail, as it illustrates many of the important concepts in this chapter. First off, we need to include the header file ``ruby.h'' to obtain the necessary definitions.
Now look at the last function, Init_Test. Every class or module defines a C global function namedInit_Name. This function will be called when the interpreter first loads the extensionName(or on startup for statically linked extensions). It is used to initialize the extension and to insinuate it into the Ruby environment. In this case, we define a new class namedTest, which is a subclass ofObject(represented by the external symbolrb_cObject; see ``ruby.h'' for others).
Next we set up addandinitializeas two instance methods for classTest. The calls torb_define_methodestablish a binding between the Ruby method name and the C function that will implement it, so a call to theaddmethod in Ruby will call the C functiont_addwith one argument.
Similarly, when newis called for this class, Ruby will construct a basic object and then callinitialize, which we have defined here to call the C functiont_initwith no (Ruby) arguments.
Now go back and look at the definition of initialize. Even though we said it took no arguments, there's a parameter here! In addition to any Ruby arguments, every method is passed an initialVALUEargument that contains the receiver for this method (the equivalent ofselfin Ruby code).
The first thing we'll do in initializeis create a Ruby array and set the instance variable@arrto point to it. Just as you would expect if you were writing Ruby source, referencing an instance variable that doesn't exist creates it.
Finally, the function t_addgets the instance variable@arrfrom the current object and callsArray#push to push the passed value onto that array. When accessing instance variables in this way, the@-prefix is mandatory---otherwise the variable is created, but cannot be referenced from Ruby.
Despite the extra, clunky syntax that C imposes, you're still writing in Ruby---you can manipulate objects using all of the method calls you've come to know and love, with the added advantage of being able to craft tight, fast code when needed.
WARNING:Every C function that is callable from Rubymustreturn aVALUE, even if it's justQnil. Otherwise, a core dump (or GPF) will be the likely result.
We can use the C version of the code in Ruby simply by require-ing it dynamically at runtime (on most platforms).
require "code/ext/Test" t = Test.new t.add("Bill Chase") |
C/Ruby datatype conversion functions and macros
|