rubocop-ordered_methods 0.4 → 0.5

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