Skip to content
Newer
Older
100644 347 lines (272 sloc) 10.1 KB
dc31232 initial version
Bozhidar Batsov authored
1 # Abstract
2
e842c36 minor change
Bozhidar Batsov authored
3 This document was created when I, as the Technical Lead of the company
4 in which I work for, was asked by the CTO to create some internal
dc31232 initial version
Bozhidar Batsov authored
5 documents describing good style and best practices for Ruby
6 programming. I started off by copying
7 [this existing style guide](https://github.com/chneukirchen/styleguide),
e842c36 minor change
Bozhidar Batsov authored
8 since I concurred with most of the points in it and then proceeded to built
dc31232 initial version
Bozhidar Batsov authored
9 upon it. I hope it will be useful to other people as well and I hope
10 that I'll get a lot of feedback and suggestions on how to improve the
11 guide for the benefit of the entire Ruby community.
12
13 ## Formatting
14
15 * Use UTF-8 as the source file encoding.
16 * Use 2 space indent, no tabs. (Your editor/IDE should have a setting to help you with that)
17 * Use Unix-style line endings. (Linux/OSX users are covered by default, Windows users have to be extra careful)
18 * if you're using Git you might want to do this `$ git config --global core.autocrlf true` to protect your project from Windows line endings creeping into your project
19 * Use spaces around operators, after commas, colons and semicolons, around { and before }.
20
e7998ad another try
Bozhidar Batsov authored
21 ```Ruby
22 sum = 1 + 2
23 a, b = 1, 2
24 1 > 2 ? true : false; puts "Hi"
25 [1, 2, 3].each { |e| puts e }
26 ```
dc31232 initial version
Bozhidar Batsov authored
27
4999e13 @harbichidian Grammatical fix on line 28.
harbichidian authored
28 * No spaces after (, [ or before ], ).
dc31232 initial version
Bozhidar Batsov authored
29
2681d4b added highlighting to all examples
Bozhidar Batsov authored
30 ```Ruby
31 some(arg).other
32 [1, 2, 3].length
33 ```
dc31232 initial version
Bozhidar Batsov authored
34
be05f8d minor fix
Bozhidar Batsov authored
35 * Indent **when** as deep as **case**. (as suggested in the Pickaxe)
dc31232 initial version
Bozhidar Batsov authored
36
2681d4b added highlighting to all examples
Bozhidar Batsov authored
37 ```Ruby
38 case
39 when song.name == "Misty"
40 puts "Not again!" when song.duration > 120
41 puts "Too long!" when Time.now.hour > 21
42 puts "It's too late"
43 else
44 song.play
45 end
46
47 kind = case year
48 when 1850..1889 then "Blues"
49 when 1890..1909 then "Ragtime"
50 when 1910..1929 then "New Orleans Jazz" when 1930..1939 then "Swing"
51 when 1940..1950 then "Bebop"
52 else "Jazz"
53 end
54 ```
dc31232 initial version
Bozhidar Batsov authored
55
56 * Use an empty line before the return value of a method (unless it
57 only has one line), and an empty line between defs.
58
2681d4b added highlighting to all examples
Bozhidar Batsov authored
59 ```Ruby
60 def some_method
61 do_something
62 do_something_else
dc31232 initial version
Bozhidar Batsov authored
63
2681d4b added highlighting to all examples
Bozhidar Batsov authored
64 result
65 end
dc31232 initial version
Bozhidar Batsov authored
66
2681d4b added highlighting to all examples
Bozhidar Batsov authored
67 def some_method
68 result
69 end
70 ```
71
dc31232 initial version
Bozhidar Batsov authored
72 * Use RDoc and its conventions for API documentation. Don't put an
73 empty line between the comment block and the **def**.
74 * Use empty lines to break up a method into logical paragraphs.
75 * Keep lines fewer than 80 characters.
76 * Emacs users should really have a look at whitespace-mode
77 * Avoid trailing whitespace.
78 * Emacs users - whitespace-mode again comes to the rescue
79
80 ## Syntax
81
2681d4b added highlighting to all examples
Bozhidar Batsov authored
82 * Use **def** with parentheses when there are arguments. Omit the
83 parentheses when the method doesn't accept any arguments.
84
85 ```Ruby
86 def some_method
87 # body omitted
88 end
dc31232 initial version
Bozhidar Batsov authored
89
2681d4b added highlighting to all examples
Bozhidar Batsov authored
90 def some_method_with_arguments(arg1, arg2)
91 # body omitted
92 end
93 ```
dc31232 initial version
Bozhidar Batsov authored
94
95 * Never use **for**, unless you exactly know why. Most of the time iterators should be used instead.
2681d4b added highlighting to all examples
Bozhidar Batsov authored
96
97 ```Ruby
98 arr = [1, 2, 3]
da7a844 @abernardes Minor formatting issue
abernardes authored
99
2681d4b added highlighting to all examples
Bozhidar Batsov authored
100 # bad
101 for elem in arr do
102 puts elem
103 end
dc31232 initial version
Bozhidar Batsov authored
104
2681d4b added highlighting to all examples
Bozhidar Batsov authored
105 # good
106 arr.each { |elem| puts elem }
107 ```
108
dc31232 initial version
Bozhidar Batsov authored
109 * Never use **then** for multiline **if/unless**.
110
2681d4b added highlighting to all examples
Bozhidar Batsov authored
111 ```Ruby
112 # bad
113 if x.odd? then
114 puts "odd"
115 end
116
117 # good
118 if x.odd?
119 puts "odd"
120 end
121 ```
dc31232 initial version
Bozhidar Batsov authored
122
5e0a7a0 a few improvements
Bozhidar Batsov authored
123 * Favor **if/then/else** over the ternary operator. *if* is an
124 expression in Ruby and the resulting code is arguably easier to
d1a1d1a minor formatting improvement
Bozhidar Batsov authored
125 read (albeit not as concise). Remember that after all _"Programs must be written for people to read, and
126 only incidentally for machines to execute."_ (Abelson and Sussman).
5e0a7a0 a few improvements
Bozhidar Batsov authored
127
128 ```Ruby
129 # good
130 result = if some_condition then something else something_else end
131
132 # not so good
133 result = some_condition ? something : something_else
134 ```
135
dc31232 initial version
Bozhidar Batsov authored
136 * Use **when x; ...** for one-line cases.
a5e10af added another example
Bozhidar Batsov authored
137 * Use **&&/||** for boolean expressions, **and/or** for control flow. (Rule
dc31232 initial version
Bozhidar Batsov authored
138 of thumb: If you have to use outer parentheses, you are using the
a5e10af added another example
Bozhidar Batsov authored
139 wrong operators.)
140
141 ```Ruby
142 # boolean expression
143 if some_condition && some_other_condition
144 do_something
145 end
146
147 # control flow
148 document.saved? or document.save!
149 ```
150
dc31232 initial version
Bozhidar Batsov authored
151 * Avoid multiline ?: (the ternary operator), use **if/unless** instead.
45feb66 minor improvement
Bozhidar Batsov authored
152 * Favor modifier **if/unless** usage when you have a single-line
153 body. Another good alternative is the usage of control flow **and/or**.
dc31232 initial version
Bozhidar Batsov authored
154
2681d4b added highlighting to all examples
Bozhidar Batsov authored
155 ```Ruby
156 # bad
157 if some_condition
158 do_something
159 end
dc31232 initial version
Bozhidar Batsov authored
160
2681d4b added highlighting to all examples
Bozhidar Batsov authored
161 # good
162 do_something if some_condition
163
164 # another good option
45feb66 minor improvement
Bozhidar Batsov authored
165 some_condition and do_something
2681d4b added highlighting to all examples
Bozhidar Batsov authored
166 ```
dc31232 initial version
Bozhidar Batsov authored
167
a5e10af added another example
Bozhidar Batsov authored
168 * Favor **unless** over **if** for negative conditions (or control
169 flow **or**):
2681d4b added highlighting to all examples
Bozhidar Batsov authored
170
171 ```Ruby
172 # bad
173 do_something if !some_condition
dc31232 initial version
Bozhidar Batsov authored
174
2681d4b added highlighting to all examples
Bozhidar Batsov authored
175 # good
176 do_something unless some_condition
dc31232 initial version
Bozhidar Batsov authored
177
2681d4b added highlighting to all examples
Bozhidar Batsov authored
178 # another good option
a5e10af added another example
Bozhidar Batsov authored
179 some_condition or do_something
2681d4b added highlighting to all examples
Bozhidar Batsov authored
180 ```
181
dc31232 initial version
Bozhidar Batsov authored
182 * Suppress superfluous parentheses when calling methods, but keep them
183 when calling "functions", i.e. when you use the return value in the
184 same line.
2681d4b added highlighting to all examples
Bozhidar Batsov authored
185
186 ```Ruby
187 x = Math.sin(y)
188 array.delete e
189 ```
190
dc31232 initial version
Bozhidar Batsov authored
191 * Prefer {...} over do...end for single-line blocks. Avoid using {...} for multi-line blocks. Always use do...end for
192 "control flow" and "method definitions" (e.g. in Rakefiles and
193 certain DSLs.) Avoid do...end when chaining.
194
195 * Avoid **return** where not required.
196
2681d4b added highlighting to all examples
Bozhidar Batsov authored
197 ```Ruby
198 # bad
199 def some_method(some_arr)
200 return some_arr.size
201 end
202
203 # good
204 def some_method(some_arr)
205 some_arr.size
206 end
207 ```
dc31232 initial version
Bozhidar Batsov authored
208
209 * Avoid line continuation (\\) where not required. In practice avoid using line continuations at all.
210
2681d4b added highlighting to all examples
Bozhidar Batsov authored
211 ```Ruby
212 # bad
213 result = 1 + \
214 2
dc31232 initial version
Bozhidar Batsov authored
215
c20ef92 minor fix
Bozhidar Batsov authored
216 # good (but still ugly as hell)
2681d4b added highlighting to all examples
Bozhidar Batsov authored
217 result = 1 \
23356d4 minor fix
Bozhidar Batsov authored
218 \+ 2
2681d4b added highlighting to all examples
Bozhidar Batsov authored
219 ```
dc31232 initial version
Bozhidar Batsov authored
220
221 * Using the return value of = is okay:
222
2681d4b added highlighting to all examples
Bozhidar Batsov authored
223 ```Ruby
224 if v = array.grep(/foo/) ...
225 ```
dc31232 initial version
Bozhidar Batsov authored
226
227 * Use ||= freely.
228
2681d4b added highlighting to all examples
Bozhidar Batsov authored
229 ```Ruby
230 # set name to Bozhidar, only if it's nil or false
231 name ||= "Bozhidar"
232 ```
dc31232 initial version
Bozhidar Batsov authored
233
234 * Avoid using Perl-style global variables(like $0-9, $`, ...)
235
236 ## Naming
237
d3c3d40 minor change
Bozhidar Batsov authored
238 * Use snake_case for methods and variables.
dc31232 initial version
Bozhidar Batsov authored
239 * Use CamelCase for classes and modules. (Keep acronyms like HTTP,
240 RFC, XML uppercase.)
241 * Use SCREAMING_SNAKE_CASE for other constants.
242 * The length of an identifier determines its scope. Use one-letter variables for short block/method parameters, according to this scheme:
243
9259e8c more indentation fixes
Bozhidar Batsov authored
244 a,b,c: any object
245 d: directory names
246 e: elements of an Enumerable
247 ex: rescued exceptions
248 f: files and file names
249 i,j: indexes
250 k: the key part of a hash entry
251 m: methods
252 o: any object
253 r: return values of short methods
254 s: strings
255 v: any value
256 v: the value part of a hash entry
257 x,y,z: numbers
dc31232 initial version
Bozhidar Batsov authored
258
259 And in general, the first letter of the class name if all objects are of that type.
260
261 * When using **inject** with short blocks, name the arguments **|a, e|** (mnemonic: accumulator, element)
262 * When defining binary operators, name the argument "other".
2681d4b added highlighting to all examples
Bozhidar Batsov authored
263
264 ```Ruby
265 def +(other)
266 # body omitted
267 end
268 ```
269
dc31232 initial version
Bozhidar Batsov authored
270 * Prefer **map** over *collect*, **find** over *detect*, **find_all** over *select*, **size** over *length*. This is not a hard requirement, though - if
271 the use of the alias enhances readability - it's ok to use it.
272
273 ## Comments
274
275 * Write self documenting code and ignore the rest of this section.
d1a1d1a minor formatting improvement
Bozhidar Batsov authored
276 * _"Good code is its own best documentation. As you’re about to add
5e0a7a0 a few improvements
Bozhidar Batsov authored
277 a comment, ask yourself, ‘How can I improve the code so that
278 this comment isn’t needed?’ Improve the code and then document
d1a1d1a minor formatting improvement
Bozhidar Batsov authored
279 it to make it even clearer."_ -- Steve McConnell
dc31232 initial version
Bozhidar Batsov authored
280 * Comments longer than a word are capitalized and use punctuation. Use two spaces after periods.
281 * Avoid superfluous comments.
5e0a7a0 a few improvements
Bozhidar Batsov authored
282
283 ```Ruby
284 # bad
285 counter += 1 # increments counter by one
286 ```
287
7a62d6e added another comments bullet point
Bozhidar Batsov authored
288 * Keep existing comments up-to-date - no comment is better than an
289 outdated comment.
290 * Avoid writing comments to explain bad code. Try to refactor the code to make it self-explanatory.
dc31232 initial version
Bozhidar Batsov authored
291
292 ## Misc
293
294 * Write **ruby -w** safe code.
295 * Avoid hashes-as-optional-parameters. Does the method do too much?
296 * Avoid long methods (longer than 10 LOC). Ideally most methods will be shorter than 5 LOC. Empty line do not contribute to the relevant LOC.
297 * Avoid long parameter lists (more than 3-4 params).
298 * Use **def self.method** to define singleton methods. This makes the methods more resistent to refactoring changes.
299
2681d4b added highlighting to all examples
Bozhidar Batsov authored
300 ```Ruby
301 class TestClass
302 # bad
303 def TestClass.some_method
304 # body omitted
305 end
306
307 # good
308 def self.some_other_method
309 # body omitted
310 end
311 end
312 ```
dc31232 initial version
Bozhidar Batsov authored
313
314 * Add "global" methods to Kernel (if you have to) and make them private.
315 * Avoid **alias** when **alias_method** will do.
316 * Use **OptionParser** for parsing complex command line options and
317 **ruby -s* for trivial command line options.
2289a47 fixed a typo
Bozhidar Batsov authored
318 * Write for Ruby 1.9. Don't use legacy Ruby 1.8 constructs.
dc31232 initial version
Bozhidar Batsov authored
319 * use the new JavaScript literal hash syntax
320 * use the new lambda syntax
321 * methods like **inject** now accept methods names as arguments - `[1, 2, 3].inject(:+)`
322 * Avoid needless metaprogramming.
323
324 ## Design
325
326 * Code in a functional way, avoid mutation when it makes sense.
327 * Do not mutate arguments unless that is the purpose of the method.
328 * Do not mess around in core classes when writing libraries. (do not monkey patch them)
d6aace1 @dquimper Fixing link
dquimper authored
329 * Do not program defensively. See this [article](http://www.erlang.se/doc/programming_rules.shtml#HDR11) for more details.
dc31232 initial version
Bozhidar Batsov authored
330 * Keep the code simple (subjective, but still...). Each method should have a single well-defined responsibility.
331 * Avoid more than 3 Level of block nesting.
332 * Don't overdesign. Overly complex solutions tend to be brittle and hard to maintain.
343699e @bbatsov Edited README.md via GitHub
authored
333 * Don't underdesign. A solution to a problem should be as simple as possible... but it should not be simpler than that. Poor initial design
dc31232 initial version
Bozhidar Batsov authored
334 can lead to a lot of problems in the future.
335 * Be consistent. In an ideal world - be consistent with the points listed here in this guidelines.
336 * Use common sense.
5e0a7a0 a few improvements
Bozhidar Batsov authored
337
338 # Contributing
339
340 Nothing written in this guide is set in stone. It's my desire to work
341 together with everyone interested in Ruby coding style, so that we could
342 ultimately create a resource that will be beneficial to the entire
343 Ruby community.
344
345 Feel free to open tickets or send pull requests with
346 improvements. Thanks in advance for your help!
Something went wrong with that request. Please try again.