rubocop-ordered_methods 0.2 → 0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efe0a069919334996c9317cf8d9dd03bb19fe984a9d8d7a294f017dcb361ec96
4
- data.tar.gz: b8c6b15fbfa6d2b44c99b051ebfb4a2ba047c2958f16cf9015b4f2d87f674fe5
3
+ metadata.gz: c161660f9f4755d2e7fe826d18a1cd704d9f62071736ea5dc4f8e540ed78cd14
4
+ data.tar.gz: 6f464af4d215c37dbeb402e0d81a730dcd96f6a77ae40892d60a382a847002c8
5
5
  SHA512:
6
- metadata.gz: cca41398955b51c5d968fc84b4ec0833339224c696de865d6421834491da2113b12d7e4bfce8fe1771b53f18a0ae872e350ffff96fccce4610b71eca38b3583d
7
- data.tar.gz: 57f61650ad8df63193aa45f9fa35133c85698a134d9a6ee3bfa305b9de074763cc45d7fc26a64da216ba79f86d5b19e5fec84084ee989f266e82dc56251f00fd
6
+ metadata.gz: af7672dbef3e4fc3d5b84a814ec08f6e372d0dadc8d1fced783c7b74a6a4abc43c9d33e53b97b2c9b4e75bba73106b9a5238daaa9709333c6a477496eb18dfa3
7
+ data.tar.gz: 73c5f91133bd0a8c1e8acd669d1c8df7e969670250a49df9698e0ea547c20ba92e0282032007fdd1406948a700c16b996c832f63269ef2014736a7165cc177d6
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /tmp/
9
9
 
10
10
  Gemfile.lock
11
+ .ruby-version
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build rubocop-ordered_methods-0.5.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install rubocop-ordered_methods-0.5.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install rubocop-ordered_methods-0.5.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.5 and build and push rubocop-ordered_methods-0.5.gem to rubygems.org" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RuboCop" fullCmd="rubocop" taksId="rubocop" /><RakeGroup description="" fullCmd="" taksId="rubocop"><RakeTask description="Auto-correct RuboCop offenses" fullCmd="rubocop:auto_correct" taksId="auto_correct" /></RakeGroup><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
@@ -2,6 +2,11 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  require: rubocop-ordered_methods
4
4
 
5
+ AllCops:
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ TargetRubyVersion: 2.4
9
+
5
10
  Metrics/BlockLength:
6
11
  Exclude:
7
12
  - spec/**/*
@@ -1,21 +1,24 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-02-17 13:54:25 -0500 using RuboCop version 0.64.0.
3
+ # on 2021-01-05 20:47:55 UTC using RuboCop version 1.7.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
9
  # Offense count: 1
10
- Metrics/AbcSize:
11
- Max: 17
10
+ # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
11
+ Metrics/MethodLength:
12
+ Max: 11
12
13
 
13
14
  # Offense count: 1
14
- # Configuration parameters: CountComments.
15
- Metrics/ClassLength:
16
- Max: 101
15
+ # Cop supports --auto-correct.
16
+ Style/IfUnlessModifier:
17
+ Exclude:
18
+ - 'lib/rubocop/cop/layout/ordered_methods.rb'
17
19
 
18
20
  # Offense count: 1
19
- # Configuration parameters: CountComments, ExcludedMethods.
20
- Metrics/MethodLength:
21
- Max: 11
21
+ # Cop supports --auto-correct.
22
+ Style/RedundantFreeze:
23
+ Exclude:
24
+ - 'lib/rubocop/cop/layout/ordered_methods.rb'
@@ -3,9 +3,10 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.2
7
6
  - 2.3
8
7
  - 2.4
9
8
  - 2.5
10
9
  - 2.6
11
- before_install: gem install bundler -v 1.17.2
10
+ script: bundle exec rake
11
+ before_install:
12
+ - gem install bundler || gem install bundler --version '< 2'
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ - nothing
10
+
11
+ ## [0.7] - 2021-01-11
12
+
13
+ ### Removed
14
+
15
+ - Drop Ruby 2.3 support
16
+ - Drop support for rubocop < 1.0
17
+
18
+ ### Changed
19
+
20
+ - Support for rubocop >= 1.0 ([#5](https://github.com/shanecav84/rubocop-ordered_methods/pull/5)). Thanks @jaredbeck.
21
+
22
+ ## [0.6] - 2020-03-01
23
+
24
+ ### Security
25
+
26
+ - Upgrade rake to avoid vulnerability https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8130
27
+ - rake is a development dependency for this gem, so shouldn't have been a risk for production
28
+
29
+ ## [0.5] - 2019-11-05
30
+
31
+ ### Removed
32
+
33
+ - Drop Ruby 2.2 support
34
+
35
+ ### Changed
36
+
37
+ - Nonadjacent qualifiers are now autocorrected (#4). Thanks @adamkiczula.
38
+ - Cache AST traversals for significant speed up on large files
39
+
40
+ ## [0.4] - 2019-06-11
41
+
42
+ ### Changed
43
+
44
+ - More robust autocorrection of a method and its surroundings (see `Corrector` in the `README`).
45
+
46
+ ## [0.3] - 2019-02-17
47
+
48
+ ### Added
49
+
50
+ - Configuration defaults
51
+
52
+ ## [0.2] - 2019-02-17
53
+
54
+ ### Added
55
+
56
+ - Autocorrector
57
+
58
+ ## [0.1] - 2019-02-17
59
+
60
+ Initial release.
61
+
62
+ [Unreleased]: https://github.com/shanecav84/rubocop-ordered_methods/compare/v0.3...HEAD
63
+ [0.3]: https://github.com/shanecav84/rubocop-ordered_methods/compare/v0.2...v0.3
64
+ [0.2]: https://github.com/shanecav84/rubocop-ordered_methods/compare/v0.1...v0.2
65
+ [0.1]: https://github.com/shanecav84/rubocop-ordered_methods/releases/tag/v0.1
data/Gemfile CHANGED
@@ -1,6 +1,5 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in rubocop-ordered_methods.gemspec
6
5
  gemspec
data/README.md CHANGED
@@ -1,32 +1,35 @@
1
+ [![Gem Version](https://badge.fury.io/rb/rubocop-ordered_methods.svg)](https://badge.fury.io/rb/rubocop-ordered_methods)
2
+ [![Build Status](https://travis-ci.org/shanecav84/rubocop-ordered_methods.svg?branch=master)](https://travis-ci.org/shanecav84/rubocop-ordered_methods)
3
+
1
4
  # RuboCop OrderedMethods
2
5
 
3
- Check that methods are defined alphabetically. Note [caveats](#caveats) for
4
- autocorrector.
6
+ Check that methods are defined alphabetically per access modifier block (class,
7
+ public, private, protected). Includes [autocorrection](#corrector).
5
8
 
6
9
  ```ruby
7
10
  # bad
8
- def self.b; end
9
- def self.a; end
11
+ def self.b_class; end
12
+ def self.a_class; end
10
13
 
11
- def b; end
12
- def a; end
14
+ def b_public; end
15
+ def a_public; end
13
16
 
14
17
  private
15
18
 
16
- def d; end
17
- def c; end
19
+ def b_private; end
20
+ def a_private; end
18
21
 
19
22
  # good
20
- def self.a; end
21
- def self.b; end
23
+ def self.a_class; end
24
+ def self.b_class; end
22
25
 
23
- def a; end
24
- def b; end
26
+ def a_public; end
27
+ def b_public; end
25
28
 
26
29
  private
27
30
 
28
- def c; end
29
- def d; end
31
+ def a_private; end
32
+ def b_private; end
30
33
  ```
31
34
 
32
35
  ## Installation
@@ -47,7 +50,7 @@ Or install it yourself as:
47
50
 
48
51
  ## Usage
49
52
 
50
- You need to tell RuboCop to load the OrderedMethods extension. There are three
53
+ You need to tell RuboCop to load the OrderedMethods extension. There are two
51
54
  ways to do this:
52
55
 
53
56
  ### RuboCop configuration file
@@ -71,17 +74,70 @@ rubocop --require rubocop-ordered_methods
71
74
 
72
75
  Name | Default value | Configurable values
73
76
  --- | --- | ---
77
+ EnforcedStyle | `alphabetical` | `alphabetical`
74
78
  IgnoredMethods | `initialize` | Array
75
79
 
76
80
  ### Corrector
77
81
 
78
- The corrector will attempt to order methods alphabetically. It attempts to
79
- include surrounding comments and the qualifiers listed in
80
- `::RuboCop::Cop::Layout::OrderedMethods::QUALIFIERS`.
82
+ The corrector will attempt to order methods based on the `EnforcedStyle`. It attempts to
83
+ include surrounding comments and the qualifiers (e.g., aliases) listed in
84
+ `::RuboCop::Cop::OrderedMethodsCorrector::QUALIFIERS`. The following (monstrous)
85
+ source is able to be correctly ordered:
86
+
87
+ ```ruby
88
+ # Long
89
+ # Preceding
90
+ # Comment
91
+ # class_b
92
+ def self.class_b; end
93
+ private_class_method :class_b
94
+
95
+ def self.class_a; end
96
+ # Long
97
+ # Succeeding
98
+ # Comment
99
+ # class_a
100
+ public_class_method :class_a
101
+
102
+ # Preceding comment for instance_b
103
+ def instance_b; end
104
+ # Long
105
+ # Succeeding
106
+ # Comment
107
+ # instance_b
108
+ alias_method :orig_instance_b, :instance_b
109
+ module_function :instance_b
110
+ private :instance_b
111
+ protected :instance_b
112
+ public :instance_b
113
+
114
+ # Long
115
+ # Preceding
116
+ # Comment
117
+ # instance_a
118
+ def instance_a; end
119
+ # Succeeding comment for instance_a
120
+ alias :new_instance_a :instance_a
121
+ alias_method :orig_instance_a, :instance_a
122
+ module_function :instance_a
123
+ private :instance_a
124
+ protected :instance_a
125
+ public :instance_a
126
+ ```
81
127
 
82
128
  #### Caveats
83
- The corrector can fail to include surrounding comments and qualifiers for some
84
- methods.
129
+
130
+ * The corrector will warn and refuse to order a method if it were to be
131
+ defined before its alias
132
+ * If there's ambiguity about which method a comment or qualifier belongs to,
133
+ the corrector might fail to order correctly. For example, in the following,
134
+ the corrector would incorrectly order the comment as a comment of `a`:
135
+
136
+ ```ruby
137
+ def b; end
138
+ # Comment b
139
+ def a; end
140
+ ```
85
141
 
86
142
  ## Development
87
143
 
@@ -94,12 +150,19 @@ bundle exec rake
94
150
 
95
151
  ## Contributing
96
152
 
97
- Bug reports and pull requests are welcome on GitHub at https://github.com/shanecav84/rubocop-ordered_methods. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
153
+ Bug reports and pull requests are welcome on GitHub at
154
+ https://github.com/shanecav84/rubocop-ordered_methods. This project is intended
155
+ to be a safe, welcoming space for collaboration, and contributors are expected
156
+ to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
157
+ conduct.
98
158
 
99
159
  ## License
100
160
 
101
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
161
+ The gem is available as open source under the terms of the
162
+ [MIT License](https://opensource.org/licenses/MIT).
102
163
 
103
164
  ## Code of Conduct
104
165
 
105
- Everyone interacting in the RuboCop OrderedMethods project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/shanecav84/rubocop-ordered_methods/blob/master/CODE_OF_CONDUCT.md).
166
+ Everyone interacting in the RuboCop OrderedMethods project’s codebases, issue
167
+ trackers, chat rooms and mailing lists is expected to follow the
168
+ [code of conduct](https://github.com/shanecav84/rubocop-ordered_methods/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rubocop/rake_task'
3
5
  require 'rspec/core/rake_task'
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'rubocop/ordered_methods'
@@ -0,0 +1,6 @@
1
+ ---
2
+ Layout/OrderedMethods:
3
+ Enabled: true
4
+ EnforcedStyle: 'alphabetical'
5
+ IgnoredMethods:
6
+ - initialize
@@ -1,3 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rubocop'
4
+ require_relative 'rubocop/ordered_methods'
2
5
  require_relative 'rubocop/cop/layout/ordered_methods'
3
6
  require_relative 'rubocop/cop/correctors/ordered_methods_corrector'
7
+
8
+ RuboCop::OrderedMethods.inject_defaults!
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'qualifier_node_matchers'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ # This verifies a method is defined before its alias
8
+ class AliasMethodOrderVerifier
9
+ class << self
10
+ include IgnoredNode
11
+ include QualifierNodeMatchers
12
+
13
+ # Disable cop for freezing on Ruby 2.2
14
+ # rubocop:disable Style/RedundantFreeze
15
+ ALIAS_BEFORE_METHOD_WARNING_FMT = "Won't reorder " \
16
+ '%<first_method_name>s and %<second_method_name>s because ' \
17
+ 'alias for %<first_method_name>s would be declared before ' \
18
+ 'its method definition.'.freeze
19
+ # rubocop:enable Style/RedundantFreeze
20
+
21
+ # rubocop:disable Style/GuardClause
22
+ def verify!(current_node, previous_node)
23
+ if moving_after_alias?(current_node, previous_node)
24
+ ignore_node(current_node)
25
+ raise_warning!(current_node.method_name, previous_node.method_name)
26
+ end
27
+ if moving_after_alias?(previous_node, current_node)
28
+ ignore_node(previous_node)
29
+ raise_warning!(previous_node.method_name, current_node.method_name)
30
+ end
31
+ end
32
+ # rubocop:enable Style/GuardClause
33
+
34
+ private
35
+
36
+ def find_aliases(current_node, siblings)
37
+ siblings.select do |sibling|
38
+ (alias?(sibling) || alias_method?(sibling)) ==
39
+ current_node.method_name
40
+ end
41
+ end
42
+
43
+ # We don't want a method to be defined after its alias
44
+ def moving_after_alias?(current_node, previous_node)
45
+ siblings = current_node.parent.children
46
+ current_node_aliases = find_aliases(current_node, siblings)
47
+ filter = current_node_aliases.delete_if do |cna|
48
+ cna.sibling_index > current_node.sibling_index
49
+ end
50
+ return false if filter.empty?
51
+
52
+ current_node_aliases.any? do |cna|
53
+ previous_node.sibling_index > cna.sibling_index
54
+ end
55
+ end
56
+
57
+ def raise_warning!(first_method_name, second_method_name)
58
+ raise Warning, format(
59
+ ALIAS_BEFORE_METHOD_WARNING_FMT,
60
+ first_method_name: first_method_name,
61
+ second_method_name: second_method_name
62
+ )
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,128 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../layout/ordered_methods'
4
+ require_relative '../alias_method_order_verifier'
5
+ require_relative '../qualifier_node_matchers'
4
6
 
5
7
  module RuboCop
6
8
  module Cop
7
9
  # This auto-corrects method order
8
10
  class OrderedMethodsCorrector
9
- class << self
10
- include IgnoredNode
11
- extend NodePattern::Macros
11
+ include QualifierNodeMatchers
12
12
 
13
- ALIAS_BEFORE_METHOD_WARNING_FMT = "Won't reorder " \
14
- '%<first_method_name>s and %<second_method_name>s because ' \
15
- 'alias for %<first_method_name>s would be declared before ' \
16
- 'its method definition.'.freeze
17
- QUALIFIERS = (
18
- %i[alias_method private_class_method public_class_method] +
19
- ::RuboCop::Cop::Layout::OrderedMethods::
20
- VISIBILITY_MODIFIERS
21
- ).freeze
22
-
23
- def_node_matcher :alias?, '(:alias ... (sym $_method_name))'
24
- def_node_matcher :qualifier?, <<-PATTERN
25
- (send nil? {#{QUALIFIERS.map(&:inspect).join(' ')}}
26
- ... (sym $_method_name))
27
- PATTERN
28
-
29
- def correct(processed_source, node, previous_node)
30
- @processed_source = processed_source
31
- @current_node = node
32
- @previous_node = previous_node
13
+ def initialize(comments, siblings)
14
+ @comments = comments
15
+ @siblings = siblings
16
+ end
33
17
 
34
- verify_alias_method_order
35
- current_range = with_surroundings(@current_node)
36
- previous_range = with_surroundings(@previous_node)
37
- lambda do |corrector|
38
- corrector.replace(current_range, previous_range.source)
39
- corrector.replace(previous_range, current_range.source)
40
- end
18
+ def correct(node, previous_node)
19
+ AliasMethodOrderVerifier.verify!(node, previous_node)
20
+ current_range = join_surroundings(node)
21
+ previous_range = join_surroundings(previous_node)
22
+ lambda do |corrector|
23
+ corrector.replace(current_range, previous_range.source)
24
+ corrector.replace(previous_range, current_range.source)
41
25
  end
26
+ end
42
27
 
43
- private
44
-
45
- def found_qualifier?(node, next_sibling)
46
- (qualifier?(next_sibling) || alias?(next_sibling)) == node.method_name
47
- end
28
+ private
48
29
 
49
- # We don't want a method to be defined after its alias
50
- def moving_after_alias?(current_node, previous_node)
51
- siblings = current_node.parent.children
52
- current_node_aliases = siblings.select do |sibling|
53
- alias?(sibling) == current_node.method_name
54
- end
55
- filter = current_node_aliases.delete_if do |cna|
56
- cna.sibling_index == current_node.sibling_index + 1
57
- end
58
- return false if filter.empty?
30
+ def find_last_qualifier_index(node)
31
+ preceding_qualifier_index = node.sibling_index
32
+ last_qualifier_index = @siblings.length - 1
33
+ while preceding_qualifier_index < last_qualifier_index
34
+ break if found_qualifier?(node, @siblings[last_qualifier_index])
59
35
 
60
- current_node_aliases.any? do |cna|
61
- previous_node.sibling_index > cna.sibling_index
62
- end
36
+ last_qualifier_index -= 1
63
37
  end
64
38
 
65
- # rubocop:disable Metrics/MethodLength, Style/GuardClause
66
- def verify_alias_method_order
67
- if moving_after_alias?(@current_node, @previous_node)
68
- ignore_node(@current_node)
69
- raise Warning, format(
70
- ALIAS_BEFORE_METHOD_WARNING_FMT,
71
- first_method_name: @current_node.method_name,
72
- second_method_name: @previous_node.method_name
73
- )
74
- end
75
- if moving_after_alias?(@previous_node, @current_node)
76
- ignore_node(@previous_node)
77
- raise Warning, format(
78
- ALIAS_BEFORE_METHOD_WARNING_FMT,
79
- first_method_name: @previous_node.method_name,
80
- second_method_name: @current_node.method_name
81
- )
82
- end
83
- end
84
- # rubocop:enable Metrics/MethodLength, Style/GuardClause
39
+ last_qualifier_index
40
+ end
85
41
 
86
- def with_comments(node)
87
- node.source_range
88
- .join(with_preceding_comments(node))
89
- .join(with_succeeding_comments(node))
90
- end
42
+ def found_qualifier?(node, next_sibling)
43
+ return false if next_sibling.nil?
91
44
 
92
- def with_modifiers_and_aliases(node)
93
- surrounding_range = node.source_range
94
- siblings = node.parent.children
95
- qualifier_index = node.sibling_index
96
- while found_qualifier?(node, siblings[qualifier_index + 1])
97
- qualifier_index += 1
98
- end
99
- found_node_range = with_comments(siblings[qualifier_index])
100
- surrounding_range.join(found_node_range)
101
- end
45
+ (qualifier?(next_sibling) || alias?(next_sibling)) == node.method_name
46
+ end
102
47
 
103
- def with_preceding_comments(node)
104
- surrounding_range = node.source_range
105
- @processed_source.ast_with_comments[node].each do |comment|
106
- surrounding_range = surrounding_range.join(comment.loc.expression)
107
- end
108
- surrounding_range
48
+ def join_comments(node, source_range)
49
+ @comments[node].each do |comment|
50
+ source_range = source_range.join(comment.loc.expression)
109
51
  end
52
+ source_range
53
+ end
110
54
 
111
- def with_succeeding_comments(node)
112
- surrounding_range = node.source_range
113
- @processed_source.each_comment do |comment|
114
- if comment.loc.expression.begin_pos == surrounding_range.end_pos + 1
115
- surrounding_range = surrounding_range.join(comment.loc.expression)
116
- end
117
- end
118
- surrounding_range
55
+ def join_modifiers_and_aliases(node, source_range)
56
+ preceding_qualifier_index = node.sibling_index
57
+ last_qualifier_index = find_last_qualifier_index(node)
58
+ while preceding_qualifier_index < last_qualifier_index
59
+ source_range = source_range.join(
60
+ @siblings[preceding_qualifier_index + 1].source_range
61
+ )
62
+ preceding_qualifier_index += 1
119
63
  end
64
+ source_range
65
+ end
120
66
 
121
- def with_surroundings(node)
67
+ def join_surroundings(node)
68
+ with_modifiers_and_aliases = join_modifiers_and_aliases(
69
+ node,
122
70
  node.source_range
123
- .join(with_comments(node))
124
- .join(with_modifiers_and_aliases(node))
125
- end
71
+ )
72
+ join_comments(node, with_modifiers_and_aliases)
126
73
  end
127
74
  end
128
75
  end
@@ -3,9 +3,9 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Check that methods are defined alphabetically.
6
+ # @example EnforcedStyle: alphabetical (default)
7
+ # # Check that methods are defined alphabetically.
7
8
  #
8
- # @example
9
9
  # # bad
10
10
  # def self.b; end
11
11
  # def self.a; end
@@ -33,98 +33,104 @@ module RuboCop
33
33
  include IgnoredMethods
34
34
  include RangeHelp
35
35
 
36
- MSG = 'Methods should be sorted alphabetically.'.freeze
37
- VISIBILITY_MODIFIERS = %i[
38
- module_function
39
- private
40
- protected
41
- public
42
- ].freeze
43
-
44
- def_node_matcher :class_def?, 'defs'
45
- def_node_matcher :instance_def?, 'def'
46
- def_node_matcher :visibility_modifier?, <<-PATTERN
47
- (send nil? { #{VISIBILITY_MODIFIERS.map(&:inspect).join(' ')} })
48
- PATTERN
36
+ COMPARISONS = {
37
+ 'alphabetical' => lambda do |left_method, right_method|
38
+ (left_method.method_name <=> right_method.method_name) != 1
39
+ end
40
+ }.freeze
41
+ ERR_INVALID_COMPARISON = 'Invalid "Comparison" config for ' \
42
+ "#{cop_name}. Expected one of: #{COMPARISONS.keys.join(', ')}".freeze
49
43
 
50
44
  def autocorrect(node)
51
- OrderedMethodsCorrector.correct(
52
- processed_source,
53
- node,
54
- @previous_node
55
- )
45
+ @corrector.correct(node, @previous_node)
56
46
  end
57
47
 
58
48
  def on_begin(node)
59
- consecutive_methods(node.children) do |previous, current|
49
+ cache(node)
50
+ consecutive_methods(@siblings) do |previous, current|
60
51
  unless ordered?(previous, current)
61
52
  @previous_node = previous
62
- add_offense(current)
53
+ add_offense(
54
+ current,
55
+ message: 'Methods should be sorted in ' \
56
+ "#{cop_config['EnforcedStyle']} order."
57
+ )
63
58
  end
64
59
  end
65
60
  end
66
61
 
67
62
  private
68
63
 
69
- def consecutive_methods(ast)
70
- filtered_and_grouped(ast).each do |method_group|
64
+ def access_modified?(node, is_class_method_block)
65
+ (node.defs_type? && !is_class_method_block) ||
66
+ (node.def_type? && is_class_method_block) ||
67
+ (node.send_type? && node.bare_access_modifier?)
68
+ end
69
+
70
+ # Cache to avoid traversing the AST multiple times
71
+ def cache(node)
72
+ @cache ||= begin
73
+ @siblings = node.children
74
+
75
+ # Init the corrector with the cache to avoid traversing
76
+ # the AST in the corrector
77
+ if @options[:auto_correct]
78
+ comments = processed_source.ast_with_comments
79
+ @corrector = OrderedMethodsCorrector.new(comments, @siblings)
80
+ end
81
+ end
82
+ end
83
+
84
+ # We disable `Style/ExplicitBlockArgument` for performance. See
85
+ # https://github.com/shanecav84/rubocop-ordered_methods/pull/5#pullrequestreview-562957146
86
+ # rubocop:disable Style/ExplicitBlockArgument
87
+ def consecutive_methods(nodes)
88
+ filtered = filter_relevant_nodes(nodes)
89
+ filtered_and_grouped = group_methods_by_access_modifier(filtered)
90
+ filtered_and_grouped.each do |method_group|
71
91
  method_group.each_cons(2) do |left_method, right_method|
72
92
  yield left_method, right_method
73
93
  end
74
94
  end
75
95
  end
96
+ # rubocop:enable Style/ExplicitBlockArgument
76
97
 
77
98
  def filter_relevant_nodes(nodes)
78
99
  nodes.select do |node|
79
100
  (
80
- class_def?(node) ||
81
- instance_def?(node) ||
82
- visibility_modifier?(node)
83
- ) && !ignored_method?(node.method_name)
101
+ (node.defs_type? || node.def_type?) &&
102
+ !ignored_method?(node.method_name)
103
+ ) || (node.send_type? && node.bare_access_modifier?)
84
104
  end
85
105
  end
86
106
 
87
- def filtered_and_grouped(ast)
88
- group_methods_by_visiblity_block(filter_relevant_nodes(ast))
89
- end
90
-
91
- # Group methods by the visiblity block they are declared in. Multiple
92
- # blocks of the same visiblity will have their methods grouped
107
+ # Group methods by the access modifier block they are declared in.
108
+ # Multiple blocks of the same modifier will have their methods grouped
93
109
  # separately; for example, the following would be separated into two
94
110
  # groups:
95
111
  # private
96
112
  # def a; end
97
113
  # private
98
114
  # def b; end
99
- # rubocop:disable Metrics/MethodLength
100
- def group_methods_by_visiblity_block(nodes)
115
+ def group_methods_by_access_modifier(nodes)
101
116
  is_class_method_block = false
117
+
102
118
  nodes.each_with_object([[]]) do |node, grouped_methods|
103
- if new_visiblity_block?(node, is_class_method_block)
119
+ if access_modified?(node, is_class_method_block)
104
120
  grouped_methods << []
105
121
  end
106
-
107
- is_class_method_block = true if class_def?(node)
108
- is_class_method_block = false if instance_def?(node)
109
-
110
- if visibility_modifier?(node)
111
- is_class_method_block = false
112
- next
113
- end
122
+ is_class_method_block = node.defs_type?
123
+ next if node.send_type? && node.bare_access_modifier?
114
124
 
115
125
  grouped_methods.last << node
116
126
  end
117
127
  end
118
- # rubocop:enable Metrics/MethodLength
119
-
120
- def new_visiblity_block?(node, is_class_method_block)
121
- (class_def?(node) && !is_class_method_block) ||
122
- (instance_def?(node) && is_class_method_block) ||
123
- visibility_modifier?(node)
124
- end
125
128
 
126
129
  def ordered?(left_method, right_method)
127
- (left_method.method_name <=> right_method.method_name) != 1
130
+ comparison = COMPARISONS[cop_config['EnforcedStyle']]
131
+ raise Error, ERR_INVALID_COMPARISON if comparison.nil?
132
+
133
+ comparison.call(left_method, right_method)
128
134
  end
129
135
  end
130
136
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # defines matchers for qualifier nodes
6
+ module QualifierNodeMatchers
7
+ extend NodePattern::Macros
8
+
9
+ QUALIFIERS = %i[
10
+ alias_method
11
+ module_function
12
+ private_class_method
13
+ public_class_method
14
+ private
15
+ protected
16
+ public
17
+ ].freeze
18
+
19
+ def_node_matcher :alias?, '(:alias ... (sym $_method_name))'
20
+ def_node_matcher :alias_method?,
21
+ '(send nil? {:alias_method} ... (sym $_method_name))'
22
+ def_node_matcher :qualifier?, <<-PATTERN
23
+ (send nil? {#{QUALIFIERS.map(&:inspect).join(' ')}}
24
+ ... (sym $_method_name))
25
+ PATTERN
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # Our namespace
5
+ module OrderedMethods
6
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
7
+ CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
8
+
9
+ def self.inject_defaults!
10
+ path = CONFIG_DEFAULT.to_s
11
+ hash = ConfigLoader.send(:load_yaml_configuration, path)
12
+ config = Config.new(hash, path)
13
+ puts "configuration from #{path}" if ConfigLoader.debug?
14
+ config = ConfigLoader.merge_with_default(config, path)
15
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
16
+ end
17
+ end
18
+ end
@@ -1,31 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
 
4
6
  Gem::Specification.new do |spec|
5
- spec.name = 'rubocop-ordered_methods'
6
- spec.version = '0.2'
7
- spec.authors = ['Shane Cavanaugh']
8
- spec.email = ['shane@shanecav.net']
7
+ spec.name = 'rubocop-ordered_methods'
8
+ spec.version = '0.7'
9
+ spec.authors = ['Shane Cavanaugh']
10
+ spec.email = ['shane@shanecav.net']
9
11
 
10
- spec.summary = 'Checks that methods are ordered alphabetically.'
11
- spec.homepage = 'https://github.com/shanecav84/rubocop-ordered_methods'
12
- spec.license = 'MIT'
12
+ spec.summary = 'Checks that methods are ordered alphabetically.'
13
+ spec.homepage = 'https://github.com/shanecav84/rubocop-ordered_methods'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 2.4'
13
16
 
14
17
  # Specify which files should be added to the gem when it is released.
15
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added
16
19
  # into git.
17
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
21
  `git ls-files -z`.split("\x0").reject do |f|
19
22
  f.match(%r{^(test|spec|features)/})
20
23
  end
21
24
  end
22
- spec.bindir = 'exe'
23
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
27
  spec.require_paths = ['lib']
25
28
 
26
- spec.add_runtime_dependency 'rubocop', '~> 0.6'
29
+ spec.add_runtime_dependency 'rubocop', '>= 1.0'
27
30
 
28
- spec.add_development_dependency 'bundler', '~> 1.17'
29
- spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'bundler'
32
+ spec.add_development_dependency 'rake', '~> 12.3.3'
30
33
  spec.add_development_dependency 'rspec', '~> 3.0'
31
34
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-ordered_methods
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Cavanaugh
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-17 00:00:00.000000000 Z
11
+ date: 2021-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.6'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0.6'
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.17'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.17'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: 12.3.3
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: '10.0'
54
+ version: 12.3.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +66,7 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
- description:
69
+ description:
70
70
  email:
71
71
  - shane@shanecav.net
72
72
  executables: []
@@ -74,24 +74,30 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".rakeTasks"
77
78
  - ".rubocop.yml"
78
79
  - ".rubocop_todo.yml"
79
80
  - ".travis.yml"
81
+ - CHANGELOG.md
80
82
  - CODE_OF_CONDUCT.md
81
83
  - Gemfile
82
84
  - LICENSE.txt
83
85
  - README.md
84
86
  - Rakefile
85
87
  - bin/console
88
+ - config/default.yml
86
89
  - lib/rubocop-ordered_methods.rb
90
+ - lib/rubocop/cop/alias_method_order_verifier.rb
87
91
  - lib/rubocop/cop/correctors/ordered_methods_corrector.rb
88
92
  - lib/rubocop/cop/layout/ordered_methods.rb
93
+ - lib/rubocop/cop/qualifier_node_matchers.rb
94
+ - lib/rubocop/ordered_methods.rb
89
95
  - rubocop-ordered_methods.gemspec
90
96
  homepage: https://github.com/shanecav84/rubocop-ordered_methods
91
97
  licenses:
92
98
  - MIT
93
99
  metadata: {}
94
- post_install_message:
100
+ post_install_message:
95
101
  rdoc_options: []
96
102
  require_paths:
97
103
  - lib
@@ -99,15 +105,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
105
  requirements:
100
106
  - - ">="
101
107
  - !ruby/object:Gem::Version
102
- version: '0'
108
+ version: '2.4'
103
109
  required_rubygems_version: !ruby/object:Gem::Requirement
104
110
  requirements:
105
111
  - - ">="
106
112
  - !ruby/object:Gem::Version
107
113
  version: '0'
108
114
  requirements: []
109
- rubygems_version: 3.0.1
110
- signing_key:
115
+ rubygems_version: 3.1.2
116
+ signing_key:
111
117
  specification_version: 4
112
118
  summary: Checks that methods are ordered alphabetically.
113
119
  test_files: []