Once in a while I come accross some Ruby code where I don’t know why it is doing stuff the way it does…
h2. Ternary Operator
I am using the Ternary Operator quite a lot, because it keeps the code concise and often times more readable then long if-else statements. One thing that I discovered just recently is the following:
val = something ? 'this' : 'that'
If you look closely, you will see that there is not a comparison ==
but an assignment =
operator present. The interesting fact though is where Ruby puts parenthesis in this code:
val = (something ? 'this' : 'that')
Makes a lot of sense, but is not obvious, especially if you are debugging some library code.
Another cool thing that you can do with the operator is nesting:
val == 0 ? 'zero' : val == 1 ? 'one' : 'other'
# is interpreted as
(val == 0 ? 'zero' : (val == 1 ? 'one' : 'other'))
But most of the times you are better of with Switch Cases.
h2. Switch Case
There are some pretty cool features in the Ruby Switch Case. You can switch by class if you like:
case "some string"
when Integer
puts "i am an int"
when String
puts "i am a string"
else
puts "dunno"
end
This works, because Ruby uses the ===
method to compare in a when block. So the when code above evaluates to:
String === "some string"
The cool thing is that you can implement the ===
method yourself and add some Ruby magic to the Switch Case.
But be aware of some stuff that might bite you while using Switch Cases! You should know that Ruby allows multiple arguments in a when block:
case val
when 5, 7
puts "good numbers"
else puts "bad numbers"
end
It’s also important to know that you need to add a newline before writing your block code. It’s also possible to write oneliners by using a semicolon or the then
keyword, otherwise the following code will be interpreted as belonging to the when condition:
case val
when 5, 7; puts "good numbers"
when 0 then puts "empty"
when 1, puts "syntax error"
else puts "bad numbers"
end
Older versions of Ruby also supported a syntax with a :
at the end instead of a ;
, wich looks kind of strange:
case val
when :number: puts "numbers"
else puts "not a numbers"
end
h2. Missing something
Since the Ruby parser allows a lot of flexibility, it’s possible to implement stuff which does not make sense at all. For example this statement which misses the if
at the beginning of the condition:
def test_failing
else puts "invalid"
end
end
Evaluating this method will fail (or even kill the ruby process):
warning: else without rescue is useless
syntax error, unexpected keyword_end, expecting $end
One thing that happens to me quite often, is that there are implicit things going on if you forget to add commas in your code, while I am not sure how and why they work:
puts "what" "the" "fuck" # => "whatthefuck"
puts String Integer # => Integer
h2. Everything is a Method
Well not everything in Ruby is implemented as a method, but there a lot of things that you can at least use like methods. Did you know for example, that you can call the accessibility modifiers in Ruby like methods? This is pretty handy if you want to mark only some methods:
def my_method; end
private :my_method
It’s also quite important to know that method objects provide a lot of interesting information. Especially if you are doing some serious debugging with a lot of inheritance and Ruby magic involved:
"".method(:class).owner # => Kernel
class A
def b;end
end
# works only in 1.9
A.new.method(:b).source_location # => ["...test.rb", 3]
When talking about methods, it’s worth knowing the keywords that are used in Ruby and in which context they can be used. A good example for this is the *
character, which can be used quite differently:
# as a simple method
1 * 2
# for varargs in method signatures
def method_name(*args)
# for unsplatting arrays
some_method_that_has_three_args(*[1, 2, 3])
You should also be aware that some operators behave different from others:
def some_array
@some_array ||= []
end
def doit
some_array << [3,4] # ok
some_array += [6,7] # raises undefined method `+' for nil:NilClass
end
h2. Predefined Variables
In analogy to Pearl, Ruby provides a bunch of "Predefined Variables":http://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html#predefinedvariables that are worth knowing. A lot of them contain information about the current environment, code or execution context.
There are f.e. some extra variables for matching groups in Rubys regular expressions:
"hey_you" =~ /(.*)_(.*)/
$1 # => hey
$2 # => you
$0 # => .../test.rb
Unfortunately $0
has nothing to do with match groups, but is the name of the current executed program...
h2. Naming Best Practices
When working with Ruby you get used to some best practices when it comes to names. This is important, because several thing are evaluated differently depending on up- and downcase:
CONSTANTS_ARE_UPPER_SNAKE_CASE
ClassesAreCamelCase
Modules::Should::Map::To::Folder::Structure
So it is quite surprising that Ruby comes with an Array()
method which transforms everything it gets into an array unless it's already an array:
Array("string") # => ["string"]
Array(["string"]) # => ["string"]
It's also worth having a deep look into the Ruby documentation about Arrays and the Enumerable Module, because they provide a bunch of really cool helpers that can save you an everage developers lifetime if you know them by heart.
For "some more cool Ruby tricks have a look at this Rubyinside post":http://www.rubyinside.com/21-ruby-tricks-902.html.
If you feel like sharing some more Ruby wisdom feel free to post a comment or contribute some sugar!