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,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