rubocop-aaa 0.0.1 → 0.0.2

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: 88bb8909e976646d38fa8d819807e978ad8e2db91592ee69fe1e8f848dc13692
4
- data.tar.gz: 84ae0416f47272ccdcf38fc48b55c060106b96cff1b5828075da5aaf4886140a
3
+ metadata.gz: e6004f573b4c0674b182fb676a0736cb40e9bbe92118c0c77e50ffb9c4f3c035
4
+ data.tar.gz: 0aa8a6cb45918ee3a50aa68bcaea9e97808c5166386c271a646b0749ea4654e9
5
5
  SHA512:
6
- metadata.gz: 5eea4bdadc3cbc5755f3c40d300dc188df672d20032c2781fd832d65c5fe795f020e1834c288acf271492450933d7f5ff9938b2bcbce28ab9e51749a60a979a3
7
- data.tar.gz: 6a8e83b998e8e385064ee34311bd280ea9c6ae251a2ed4a9ad081790e564233283052ae4221a4d163340a04894d14001af6d8ef82cfb1d517b166802f9be2b80
6
+ metadata.gz: 8efaad9641a3826f7a343d06d0b3b489e4046e572831923015c80a868f146006e519ce82e30126515b6c0fb98c6b2bc0d0494803d2c2358e28f7d5cc491a0d72
7
+ data.tar.gz: f1ed6f5e2ba4596918841a93c4d081ef20109e18335da6bb00900e21132addedb03bf62fb950302da25e09ab1b3a2a3c82f1d6927e790fb97830b31e22159fb3
data/README.md CHANGED
@@ -83,6 +83,12 @@ AAA/Pattern:
83
83
  assert: [検証, 確認]
84
84
  ```
85
85
 
86
+ ## Auto-correct
87
+
88
+ When **all three** section comments are missing, `rubocop -a` (or `rubocop --autocorrect`) inserts a `# arrange` / `# act` / `# assert` template at the top of the block. You then move each comment above the code that belongs to it.
89
+
90
+ Other cases — one or two sections missing, wrong order, empty section — are reported with explicit hints in the offense message but are not auto-corrected, because the correct insertion point depends on the test's intent.
91
+
86
92
  ## License
87
93
 
88
94
  MIT
@@ -2,11 +2,16 @@ module RuboCop
2
2
  module Cop
3
3
  module AAA
4
4
  class Pattern < Base
5
+ extend AutoCorrector
6
+
5
7
  SECTIONS = %i[arrange act assert].freeze
6
8
 
7
- MSG_MISSING = 'Missing "%<section>s" comment in test block.'.freeze
8
- MSG_ORDER = 'AAA comments must appear in order: arrange -> act -> assert.'.freeze
9
- MSG_EMPTY = 'Section "%<section>s" has no statements.'.freeze
9
+ MSG_MISSING_ALL = 'Missing arrange/act/assert section comments. Insert # %<arrange>s, # %<act>s, and # %<assert>s to mark each section (auto-correct scaffolds a template at the top of the block).'.freeze
10
+ MSG_MISSING_ARRANGE = 'Missing "arrange" comment. Insert # %<label>s before the code that sets up test state.'.freeze
11
+ MSG_MISSING_ACT = 'Missing "act" comment. Insert # %<label>s before the code that triggers the behavior under test.'.freeze
12
+ MSG_MISSING_ASSERT = 'Missing "assert" comment. Insert # %<label>s before the code that verifies the result.'.freeze
13
+ MSG_ORDER = 'AAA comments must appear in order: arrange -> act -> assert. Found "%<found>s" after "%<previous>s".'.freeze
14
+ MSG_EMPTY = 'Section "%<section>s" has no statements. Add code between # %<section>s and the next section, or remove the # %<section>s comment.'.freeze
10
15
 
11
16
  DEFAULT_LABELS = {
12
17
  'arrange' => %w[arrange],
@@ -23,19 +28,27 @@ module RuboCop
23
28
  seen = {}
24
29
  found.each { |section, comment| seen[section] ||= comment }
25
30
 
26
- SECTIONS.each do |section|
27
- unless seen[section]
28
- add_offense(node, message: format(MSG_MISSING, section: section))
29
- return
30
- end
31
+ missing = SECTIONS.reject { |s| seen[s] }
32
+
33
+ if missing.size == SECTIONS.size
34
+ report_all_missing(node)
35
+ return
36
+ end
37
+
38
+ unless missing.empty?
39
+ missing.each { |s| report_missing_one(node, s) }
40
+ return
31
41
  end
32
42
 
33
43
  ordered = SECTIONS.map { |s| seen[s] }
34
44
  (1...ordered.size).each do |i|
35
- if ordered[i].loc.expression.begin_pos < ordered[i - 1].loc.expression.begin_pos
36
- add_offense(ordered[i], message: MSG_ORDER)
37
- return
38
- end
45
+ next unless ordered[i].loc.expression.begin_pos < ordered[i - 1].loc.expression.begin_pos
46
+
47
+ add_offense(
48
+ ordered[i],
49
+ message: format(MSG_ORDER, found: SECTIONS[i], previous: SECTIONS[i - 1])
50
+ )
51
+ return
39
52
  end
40
53
 
41
54
  return if allow_empty_section?
@@ -46,6 +59,64 @@ module RuboCop
46
59
 
47
60
  private
48
61
 
62
+ def report_all_missing(node)
63
+ labels_for_template = {
64
+ arrange: preferred_label('arrange'),
65
+ act: preferred_label('act'),
66
+ assert: preferred_label('assert')
67
+ }
68
+ message = format(MSG_MISSING_ALL, labels_for_template)
69
+
70
+ add_offense(node, message: message) do |corrector|
71
+ insert_template(corrector, node, labels_for_template)
72
+ end
73
+ end
74
+
75
+ def report_missing_one(node, section)
76
+ message_template = {
77
+ arrange: MSG_MISSING_ARRANGE,
78
+ act: MSG_MISSING_ACT,
79
+ assert: MSG_MISSING_ASSERT
80
+ }[section]
81
+ # Anchor each offense to a distinct location so RuboCop does not dedupe
82
+ # them when multiple sections are missing.
83
+ location = {
84
+ arrange: node.send_node.loc.expression,
85
+ act: node.loc.begin,
86
+ assert: node.loc.end
87
+ }[section]
88
+ add_offense(location, message: format(message_template, label: preferred_label(section.to_s)))
89
+ end
90
+
91
+ def insert_template(corrector, node, labels_for_template)
92
+ source = processed_source.raw_source
93
+ block_start = node.loc.begin.end_pos # position right after "do" / "{"
94
+ indent = detect_indent(node, block_start)
95
+
96
+ template = +"\n#{indent}# #{labels_for_template[:arrange]}"
97
+ template << "\n#{indent}# #{labels_for_template[:act]}"
98
+ template << "\n#{indent}# #{labels_for_template[:assert]}"
99
+
100
+ corrector.insert_after(node.loc.begin, template)
101
+ end
102
+
103
+ def detect_indent(node, block_start)
104
+ source = processed_source.raw_source
105
+ # Prefer the indentation of the first line of body content.
106
+ tail = source[block_start..-1] || ''
107
+ tail.each_line do |line|
108
+ next if line.strip.empty?
109
+
110
+ stripped = line.sub(/^\n/, '')
111
+ match = stripped.match(/\A([ \t]*)\S/)
112
+ return match[1] if match
113
+ end
114
+ # Fallback: use the block's own indent + 2 spaces.
115
+ block_line = source[0...node.loc.expression.begin_pos].rpartition("\n").last
116
+ lead = block_line.match(/\A[ \t]*/)[0]
117
+ "#{lead} "
118
+ end
119
+
49
120
  def collect_sections(node)
50
121
  block_range = node.loc.expression
51
122
  processed_source.comments.each_with_object([]) do |comment, acc|
@@ -98,6 +169,10 @@ module RuboCop
98
169
  comment.text.sub(/\A#\s*/, '').strip
99
170
  end
100
171
 
172
+ def preferred_label(section)
173
+ (labels[section] && labels[section].first) || section
174
+ end
175
+
101
176
  def test_method?(name)
102
177
  test_functions.include?(name.to_s)
103
178
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-aaa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - babu-ch