rubocop-mangrove 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []