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,54 @@
1
+ describe RuboCop::Cop::Airbnb::RiskyActiverecordInvocation do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it "allows where statement that's a hash" do
5
+ source = [
6
+ 'Users.where({:name => "Bob"})',
7
+ ].join("\n")
8
+
9
+ inspect_source(source)
10
+ expect(cop.offenses).to be_empty
11
+ end
12
+
13
+ it "allows where statement that's a flat string" do
14
+ source = 'Users.where("age = 24")'
15
+
16
+ inspect_source(source)
17
+ expect(cop.offenses).to be_empty
18
+ end
19
+
20
+ it "allows a multiline where statement" do
21
+ source = "Users.where(\"age = 24 OR \" \\\n\"age = 25\")"
22
+
23
+ inspect_source(source)
24
+ expect(cop.offenses).to be_empty
25
+ end
26
+
27
+ it "allows interpolation in subsequent arguments to where" do
28
+ source = 'Users.where("name like ?", "%#{name}%")'
29
+
30
+ inspect_source(source)
31
+ expect(cop.offenses).to be_empty
32
+ end
33
+
34
+ it "disallows interpolation in where statements" do
35
+ source = 'Users.where("name = #{username}")'
36
+
37
+ inspect_source(source)
38
+ expect(cop.offenses.size).to eq(1)
39
+ end
40
+
41
+ it "disallows addition in where statements" do
42
+ source = 'Users.where("name = " + username)'
43
+
44
+ inspect_source(source)
45
+ expect(cop.offenses.size).to eq(1)
46
+ end
47
+
48
+ it "disallows interpolation in order statements" do
49
+ source = 'Users.where("age = 24").order("name #{sortorder}")'
50
+
51
+ inspect_source(source)
52
+ expect(cop.offenses.size).to eq(1)
53
+ end
54
+ end
@@ -0,0 +1,284 @@
1
+ describe RuboCop::Cop::Airbnb::RspecDescribeOrContextUnderNamespace do
2
+ subject(:cop) { described_class.new }
3
+
4
+ let(:tmpdir) { Dir.mktmpdir }
5
+ let(:models_spec_dir) do
6
+ FileUtils.mkdir_p("#{tmpdir}/spec/models").first
7
+ end
8
+
9
+ after do
10
+ FileUtils.rm_rf tmpdir
11
+ end
12
+
13
+ shared_examples 'rspec namespacing rule' do
14
+ context 'under a namespace' do
15
+ it 'rejects without change message when argument is a string' do
16
+ source = [
17
+ 'module Foo',
18
+ " #{method} 'SomeClass' do",
19
+ ' it "passes" do',
20
+ ' expect(true).to be_true',
21
+ ' end',
22
+ ' end',
23
+ 'end',
24
+ ].join("\n")
25
+
26
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
27
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
28
+ inspect_source(source, file)
29
+ end
30
+
31
+ expect(cop.offenses.size).to eql(1)
32
+ expect(cop.offenses.first.message).
33
+ to include('Declaring a `module` in a spec can break autoloading because ')
34
+
35
+ expect(cop.offenses.first.message).
36
+ not_to include(
37
+ "Change `#{method} SomeClass do` to `#{method} Foo::SomeClass do`"
38
+ )
39
+
40
+ expect(cop.offenses.first.message).
41
+ to include('Remove `module Foo` and fix `Foo::CONST` and `Foo.method` calls')
42
+ end
43
+
44
+ it 'rejects with change message when argument is a constant' do
45
+ source = [
46
+ 'module Foo',
47
+ " #{method} SomeClass do",
48
+ ' it "passes" do',
49
+ ' expect(true).to be_true',
50
+ ' end',
51
+ ' end',
52
+ 'end',
53
+ ].join("\n")
54
+
55
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
56
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
57
+ inspect_source(source, file)
58
+ end
59
+
60
+ expect(cop.offenses.size).to eql(1)
61
+ expect(cop.offenses.first.message).
62
+ to include('Declaring a `module` in a spec can break autoloading because ')
63
+
64
+ expect(cop.offenses.first.message).
65
+ to include(
66
+ "Change `#{method} SomeClass do` to `#{method} Foo::SomeClass do`"
67
+ )
68
+
69
+ expect(cop.offenses.first.message).
70
+ to include('Remove `module Foo` and fix `Foo::CONST` and `Foo.method` calls')
71
+ end
72
+
73
+ it 'rejects when within a nested block' do
74
+ source = [
75
+ 'module Foo',
76
+ ' 1.times do',
77
+ " #{method} SomeClass do",
78
+ ' it "passes" do',
79
+ ' expect(true).to be_true',
80
+ ' end',
81
+ ' end',
82
+ ' end',
83
+ 'end',
84
+ ].join("\n")
85
+
86
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
87
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
88
+ inspect_source(source, file)
89
+ end
90
+
91
+ expect(cop.offenses.size).to eql(1)
92
+ expect(cop.offenses.first.message).
93
+ to include('Declaring a `module` in a spec can break autoloading because ')
94
+
95
+ expect(cop.offenses.first.message).
96
+ to include(
97
+ "Change `#{method} SomeClass do` to `#{method} Foo::SomeClass do`"
98
+ )
99
+
100
+ expect(cop.offenses.first.message).
101
+ to include('Remove `module Foo` and fix `Foo::CONST` and `Foo.method` calls')
102
+ end
103
+
104
+ it 'rejects when a block is executed prior' do
105
+ source = [
106
+ 'module Foo',
107
+ ' [1,2,3].each do',
108
+ ' something',
109
+ ' end',
110
+ '',
111
+ " #{method} SomeClass do",
112
+ ' it "passes" do',
113
+ ' expect(true).to be_true',
114
+ ' end',
115
+ ' end',
116
+ 'end',
117
+ ].join("\n")
118
+
119
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
120
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
121
+ inspect_source(source, file)
122
+ end
123
+
124
+ expect(cop.offenses.size).to eql(1)
125
+ expect(cop.offenses.first.message).
126
+ to include('Declaring a `module` in a spec can break autoloading because ')
127
+
128
+ expect(cop.offenses.first.message).
129
+ to include(
130
+ "Change `#{method} SomeClass do` to `#{method} Foo::SomeClass do`"
131
+ )
132
+
133
+ expect(cop.offenses.first.message).
134
+ to include('Remove `module Foo` and fix `Foo::CONST` and `Foo.method` calls')
135
+ end
136
+ end
137
+ end
138
+
139
+ context 'describe' do
140
+ let!(:method) { 'describe' }
141
+
142
+ it_behaves_like 'rspec namespacing rule'
143
+ end
144
+
145
+ context 'RSpec.describe' do
146
+ let!(:method) { 'RSpec.describe' }
147
+
148
+ it_behaves_like 'rspec namespacing rule'
149
+ end
150
+
151
+ context 'context' do
152
+ let!(:method) { 'context' }
153
+
154
+ it_behaves_like 'rspec namespacing rule'
155
+ end
156
+
157
+ context 'RSpec.context' do
158
+ let!(:method) { 'RSpec.context' }
159
+
160
+ it_behaves_like 'rspec namespacing rule'
161
+ end
162
+
163
+ it 'accepts if file is not a spec file' do
164
+ source = [
165
+ 'module Foo',
166
+ ' RSpec.describe "SomeClass" do',
167
+ ' it "passes" do',
168
+ ' expect(true).to be_true',
169
+ ' end',
170
+ ' end',
171
+ 'end',
172
+ ].join("\n")
173
+
174
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
175
+ File.open "#{models_spec_dir}/foo/some_class.rb", "w" do |file|
176
+ inspect_source(source, file)
177
+ end
178
+
179
+ expect(cop.offenses).to be_empty
180
+ end
181
+
182
+ it 'accepts if not under a module' do
183
+ source = [
184
+ 'RSpec.describe "SomeClass" do',
185
+ ' it "passes" do',
186
+ ' expect(true).to be_true',
187
+ ' end',
188
+ 'end',
189
+ ].join("\n")
190
+
191
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
192
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
193
+ inspect_source(source, file)
194
+ end
195
+
196
+ expect(cop.offenses).to be_empty
197
+ end
198
+
199
+ it 'accepts if not describe or context' do
200
+ source = [
201
+ 'module Foo',
202
+ ' not_describe_or_context "SomeClass" do',
203
+ ' it "passes" do',
204
+ ' expect(true).to be_true',
205
+ ' end',
206
+ ' end',
207
+ 'end',
208
+ ].join("\n")
209
+
210
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
211
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
212
+ inspect_source(source, file)
213
+ end
214
+
215
+ expect(cop.offenses).to be_empty
216
+ end
217
+
218
+ it 'accepts an empty module' do
219
+ source = [
220
+ 'RSpec.describe "SomeClass" do',
221
+ ' module Bar; end',
222
+ '',
223
+ ' it "passes" do',
224
+ ' expect(true).to be_true',
225
+ ' end',
226
+ 'end',
227
+ ].join("\n")
228
+
229
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
230
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
231
+ inspect_source(source, file)
232
+ end
233
+
234
+ expect(cop.offenses).to be_empty
235
+ end
236
+
237
+ it 'accepts a module with code' do
238
+ source = [
239
+ 'RSpec.describe "SomeClass" do',
240
+ ' module Bar',
241
+ ' def self.foo',
242
+ ' end',
243
+ ' foo',
244
+ ' end',
245
+ '',
246
+ ' it "passes" do',
247
+ ' expect(true).to be_true',
248
+ ' end',
249
+ 'end',
250
+ ].join("\n")
251
+
252
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
253
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
254
+ inspect_source(source, file)
255
+ end
256
+
257
+ expect(cop.offenses).to be_empty
258
+ end
259
+
260
+ it 'accepts when describe or context to be called when class or module is not RSpec' do
261
+ source = [
262
+ 'module Foo',
263
+ ' Bar.describe "SomeClass" do',
264
+ ' it "passes" do',
265
+ ' expect(true).to be_true',
266
+ ' end',
267
+ ' end',
268
+ '',
269
+ ' Bar.context "SomeClass" do',
270
+ ' it "passes" do',
271
+ ' expect(true).to be_true',
272
+ ' end',
273
+ ' end',
274
+ 'end',
275
+ ].join("\n")
276
+
277
+ FileUtils.mkdir_p "#{models_spec_dir}/foo"
278
+ File.open "#{models_spec_dir}/foo/some_class_spec.rb", "w" do |file|
279
+ inspect_source(source, file)
280
+ end
281
+
282
+ expect(cop.offenses).to be_empty
283
+ end
284
+ end
@@ -0,0 +1,64 @@
1
+ describe RuboCop::Cop::Airbnb::RspecEnvironmentModification do
2
+ subject(:cop) { described_class.new }
3
+
4
+ before(:each) do
5
+ allow(cop).to receive(:is_spec_file?).and_return(true)
6
+ end
7
+
8
+ it 'does not allow assignment of Rails.env' do
9
+ source = [
10
+ 'Rails.env = :production',
11
+ ].join("\n")
12
+ inspect_source(source)
13
+ expect(cop.offenses.size).to eql(1)
14
+ end
15
+
16
+ it 'allows assignment of Rails.env when not in spec' do
17
+ allow(cop).to receive(:is_spec_file?).and_return(false)
18
+ source = [
19
+ 'Rails.env = :production',
20
+ ].join("\n")
21
+ inspect_source(source)
22
+ expect(cop.offenses).to be_empty
23
+ end
24
+
25
+ it 'rejects allow style stubbing of Rails.env' do
26
+ source = [
27
+ 'def some_method(a)',
28
+ ' allow(Rails.env).to receive(:production?)',
29
+ 'end',
30
+ ].join("\n")
31
+ inspect_source(source)
32
+ expect(cop.offenses.size).to eql(1)
33
+ end
34
+
35
+ it 'rejects expect style stubbing of Rails.env' do
36
+ source = [
37
+ 'def some_method(a)',
38
+ ' expect(Rails.env).to receive(:production?)',
39
+ 'end',
40
+ ].join("\n")
41
+ inspect_source(source)
42
+ expect(cop.offenses.size).to eql(1)
43
+ end
44
+
45
+ it 'rejects .stub stubbing of Rails.env' do
46
+ source = [
47
+ 'def some_method(a)',
48
+ ' Rails.env.stub(:production)',
49
+ 'end',
50
+ ].join("\n")
51
+ inspect_source(source)
52
+ expect(cop.offenses.size).to eql(1)
53
+ end
54
+
55
+ it 'allows stub_env' do
56
+ source = [
57
+ 'def some_method(a)',
58
+ ' stub_env(:production)',
59
+ 'end',
60
+ ].join("\n")
61
+ inspect_source(source)
62
+ expect(cop.offenses).to be_empty
63
+ end
64
+ end
@@ -0,0 +1,122 @@
1
+ describe RuboCop::Cop::Airbnb::SimpleModifierConditional do
2
+ subject(:cop) { described_class.new }
3
+
4
+ context 'multiple conditionals' do
5
+ it 'rejects with modifier if with multiple conditionals' do
6
+ source = [
7
+ 'return true if some_method == 0 || another_method',
8
+ ].join("\n")
9
+
10
+ inspect_source(source)
11
+ expect(cop.offenses.size).to eq(1)
12
+ end
13
+
14
+ it 'rejects with modifier unless with multiple conditionals' do
15
+ source = [
16
+ 'return true unless true && false',
17
+ ].join("\n")
18
+
19
+ inspect_source(source)
20
+ expect(cop.offenses.size).to eq(1)
21
+ end
22
+
23
+ it 'allows with modifier if operator conditional' do
24
+ source = [
25
+ 'return true if some_method == 0',
26
+ ].join("\n")
27
+
28
+ inspect_source(source)
29
+ expect(cop.offenses).to be_empty
30
+ end
31
+
32
+ it 'allows with modifier if with single conditional' do
33
+ source = [
34
+ 'return true if some_method == 0',
35
+ 'return true if another_method',
36
+ ].join("\n")
37
+
38
+ inspect_source(source)
39
+ expect(cop.offenses).to be_empty
40
+ end
41
+
42
+ it 'allows with modifier if and unless with single conditional ' do
43
+ source = [
44
+ 'return true if some_method',
45
+ 'return true unless another_method > 5',
46
+ ].join("\n")
47
+
48
+ inspect_source(source)
49
+ expect(cop.offenses).to be_empty
50
+ end
51
+
52
+ it 'allows multiple conditionals in block form' do
53
+ source = [
54
+ 'if some_method == 0 && another_method > 5 || true || false',
55
+ ' return true',
56
+ 'end',
57
+ ].join("\n")
58
+
59
+ inspect_source(source)
60
+ expect(cop.offenses).to be_empty
61
+ end
62
+ end
63
+
64
+ context 'multiple lines' do
65
+ it 'rejects modifier conditionals that span multiple lines' do
66
+ source = [
67
+ 'return true if true ||',
68
+ ' false',
69
+ 'return true unless true ||',
70
+ ' false',
71
+ ].join("\n")
72
+
73
+ inspect_source(source)
74
+ expect(cop.offenses.size).to eq(2)
75
+ end
76
+
77
+ it 'rejects with modifier if with method that spans multiple lines' do
78
+ source = [
79
+ 'return true if some_method(param1,',
80
+ ' param2,',
81
+ ' param3)',
82
+ 'return true unless some_method(param1,',
83
+ ' param2,',
84
+ ' param3)',
85
+ ].join("\n")
86
+
87
+ inspect_source(source)
88
+ expect(cop.offenses.size).to eq(2)
89
+ end
90
+
91
+ it 'rejects inline if/unless after a multiline statement' do
92
+ source = [
93
+ 'return some_method(',
94
+ ' param1,',
95
+ ' param2,',
96
+ ' param3',
97
+ ') if another_method == 0',
98
+ 'return some_method(',
99
+ ' param1,',
100
+ ' param2,',
101
+ ' param3',
102
+ ') unless another_method == 0',
103
+ ].join("\n")
104
+
105
+ inspect_source(source)
106
+ expect(cop.offenses.size).to eq(2)
107
+ end
108
+
109
+ it 'allows multline conditionals in block form' do
110
+ source = [
111
+ 'if some_method(param1,',
112
+ ' param2,',
113
+ ' parma3)',
114
+ ' return true',
115
+ 'end',
116
+ ].join("\n")
117
+
118
+ inspect_source(source)
119
+ expect(cop.offenses).to be_empty
120
+ end
121
+ end
122
+ end