spbtv_code_style 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57082afb7d19156a7145046e3989e8e73189751c
4
- data.tar.gz: defc7bcedc0a0d240e8cb8d700e801c167b2088f
3
+ metadata.gz: 0de24f59699801bfff09af903c583958f4b3c755
4
+ data.tar.gz: 197af631ec792872175430b8c7ccfe1dfacdb1a2
5
5
  SHA512:
6
- metadata.gz: 8156435a9f0fe302f9be4315edc4282af427b4553b78eaa5ef6cfe7cb5c9ff6b0e74477df5787f671b1b22a5f56f04d6fd5212fc250b9376f0709d8ce1e6ae74
7
- data.tar.gz: 75c97c92314ead99f81655fc8490ee4528e81714ba1660d6863412babf4ce272bfc3c441de76b2df6bb5467b3f00823b6a5f6b721d9541b050292ab71d7a6387
6
+ metadata.gz: 0abe4066eb2bb1c5ef46f06f721d97d2d0f3b771533e5feb483f6d00a9fea89c16b3dd1c28d6c2da4d6ef573df3e0f21161a72d69f4f3a566fc4b0edf765b5b7
7
+ data.tar.gz: 259dfdec5f01c3632aef02bec2f6445dbcd2120c310e2ec59177107a0d33e72b212a29bd95a7ac2eedb6c222416a0c3637ea62b5ca3222717e026a8b2394132e
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,3 +1,11 @@
1
+ require:
2
+ - rubocop-rspec
3
+ - ./lib/rubocop/cop/spbtv/postgres/add_column_with_default
4
+ - ./lib/rubocop/cop/spbtv/postgres/add_column_with_not_null
5
+ - ./lib/rubocop/cop/spbtv/postgres/add_index
6
+ - ./lib/rubocop/cop/spbtv/postgres/change_column
7
+ - ./lib/rubocop/cop/spbtv/multiple_validation
8
+
1
9
  Rails:
2
10
  Enabled: true
3
11
 
@@ -29,9 +37,6 @@ Style/Next:
29
37
  Style/GuardClause:
30
38
  Enabled: false
31
39
 
32
- Metrics/LineLength:
33
- Max: 120
34
-
35
40
  Style/TrivialAccessors:
36
41
  AllowPredicates: true
37
42
 
@@ -41,6 +46,11 @@ Style/IfUnlessModifier:
41
46
  Style/EmptyCaseCondition:
42
47
  Enabled: false
43
48
 
49
+ Metrics/ClassLength:
50
+ Severity: refactor
51
+ Exclude:
52
+ - '**/db/**/*'
53
+
44
54
  Metrics/AbcSize:
45
55
  Severity: refactor
46
56
 
@@ -50,8 +60,18 @@ Metrics/PerceivedComplexity:
50
60
  Metrics/ParameterLists:
51
61
  Severity: refactor
52
62
 
63
+ Metrics/LineLength:
64
+ Max: 120
65
+
66
+ Metrics/AbcSize:
67
+ Severity: refactor
68
+ Exclude:
69
+ - '**/db/**/*'
70
+
53
71
  Metrics/MethodLength:
54
72
  Severity: refactor
73
+ Exclude:
74
+ - '**/db/**/*'
55
75
 
56
76
  Metrics/CyclomaticComplexity:
57
77
  Severity: refactor
@@ -76,3 +96,33 @@ Style/TrailingCommaInLiteral:
76
96
 
77
97
  Style/TrailingCommaInArguments:
78
98
  EnforcedStyleForMultiline: comma
99
+
100
+ Postgres/AddColumnWithDefault:
101
+ Exclude:
102
+ - '**/db/migrate/2015*'
103
+ - '**/db/migrate/20160*'
104
+ - '**/db/migrate/201610*'
105
+
106
+ Postgres/AddColumnWithNotNull:
107
+ Exclude:
108
+ - '**/db/migrate/2015*'
109
+ - '**/db/migrate/20160*'
110
+ - '**/db/migrate/201610*'
111
+
112
+ Postgres/AddIndex:
113
+ Exclude:
114
+ - '**/db/migrate/2015*'
115
+ - '**/db/migrate/20160*'
116
+ - '**/db/migrate/201610*'
117
+
118
+ Postgres/ChangeColumn:
119
+ Exclude:
120
+ - '**/db/migrate/2015*'
121
+ - '**/db/migrate/20160*'
122
+ - '**/db/migrate/201610*'
123
+
124
+ Rails/NotNullColumn:
125
+ Enabled: false
126
+
127
+ RSpec/MultipleExpectations:
128
+ Max: 3
data/.strict_rubocop.yml CHANGED
@@ -3,6 +3,8 @@ inherit_from:
3
3
 
4
4
  Metrics/AbcSize:
5
5
  Severity: warning
6
+ Exclude:
7
+ - '**/db/**/*'
6
8
 
7
9
  Metrics/PerceivedComplexity:
8
10
  Severity: warning
@@ -12,6 +14,8 @@ Metrics/ParameterLists:
12
14
 
13
15
  Metrics/MethodLength:
14
16
  Severity: warning
17
+ Exclude:
18
+ - '**/db/**/*'
15
19
 
16
20
  Metrics/CyclomaticComplexity:
17
21
  Severity: warning
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1.5
5
4
  - 2.2.2
6
5
  - 2.2.3
7
6
  - ruby-head
@@ -12,3 +11,4 @@ matrix:
12
11
  before_install: gem install bundler -v 1.10.6
13
12
  script:
14
13
  - bundle exec rubocop --fail-level C
14
+ - bundle exec rspec
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Spbtv
6
+ # Prefer validating one attribute at once.
7
+ #
8
+ # @example
9
+ # @bad
10
+ # validates :name, :age, presence: true
11
+ #
12
+ # @good
13
+ # validates :age, presence: true
14
+ # validates :name, presence: true
15
+ #
16
+ class MultipleValidation < Cop
17
+ MSG = 'Prefer validating one attribute at once.'.freeze
18
+
19
+ def on_send(node)
20
+ _, _, *args = *node
21
+ if node.command?(:validates) && args.length > 2
22
+ add_offense(node, :selector, MSG)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def autocorrect(node)
29
+ _receiver, method_name, *args = *node
30
+ *attributes, options = args
31
+
32
+ multiline_replacement = attributes.map do |attribute|
33
+ "#{method_name} #{attribute.source}, #{options.source}"
34
+ end
35
+
36
+ lambda do |corrector|
37
+ corrector.replace(node.source_range, multiline_replacement.sort.join("\n"))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Spbtv
6
+ module Postgres
7
+ # Do not add a column with a default value.
8
+ #
9
+ # Adding a column with a default requires updating each row of the table (to store
10
+ # the new column value). For big table this will create long running operation
11
+ # that locks it.
12
+ #
13
+ # So if you intend to fill the column with mostly non default values,
14
+ # it’s best to add the column with no default, insert the correct values
15
+ # using UPDATE (correct way is to do batched updates, for example,
16
+ # update 1000 rows at a time, because big update will create table-wide lock),
17
+ # and then add any desired default.
18
+ #
19
+ # @example
20
+ # @bad
21
+ # add_column :users, :name, :string, default: "Peter"
22
+ #
23
+ # @good
24
+ # add_column :users, :name, :string
25
+ # User.find_in_batches do |batch|
26
+ # batch.update_all(name: 'Peter')
27
+ # end
28
+ #
29
+ class AddColumnWithDefault < Cop
30
+ MSG = 'Do not add a column with a default value.'.freeze
31
+
32
+ def_node_matcher :add_column_with_default?, <<-PATTERN
33
+ (send nil :add_column _ _ _ (hash $...))
34
+ PATTERN
35
+
36
+ def_node_matcher :has_default?, <<-PATTERN
37
+ (pair (sym :default) !(:nil))
38
+ PATTERN
39
+
40
+ def on_send(node)
41
+ pairs = add_column_with_default?(node)
42
+ return unless pairs
43
+ has_default = pairs.detect { |pair| has_default?(pair) }
44
+
45
+ return unless has_default
46
+
47
+ add_offense(has_default, :expression)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Spbtv
6
+ module Postgres
7
+ # Do not add a NOT NULL column.
8
+ #
9
+ # This will have the same problem, as “Add a column with a default”.
10
+ # To make this operation without locking, you can create a new table
11
+ # with the addition of the non-nullable column, write to both tables,
12
+ # backfill, and then switch to the new table. This workaround is
13
+ # incredibly onerous and need two times more space than is a table takes.
14
+ #
15
+ # @example
16
+ # @bad
17
+ # add_column :users, :name, :string, null: false
18
+ #
19
+ # @good
20
+ # add_column :users, :name, :string
21
+ #
22
+ class AddColumnWithNotNull < Cop
23
+ MSG = 'Do not add a NOT NULL column.'.freeze
24
+
25
+ def_node_matcher :add_not_null_column?, <<-PATTERN
26
+ (send nil :add_column _ _ _ (hash $...))
27
+ PATTERN
28
+
29
+ def_node_matcher :null_false?, <<-PATTERN
30
+ (pair (sym :null) (false))
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ pairs = add_not_null_column?(node)
35
+ return unless pairs
36
+
37
+ null_false = pairs.detect { |pair| null_false?(pair) }
38
+ return unless null_false
39
+
40
+ add_offense(null_false, :expression)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Spbtv
6
+ module Postgres
7
+ # Do not add an index.
8
+ #
9
+ # Normally PostgreSQL locks the table to be indexed against writes and performs
10
+ # the entire index build with a single scan of the table. Other transactions
11
+ # can still read the table, but not to insert, update, or delete rows until
12
+ # the index build is finished.
13
+ #
14
+ # To overcome this issue you may specify the CONCURRENTLY option of CREATE INDEX.
15
+ # When this option is used, PostgreSQL must perform two scans of the table, and in
16
+ # addition it must wait for all existing transactions that could potentially
17
+ # modify or use the index to terminate.
18
+ #
19
+ # If a problem arises while scanning the table, such as a uniqueness violation
20
+ # in a unique index, the CREATE INDEX command will fail but leave behind an
21
+ # “invalid” index.
22
+ #
23
+ # The recommended recovery method in such cases is to drop the index and
24
+ # try again to perform CREATE INDEX CONCURRENTLY.
25
+ #
26
+ # Another difference is that a regular CREATE INDEX command can be performed
27
+ # within a transaction block, but CREATE INDEX CONCURRENTLY cannot.
28
+ #
29
+ # @see https://www.postgresql.org/docs/9.2/static/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY
30
+ # @see https://robots.thoughtbot.com/how-to-create-postgres-indexes-concurrently-in
31
+ #
32
+ # @example
33
+ # @bad
34
+ # class AddIndexToAsksActive < ActiveRecord::Migration
35
+ # def change
36
+ # add_index :asks, :active
37
+ # end
38
+ # end
39
+ #
40
+ # @good
41
+ # class AddIndexToAsksActive < ActiveRecord::Migration
42
+ # disable_ddl_transaction!
43
+ # def change
44
+ # add_index :asks, :active, algorithm: :concurrently
45
+ # end
46
+ # end
47
+ #
48
+ class AddIndex < Cop
49
+ MSG = 'Do not add an index.'.freeze
50
+
51
+ def_node_search :disable_ddl_transaction?, '(send nil :disable_ddl_transaction!)'
52
+
53
+ def_node_matcher :add_index_without_options?, <<-PATTERN
54
+ (send nil :add_index _ _)
55
+ PATTERN
56
+
57
+ def_node_matcher :add_index_with_options?, <<-PATTERN
58
+ (send nil :add_index _ _ (hash $...))
59
+ PATTERN
60
+
61
+ def_node_matcher :concurrently?, <<-PATTERN
62
+ (pair (sym :algorithm) (sym :concurrently))
63
+ PATTERN
64
+
65
+ def on_class(node)
66
+ @disable_ddl_transaction = disable_ddl_transaction?(node)
67
+ end
68
+
69
+ def on_send(node)
70
+ if add_index_without_options?(node)
71
+ add_offense(node, :expression)
72
+ elsif (options = add_index_with_options?(node))
73
+ has_concurrently = options.detect { |pair| concurrently?(pair) }
74
+ unless has_concurrently && @disable_ddl_transaction
75
+ add_offense(node, :expression)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Spbtv
6
+ module Postgres
7
+ # Do not change column.
8
+ #
9
+ # It is not strictly unsafe for all changes. Changing the
10
+ # length of a varchar, for example, does not lock a table.
11
+ # But if column type change requires a rewrite or not depends
12
+ # on the datatype, in this case this operation requires updating
13
+ # each row of the table. As workaround, you can add a new column
14
+ # with needed type, change the code to write to both columns,
15
+ # and backfill the new column.
16
+ #
17
+ # @example
18
+ # @bad
19
+ # change_column :suppliers, :name, :string, limit: 80
20
+ #
21
+ class ChangeColumn < Cop
22
+ MSG = 'Do not change column.'.freeze
23
+
24
+ def on_send(node)
25
+ _, _, * = *node
26
+ if node.command?(:change_column)
27
+ add_offense(node, :selector, MSG)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubocop'
2
+ require_relative 'cop/spbtv/postgres/add_column_with_default'
3
+ require_relative 'cop/spbtv/postgres/add_column_with_not_null'
4
+ require_relative 'cop/spbtv/postgres/add_index'
5
+ require_relative 'cop/spbtv/postgres/change_column'
6
+ require_relative 'cop/spbtv/multiple_validation'
@@ -1,4 +1,4 @@
1
1
  # Just namespace for version number
2
2
  module SpbtvCodeStyle
3
- VERSION = '1.5.0'.freeze
3
+ VERSION = '1.6.0'.freeze
4
4
  end
@@ -18,7 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.add_runtime_dependency 'rubocop-checkstyle_formatter'
19
19
  spec.add_runtime_dependency 'rspec_junit_formatter'
20
20
 
21
- spec.add_development_dependency 'rubocop', '~> 0.40.0'
22
21
  spec.add_development_dependency 'bundler', '~> 1.10'
23
22
  spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec', '~> 3.5'
24
+ spec.add_development_dependency 'rubocop', '~> 0.43.0'
25
+ spec.add_development_dependency 'rubocop-rspec', '1.7.0'
24
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spbtv_code_style
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tema Bolshakov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-27 00:00:00.000000000 Z
11
+ date: 2016-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop-checkstyle_formatter
@@ -39,47 +39,75 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubocop
42
+ name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.40.0
47
+ version: '1.10'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.40.0
54
+ version: '1.10'
55
55
  - !ruby/object:Gem::Dependency
56
- name: bundler
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.10'
61
+ version: '10.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.10'
68
+ version: '10.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '3.5'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '3.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.43.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.43.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.7.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.7.0
83
111
  description:
84
112
  email:
85
113
  - abolshakov@spbtv.com
@@ -88,6 +116,7 @@ extensions: []
88
116
  extra_rdoc_files: []
89
117
  files:
90
118
  - ".gitignore"
119
+ - ".rspec"
91
120
  - ".rubocop.yml"
92
121
  - ".strict_rubocop.yml"
93
122
  - ".travis.yml"
@@ -96,6 +125,12 @@ files:
96
125
  - LICENSE
97
126
  - README.md
98
127
  - Rakefile
128
+ - lib/rubocop/cop/spbtv/multiple_validation.rb
129
+ - lib/rubocop/cop/spbtv/postgres/add_column_with_default.rb
130
+ - lib/rubocop/cop/spbtv/postgres/add_column_with_not_null.rb
131
+ - lib/rubocop/cop/spbtv/postgres/add_index.rb
132
+ - lib/rubocop/cop/spbtv/postgres/change_column.rb
133
+ - lib/rubocop/spbtv.rb
99
134
  - lib/spbtv_code_style.rb
100
135
  - spbtv_code_style.gemspec
101
136
  homepage: https://github.com/spbtv/spbtv_code_style