rubocop-airbnb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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