rubocop-ordered_methods 0.8 → 0.10

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: fc5f933eab16f22d4ce9e90bac7b7da25af7af45f7fd1204974ea26d98287476
4
- data.tar.gz: c3e5a535a8667acf2c88e8c127219b8b8e330d10e6575df5748391ec1c7758ba
3
+ metadata.gz: c43226dde578a4844ba7c579a7fa5dfb52f05dce2e84d9a68f1e250e272d4e58
4
+ data.tar.gz: 636542d7c4be5982d3424703ba2062c72c4fdbfcf4f289a5b593050b68c16969
5
5
  SHA512:
6
- metadata.gz: c83ba399a7357517935466f59e4be28b75fbb399a571041b54ba4be1c387797b1867be69fcac2abe8e60e89572b34d35d9a327a171880cec2d9807ee258766ca
7
- data.tar.gz: dc2897b646af1eb6e2b84dbe2e693be8a0a48de8645caf9551557c6dfe36809a34c92c4166428f9f0b17bd541c3a5c8bf60d349ea3db3286c09ebb4897467e7e
6
+ metadata.gz: 1eced8a7bb0e4a33bf58cae6b0b0d90fd9814318635689450ee34646905a5a41fbd97189c51d9763706f307d4ed4c3032e3eb02af2aa5ce79c373f12bd5f1019
7
+ data.tar.gz: 4c528b7368611c20b2ab790f28502f3c44e4e6546bcbff35b199c749932583bdea36cc5d441e598efb7b7e199b63fbac97f50a6534b206052f60474ebe24147a
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ rspec:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby:
15
+ - "2.7"
16
+ - "3.0"
17
+ - "3.1"
18
+ - "3.2"
19
+
20
+ name: "Ruby ${{ matrix.ruby }}: run rspec"
21
+ steps:
22
+ - uses: actions/checkout@v3
23
+ - uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: "${{ matrix.ruby }}"
26
+ bundler-cache: true
27
+ - run: bundle exec rspec
28
+
29
+ rubocop:
30
+ runs-on: ubuntu-latest
31
+ strategy:
32
+ matrix:
33
+ ruby:
34
+ - "2.7"
35
+ - "3.0"
36
+ - "3.1"
37
+ - "3.2"
38
+
39
+ name: "Ruby ${{ matrix.ruby }}: run rubocop"
40
+ steps:
41
+ - uses: actions/checkout@v3
42
+ - uses: ruby/setup-ruby@v1
43
+ with:
44
+ ruby-version: "${{ matrix.ruby }}"
45
+ bundler-cache: true
46
+ - run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -5,7 +5,16 @@ require: rubocop-ordered_methods
5
5
  AllCops:
6
6
  NewCops: enable
7
7
  SuggestExtensions: false
8
- TargetRubyVersion: 2.4
8
+ TargetRubyVersion: 2.7
9
+
10
+ # Subtle, left to author's discretion. In a long method with many guard clauses,
11
+ # a blank line may help. But, in a short method, especially with only a single
12
+ # guard clause, a blank line can be disruptive.
13
+ Layout/EmptyLineAfterGuardClause:
14
+ Enabled: false
15
+
16
+ Layout/LineEndStringConcatenationIndentation:
17
+ EnforcedStyle: indented
9
18
 
10
19
  Metrics/BlockLength:
11
20
  Exclude:
@@ -18,3 +27,9 @@ Metrics/MethodLength:
18
27
  Naming/FileName:
19
28
  Exclude:
20
29
  - lib/rubocop-ordered_methods.rb
30
+
31
+ # Use the semantic style. If a block has side effects use `do`, and if it is
32
+ # pure use `{}`. This style is too nuanced for a linter, so the cop is
33
+ # disabled.
34
+ Style/BlockDelimiters:
35
+ Enabled: false
data/.travis.yml CHANGED
@@ -3,10 +3,10 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.3
7
6
  - 2.4
8
7
  - 2.5
9
8
  - 2.6
9
+ - 2.7
10
10
  script: bundle exec rake
11
11
  before_install:
12
12
  - gem install bundler || gem install bundler --version '< 2'
data/CHANGELOG.md CHANGED
@@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.10] - 2021-03-10
10
+
11
+ ### Removed
12
+
13
+ - Drop support for Ruby 2.4, 2.5, and 2.6
14
+
15
+ ### Added
16
+
17
+ - Support for custom method qualifiers ([#11](https://github.com/shanecav84/rubocop-ordered_methods/pull/11)). Thanks @Darhazer.
18
+ - Setup CI ([#12](https://github.com/shanecav84/rubocop-ordered_methods/pull/12)). Thanks @Darhazer.
19
+
20
+ ## [0.9] - 2021-03-10
21
+
22
+ ### Added
23
+
24
+ - Autocorrection support for Sorbet signatures
25
+
9
26
  ## [0.8] - 2021-02-01
10
27
 
11
28
  ### Fixed
data/Gemfile CHANGED
@@ -2,4 +2,9 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
+ gem 'bundler'
6
+ gem 'byebug'
7
+ gem 'rake', '~> 12.3.3'
8
+ gem 'rspec', '~> 3.0'
9
+
5
10
  gemspec
data/README.md CHANGED
@@ -74,8 +74,23 @@ rubocop --require rubocop-ordered_methods
74
74
 
75
75
  Name | Default value | Configurable values
76
76
  --- | --- | ---
77
- EnforcedStyle | `alphabetical` | `alphabetical`
78
- IgnoredMethods | `initialize` | Array
77
+ EnforcedStyle | `'alphabetical'` | `'alphabetical'`
78
+ IgnoredMethods | `['initialize']` | Array
79
+ MethodQualifiers | `[]` | Array
80
+ Signature | `nil` | `'sorbet'`, `nil`
81
+
82
+ #### Example
83
+
84
+ ```
85
+ # .rubocop.yml
86
+ Layout/OrderedMethods:
87
+ EnforcedStyle: alphabetical
88
+ IgnoredMethods:
89
+ - initialize
90
+ MethodQualifiers:
91
+ - memoize
92
+ Signature: sorbet
93
+ ```
79
94
 
80
95
  ### Corrector
81
96
 
@@ -125,6 +140,23 @@ protected :instance_a
125
140
  public :instance_a
126
141
  ```
127
142
 
143
+ #### Method qualifiers
144
+ Some gems (like `memery`, `memoist`, etc.) provide a DSL that modifies the method (e.g. for memoization).
145
+ Those DSL methods can be added to the `MethodQualifiers` configuration, and they will be respected.
146
+
147
+ E.g. the following source can be correctly ordered:
148
+ ```ruby
149
+ def b; end;
150
+ memoize def a;end
151
+ ```
152
+
153
+ #### Method signatures
154
+
155
+ Support for (Sorbet) method signatures was added to the corrector by
156
+ [#7](https://github.com/shanecav84/rubocop-ordered_methods/pull/7).
157
+ It is off by default due to performance concerns (not yet benchmarked). Enable
158
+ with `Signature: sorbet`.
159
+
128
160
  #### Caveats
129
161
 
130
162
  * The corrector will warn and refuse to order a method if it were to be
data/config/default.yml CHANGED
@@ -4,3 +4,4 @@ Layout/OrderedMethods:
4
4
  EnforcedStyle: 'alphabetical'
5
5
  IgnoredMethods:
6
6
  - initialize
7
+ Signature: ~
@@ -10,9 +10,11 @@ module RuboCop
10
10
  class OrderedMethodsCorrector
11
11
  include QualifierNodeMatchers
12
12
 
13
- def initialize(comments, siblings)
14
- @comments = comments
13
+ # @param cop_config ::RuboCop::Config
14
+ def initialize(comment_locations, siblings, cop_config)
15
+ @comment_locations = comment_locations
15
16
  @siblings = siblings
17
+ @cop_config = cop_config
16
18
  end
17
19
 
18
20
  def correct(node, previous_node)
@@ -45,13 +47,19 @@ module RuboCop
45
47
  (qualifier?(next_sibling) || alias?(next_sibling)) == node.method_name
46
48
  end
47
49
 
50
+ # @param node RuboCop::AST::DefNode
51
+ # @param source_range Parser::Source::Range
52
+ # @return Parser::Source::Range
48
53
  def join_comments(node, source_range)
49
- @comments[node].each do |comment|
54
+ @comment_locations[node.loc].each do |comment|
50
55
  source_range = source_range.join(comment.loc.expression)
51
56
  end
52
57
  source_range
53
58
  end
54
59
 
60
+ # @param node RuboCop::AST::DefNode
61
+ # @param source_range Parser::Source::Range
62
+ # @return Parser::Source::Range
55
63
  def join_modifiers_and_aliases(node, source_range)
56
64
  preceding_qualifier_index = node.sibling_index
57
65
  last_qualifier_index = find_last_qualifier_index(node)
@@ -64,12 +72,46 @@ module RuboCop
64
72
  source_range
65
73
  end
66
74
 
75
+ # @param node RuboCop::AST::DefNode
76
+ # @param source_range Parser::Source::Range
77
+ # @return Parser::Source::Range
78
+ def join_signature(node, source_range)
79
+ sib = node.left_sibling
80
+ if signature?(sib)
81
+ # If there is a comment directly above the sig, first calculate the
82
+ # range that covers both.
83
+ with_comment = join_comments(sib, sib.source_range)
84
+ source_range.join(with_comment)
85
+ else
86
+ source_range
87
+ end
88
+ end
89
+
90
+ def join_signature?
91
+ @cop_config['Signature'] == 'sorbet'
92
+ end
93
+
94
+ # @param node RuboCop::AST::DefNode
95
+ # @return Parser::Source::Range
67
96
  def join_surroundings(node)
68
97
  with_modifiers_and_aliases = join_modifiers_and_aliases(
69
98
  node,
70
99
  node.source_range
71
100
  )
72
- join_comments(node, with_modifiers_and_aliases)
101
+ with_comments = join_comments(node, with_modifiers_and_aliases)
102
+ if join_signature?
103
+ join_signature(node, with_comments)
104
+ else
105
+ with_comments
106
+ end
107
+ end
108
+
109
+ # https://sorbet.org/docs/sigs
110
+ # @param node RuboCop::AST::Node
111
+ def signature?(node)
112
+ return false unless node&.type == :block
113
+ child = node.children.first
114
+ child&.type == :send && child.method_name == :sig
73
115
  end
74
116
  end
75
117
  end
@@ -35,20 +35,27 @@ module RuboCop
35
35
  include RangeHelp
36
36
 
37
37
  COMPARISONS = {
38
- 'alphabetical' => lambda do |left_method, right_method|
39
- (left_method.method_name <=> right_method.method_name) != 1
38
+ 'alphabetical' => lambda do |left_node, right_node|
39
+ (method_name(left_node) <=> method_name(right_node)) != 1
40
40
  end
41
41
  }.freeze
42
42
  ERR_INVALID_COMPARISON = 'Invalid "Comparison" config for ' \
43
43
  "#{cop_name}. Expected one of: #{COMPARISONS.keys.join(', ')}".freeze
44
44
 
45
+ def self.method_name(node)
46
+ return node.method_name unless node.send_type?
47
+
48
+ node.first_argument.method_name
49
+ end
50
+
45
51
  def autocorrect(node)
46
- @corrector.correct(node, @previous_node)
52
+ _siblings, corrector = cache(node)
53
+ corrector.correct(node, @previous_node)
47
54
  end
48
55
 
49
56
  def on_begin(node)
50
- cache(node)
51
- consecutive_methods(@siblings) do |previous, current|
57
+ siblings, _corrector = cache(node)
58
+ consecutive_methods(siblings) do |previous, current|
52
59
  unless ordered?(previous, current)
53
60
  @previous_node = previous
54
61
  add_offense(
@@ -68,20 +75,33 @@ module RuboCop
68
75
  (node.send_type? && node.bare_access_modifier?)
69
76
  end
70
77
 
78
+ # rubocop:disable Metrics/MethodLength
71
79
  # Cache to avoid traversing the AST multiple times
72
80
  def cache(node)
73
- @cache ||= begin
74
- @siblings = node.children
75
-
76
- # Init the corrector with the cache to avoid traversing the AST in
77
- # the corrector. We always init the @corrector, even if
78
- # @options[:auto_correct] is nil, because `add_offense` always
79
- # attempts correction. This correction attempt is how RuboCop knows
80
- # if the offense can be labeled "[Correctable]".
81
- comments = processed_source.ast_with_comments
82
- @corrector = OrderedMethodsCorrector.new(comments, @siblings)
81
+ @cache ||= Hash.new do |h, key|
82
+ h[key.hash] = begin
83
+ siblings = node.children
84
+
85
+ # Init the corrector with the cache to avoid traversing the AST in
86
+ # the corrector.
87
+ #
88
+ # We always init the @corrector, even if @options[:auto_correct] is
89
+ # nil, because `add_offense` always attempts correction. This
90
+ # correction attempt is how RuboCop knows if the offense can be
91
+ # labeled "[Correctable]".
92
+ comment_locations = ::Parser::Source::Comment.associate_locations(
93
+ processed_source.ast,
94
+ processed_source.comments
95
+ )
96
+ corrector = OrderedMethodsCorrector.new(comment_locations, siblings, cop_config)
97
+
98
+ [siblings, corrector]
99
+ end
83
100
  end
101
+
102
+ @cache[node.hash]
84
103
  end
104
+ # rubocop:enable Metrics/MethodLength
85
105
 
86
106
  # We disable `Style/ExplicitBlockArgument` for performance. See
87
107
  # https://github.com/shanecav84/rubocop-ordered_methods/pull/5#pullrequestreview-562957146
@@ -99,10 +119,7 @@ module RuboCop
99
119
 
100
120
  def filter_relevant_nodes(nodes)
101
121
  nodes.select do |node|
102
- (
103
- (node.defs_type? || node.def_type?) &&
104
- !ignored_method?(node.method_name)
105
- ) || (node.send_type? && node.bare_access_modifier?)
122
+ relevant_node?(node) || (node.send_type? && qualifier_macro?(node))
106
123
  end
107
124
  end
108
125
 
@@ -134,6 +151,17 @@ module RuboCop
134
151
 
135
152
  comparison.call(left_method, right_method)
136
153
  end
154
+
155
+ def qualifier_macro?(node)
156
+ return true if node.bare_access_modifier?
157
+
158
+ cop_config['MethodQualifiers'].to_a.include?(node.method_name.to_s) &&
159
+ relevant_node?(node.first_argument)
160
+ end
161
+
162
+ def relevant_node?(node)
163
+ (node.defs_type? || node.def_type?) && !ignored_method?(node.method_name)
164
+ end
137
165
  end
138
166
  end
139
167
  end
@@ -20,9 +20,16 @@ module RuboCop
20
20
  def_node_matcher :alias_method?,
21
21
  '(send nil? {:alias_method} ... (sym $_method_name))'
22
22
  def_node_matcher :qualifier?, <<-PATTERN
23
- (send nil? {#{QUALIFIERS.map(&:inspect).join(' ')}}
24
- ... (sym $_method_name))
23
+ (send nil? #method_qualifier? ... (sym $_method_name))
25
24
  PATTERN
25
+
26
+ def method_qualifier?(name)
27
+ qualifiers.include?(name)
28
+ end
29
+
30
+ def qualifiers
31
+ @qualifiers ||= QUALIFIERS + @cop_config['MethodQualifiers'].to_a.map(&:to_sym)
32
+ end
26
33
  end
27
34
  end
28
35
  end
@@ -5,14 +5,14 @@ $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.8'
8
+ spec.version = '0.10'
9
9
  spec.authors = ['Shane Cavanaugh']
10
10
  spec.email = ['shane@shanecav.net']
11
11
 
12
12
  spec.summary = 'Checks that methods are ordered alphabetically.'
13
13
  spec.homepage = 'https://github.com/shanecav84/rubocop-ordered_methods'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = '>= 2.4'
15
+ spec.required_ruby_version = '>= 2.7'
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
18
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added
@@ -28,7 +28,5 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_runtime_dependency 'rubocop', '>= 1.0'
30
30
 
31
- spec.add_development_dependency 'bundler'
32
- spec.add_development_dependency 'rake', '~> 12.3.3'
33
- spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.metadata['rubygems_mfa_required'] = 'true'
34
32
  end
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.8'
4
+ version: '0.10'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Cavanaugh
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-01 00:00:00.000000000 Z
11
+ date: 2023-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,48 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 12.3.3
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 12.3.3
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
69
27
  description:
70
28
  email:
71
29
  - shane@shanecav.net
@@ -73,6 +31,7 @@ executables: []
73
31
  extensions: []
74
32
  extra_rdoc_files: []
75
33
  files:
34
+ - ".github/workflows/main.yml"
76
35
  - ".gitignore"
77
36
  - ".rakeTasks"
78
37
  - ".rubocop.yml"
@@ -96,7 +55,8 @@ files:
96
55
  homepage: https://github.com/shanecav84/rubocop-ordered_methods
97
56
  licenses:
98
57
  - MIT
99
- metadata: {}
58
+ metadata:
59
+ rubygems_mfa_required: 'true'
100
60
  post_install_message:
101
61
  rdoc_options: []
102
62
  require_paths:
@@ -105,14 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
65
  requirements:
106
66
  - - ">="
107
67
  - !ruby/object:Gem::Version
108
- version: '2.4'
68
+ version: '2.7'
109
69
  required_rubygems_version: !ruby/object:Gem::Requirement
110
70
  requirements:
111
71
  - - ">="
112
72
  - !ruby/object:Gem::Version
113
73
  version: '0'
114
74
  requirements: []
115
- rubygems_version: 3.1.2
75
+ rubygems_version: 3.2.33
116
76
  signing_key:
117
77
  specification_version: 4
118
78
  summary: Checks that methods are ordered alphabetically.