Ruby Cookbook

Lucas Carlson and Leonard Richardson

O'REILLY' Beijing • Cambridge • Farnham • Köln • Paris • Sebastopol • Taipei • Tokyo Tableof Contents

Preface xix 1. Strings 1 1.1 Building a String from Parts 4 1.2 Substituting Variables into Strings 6 1.3 Substituting Variables into an Existing String 8 1.4 Reversing a String by Words or Characters 10 1.5 Representing Unprintable Characters 11 1.6 Converting Between Characters and Values 14 1.7 Converting Between Strings and Symbols 14 1.8 Processing a String One Character at a Time 16 1.9 Processing a String One Word at a Time 17 1.10 Changing the Case of a String 19 1.11 Managing Whitespace 21 L12 Testing Whether an Object Is String-Like 22 1.13 Getting the Partsofa String YouWant 23 1.14 Handling International Encodings 24 1.15 Word-Wrapping Lines of Text 26 1.16 Generating aSuccession of Strings 28 1.17 Matching Strings with Regulär Expressions 30 1.18 Replacing Multiple Patterns in a Single Pass 32 1.19 Validating an Email Address 33 1.20 Classifying Text with a Bayesian Analyzer 37 2. Numbers ..... 39 2.1 Parsing a Number from a String 40 2.2 Comparing Floating-Point Numbers 43 2.3 Representing Numbers to Arbitrary Precision 45 2.4 Representing Rational Numbers . 48 2.5 Generating Random Numbers 50 2.6 Converting Between Numeric Bases 52 2.7 Taking Logarithms 53 2.8 Finding Mean, Mediän, and Mode 55 2.9 Converting Between Degrees and Radians 58 2.10 Multiplying Matrices 60 2.11 Solving a System of Linear Equations 64 2.12 Using Complex Numbers 67 2.13 Simulating a Subclass of Fixnum 69 2.14 Doing Math with Roman Numbers 73 2.15 Generating a Sequerice of Numbers 78

2.16 Generating Prime Numbers ..• :81 2.17 Checking a Credit Card Checksum . 85

3. Date and Time 87 3.1 Finding Today's Date ' 90 3.2 Parsing Dates, Precisely or Fuzzily 93 3.3 Printing a Date 96 3.4 Iterating Over Dates 100 3.5 Doing Date Arithmetic 102 3.6 Counting the Days Since an Arbitrary Date 104 3.7 Converting Between Time Zones 106 3.8 Checking Whether Daylight Saving Time Is in Effect 109 3.9 Converting Between Time and DateTime Objects 110 3.10 Finding the Day of the Week 113 3.11 Handling Commercial D ates 115 3.12 Running a Code Block Periodically 116 3.13 Waiting a Certain Amount of Time 118 3.14 Adding a Timeout to a Long-Running Operation 121

4. Arrays 123 4.1 Iterating Over an Array 125 4.2 Rearranging Values Without Using Temporary Variables 129 4.3 Stripping Duplicate Elements from an Array 130 4.4 Reversing an Array . 132 4.5 Sorting an Array 132 4.6 Ignoring Case When Sorting Strings 134

viii I Tableof Contents 4.7 Making Sure a Sorted Array Stays Sorted 135 4.8 Summing the Items of an Array 140 4.9 Sorting an Array by Frequency of Appearance 141 4.10 Shuffling an Array 143 4.11 Getting the N Smallest Items of an Array 145 - 4.12 Building Up a Hash Using Injection 147 4.13 Extracting Portions of Arrays 149 4.14 Computing Set Operations on Arrays 152 4.15 Partitioning or Classifying a Set 155

5. Hashes ... . 159 5.1 Using Symbols as Hash Keys 161 5.2 Creating a Hash with a Default Value 162 5.3 Adding Elements to a Hash 164 5.4 Removing Elements from a Hash 166 5.5 Using an Array or Other Modifiable Object as a Hash Key 168 5.6 Keeping Multiple Values for the Same Hash Key 170 5.7 Iterating Over a Hash 171 5.8 Iterating Over a Hash in Insertion Order 174 5.9 Printing a Hash 175 5.10 Invertmg a Hash . 177 5.11 Choosing Randomly from a Weighted List 179 5.12 Building a Histogram 181 5.13 Remapping the Keys and Values of a Hash 183 5.14 Extracting Portions of Hashes 184 5.15 Searching a Hash with Regulär Expressions 185

6. Files and Directories 187 6.1 Checking to See If a File Exists . 190 6.2 Checking Your Access to a File 191 6.3 Changing the Permissions on a File 193 6.4 Seeing When a File Was Last Used 196 6.5 Listing a Directory 198 6.6 Reading the Contents of a File 201 6.7 Writing to a File ' 204 6.8 Writing to a Temporary File 206 6.9 Picking a Random Line from ä File 207 6.10 Comparing Two Files 209 6.11 Performing Random Access ori "Reäd-Once" Input Streams 212

Tahlpnffnntpnt«; I 6.12 Walking a Directory Tree 214 6.13 Lockinga File 217 6.14 Backing Up to Versioned Filenames 220 6.15 Pretending a String Is a File 222 6.16 Redirecting Standard Input or Output , 225 6.17 Processing a Binary File 227 6.18 Deletinga File • 231 6.19 Truhcatinga File 232 6.20 Finding the Files You Want 233 6.21 Finding and Changing the Current Working Directory 235

7. Code Blocks and Iteration 237 7.1 Creating and Invoking a Block .. 240 7.2 Writing a Method That Accepts a Block 241 7.3 Binding a Block Argument to a Variable . 244 7.4 Blocks as Closures: Using Outside Variables Within a Code Block 246 7.5 Writing an Iterator Over a Data Structure 247 7.6 Changing the Way an Object Iterates 250 7.7 Writing Block Methods That Classify or Collect 253 7.8 Stopping an Iteration 254 7.9 Looping Through Multiple Iterables in Parallel 256 7.10 Hiding Setup and Cleanup in a Block Method 260 7.11 Coupling Systems Loosely with Callbacks 262

8. Objects and Classes 267 8.1 Managing Instance Data 269 8.2 Managing Class Data 272 8.3 Checking Class or Module Membership 275 8.4 Writing an Inherited Class 277 8.5 Overloading Methods 279 8.6 Validating and Modifying Attribute Values 281 8.7 Defining a Virtual Attribute . 283 8.8 Delegating Method Calls to Another Object 284 8.9 Converting and Coercing Objects to Different Types 287 8.10 Getting a Hüman-Readable Printout of Any Object 291 8.11 Accepting or Passing a Variable Number of Arguments 293 8.12 Simulating Keyword Arguments . 295 8.13 Calling a Superclass's Method 297 8.14 Creating an Abstract Method 299

x I Tafale of Contents 8.15 Freezing an Object to Prevent Changes 302 8.16 Making a Copy of an Object 304 8.17 Declaring Constants 307 8.18 Implementing Class and Singleton Methods 309 8.19 Controlling Access by Making Methods Private 311

9. Modulesand Namespaces ., 315 9.1 Simulating Multiple Inheritance with Mixins 315 9.2 Extending Specific Objects with Modules 319 9.3 Mixing in Class Methods 321 9.4 Implementing Enumerable: Write One Method, Get 22 Free 322 9.5 Avoiding Naming Collisions with Namespaces 324 9.6 Automatically Loading Libraries as Needed 326 9.7 Including Namespaces 328 9.8 Initializing Instance Variables Defined by a Module 329 9.9 Automatically Initializing Mixed-In Modules 330

10. Reflection and Metaprogramming 333 10.1 Finding an Object's Class and Superclass . 334 10.2 Listing an Object's Methods 335 10.3 Listing Methods Unique to an Object 337 10.4 Getting a Reference to a Method 339 10.5 Fixing Bugs in Someone Else's Class 341 10.6 Listening for Changes to a Class 343 10.7 Checking Whether an Object Has Necessary Attributes 345 10.8 Responding to Calls to Undefined Methods 347 10.9 Automatically Initializing Instance Variables 351 10.10 Avoiding Boilerplate Code with Metaprogramming 352 10.11 Metaprogramming with String Evaluations 355 10.12 Evaluating Code in an Earlier Context 357 10.13 Undefining a Method 358 10.14 Aliasing Methods . 361 10.15 Doing Aspect-Oriented Programming 364 10.16 Enforcing Software Contracts 367

11. XML and HTML 371 11.1 Checking XML Well-Formedness 372 11.2 Extracting Data from a Document's Tree Structure 374 11.3 Extracting Data While Parsing a Document 376

Tahlertf fnntantt I vi 11.4 Navigating a Document with XPath 377 11.5 Parsing Invalid Markup 380 11.6 Converting an XML Document into a Hash 382 11.7 Validatirig an XML Document 385 11.8 Substituting XML Entities 388 11.9 Creating and Modifying XML Documents 390 11.10 Compressing Whitespace in an XML Document 394 11.11 Guessing a Document's Encoding 395 11.12 Converting from One Encoding to Another 396 11.13 Extracting All the URLs from an HTML Document 398 11.14 Transforming Piain Text to HTML 401 11.15 Converting HTML Documents from the Web into Text 402 11.16 A Simple Feed Aggregator 405

12. Graphics and Other File Formats 409 12.1 Thumbnailing Images 409 12.2 Adding Text to an Image , 412 12.3 Converting One Image Format to Another 415 12.4 GraphingData 417 12.5 Adding Graphical Context with Sparklines 421 12.6 Strongly Encrypting Data 424 12.7 Parsing Comma-Separated Data 426 12.8 Parsing Not-Quite-Comma-Separated Data 429 12.9 Generating and Parsing Excel Spreadsheets 431 12.10 Compressing and Archiving Files with Gzip and Tar 433 12.11 Reading and Writing ZIP Files 436 12.12 Reading and Writing Configuration Files 437 12.13 Generating PDF Files 439 12.14 Representing Data as MIDI Music 443

13. Databases and Persistence 447 13.1 Serializing Data with YAML 450 13.2 Serializing Data with Marshai 454 13.3 Persisting Objects with Madeleine 455 13.4 Indexing Unstructured Text with SirnpleSearch 458 13.5 Indexing Structured Text with Ferret 45 9 13.6 Using Berkeley DB Databases 463 13.7 Controlling MySQL on Unix 465 13.8 Finding the Number of Rows Returned by a Query 466 13.9 Talking Directly to a MySQL Database 468 13.10 Talking Directly to a PostgreSQL Database . 470 13.11 Using Object Relational Mapping with ActiveRecord 473 13.12 Using Object Relational Mapping with Og . 477 13.13 Building Queries Programmatically • 481 ' 13.14 Validating Data with ActiveRecord 485 13.15 Preventing SQL Injection Attacks 487 13.16 Using Transactions in ActiveRecord 490 13.17 Adding Hooks to Table Events 492 13.18 Adding Taggability with a Database Mixin 495

14. Internet Services , 499 14.1 Grabbing the Contents of a Web Page 500 14.2 Making an HTTPS Web Request 502 14.3 Customizing HTTP Request Headers 504 14.4 Performing DNS Queries 506 14.5 SendingMail 508 14.6 Reading Mail with IMAP 512 14.7 Reading Mail with POP3 516 14.8 Being an FTP Client 520 14.9 Being a Telnet Client 522 14.10 Being an SSH Client 525 14.11 Copying a File to Another Machine 527 14.12 Being a BitTorrent Client 529 14.13 Pinging a Machine 531 14.14 Writing an Internet Server 532 14.15 Parsing URLs 534 14.16 Writing a CGI Script 537 14.17 Setting Cookies and Other HTTP Response Headers 540 14.18 Handling File Uploads via CGI 543 14.19 Running Servlets with WEBrick 546 14.20 A Real-World HTTP Client 551

15. Web Development: 555 15.1 Writing a Simple Rails Application to Show System Status 557 15.2 Passing Data from the Controller to the View 560 15.3 Creating a Layout for Your Header and Footer 563 15.4 Redirecting to a Different Location 565 15.5 Displaying Templates with Render 567

Tahlenf fnnhsrttc I viii 15.6 Integratinga Database with Your Rails Application 570 15.7 Understanding Pluralization Rules 573 15.8 Creating a Lögm System 575 15.9 Storing Hashed User Passwords in the Database 579 15.10 Escaping HTML and JavaScript for Display 581 15.11 Setting and Retrieving Session Information • 582 15.12 Setting and Retrieving Cookies 585 15.13 Extracting Code into Helper Functions 587 15.14 Refactoring the View into Partial Snippets of Views 588 15.15 Adding DHTML Effects with script.aculo.us 592 15.16 Generating Forms for Manipulating Model Objects 594 15.17 Creating an Ajax Form 598 15.18 Exposing Web Services on Your Web Site 601 15.19 Sending Mail with Rails 604 15.20 Automatically Sending Error Messages to Your Email 606 15.21 Documenting Your Web Site 608 15.22 Unit Testing Your Web Site 609 15.23 Using breakpoint in Your Web Application 613

16. Web Services and Distributed Programming 616 16.1 Searching for Books on Amazon 617 16.2 Finding Photos on Flickr 620 16.3 Writing an XML-RPC Client 623 16.4 Writing a SOAP Client 625 16.5 Writing a SOAP Server 627 16.6 Searching the Web with Google's SOAP Service 628 16.7 Using a WSDL File to Make SOAP Calls Easier 630 16.8 Charging a Credit Card 632 16.9 Finding the Cost to Ship Packages via UPS or FedEx 633 16.10 Sharing a Hash Between Any Number of Computers 635 16.11 Implementing a Distributed Queue 639 16.12 Creating aShared "Whiteboard" , 640 16.13 Securing DRb Services with Access Control Lists 644 16.14 Automatically Discovering DRb Services with Rinda 645 16.15 Proxyirig Objects That Can't Be Distributed 647 16.16 Storing Data on Distributed RAM with MemCached 650 16.17 Cachmg Expensive Results with MemCached 652 16.18 ARemote-Controlled Jukebox 655 17. Testing, Debugging, Optimizing, and Documenting 661 17.1 Running Code Only in DebugMode 662 17.2 Raising an Exception 664 17.3 Handling an Exception 666 17.4 Rerunning After an Exception 668 - 17.5 Adding Logging tö Your Application 669 17.6 Creatingjand Understanding Tracebacks 672 17.7 Writing tJnit Tests 674 17.8 Running Unit Tests . 677 17.9 Testing Code That Uses External Resources 6.79 17.10 Using breakpoint to Inspect and Change the State of Your Application 684 17.11 Documenting Your Application 686 17.12 Profiling Your Application 691 17.13 Benchmarking Competing Solutions 694 17.14 Running Multiple Analysis Tools at Once 696 17.15 Who's Calling That Method? A Call Graph Analyzer 697

18. PackagingandDistributihgSoftware ... 701 18.1 Finding Libraries by Querying Gern Respositories 702 18.2 Installing and Using a Gern 705 18.3 Requiring a Specific Version of a Gern 708 18.4 Uninstalling a Gern 711 18.5 Reading Documentation for Installed Gems 712 18.6 Packaging Your Code as a Gern 714 18.7 Distributing Your Gems 717 18.8 Installing and Creating Standalone Packages with setup.rb 719

19. Automating Tasks with 723 19.1 Automatically Running Unit Tests 725 19.2 Automatically Generating Documentation 727 19.3 Cleaning Up Generated Files 729 19.4 Automatically Building a Gern 731 19.5 Gathering Statistics About Your Code 732 19.6 Publishing Your Documentation 735 19.7 Running Multiple Tasks in Parallel 737 19.8 A Generic Project Rakefile 738

Tahlonf fnntnntc I vu 20. Multitasking and Multithreading 745 20.1 Running a Daemon Process on Unix 746 20.2 Creating a Windows Service 749 20.3 Doing Two Things at Once with Threads 752 20.4 Synchronizing Access to an Object 754 20.5 Terminating a Thread 757 20.6 Running a Code Block on Many Objects Simultaneously 760 20.7 Limiting Multithreading with a Thread Pool 763 20.8 Driving an External Process with popen 765 20.9 Capturing the Output and Error Streams from a Unix Shell Command 767 20.10 Controlling a Process on Another Machine 768 20.11 Avoiding Deadlock 770 21. User Interface . ,., ...... 773 21.1 Getting Input One Line at a Time 774 21.2 Getting Input One Character at a Time 776 21.3 Parsing Command-Line Arguments 779 21.4 Testing Whether a Program Is Running mteractively 782 21.5 Setting Up and Tearing Down aCurses Program 782 21.6 Clearing the Screen 785 21.7 Determining Terminal Size 786 21.8 Changing Text Color 788 21.9 Reading a Password 791 21.10 Allowing Input Editing with Readline 792 21.11 Making Your Keyboard Lights Blink 794 21.12 Creating a GUI Application with Tk 796 21.13 Creating a GUI Application with wxRuby 800 21.14 Creating a GUI Application with Ruby/GTK 803 21.15 Creating a Mac OS X Application with RubyCocoa 807 21.16 Using AppleScript to Get User Input 815

22. Extending Ruby with Other Languages 817 22.1 Writing a Extension for Ruby - 818 22.2 Using a C Library from Ruby 821 22.3 CallingaC Library Through SWIG ' 825 22.4 Writing Inline C in Your Ruby Code 827 22.5 Using Java Libraries with JRuby 830

xvi I Tableof Contents' 23. System Administration ... 833 23.1 Scripting an External Program 834 23.2 Managing Windows Services 835 23.3 Running Code as Another User 837 23.4 Running Periodic Tasks Without cron or at 839 23.5 Deleting Files That Match a Regulär Expression 840 23.6 Renaming Files in Bulk 842 23.7 Finding Duplicate Files 845 23.8 Automating Backups 848 23.9 Normalizing Ownership and Permissions in User Directories 849 23.10 Killing All Processes for a Given User 852

Index f. 855

Tahlo nf f nntonte I vwii