Skip to content

Instantly share code, notes, and snippets.

@alloy-d
Last active August 29, 2015 14:24
Show Gist options
  • Save alloy-d/8bf9a6a3d7ad142152b3 to your computer and use it in GitHub Desktop.
Save alloy-d/8bf9a6a3d7ad142152b3 to your computer and use it in GitHub Desktop.
Overture house style guide.
# # Overture's House Style Guide for Ruby
#
# This is a configuration file for [Rubocop][rubocop].
#
# It is based on [the default configuration file for Rubocop
# 0.32.1][rubocop-source-default-config].
#
# This style guide assumes that you are not writing code for any version
# of Ruby before version 1.9.
#
# [rubocop]: https://github.com/bbatsov/rubocop
# [rubocop-source-default-config]: https://github.com/bbatsov/rubocop/blob/v0.32.1/config/default.yml
# ## Usage
#
# Put this file in the root of your project as `.rubocop.yml`.
# Expectation: we will have some minimal project-specific configuration.
# Put that in `.rubocop-project.yml`.
#inherit_from:
# - .rubocop-project.yml
AllCops:
DisplayCopNames: yes
DisplayStyleGuide: yes
# ---
# The best compromise for readability is the "table" style enforced by
# Rubocop. It keeps keys, values, and hash rockets (if applicable)
# left-aligned in columns.
#
# To illustrate:
#
# example = {
# "key one" => 1
# "second" => 2
# "x" => "3"
# }
#
# These rules are applied to a hash passed in as the last argument to
# a method call only if it is *explicit* (i.e., it has the braces).
#
# Implicit hashes are meant for compactness or clarity, and enforcing
# alignment rules could conflict with those goals.
Style/AlignHash:
EnforcedHashRocketStyle: table
EnforcedColonStyle: table
EnforcedLastArgumentHashStyle: ignore_implicit
# ---
# When a method call is split across lines, we prefer the arguments
# indented for consistency with the rest of the code, instead of aligned
# with the call's parentheses.
#
# For example:
#
# good_method_call(
# "this is the first argument.",
# "this is argument number two!",
# )
#
# is more readable than
#
# bad_method_call("this is the first argument.",
# "this is argument number two!")
#
# The second breaks the flow of the code's indentation and makes it
# harder for the eye to parse. It also makes it far more likely that
# argument lines will wrap and become unwieldy.
#
# ### Unenforced Rules
#
# Additional style preferences that Rubocop does not enforce:
#
# - If a method call is split across lines, each argument should be on
# its own line, *including the first argument*.
# - If a method call is split across lines, each argument should have
# a trailing comma, *including the last argument*.
# - If a method call is split across lines, the closing parenthesis
# should be on a line of its own, with the same indentation as the
# start of the method call.
#
Style/AlignParameters:
EnforcedStyle: with_fixed_indentation
# ---
# `and` and `or` do not have the same precedence as `&&` and `||`, so
# their use in conditionals is confusing. We prefer consistent use of
# `&&` and `||` for clarity.
#
# `and` and `or` do have some clear uses for control flow, so we'll
# allow that:
#
# File.exist?(".rubocop.yml") or raise "YOU ARE DREADFULLY UNSTYLISH"
#
# ### Unenforced Rules
#
# An additional rule that is *not* enforced by Rubocop is that `!`
# should also be preferred to `not`. `not` has issues similar to those
# of `and` and `or`. It also (fun fact!) inexplicably causes syntax
# errors in some combinations with them.
Style/AndOr:
EnforcedStyle: conditionals
# ---
# The block delimiters cop will enforce braces or `do`/`end` around
# blocks depending on either length (braces for single-line blocks) or
# context (braces for functional blocks).
#
# Our style can't be fully enforced by either of those rules, so this
# cop is disabled.
#
# ### Unenforced Rules
#
# Our style is this:
#
# - `do`/`end` should *always* be used for multi-line blocks. A block
# braces should never span more than one line.
# - `do`/`end` can be used around a single-line block when the line is
# long or putting it in a `do`/`end` block adds clarity.
#
# For example:
#
# style_guide.tap {|s| s.save! }
#
# new_guide = style_guide.rules.map do |rule|
# rule.explanation.gsub("Ruby", "Elixir")
# end
#
# are probably more readable than
#
# style_guide.tap do |guide|
# guide.save!
# end
#
# new_guide = style_guide.rules.map{|r| r.explanation.gsub("Ruby", "Elixir") }
#
Style/BlockDelimiters:
Enabled: false
# ---
# This cop enforces a preference on braces around hash literals in
# parameters. Its provided policies don't match our style.
#
# ### Unenforced Rules
#
# - Braces must be used when there is more than one hash parameter.
# Otherwise, Ruby will not be able to divide the hash parameters
# correctly.
# - Braces should be used when a hash parameter is split across lines.
# In that case, the first entry in the hash should be on a new line
# after the opening brace.
# - Braces should generally not be used for an implicit hash as the
# parameter, but this is up to the author's discretion.
#
# For example:
#
# good_method_call({first_hash: true}, {second_hash: true})
#
# good_method_call({
# first_option: "one",
# second_option: 2,
# })
#
# good_method_call(implicit_hash: true)
#
Style/BracesAroundHashParameters:
Enabled: false
# ---
# There is no aesthetically pleasing way to indent a `case` block.
#
# The `end` corresponding to a `case` should start on the same column as
# the line that started the `case`.
Style/CaseIndentation:
IndentWhenRelativeTo: end
IndentOneStep: yes
# ---
# Whether to use the nested or compact style for class or module
# definitions is up to the author's discretion.
#
# The nested style is usually preferable, but it can become unwieldy if
# the nesting hierarchy is complex.
#
# A good rule of thumb is probably to use the nested style unless you're
# nesting something more than 2 or 3 levels deep.
Style/ClassAndModuleChildren:
Enabled: false
# ---
# Both `kind_of?` and `is_a?` are available methods for checking
# class and module inheritance.
#
# Each has cases in which it is more clear. It's up to the author's
# discretion as long as clarity is achieved.
Style/ClassCheck:
Enabled: false
# ---
# `map`, `reduce`, `find`, and `select` are clear and common names.
# `collect`, `inject`, and `detect` are not less-obvious aliases for
# these, and are not preferred.
Style/CollectionMethods:
PreferredMethods:
collect: 'map'
collect!: 'map!'
inject: 'reduce'
detect: 'find'
find_all: 'select'
# ---
# Backticks are clear and easy to understand for single-line shell
# commands.
#
# If you need to split a shell command across multiple lines, use `%x`.
Style/CommandLiteral:
EnforcedStyle: mixed
# ---
# There are a few types of "special" comments like `# TODO`
# that should follow a standard format.
#
# Rubocop will ensure that any comment that starts with one of the
# keywords below has a colon and a comment:
#
# # REVIEW: we probably don't need all of these keywords, though.
#
Style/CommentAnnotation:
Keywords:
- TODO
- FIXME
- OPTIMIZE
- HACK
- REVIEW
# ---
# It's easier to see at a glance that method chaining is happening
# if the dot is at the beginning of the line.
#
# Putting the dot at the beginning of the line also makes it easier to
# add extra methods into a chain. It also makes VCS history cleaner;
# see the argument for `Style/TrailingComma` for a similar argument.
#
# We prefer
#
# (1..10).map {|n| n * 2 }
# .take {|n| n % 5 == 3 }
# .each {|n| puts n }
#
# to
#
# (1..10).map {|n| n * 2 }.
# take {|n| n % 5 == 3 }.
# each {|n| puts n }
#
Style/DotPosition:
EnforcedStyle: leading
# ---
# An empty else is redundant and unnecessary,
# but an else with a nil make intent explicit.
#
# Have an `else` block that evaluates to `nil` if you think it makes
# your code more clear.
Style/EmptyElse:
EnforcedStyle: empty
# ---
# Empty lines break up code.
#
# We will not stop you from having two empty lines in a row,
# if you feel that it makes your code clearer or cleaner.
Style/EmptyLines:
Enabled: false
# ---
# Keeping empty lines around access modifiers makes them more prominent.
#
# Access modifiers don't change indentation, so they run the risk of looking
# like they're associated with the following method if they're placed too
# close. The empty line adds clarity.
Style/EmptyLinesAroundAccessModifier:
Enabled: true
# ---
# One-line defs should be concise and obvious.
#
# Empty lines between them shouldn't be too helpful,
# so feel free to butt them up against each other if you think it's
# clear.
Style/EmptyLineBetweenDefs:
AllowAdjacentOneLineDefs: true
# ---
# It looks ridiculous to require an empty line at the beginning of every
# block, but it *can* aid clarity in some cases if an empty line is
# included.
#
# You should generally not include an empty line, but you should do so
# at your discretion if it enhances clarity for the reader.
Style/EmptyLinesAroundBlockBody:
Enabled: false
Style/EmptyLinesAroundClassBody:
Enabled: false
Style/EmptyLinesAroundModuleBody:
Enabled: false
# ---
# The encoding for a file controls what the interpreter expects to see.
#
# It *also* affects how strings are treated *in the context of that
# file*, so
#
# - it should always be specified explicitly.
# - it should be specified consistently across the codebase.
# - it should be set to utf-8 unless there is a *very, very good
# reason* to do something else.
#
Style/Encoding:
EnforcedStyle: always
AutoCorrectEncodingComment: '# encoding: utf-8'
Style/FirstParameterIndentation:
EnforcedStyle: consistent
# ---
# A `for` can either be done as an `each` or, in rarer cases, a `while`.
#
# We prefer `each`, because it is more idiomatic Ruby and is probably
# always cleaner.
Style/For:
EnforcedStyle: each
# ---
# Ruby's `sprintf` works exactly the same as `sprintf` anywhere else
# (like, say, in C). That makes it clear to anyone who has ever seen
# a `sprintf` before.
#
# `format`, while a more sensible name, is less common and can mean
# different things in other languages.
#
# We prefer `sprintf` for clarity.
Style/FormatString:
EnforcedStyle: sprintf
# ---
# ### Unenforced Rules
#
# Guard clauses can be simpler and clearer than full-blown conditionals
# in many cases. We prefer them in those cases:
#
# def process
# do_process if ready_to_process?
# end
#
# get '/protected' do
# return 401 if !current_user.authorized?
#
# # continue for authorized users only
# end
#
# However, there are cases in which an explicit conditional makes the
# author's intent more clear. Using conditionals in those cases is up
# to the author's discretion.
#
# Especially in cases where we halt processing based on a condition (for
# example, the `return 401 if !current_user.authorized?` above), we
# prefer the guard clause, since it puts the `return` (or `next` or
# other flow-halting thing) prominently at the front of the line.
Style/GuardClause:
Enabled: false
# ---
# When writing a hash literal:
#
# - use Ruby 1.9 syntax if your keys are only symbols.
# - use hash rockets for *all* keys if they are not *all* symbols.
#
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys
# Gemfiles, however, have their own standard syntax.
# Let's not police that.
Exclude:
- Gemfile
# ---
# A multiline if/unless is more blatantly clear than a modifier.
#
# If you think it adds necessary clarity to your code, use a multiline
# if/unless.
Style/IfUnlessModifier:
Enabled: false
# ---
# Indentation should always be consistent, with two-space indentation
# levels.
#
# Method definitions should always be indented one level from the
# enclosing scope, even if they are modified by a `protected` or
# `private` modifier. Those access modifiers do not have
# a corresponding `end`, so they should not change the indentation
# level.
#
# class Thingy
# def do_things
# # ...
# end
#
# private
# def do_private_things
# # ...
# end
# end
#
# If the first key of a hash is on a separate line from the opening
# brace, it should be indented on level from the start of the line
# containing the opening brace. For example:
#
# # Yes!
# pretty_method_call({
# first_key: "indented one level",
# })
#
# # Yuck!
# hideous_method_call({
# first_key: "way out in the margins!",
# })
#
Style/IndentationConsistency:
EnforcedStyle: normal
Style/IndentationWidth:
Width: 2
Style/IndentHash:
EnforcedStyle: consistent
# ---
# ### Unenforced Rules
#
# We prefer the new 1.9-style lambda shorthand for consistency.
#
# Use the old style `lambda do ... end` when it stands alone and
# makes the code more clear, but feel free to use the new style
# wherever it makes the code more consistent.
#
# Always use the new style for single-line lambdas.
#
# # Good:
# id = ->(x) { x }
# palindrome = ->(x) do
# reversed = x.reverse
# x + reversed
# end
Style/Lambda:
Enabled: false
# ---
# ### Unenforced Rules
#
# There are three ways to call `Proc`s.
#
# We support either using `.call()` or `[]`; there are good use cases
# for each, and which to use is up to your discretion. A good rule of
# thumb is that you should use `[]` when it contextually resembles
# a hash or array access and makes the code more readable.
#
# You should not use `.()`, because it resembles literally nothing else
# in Ruby and makes no sense to new readers.
#
# To clarify:
#
# id = ->(x) { x }
#
# id.call(5) # => good!
# id[5] # => good (sometimes).
# id.(5) # => WTF even is this?
#
# This cop allows enforcing either `[]` or `.call()`, but not allowing
# both.
Style/LambdaCall:
Enabled: false
# ---
# ### Unenforced Rules
#
# You should always have a space before textual comments.
#
# It sometimes enhances clarity to have no space before commented-out code.
#
# However, you should not routinely check in commented-out code.
# If you intend to delete it, then make sure it is in VCS history and just delete it.
Style/LeadingCommentSpace:
Enabled: false
# ---
# This enforces using `unless whatever` instead of `if !whatever`.
#
# The choice of `unless` versus `if not` is a choice made by the author to
# show intent, so we won't enforce either. Write what is most clear.
Style/NegatedIf:
Enabled: false
# ---
# This enforces using `next` to skip iteration instead of ending an
# iteration block with a conditional.
#
# The example from [Rubocop's source][rubocop-source-style-next]
# follows:
#
# # Bad:
# [1, 2].each do |a|
# if a == 1
# puts a
# end
# end
#
# # Good:
# [1, 2].each do |a|
# next unless a == 1
# puts a
# end
#
# [rubocop-source-style-next]: https://github.com/bbatsov/rubocop/blob/v0.32.1/lib/rubocop/cop/style/next.rb
#
Style/Next:
EnforcedStyle: skip_modifier_ifs
MinBodyLength: 3
# ---
# `if !x.nil?` is more explicit and clear than `if x`.
#
# Either is acceptable, and it's up to the author's discretion whether
# `if x` is clear enough.
#
# When in doubt, use `.nil?`.
Style/NonNilCheck:
IncludeSemanticChanges: false
# ---
# We prefer method definitions to have parenthesis around parameters,
# simply because it's less jarring:
#
# # Consistent and clear:
# def take_arguments(one, another) end
#
# # Jarring:
# def take_arguments one, another end
#
Style/MethodDefParentheses:
EnforcedStyle: require_parentheses
# ---
# Snake-case method names are consistent with core Ruby and the standard
# library.
Style/MethodName:
EnforcedStyle: snake_case
# ---
# Chaining multiline blocks can be ugly, but it can be useful for expressing
# a functional pipeline that data passes through.
#
# If you're using a lot of multiline blocks, consider whether they can be
# turned into methods instead.
Style/MultilineBlockChain:
Enabled: false
# ---
# Indentation makes it visually clear that something is happening
# across lines.
Style/MultilineOperationIndentation:
EnforcedStyle: indented
# ---
# Once your numeric literals get sufficiently large, you should aid the
# reader by using `_` to separate each three digits.
#
# You should do this once you get to six digits:
#
# 600_000 # => yay, I can read it!
# 600000 # => my god, it's full of zeroes.
#
Style/NumericLiterals:
MinDigits: 6
# Compelling use case for safe assignment in conditions:
#
# author = "Adam Lloyd <[email protected]>"
#
# if (m = author.match(/(#{EMAIL_REGEX})/))
# send_angry_email(m[1])
# end
#
Style/ParenthesesAroundCondition:
AllowSafeAssignment: true
# ---
# You can use whatever gobbledygook delimiters you want when using
# percent literals. Sometimes that's good, but it's probably better to
# be consistent.
#
# Brackets are convenient because they are paired and therefore don't
# need to be escaped within the literal as long as they remain paired.
#
# For all except regexes (`%r`), parentheses make sense. For regexes,
# all of the bracket pairs have meaning, so we'll use `{}`, as it's less
# common than `()` and `[]`.
#
# These are the Rubocop defaults.
Style/PercentLiteralDelimiters:
PreferredDelimiters:
'%': ()
'%i': ()
'%q': ()
'%Q': ()
'%r': '{}'
'%s': ()
'%w': ()
'%W': ()
'%x': ()
# ---
# We provide multiple arguments to `raise`, instead of using
# `Exception.new`:
#
# # Good!
# raise StyleException, "you are exceptionally stylish"
#
# # Nope.
# raise StyleException.new("your exceptions ain't on fleek")
#
# Confession: this is entirely because I always forget the `.new` and
# try to call the Exception subclass as a method.
Style/RaiseArgs:
EnforcedStyle: exploded
# ---
# Passing multiple arguments to `return` results in returning an array.
#
# You should just be clear and make the array explicit.
Style/RedundantReturn:
AllowMultipleReturnValues: false
# ---
# In many cases, explicitly making calls against `self` is safer and more clear.
#
# We encourage using `self`, even if it's redundant.
Style/RedundantSelf:
Enabled: false
# ---
# The choices here are:
# - slashes, which enforces slashes always
# - percent_r, which enforces %r always
# - mixed, which enforces slashes for single-line and %r for
# multi-line.
#
# Our ideal situation would be:
# - slashes always,
# - unless there's a slash in the regex, for which %r is better,
# - and with the `x` modifier on multi-line regexes.
#
# The `x` modifier lets you break regexes across lines and put
# comments in them, which seems like a *really* good idea if you have
# a regex that is so large that you want to break it across lines.
#
# This is a fairly good approximation of that, minus the `x` bit.
Style/RegexpLiteral:
EnforcedStyle: slashes
AllowInnerSlashes: false
# ---
# The rescue modifier is bad practice for doing real error handling,
# but can be used effectively.
#
# If you have a need to handle a particular class of error, use a
# multiline `begin`/`rescue`. If you need to make sure that, e.g.,
# a value exists regardless of *any* error that occurs in fetching it,
# a rescue modifier is fine.
Style/RescueModifier:
Enabled: false
# ---
# Assuming the use of "expression" is on point here, this should allow
#
# def shorty; true end
#
# but not
#
# def shorty; puts 'lol j/k long'; true end
#
# This will almost always result in more readable code.
Style/Semicolon:
AllowAsExpressionSeparator: false
# ---
# `fail` is a synonym for `raise`, but it's unusual and is apparently
# overridden in some places.
#
# We prefer `raise`, which is the clear standard.
#
# See: https://github.com/bbatsov/ruby-style-guide/issues/233
Style/SignalException:
EnforcedStyle: only_raise
# ---
# Block param names can be a form of documentation for the block.
#
# Rubocop can enforce specific variables names for one-line blocks,
# but we would prefer to leave them up to the author's discretion.
Style/SingleLineBlockParams:
Enabled: false
# ---
# I think single-line methods can be very clear if they're short,
# and I think there's some space between "short" and "empty", which is
# the only thing this cop supports.
#
# Single-line methods are bad if they're complex, but something like
#
# def supports_editing?; true end
#
# is plenty clear and concise, despite not being totally empty.
Style/SingleLineMethods:
Enabled: false
# ---
# It's probably better to go with single quotes in general.
#
# However, that becomes tricky when you have apostrophes or single
# quotes in the string you're quoting, and I think it looks bad to
# single-quote any string except those that have single quotes in
# them.
#
# Also, single-quoting by means that you need to change your quote
# style if you want to use interpolation. Doing that by default sets
# you up to accidentally try interpolation in non-interpolated
# strings.
Style/StringLiterals:
EnforcedStyle: double_quotes
# ---
# Here, it probably makes sense to enforce single-quotes.
#
# It's less potentially misleading on first glance, and it discourages
# doing interpolation inside of interpolation. If you're thinking of
# doing that, it's probably a bad and super-confusing idea.
Style/StringLiteralsInInterpolation:
EnforcedStyle: single_quotes
# ---
# Preference:
#
# lambda {|x| x }
#
# looks better and easier for the eye to parse than
#
# lambda {| x | x }
#
Style/SpaceAroundBlockParameters:
EnforcedStyleInsidePipes: no_space
# ---
# Preference:
#
# def something(required, defaulted="defaulted")
#
# is easier for the eye to parse clearly than
#
# def something(required, defaulted = "defaulted")
#
Style/SpaceAroundEqualsInParameterDefault:
EnforcedStyle: no_space
# ---
# Allowing multiple spaces around `=` and `=>` allows authors to align
# contiguous lines neatly.
#
# Think
#
# short = true
# super_long_name = true
#
# instead of
#
# short = true
# super_long_name = true
#
# Whether this is actually helpful will depend on context.
Style/SpaceAroundOperators:
MultiSpaceAllowedForOperators:
- '='
- '=>'
# ---
# Preference: it usually looks cleaner to use the space:
#
# (1..10).map {|n| n ** 2 }
#
# compared to
#
# (1..10).map{|n| n ** 2 }
#
Style/SpaceBeforeBlockBraces:
EnforcedStyle: space
# ---
# Preference: it looks cleaner to omit the space:
#
# [:thing_one, :thing_two]
#
# compared to
#
# [ :thing_one, :thing_two ]
#
Style/SpaceInsideBrackets:
Enabled: true
# ---
# Preference: blocks look most clear when only arguments butt up against
# the opening brace.
#
# 5.times { puts "iteration!" } # => good!
# 5.times {puts "iteration!"} # => weird.
#
# 5.times {|n| puts "#{n}th iteration!" } # => good!
# 5.times { |n| puts "#{n}th iteration!" } # => weird.
#
Style/SpaceInsideBlockBraces:
EnforcedStyle: space
SpaceBeforeBlockParameters: no
# ---
# Space inside the braces of a single-line hash literal is extraneous
# and doesn't aid the eye in parsing.
#
# When we enforce spaces inside braces for blocks (without arguments),
# it becomes very clear what you're looking at inside braces if there's
# *no* space inside of hash literals.
#
# {"x" => 4}
#
# vs
#
# { "x" => 4 }
#
# That said, in *most* cases, it's most clear to have a hash literal
# span multiple lines.
Style/SpaceInsideHashLiteralBraces:
EnforcedStyle: no_space
EnforcedStyleForEmptyBraces: no_space
# ---
# When possible, we prefer to use symbols as procs.
#
# For example:
#
# # Yuck, so verbose.
# (1..10).map {|n| n.to_s }
#
# # Wow, look at those space savings!
# (1..10).map(&:to_s)
#
Style/SymbolProc:
IgnoredMethods:
- respond_to
# ---
# It's generally good practice to have a trailing newline.
#
# If you butt heads with this cop, you might want to look into
# reconfiguring your editor.
Style/TrailingBlankLines:
EnforcedStyle: final_newline
# ---
# ### Unenforced Rules
#
# If you leave a comma out after the last item in a multiline list,
# you *will* eventually add another item to the end of the list and
# forget to add a comma to the preceding line. Later, you will find
# yourself fixing a syntax error.
#
# Also, if appending to a multiline list requires adding a comma to one
# line and then adding another line, your VCS's history will record that
# as a two-line change instead of the one-line change it really is.
# This will result in bloated diffs and misleading blames.
#
# The reason that this is unenforced is that Rubocop reports errors
# here for multiline *method calls*, too. Since it treats as multiline
# even method calls with a single multiline *hash* argument, it suggests
# that `})` become `},)`, which is hideous.
Style/TrailingComma:
# EnforcedStyleForMultiline: comma
Enabled: false
# ---
# The defaults for trivial accessors seem pretty reasonable.
#
# Disabling `ExactNameMatch` causes the cop to suggest accessors for
# things like
#
# def name
# @other_name
# end
#
# which is probably useful, because turning that into an accessor would
# be clearer.
#
# Other than that, we're changing nothing here. See the defaults
# [here](https://github.com/bbatsov/rubocop/blob/v0.32.1/config/default.yml#L671).
Style/TrivialAccessors:
ExactNameMatch: off
# ---
# Snake case variable names are the standard in Ruby.
Style/VariableName:
EnforcedStyle: snake_case
# ---
# There are few cases I can think of in which a `while` or `until`
# modifier is clearer than the multiline version. I think the modifier
# variant is more unclear the longer the line is.
Style/WhileUntilModifier:
MaxLineLength: 80
# ---
# This cop encourages the use of word arrays when applicable, rather
# than more-verbose array literals of quotes strings.
#
# For example:
#
# ["here", "are", "some", "words"]
#
# becomes
#
# %w(here are some words)
#
# We keep the default Rubocop regex because it seems sane, but start
# enforcing this rule only once you hit an array of three or more
# things. Enforcing it for less than that just seems overbearing.
Style/WordArray:
MinSize: 3
WordRegex: !ruby/regexp '/\A[\p{Word}]+\z/'
# ## Metrics
# This limits [ABC size](http://c2.com/cgi/wiki?AbcMetric).
#
# The default of 15 seems to be a little bit too strict.
Metrics/AbcSize:
Max: 20
# ---
# The default maximum for block nesting is 3. That seems reasonable.
Metrics/BlockNesting:
Max: 3
# ---
# A 100-line maximum seems arbitrary and small, but it *is* a good idea
# to start complaining about classes and modules getting too large.
Metrics/ClassLength:
CountComments: no
Max: 250
Metrics/ModuleLength:
CountComments: no
Max: 250
# ---
# The default for cyclomatic complexity is 6.
#
# That seems like it could be low, but we'll try to adhere to it.
Metrics/CyclomaticComplexity:
Max: 6
# ---
# There are a lot of cases where it's obnoxious to constrain lines to 80
# characters because they are more clear than they would be if split up.
#
# However, there probably *is* a point at which lines become too long to
# be clear. Let's hypothesize that that's at 120 characters.
Metrics/LineLength:
Max: 120
# ---
# Many of our enforced rules result in code longer than that encouraged
# by Rubocop's default style guide. As a result, we will probably wind up
# with longer methods by line than Rubocop expects.
#
# Rubocop's default is 10; we'll go with double that.
Metrics/MethodLength:
CountComments: no
Max: 20
# ---
# If our parameter lists contain more than 4 things, we should be using
# an options hash.
#
# If we have more than 4 *required* arguments, we're building something
# truly obnoxious to consume, and we should rethink the interface we're
# providing.
Metrics/ParameterLists:
CountKeywordArgs: yes
Max: 4
# ---
# The perceived complexity cop tries to measure the complexity that
# a method presents to a reader. See [its explanation in the
# source](https://github.com/bbatsov/rubocop/blob/v0.32.1/lib/rubocop/cop/metrics/perceived_complexity.rb)
# for more information.
#
# The default maximum score of 7 seems like it could be low but worth
# striving for.
Metrics/PerceivedComplexity:
Max: 7
# ## Linting
# See Style/ParenthesesAroundCondition.
Lint/AssignmentInCondition:
AllowSafeAssignment: yes
# ---
# The `end` should always be indented consistently with the block level
# it ends. That is,
#
# stylish = if adheres_to_this_guide?
# :probably
# else
# :probably_not
# end
#
# is clear, while
#
# stylish = if adheres_to_this_guide?
# :probably
# else
# :probably_not
# end
#
# is weird.
#
# Put differently, if you were to add `end`s to close all of the
# contexts you have open, you should have a cascade of `end`s, each of
# which is indented two spaces less than the previous, down to 0 spaces
# of indentation.
#
# There might be other cases in which this linter doesn't align things
# accordingly, but it's unclear what they are.
Lint/EndAlignment:
AlignWith: variable
AutoCorrect: true
# ---
# Similar to the previous rule, you should always be able to make
# a consistent cascade of `end`s.
#
# `start_of_line` here means that the `end` will be indented the same as
# the line that contains the corresponding `def`, even if the `def` is
# preceded by an access modifier like `private` or `protected`.
#
# Why would you precede the `def` with one of those? Unclear.
Lint/DefEndAlignment:
AlignWith: start_of_line
# ---
# You don't *need* to declare block arguments if you don't use them.
#
# However, it can make the code easier to understand and modify later,
# so we don't *require* that you omit arguments that you don't use.
Lint/UnusedBlockArgument:
Enabled: false
# ---
# See Lint/UnusedBlockArgument.
Lint/UselessAssignment:
Enabled: false
# ## Rails Cops
# `before_action` is more clear than `before_filter`.
#
# Not all actions are filters, but all filters are actions.
#
# Additionally, this makes it a little more clear that a "filter" is
# responsible for taking the action of redirecting (or returning a 401
# or whatever) if necessary.
Rails/ActionFilter:
EnforcedStyle: action
# ---
# If there were a cop that only allowed you to use the most sensible and
# correct `Date`/`Time`/`DateTime` methods, we'd enable that.
#
# This is a good start. But you're still in deep trouble if you have to
# deal with time.
#
# For elaboration on this, see [the
# source](https://github.com/bbatsov/rubocop/blob/v0.32.1/lib/rubocop/cop/rails/date.rb).
Rails/Date:
EnforcedStyle: always
# ---
# This cop ensures that you pass a block to `default_scope`, not
# a Proc.
Rails/DefaultScope:
Include:
- app/controllers/**/*.rb
# ---
# Building up a query by doing `.where(...)` and *then* retrieving
# things from it is consistent and clear.
#
# I'm in favor of doing `.where(...).first` instead of `.find_by(...)`
# to maintain that consistency, if the author thinks that's clearer.
# Another advantage of always using `where` is that it becomes easier to
# change what you retrieve later.
#
# There is no performance impact either way, since [`find_by` just does
# a `.where.take`, anyway][rails-docs-find-by].
#
# This cop would rewrite *any* `.where(...).first` as a `.find_by(...)`,
# which is in conflict with that.
#
# [rails-docs-find-by]: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by
Rails/FindBy:
Enabled: false
# ---
# `find_each` is far more efficient when iterating over query results.
# From the Rails documentation:
#
# > Looping through a collection of records from the database (using the all method, for example) is very inefficient since it will try to instantiate all the objects at once.
# >
# > In that case, batch processing methods allow you to work with the records in batches, thereby greatly reducing memory consumption.
# >
# > The find_each method uses find_in_batches with a batch size of 1000 (or as specified by the :batch_size option).
#
# Our setting deviates from the Rubocop default in that it also checks
# controllers, Grape API code in `app/api`, DB code (in case we need to
# use this in migrations), and Rake tasks.
Rails/FindEach:
Include:
- app/api/**/*.rb
- app/controllers/**/*.rb
- app/models/**/*.rb
- db/**/*.rb
- lib/tasks/**/*.rake
# ---
# This cop prefers `has_many :through` to `has_and_belongs_to_many`.
#
# We prefer `has_many :through` because it is more explicit and gives us
# more control over the join model.
Rails/HasAndBelongsToMany:
Include:
- app/models/**/*.rb
# ---
# This cop prefers `Rails.logger` calls to standard Ruby output methods.
#
# We will generally capture stdout and stderr, but we prefer
# `Rails.logger` because it gives us on central point of control and
# configuration for logging.
Rails/Output:
Include:
- app/**/*.rb
- config/**/*.rb
- db/**/*.rb
- lib/**/*.rb
# ---
# This cop prefers subscripting to using `read_attribute` or
# `write_attribute`.
#
# It feels a little cleaner to do
#
# if self[:attributed]
# self[:attributed] = false
# end
#
# than
#
# if read_attribute(:attributed)
# write_attribute(:attributed, false)
# end
#
# Our setting differs from the Rubocop default in that it also checks
# Grape API code in app/api, controller code, DB code (in the event
# that we need to do this in migrations or seeds), and Rake tasks.
Rails/ReadWriteAttribute:
Include:
- app/api/**/*.rb
- app/controllers/**/*.rb
- app/models/**/*.rb
- db/**/*.rb
- lib/tasks/**/*.rake
# ---
# This cop makes sure that we pass a `Proc` into a `scope`, rather than
# a plain method call. That is,
#
# scope :correct, -> { where(uses_proc: true) }
#
# rather than
#
# scope :incorrect, where(does_a_method_call_at_definition_time: true)
#
Rails/ScopeArgs:
Include:
- app/models/**/*.rb
# ---
# TL;DR: time zones are awful. In Rails, you should always call your
# `Time` API methods on `Time.zone`.
#
# In fact, the only reason that this is set to "acceptable" is that
# there is no "correct" way to parse a timestamp; it's only acceptable
# to do `DateTime.strptime(...).in_time_zone`.
Rails/TimeZone:
EnforcedStyle: acceptable
# ---
# We prefer the new style of Rails validations to the old.
#
# That is,
#
# validates :style, presence: true # => yay!
#
# validates_presence_of :style # => boo. :-(
#
Rails/Validation:
Include:
- app/models/**/*.rb
@alloy-d
Copy link
Author

alloy-d commented Jul 8, 2015

This reads better if run through docco:

$ npm install -g docco
$ docco -e .rb ruby.rubocop.yml
$ open docs/ruby.rubocop.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment