You are previewing Ruby Under a Microscope.
O'Reilly logo
Ruby Under a Microscope

Book Description

Ruby Under a Microscope gives developers an inside, hands-on look at Ruby's core, using simple diagrams coupled with clear explanations.

Table of Contents

  1. Ruby Under a Microscope: An Illustrated Guide to Ruby Internals
  2. Dedication
  3. Advance Praise for Ruby under a Microscope
  4. About the Author
  5. Foreword
  6. Acknowledgments
  7. Introduction
    1. Who This Book Is For
    2. Using Ruby to Test Itself
    3. Which Implementation of Ruby?
    4. Overview
  8. 1. Tokenization and Parsing
    1. Tokens: The Words That Make Up the Ruby Language
    2. Experiment 1-1: Using Ripper to Tokenize Different Ruby Scripts
    3. Parsing: How Ruby Understands Your Code
      1. Understanding the LALR Parse Algorithm
      2. Some Actual Ruby Grammar Rules
    4. Experiment 1-2: Using Ripper to Parse Different Ruby Scripts
    5. Summary
  9. 2. Compilation
    1. No Compiler for Ruby 1.8
    2. Ruby 1.9 and 2.0 Introduce a Compiler
    3. How Ruby Compiles a Simple Script
    4. Compiling a Call to a Block
    5. Experiment 2-1: Displaying YARV Instructions
    6. The Local Table
      1. Compiling Optional Arguments
      2. Compiling Keyword Arguments
    7. Experiment 2-2: Displaying the Local Table
    8. Summary
  10. 3. How Ruby Executes Your Code
    1. YARV’s Internal Stack and Your Ruby Stack
      1. Stepping Through How Ruby Executes a Simple Script
      2. Executing a Call to a Block
    2. Experiment 3-1: Benchmarking Ruby 2.0 and Ruby 1.9 vs. Ruby 1.8
    3. Local and Dynamic Access of Ruby Variables
      1. Local Variable Access
      2. Method Arguments Are Treated Like Local Variables
      3. Dynamic Variable Access
    4. Experiment 3-2: Exploring Special Variables
    5. Summary
  11. 4. Control Structures and Method Dispatch
    1. How Ruby Executes an if Statement
    2. Jumping from One Scope to Another
      1. Catch Tables
      2. Other Uses for Catch Tables
    3. Experiment 4-1: Testing How Ruby Implements for Loops Internally
    4. The send Instruction: Ruby’s Most Complex Control Structure
      1. Method Lookup and Method Dispatch
      2. Eleven Types of Ruby Methods
    5. Calling Normal Ruby Methods
      1. Preparing Arguments for Normal Ruby Methods
    6. Calling Built-In Ruby Methods
      1. Calling attr_reader and attr_writer
      2. Method Dispatch Optimizes attr_reader and attr_writer
    7. Experiment 4-2: Exploring How Ruby Implements Keyword Arguments
    8. Summary
  12. 5. Objects and Classes
    1. Inside a Ruby Object
      1. Inspecting klass and ivptr
      2. Visualizing Two Instances of One Class
      3. Generic Objects
      4. Simple Ruby Values Don’t Require a Structure at All
      5. Do Generic Objects Have Instance Variables?
      6. Where Does Ruby Save Instance Variables for Generic Objects?
    2. Experiment 5-1: How Long Does It Take to Save a New Instance Variable?
    3. What’s Inside the RClass Structure?
      1. Inheritance
      2. Class Instance Variables vs. Class Variables
      3. Getting and Setting Class Variables
      4. Constants
      5. The Actual RClass Structure
    4. Experiment 5-2: Where Does Ruby Save Class Methods?
    5. Summary
  13. 6. Method Lookup and Constant Lookup
    1. How Ruby Implements Modules
      1. Modules Are Classes
      2. Including a Module into a Class
    2. Ruby’s Method Lookup Algorithm
      1. A Method Lookup Example
      2. The Method Lookup Algorithm in Action
      3. Multiple Inheritance in Ruby
      4. The Global Method Cache
      5. The Inline Method Cache
      6. Clearing Ruby’s Method Caches
      7. Including Two Modules into One Class
      8. Including One Module into Another
      9. A Module#prepend Example
      10. How Ruby Implements Module#prepend
    3. Experiment 6-1: Modifying a Module After Including It
      1. Classes See Methods Added to a Module Later
      2. Classes Don’t See Submodules Included Later
      3. Included Classes Share the Method Table with the Original Module
    4. Constant Lookup
      1. Finding a Constant in a Superclass
      2. How Does Ruby Find a Constant in the Parent Namespace?
    5. Lexical Scope in Ruby
      1. Creating a Constant for a New Class or Module
      2. Finding a Constant in the Parent Namespace Using Lexical Scope
      3. Ruby’s Constant Lookup Algorithm
    6. Experiment 6-2: Which Constant Will Ruby Find First?
      1. Ruby’s Actual Constant Lookup Algorithm
    7. Summary
  14. 7. The Hash Table: The Workhorse of Ruby Internals
    1. Hash Tables in Ruby
      1. Saving a Value in a Hash Table
      2. Retrieving a Value from a Hash Table
    2. Experiment 7-1: Retrieving a Value from Hashes of Varying Sizes
    3. How Hash Tables Expand to Accommodate More Values
      1. Hash Collisions
      2. Rehashing Entries
    4. Experiment 7-2: Inserting One New Element into Hashes of Varying Sizes
    5. How Ruby Implements Hash Functions
    6. Experiment 7-3: Using Objects as Keys in a Hash
      1. Hash Optimization in Ruby 2.0
    7. Summary
  15. 8. How Ruby Borrowed a Decades-Old Idea from Lisp
    1. Blocks: Closures in Ruby
      1. Stepping Through How Ruby Calls a Block
      2. Borrowing an Idea from 1975
    2. Experiment 8-1: Which Is Faster: A while Loop or Passing a Block to each?
    3. Lambdas and Procs: Treating a Function as a First-Class Citizen
      1. Stack vs. Heap Memory
      2. A Closer Look at How Ruby Saves a String Value
      3. How Ruby Creates a Lambda
      4. How Ruby Calls a Lambda
      5. The Proc Object
    4. Experiment 8-2: Changing Local Variables After Calling lambda
      1. Calling lambda More Than Once in the Same Scope
    5. Summary
  16. 9. Metaprogramming
    1. Alternative Ways to Define Methods
      1. Ruby’s Normal Method Definition Process
      2. Defining Class Methods Using an Object Prefix
      3. Defining Class Methods Using a New Lexical Scope
      4. Defining Methods Using Singleton Classes
      5. Defining Methods Using Singleton Classes in a Lexical Scope
      6. Creating Refinements
      7. Using Refinements
    2. Experiment 9-1: Who Am I? How self Changes with Lexical Scope
      1. self in the Top Scope
      2. self in a Class Scope
      3. self in a Metaclass Scope
      4. self Inside a Class Method
    3. Metaprogramming and Closures: eval, instance_eval, and binding
      1. Code That Writes Code
      2. Calling eval with binding
      3. An instance_eval Example
      4. Another Important Part of Ruby Closures
      5. instance_eval Changes self to the Receiver
      6. instance_eval Creates a Singleton Class for a New Lexical Scope
    4. Experiment 9-2: Using a Closure to Define a Method
      1. Using define_method
      2. Methods Acting as Closures
    5. Summary
  17. 10. JRuby: Ruby on the JVM
    1. Running Programs with MRI and JRuby
      1. How JRuby Parses and Compiles Your Code
      2. How JRuby Executes Your Code
      3. Implementing Ruby Classes with Java Classes
    2. Experiment 10-1: Monitoring JRuby’s Just-in-Time Compiler
      1. Experiment Code
      2. Using the -J-XX:+PrintCompilation Option
      3. Does JIT Speed Up Your JRuby Program?
    3. Strings in JRuby and MRI
      1. How JRuby and MRI Save String Data
      2. Copy-on-Write
    4. Experiment 10-2: Measuring Copy-on-Write Performance
      1. Creating a Unique, Nonshared String
      2. Experiment Code
      3. Visualizing Copy-on-Write
      4. Modifying a Shared String Is Slower
    5. Summary
  18. 11. Rubinius: Ruby Implemented with Ruby
    1. The Rubinius Kernel and Virtual Machine
      1. Tokenization and Parsing
      2. Using Ruby to Compile Ruby
      3. Rubinius Bytecode Instructions
      4. Ruby and C++ Working Together
      5. Implementing Ruby Objects with C++ Objects
    2. Experiment 11-1: Comparing Backtraces in MRI and Rubinius
      1. Backtraces in Rubinius
    3. Arrays in Rubinius and MRI
      1. Arrays Inside of MRI
      2. Arrays Inside of Rubinius
    4. Experiment 11-2: Exploring the Rubinius Implementation of Array#shift
      1. Reading Array#shift
      2. Modifying Array#shift
    5. Summary
  19. 12. Garbage Collection in MRI, JRuby, and Rubinius
    1. Garbage Collectors Solve Three Problems
    2. Garbage Collection in MRI: Mark and Sweep
      1. The Free List
      2. Marking
      3. How Does MRI Mark Live Objects?
      4. Sweeping
      5. Lazy Sweeping
      6. Disadvantages of Mark and Sweep
    3. Experiment 12-1: Seeing MRI Garbage Collection in Action
      1. Seeing MRI Perform a Lazy Sweep
      2. Seeing MRI Perform a Full Collection
      3. Interpreting a GC Profile Report
    4. Garbage Collection in JRuby and Rubinius
    5. Copying Garbage Collection
      1. Bump Allocation
      2. The Semi-Space Algorithm
      3. The Eden Heap
    6. Generational Garbage Collection
      1. The Weak Generational Hypothesis
      2. Using the Semi-Space Algorithm for Young Objects
      3. Promoting Objects
      4. Garbage Collection for Mature Objects
    7. Concurrent Garbage Collection
      1. Marking While the Object Graph Changes
      2. Tricolor Marking
      3. Three Garbage Collectors in the JVM
    8. Experiment 12-2: Using Verbose GC Mode in JRuby
      1. Triggering Major Collections
    9. Further Reading
    10. Summary
  20. Index
  21. Copyright