rubocop-ordered_methods 0.4 → 0.5

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: 711dd4dc7c13df5dc95040f2824dc88868fc3ebc5996088630d0a13638853308
4
- data.tar.gz: 4b9e74bb42389db5ac593b9194e5e6138b9d01f174c1d165fc4949e33d6da4b2
3
+ metadata.gz: 5666abbd94c131384aa150fd5d1065c26a17c937b924b0bac4bc7142055a4528
4
+ data.tar.gz: dc127d1fe270e7c41037218ccfd7cba20297dee56fc59b1998188530ce3ef564
5
5
  SHA512:
6
- metadata.gz: 3b427b3dec7ba7f85f291da04d988f0bad8981b4db54ebf769fbf29de2e170abc200a0daf1297ebd92e6dcc5d4a3eb6fb8a058f7d72eae8ba06a412434886b5f
7
- data.tar.gz: 03fe372de5334f2b6c25c1a0b78a8047d7cecd8f010eb441ea2d649b39f58228574b65f4eb64a14611072473329c7f1a4cc6a4c21ef62d59da3d2187950f797f
6
+ metadata.gz: 3cfbc383385af0d961764fa99886da093636f26a17271541fae6aa050a1dfc65518fe4a0c9a1ec0c069e86cad3838d2394e22ae2630a2b547e4bd8bb0f823e81
7
+ data.tar.gz: 56e6d697ee553d9a362b12f009154b0df809dbc67b1a4232082dfe1a03e1401591231cbbffea68d5e1515886151827c54eb47476c9c542e28b6692bf777a0a73
data/.rubocop.yml CHANGED
@@ -2,6 +2,9 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  require: rubocop-ordered_methods
4
4
 
5
+ AllCops:
6
+ TargetRubyVersion: 2.3
7
+
5
8
  Metrics/BlockLength:
6
9
  Exclude:
7
10
  - spec/**/*
data/.travis.yml CHANGED
@@ -3,7 +3,6 @@ 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
data/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5] - 2019-11-05
10
+
11
+ ### Removed
12
+
13
+ - Drop Ruby 2.2 support
14
+
15
+ ### Changed
16
+
17
+ - Nonadjacent qualifiers are now autocorrected (#4). Thanks @adamkiczula.
18
+ - Cache AST traversals for significant speed up on large files
19
+
9
20
  ## [0.4] - 2019-06-11
10
21
 
11
22
  ### Changed
data/README.md CHANGED
@@ -3,33 +3,33 @@
3
3
 
4
4
  # RuboCop OrderedMethods
5
5
 
6
- Check that methods are defined alphabetically. Note [caveats](#caveats) for
7
- autocorrection.
6
+ Check that methods are defined alphabetically per access modifier block (class,
7
+ public, private, protected). Includes [autocorrection](#corrector).
8
8
 
9
9
  ```ruby
10
10
  # bad
11
- def self.b; end
12
- def self.a; end
11
+ def self.b_class; end
12
+ def self.a_class; end
13
13
 
14
- def b; end
15
- def a; end
14
+ def b_public; end
15
+ def a_public; end
16
16
 
17
17
  private
18
18
 
19
- def d; end
20
- def c; end
19
+ def b_private; end
20
+ def a_private; end
21
21
 
22
22
  # good
23
- def self.a; end
24
- def self.b; end
23
+ def self.a_class; end
24
+ def self.b_class; end
25
25
 
26
- def a; end
27
- def b; end
26
+ def a_public; end
27
+ def b_public; end
28
28
 
29
29
  private
30
30
 
31
- def c; end
32
- def d; end
31
+ def a_private; end
32
+ def b_private; end
33
33
  ```
34
34
 
35
35
  ## Installation
@@ -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,120 +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 = %i[
18
- alias_method
19
- module_function
20
- private_class_method
21
- public_class_method
22
- private
23
- protected
24
- public
25
- ].freeze
26
-
27
- def_node_matcher :alias?, '(:alias ... (sym $_method_name))'
28
- def_node_matcher :qualifier?, <<-PATTERN
29
- (send nil? {#{QUALIFIERS.map(&:inspect).join(' ')}}
30
- ... (sym $_method_name))
31
- PATTERN
32
-
33
- def correct(processed_source, node, previous_node)
34
- @processed_source = processed_source
35
- @current_node = node
36
- @previous_node = previous_node
13
+ def initialize(comments, siblings)
14
+ @comments = comments
15
+ @siblings = siblings
16
+ end
37
17
 
38
- verify_alias_method_order
39
- current_range = join_surroundings(@current_node)
40
- previous_range = join_surroundings(@previous_node)
41
- lambda do |corrector|
42
- corrector.replace(current_range, previous_range.source)
43
- corrector.replace(previous_range, current_range.source)
44
- 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)
45
25
  end
26
+ end
46
27
 
47
- private
28
+ private
48
29
 
49
- def found_qualifier?(node, next_sibling)
50
- return false if next_sibling.nil?
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])
51
35
 
52
- (qualifier?(next_sibling) || alias?(next_sibling)) == node.method_name
36
+ last_qualifier_index -= 1
53
37
  end
54
38
 
55
- def join_comments(node, source_range)
56
- @processed_source.ast_with_comments[node].each do |comment|
57
- source_range = source_range.join(comment.loc.expression)
58
- end
59
- source_range
60
- end
39
+ last_qualifier_index
40
+ end
61
41
 
62
- def join_modifiers_and_aliases(node, source_range)
63
- siblings = node.parent.children
64
- preceding_qualifier_index = node.sibling_index
65
- while found_qualifier?(node, siblings[preceding_qualifier_index + 1])
66
- source_range = source_range.join(
67
- siblings[preceding_qualifier_index + 1].source_range
68
- )
69
- preceding_qualifier_index += 1
70
- end
71
- source_range
72
- end
42
+ def found_qualifier?(node, next_sibling)
43
+ return false if next_sibling.nil?
73
44
 
74
- def join_surroundings(node)
75
- with_modifiers_and_aliases = join_modifiers_and_aliases(
76
- node,
77
- node.source_range
78
- )
79
- join_comments(node, with_modifiers_and_aliases)
80
- end
81
-
82
- # We don't want a method to be defined after its alias
83
- def moving_after_alias?(current_node, previous_node)
84
- siblings = current_node.parent.children
85
- current_node_aliases = siblings.select do |sibling|
86
- alias?(sibling) == current_node.method_name
87
- end
88
- filter = current_node_aliases.delete_if do |cna|
89
- cna.sibling_index == current_node.sibling_index + 1
90
- end
91
- return false if filter.empty?
45
+ (qualifier?(next_sibling) || alias?(next_sibling)) == node.method_name
46
+ end
92
47
 
93
- current_node_aliases.any? do |cna|
94
- previous_node.sibling_index > cna.sibling_index
95
- end
48
+ def join_comments(node, source_range)
49
+ @comments[node].each do |comment|
50
+ source_range = source_range.join(comment.loc.expression)
96
51
  end
52
+ source_range
53
+ end
97
54
 
98
- # rubocop:disable Metrics/MethodLength, Style/GuardClause
99
- def verify_alias_method_order
100
- if moving_after_alias?(@current_node, @previous_node)
101
- ignore_node(@current_node)
102
- raise Warning, format(
103
- ALIAS_BEFORE_METHOD_WARNING_FMT,
104
- first_method_name: @current_node.method_name,
105
- second_method_name: @previous_node.method_name
106
- )
107
- end
108
- if moving_after_alias?(@previous_node, @current_node)
109
- ignore_node(@previous_node)
110
- raise Warning, format(
111
- ALIAS_BEFORE_METHOD_WARNING_FMT,
112
- first_method_name: @previous_node.method_name,
113
- second_method_name: @current_node.method_name
114
- )
115
- end
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
116
63
  end
117
- # rubocop:enable Metrics/MethodLength, Style/GuardClause
64
+ source_range
65
+ end
66
+
67
+ def join_surroundings(node)
68
+ with_modifiers_and_aliases = join_modifiers_and_aliases(
69
+ node,
70
+ node.source_range
71
+ )
72
+ join_comments(node, with_modifiers_and_aliases)
118
73
  end
119
74
  end
120
75
  end
@@ -42,15 +42,12 @@ module RuboCop
42
42
  "#{cop_name}. Expected one of: #{COMPARISONS.keys.join(', ')}".freeze
43
43
 
44
44
  def autocorrect(node)
45
- OrderedMethodsCorrector.correct(
46
- processed_source,
47
- node,
48
- @previous_node
49
- )
45
+ @corrector.correct(node, @previous_node)
50
46
  end
51
47
 
52
48
  def on_begin(node)
53
- consecutive_methods(node.children) do |previous, current|
49
+ cache(node)
50
+ consecutive_methods(@siblings) do |previous, current|
54
51
  unless ordered?(previous, current)
55
52
  @previous_node = previous
56
53
  add_offense(
@@ -70,6 +67,20 @@ module RuboCop
70
67
  (node.send_type? && node.bare_access_modifier?)
71
68
  end
72
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
+
73
84
  def consecutive_methods(nodes)
74
85
  filtered = filter_relevant_nodes(nodes)
75
86
  filtered_and_grouped = group_methods_by_access_modifier(filtered)
@@ -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
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'rubocop-ordered_methods'
8
- spec.version = '0.4'
8
+ spec.version = '0.5'
9
9
  spec.authors = ['Shane Cavanaugh']
10
10
  spec.email = ['shane@shanecav.net']
11
11
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-ordered_methods
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Cavanaugh
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-11 00:00:00.000000000 Z
11
+ date: 2019-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -86,8 +86,10 @@ files:
86
86
  - bin/console
87
87
  - config/default.yml
88
88
  - lib/rubocop-ordered_methods.rb
89
+ - lib/rubocop/cop/alias_method_order_verifier.rb
89
90
  - lib/rubocop/cop/correctors/ordered_methods_corrector.rb
90
91
  - lib/rubocop/cop/layout/ordered_methods.rb
92
+ - lib/rubocop/cop/qualifier_node_matchers.rb
91
93
  - lib/rubocop/ordered_methods.rb
92
94
  - rubocop-ordered_methods.gemspec
93
95
  homepage: https://github.com/shanecav84/rubocop-ordered_methods