rubocop-pixelforce 0.1.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.
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: []