Table of Contents
Preface
1. Tokenization, Parsing and Compilation
Tokens: the words that make up the Ruby language
Parsing: how Ruby understands the code you write
Understanding the LALR parse algorithm
Some actual Ruby grammar rules
Compilation: how Ruby translates your code into a new language
Stepping through how Ruby compiles a simple script
Compiling a call to a block
Tokenization, parsing and compilation in JRuby
Tokenization, parsing and compilation in Rubinius
2. How Ruby Executes Your Code
YARV's internal stack and your Ruby stack
Stepping through how Ruby executes a simple script
Executing a call to a block
Local and dynamic access of Ruby variables
Local variable access
Dynamic variable access
How YARV controls your program's execution flow
How Ruby executes an if statement
Jumping from one scope to another
How JRuby executes your code
How Rubinius executes your code
3. Objects, Classes and Modules
What's inside a Ruby object?
Generic objects
Do generic objects have instance variables?
Deducing what's inside the RClass structure
The actual RClass structure
How Ruby implements modules and method lookup
What happens when you include a module in a class?
Ruby's method lookup algorithm
Including two modules in one class
Objects, classes and modules in JRuby
Objects, classes and modules in Rubinius
4. Hash Tables
Hash tables in Ruby
How hash tables expand to accommodate more values
How Ruby implements hash functions
Hash tables in JRuby
Hash tables in Rubinius
5. How Ruby Borrowed a Decades Old Idea From Lisp
Blocks: Closures in Ruby
Stepping through how Ruby calls a block
Borrowing an idea from 1975
Lambdas and Procs: treating functions as a first class citizen
Stack memory vs. heap memory
Stepping through how Ruby creates a lambda
Stepping through how Ruby calls a lambda
The Proc object
Metaprogramming and closures: eval, instance_eval and binding
Calling eval with binding
Stepping through a call to instance_eval
Another important part of Ruby closures
Closures in JRuby
Closures in Rubinius
Conclusion
Experiments:
Experiment 1-1: Using Ripper to tokenize different Ruby scripts
Experiment 1-2: Using Ripper to parse different Ruby scripts
Experiment 1-3: Using the RubyVM class to display YARV instructions
Experiment 2-1: Benchmarking Ruby 1.9 vs. Ruby 1.8
Experiment 2-2: Exploring special variables
Experiment 2-3: Testing how Ruby implements for loops internally
Experiment 3-1: How long does it take to save a new instance variable?
Experiment 3-2: Where does Ruby save class methods?
Experiment 3-3: Modifying a module after including it
Experiment 4-1: Retrieving a value from hashes of varying sizes
Experiment 4-2: Inserting one new element into hashes of varying sizes
Experiment 4-3: Using objects as keys in a hash
Experiment 5-1: Which is faster: a while loop or passing a block to each?
Experiment 5-2: Changing local variables after calling lambda
Experiment 5-3: Using a closure to define a method