rubocop-pixelforce 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 21571919cdfc1f3ec42641eb3d4d6c8f383773ee285e3c8222c7117e6259cfd7
4
+ data.tar.gz: 5c11a46f1f2a3e29ea0e4ac34ef192c95aedbca917be5b7780c57abe90546b11
5
+ SHA512:
6
+ metadata.gz: b7185e91a5ee8b961caed63b085b9c9d29dc186f3f21eaa157f08c6031934f0b45dee421a8034ab2db2b9805566db7513f2b61fcd17364f4ee8018dc271b1845
7
+ data.tar.gz: ac13031680fb145c6e8e30da1746f19ba243f2c93d974011cd1970d5a604644c46a72aa7a385e452cb8a856d454d411ff757af8995bb0aa2e81d140fe6c410d8
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.4.7
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rubocop-pixelforce.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Rubocop::Pixelforce
2
+
3
+ Custom Rubocop cop for PixlForce
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rubocop-pixelforce'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ and create .rubocop file like this
19
+
20
+ ```
21
+ inherit_gem:
22
+ rubocop-pixelforce: default.yml
23
+ ```
24
+
25
+ ## Pixelforce/ClassStructure: Don't Use empty lines between same categories.
26
+
27
+ ```ruby
28
+ # bad
29
+ belongs_to :user
30
+
31
+ belongs_to :category
32
+
33
+ after_commit :update_geo_location
34
+
35
+ # good
36
+ belongs_to :user
37
+ belongs_to :category
38
+
39
+ after_commit :update_geo_location
40
+ ```
41
+
42
+ ## Pixelforce/ClassStructure: Use empty lines between categories.
43
+
44
+ ```ruby
45
+ # bad
46
+ enum status: { draft: 0, active: 1, approved: 2, declined: 3 }
47
+ belongs_to :user
48
+ belongs_to :category
49
+ after_commit :update_geo_location
50
+
51
+ # good
52
+ enum status: { draft: 0, active: 1, approved: 2, declined: 3 }
53
+
54
+ belongs_to :user
55
+ belongs_to :category
56
+
57
+ after_commit :update_geo_location
58
+ ```
59
+
60
+
61
+ ## Development
62
+
63
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
64
+
65
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
66
+
67
+ ## Contributing
68
+
69
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rubocop-pixelforce.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rubocop/pixelforce"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/default.yml ADDED
@@ -0,0 +1,134 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rails
4
+ - rubocop-pixelforce
5
+
6
+ AllCops:
7
+ Exclude:
8
+ - 'Gemfile'
9
+ - 'db/**/*'
10
+ - 'bin/*'
11
+
12
+ Rails/UnknownEnv:
13
+ Environments:
14
+ - production
15
+ - development
16
+ - test
17
+ - staging
18
+
19
+ Rails/FilePath:
20
+ Enabled: false
21
+
22
+ Pixelforce/ClassStructure:
23
+ Enabled: true
24
+ ExpectedOrder:
25
+ - module_inclusion
26
+ - constants
27
+ - attr_macros
28
+ - association
29
+ - public_attribute_macros
30
+ - public_delegate
31
+ - macros
32
+ - callbacks
33
+ - public_class_methods
34
+ - initializer
35
+ - public_methods
36
+ - protected_attribute_macros
37
+ - protected_methods
38
+ - private_attribute_macros
39
+ - private_delegate
40
+ - private_methods
41
+ Categories:
42
+ attr_macros:
43
+ - attr_accessor
44
+ - enum
45
+ association:
46
+ - belongs_to
47
+ - has_many
48
+ - has_one
49
+ public_attribute_macros:
50
+ - accepts_nested_attributes_for
51
+ attribute_macros:
52
+ - attr_accessor
53
+ - attr_reader
54
+ - attr_writer
55
+ callbacks:
56
+ - before_create
57
+ - before_save
58
+ - before_update
59
+ - before_validation
60
+ - before_destroy
61
+ - before_commit
62
+ - after_create
63
+ - after_save
64
+ - after_update
65
+ - after_validation
66
+ - after_destroy
67
+ - after_commit
68
+ macros:
69
+ - validates
70
+ - validate
71
+ module_inclusion:
72
+ - include
73
+ - prepend
74
+ - extend
75
+
76
+ Layout/AlignHash:
77
+ EnforcedColonStyle: table
78
+
79
+ Metrics/ModuleLength:
80
+ Enabled: false
81
+
82
+ Style/NestedTernaryOperator:
83
+ Enabled: false
84
+
85
+ Style/FrozenStringLiteralComment:
86
+ Enabled: false
87
+
88
+ Documentation:
89
+ Enabled: false
90
+
91
+ Metrics/LineLength:
92
+ Enabled: false
93
+
94
+ Metrics/MethodLength:
95
+ Enabled: false
96
+
97
+ Metrics/BlockNesting:
98
+ Enabled: false
99
+
100
+ Metrics/AbcSize:
101
+ Enabled: false
102
+
103
+ Metrics/ClassLength:
104
+ Enabled: false
105
+
106
+ Metrics/BlockLength:
107
+ Enabled: false
108
+
109
+ Style/IfUnlessModifier:
110
+ Enabled: false
111
+
112
+ Metrics/CyclomaticComplexity:
113
+ Enabled: false
114
+
115
+ Metrics/PerceivedComplexity:
116
+ Enabled: false
117
+
118
+ Style/GuardClause:
119
+ Enabled: false
120
+
121
+ Style/AsciiComments:
122
+ Enabled: false
123
+
124
+ Style/ClassAndModuleChildren:
125
+ Enabled: false
126
+
127
+ Style/TernaryParentheses:
128
+ Enabled: false
129
+
130
+ Style/GlobalVars:
131
+ Enabled: false
132
+
133
+ Metrics/ParameterLists:
134
+ Enabled: false
@@ -0,0 +1,3 @@
1
+ require 'rubocop'
2
+
3
+ require 'rubocop/cop/pixelforce/class_structure'
@@ -0,0 +1,225 @@
1
+ module RuboCop
2
+ module Cop
3
+ module Pixelforce
4
+ class ClassStructure < Cop
5
+ HUMANIZED_NODE_TYPE = {
6
+ casgn: :constants,
7
+ defs: :class_methods,
8
+ def: :public_methods,
9
+ sclass: :class_singleton
10
+ }.freeze
11
+
12
+ VISIBILITY_SCOPES = %i[private protected public].freeze
13
+ MSG = '`%<category>s` is supposed to appear before ' \
14
+ '`%<previous>s`.'
15
+
16
+ def_node_matcher :visibility_block?, <<~PATTERN
17
+ (send nil? { :private :protected :public })
18
+ PATTERN
19
+
20
+ # Validates code style on class declaration.
21
+ # Add offense when find a node out of expected order.
22
+ def on_class(class_node)
23
+ previous = -1
24
+ previous_category = nil
25
+ previous_node_end_line = -1
26
+ previous_method_name = nil
27
+ walk_over_nested_class_definition(class_node) do |node, category|
28
+ index = expected_order.index(category)
29
+ if index < previous
30
+ message = format(MSG, category: category,
31
+ previous: expected_order[previous])
32
+ add_offense(node, message: message)
33
+ end
34
+
35
+ if previous_category && category != previous_category && node.loc.first_line - previous_node_end_line < 2
36
+ add_offense(node, message: "Use empty lines between categories.")
37
+ end
38
+
39
+ if previous_method_name && previous_method_name == node.method_name && node.loc.first_line - previous_node_end_line > 1
40
+ add_offense(node, message: "Don't Use empty lines between same categories.")
41
+ end
42
+ previous = index
43
+ previous_category = category
44
+ previous_node_end_line = node.loc.last_line
45
+ previous_method_name = node.method_name
46
+ end
47
+ end
48
+
49
+ # Autocorrect by swapping between two nodes autocorrecting them
50
+ def autocorrect(node)
51
+ node_classification = classify(node)
52
+ previous = left_siblings_of(node).find do |sibling|
53
+ classification = classify(sibling)
54
+ !ignore?(classification) && node_classification != classification
55
+ end
56
+
57
+ current_range = source_range_with_comment(node)
58
+ previous_range = source_range_with_comment(previous)
59
+
60
+ lambda do |corrector|
61
+ corrector.insert_before(previous_range, current_range.source)
62
+ corrector.remove(current_range)
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ # Classifies a node to match with something in the {expected_order}
69
+ # @param node to be analysed
70
+ # @return String when the node type is a `:block` then
71
+ # {classify} recursively with the first children
72
+ # @return String when the node type is a `:send` then {find_category}
73
+ # by method name
74
+ # @return String otherwise trying to {humanize_node} of the current node
75
+ def classify(node)
76
+ return node.to_s unless node.respond_to?(:type)
77
+
78
+ case node.type
79
+ when :block
80
+ classify(node.send_node)
81
+ when :send
82
+ find_category(node)
83
+ else
84
+ humanize_node(node)
85
+ end.to_s
86
+ end
87
+
88
+ # Categorize a node according to the {expected_order}
89
+ # Try to match {categories} values against the node's method_name given
90
+ # also its visibility.
91
+ # @param node to be analysed.
92
+ # @return [String] with the key category or the `method_name` as string
93
+ def find_category(node)
94
+ name = node.method_name.to_s
95
+ category, = categories.find { |_, names| names.include?(name) }
96
+ key = category || name
97
+ visibility_key = "#{node_visibility(node)}_#{key}"
98
+ expected_order.include?(visibility_key) ? visibility_key : key
99
+ end
100
+
101
+ def walk_over_nested_class_definition(class_node)
102
+ class_elements(class_node).each do |node|
103
+ classification = classify(node)
104
+ next if ignore?(classification)
105
+
106
+ yield node, classification
107
+ end
108
+ end
109
+
110
+ def class_elements(class_node)
111
+ class_def = class_node.body
112
+
113
+ return [] unless class_def
114
+
115
+ if class_def.def_type? || class_def.send_type?
116
+ [class_def]
117
+ else
118
+ class_def.children.compact
119
+ end
120
+ end
121
+
122
+ def ignore?(classification)
123
+ classification.nil? ||
124
+ classification.to_s.end_with?('=') ||
125
+ expected_order.index(classification).nil?
126
+ end
127
+
128
+ def node_visibility(node)
129
+ scope = find_visibility_start(node)
130
+ scope&.method_name || :public
131
+ end
132
+
133
+ def find_visibility_start(node)
134
+ left_siblings_of(node)
135
+ .reverse
136
+ .find(&method(:visibility_block?))
137
+ end
138
+
139
+ # Navigate to find the last protected method
140
+ def find_visibility_end(node)
141
+ possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
142
+ right = right_siblings_of(node)
143
+ right.find do |child_node|
144
+ possible_visibilities.include?(node_visibility(child_node))
145
+ end || right.last
146
+ end
147
+
148
+ def siblings_of(node)
149
+ node.parent.children
150
+ end
151
+
152
+ def right_siblings_of(node)
153
+ siblings_of(node)[node.sibling_index..-1]
154
+ end
155
+
156
+ def left_siblings_of(node)
157
+ siblings_of(node)[0, node.sibling_index]
158
+ end
159
+
160
+ def humanize_node(node)
161
+ if node.def_type?
162
+ return :initializer if node.method?(:initialize)
163
+
164
+ return "#{node_visibility(node)}_methods"
165
+ end
166
+ HUMANIZED_NODE_TYPE[node.type] || node.type
167
+ end
168
+
169
+ def source_range_with_comment(node)
170
+ begin_pos, end_pos =
171
+ if node.def_type?
172
+ start_node = find_visibility_start(node) || node
173
+ end_node = find_visibility_end(node) || node
174
+ [begin_pos_with_comment(start_node),
175
+ end_position_for(end_node) + 1]
176
+ else
177
+ [begin_pos_with_comment(node), end_position_for(node)]
178
+ end
179
+
180
+ Parser::Source::Range.new(buffer, begin_pos, end_pos)
181
+ end
182
+
183
+ def end_position_for(node)
184
+ end_line = buffer.line_for_position(node.loc.expression.end_pos)
185
+ buffer.line_range(end_line).end_pos
186
+ end
187
+
188
+ def begin_pos_with_comment(node)
189
+ annotation_line = node.first_line - 1
190
+ first_comment = nil
191
+
192
+ processed_source.comments_before_line(annotation_line)
193
+ .reverse_each do |comment|
194
+ if comment.location.line == annotation_line
195
+ first_comment = comment
196
+ annotation_line -= 1
197
+ end
198
+ end
199
+
200
+ start_line_position(first_comment || node)
201
+ end
202
+
203
+ def start_line_position(node)
204
+ buffer.line_range(node.loc.line).begin_pos - 1
205
+ end
206
+
207
+ def buffer
208
+ processed_source.buffer
209
+ end
210
+
211
+ # Load expected order from `ExpectedOrder` config.
212
+ # Define new terms in the expected order by adding new {categories}.
213
+ def expected_order
214
+ cop_config['ExpectedOrder']
215
+ end
216
+
217
+ # Setting categories hash allow you to group methods in group to match
218
+ # in the {expected_order}.
219
+ def categories
220
+ cop_config['Categories']
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,6 @@
1
+ require "rubocop/pixelforce/version"
2
+
3
+ module Rubocop
4
+ module Pixelforce
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Rubocop
2
+ module Pixelforce
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "rubocop/pixelforce/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rubocop-pixelforce"
7
+ spec.version = Rubocop::Pixelforce::VERSION
8
+ spec.authors = ["Ben Zhang"]
9
+ spec.email = ["bzbnhang@gmail.com"]
10
+
11
+ spec.summary = %q{Custom Rubocop cop for PixelForce.}
12
+ spec.description = %q{Use empty lines between categories and Don't Use empty lines between same categories.}
13
+ spec.homepage = "https://github.com/BenZhang/rubocop-pixelforce"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/BenZhang/rubocop-pixelforce"
17
+ spec.metadata["changelog_uri"] = "https://github.com/BenZhang/rubocop-pixelforce"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_development_dependency "bundler", "~> 2.0"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+
32
+ spec.add_runtime_dependency "rubocop", "~> 0.76"
33
+ spec.add_runtime_dependency "rubocop-performance"
34
+ spec.add_runtime_dependency "rubocop-rails"
35
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-pixelforce
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Zhang
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-11-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.76'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.76'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-performance
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Use empty lines between categories and Don't Use empty lines between
98
+ same categories.
99
+ email:
100
+ - bzbnhang@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - bin/setup
113
+ - default.yml
114
+ - lib/rubocop-pixelforce.rb
115
+ - lib/rubocop/cop/pixelforce/class_structure.rb
116
+ - lib/rubocop/pixelforce.rb
117
+ - lib/rubocop/pixelforce/version.rb
118
+ - rubocop-pixelforce.gemspec
119
+ homepage: https://github.com/BenZhang/rubocop-pixelforce
120
+ licenses: []
121
+ metadata:
122
+ homepage_uri: https://github.com/BenZhang/rubocop-pixelforce
123
+ source_code_uri: https://github.com/BenZhang/rubocop-pixelforce
124
+ changelog_uri: https://github.com/BenZhang/rubocop-pixelforce
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.7.10
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Custom Rubocop cop for PixelForce.
145
+ test_files: []