rubocop-socketry 0.3.0 → 0.4.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: 1fb81a6b4ae8d6132faef03c4f809249303f4fd8c649b0848b3ad50739651373
4
- data.tar.gz: 36458e66b06668b2b7e2982463c9502ea198949b6b1ec8d8f88e3cc8d3fdd494
3
+ metadata.gz: 65b739aa23100b336f58f95cb7e4095888d3c1700f04d91d429b015b5a2cabd0
4
+ data.tar.gz: 484ec62657a1ed62f9598e064603086f377a9f7285bad489edbe0a6a5c2c8bc8
5
5
  SHA512:
6
- metadata.gz: 0caef0060a18b50b43248beeb00276513ee6be2d33c1e8818cc1293588cdb2844a7639e32886a0409dd00f93928bb8a7d5eda11ce1c3b814d8313d97c3a32388
7
- data.tar.gz: 8f0dd11b87b6e878cef827ccab72891840c4f6668b78d486e85dbbc0be7c3afcafd7fa1494b0ef653b6c6134d83f3b5898e75bb420a6f2061b8fe1fcb3ad8714
6
+ metadata.gz: bd7fe0c6568fe75068be352e44af560da13da579a9b55e0c46f8a4021f4146c2ecb4ab2305ac6e866d73afcd5343daceb172434e67192dba9d04a02b2c1b00b5
7
+ data.tar.gz: 8a936f14c6b301d717298d1499458f10985a054bcba840062e73a3d34ecae4c150f57dd87ecc37c302755826e92d3c6d648c63385d2b408f44acd76bbe662305
checksums.yaml.gz.sig CHANGED
Binary file
@@ -7,3 +7,8 @@ Layout/ConsistentBlankLineIndentation:
7
7
  Description: "Ensures that blank lines have the same indentation as the previous non-blank line."
8
8
  Enabled: true
9
9
  VersionAdded: "0.1.0"
10
+
11
+ Layout/BlockDelimiterSpacing:
12
+ Description: "Enforces consistent spacing before block delimiters."
13
+ Enabled: true
14
+ VersionAdded: "0.4.0"
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "rubocop"
7
+
8
+ module RuboCop
9
+ module Socketry
10
+ module Layout
11
+ # A RuboCop cop that enforces consistent spacing before block delimiters.
12
+ #
13
+ # This cop enforces the following style:
14
+ # - `foo {bar}` - space when method has no parentheses and is not chained
15
+ # - `foo(1, 2) {bar}` - space after closing paren for standalone methods
16
+ # - `array.each{|x| x*2}.reverse` - no space for method chains (even with parens)
17
+ class BlockDelimiterSpacing < RuboCop::Cop::Base
18
+ extend Cop::AutoCorrector
19
+
20
+ MSG_ADD_SPACE = "Add a space before the opening brace."
21
+ MSG_REMOVE_SPACE = "Remove space before the opening brace for method chains."
22
+
23
+ def on_block(node)
24
+ return unless node.braces?
25
+
26
+ send_node = node.send_node
27
+
28
+ # Priority: Check if it's part of a method chain first
29
+ # Method chains should never have space, even with parentheses
30
+ if part_of_method_chain?(node)
31
+ # array.each{|x| x*2}.reverse - no space
32
+ # obj.method(1, 2){|x| x}.other - also no space
33
+ check_no_space_before_brace(node, send_node)
34
+ elsif has_parentheses?(send_node)
35
+ # foo(1, 2) {bar} - space after ) for standalone methods
36
+ check_space_after_paren(node, send_node)
37
+ else
38
+ # foo {bar} - space for standalone methods without parens
39
+ check_space_before_brace(node, send_node)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ # Check if the block is part of a method chain (e.g., foo{}.bar or foo.bar{}.baz)
46
+ def part_of_method_chain?(block_node)
47
+ send_node = block_node.send_node
48
+ parent = block_node.parent
49
+
50
+ # Check if there's a method call after the block (foo{}.bar)
51
+ has_chained_method_after = parent&.send_type? && parent.receiver == block_node
52
+
53
+ # Check if the block's receiver exists (foo.bar{} or array.map{})
54
+ # Any method call with a receiver is part of a chain
55
+ has_receiver_before = send_node.receiver
56
+
57
+ has_chained_method_after || has_receiver_before
58
+ end
59
+
60
+ # Check if the method call has parentheses
61
+ def has_parentheses?(send_node)
62
+ send_node.parenthesized?
63
+ end
64
+
65
+ # Check that there's a space between closing paren and opening brace
66
+ def check_space_after_paren(block_node, send_node)
67
+ paren_end = send_node.loc.end
68
+ brace_begin = block_node.loc.begin
69
+
70
+ return unless paren_end && brace_begin
71
+
72
+ # Get the source between ) and {
73
+ space_range = Parser::Source::Range.new(
74
+ processed_source.buffer,
75
+ paren_end.end_pos,
76
+ brace_begin.begin_pos
77
+ )
78
+
79
+ space_between = space_range.source
80
+
81
+ # Should have exactly one space
82
+ return if space_between == " "
83
+
84
+ if space_between.empty?
85
+ add_offense(
86
+ brace_begin,
87
+ message: MSG_ADD_SPACE
88
+ ) do |corrector|
89
+ corrector.insert_before(brace_begin, " ")
90
+ end
91
+ elsif space_between.match?(/\A\s+\z/)
92
+ # Multiple spaces or tabs - replace with single space
93
+ add_offense(
94
+ space_range,
95
+ message: MSG_ADD_SPACE
96
+ ) do |corrector|
97
+ corrector.replace(space_range, " ")
98
+ end
99
+ end
100
+ end
101
+
102
+ # Check that there's no space before the opening brace
103
+ def check_no_space_before_brace(block_node, send_node)
104
+ brace_begin = block_node.loc.begin
105
+
106
+ # Find the position just before the brace
107
+ char_before_pos = brace_begin.begin_pos - 1
108
+
109
+ return if char_before_pos < 0
110
+
111
+ char_before = processed_source.buffer.source[char_before_pos]
112
+
113
+ # If there's a space before the brace, we need to remove it
114
+ return unless char_before == " "
115
+
116
+ # Don't remove space if it's after a closing paren (that case is handled separately)
117
+ if send_node.loc.end && send_node.loc.end.end_pos == char_before_pos + 1
118
+ return
119
+ end
120
+
121
+ # Find the extent of whitespace before the brace
122
+ start_pos = char_before_pos
123
+ while start_pos > 0 && processed_source.buffer.source[start_pos - 1] =~ /\s/
124
+ start_pos -= 1
125
+ end
126
+
127
+ space_range = Parser::Source::Range.new(
128
+ processed_source.buffer,
129
+ start_pos,
130
+ brace_begin.begin_pos
131
+ )
132
+
133
+ add_offense(
134
+ space_range,
135
+ message: MSG_REMOVE_SPACE
136
+ ) do |corrector|
137
+ corrector.remove(space_range)
138
+ end
139
+ end
140
+
141
+ # Check that there's a space before the opening brace (for standalone methods)
142
+ def check_space_before_brace(block_node, send_node)
143
+ brace_begin = block_node.loc.begin
144
+
145
+ # Find the position just before the brace
146
+ char_before_pos = brace_begin.begin_pos - 1
147
+
148
+ return if char_before_pos < 0
149
+
150
+ char_before = processed_source.buffer.source[char_before_pos]
151
+
152
+ # If there's already a space, we're good
153
+ return if char_before == " "
154
+
155
+ # Otherwise, we need to add a space
156
+ add_offense(
157
+ brace_begin,
158
+ message: MSG_ADD_SPACE
159
+ ) do |corrector|
160
+ corrector.insert_before(brace_begin, " ")
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module RuboCop
7
7
  module Socketry
8
- VERSION = "0.3.0"
8
+ VERSION = "0.4.0"
9
9
  end
10
10
  end
@@ -6,6 +6,7 @@
6
6
  require_relative "socketry/version"
7
7
  require_relative "socketry/plugin"
8
8
  require_relative "socketry/layout/consistent_blank_line_indentation"
9
+ require_relative "socketry/layout/block_delimiter_spacing"
9
10
 
10
11
  # @namespace
11
12
  module RuboCop
data/readme.md CHANGED
@@ -27,9 +27,13 @@ Layout/ConsistentBlankLineIndentation:
27
27
 
28
28
  Please see the [project releases](https://socketry.github.io/rubocop-socketry/releases/index) for all releases.
29
29
 
30
+ ### v0.4.0
31
+
32
+ - Added `Layout/BlockDelimiterSpacing` cop to enforce consistent spacing before block delimiters.
33
+
30
34
  ### v0.1.0
31
35
 
32
- - Initial implementaiton of `Layout/ConsistentBlankLineIndentation`.
36
+ - Initial implementation of `Layout/ConsistentBlankLineIndentation`.
33
37
 
34
38
  ## Contributing
35
39
 
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.4.0
4
+
5
+ - Added `Layout/BlockDelimiterSpacing` cop to enforce consistent spacing before block delimiters.
6
+
3
7
  ## v0.1.0
4
8
 
5
- - Initial implementaiton of `Layout/ConsistentBlankLineIndentation`.
9
+ - Initial implementation of `Layout/ConsistentBlankLineIndentation`.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-socketry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -73,6 +73,7 @@ files:
73
73
  - agent.md
74
74
  - lib/rubocop/socketry.rb
75
75
  - lib/rubocop/socketry/config.yaml
76
+ - lib/rubocop/socketry/layout/block_delimiter_spacing.rb
76
77
  - lib/rubocop/socketry/layout/consistent_blank_line_indentation.rb
77
78
  - lib/rubocop/socketry/plugin.rb
78
79
  - lib/rubocop/socketry/version.rb
metadata.gz.sig CHANGED
Binary file