What I like about Ruby

From WhyNotWiki
(Redirected from Why I love Ruby)
Jump to: navigation, search

Error! Missing argument!

Ruby is an awesome language. Top reasons I love Ruby / coolest features of Ruby:

  1. Blocks:
    • Try and do this cleanly in other languages: assert_raise(RuntimeError) { Roman.new(0) }! You can't unless assert_raise is implemented to accept a block: assert_raise(Exception, ...) { block }.
    • (http://martinfowler.com/bliki/Closure.html)
  2. Iterators (methods that invoke a block of code repeatedly; f.e.: c.each, 5.times, ...)
    • Usually these are methods that return successive elements from some kind of collection.
    • Rubyisms in Rails (p. 23-24) provides a great metaphor, comparing iterators with highways: Before iterators (highways), "iterating through the elements of an array was a lot like driving cross-country on local roads. Your code [the car] has to figure out the route. [...] This approach practically breeds bugs: It is easy for callers to make a wrong turn [...]--and it also forces callers to worry too much about navigation while driving." With iterators, however, "the result is much cleaner code. Callers who need to iterate over the element no longer need to worry about keeping track of where they are in the array and how to get to the next element; the iterator handles that. All the calling code needs to do is apply whatever logic it needs against each array element."
  3. Class Enumerable: Forget for loops; if an object is enumerable, you don't need them!
    • ARGV.each_with_index { |item, index| puts "#{index}: #{item}" } for instance
  4. Parallel assignment: Swap variables like this: a, b = b, a
  5. Similarly, you can have a method return more than one value: return_value1, return_value2 = my_method()
  6. Built-in regular expression support
    • can pass a block (instead of a string) to a substitution command
  7. Named argument passing (well, almost). You can pass a hash as the last argument to method calls, which acts like named argument passing (true named arguments might come in a future version), so you don't have to look up which argument is which when you see something like my_method(3, true, 14, 1, false) !
  8. Everything is an object: It's more object oriented than, say, Java, which makes a distinction between primitives like 3 and objects. In Ruby, even 3 is an object!
    • You can extend the base classes! This lets you do nifty things like give Integer objects a "minutes" method (3.minutes) or give String objects a to_zip method.
  9. Accessor methods are actually easy to write! (attr_accessor, attr_reader, ...) So easy, in fact, that I use accessors instead of accessing the member variable directly (which you can't do in Ruby, unless you cheat and use instance_variable_get())
  10. very expressive
  11. unobtrusive
  12. build new domain-specific languages, like XML builder (.rxml)
  13. code blocks that you can "pass" to methods (and Procs)
  14. Attributes
    • It's easy to make getters and setters, using attr_writer and attr_reader. No more monotonous hand-coding of accessor methods!
    • To the user of your class, attributes look just like variables, even though implemented with methods. You can create virtual attributes. Hides private implementation details nicely.
    • Makes it so you don't need to create support classes, etc. for iterators
  15. Nice, clean, intuitive, easy syntax
    • no wasted punctuation. Can take shortcuts, like omitting the { } when you pass a hash to a method, omitting the () in function calls
    • array expansion/collapsal with the * operator
  16. Symbols (:method => :post), which are a little cooler than strings and also can be typed with one fewer keystroke!
    • The main reason to like them, though, is because "Symbols denote specialness. [...] The use of a symbol indicates that the name or value is not an arbitrary string but one of a limited set of expected values." It's like using a value from an enumeration in other languages, only easier to use because you don't have to declare anything before you use them! (Rubyisms in Rails)
    • They are also more efficient than strings: Multiple references to a symbol all refer to a single location in memory, so comparing them is very trivial; each strings, by contrast, is a different object, stored in a different location in memory.
  17. Can add/override methods of built-in classes! (re-opening classes, and mixins)
    • Add missing functionality: For instance, add a strip_slashes() method to the String class if it doesn't have one and you feel it belongs in the String class (not somewhere else).
    • Mock out methods in your tests to speed them up and reduce coupling
  18. built-in security considerations (tainted variables and such)
  19. You can make method names like "valid?" which is nicer/cleaner than "is_valid" (and other such boolean method).
  20. Operators (+, [], etc.) are easy to define in your classes (unlike in C) or override in other people's classes
    • Once you define/override +, you get += for free (and redefine == to get != for free, and redefine <=> to get < and >, etc.)
  21. Flexible syntax: Takes the best/most common ideas about syntax and combines them:
    • I've heard some of these features called "syntatic sugar"
    • and or &&
    • then or : (Python style)
    • /regex/ or RegEx.new(regex) [?]
    • { block of code } (C/Java style) or do block of code end
    • for item in items {} (Python style) or items.each do |item| {}
  22. Familiar/accessible to people coming from other languages:
  23. Powerful case/switch command (unlike C and Java!):
    • Any object (that defines ===) can be tested; it can even match the different cases by regular expression!
  24. The definition of truth is simple and logical (treating "" or 0 as false like other language do would be bad)
  25. You can concatenate lists with the + operator, and add to a list with << !
  26. if/unless modifiers (conditional execution): You can put an if condition after a statement
    • Example: file.close unless file.nil? is more readable and much more concise than its 3-line unless file.nil? / file.close / end brother. It also puts the focus on the normal case rather than putting the exception handling right in your face.
  27. unless modifiers: Similar to if and unless, you can throw an unless clause after any block of code to very conciselesy rescue any exception that it might throw and supply a default value for that case.
  28. Ruby code is human-readable, almost the way English is, only even more expressive than English.
    • You can say things naturally, like 3.times do or 5..10 or 6.downto(1)
    • No ; is needed at the end of lines. Why bother??
  29. Principle of least surprise / no arbitrary restrictions Orthogonality (concepts extended in all possible intuitive directions):
    • Just about everything in Ruby can be treated as an expression (that is, returns a value). This includes if statements! You can even exit out of a loop with a certain value (using break return_value).
    • Why return a simple a true or false when you can return even more? 99 and "cat" gives "cat" and 99 or false gives 99! A more useful example
    • & doesn't just do bitwise oring like it does in many other languages. It is extended in an intuitive way for Arrays, for example: set intersection (|, similarly, does set union, just like you'd expect!)!
  30. Powerful exception handling
    • re-raise: You can intercept an exception, do something with it, and then raise it again and throw it on up the stack.
    • retry: You can decide to "give it another shot" from your exception handler, basically cancelling the exception!
    • begin/rescue/else/ensure : Most languages don't have the "else" branch. Minor point.
    • concise alternatives allowed: can use def/ensure/end or def/rescue/end without begin/end
  31. IO/file/process management (popen, etc.) is much easier and more intuitive in Ruby than in, say, Python. You can pass a block to an open/popen and it will automatically close the file/pipe when the block ends!
  32. Easy expansion of arrays / intuitive handling of arrays:
    • Extract multiple values from arrays in one line: a = [1, 2]; x, y = a
    • It even works in for loops!: for roman_numeral, number in [['m', 1000], ['cm', 900], ['d', 500]]; puts roman_numeral; end
  33. You can include a ? or ! at the end of a method name
    • So instead of names like is_a, is_valid, etc., you often find nams like is_a?, valid?, etc.
    • object.is_a?(Hash)
    • object.nil?
  34. alias_method: The easiest way to create wrapper/alias functions that I've ever seen!
  35. Conditional assignment/initialization (||=): Great for when you only want to set it to this default value if it doesn't already have a value.
  36. Many ways to create and delimit strings: ", ', %q{}, %q(), <<<here_document (more flexible here-doc syntax than other languages I've seen), ... just about anything you can imagine!
  37. It is not static typed, so I don't have a false sense of security that the code is bug free if it compiles. Plus, I don't waste time with all the beaurocracy of having to declare types of everything ahead of time. (Why static typing isn't the solution)


String delimiters

In many languages, " and ' are your only string delimiters, so you often have to do escaping like this:

"<span class=\"RequiredField\">"

or somewhat arbitrary alternation of delimiters, like this:

"<span class='RequiredField'>"

I don't like either option very much.

Ruby provides a 3rd method for string delimiters: The special, flexible % delimiter!

%Q{<span class="RequiredField">}

In other languages, you have to choose between between ' or " -- if you want to create a string that contains both of those, you have to start escaping one of them (whichever one you don't choose as your string delimiter. In Ruby, you have a 'lot' more flexibility!

Start with...

"an arg that's got quotes"

...decide you want your string to contain "" characters as well... no problem, upgrade to %q{} syntax!

%q{an 'arg' that's got "quotes"}

...decide you want your string to contain {} characters as well... no problem, change your delimiter to whatever the heck you want! In fact, you can go on like this nearly indefinitely -- keep changing to a different delimiter that doesn't occur in your delimited string literal -- until you run out of valid delimiters... Suffice it to say, that hasn't happened to me yet!

%q|an 'arg}' that's got "quotes"|
%q(an 'arg}' that's got "quotes" and |stuff|)
%q<an 'arg}' that's got "quotes" (and |stuff|)>
%q[<an> 'arg}' <that's> got "quotes" (and |stuff|)]
%q#<an> 'arg}' <that's> [got] "quotes" (and |stuff|)#
%q$<an> 'arg}' <that's> [got] #"quotes"# (and |stuff|)$

String interpolation

You can put any Ruby code inside #{...}

... including more strings with string interpolation inside of them!

irb -> "Interpolate #{" #{ " #{ "th"+"is" } " } " } !"
    => "Interpolate   this   !"

Sane behavior rather than errors

irb -> [].pop
    => nil

irb -> nil.to_s
    => ""

irb -> nil.to_a
    => []

I think Facets has an extension that adds even more sane behavior.

Familiar/accessible to people coming from other languages

  • IO objects support << operator (method), for those familiar with C++'s iostream
  • For those familiar with Python's use of the colon (if expr:), you can use that here too if you want. Or, if you're familiar with Basic, you can do 'if expr then whatever end'. Or, you can be normal and just do 'if expr whatever end'.
  • $? is familiar to bash scripters
  • $` is apparently familiar to perl programmers
  • command if expression is familiar to perl programmers
Personal tools