Sunday, March 6, 2011

Ruby Expression at First Glance

I started to learn Ruby language over the weekend.

If you have a C-like syntax language background like me, planned to learn Ruby for years, but never get started (with a valid reason, I know :-) Something quick to share with you today: a short highlights of Ruby expression.

Every statement returns a value
  • Every statement is an expression. You can code something like this:
    a = b = 1  # => 1
    
    bar = "spam"
    foo = if bar == "spam"
            "great!"
          else
            "keep going"
          end
    p foo  # => "great!"
    
    defined? var                 # => nil
    var = var || "default value" # => "default value"
    
Using defined?
  • If var is not defined, defined? var returns nil. Otherwise, it returns the var description.
  • It's a handy tool when learning the language in irb. But just curious how it is used in production code..
Parallel assignment
  • Swapping values of two variables is easy, like Python
    a = 1
    b = 2
    a, b = b, a   # => a=2, b=1
    
  • Or you can perform neat stunts using splat (asterisk prefix)
    list = [1,2,3,4]
    
    first, *, sec_last, last = list
      # => first=1, sec_last=3, last=4
    
    first, *middle, last = list     
      # => first=1, middle=[2,3], last=4
    
    # more stunts..
    a, b, c, d = *(1..2), *[3, 4]  # => a=1, b=2, c=3, d=4
    
The Ruby Truth
  • Everything is true, except nil, false.
  • That means 0 and '' is evaluated to true! Beeee careful.
Conditions
  • You can use normal if..elsif..else..end or unless..end statements
  • or append if/unless to a statement, like Perl
    process(order) if order.valid?
    
No breaks in case statement
  • Great to see there is no breaks :)
  • Note that, when statement uses === operator (case equality) to perform matching.
    case command 
    when "debug"
      dump_debug_info
      dump_symbols 
    when /p\s+(\w+)/
      dump_variable($1) 
    when "quit", "exit"
      exit 
    else
      print "Illegal command: #{command}" 
    end
Looping
  • Ruby provides while..end and until..end, or you can append while/until to a statement:
    puts a += 1 until a == 100
  • We may use for..in..end and loop do..end to iterate through a list, but I believe many Rubyists prefer list.each{}.
Variable scoping
  • Block introduces new scope. Block is a chunk of codes enclosed within {..} or do..end. A few ground rules:
    1. New variable defined in a block is not visible outside the block.
    2. Variables exist before a block, can be accessed within the block (think closure).
    3. A block's parameter will shadow a variable outside the block with same name.
    Here's an example,
    defined? local  # => nil
    x = y = -1
    [1,2,3].each do |x|
      local = y = x
    end
    defined? local  # => nil
    p x             # => -1
    p y             # => 3
    
  • Built-in expressions such as if, unless, while, until, for do not use block. So they do not introduce new scope. As a result, new variables defined in a while loop, will continue to exist after the loop.

Learn Ruby?
My rubyist friend, Yasith recommended to start with this book: Programming Ruby. The latest edition Programming Ruby 1.9 is available on bookshelf.