Ruby Style, Conventions, and Idioms
“Art inhabits the country between chaos and cliché.” — Barbara Herrstein Smith.
Take a look at that quotation above from B. H. Smith. Your code needs to observe her rule about art. Obviously there is a big problem if your code is chaotic: No one will understand it. What about cliché? Writing code that takes no advantage of the power that Ruby gives you is clichéd: It’s just the same old boring code you could write in any language like C, Java, etc.: Wordy, baggy, voluminous. Ruby gives you the opportunity to be concise and elegant. What follows are some notes so that you can write stylistic code, which is to say, code that that is neither chaotic nor clichéd.
Please let us know if there are additional topics you’d like to see addressed here.
Visual Style
- indent 2 spaces: “using two-character indentation will make you friends in the community if you plan on distributing your code” (Pickaxe, p. 14). If you are flagrant in your disregard of this recommendation, we may ask you to update your formatting and re-submit. Make sure that your editor uses spaces for the indentation. Some editors will accept tabs and present the indentation visually as two spaces, while there will be tabs in the file. In any case, here’s what two-character indentation should look like:
class MVC # Instantiate an MVC applicatio with the given Model and Array of Views def initialize(model, *views) controller = Controller.new(model, *views) controller.get_input end end - line up your hashes all pretty, please. don’t make a hash of them.
ZIP_COMMANDS = { '0. Native ZIP' => 'zip', '1. rubyzip' => 'ruby ' + quote_if_windows(File.join(File.dirname(__FILE__), 'bin', 'zip_in_ruby.rb')), '2. PKZIPC' => (quote_if_windows(File.join(File.dirname(__FILE__), 'bin', 'PKZIPC.exe')) + ' -add -dir -r') }
Conventions
- do/end vs {}: If a block contains 1 (or 2…) statements, use braces. If it is a multi-line block, use do/end (Pickaxe, p. 21).
a = [ 1, 2, 3 ].collect { |e| e + 1 }vs.
a = [ 1, 2, 3 ].collect do |e| puts "incrementing #{e}" e += 1 endRemember that the precedence of braces is higher than do/end (see Pickaxe, p. 168). Generally, this means that braces apply to the single item just to the left of the braces, while with do/end, everything to the left is evaluated first… The stylistic issue here is that it’s unclear without parentheses:
def method1(p1, p2) if block_given? yield end end def method2 if block_given? yield end end # do/end binds with method1 (do/end has lower precedence) method1 1, method2 do puts 'do/end block' end # {} binds with method2 ({} has higher precedence) method1 1, method2 { puts 'braces block' } - don’t use globals, please. Guess what? We haven’t taught you the syntax for global variables. If you need something at the “global” level, stick it in a file, and then create a class that supplies that “global” variable to any other class that needs it. Why do globals stink? First off, you’re asking for a name collision (some other class may just happen to make different assumptions about a global with the same name). Even if the name is sufficiently obscure, you’re locking in any code that would also use that global to that specific name. Ick.
Idioms
- ||=
The idea here is this: You want to assign a value to some variable only if the variable doesn’t have a value. If you ask for the value of a variable that has never been defined, that value is nil. Therefore, you can write “a = a || 10″ which means: If a does not have a value, set it to 10. Shorthand: a ||= 10. I’m a bit surprised that the Pickaxe doesn’t discuss this.
Things to Avoid
- Special variables such as $=, $/, etc. (see Pickaxe, p. 333ff). Why? They’re just not clear. If your shop has lots of Perl developers, maybe it’s ok.
Rules of thumb
Some of these are a bit sketchy . . . will get expanded over time.
- When to use parens with method names (short answer: If there’s any hint of ambiguity, use parens)
- If you want to use return, be consistent
- how much method chaining is reasonable? (Law of Demeter)
- Lots of short methods: good
- consider a flat / shallow class_hierarchy
- Metaprogramming is appropriate when…
- Huge payoff in terms of usage (esp. if facilitates DRY)
- Can’t be done any other way
Recent Comments