浅析Ruby的源代码布局及其编程风格
使用UTF-8作为源文件编码。
每个缩进级别使用两个spaces(又名软tabs).不要硬tabs
#bad-fourspaces defsome_method do_something end #good defsome_method do_something end
使用Unix-风格换行符。(*BSD/Solaris/Linux/OSX用户被为默认涵盖,Windows用户必须特别小心.)
- \n是换行,英文是LineFeed,ASCII码是0xA。
- \r是回车,英文是CarriageReturn,ASCII码是0xD。
- windows下enter是\n\r,unix下是\n,mac下是\r
如果你正在使用Git你可能会想要添加下面的配置设置来保护你的项目(避免)Windows蔓延过来的换行符:
$gitconfig--globalcore.autocrlftrue
不用使用;来分割语句和表达式。以此推论-一行使用一个表达式
#bad puts'foobar';#superfluoussemicolon puts'foo';puts'bar'#twoexpressiononthesameline #good puts'foobar' puts'foo' puts'bar' puts'foo','bar'#thisappliestoputsinparticular
对于没有内容的类定义,尽可能使用单行类定义形式.
#bad classFooError<StandardError end #okish classFooError<StandardError;end #good FooError=Class.new(StandardError)
避免单行方法。即便还是会受到一些人的欢迎,这里还是会有一些古怪的语法用起来很容易犯错.
无论如何-应该一行不超过一个单行方法.
#bad deftoo_much;something;something_else;end #okish-noticethatthefirst;isrequired defno_braces_method;bodyend #okish-noticethatthesecond;isoptional defno_braces_method;body;end #okish-validsyntax,butno;makeitkindofhardtoread defsome_method()bodyend #good defsome_method body end
空方法是这个规则的例外。
#good defno_op;end
操作符旁的空格,在逗号,冒号和分号后;在{旁和在}之前,大多数空格可能对Ruby解释(代码)无关,但是它的恰当使用是让代码变得易读的关键。
sum=1+2 a,b=1,2 1>2?true:false;puts'Hi' [1,2,3].each{|e|putse}
唯一的例外是当使用指数操作时:
#bad e=M*c**2 #good e=M*c**2
{和}值得额外的澄清,自从它们被用于块和hash字面量,以及以表达式的形式嵌入字符串。
对于hash字面量两种风格是可以接受的。
#good-spaceafter{andbefore} {one:1,two:2} #good-nospaceafter{andbefore} {one:1,two:2}
第一种稍微更具可读性(并且争议的是一般在Ruby社区里面更受欢迎)。
第二种可以增加了块和hash可视化的差异。
无论你选哪一种都行-但是最好保持一致。
目前对于嵌入表达式,也有两个选择:
#good-nospaces "string#{expr}" #ok-arguablymorereadable "string#{expr}"
第一种风格极为流行并且通常建议你与之靠拢。第二种,在另一方面,(有争议)更具可读性。
如同hash-选取一个风格并且保持一致。
没有空格(,[之后或者],)之前。
some(arg).other [1,2,3].length !之后没有空格. #bad !something #good !something
when和case缩进深度一致。我知道很多人会不同意这点,但是它是"TheRubyProgrammingLanguage"和"ProgrammingRuby"中公认的风格。
#bad case whensong.name=='Misty' puts'Notagain!' whensong.duration>120 puts'Toolong!' whenTime.now.hour>21 puts"It'stoolate" else song.play end #good case whensong.name=='Misty' puts'Notagain!' whensong.duration>120 puts'Toolong!' whenTime.now.hour>21 puts"It'stoolate" else song.play end case whensong.name=='Misty' puts'Notagain!' whensong.duraton>120 puts'Toolong!' whenTime.now>21 puts"It'stoolate" else song.play end
当赋值一个条件表达式的结果给一个变量时,保持分支的缩排在同一层。
#bad-prettyconvoluted kind=caseyear when1850..1889then'Blues' when1890..1909then'Ragtime' when1910..1929then'NewOrleansJazz' when1930..1939then'Swing' when1940..1950then'Bebop' else'Jazz' end result=ifsome_cond calc_something else calc_something_else end #good-it'sapparentwhat'sgoingon kind=caseyear when1850..1889then'Blues' when1890..1909then'Ragtime' when1910..1929then'NewOrleansJazz' when1930..1939then'Swing' when1940..1950then'Bebop' else'Jazz' end result=ifsome_cond calc_something else calc_something_else end #good(andabitmorewidthefficient) kind= caseyear when1850..1889then'Blues' when1890..1909then'Ragtime' when1910..1929then'NewOrleansJazz' when1930..1939then'Swing' when1940..1950then'Bebop' else'Jazz' end result= ifsome_cond calc_something else calc_something_else end
在方法定义之间使用空行并且一个方法根据逻辑段来隔开。
defsome_method data=initialize(options) data.manipulate! data.result end defsome_methods result end
避免在一个方法调用的最后一个参数有逗号,特别是当参数不在另外一行。
#bad-easiertomove/add/removeparameters,butstillnotpreferred some_method( size, count, color, ) #bad some_method(size,count,color,) #good some_method(size,count,color)
当给方法的参数赋默认值时,在=两边使用空格:
#bad defsome_method(arg1=:default,arg2=nil,arg3=[]) #dosomething... end #good defsome_method(arg1=:default,arg2=nil,arg3=[]) #dosomething... end
虽然几本Ruby书建议用第一个风格,不过第二个风格在实践中更为常见(并可争议地可读性更高一点)。
避免在不需要的时候使用行继续符\。实践中,
除非用于连接字符串,否则避免在任何情况下使用行继续符。
#bad result=1-\ 2 #good(butstilluglyashell) result=1\ -2 long_string='Firstpartofthelongstring'\ 'andsecondpartofthelongstring'
采用连贯的多行方法链式风格。在Ruby社区有两种受欢迎的风格,它们都被认为很好
-.开头(选项A)和尾随.(选项B)。
(选项A)当一个链式方法调用需要在另一行继续时,将.放在第二行。
#bad-needtoconsultfirstlinetounderstandsecondline one.two.three. four #good-it'simmediatelyclearwhat'sgoingonthesecondline one.two.three .four
(选项B)当在另一行继续一个链式方法调用,将.放在第一行来识别要继续的表达式。
#bad-needtoreadaheadtothesecondlinetoknowthatthechaincontinues one.two.three .four #good-it'simmediatelyclearthattheexpressioncontinuesbeyondthefirstline one.two.three. four
在这里可以发现有关这两个另类风格的优点的讨论。
如果一个方法调用的跨度超过了一行,对齐它们的参数。当参数对齐因为行宽限制而不合适,
在第一行之后单缩进也是可以接受的。
#startingpoint(lineistoolong) defsend_mail(source) Mailer.deliver(to:'bob@example.com',from:'us@example.com',subject:'Importantmessage',body:source.text) end #bad(doubleindent) defsend_mail(source) Mailer.deliver( to:'bob@example.com', from:'us@example.com', subject:'Importantmessage', body:source.text) end #good defsend_mail(source) Mailer.deliver(to:'bob@example.com', from:'us@example.com', subject:'Importantmessage', body:source.text) end #good(normalindent) defsend_mail(source) Mailer.deliver( to:'bob@example.com', from:'us@example.com', subject:'Importantmessage', body:source.text ) end
对齐多行跨度的arrayliterals的元素。
#bad-singleindent menu_item=['Spam','Spam','Spam','Spam','Spam','Spam','Spam','Spam', 'Bakedbeans','Spam','Spam','Spam','Spam','Spam'] #good menu_item=[ 'Spam','Spam','Spam','Spam','Spam','Spam','Spam','Spam', 'Bakedbeans','Spam','Spam','Spam','Spam','Spam' ] #good menu_item= ['Spam','Spam','Spam','Spam','Spam','Spam','Spam','Spam', 'Bakedbeans','Spam','Spam','Spam','Spam','Spam']
大数值添加下划线来提高它们的可读性。
#bad-howmany0sarethere? num=1000000 #good-mucheasiertoparseforthehumanbrain num=1_000_000
使用RDoc以及它的惯例来撰写API文档。注解区块及def不要用空行隔开。
每一行限制在80个字符内。
避免行尾空格。
不要使用区块注释。它们不能由空白引导(=begin必须顶头开始),并且不如普通注释容易辨认。
#bad ==begin commentline anothercommentline ==end #good #commentline #anothercommentline
在API文档中使用RDoc和它的公约。不要在注释代码块和def之间加入空行。
保持每一行少于80字符。
避免尾随空格。