Ruby for ActionScripters

20 Jan 2011 – Luke Bayes

Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.

This means that Ruby has opinions, and many of Ruby’s opinions are exactly inverted from what you may have grown to love in ActionScript. There was a time when this made me uncomfortable, and I’m sure it will make some of you uncomfortable too. Well, not you of course, but maybe someone you know…

The intention of this article, is to provide a brief introduction to Ruby for developers that are already familiar with ActionScript 3.0. It is not my intention to provide comprehensive coverage of the Ruby language here. For a much more well-written and far more comprehensive explanation of Ruby, please take the time to read Why’s Poignant Guide to Ruby, quite possibly the most entertaining and well-written computer book in history.



Ruby Pomegranate Seeds courtesy of Greencolander and the Creative Commons license.

Quack like a what?

Ruby is a dynamic language, which means that a variable can be any concrete data type. The important thing is that an object define the methods and attributes that its clients attempt to access. This paradigm is often referred to as Duck Typing.

Trying Ruby

If you have installed Ruby (Preferably with RVM or something similar), you can kick off a Read Eval Print Loop (REPL) by typing:

irb

(Type ‘quit’ and hit enter to leave the REPL)

The puts method will send a String value to stdout and you can think of this like ActionScript’s trace method.

puts 'Hello World'

Try running irb and then puts some messages now.

When using irb, you can do the following to try out Sprout features.

require 'rubygems'
require 'sprout'

# Output the methods on Sprout (minus the detritus from Object):
puts Sprout.methods - Object.methods

# Output Sprout.home
puts Sprout.home
puts Sprout.cache

Strings

There are a handful of different ways to declare Strings in Ruby, but the main thing I’d like to highlight here is the difference between single quotes and double quotes.

A String that is defined within single quotes will contain literally whatever is defined within the quotes. This means that backslashes will not be rendered as escape sequences, they will just be backslash characters. There is no way to insert expressions in between single quotes, so if you want to assemble a string with single quotes, this is done by concatenating different strings together.

Single quoted strings are usually preferred as they cost less in terms of work. I usually use single quotes wherever I don’t need an evaluated expression or escape sequence, but for the benefit of people that don’t know about these differences, I do try to use double quotes in generated Rake files wherever someone might try an expression (like in task names).

A String that is defined within double quotes will be interpreted for embedded Ruby expressions and escape sequences will be resolved so that they are replaced with the character literal that they represent.

suffix = "World!\n"
str = "Hello #{suffix}"

If you’re thinking in ActionScript, you’ll probably be tempted to concatenate Strings with expressions like:

a = 'aaa'
b = 'bbb'
puts 'a: ' + a + ' b: ' + b

While this will usually work, it will explode if the expression values are nil. The preferred way to assemble Strings and expression values (especially for debugging), is to use double quotes and Ruby expression syntax like:

a = 'aaa'
b = 'bbb'
puts "a: #{a} b: #{b}"

This will call to_s on provided expressions and insert an empty String for values that are nil.

Symbols

Ruby has an interesting primitive called a Symbol. Symbols are not Strings, but are often used in places where a String might also suffice. There are some differences between Symbols and Strings and the first one is that Symbols are more memory efficient than Strings.

A Symbol is defined (or referenced) in Ruby with a leading colon as follows:

name = :beaker

A good rule of thumb that Jim Weirich shared and that I agree with, is as follows:

  1. If the contents (i.e. the sequence of characters) of the object is important, use a String.
  2. If the identity of the object is important, use a Symbol.

The idea here, is that if you’re just trying to give a meaningful name to a pointer (as in Hash keys, or referring to methods by name), then Symbols are probably appropriate. If the value is what’s important, Strings might make more sense.

You can transform a String to a Symbol with the to_sym method, and you can transform a Symbol to a String with the to_s method. Outside of a Rails application Strings are not considered equal to Symbols that look similar.

:beaker == 'beaker'        # false
:beaker.to_s == 'beaker'   # true
:beaker == 'beaker'.to_sym # true

Symbols are a tricky part of Ruby and it’s important when working with Rake files to understand when a Symbol is appropriate and when it is not.

In Rake, a Symbol is often used for a Rake task name, unless that task refers to a file, then a String must be used. This is because Symbols cannot include slashes, dots or other important components of a File name.

More information on Symbols

Parentheses

The parentheses that surround parameters in a Ruby method declaration (and method calls) are optional, and by convention, are only used when critical for proper execution, or to improve legibility for nested expressions. As with most things stylish there is little consensus on when to use or omit parentheses in Ruby.

Making parentheses optional does take some time to get used to, but eventually it leads to improved readability, especially in environments like Rake files.

Following are some examples to help you understand this issue.

This method in ActionScript:

public function foo(a:String, b:String):void {
  trace("a: " + a + " b: " + b);
}

Could be defined like this in Ruby:

def foo a, b
  puts "a #{a}, b #{b}"
end

But may also be written like this:

def foo(a, b)
  puts "a #{a}, b #{b}"
end

Additionally, to call that method in ActionScript you might:

foo("bar", "baz");

But in Ruby:

foo "bar", "baz"

Of course, the following is also valid Ruby:

foo("bar", "baz")

You may be wondering, “When should I add the parens?” at this point. Here is a reasonable example of an expression that probably should get parentheses:

assert foo("bar", "baz")

This expression is calling the imaginary foo method, sending it two arguments, bar and baz, then it’s sending the return value of that method call to the assert method.

Even though the interpreter can figure out what’s going on without them, it’s arguably more readable to parenthesize nested expressions.

Return values

You should also know that Ruby methods always return a value, whether you use the return keyword or not. The last expression that is evaluated within a Ruby method is what is returned. This can of course, be nil.

Hash Rockets

Ruby Hashes are historically delimited by a “Hash Rocket”, this is an equal sign, followed by a greater than sign, like:

=>

To show what I mean, the following ActionScript Hash:

var hash:Object = { a: 'a', b: 'b', c: 'c' };

Could be written in Ruby like this:

hash = { :a => 'a', :b => 'b', :c => 'c' }

Even though the Hash Rocket is no longer required in Ruby 1.9.x, Sprouts is still using it for the time being. We’ll likely update to the new (more ECMA-like) syntax at some point in the future, but while we generally work in legacy versions of Ruby, there’s no good reason to actively break backwards compatibility.

Hash Brackets

You should also note that, like parentheses on methods, curly brackets around Hashes are optional, so the previous Hash may also be declared like:

hash = :a => 'a', :b => 'b', :c => 'c'

Notice how the Ruby Hash prefixes the Hash keys with a colon. This indicates that we’re using Symbols as keys.

Rake

I believe that Rake (and how Sprouts uses) it is a large enough topic for it’s own post, but while we’re talking about duck typing, Strings, Symbols and Hashes, I really want to highlight how these syntactic concepts are exploited in Rake.

A simple, named Rake task:

# Note the Symbol name:
task :my_task do
  # Do some work here.
end

A simple, file Rake task:

# Note the single quotes:
name = 'SomeProject'

# Note the double-quotes and expression:
file "bin/#{name}Runner.swf" do
  # Create the file here.
end

A simple, named Rake task that depends on another:

# Note the hash with a single Symbol key
# and Symbol value:
task :my_task => :other_task do
  # Do some work here.
end

A simple, named Rake task that depends on multiple other tasks:

# Not the hash with a single Symbol key,
# and Array of Symbol values:
task :my_task => [:other_task_one, :other_task_two] do
  # Do some work here.
end

When referring to Rake tasks by name, it’s generally a good idea to use Symbols for tasks that were defined with Symbols and Strings for tasks that were defined as such.

For more detailed (and well-written) information, be sure to read Martin Fowler’s seminal post on Rake.

Conclusion

That’s probably enough Ruby to get you through reading and editing a Rake file. I sincerely hope you find yourself intrigued by this language and, like me, get drawn into a new way of considering programming problems.

If you find anything here in error, please let us know, or better yet – fork, fix and send a pull request.