Many of this was taken from https://github.com/styleguide/ruby, https://github.com/bbatsov/ruby-style-guide and https://github.com/bbatsov/rails-style-guide.
-
Use 2 spaces and no tabs.
-
Never leave trailing whitespace.
-
End each file with a newline.
-
Use spaces around operators, after commas, colons and semicolons, around
{and before}.sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts "foobar" [1, 2, 3].each { |foo| puts foo }
-
Use spaces in argument list and put one empty line between method definitions.
def foo(arg1, arg2, arg3) # ... end def bar(arg1 = :default, arg2 = nil, arg3 = {}) # ... end def qux(arg1: :default, arg2: nil, arg3: []) # ... end
-
No spaces after
(,[,!or before],)or around**,..or in string interpolations.foo(bar).method [1, 2, 3].length !number? 2**2 1..5 "foo#{bar}"
-
Use double-quoted strings.
# bad 'foobar' # good "foobar"
-
Large numeric literals.
# bad num = 1000000 # good num = 1_000_000
-
Avoid the use of
!!.# bad x = "test" # obscure nil check if !!x # body omitted end x = false # double negation is useless on booleans !!x # => false # good x = "test" unless x.nil? # body omitted end
-
Use shorthand self assignment operators whenever applicable.
# bad x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # good x += y x *= y x **= y x /= y x ||= y x &&= y
-
Leverage the fact that if and case are expressions which return a result.
# bad if condition result = "foo" else result = "bar" end # good result = if condition "foo" else "bar" end
-
Put one empty line after
classormoduledefinitions and before theend.class MyClass # first line goes here end
-
No empty lines after
defand before theendin a method.def foo # first line goes here end
-
Only one space for multiple line assignments.
# bad foo = bar foobar = foo foobarqux = qux # good foo = bar foobar = foo foobarqux = qux
-
Multiple line assignment.
# bad hash = { foo1: :bar1, foo2: :bar2, foo3: :bar3, foo4: :bar4, foo5: :bar5 } array = [:foobar1, :foobar2, :foobar3, :foobar4, :foobar5, :foobar6, :foobar7, :foobar8, :foobar9] # good - the preferred way hash = { foo1: :bar1, foo2: :bar2, foo3: :bar3, foo4: :bar4, foo5: :bar5 } array = [ :foobar1, :foobar2, :foobar3, :foobar4, :foobar5, :foobar6, :foobar7, :foobar8, :foobar9 ] # good - But not the preferred way. Move the left brace to the next line, if the hash gets unclear. hash = { foo1: :bar1, foo2: :bar2, foo3: :bar3, foo4: :bar4, foo5: :bar5 } array = [ :foobar1, :foobar2, :foobar3, :foobar4, :foobar5, :foobar6, :foobar7, :foobar8, :foobar9 ]
-
Indent
whenas deep ascase.kind = case foo when "bar" "foobar" when "foo" "foofoo" else "foo" end
-
The
andandorkeywords are banned. Always use&&and||instead!# because of: foo = "ThisIsNotABoolean" bar = false result = foo and bar # => 'ThisIsNotABoolean' # but we want this: result = foo && bar # => false
-
Method defininitions:
# bad def my_method arg end # good def my_method(arg) end
-
Method calls: parantheses around parameters are not necessary. If the argument list of a method call spans more than one line, parantheses are mandatory.
# good object.method arg object.method(arg) # bad object.method arg1, arg2, arg3, arg4, arg5, arg6 # good object.method(arg1, arg2, arg3, arg4, arg5, arg6 )
-
Multi-line method chaining: put points at the end of lines and methods on new lines. If using any newlines put every method to a new line.
# bad foo.bar.qux .baz # better foo.bar.qux. baz # ok foo.bar.qux.baz # bad foo.bar.qux.baz.bla.blub.first.last.all.includes(:myself).order(:left) # bad foo.bar.qux.baz.bla. blub.first.last. all.includes(:myself). order(:left) # good foo. bar. qux. baz. bla. blub. first. last. all. includes(:myself). order(:left)
-
Avoid the usage of
is_orhas_at the beginning of method names.# bad is_admin? has_super_permissions? # good admin? super_permissions?
-
Many arguments in method definition
# bad def foobarqux(text, small_text: nil, text_class: nil, no_text: (text.blank? && small_text.blank?), extra_content: nil, icon: nil, color_type: :default, large_button: large_button_default?, no_button: false, icon_only: false, icon_position: :left, disabled: false, text_icon_space: (no_button ? "" : " ").html_safe, **options) # ... end # good def foobarqux( text, small_text: nil, text_class: nil, no_text: text.blank? && small_text.blank?, extra_content: nil, icon: nil, color_type: :default, large_button: large_button_default?, no_button: false, icon_only: false, icon_position: :left, disabled: false, text_icon_space: (no_button ? "" : " ").html_safe, **options ) # ... end
-
Use named parameters for methods with optional parameters (only for projects using Ruby 2.0 or greater)
# bad (ok for ruby < 2.0) def foo(options = {}) bar = options.fetch(:bar, "default") puts bar end # good def foo(bar: "default") puts bar end # foo => "default" # foo(bar: "baz") => "baz"
-
Long argument line in method call
# bad simple_form_for @object, url: long_route_method_path , html: { class: 'form-horizontal', multipart: true, data: { data: :data, another_data: another_data, some_more_data: some_more_data }} do |f| # ... end # good simple_form_for( @object, url: long_route_method_path, html: { class: "form-horizontal", multipart: true, data: { data: :data, another_data: another_data, some_more_data: some_more_data } } ) do |f| # ... end
# bad create(:user, :user => build(:user, :email => "user@webit.de", :password => "password", :password_confirmation => "password")) # good create( :user, user: build( :user, email: "user@webit.de", password: "password", password_confirmation: "password" ) ) # bad Mailer.deliver(to: "bob@example.com", from: "us@example.com", subject: "Important message", body: source.text) # good Mailer.deliver( to: "bob@example.com", from: "us@example.com", subject: "Important message", body: source.text ) # bad pdf.invoice_info(infos: { "user_name" => user_name, "invoice_number" => invoice_number, "customer_number" => customer_number }) # good pdf.invoice_info( infos: { "user_name" => user_name, "invoice_number" => invoice_number, "customer_number" => customer_number } )
-
The names of potentially dangerous methods (i.e. methods that modify
selfor the arguments) should end with an exclamation mark if there exists a safe version of that dangerous method.# bad - there is no matching 'safe' method class Person def update! end end # good class Person def update end end # good class Person def update! end def update end end
-
If there are many conditions, use 4 spaces relatively to the beginning of the statement for the next lines
# bad if condition_a && condition_b && condition_c && condition_f && condition_e # ... end # good if condition_a && condition_b && condition_c && condition_f && condition_e # ... end # good unless condition_a && condition_b && condition_c && condition_f && condition_e # ... end
-
Use one expression per branch in a ternary operator. This also means that ternary operators must not be nested. Prefer if/else constructs in these cases.
# bad some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # good if some_condition nested_condition ? nested_something : nested_something_else else something_else end
-
Use the Ruby 1.9 hash literal syntax when your hash keys are symbols.
# bad hash = { :one => 1, :two => 2, :three => 3 } # good hash = { one: 1, two: 2, three: 3 } # since ruby 2.2 we can create a hash like this: hash = { "one": 1, "two": 2, "three": 3 } # but keep in mind: hash[:one] => 1 hash["one"] => nil
-
Favor the use of Array#join over the fairly cryptic
Array#*with a string argument.# bad %w(one two three) * ", " # => "one, two, three" # good %w(one two three).join(", ") # => "one, two, three"
-
Comments
# bad =begin comment line another comment line =end # bad #comment without leading whitespace # good # comment line # another comment line
-
Use TomDoc for documentation.
# Public: Duplicate some text an arbitrary number of times. # # text - The String to be duplicated. # count - The Integer number of times to duplicate the text. # # Examples # # multiplex("Tom", 4) # # => "TomTomTomTom" # # Returns the duplicated String. def multiplex(text, count) text * count end
-
Do not use
fail.# bad if password.length < 8 fail "Password too short" end # good if password.length < 8 raise "Password too short" end
-
Do not use
refute.# bad refute valid? # good assert_not valid?
-
Use underscore for HTML IDs
# bad <input id="foo-bar" /> # bad <input id="fooBar" /> # good <input id="foo_bar" />
-
Use
presenceinstead ofpresent?if possible# bad state = params[:state] if params[:state].present? country = params[:country] if params[:country].present? region = state || country || "US" # good region = params[:state].presence || params[:country].presence || "US"
-
Use lambdas instead of strings for
assert_differenceandassert_no_difference(andassert_changes/assert_no_changesas of Rails 5.1)# bad (no code highlight, no inspections etc.) should "filter old news when wanted" do assert_difference "News.count" do assert_no_difference "News.just_new.count" do News.create(published_at: 6.months.ago - 1.day) end end end # good should "filter old news when wanted" do assert_difference -> { News.count } do assert_no_difference -> { News.just_new.count } do News.create(published_at: 6.months.ago - 1.day) end end end