rubocop-canon 0.1.0 → 0.2.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: ec9b67b96a586164140535f5e47bae25d02443a7f37094b0dd6fe8c2256d7d57
4
- data.tar.gz: 79bebd07f1aec3b30061849a9c0166640eef0728756dc6eb477d47e17c5a9c69
3
+ metadata.gz: bdf44fc516121d61d209401a8c2b58f4603ce3d3c7951ec9a232a4acc8cc5175
4
+ data.tar.gz: 7881f90e36d55ba4bc3a7cd940640827ab91973e53c13d494da72058ba837c43
5
5
  SHA512:
6
- metadata.gz: 49faab8220e3b5c1fe4004566a664c19051848136a628245e7e30da3e5b072fed9b349089681831cd5efac7052e40dd788986e9827ee16569617c26a304b541c
7
- data.tar.gz: d01f901f2b9748cf4617eb75a633930dd8c9049c1c45bd4c6379cce308ac1678f5fc41facb34a4d5da664b9ea1dbcfb5fbad15232eb90437921cf79f1fdea79b
6
+ metadata.gz: 9903f67032ee8161d257aee6f9a773def334c7537eb2e9f066ac0a90bf1fa3dabe21f96a9e7208575ead7baabbef0bb7013ad22502f8a76c2ebbd6a7487f5569
7
+ data.tar.gz: fcf0cd9d4304f5dee4bb21d73d914a58e8dc240c17f3d55dfedfca2a8ee766368437871a899dd76eb607f81ef616cb7c31fe7b6221d23119b9dba02ccf020c7b
data/README.md CHANGED
@@ -6,7 +6,10 @@ Deterministic RuboCop cops that reduce Ruby code to canonical form. Given any in
6
6
 
7
7
  | Cop | What it does |
8
8
  |-----|-------------|
9
+ | `Canon/BlockPhases` | A block body ends in one unbroken run of calls, opened by one blank line |
10
+ | `Canon/DeclarationGroups` | One blank line between declaration groups, none inside a group |
9
11
  | `Canon/KeywordShorthand` | `foo(bar: bar)` becomes `foo(bar:)` |
12
+ | `Canon/MethodBodyBlankLines` | One blank line around a method body's standalone calls, none anywhere else |
10
13
  | `Canon/SortHash` | `{b: 1, a: 2}` becomes `{a: 2, b: 1}` |
11
14
  | `Canon/SortKeywords` | `method(z: 1, a: 2)` becomes `method(a: 2, z: 1)` |
12
15
  | `Canon/SortMethodArguments` | `attr_reader :z, :a` becomes `attr_reader :a, :z` |
@@ -29,6 +32,32 @@ plugins:
29
32
 
30
33
  ## Configuration
31
34
 
35
+ The blank-line cops are driven by name lists:
36
+
37
+ ```yaml
38
+ Canon/BlockPhases:
39
+ Blocks: # only check blocks of these methods (required)
40
+ - it
41
+ TrailingMethods: # calls that make up the trailing phase (required)
42
+ - expect
43
+ MaxPhases: 3 # phases allowed before the trailing one
44
+
45
+ Canon/DeclarationGroups:
46
+ GroupedMethods: # method names that form one group
47
+ - [belongs_to, has_many, has_one]
48
+ - [validate, validates]
49
+
50
+ Canon/MethodBodyBlankLines:
51
+ SeparatedMethods: # calls that take a blank line beside them
52
+ - expose
53
+ - mail
54
+ - errors.add # dotted: matches a receiver and method together
55
+ ```
56
+
57
+ `Canon/BlockPhases` does nothing without both lists. `Canon/DeclarationGroups` treats every
58
+ method name as its own group until `GroupedMethods` merges them. `Canon/MethodBodyBlankLines`
59
+ only removes blank lines until `SeparatedMethods` says where they belong.
60
+
32
61
  `Canon/SortHash` and the three sort cops accept:
33
62
 
34
63
  ```yaml
@@ -49,7 +78,7 @@ Canon/SortMethodArguments:
49
78
  - delegate
50
79
  ```
51
80
 
52
- `Canon/SortKeywords` and `Canon/SortMethodArguments` are disabled by default. They require a `Methods` list to function.
81
+ Every cop is disabled by default. Enable the ones you want in your `.rubocop.yml`.
53
82
 
54
83
  ## License
55
84
 
data/config/default.yml CHANGED
@@ -1,11 +1,31 @@
1
+ Canon/BlockPhases:
2
+ Description: 'Separate a block body into phases, ending in a trailing run of calls.'
3
+ Enabled: false
4
+ VersionAdded: '0.2'
5
+ Blocks: []
6
+ MaxPhases: 3
7
+ TrailingMethods: []
8
+
9
+ Canon/DeclarationGroups:
10
+ Description: 'Separate declaration groups with one blank line and nothing inside a group.'
11
+ Enabled: false
12
+ VersionAdded: '0.2'
13
+ GroupedMethods: []
14
+
1
15
  Canon/KeywordShorthand:
2
16
  Description: 'Use Ruby 3.1+ keyword shorthand where a local variable matches the key name.'
3
- Enabled: true
17
+ Enabled: false
4
18
  VersionAdded: '0.1'
5
19
 
20
+ Canon/MethodBodyBlankLines:
21
+ Description: "One blank line around a method body's standalone calls, none anywhere else."
22
+ Enabled: false
23
+ VersionAdded: '0.2'
24
+ SeparatedMethods: []
25
+
6
26
  Canon/SortHash:
7
27
  Description: 'Sort hash keys alphabetically.'
8
- Enabled: true
28
+ Enabled: false
9
29
  VersionAdded: '0.1'
10
30
  ShorthandsFirst: false
11
31
  ExcludeMethods: []
@@ -25,5 +45,5 @@ Canon/SortMethodArguments:
25
45
 
26
46
  Canon/SortMethodDefinition:
27
47
  Description: 'Sort keyword arguments in method definitions alphabetically.'
28
- Enabled: true
48
+ Enabled: false
29
49
  VersionAdded: '0.1'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Canon
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Canon
6
+ # Shared mechanics for the cops that decide where a blank line belongs.
7
+ #
8
+ # A cop mixing this in supplies the decision — how many blank lines a
9
+ # pair of statements takes — and leaves the counting, the comment guard,
10
+ # the source ranges and the corrections here.
11
+ module BlankLineHelp
12
+ include RangeHelp
13
+
14
+ BLOCK_TYPES = %i[block numblock].freeze
15
+
16
+ private
17
+
18
+ def body_statements(node)
19
+ body = node.body
20
+ return [] if body.nil?
21
+ return body.children if body.begin_type?
22
+
23
+ [body]
24
+ end
25
+
26
+ def blank_lines_between(previous, following)
27
+ following.first_line - previous.last_line - 1
28
+ end
29
+
30
+ def comments_between?(previous, following)
31
+ processed_source.comments.any? do |comment|
32
+ comment.loc.line >= previous.last_line && comment.loc.line < following.first_line
33
+ end
34
+ end
35
+
36
+ def register_extra_blank_line(previous, message)
37
+ add_offense(blank_line_range(previous), message:) do |corrector|
38
+ corrector.remove(newline_range(previous))
39
+ end
40
+ end
41
+
42
+ def register_missing_blank_line(previous, following, message)
43
+ add_offense(first_line_range(following), message:) do |corrector|
44
+ corrector.insert_after(line_range(previous.last_line), "\n")
45
+ end
46
+ end
47
+
48
+ def call_chain(node)
49
+ chain = []
50
+ current = unwrap_block(node)
51
+
52
+ while current.respond_to?(:send_type?) && current.send_type?
53
+ chain.unshift(current.method_name.to_s)
54
+ current = unwrap_block(current.receiver)
55
+ end
56
+
57
+ chain
58
+ end
59
+
60
+ def unwrap_block(node)
61
+ return if node.nil?
62
+ return node.send_node if BLOCK_TYPES.include?(node.type)
63
+
64
+ node
65
+ end
66
+
67
+ def line_range(line)
68
+ processed_source.buffer.line_range(line)
69
+ end
70
+
71
+ def blank_line_range(previous)
72
+ line_range(previous.last_line + 1)
73
+ end
74
+
75
+ def newline_range(previous)
76
+ range_between(line_range(previous.last_line).end_pos, line_range(previous.last_line + 1).end_pos)
77
+ end
78
+
79
+ def first_line_range(node)
80
+ line_end = line_range(node.first_line).end_pos
81
+
82
+ range_between(node.source_range.begin_pos, [node.source_range.end_pos, line_end].min)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Canon
6
+ # Enforces the phase structure of a block body.
7
+ #
8
+ # A body checked by this cop ends in a *trailing phase*: the run of
9
+ # statements that call one of `TrailingMethods`. Exactly one blank line
10
+ # opens that run, no blank line splits it, and the statements before it
11
+ # form at most `MaxPhases` - 1 further phases.
12
+ #
13
+ # `Blocks` names the methods whose blocks are checked and
14
+ # `TrailingMethods` the calls that make up the trailing phase, matched
15
+ # against the leftmost call in a chain. Both are empty by default, so
16
+ # the cop does nothing until it is configured.
17
+ #
18
+ # @example Blocks: ['step'], TrailingMethods: ['report']
19
+ # # bad — no blank line opens the trailing phase
20
+ # step 'totals the order' do
21
+ # order = build_order
22
+ # report order.total
23
+ # end
24
+ #
25
+ # # bad — a blank line splits the trailing phase
26
+ # step 'totals the order' do
27
+ # order = build_order
28
+ #
29
+ # report order.total
30
+ #
31
+ # report order.currency
32
+ # end
33
+ #
34
+ # # good
35
+ # step 'totals the order' do
36
+ # order = build_order
37
+ #
38
+ # report order.total
39
+ # report order.currency
40
+ # end
41
+ class BlockPhases < Base
42
+ extend AutoCorrector
43
+ include BlankLineHelp
44
+
45
+ MSG_EXTRA = 'Remove the blank line inside the trailing phase.'
46
+ MSG_MISSING = 'Add a blank line before the trailing phase.'
47
+ MSG_TOO_MANY_PHASES = 'Use at most %<max_phases>d phases in a block body.'
48
+
49
+ def on_block(node)
50
+ return unless configured_block?(node)
51
+
52
+ check_phases(node)
53
+ end
54
+
55
+ alias on_numblock on_block
56
+
57
+ private
58
+
59
+ def check_phases(node)
60
+ statements = body_statements(node)
61
+ return if statements.size < 2
62
+
63
+ trailing_start = detect_trailing_start(statements)
64
+ return if trailing_start.nil?
65
+
66
+ check_trailing_phase(statements, trailing_start)
67
+ check_leading_phases(statements, trailing_start)
68
+ end
69
+
70
+ def check_trailing_phase(statements, trailing_start)
71
+ statements[trailing_start..].each_cons(2) do |previous, following|
72
+ next if comments_between?(previous, following)
73
+ next if blank_lines_between(previous, following) != 1
74
+
75
+ register_extra_blank_line(previous, MSG_EXTRA)
76
+ end
77
+ end
78
+
79
+ def check_leading_phases(statements, trailing_start)
80
+ return if trailing_start.zero?
81
+
82
+ check_separator(statements[trailing_start - 1], statements[trailing_start])
83
+ check_phase_count(statements[..(trailing_start - 1)])
84
+ end
85
+
86
+ def check_separator(previous, following)
87
+ return if comments_between?(previous, following)
88
+ return if blank_lines_between(previous, following) == 1
89
+
90
+ register_missing_blank_line(previous, following, MSG_MISSING)
91
+ end
92
+
93
+ def check_phase_count(statements)
94
+ separators = statements.each_cons(2).count do |previous, following|
95
+ blank_lines_between(previous, following).positive?
96
+ end
97
+ return if separators < max_phases - 1
98
+
99
+ add_offense(statements.first, message: format(MSG_TOO_MANY_PHASES, max_phases:))
100
+ end
101
+
102
+ def detect_trailing_start(statements)
103
+ trailing_start = nil
104
+
105
+ statements.each_with_index.reverse_each do |statement, index|
106
+ break unless trailing?(statement)
107
+
108
+ trailing_start = index
109
+ end
110
+
111
+ trailing_start
112
+ end
113
+
114
+ def configured_block?(node)
115
+ return false unless node.send_node.receiver.nil?
116
+
117
+ block_methods.include?(node.method_name.to_s)
118
+ end
119
+
120
+ def trailing?(node)
121
+ chain = call_chain(node)
122
+ return false if chain.empty?
123
+
124
+ trailing_methods.include?(chain.first)
125
+ end
126
+
127
+ def block_methods
128
+ @block_methods ||= Array(cop_config['Blocks']).map(&:to_s)
129
+ end
130
+
131
+ def trailing_methods
132
+ @trailing_methods ||= Array(cop_config['TrailingMethods']).map(&:to_s)
133
+ end
134
+
135
+ def max_phases
136
+ cop_config['MaxPhases']
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Canon
6
+ # Enforces blank lines between declaration groups in a class, module or
7
+ # DSL block body.
8
+ #
9
+ # Two declarations belong to the same group when they call the same
10
+ # method and both fit on one line. A declaration spanning several lines,
11
+ # and any block, is a group of one. Groups are separated by exactly one
12
+ # blank line; declarations inside a group are not separated at all.
13
+ #
14
+ # `GroupedMethods` merges method names that belong to one group.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # class Shift < ApplicationRecord
19
+ # belongs_to :service
20
+ #
21
+ # belongs_to :site
22
+ # validates :starts_at, presence: true
23
+ # end
24
+ #
25
+ # # good
26
+ # class Shift < ApplicationRecord
27
+ # belongs_to :service
28
+ # belongs_to :site
29
+ #
30
+ # validates :starts_at, presence: true
31
+ # end
32
+ #
33
+ # @example GroupedMethods: [[belongs_to, has_many]]
34
+ # # good
35
+ # class Shift < ApplicationRecord
36
+ # belongs_to :site
37
+ # has_many :shift_assignments, dependent: :destroy
38
+ #
39
+ # validates :starts_at, presence: true
40
+ # end
41
+ class DeclarationGroups < Base
42
+ extend AutoCorrector
43
+ include BlankLineHelp
44
+
45
+ MSG_EXTRA = 'Remove the blank line between declarations of the same group.'
46
+ MSG_MISSING = 'Add a blank line between declaration groups.'
47
+ ACCESS_MODIFIERS = %i[private protected public module_function private_class_method].freeze
48
+ DEFINITION_TYPES = %i[def defs].freeze
49
+ DECLARATION_TYPES = %i[casgn block numblock def defs].freeze
50
+
51
+ def on_class(node)
52
+ check_declarations(node)
53
+ end
54
+
55
+ def on_module(node)
56
+ check_declarations(node)
57
+ end
58
+
59
+ def on_block(node)
60
+ return unless declaration_context?(node)
61
+
62
+ check_declarations(node)
63
+ end
64
+
65
+ alias on_numblock on_block
66
+
67
+ private
68
+
69
+ def check_declarations(node)
70
+ statements = body_statements(node)
71
+ return if statements.size < 2
72
+ return unless statements.all? { |statement| declaration?(statement) }
73
+
74
+ statements.each_cons(2) do |previous, following|
75
+ next if definitions?(previous, following)
76
+ next if access_modifier?(previous)
77
+ next if access_modifier?(following)
78
+
79
+ check_gap(previous, following, expected_blank_lines(previous, following))
80
+ end
81
+ end
82
+
83
+ def check_gap(previous, following, expected)
84
+ return if comments_between?(previous, following)
85
+
86
+ blank_lines = blank_lines_between(previous, following)
87
+ return if blank_lines == expected
88
+ return if blank_lines > 1
89
+
90
+ return register_extra_blank_line(previous, MSG_EXTRA) if expected.zero?
91
+
92
+ register_missing_blank_line(previous, following, MSG_MISSING)
93
+ end
94
+
95
+ def expected_blank_lines(previous, following)
96
+ return 0 if group_key(previous) == group_key(following)
97
+
98
+ 1
99
+ end
100
+
101
+ def group_key(node)
102
+ return node.object_id if multiline?(node)
103
+ return :constant if node.casgn_type?
104
+ return node.object_id unless node.send_type?
105
+
106
+ grouped_key(node.method_name)
107
+ end
108
+
109
+ def grouped_key(method_name)
110
+ name = method_name.to_s
111
+ group_index = grouped_methods.index { |group| group.include?(name) }
112
+ return name if group_index.nil?
113
+
114
+ group_index
115
+ end
116
+
117
+ def declaration_context?(node)
118
+ enclosing = node.each_ancestor(:def, :defs, :class, :module).first
119
+ return false if enclosing.nil?
120
+ return true if enclosing.class_type?
121
+
122
+ enclosing.module_type?
123
+ end
124
+
125
+ def declaration?(node)
126
+ return true if DECLARATION_TYPES.include?(node.type)
127
+
128
+ node.send_type? && node.receiver.nil?
129
+ end
130
+
131
+ def definitions?(previous, following)
132
+ DEFINITION_TYPES.include?(previous.type) && DEFINITION_TYPES.include?(following.type)
133
+ end
134
+
135
+ def access_modifier?(node)
136
+ return false unless node.send_type?
137
+ return false unless node.arguments.empty?
138
+
139
+ ACCESS_MODIFIERS.include?(node.method_name)
140
+ end
141
+
142
+ def multiline?(node)
143
+ node.first_line != node.last_line
144
+ end
145
+
146
+ def grouped_methods
147
+ @grouped_methods ||= Array(cop_config['GroupedMethods']).map { |group| Array(group).map(&:to_s) }
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Canon
6
+ # Enforces blank lines around a method body's standalone calls and
7
+ # nowhere else.
8
+ #
9
+ # `SeparatedMethods` names the calls that stand on their own —
10
+ # `authorize!`, `expose`, `mail`. Each takes exactly one blank line
11
+ # between it and any statement next to it. Every other pair of
12
+ # statements takes none, because a blank line there marks a step that
13
+ # wants a name: extract a method instead.
14
+ #
15
+ # The list is empty by default, so the cop only removes until it is
16
+ # configured.
17
+ #
18
+ # The position after a guard clause belongs to
19
+ # `Layout/EmptyLineAfterGuardClause`, so this cop leaves it alone.
20
+ #
21
+ # An entry matches a method name anywhere in the call chain. Write it
22
+ # dotted — `errors.add` — to match a receiver and method together, so
23
+ # `coverage_request.errors.add(...)` matches and a bare `add` does not.
24
+ #
25
+ # @example SeparatedMethods: ['authorize!', 'expose']
26
+ # # bad
27
+ # def index
28
+ # authorize!
29
+ # shift = find_shift
30
+ # employees = Employee.for_shift(shift)
31
+ # expose employees
32
+ # end
33
+ #
34
+ # # good
35
+ # def index
36
+ # authorize!
37
+ #
38
+ # shift = find_shift
39
+ # employees = Employee.for_shift(shift)
40
+ #
41
+ # expose employees
42
+ # end
43
+ #
44
+ # # good — no standalone call, so no blank line
45
+ # def reset
46
+ # Current.session = nil
47
+ # Current.account = nil
48
+ # end
49
+ #
50
+ # # good — the guard clause owns its own blank line
51
+ # def total
52
+ # items = order.items
53
+ # return 0 if items.empty?
54
+ #
55
+ # items.sum(&:amount)
56
+ # end
57
+ class MethodBodyBlankLines < Base
58
+ extend AutoCorrector
59
+ include BlankLineHelp
60
+
61
+ MSG_EXTRA = 'Remove the blank line inside the method body.'
62
+ MSG_MISSING = 'Add a blank line around the standalone call.'
63
+ JUMP_METHODS = %i[raise fail throw].freeze
64
+
65
+ def on_def(node)
66
+ check_method_body(node)
67
+ end
68
+
69
+ def on_defs(node)
70
+ check_method_body(node)
71
+ end
72
+
73
+ private
74
+
75
+ def check_method_body(node)
76
+ statements = body_statements(node)
77
+ return if statements.size < 2
78
+
79
+ statements.each_cons(2) do |previous, following|
80
+ next if guard?(previous)
81
+
82
+ check_gap(previous, following, expected_blank_lines(previous, following))
83
+ end
84
+ end
85
+
86
+ def check_gap(previous, following, expected)
87
+ return if comments_between?(previous, following)
88
+
89
+ blank_lines = blank_lines_between(previous, following)
90
+ return if blank_lines == expected
91
+ return if blank_lines > 1
92
+
93
+ return register_extra_blank_line(previous, MSG_EXTRA) if expected.zero?
94
+
95
+ register_missing_blank_line(previous, following, MSG_MISSING)
96
+ end
97
+
98
+ def expected_blank_lines(previous, following)
99
+ return 1 if separated?(previous)
100
+ return 1 if separated?(following)
101
+
102
+ 0
103
+ end
104
+
105
+ def separated?(node)
106
+ chain = call_chain(node)
107
+ return false if chain.empty?
108
+
109
+ separated_methods.any? { |name| matches_chain?(chain, name) }
110
+ end
111
+
112
+ def matches_chain?(chain, name)
113
+ return chain.include?(name) unless name.include?('.')
114
+
115
+ chain.each_cons(2).any? { |pair| pair.join('.') == name }
116
+ end
117
+
118
+ def guard?(node)
119
+ return true if jump?(node)
120
+ return false unless node.if_type?
121
+ return false unless node.modifier_form?
122
+ return true if jump?(node.if_branch)
123
+
124
+ jump?(node.else_branch)
125
+ end
126
+
127
+ def jump?(node)
128
+ return false if node.nil?
129
+ return true if node.return_type?
130
+ return true if node.break_type?
131
+ return true if node.next_type?
132
+
133
+ node.send_type? && JUMP_METHODS.include?(node.method_name)
134
+ end
135
+
136
+ def separated_methods
137
+ @separated_methods ||= Array(cop_config['SeparatedMethods']).map(&:to_s)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
data/lib/rubocop-canon.rb CHANGED
@@ -3,7 +3,11 @@
3
3
  require 'rubocop'
4
4
  require_relative 'rubocop/canon/version'
5
5
  require_relative 'rubocop/canon/plugin'
6
+ require_relative 'rubocop/cop/canon/blank_line_help'
7
+ require_relative 'rubocop/cop/canon/block_phases'
8
+ require_relative 'rubocop/cop/canon/declaration_groups'
6
9
  require_relative 'rubocop/cop/canon/keyword_shorthand'
10
+ require_relative 'rubocop/cop/canon/method_body_blank_lines'
7
11
  require_relative 'rubocop/cop/canon/sort_hash'
8
12
  require_relative 'rubocop/cop/canon/sort_keywords'
9
13
  require_relative 'rubocop/cop/canon/sort_method_arguments'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - skiftle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-02-24 00:00:00.000000000 Z
11
+ date: 2026-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lefthook
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: lint_roller
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -56,7 +70,11 @@ files:
56
70
  - lib/rubocop-canon.rb
57
71
  - lib/rubocop/canon/plugin.rb
58
72
  - lib/rubocop/canon/version.rb
73
+ - lib/rubocop/cop/canon/blank_line_help.rb
74
+ - lib/rubocop/cop/canon/block_phases.rb
75
+ - lib/rubocop/cop/canon/declaration_groups.rb
59
76
  - lib/rubocop/cop/canon/keyword_shorthand.rb
77
+ - lib/rubocop/cop/canon/method_body_blank_lines.rb
60
78
  - lib/rubocop/cop/canon/sort_hash.rb
61
79
  - lib/rubocop/cop/canon/sort_keywords.rb
62
80
  - lib/rubocop/cop/canon/sort_method_arguments.rb
@@ -84,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
102
  - !ruby/object:Gem::Version
85
103
  version: '0'
86
104
  requirements: []
87
- rubygems_version: 3.4.1
105
+ rubygems_version: 3.4.19
88
106
  signing_key:
89
107
  specification_version: 4
90
108
  summary: Deterministic RuboCop cops for canonical Ruby form