Recently in ruby Category

My Ruby Book on your iPhone. Cheap!

| 3 Comments

O'Reilly has just released The Ruby Programming Language as a standalone iphone app! Looks like you can get your hands on it for just $5 (The cover price of the print edition is $40.) I don't have an iphone, but if you do, I'd love to hear how the book looks and works for you in that format.

At the same time, O'Reilly has dropped the ebook price for other readers from $30 to $10. Amazon's Kindle price is still $18 today. I don't know if that is going to go down or not. (Update 8/27: the kindle price is now $8.)

I'm not sure how I feel about O'Reilly using my book for their marketing experiments, but it's certainly a good deal for readers. So I ask for your help in making up for the reduced price with a massive increase in sales volume! :-)

And if I can engage in some more self-promotion: reviewers on Amazon think that this is the best book I've ever written. The 26 reviewers have all given it a 5-star rating, and the most recent review goes over the top and calls it "the best ever written programming language book". Wow. You know you want it on your iPhone!

Update: my editor says that he thinks this new ebook price is a temporary sale.

$SAFE is Proc-local

| 1 Comment

While researching Ruby's new-in-1.9 Object methods untrusted?, untrust, and trust, I discovered something I did not know about the $SAFE variable: in addition to being Thread-local, it is also Proc-local. Proc objects (both procs and lambdas) have their own copy of $SAFE, and they run at whatever $SAFE level was in effect when the Proc was created not the safe level that is in effect when they are invoked. This was discussed three years ago over at _why's old blog.

There is a corollary, however that was demonstrated but not discussed in a recent ruby-core post by Shugo Maeda: if you set $SAFE inside a proc or a lambda, that setting is local, and does not change the global safe level. Googling for "safe_eval" implementations shows that everyone uses Thread.new to create a sandbox with a locally elevated safe level. It turns out, however, that an ordinary lambda will also work. (One can argue, however, that a thread gives extra safety because it can be monitored and killed to guard against runaway code that doesn't terminate.)

In any case, here is the method I defined to try this out. Pass it a safe level (it defaults to 4) and a block of code, and it will execute the block at that level without altering the global safe level and without creating a new thread:

# Execute a block at the specified safe level. Tested with Ruby 1.9 and 1.8.7
def safely(level = 4)
  sandbox = lambda do # Set up a sandbox 
    $SAFE = level     # Go to the specified safe level for this lambda only
    yield             # Invoke the block at that level
  end
  sandbox.call        # Invoke the sandbox without changing $SAFE globally
end

# Use this method like this. 
x = safely { eval('"untrusted code"') }
[x, x.tainted?, x.untrusted?]  # => ["untrusted code", true, true]

I'm not convinced that this method is actually useful in practice, but I thought it was interesting, and it reminds me again how cool it is to be able to define methods that accept blocks and act like control statements.

Ruby Review Roundup

| 2 Comments

The Ruby Programming Language has been gratifyingly well received by readers and reviewers. In addition to glowing reviews at rubyinside.com and slashdot.org, it has been reviewed ten times at amazon.com and I proud to say that all ten reviews give it a five-star rating.

Here are the reviews. For all except the slashdot review, the linked text is the title of the review:

Thanks everyone!

Errata for my Ruby Book

I've put together a list of 81 errors and updates to my Ruby book. These are fixed in the next printing. If you already own a copy of the book, however, you can go through and enter the changes yourself, if you are so inclined.

I use O'Reilly's style for describing the changes. Each entry in the file begins with a page number within delimiter characters. The delimiters indicate the severity of the change:

  • Page numbers in parentheses usually indicate typos or other minor non-technical changes. You can ignore these if you want.
  • Page numbers in curly braces indicate minor technical errors that have been corrected
  • Page numbers in square braces indicate more severe technical errors that have been corrected. There are only two of these, but they're worth noting.
  • Page numbers in angle brackets are updates (this differs a bit from normal O'Reilly style) to keep the book in sync with the evolution of Ruby 1.9. In my opinion, these are the interesting ones.

I've posted my list of changes here. They will all eventually appear on O'Reilly's errata page for the book as well.

Help fix up my book, please

| 3 Comments

The Ruby Programming Language is going to be reprinted next week, and O'Reilly has given me SVN write access to the docbook files to fix typos, errors, etc. I've got a list of about 25 relatively minor erros that I'll be fixing, but I'd love to stomp out more bugs on this reprint.

So, if you've got a copy of the book, and have found typos, mistakes or omissions, please let me know. You can email me (david@ this domain) or post them as comments on this blog. (Normally, you'd submit them on the O'Reilly website but since time is factor for this reprint, send them directly to me, please.) Keep in mind that this is just a reprint, not a new edition of the book, so I'm pretty constrained about the kinds of changes I can make. I can't add new sections or figures or tables, or cover brand new topics that aren't currently covered. I can often squeeze in short new paragraphs when they're needed to clarify things or if there is something important that I left out.

Thanks to DH, MD, RM, and DB, all of whom submitted one or more errata to me or to O'Reilly's website recently. I don't have access to the names (or initials) of the others who submitted errata to the publisher's website back in March and February.

Update: Thanks to those (BR, CS, ADS, MD) who commented and emailed me with other errors to correct. I ended up making about 80 changes--half to fix typos and minor errors, and half to update the book to track minor (mostly) changes in Ruby 1.9. I'll post a list of all changes soon.

Welcome Slashdot Readers

| 1 Comment

If you arrived here after reading slashdot's review of The Ruby Programming Language, you've come to the right place. Thanks, Brian, for the kind words! The post below includes links to the book's table of contents and to an interactive preview.

Finally!

| 2 Comments

The Ruby Programming Language is finally in stock and shipping from online booksellers!

Press Release: actually quite a good overview of the book, who it is for and the niche it hopes to fill.

Preview: an interactive table-of-contents, with excerpts from each chapter and section.

Table of contents (in PDF form)

Buy it from:

I think (and hope) that this should be my last post flogging this book!

Preview my Ruby book

I've just discovered that the O'Reilly website now displays a browsable table of contents that allows you to preview the start of each chapter and each section of my book.

In other book news, Amazon is still listing the book for pre-order, so I guess the January 24th date isn't quite right.

Update: I received my copy from O'Reilly today, so the book has been printed, and Amazon should be shipping orders soon.

Second Update, (February 1st): Amazon now shows the book available for order, but is saying "two to three weeks" for shipping. The folks in the know at O'Reilly say that books are on their way from the O'Reilly warehouse to the Amazon warehouse, and Amazon should start shipping them out by mid-week. In the meantime, it looks as if oreilly.com is the only place that is currently shipping copies of the book. I was under the mistaken impression that books went directly from the printer to major booksellers like Amazon. Given these normal and predictable shipping delays, I don't know why Amazon listed 1/24 as the availability date for so long.

They still seem to be offering the extra 5% discount. I've also discovered that you can get an even better price on it at buy.com (though they don't have it in stock yet, either).

Finally, the book is available now online (for preview or by subscription) at Safari.

Examples from my Ruby book now online

| 4 Comments

All the example code from my Ruby book is now available for download.

As I've mentioned before, you can also browse the book's table of contents.

Last day for Amazon's pre-order discount

Amazon continues to say that my Ruby book will be in stock tomorrow. So today is the last day that you can pre-order the book and save an additional 5% on it. As I type this, they're listing it at $26.39. After another 5%, you'd be paying just over $25, which is pretty good for a $40 book.

Off to the Printer

| 6 Comments

The Ruby Programming Language was sent to the printer on Friday the 11th, and should be printed and bound on Monday January 21st. This is on schedule. Amazon still says that they expect to start fulfilling orders on January 24th. I don't know the logistics of getting copies from the printer to Amazon, but it seems likely that they can meet (or come close) to that date.

I've uploaded a pdf of the final frontmatter in case you'd like to browse the table of contents to see what material I cover. (My older, homebrew TOC is a little out of date but includes 2nd-level section titles as well as the top-level sections, so it gives quite a bit more detail about the book's contents.)

I've seen the book get as high as #64 on Amazon's list of bestselling programming books even before it is released. It's fallen off the list today, but if you pre-order it now, maybe it will come back on! :-)

Update: In the comments, Adriano asks a good (and common) question about the stability of Ruby 1.9. I'm posting my response here:

Adriano,

Thanks for your comment. I hope my book can meet your expectations! I should make clear that this book is a language reference, but not an API reference. Unlike my JavaScript book, there is not a section that documents each class and method of the core library. (Though there is a long example-based chapter that demonstrates the most important classes of the core library.)

Matz has changed the release numbering scheme for this release of Ruby. 1.9.x will be a stable version of the language, not a development version, despite the fact that 9 is an odd number. The original intent, I believe, was to release 1.9.1 on Christmas. But the code was not stable enough. So Matz's Christmas release is still called 1.9.0, and is effectively a beta-release of 1.9. Matz does not yet recommend it for production use, but it is stable enough to begin porting applications to.

The Christmas release of 1.9.0 was nominally an API freeze as well. There have been, and will continue to be minor API changes between 1.9.0 and 1.9.1, but there shouldn't be many of them: the intent is to keep the API frozen.

My book went to the printer after the Christmas release, so it covers everything that was in the frozen 1.9.0 release, and even a couple of changes that happened after the release. I may have to release a few errata when 1.9.1 comes out, but overall, this book should have very complete coverage of 1.9.x

Giles Bowkett Replaced by Mindless Fanboy

| 2 Comments

This post, and its title, is a response to Giles Bowkett's clairvoyant review of my Ruby book. In that review, he says:

  • I am "soulless",
  • my publisher was "really cool once", and that
  • you "sure as hell don't want a copy of Flanagan's upcoming book".

The book is not out yet, and as far as I know no one has shown him one of the drafts circulated at ruby-conf. He bases his opinions on one comment I posted on Sam Ruby's blog.

The crux of Giles's argument is apparently that O'Reilly was disrespectful to the Ruby community because they're "publishing something by an author...who isn't even a significant part of the community".

Being called "soulless" (that's a fighting word, Giles) makes me angry, but this "in group" nonsense is what gets under my skin and is why I'm taking this fight to my blog. Had Giles been a participant in the ruby-core mailing list he would know that I've been an active member of that list for almost a year. He might also know that I have commit privileges and have made small but non-trivial contributions (such as implementing \u Unicode escapes in string literals) to the Ruby 1.9 codebase.

I've spent a year and a half learning and writing about Ruby. I've argued vocally for changes to the language and I've implemented changes to the language. Of course I'm part of the Ruby community. What Giles really means is that I'm not part of the Ruby club, of which Giles fancies himself a member. I have to say that this fanboy boosterism that pervades certain Ruby circles is a real turn off for newcomers to the language. The Ruby club has never managed to produce competent (English-language) documentation of the language, Giles. How can you blame O'Reilly for asking an experienced writer to do the job?

Giles writes:

Bear in mind this...comes from somebody who's programming and blogging at 11pm on a Friday

You need to learn, Giles, that insults posted on a blog at 11pm on a Friday can still be gracefully retracted...it would be soulful thing to do.

(I should make clear that I do not know Giles. The title of this post parallels the title of his post, but I do not really know if he is a mindless fanboy, or just acts like one sometimes.)

Surprise!

| 4 Comments

In the post below I hinted at a secret contributor, besides Matz and myself, to the Ruby book. Amazon now displays the latest cover design for the book, and all can now be revealed....

To find out who's contribution I am honored to have in this book, click on the Amazon.com link to the right to visit the pre-order page for the book. This will let you see the cover at a readable size--look for the "see larger image" link. If you've been working with Ruby for a while, you will recognize the new name on the cover.

And when you've recovered from your surprise, you can pre-order your copy of the book! :-)

Update: the name has now disappeared from the cover. I don't know why. When I first posted this, it read: "with drawings by why the lucky stiff"

Ruby book into production

| 2 Comments

I've submitted my Ruby book to the production department at O'Reilly.They're going to allow me to make last minute changes as the final details (mainly IO encoding issues) are implemented in Ruby 1.9, but it really is going to get printed in very early 2008. (At the risk of repeating myself, let me suggest that you pre-order it now!)

In other news, the cover (which you can see enlarged in the post below) is being modified to add another name alongside mine and Matz's. I'm keeping this a surprise for now, but I will say that the name is well-known within the Ruby community, and that I think everyone will be happy with this person's contribution to the book!

O'Reilly Animal for my Ruby Book: Sungems

| 1 Comment

My upcoming book, The Ruby Programming Language, now has cover art!. Here it is (hotlinked from amazon):

The birds on the cover are Horned Sungem hummingbirds. (Ruby-throated hummingbirds would have been nice, too, but these are beautiful birds and have "gem" in their name!) Here are photos showing the "horns" on the male and the cool-looking tail.

The Wikipedia entry has this to say about horned sungems:

The Horned Sungem (Heliactin bilophus) is a South American hummingbird, the only species of the genus Heliactin. The scientific name bilophus is sometimes considered a nomen oblitum, which, if accepted, results in Heliactin cornutus being the correct name for this species. It can achieve 90 wingbeats per second when it's hovering to drink nectar from flowers. A wingbeat is one complete up-and-down movement, which means that the horned sungem moves its wing muscles at a rate of more than 10,000 times per minute. It prefers fairly dry open or semi-open habitats, such as savanna and Cerrado. It avoids dense humid forest.

The book is nearing completion and I hope it will be available within one month of the release of Ruby 1.9. Pre-order it today! Your enthusiastic (I hope :-) pre-orders will help O'Reilly know how many copies to print. And amazon.com offers an additional 5% discount on these early orders.

New Book: The Ruby Programming Language

| 13 Comments

I am pleased to announced that I'm nearing completion of The Ruby Programming Language, an updated and expanded version of Matz's Ruby in a Nutshell. It will be published by O'Reilly in early 2008 and is available for pre-order now at Amazon.com

Here's how I describe the book in the preface:

This book is an updated version of Matz's book Ruby in a Nutshell which has been expanded well beyond O'Reilly's Nutshell format. As its new title implies, this book covers the Ruby programming language and aspires to do so comprehensively while still being accessible to any experienced programmer who takes the time to read it carefully. This first edition of the book covers Ruby 1.8 and Ruby 1.9.

Ruby blurs the distinction between language and platform, and so the coverage of the language includes a detailed overview of the core Ruby API. But this book is not an API reference and does not attempt to document every class and every method of the core library. Also, this is not a book about Ruby frameworks (like Rails) nor a book about Ruby tools (like rake and gem). This book does not attempt to teach OO programming, or any kind of programming methodology. And although this book documents Ruby authoritatively, it is not intended as a specification for the language: language implementers will need more than this book to correctly implement Ruby.

If you're going to be at RubyConf this weekend, my editor from O'Reilly will have drafts of the book that you can take a look at. If you're not going to be there, you can't see the book itself, but you can browse the table of contents to get an idea of the breadth and depth of the language coverage. (This TOC includes a relatively short table of examples. The book actually contains quite a bit of example code, but most of the examples are unnumbered and don't appear in the TOC.)

I've been working on this book for about a year now and am very excited about it. My hope is that it will be for Ruby what JavaScript: The Definitive Guide is for JavaScript!

Fluent Programming in Ruby

| 3 Comments

Matz has just checked a change into the Ruby 1.9 tree to allow programming with fluent interfaces. The change is marked "experimental", but if it stays in the tree, we'll be able to write Ruby code like this:

puts "hello"
        .upcase
        .reverse
        .slice(0)    # => Prints "O"

(This is a silly example; Martin Fowler's page linked above has more compelling examples of this style of method chaining.)

We've always been able to do method chaining in Ruby, of course. What Matz's patch does is allow newlines in between the methods. This is tricky in languages like Ruby that don't require semicolons because newlines usually act as the statement terminators. So with this new modification a newline does not terminate a statement if the first non-space character on the following line is a period.

P.S. In case it hasn't been obvious from my recent postings on Ruby, I'm writing a book about Ruby. And I'm nearly done!

Fibonacci numbers with Ruby 1.9 Fibers

Here's how to use the new Fiber class (warning: class name may change) to generate an infinite sequence of Fibonacci numbers. I use "generate" in the sense of Python's generators. Ruby's new fibers are "semi-coroutines"

fib = Fiber.new do 
  x, y = 0, 1
  loop do 
    Fiber.yield y
    x,y = y,x+y
  end
end

20.times { puts fib.resume }

Remember that the Fiber class was added to Ruby 1.9 yesterday, so you need a very recent snapshot to make this work.

Here's a slightly higher-level way to do the Fibonacci numbers. We hide the Fiber class inside of a Generator class:

class Generator
  def initialize &block
    @f = Fiber.new &block
  end

  def next?
    @f.alive?
  end

  def next(*args)
    @f.resume(*args)
  end
end

fib2 = Generator.new do 
  x, y = 0, 1
  loop do 
    Fiber.yield y
    x,y = y,x+y
  end
end
20.times { puts fib2.next }

Coroutines (via fibers) in Ruby 1.9

As a followup to the post below, here is some example code using fibers to implement co-routines. This works in today's snapshot build, but it uses brand-new stuff, so it probably won't work if your build is more than a day old. Similarly, the API may change again, so it might not work if your snapshot is too new, either. svn.ruby-lang.org seems to be down (for me at least) right now, so I got my snapshot here: http://www.mirrorservice.org/sites/ftp.ruby-lang.org/pub/ruby/snapshot.tar.gz The code works for me on Linux, but I haven't tested it elsewhere:

f = g = nil

f = Fiber::Core.new { |x|
  puts "F1: #{x}"        
  x = g.transfer(x+1)    
  puts "F2: #{x}"
  x = g.transfer(x+1)
  puts "F3: #{x}"
}

g = Fiber::Core.new { |x|   
  puts "G1: #{x}"           
  x = f.transfer(x+1)
  puts "G2: #{x}"
  x = f.transfer(x+1)
}

f.transfer(100)

This code prints the following

F1: 100
G1: 101
F2: 102
G2: 103
F3: 104

Notice that the code uses the class Fiber::Core, and its instance method transfer. There is also a Fiber class, with a slightly higher-level API involving the instance method resume and the class method yield. I'm not sure exactly how these are intended to be used, but I was able to produce the same output as above using Fiber (instead of Fiber::Core) as follows:

g = Fiber.new { |x|
  puts "G1: #{x}"
  x = Fiber.yield(x+1)   # Can't use resume here: double resume error
  puts "G2: #{x}"
  x = Fiber.yield(x+1)
}

f = Fiber.new { |x|
  puts "F1: #{x}"
  x = g.resume(x+1)
  puts "F2: #{x}"
  x = g.resume(x+1)
  puts "F3: #{x}"
}

f.resume(100)

Update: Koichi SASADA notes on ruby-core:

Fiber::Core and Fiber::Core#transfer is black magic. So I'm planning to rename this class and method to Fiber::DangerousCore::__unsafe_transfer__I_cant_promise_your_program_run_correctly__!

He also says that the Fiber class is a "semi-coroutine" like Python's generator and that the method names Fiber.resume and Fiber::yield are taken from the language Lua. Time to go read up on Lua, I suppose

External Iterators in Ruby 1.9 Core!

| 1 Comment

Ruby 1.9 has, for a while now, supported Enumerators. These are Enumerable objects returned by iterator methods when the methods are invoked with no blocks. Until recently, Enumerators were still internal, Ruby-style iterators that you invoke with each.

But that has changed. I haven't seen this discussed anywhere in English, but recent builds of Ruby 1.9 (my build is from August 17th) also define methods next and next? on Enumerator. These are Python-style (and Java-style) external iterators:

Update: 8/24/07: Matz has just removed the next? method. So you now have to be ready to catch StopIteration when using Enumerators. This means that the twine method below doesn't work anymore..

r = 1..3   # An enumerable object
e = r.each  # An enumerator object
e.next   # => 1
e.next # => 2
e.next # => 3
e.next # StopIteration exception raised

True external iterators make the age-old problem of parallel iteration in Ruby trivial to solve. Here are some examples:

def twine(*enumerables)
  enumerators = enumerables.map { |x| x.each }
  while not enumerators.empty?
    e = enumerators.shift
    if e.next?
      yield e.next
      enumerators << e
    end
  end
end

def braid(*enumerables)
  enumerators = enumerables.map { |x| x.each }
  begin
    loop do
      values = enumerators.map {|x| x.next }
      yield *values
    end
  rescue StopIteration
    # This is normal termination condition
  end
end

a = [1,2,3]
b = [4,5,6]
twine(a,b,'a'..'b') { |x| puts x }
braid(a,b,7..10) { |x,y,z| print "#{x},#{y},#{z}\n" }

It appears that these new external iterators are not build on the old Generator library which used continuations (I think). Instead, they use a new Fiber class (a kind of micro-thread). It is not documented yet, but its in there in recent 1.9 builds. If you know how to use Fiber, feel free to explain in the comments.

Changes between Ruby 1.8 and Ruby 1.9

This is a repost. The original from August 2nd started getting comment spam, and I accidentally deleted the post while deleting the spammy comments. The original, valid comments are gone as well, which is unfortunate, because Tom Klaasen and Dmitry Kim made helpful points that resulted in corrections to the post below.

Someone recently emailed the ruby-core mailing list asking "Is there some list of 'bullet points' on the major differences between the syntax of Ruby 1.8 and Ruby 1.9 available somewhere?" The response, of course was a link to the definitive list of changes in Ruby 1.9.

But that is an exhaustive list instead of just highlighting the major changes. So, the following is my somewhat more digested list of the important changes, as I understand them. Additions, corrections, clarifications, and so forth are welcome in the comments.

Nifty Ruby Unicode codepoints utility

I recently learned about the Module.const_missing method for lazily computed constants, and came up with this Unicode utility module to try it out.

#
# This module lazily defines constants of the form Uxxxx for all Unicode
# codepoints from U0000 to U10FFFF. The value of each constant is the
# UTF-8 string for the codepoint.
# Examples:
#   copyright = Unicode::U00A9
#   euro = Unicode::U20AC
#   infinity = Unicode::U221E
#
module Unicode
  def self.const_missing(name)  
    # Check that the constant name is of the right form: U0000 to U10FFFF
    if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/
      # Convert the codepoint to an immutable UTF-8 string,
      # define a real constant for that value and return the value
      const_set(name, [$1.to_i(16)].pack("U").freeze)
    else  # Raise an error for constants that are not Unicode.
      raise NameError, "Uninitialized constant: Unicode::#{name}"
    end
  end
end

Concurrent Exchanger class in Ruby

I've always thought that java.util.concurrent.Exchanger was a nifty little class. The javadoc I've linked to describes it like this:

A synchronization point at which two threads can exchange objects. Each thread presents some object on entry to the exchange method, and receives the object presented by the other thread on return.

The javadoc also includes a nifty little example demonstrating why you might want an Exchanger object.

I decided to try to implement this in Ruby, to test my understanding of Mutex and ConditionVariable. The code is below. I'm not sure how useful it actually is, but it was fun to write. And if you can understand what it does, then you've got a good working knowledge of threads in Ruby!

Finally, if you've got the JDK installed, unzip the src.zip file and take a look at the source code for in java/util/concurrent/Exchanger.java. It is much more complicated than this trivial example. It was eye-opening to see how carefully written classes like this one are for high performance on multi-core or multi-CPU systems.

Ruby Structs for Immutable Types

Ruby's Struct class is a great way to define simple classes. For example, to define a simple Point class with getter and setter methods for x and y attributes, along with working ==, hash, and to_s methods, we can just write:

Point = Struct.new(:x,:y)

Struct was designed with mutable types in mind, but that doesn't mean that we are restricted to mutable types. Here's how we change the just-defined Point class to be immutable:

Point = Struct.new(:x, :y)  # Define mutable class
class Point                 # Open the class
  undef x=,y=,[]=           # Undefine mutator methods
end

Why do this for all of your Struct-based classes, however? Let's add a new factory method to Struct itself. If you want an immutable structure, use Struct.immutable instead of Struct.new:

def Struct.immutable(*args)  # Factory method for immutable classes
  Struct.new(*args).class_eval do # Define struct, then modify it
    undef []=                     # Undefine general mutator
    args.each do |sym|            # For each field of the struct
      mutator = :"#{sym.to_s}="   # Symbol for setter method
      remove_method mutator       # Undefine that method
    end
    self                          # Return the class
  end
end

Warning: I haven't actually tested this carefully, but it seems to work. Suggestions, corrections, etc., are welcome in the comments.

Functional Programming Hacks for Ruby

| 1 Comment

I've been noodling around with Proc, Method, UnboundMethod and Symbol, and have come up with the following utilities for:

  • function composition
  • function memoization
  • function currying
  • symbol-to-method conversion (different than Symbol.to_proc)

I don't claim that any of this is actually useful. But it might be mind-expanding or character building.

I'm relatively new to Ruby, so comments from more experienced rubyists are more than welcome.

The code follows...

Ruby exception-handling quiz

Test your knowledge of Ruby's rescue/else/ensure exception handling construct! Fire up irb to check your answers.

1) What is the value of x?

x = begin 1; rescue 2; else 3;  ensure 4; end

2. What does this method return?

def test
  return 1
rescue
  return 2
else
  return 3
end

3. What does this method return?

def test
  return 1
ensure
  return 2
end

4. How about this one?

def test
  1
ensure
  2
end

5. What kind of exception does this method raise?

def test
  raise ArgumentError
rescue ArgumentError
  raise TypeError
end

6. What kind of exception does this method raise?

def test
  raise ArgumentError
ensure
  raise TypeError
end

7. What does this method do?

def test
  3.times do |x|
    begin
      puts x
      raise "error"
    ensure
      next
    end
  end
end

rescue clauses on Ruby class and module definitions

I've been studying exceptions in Ruby, and have discovered some syntax that is not documented in the Pickaxe, nor anywhere obvious that I can find with Google.

Everyone knows about rescue clauses with begin/end. And most Ruby programmers probably know that you can use a rescue clause at the end of a method definition. What I was surprised to discover (by reading the parse.y grammar file in the source distribution) is that rescue clauses are also allowed at the end of class and module definitions.

This, for example, is legal Ruby:

class Test
  def t
    1
  end
  raise "foo"
rescue 
  p $!
else
  p "Class Test defined without exceptions"
ensure
  p "Exiting class Test"
end

p Test.new.t

I'm not sure when this would be useful, but it is legal, and it ought to be documented!

Local variable assertion in Ruby

| 5 Comments

I'm just starting with Ruby, but one of the tricky parts of this language is that since it has no way to declare a variable, you can't tell it that you want a variable to be local. When you assign a value to a variable, you will be using a variable from a containing scope, if any such variable exists. And if no such variable exists, then you'll be creating a new one in the local scope. Block parameters also work this way, which is confusing.

I've attempted to create a workaround. My local() method asserts that the named variables do not yet exist, guaranteeing that any uses that follow will create local variables instead of clobbering existing variables. My code is in the extended entry. See the introductory comment for usage information.

I don't have enough Ruby experience yet to know if this is actually something useful, or just a curiosity. Creating this function was an interesting exercise for me, so I haven't looked yet to see if something like this already exists.

Read on for the code...

Integer division and negative numbers

| 7 Comments

I thought I understood basic arithmetic!

I've just learned that Ruby and Python (and, I'm told Tcl) define integer division of or by a negative number differently that C and Java do. Consider the quotient -7/3. Java gives -2. Ruby gives -3.

Modulo is different, too: In Java -7%3 is -1. But in Ruby it is 2.

I think I prefer the C and Java version of division, because it has the nice property that: -x/y = -(x/y). In general, this is not the case in Ruby.

On the other hand, Ruby's integer division can be explained with a simple rule. For the quotient q=x/y, we can say that q is the largest integer such that q*y<=x. For this rule, "largest" and "less than" have their obvious meanings: closest to positive infinity and closer to negative infinity. Maybe there is an equally succinct and general definition of integer division for C and Java, but it looks to me as if it requires special-casing the signs of the operands or defining "less than" as "closer to zero".

I haven't done much programming in Ruby or Python, but I suspect that this isn't the kind of thing that lis likely to cause bugs in practice. I don't know when I actually do integer division with negative operands. It reminds me, however of Josh Bloch's recent blog post and drives home his point that integer arithmetic is not as simple as it appears!

(Ruby and Python aficionados are invited to use the comments to explain why your language of choice does the right thing :-)

Update: comments are now closed. Comment spammers have found the entry

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en