rubocop-airbnb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE.md +9 -0
  5. data/README.md +68 -0
  6. data/config/default.yml +39 -0
  7. data/config/rubocop-airbnb.yml +96 -0
  8. data/config/rubocop-bundler.yml +8 -0
  9. data/config/rubocop-gemspec.yml +9 -0
  10. data/config/rubocop-layout.yml +514 -0
  11. data/config/rubocop-lint.yml +315 -0
  12. data/config/rubocop-metrics.yml +47 -0
  13. data/config/rubocop-naming.yml +68 -0
  14. data/config/rubocop-performance.yml +143 -0
  15. data/config/rubocop-rails.yml +193 -0
  16. data/config/rubocop-rspec.yml +281 -0
  17. data/config/rubocop-security.yml +13 -0
  18. data/config/rubocop-style.yml +953 -0
  19. data/lib/rubocop-airbnb.rb +11 -0
  20. data/lib/rubocop/airbnb.rb +16 -0
  21. data/lib/rubocop/airbnb/inflections.rb +14 -0
  22. data/lib/rubocop/airbnb/inject.rb +20 -0
  23. data/lib/rubocop/airbnb/rails_autoloading.rb +55 -0
  24. data/lib/rubocop/airbnb/version.rb +8 -0
  25. data/lib/rubocop/cop/airbnb/class_name.rb +47 -0
  26. data/lib/rubocop/cop/airbnb/class_or_module_declared_in_wrong_file.rb +138 -0
  27. data/lib/rubocop/cop/airbnb/const_assigned_in_wrong_file.rb +74 -0
  28. data/lib/rubocop/cop/airbnb/continuation_slash.rb +25 -0
  29. data/lib/rubocop/cop/airbnb/default_scope.rb +20 -0
  30. data/lib/rubocop/cop/airbnb/factory_attr_references_class.rb +74 -0
  31. data/lib/rubocop/cop/airbnb/factory_class_use_string.rb +39 -0
  32. data/lib/rubocop/cop/airbnb/mass_assignment_accessible_modifier.rb +18 -0
  33. data/lib/rubocop/cop/airbnb/module_method_in_wrong_file.rb +104 -0
  34. data/lib/rubocop/cop/airbnb/no_timeout.rb +19 -0
  35. data/lib/rubocop/cop/airbnb/opt_arg_parameters.rb +38 -0
  36. data/lib/rubocop/cop/airbnb/phrase_bundle_keys.rb +67 -0
  37. data/lib/rubocop/cop/airbnb/risky_activerecord_invocation.rb +63 -0
  38. data/lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb +114 -0
  39. data/lib/rubocop/cop/airbnb/rspec_environment_modification.rb +58 -0
  40. data/lib/rubocop/cop/airbnb/simple_modifier_conditional.rb +23 -0
  41. data/lib/rubocop/cop/airbnb/spec_constant_assignment.rb +55 -0
  42. data/lib/rubocop/cop/airbnb/unsafe_yaml_marshal.rb +47 -0
  43. data/rubocop-airbnb.gemspec +32 -0
  44. data/spec/rubocop/cop/airbnb/class_name_spec.rb +78 -0
  45. data/spec/rubocop/cop/airbnb/class_or_module_declared_in_wrong_file_spec.rb +174 -0
  46. data/spec/rubocop/cop/airbnb/const_assigned_in_wrong_file_spec.rb +178 -0
  47. data/spec/rubocop/cop/airbnb/continuation_slash_spec.rb +162 -0
  48. data/spec/rubocop/cop/airbnb/default_scope_spec.rb +38 -0
  49. data/spec/rubocop/cop/airbnb/factory_attr_references_class_spec.rb +160 -0
  50. data/spec/rubocop/cop/airbnb/factory_class_use_string_spec.rb +26 -0
  51. data/spec/rubocop/cop/airbnb/mass_assignment_accessible_modifier_spec.rb +28 -0
  52. data/spec/rubocop/cop/airbnb/module_method_in_wrong_file_spec.rb +181 -0
  53. data/spec/rubocop/cop/airbnb/no_timeout_spec.rb +30 -0
  54. data/spec/rubocop/cop/airbnb/opt_arg_parameter_spec.rb +103 -0
  55. data/spec/rubocop/cop/airbnb/phrase_bundle_keys_spec.rb +74 -0
  56. data/spec/rubocop/cop/airbnb/risky_activerecord_invocation_spec.rb +54 -0
  57. data/spec/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace_spec.rb +284 -0
  58. data/spec/rubocop/cop/airbnb/rspec_environment_modification_spec.rb +64 -0
  59. data/spec/rubocop/cop/airbnb/simple_modifier_conditional_spec.rb +122 -0
  60. data/spec/rubocop/cop/airbnb/spec_constant_assignment_spec.rb +80 -0
  61. data/spec/rubocop/cop/airbnb/unsafe_yaml_marshal_spec.rb +50 -0
  62. data/spec/spec_helper.rb +35 -0
  63. metadata +150 -0
@@ -0,0 +1,26 @@
1
+ describe RuboCop::Cop::Airbnb::FactoryClassUseString do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'rejects with :class => Model' do
5
+ source = [
6
+ 'factory :help_answer, :class => Help::Answer do',
7
+ ' text { Faker::Company.name }',
8
+ 'end',
9
+ ].join("\n")
10
+ inspect_source(source)
11
+
12
+ expect(cop.offenses.size).to eq(1)
13
+ expect(cop.offenses.map(&:line)).to eq([1])
14
+ end
15
+
16
+ it 'passes with :class => "Model"' do
17
+ source = [
18
+ 'factory :help_answer, :class => "Help::Answer" do',
19
+ ' text { Faker::Company.name }',
20
+ 'end',
21
+ ].join("\n")
22
+ inspect_source(source)
23
+
24
+ expect(cop.offenses).to be_empty
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ describe RuboCop::Cop::Airbnb::MassAssignmentAccessibleModifier do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'rejects when accessible= is called' do
5
+ source = [
6
+ 'def some_method',
7
+ ' user = User.new',
8
+ ' user.accessible = [:first_name, :last_name]',
9
+ ' user.update_attributes(:first_name => "Walter", :last_name => "Udoing")',
10
+ 'end',
11
+ ].join("\n")
12
+ inspect_source(source)
13
+ expect(cop.offenses.size).to eq(1)
14
+ end
15
+
16
+ it 'accepts when accessible= is not called' do
17
+ source = [
18
+ 'def some_method',
19
+ ' user = User.new',
20
+ ' user.first_name = "Walter"',
21
+ ' user.last_name = "Udoing"',
22
+ ' user.save!',
23
+ 'end',
24
+ ].join("\n")
25
+ inspect_source(source)
26
+ expect(cop.offenses).to be_empty
27
+ end
28
+ end
@@ -0,0 +1,181 @@
1
+ describe RuboCop::Cop::Airbnb::ModuleMethodInWrongFile do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:config) do
5
+ RuboCop::Config.new(
6
+ {
7
+ "Rails" => {
8
+ "Enabled" => true,
9
+ },
10
+ }
11
+ )
12
+ end
13
+
14
+ # Put source in a directory under /tmp because this cop cares about the filename
15
+ # but not the parent dir name.
16
+ let(:tmpdir) { Dir.mktmpdir }
17
+ let(:models_dir) do
18
+ gemfile = File.new("#{tmpdir}/Gemfile", "w")
19
+ gemfile.close
20
+ FileUtils.mkdir_p("#{tmpdir}/app/models").first
21
+ end
22
+
23
+ after do
24
+ FileUtils.rm_rf tmpdir
25
+ end
26
+
27
+ it 'rejects if module method is in file with non-matching name' do
28
+ source = [
29
+ 'module Hello',
30
+ ' module Foo',
31
+ ' def baz', # error is here if this file is named bar.rb
32
+ ' 42',
33
+ ' end',
34
+ ' end',
35
+ 'end',
36
+ ].join("\n")
37
+
38
+ File.open "#{models_dir}/bar.rb", "w" do |file|
39
+ inspect_source(source, file)
40
+ end
41
+
42
+ expect(cop.offenses.size).to eq(1)
43
+ expect(cop.offenses.map(&:line).sort).to eq([3])
44
+ expect(cop.offenses.first.message).to include("Method baz should be defined in hello/foo.rb.")
45
+ end
46
+
47
+ it 'accepts if module method is in file with matching name' do
48
+ source = [
49
+ 'module Foo',
50
+ ' def baz',
51
+ ' 42',
52
+ ' end',
53
+ 'end',
54
+ ].join("\n")
55
+
56
+ File.open "#{models_dir}/foo.rb", "w" do |file|
57
+ inspect_source(source, file)
58
+ end
59
+
60
+ expect(cop.offenses).to be_empty
61
+ end
62
+
63
+ it 'rejects with "self." static methods and a non-matching name' do
64
+ source = [
65
+ 'module Foo',
66
+ ' def self.baz',
67
+ ' 42',
68
+ ' end',
69
+ 'end',
70
+ ].join("\n")
71
+
72
+ File.open "#{models_dir}/bar.rb", "w" do |file|
73
+ inspect_source(source, file)
74
+ end
75
+
76
+ expect(cop.offenses.size).to eq(1)
77
+ expect(cop.offenses.map(&:line).sort).to eq([2])
78
+ end
79
+
80
+ it 'accepts with "self." static methods and a matching name' do
81
+ source = [
82
+ 'module Foo',
83
+ ' def self.baz',
84
+ ' 42',
85
+ ' end',
86
+ 'end',
87
+ ].join("\n")
88
+
89
+ File.open "#{models_dir}/foo.rb", "w" do |file|
90
+ inspect_source(source, file)
91
+ end
92
+
93
+ expect(cop.offenses).to be_empty
94
+ end
95
+
96
+ it 'rejects with "<<" static methods and a non-matching name' do
97
+ source = [
98
+ 'module Foo',
99
+ ' class << self',
100
+ ' def baz',
101
+ ' 42',
102
+ ' end',
103
+ ' end',
104
+ 'end',
105
+ ].join("\n")
106
+
107
+ File.open "#{models_dir}/bar.rb", "w" do |file|
108
+ inspect_source(source, file)
109
+ end
110
+
111
+ expect(cop.offenses.size).to eq(1)
112
+ expect(cop.offenses.map(&:line).sort).to eq([3])
113
+ end
114
+
115
+ it 'accepts with "<<" static methods and a matching name' do
116
+ source = [
117
+ 'module Foo',
118
+ ' class << self',
119
+ ' def baz',
120
+ ' 42',
121
+ ' end',
122
+ ' end',
123
+ 'end',
124
+ ].join("\n")
125
+
126
+ File.open "#{models_dir}/foo.rb", "w" do |file|
127
+ inspect_source(source, file)
128
+ end
129
+
130
+ expect(cop.offenses).to be_empty
131
+ end
132
+
133
+ it 'accepts methods defined in a nested class' do
134
+ source = [
135
+ 'module Foo',
136
+ ' class Bar',
137
+ ' def qux',
138
+ ' end',
139
+ ' end',
140
+ 'end',
141
+ ].join("\n")
142
+
143
+ File.open "#{models_dir}/foo.rb", "w" do |file|
144
+ inspect_source(source, file)
145
+ end
146
+
147
+ expect(cop.offenses).to be_empty
148
+ end
149
+
150
+ it 'accepts methods where the containing class uses an acronym' do
151
+ source = [
152
+ 'module CSVFoo',
153
+ ' def baz',
154
+ ' 42',
155
+ ' end',
156
+ 'end',
157
+ ].join("\n")
158
+
159
+ File.open "#{models_dir}/csv_foo.rb", "w" do |file|
160
+ inspect_source(source, file)
161
+ end
162
+
163
+ expect(cop.offenses).to be_empty
164
+ end
165
+
166
+ it 'ignores rake tasks' do
167
+ source = [
168
+ 'module Hello',
169
+ ' def baz', # error is here if this file is named bar.rb
170
+ ' 42',
171
+ ' end',
172
+ 'end',
173
+ ].join("\n")
174
+
175
+ File.open "#{models_dir}/bar.rake", "w" do |file|
176
+ inspect_source(source, file)
177
+ end
178
+
179
+ expect(cop.offenses).to be_empty
180
+ end
181
+ end
@@ -0,0 +1,30 @@
1
+ describe RuboCop::Cop::Airbnb::NoTimeout do
2
+ subject(:cop) { described_class.new }
3
+
4
+ context 'send' do
5
+ it 'rejects Timeout.timeout' do
6
+ source = [
7
+ 'def some_method(a)',
8
+ ' Timeout.timeout(5) do',
9
+ ' some_other_method(a)',
10
+ ' end',
11
+ 'end',
12
+ ].join("\n")
13
+ inspect_source(source)
14
+ expect(cop.offenses.size).to eql(1)
15
+ expect(cop.offenses.first.message).to start_with('Do not use Timeout.timeout')
16
+ end
17
+
18
+ it 'accepts foo.timeout' do
19
+ source = [
20
+ 'def some_method(a)',
21
+ ' foo.timeout do',
22
+ ' some_other_method(a)',
23
+ ' end',
24
+ 'end',
25
+ ].join("\n")
26
+ inspect_source(source)
27
+ expect(cop.offenses).to be_empty
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,103 @@
1
+ describe RuboCop::Cop::Airbnb::OptArgParameters do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'allows method with no parameters' do
5
+ source = [
6
+ 'def my_method',
7
+ 'end',
8
+ ].join("\n")
9
+
10
+ inspect_source(source)
11
+ expect(cop.offenses).to be_empty
12
+ end
13
+
14
+ it 'allows method with one parameter' do
15
+ source = [
16
+ 'def my_method(params)',
17
+ 'end',
18
+ ].join("\n")
19
+
20
+ inspect_source(source)
21
+ expect(cop.offenses).to be_empty
22
+ end
23
+
24
+ it 'allows method with one parameter with a default hash value' do
25
+ source = [
26
+ 'def my_method(params = {})',
27
+ 'end',
28
+ ].join("\n")
29
+
30
+ inspect_source(source)
31
+ expect(cop.offenses).to be_empty
32
+ end
33
+
34
+ it 'allows method named default parameters' do
35
+ source = [
36
+ 'def my_method(a, b, c: 5, d: 6)',
37
+ 'end',
38
+ ].join("\n")
39
+
40
+ inspect_source(source)
41
+ expect(cop.offenses).to be_empty
42
+ end
43
+
44
+ it 'allows method with multiple parameter with a default hash value' do
45
+ source = [
46
+ 'def my_method(a, b, c, params = {})',
47
+ 'end',
48
+ ].join("\n")
49
+
50
+ inspect_source(source)
51
+ expect(cop.offenses).to be_empty
52
+ end
53
+
54
+ it 'allows method with default parameter before block parameter' do
55
+ source = [
56
+ 'def my_method(a, b, c, params = {}, &block)',
57
+ 'end',
58
+ ].join("\n")
59
+
60
+ inspect_source(source)
61
+ expect(cop.offenses).to be_empty
62
+ end
63
+
64
+ it 'rejects method with a default parameter other than the last non-block parameter' do
65
+ source = [
66
+ 'def my_method(a, b = nil, c, &block)',
67
+ 'end',
68
+ ].join("\n")
69
+
70
+ inspect_source(source)
71
+ expect(cop.offenses.size).to eq(1)
72
+ end
73
+
74
+ it 'rejects method with a default parameter other than the last parameter' do
75
+ source = [
76
+ 'def my_method(a, b = 5, c = nil, params = {})',
77
+ 'end',
78
+ ].join("\n")
79
+
80
+ inspect_source(source)
81
+ expect(cop.offenses.size).to eq(2)
82
+ end
83
+
84
+ it 'rejects method where last parameter has a default value of nil' do
85
+ source = [
86
+ 'def my_method(a, b, c, params = nil)',
87
+ 'end',
88
+ ].join("\n")
89
+
90
+ inspect_source(source)
91
+ expect(cop.offenses.size).to eq(1)
92
+ end
93
+
94
+ it 'rejects method where last parameter has a default value of a constant' do
95
+ source = [
96
+ 'def my_method(a, b, c, params = Constants::A_CONSTANT)',
97
+ 'end',
98
+ ].join("\n")
99
+
100
+ inspect_source(source)
101
+ expect(cop.offenses.size).to eq(1)
102
+ end
103
+ end
@@ -0,0 +1,74 @@
1
+ describe RuboCop::Cop::Airbnb::PhraseBundleKeys do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'generates offenses for mismatched keys in PhraseBundle classes' do
5
+ source = <<EOS
6
+ # encoding: UTF-8
7
+ module PhraseBundles
8
+ class Host < PhraseBundle
9
+
10
+ def phrases
11
+ {
12
+ "shortened_key" => t(
13
+ "my_real_translation_key",
14
+ default: 'Does not matter',
15
+ ),
16
+ }
17
+ end
18
+ end
19
+ end
20
+ EOS
21
+
22
+ inspect_source(source)
23
+ expect(cop.offenses.size).to eq(1)
24
+ expect(cop.offenses.map(&:line).sort).to eq([7])
25
+ expect(cop.messages).to eq(
26
+ ['Phrase bundle keys should match their translation keys.']
27
+ )
28
+ end
29
+
30
+ it 'does not generate offenses for matching keys in PhraseBundle classes' do
31
+ source = <<EOS
32
+ # encoding: UTF-8
33
+ module PhraseBundles
34
+ class Host < PhraseBundle
35
+
36
+ def phrases
37
+ {
38
+ "my_real_translation_key" => t(
39
+ "my_real_translation_key",
40
+ default: 'Does not matter',
41
+ ),
42
+ }
43
+ end
44
+ end
45
+ end
46
+ EOS
47
+
48
+ inspect_source(source)
49
+ inspect_source(source)
50
+ expect(cop.offenses).to be_empty
51
+ end
52
+
53
+ it 'passes on t calls that are not in PhraseBundle classes' do
54
+ source = <<EOS
55
+ # encoding: UTF-8
56
+ module PhraseBundles
57
+ class Host
58
+
59
+ def phrases
60
+ {
61
+ "shortened_key" => t(
62
+ "my_real_translation_key",
63
+ default: 'Does not matter',
64
+ ),
65
+ }
66
+ end
67
+ end
68
+ end
69
+ EOS
70
+
71
+ inspect_source(source)
72
+ expect(cop.offenses).to be_empty
73
+ end
74
+ end