Ruby / Coding conventions
From WhyNotWiki
[edit] Method suffixes (! and ?)
This is a convention by design; the author of Ruby had this convention in mind when he created these "suffixes".
- ! for potentially "dangerous" methods
- ? for methods that answer a question, for boolean methods (
active?rather thanis_active)
Bruce Tate (2007-03-13). Crossing borders: Extensions in Rails: The anatomy of an acts_as plug-in (http://www-128.ibm.com/developerworks/java/library/j-cb03137/index.html).
The ! is a Rails convention for methods that modify and save an attribute in one step.
[edit] Monkey patching: overriding methods but retaining the original method (alias_method)
Should we adopt something like this convention?:
alias_method :add_before_[name_of_your_class], :add
def add(arg, ...) # actually override it
whatever
add_before_[name_of_your_class] # can optionally wrap the method that we just overrode
whatever
end
Seems popular in the Ruby world...and it makes sense... 1. name is almost certain to be unique 2. makes it pretty clear that this method is only known to / used by [your library] (and therefore no one else should be calling it); 3. it identifies the culprit ([your library]) more clearly when the method is displayed in a backtrace (I think?)
There's also this pattern that I've seen occasionally, whereby we create both a "...with..." and a "...without..." method and then we point the real method to the "...with..." method.
def tag_with_form_spam_protection(name, *args)
returning tag_without_form_spam_protection(name, *args) do |out|
...
end
end
alias_method :tag_without_form_spam_protection, :tag
alias_method :tag, :tag_with_form_spam_protection
[edit] alias_method over alias
The order makes more sense: new_name is an alias for old_name
I think Facets might have an extension (?) that lets you actually use a hash so you can use an arrow and make the direction of the alias explicit: alias_method :new_name => :old_name
[edit] Use English, not cryptic, hard-to-remember 2-character abbreviations
I recommend avoiding the use of cryptic punctuation-mark variables like $:, $!, $1, $_, $?, $$.
Obviously, we can only avoid using those if they have aliases.
The following aliases are built-in (see pickaxe book, p. 334.):
| short variable | longer variable |
|---|---|
$: |
$LOADPATH |
| others? | ? |
For the rest, there is this library: http://www.ruby-doc.org/stdlib/libdoc/English/rdoc/index.html
I like $: for its conciseness and non-all-upper-case-ness, but there are so many of these tiny variables that I don't think we'll be able to keep them all straight. Which could lead to bugs. I reluctantly vote that we consistently use long versions ($LOAD_PATH, etc.).
[edit] Initialization of instance variables in constructors
class Base
def initialize(user, thing)
@user, @thing=
user, thing
end
end
[edit] A slick way to do constructors so they don't have to do any/much initialization
Which would you rather read/write?
specification = Gem::Specification.new do |s| s.name = "Name" s.summary = "A summary" s.version = "20.19" s.author = "Me!" end
or
specification = Gem::Specification.new("Name", "A summary", "20.19", "Me!")
?
I personally prefer the first. Less claustrophobic when I can be in a block (where I can feel free to put any Ruby code).
It also makes the constructor easier to write and maintain:
def initialize yield self end
rather than:
def initialize(name, summary, version, author, many, many, more, arguments) self.name = name ... end
[edit] Don't nest things when you don't need to
Instead, consider doing things sequentially...
(This applies to all languages, really...)
%{ri #{names.map {|name| name.to_s}.join(" ")}}
(From Programming Ruby, p. 191)
when you can just do this:
"ri " + names.map {|name| name.to_s}.join(" ")
? Quite a bit easier on the eyes, IMHO. It loses two of the }'s.
[edit] Splitting long "single commands" into multiple commands
[edit] Example 1
html += months.map { |month|
link_to_unless(
@start_date == month.to_date,
month.to_date.month_for_report, :month => month.to_date
)
}.join(" | ")
[edit] String interpolation or concatenation?
"The #{what} kind"
or
"The " + what + " kind"
[edit] do/end verses { }
http://docs.rubyrake.org/read/chapter/4
Blocks may be specified with either a do/end pair, or with curly braces in Ruby. We strongly recommend using do/end to specify the actions for tasks and rules. Because the rakefile idiom tends to leave off parenthesis on the task/file/rule methods, unusual ambiguities can arise when using curly braces.
For example, suppose that the method object_files returns a list of object files in a project. Now we use object_files as the prerequistes in a rule specified with actions in curly braces.
# DON'T DO THIS! file "prog" => object_files { # Actions are expected here (but it doesn't work)! }Because curly braces have a higher precedence than do/end, the block is associated with the object_files method rather than the file method.
This is the proper way to specify the task …
# THIS IS FINE file "prog" => object_files do # Actions go here end
I sort of want to just always use { } instead of do/end. I think that would *look* nicer. And then I could reserve the "def" keyword for def, if, for, etc.
But like they say, {} has a higher associativity than do/end and can be confused with a hash, so it might be safer to follow their instructions.
[edit] Clean way to write symbols for dynamic calling a setter
I was disappointed that dynamically calling getters was so much cleaner looking than calling setters. I still am, but this trick helps...
This:
@@phone_fields = [:contact_phone, :contact_fax, :contact_mobile_phone]
def before_save
@@phone_fields.each { |phone_field|
unless self.send(phone_field).blank?
self.send(:"#{phone_field}=", self.send(phone_field).numbers_only)
end
}
end
is cleaner than this:
def before_save
@@phone_fields.each { |phone_field|
unless self.send(phone_field).blank?
self.send("#{phone_field}=".to_sym, self.send(phone_field).numbers_only)
end
}
end
[edit] Question: ternary if operator or if at end of statement?
I prefer this:
def error_messages_for (objects)
objects = objects.is_a?(Array) ? objects : [objects]
a bit better than:
def error_messages_for (objects)
objects = [objects] if !objects.is_a?(Array)
Why? Because:
- When you read it, you read the normal case (objects = objects, or stays the same) as well as the the exceptional case (objects = [objects]). In the second variation, you read only the exceptional case and may accidentally assume that it always happens unless you pay careful attention to the condition.
- I guess I prefer (at least in this case) to explicitly enumerate the cases.
- It uses the positive (is_a?) rather than the negative (!is_a?).
[edit] Question: how best to split a long single command over multiple lines
[edit] Example 1: assert_tag
This example illustrates how there can be many valid ways to write the same thing. The chances of 5 developers writing this one the same way are very, very slim. This seems unfortunate. Can someone please tell me the best way to write this and give me a good reason why you think your way is better than all the others?
assert_tag :attributes => { :id => "errorExplanation" },
:descendant => {
:attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name."
}
assert_tag :attributes => { :id => "errorExplanation" },
:descendant => { :attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name."
}
assert_tag :attributes => { :id => "errorExplanation" },
:descendant => { :attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name." }
assert_tag :attributes => { :id => "errorExplanation" },
:descendant => {
:attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name."
}
assert_tag({
:attributes => { :id => "errorExplanation" },
:descendant => {
:attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name."
}
})
assert_tag \
:attributes => { :id => "errorExplanation" },
:descendant => {
:attributes => { :class => "something" },
:content => "Oops! Don't forget to enter your First Name."
}
Which one you like the best depends on:
- Whether you prefer indenting only 2 spaces at a time or indenting as much as it takes to make things line up
- Whether you prefer to have closing }s on their own line or if you can tolerate them on the end of the line in order to save lines
- ...
[edit] Use ample whitespace
Whitespace is cheap -- use it!!
Newlines
You can use it by putting blank lines between methods, or between sections within a long method...
Spaces
Do you prefer (1)
system Escape.shell_command(["echo", %q{!&'"`$0 |()<>}])
or (2)
system Escape.shell_command([ "echo", %q{!&'"`$0 |()<>} ])
? I don't know about you, but I prefer (2)!
[edit] External links
http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=RubyCodingConvention
