rubocop-nathank 1.0.0 → 2.0.0

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: d1cbe27ef830beab287c9fe5f094cb0779bd11624b305c70c5dc9cf213c06693
4
- data.tar.gz: d2056f2799a73989349c29d89cde6437d79d4084043325176bb6162ddc55c20f
3
+ metadata.gz: 0cec356ff42dae5257d46997d1266931e657bacc97da9dc7f275d487782ab80e
4
+ data.tar.gz: 5dafe29111e93b1b6d4c6373076999e52ad60451b8160f840d7478194754a71f
5
5
  SHA512:
6
- metadata.gz: f56ce9201f12e91a550d6024fdeffb1d7bef352e1424b1577ddc6b6cfa17cbfc6566d9ec2536cc12cea23c94df7e4f68b2cf20216fe1726e35dd3e7e0053fd62
7
- data.tar.gz: b5c2e4a4460a4c06713cd78f98bd04688cac75acdce2faf4d08c13d4f598021720b69b4557ca9acae7aa022b193d133c92f6fdc61626cac251d2961dd98df6a9
6
+ metadata.gz: 1f3c75b4d53b7f1dad397a9f6a96e3510cbbce0cbf862b3d508eee4c3825893cc529eb59ab4cfff4853972ac937e5638456e258f6fffcd766df39a3d10f72c9a
7
+ data.tar.gz: 92bb4cbfdd73e40a589f4869a96d6a7c95d0fe633c8cbc0f001dd7cc383134b184c6213ab296a441e90ca54d1ded94be37effc7674f726e7b5af51e58cf6c640
data/CHANGELOG.md CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.0.0] - 2026-10-29
11
+
12
+ ### Changed
13
+
14
+ - The plugin sets `AllCops/DisabledByDefault`, which is what it was always for:
15
+ RuboCop's own cops are off and the house cops are on, so a project needs
16
+ nothing in its `.rubocop.yml` beyond the `plugins:` entry.
17
+ - A project must no longer set `AllCops/DisabledByDefault` itself. Your config is
18
+ merged over the plugin's, so setting it again takes the house cops off along
19
+ with RuboCop's and the run reports nothing. Remove it, and remove the
20
+ `Nathank/*: Enabled: true` lines it made necessary.
21
+
22
+ ### Removed
23
+
24
+ - `Nathank/SingleLineMethodsForEvents`. Endless methods are a matter of taste
25
+ rather than house style, and the cop raised on any file holding a method with
26
+ its own `rescue`, which took it out of the run without saying so. Remove any
27
+ `.rubocop.yml` entry for it.
28
+
29
+ ### Fixed
30
+
31
+ - `prism_statements` reads the statements of a `BeginNode`, so a method with its
32
+ own `rescue` or `ensure` no longer raises `undefined method 'body'`.
33
+
10
34
  ## [1.0.0] - 2026-10-27
11
35
 
12
36
  ### Added
@@ -26,5 +50,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
26
50
  lint_roller plugin class is now `RuboCop::Nathank::Plugin`, referenced by the
27
51
  gemspec's `default_lint_roller_plugin` metadata.
28
52
 
29
- [Unreleased]: https://github.com/n-at-han-k/rubocop-nathank/compare/v1.0.0...HEAD
53
+ [Unreleased]: https://github.com/n-at-han-k/rubocop-nathank/compare/v2.0.0...HEAD
54
+ [2.0.0]: https://github.com/n-at-han-k/rubocop-nathank/compare/v1.0.0...v2.0.0
30
55
  [1.0.0]: https://github.com/n-at-han-k/rubocop-nathank/releases/tag/v1.0.0
@@ -3,6 +3,10 @@
3
3
  # This is the default configuration file for rubocop-nathank.
4
4
  # You can override any of these settings in your .rubocop.yml file.
5
5
 
6
+ # The whole point of the plugin: the house style is what these cops say, not what RuboCop's defaults say, so the defaults are off and the cops below are on. A project wanting one of the defaults back enables it by name in its own .rubocop.yml, which is merged over this. It must not set DisabledByDefault itself: that would take these cops off too.
7
+ AllCops:
8
+ DisabledByDefault: true
9
+
6
10
  Nathank/BeginBlockAssignment:
7
11
  Description: "Bans assigning a `begin...end` expression; the assignment goes inside the block."
8
12
  Enabled: true
@@ -41,11 +45,6 @@ Nathank/NoReturn:
41
45
  Enabled: true
42
46
  VersionAdded: "0.1.0"
43
47
 
44
- Nathank/SingleLineMethodsForEvents:
45
- Description: "A one-expression method body uses the endless form."
46
- Enabled: true
47
- VersionAdded: "0.1.0"
48
-
49
48
  Nathank/UseTap:
50
49
  Description: "Requires `tap` where a method assigns a local on its first line and returns it on its last."
51
50
  Enabled: true
@@ -98,11 +98,16 @@ module RuboCop
98
98
 
99
99
  # The statements of a body, whether it holds one or many.
100
100
  #
101
- # @parameter body [Prism::StatementsNode | nil] the body of a method, module, or block.
101
+ # A method with its own `rescue` has a BeginNode body, whose statements are one level in.
102
+ #
103
+ # @parameter body [Prism::Node | Nil] the body of a method, module, or block.
102
104
  # @returns [Array(Prism::Node)] its statements, which is empty when there is no body.
103
105
  def prism_statements(body)
104
- if body.nil?
106
+ case body
107
+ when nil
105
108
  []
109
+ when ::Prism::BeginNode
110
+ self.prism_statements(body.statements)
106
111
  else
107
112
  body.body
108
113
  end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module RuboCop
7
7
  module Nathank
8
- VERSION = "1.0.0"
8
+ VERSION = "2.0.0"
9
9
  end
10
10
  end
@@ -12,7 +12,6 @@ require_relative "nathank/comment_structure"
12
12
  require_relative "nathank/no_conditional_assignment"
13
13
  require_relative "nathank/no_modifier_if"
14
14
  require_relative "nathank/no_return"
15
- require_relative "nathank/single_line_methods_for_events"
16
15
  require_relative "nathank/use_tap"
17
16
 
18
17
  # @namespace
data/readme.md CHANGED
@@ -16,6 +16,30 @@ plugins:
16
16
  - rubocop-nathank
17
17
  ```
18
18
 
19
+ That is the whole configuration. The plugin sets `AllCops/DisabledByDefault`, so RuboCop's own
20
+ cops are off and the ones below are on: the house style is what these cops say rather than what
21
+ the defaults say, and a project does not have to list them to get them.
22
+
23
+ A default you want back is enabled by name, and a house cop you do not want is disabled the same
24
+ way, because your `.rubocop.yml` is merged over the plugin's:
25
+
26
+ ``` yaml
27
+ # .rubocop.yml
28
+ plugins:
29
+ - rubocop-nathank
30
+
31
+ Style/StringLiterals:
32
+ Enabled: true
33
+ EnforcedStyle: double_quotes
34
+
35
+ Nathank/NoReturn:
36
+ Enabled: false
37
+ ```
38
+
39
+ What you must not do is set `AllCops/DisabledByDefault` yourself. The plugin already sets it, and
40
+ your file is merged over the plugin's: setting it again takes the plugin's own cops off along with
41
+ RuboCop's, and you get a run which inspects every file and reports nothing.
42
+
19
43
  ## Available Cops
20
44
 
21
45
  * `Nathank/BeginBlockAssignment` - no assigning a `begin...end`; the assignment goes inside.
@@ -23,7 +47,6 @@ plugins:
23
47
  * `Nathank/NoModifierIf` - no modifier `if` / `unless`, so a guard cannot hide off the right edge.
24
48
  * `Nathank/NoReturn` - no `return`; the last expression is the return value.
25
49
  * `Nathank/UseTap` - `tap` where a method assigns a local and returns it.
26
- * `Nathank/SingleLineMethodsForEvents` - a one-expression body uses the endless form.
27
50
  * `Nathank/CommentStructure` - how a comment is built: unwrapped paragraphs, a summary no longer
28
51
  than the code earns, and annotations on a documented interface.
29
52
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-nathank
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Kidd
@@ -81,7 +81,6 @@ files:
81
81
  - lib/rubocop/nathank/no_modifier_if.rb
82
82
  - lib/rubocop/nathank/no_return.rb
83
83
  - lib/rubocop/nathank/plugin.rb
84
- - lib/rubocop/nathank/single_line_methods_for_events.rb
85
84
  - lib/rubocop/nathank/support/prism_source.rb
86
85
  - lib/rubocop/nathank/use_tap.rb
87
86
  - lib/rubocop/nathank/version.rb
@@ -1,168 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the Apache License, Version 2.0.
4
- # Copyright, 2026, by General Intelligence Systems.
5
-
6
- require_relative "support/prism_source"
7
-
8
- module RuboCop
9
- module Nathank
10
- # Requires a method whose body is a single expression to use the endless method form.
11
- #
12
- # @example
13
- # # bad
14
- # def event_type
15
- # "m.room.message"
16
- # end
17
- # # good
18
- # def event_type = "m.room.message"
19
- class SingleLineMethodsForEvents < ::RuboCop::Cop::Base
20
- include PrismSource
21
- extend ::RuboCop::Cop::AutoCorrector
22
-
23
- MSG = "A method whose body is one expression must use the endless form: `def name = expression`."
24
-
25
- # Expressions which can follow ` = ` unchanged. Anything with its own `end`, or with lower precedence than the assignment, is left as a block: what it would parse as is not what it says as a body.
26
- ACCEPTED_BODIES = [
27
- ::Prism::ArrayNode,
28
- ::Prism::CallNode,
29
- ::Prism::ClassVariableReadNode,
30
- ::Prism::ConstantPathNode,
31
- ::Prism::ConstantReadNode,
32
- ::Prism::FalseNode,
33
- ::Prism::FloatNode,
34
- ::Prism::GlobalVariableReadNode,
35
- ::Prism::HashNode,
36
- ::Prism::ImaginaryNode,
37
- ::Prism::InstanceVariableReadNode,
38
- ::Prism::IntegerNode,
39
- ::Prism::InterpolatedStringNode,
40
- ::Prism::InterpolatedSymbolNode,
41
- ::Prism::InterpolatedXStringNode,
42
- ::Prism::LocalVariableReadNode,
43
- ::Prism::NilNode,
44
- ::Prism::RangeNode,
45
- ::Prism::RationalNode,
46
- ::Prism::RegularExpressionNode,
47
- ::Prism::SelfNode,
48
- ::Prism::StringNode,
49
- ::Prism::SymbolNode,
50
- ::Prism::TrueNode,
51
- ::Prism::XStringNode,
52
- ].freeze
53
-
54
- def on_new_investigation
55
- self.prism_each(::Prism::DefNode).each do |node|
56
- if self.rewriteable?(node)
57
- self.report(node)
58
- end
59
- end
60
- end
61
-
62
- private
63
-
64
- # The one expression a method's body is, when that is what it is.
65
- def sole_expression(node)
66
- statements = self.prism_statements(node.body)
67
-
68
- if statements.size == 1
69
- statements.first
70
- else
71
- nil
72
- end
73
- end
74
-
75
- # A method is rewritten only when it is not endless, not a setter, and has one non-heredoc body expression on one line.
76
- def rewriteable?(node)
77
- body = self.sole_expression(node)
78
-
79
- !self.endless?(node) &&
80
- !self.setter?(node.name) &&
81
- !body.nil? &&
82
- ACCEPTED_BODIES.any?{|klass| body.is_a?(klass)} &&
83
- self.single_line?(node, body) &&
84
- !self.prism_heredoc?(body)
85
- end
86
-
87
- # An endless method is written with `=` rather than a body closed by `end`.
88
- def endless?(node)
89
- !node.equal_loc.nil?
90
- end
91
-
92
- # The offense is reported either way; the correction is withheld when a comment sits inside the method, since replacing the method would take the comment with it.
93
- def report(node)
94
- range = self.prism_node_range(node)
95
-
96
- if self.comment?(node)
97
- add_offense(range)
98
- else
99
- add_offense(range) do |corrector|
100
- corrector.replace(range, self.endless_form(node))
101
- end
102
- end
103
- end
104
-
105
- # `def foo=(value)` and `def []=(key, value)` have no endless form.
106
- def setter?(name)
107
- name == :[]= || /\A[a-zA-Z_]\w*=\z/.match?(name.to_s)
108
- end
109
-
110
- # The body on one line, and the signature on one line too, so that the rewritten method is still a single line.
111
- def single_line?(node, body)
112
- body.location.start_line == body.location.end_line &&
113
- !self.signature_source(node).include?("\n")
114
- end
115
-
116
- # The source of the signature, e.g. `def build(**fields)`, without the gap before the body.
117
- def signature_source(node)
118
- source = processed_source.buffer.source
119
-
120
- # byteslice, because every offset here is one of Prism's and those count bytes, where `String#[]` counts characters.
121
- source.byteslice(node.location.start_offset...self.signature_end(node))
122
- end
123
-
124
- def signature_end(node)
125
- ending = node.name_loc.end_offset
126
-
127
- if parameters = node.parameters
128
- [ending, parameters.location.end_offset].max
129
- else
130
- ending
131
- end
132
- end
133
-
134
- def comment?(node)
135
- self.prism_comments.any? do |comment|
136
- (node.location.start_line..node.location.end_line).cover?(comment.location.start_line)
137
- end
138
- end
139
-
140
- def endless_form(node)
141
- "#{self.signature(node)} = #{self.prism_source(self.sole_expression(node))}"
142
- end
143
-
144
- def signature(node)
145
- "#{self.receiver_prefix(node)}#{node.name}#{self.arguments_suffix(node)}"
146
- end
147
-
148
- def receiver_prefix(node)
149
- if node.receiver
150
- "def #{self.prism_source(node.receiver)}."
151
- else
152
- "def "
153
- end
154
- end
155
-
156
- # Bare arguments are ambiguous before ` = `; parenthesize them.
157
- def arguments_suffix(node)
158
- parameters = node.parameters
159
-
160
- if parameters.nil?
161
- ""
162
- else
163
- "(#{self.prism_source(parameters)})"
164
- end
165
- end
166
- end
167
- end
168
- end