rubocop-ordered_methods 0.2 → 0.7

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
  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: []