forked from covermymeds/rubocop-thread_safety
-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from rubocop/documentation
Add documentation
- Loading branch information
Showing
6 changed files
with
306 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'bundler/gem_tasks' | ||
require 'open3' | ||
require 'rspec/core/rake_task' | ||
|
||
Dir['tasks/**/*.rake'].each { |t| load t } | ||
|
||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
desc 'Confirm documentation is up to date' | ||
task confirm_documentation: :generate_cops_documentation do | ||
_, _, _, process = | ||
Open3.popen3('git diff --exit-code docs/') | ||
|
||
unless process.value.success? | ||
abort 'Please run `rake generate_cops_documentation` ' \ | ||
'and add docs/ to the commit.' | ||
end | ||
end | ||
|
||
task default: :spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
=== Department xref:cops_threadsafety.adoc[ThreadSafety] | ||
|
||
* xref:cops_threadsafety.adoc#threadsafetyclassandmoduleattributes[ThreadSafety/ClassAndModuleAttributes] | ||
* xref:cops_threadsafety.adoc#threadsafetyinstancevariableinclassmethod[ThreadSafety/InstanceVariableInClassMethod] | ||
* xref:cops_threadsafety.adoc#threadsafetymutableclassinstancevariable[ThreadSafety/MutableClassInstanceVariable] | ||
* xref:cops_threadsafety.adoc#threadsafetynewthread[ThreadSafety/NewThread] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
= ThreadSafety | ||
|
||
== ThreadSafety/ClassAndModuleAttributes | ||
|
||
|=== | ||
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | ||
|
||
| Enabled | ||
| Yes | ||
| No | ||
| - | ||
| - | ||
|=== | ||
|
||
Avoid mutating class and module attributes. | ||
|
||
They are implemented by class variables, which are not thread-safe. | ||
|
||
=== Examples | ||
|
||
[source,ruby] | ||
---- | ||
# bad | ||
class User | ||
cattr_accessor :current_user | ||
end | ||
---- | ||
|
||
== ThreadSafety/InstanceVariableInClassMethod | ||
|
||
|=== | ||
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | ||
|
||
| Enabled | ||
| Yes | ||
| No | ||
| - | ||
| - | ||
|=== | ||
|
||
Avoid instance variables in class methods. | ||
|
||
=== Examples | ||
|
||
[source,ruby] | ||
---- | ||
# bad | ||
class User | ||
def self.notify(info) | ||
@info = validate(info) | ||
Notifier.new(@info).deliver | ||
end | ||
end | ||
class Model | ||
class << self | ||
def table_name(name) | ||
@table_name = name | ||
end | ||
end | ||
end | ||
class Host | ||
%i[uri port].each do |key| | ||
define_singleton_method("#{key}=") do |value| | ||
instance_variable_set("@#{key}", value) | ||
end | ||
end | ||
end | ||
module Example | ||
module ClassMethods | ||
def test(params) | ||
@params = params | ||
end | ||
end | ||
end | ||
module Example | ||
class_methods do | ||
def test(params) | ||
@params = params | ||
end | ||
end | ||
end | ||
module Example | ||
module_function | ||
def test(params) | ||
@params = params | ||
end | ||
end | ||
module Example | ||
def test(params) | ||
@params = params | ||
end | ||
module_function :test | ||
end | ||
---- | ||
|
||
== ThreadSafety/MutableClassInstanceVariable | ||
|
||
|=== | ||
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | ||
|
||
| Enabled | ||
| Yes | ||
| Yes (Unsafe) | ||
| - | ||
| - | ||
|=== | ||
|
||
Checks whether some class instance variable isn't a | ||
mutable literal (e.g. array or hash). | ||
|
||
It is based on Style/MutableConstant from RuboCop. | ||
See https://github.com/rubocop-hq/rubocop/blob/master/lib/rubocop/cop/style/mutable_constant.rb | ||
|
||
Class instance variables are a risk to threaded code as they are shared | ||
between threads. A mutable object such as an array or hash may be | ||
updated via an attr_reader so would not be detected by the | ||
ThreadSafety/ClassAndModuleAttributes cop. | ||
|
||
Strict mode can be used to freeze all class instance variables, rather | ||
than just literals. | ||
Strict mode is considered an experimental feature. It has not been | ||
updated with an exhaustive list of all methods that will produce frozen | ||
objects so there is a decent chance of getting some false positives. | ||
Luckily, there is no harm in freezing an already frozen object. | ||
|
||
=== Examples | ||
|
||
==== EnforcedStyle: literals (default) | ||
|
||
[source,ruby] | ||
---- | ||
# bad | ||
class Model | ||
@list = [1, 2, 3] | ||
end | ||
# good | ||
class Model | ||
@list = [1, 2, 3].freeze | ||
end | ||
# good | ||
class Model | ||
@var = <<~TESTING.freeze | ||
This is a heredoc | ||
TESTING | ||
end | ||
# good | ||
class Model | ||
@var = Something.new | ||
end | ||
---- | ||
|
||
==== EnforcedStyle: strict | ||
|
||
[source,ruby] | ||
---- | ||
# bad | ||
class Model | ||
@var = Something.new | ||
end | ||
# bad | ||
class Model | ||
@var = Struct.new do | ||
def foo | ||
puts 1 | ||
end | ||
end | ||
end | ||
# good | ||
class Model | ||
@var = Something.new.freeze | ||
end | ||
# good | ||
class Model | ||
@var = Struct.new do | ||
def foo | ||
puts 1 | ||
end | ||
end.freeze | ||
end | ||
---- | ||
|
||
=== Configurable attributes | ||
|
||
|=== | ||
| Name | Default value | Configurable values | ||
|
||
| EnforcedStyle | ||
| `literals` | ||
| `literals`, `strict` | ||
|=== | ||
|
||
== ThreadSafety/NewThread | ||
|
||
|=== | ||
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | ||
|
||
| Enabled | ||
| Yes | ||
| No | ||
| - | ||
| - | ||
|=== | ||
|
||
Avoid starting new threads. | ||
|
||
Let a framework like Sidekiq handle the threads. | ||
|
||
=== Examples | ||
|
||
[source,ruby] | ||
---- | ||
# bad | ||
Thread.new { do_work } | ||
---- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rubocop' | ||
require 'rubocop-thread_safety' | ||
require 'rubocop/cops_documentation_generator' | ||
require 'yard' | ||
|
||
YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task| | ||
task.files = ['lib/rubocop/cop/**/*.rb'] | ||
task.options = ['--no-output'] | ||
end | ||
|
||
desc 'Generate docs of all cops departments' | ||
task generate_cops_documentation: :yard_for_generate_documentation do | ||
deps = ['ThreadSafety'] | ||
CopsDocumentationGenerator.new(departments: deps).call | ||
end | ||
|
||
desc 'Syntax check for the documentation comments' | ||
task documentation_syntax_check: :yard_for_generate_documentation do | ||
require 'parser/ruby31' | ||
|
||
ok = true | ||
YARD::Registry.load! | ||
cops = RuboCop::Cop::Registry.global | ||
cops.each do |cop| | ||
examples = YARD::Registry.all(:class).find do |code_object| | ||
next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge | ||
|
||
break code_object.tags('example') | ||
end | ||
|
||
examples.to_a.each do |example| | ||
buffer = Parser::Source::Buffer.new('<code>', 1) | ||
buffer.source = example.text | ||
parser = Parser::Ruby31.new(RuboCop::AST::Builder.new) | ||
parser.diagnostics.all_errors_are_fatal = true | ||
parser.parse(buffer) | ||
rescue Parser::SyntaxError => e | ||
path = example.object.file | ||
puts "#{path}: Syntax Error in an example. #{e}" | ||
ok = false | ||
end | ||
end | ||
abort unless ok | ||
end |