rubocop-mangrove 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c0b629613576ae8b27696cb189bffaedd892ee5f428c3aaa31eeb2da988318ee
4
+ data.tar.gz: 26f618e9b5b17794dc0c1b3fd6b85619ce29b9699efb4cceb57d675cc62e1fc2
5
+ SHA512:
6
+ metadata.gz: 8d5ff48c0c8d3a8ae9156820033c6a75b2d12dcb0c4803f8887dde7a263cf5b6b5bbffcd0f918ef7db1bfc271c6f65210990668e21c2b0ff784c46c646175723
7
+ data.tar.gz: 277aea0678c9dd5ac14cd2653544600f0fd93a7856b433cf7fc6b047e1c3a1983e96a95b76cefc49b2abfa00fdc60fd18c74e8d92dda9cac6fe3c4030e1ab67d
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,58 @@
1
+ Naming/FileName:
2
+ Exclude:
3
+ - lib/rubocop-mangrove.rb
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.2
7
+
8
+ Layout/FirstArrayElementIndentation:
9
+ EnforcedStyle: consistent
10
+
11
+ Layout/LineLength:
12
+ Enabled: false
13
+
14
+ Layout/MultilineMethodCallIndentation:
15
+ EnforcedStyle: indented
16
+
17
+ Metrics/AbcSize:
18
+ Enabled: false
19
+
20
+ Metrics/BlockLength:
21
+ Enabled: false
22
+
23
+ Metrics/ClassLength:
24
+ Enabled: false
25
+
26
+ Metrics/MethodLength:
27
+ Enabled: false
28
+
29
+ Metrics/ModuleLength:
30
+ Enabled: false
31
+
32
+ Naming/VariableNumber:
33
+ EnforcedStyle: snake_case
34
+
35
+ Style/BlockDelimiters:
36
+ EnforcedStyle: always_braces
37
+ AllowedMethods:
38
+ - describe
39
+ - context
40
+ - it
41
+
42
+ Style/Documentation:
43
+ Enabled: false
44
+
45
+ Style/GuardClause:
46
+ Enabled: false
47
+
48
+ Style/IfUnlessModifier:
49
+ Enabled: false
50
+
51
+ Style/StringLiterals:
52
+ Enabled: true
53
+ EnforcedStyle: double_quotes
54
+
55
+ Style/StringLiteralsInInterpolation:
56
+ Enabled: true
57
+ EnforcedStyle: double_quotes
58
+
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ ```
2
+ git config core.hooksPath hooks
3
+ bundle exec rspec -f d
4
+ bundle exec rubocop -DESP
5
+ bundle exec srb typecheck
6
+ bundle exec ordinare --check
7
+ bundle exec ruboclean
8
+ bundle exec yardoc -o docs/ --plugin yard-sorbet
9
+ rake build
10
+ rake release
11
+ ```
12
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ task(:check) {
7
+ system("bundle exec ordinare --check") &&
8
+ system("bundle exec rubocop -DESP") &&
9
+ system("bundle exec rspec -f d")
10
+ }
11
+
12
+ task default: :check
@@ -0,0 +1,6 @@
1
+ # Write it!
2
+
3
+ Mangrove/UnhandledUnwrap:
4
+ Description: 'Unhandled calling of #unwrap!'
5
+ Enabled: true
6
+ VersionAdded: "0.1.0"
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parser/current"
4
+ require "unparser"
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Mangrove
9
+ class UnhandledUnwrap < Base
10
+ extend ::RuboCop::Cop::AutoCorrector
11
+
12
+ MSG = "unwrap! is used inside method that is not rescuing ControlSignal"
13
+
14
+ def on_def(node)
15
+ exam(node)
16
+ end
17
+
18
+ def on_defs(node)
19
+ exam(node)
20
+ end
21
+
22
+ # def on_block(node)
23
+ # examinate(node)
24
+ # end
25
+
26
+ private
27
+
28
+ def_node_matcher :calling_unwrap?, <<~PATTERN
29
+ `(send ... :unwrap!)
30
+ PATTERN
31
+
32
+ def_node_matcher :rescuing_signal?, <<~PATTERN
33
+ (rescue <(resbody <(array <(const ... :ControlSignal) ...>) ...>) ...>)
34
+ PATTERN
35
+
36
+ def_node_matcher :rescuing_signal_with_ensure?, <<~PATTERN
37
+ (ensure <(rescue <(resbody <(array <(const ... :ControlSignal) ...>) ...>) ...>) ...>)
38
+ PATTERN
39
+
40
+ def exam(node)
41
+ return unless calling_unwrap?(node)
42
+
43
+ rescuing_control_signal = node.children.any? { |child_node|
44
+ rescuing_signal?(child_node) || rescuing_signal_with_ensure?(child_node)
45
+ }
46
+
47
+ return if rescuing_control_signal
48
+
49
+ add_offense(node) { |corrector|
50
+ source = node.source
51
+ ast = ::Parser::CurrentRuby.parse(source)
52
+ source_buffer = ::Parser::Source::Buffer.new("", source: node.source)
53
+ rewriter = ::RuboCop::Cop::Mangrove::UnhandledUnwrap::Rewriter.new
54
+ corrector.replace(node, rewriter.rewrite(source_buffer, ast))
55
+ }
56
+ end
57
+
58
+ class Rewriter < Parser::TreeRewriter
59
+ def on_def(node)
60
+ indent = node.location.expression.begin.column
61
+ code = ::Unparser.unparse(with_rescue(node))
62
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
63
+ replace(node.location.expression, indented_code)
64
+ end
65
+
66
+ def on_defs(node)
67
+ indent = node.location.expression.begin.column
68
+ code = ::Unparser.unparse(with_rescue(node))
69
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
70
+ replace(node.location.expression, indented_code)
71
+ end
72
+
73
+ def on_block(node)
74
+ indent = node.location.expression.begin.column
75
+ code = ::Unparser.unparse(with_rescue(node))
76
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
77
+ replace(node.location.expression, indented_code)
78
+ end
79
+
80
+ private
81
+
82
+ def rescue_node(body)
83
+ ::Parser::AST::Node.new(:rescue, [
84
+ body,
85
+ nil
86
+ ])
87
+ end
88
+
89
+ def add_rescue_node(parent)
90
+ children = parent.children.dup
91
+ # nilの場合はblockをこちらで包む必要がある
92
+ # nilではない場合はすでに包まれているのでこちらで包む必要はない
93
+ method_body_index = children.length - 1
94
+ method_body = children[method_body_index]
95
+
96
+ children[method_body_index] = rescue_node(method_body)
97
+ parent.updated(nil, children)
98
+ end
99
+
100
+ def use_rescue_node(parent)
101
+ children = parent.children.dup
102
+
103
+ rescue_index = children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
104
+
105
+ rescue_node_on_ast = children[rescue_index]
106
+ updated_rescue_node_on_ast = insert_rescue_body_node(rescue_node_on_ast)
107
+ children[rescue_index] = updated_rescue_node_on_ast
108
+
109
+ parent.updated(nil, children)
110
+ end
111
+
112
+ def insert_rescue_body_node(rescue_node)
113
+ rescue_node_children = rescue_node.children.dup
114
+ rescue_body_node_index = rescue_node_children.find_index { _1.respond_to?(:type) && _1.type == :resbody }
115
+
116
+ # when rescue is newly inserted
117
+ rescue_body_node_index = rescue_node_children.length - 1 if rescue_body_node_index.nil?
118
+
119
+ rescue_node_children.insert(rescue_body_node_index, rescue_body_node)
120
+ rescue_node.updated(nil, rescue_node_children)
121
+ end
122
+
123
+ def use_ensure_node(ensure_node)
124
+ # ensureのchildrenの最後から2番目(最後のrescue)に追加する
125
+
126
+ ensure_node_children = ensure_node.children.dup
127
+
128
+ rescue_index = ensure_node_children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
129
+
130
+ ensure_node = add_rescue_node(ensure_node) if rescue_index.nil?
131
+
132
+ use_rescue_node(ensure_node)
133
+ end
134
+
135
+ def with_rescue(parent)
136
+ children = parent.children.dup
137
+ ensure_index = children.find_index { _1.respond_to?(:type) && _1.type == :ensure }
138
+
139
+ if ensure_index.nil?
140
+ rescue_index = children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
141
+
142
+ parent = add_rescue_node(parent) if rescue_index.nil?
143
+
144
+ use_rescue_node(parent)
145
+ else
146
+ updated_ensure_node = use_ensure_node(children[ensure_index])
147
+ children[ensure_index] = updated_ensure_node
148
+ parent.updated(nil, children)
149
+ end
150
+ end
151
+
152
+ def rescue_body_node
153
+ ::Parser::AST::Node.new(:resbody, [
154
+ ::Parser::AST::Node.new(:array, [
155
+ ::Parser::AST::Node.new(:const, [
156
+ ::Parser::AST::Node.new(:const, [
157
+ ::Parser::AST::Node.new(:const, [
158
+ ::Parser::AST::Node.new(:cbase),
159
+ :Mangrove
160
+ ]),
161
+ :ControlFlow
162
+ ]),
163
+ :ControlSignal
164
+ ])
165
+ ]),
166
+ ::Parser::AST::Node.new(:lvasgn, [:e]),
167
+ ::Parser::AST::Node.new(:send, [
168
+ ::Parser::AST::Node.new(:const, [
169
+ ::Parser::AST::Node.new(:const, [
170
+ ::Parser::AST::Node.new(:const, [
171
+ ::Parser::AST::Node.new(:cbase),
172
+ :Mangrove
173
+ ]),
174
+ :Result
175
+ ]),
176
+ :Err
177
+ ]),
178
+ :new,
179
+ ::Parser::AST::Node.new(:send, [
180
+ ::Parser::AST::Node.new(
181
+ :lvar, [:e]
182
+ ),
183
+ :inner_value
184
+ ])
185
+ ])
186
+ ])
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mangrove/unhandled_unwrap"
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The original code is from https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
4
+ # See https://github.com/rubocop/rubocop-rspec/blob/master/MIT-LICENSE.md
5
+ module RuboCop
6
+ module Mangrove
7
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
8
+ # bit of our configuration.
9
+ module Inject
10
+ def self.defaults!
11
+ path = CONFIG_DEFAULT.to_s
12
+ hash = ConfigLoader.send(:load_yaml_configuration, path)
13
+ config = Config.new(hash, path).tap(&:make_excludes_absolute)
14
+ puts "configuration from #{path}" if ConfigLoader.debug?
15
+ config = ConfigLoader.merge_with_default(config, path)
16
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Mangrove
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mangrove/version"
4
+
5
+ module RuboCop
6
+ module Mangrove
7
+ class Error < StandardError; end
8
+ # Your code goes here...
9
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
10
+ CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
11
+ CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
12
+
13
+ private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ require_relative "rubocop/mangrove"
6
+ require_relative "rubocop/mangrove/version"
7
+ require_relative "rubocop/mangrove/inject"
8
+
9
+ RuboCop::Mangrove::Inject.defaults!
10
+
11
+ require_relative "rubocop/cop/mangrove_cops"
@@ -0,0 +1,6 @@
1
+ module Rubocop
2
+ module Mangrove
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-mangrove
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kazuma Murata
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-09-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
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: unparser
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Type Utility for Ruby.
56
+ email:
57
+ - kazzix14@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rspec"
63
+ - ".rubocop.yml"
64
+ - README.md
65
+ - Rakefile
66
+ - config/default.yml
67
+ - lib/rubocop-mangrove.rb
68
+ - lib/rubocop/cop/mangrove/unhandled_unwrap.rb
69
+ - lib/rubocop/cop/mangrove_cops.rb
70
+ - lib/rubocop/mangrove.rb
71
+ - lib/rubocop/mangrove/inject.rb
72
+ - lib/rubocop/mangrove/version.rb
73
+ - sig/rubocop/mangrove.rbs
74
+ homepage: https://github.com/kazzix14/mangrove
75
+ licenses: []
76
+ metadata:
77
+ homepage_uri: https://github.com/kazzix14/mangrove
78
+ source_code_uri: https://github.com/kazzix14/rubocop-mangrove
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 3.2.0
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 3.4.18
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Type Utility for Ruby.
98
+ test_files: []