rubocop-rbs 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: 8d4c9bb32e6323c9c18f2b096da62d0e22e18be953d63aaa5604a2dd08861af7
4
+ data.tar.gz: 9b593cc7039f03b3cc07635fd0b25a465d404289decabe459befe45c1431efa5
5
+ SHA512:
6
+ metadata.gz: 5f8b812d5aa182a68e3ca9e4da6cc0e48df67b43851f32f0b740a3d1e29c0095b0c6f4d949374c0ff195e8019c7014bcf9b7add13a76473d1b5f5963decd8a13
7
+ data.tar.gz: 6ffd5e997d7995e223cf9de22b0f56b29b4de840965e84881ac00140f0095c818d6391e42e596508051d19c8a3c24882b040516fc5fd38d0384fd2ea8a6a94b6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Mattia Roccoberton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # RuboCop RBS
2
+
3
+ RucoCop extension that check RBS signatures.
4
+
5
+ > DISCLAIMER: this extension is an ALPHA version, it could be not 100% stable
6
+
7
+ Check for:
8
+ - invalid RBS files;
9
+ - missing RBS method signatures;
10
+ - mismatching RBS method signatures arguments.
11
+
12
+ Please ⭐ if you like it.
13
+
14
+ **Know limitations**: some IDEs don't update the RBS cops offenses in real-time when a change is applied because only the .rb files are actively monitored.
15
+
16
+ ## Install
17
+
18
+ - Add to your Gemfile: `gem 'rubocop-rbs'` (and execute bundle)
19
+
20
+ ## Usage
21
+
22
+ - Execute `rubocop`
23
+
24
+ To disable the cop:
25
+
26
+ ```yml
27
+ Rbs/MethodSignature:
28
+ Enabled: false
29
+ ```
30
+
31
+ ## Do you like it? Star it!
32
+
33
+ If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
34
+
35
+ Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
36
+
37
+ ## Contributors
38
+
39
+ - [Mattia Roccoberton](https://blocknot.es/): author
40
+
41
+ ## License
42
+
43
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
File without changes
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rbs
6
+ # Check for:
7
+ # - invalid RBS files;
8
+ # - missing RBS method signatures;
9
+ # - mismatching RBS method signatures arguments.
10
+ class MethodSignature < Cop
11
+ MSG = 'signature mismatch'
12
+
13
+ def on_def(node)
14
+ methods = module_methods(node.parent_module_name)
15
+ return unless methods
16
+ return add_offense(node, message: 'missing signature') unless methods.key?(node.method_name)
17
+
18
+ result = check_arity(node, methods[node.method_name].method_types)
19
+ add_offense(node, message: result) if result
20
+ rescue RBS::BaseError => e
21
+ add_offense(node, message: "signature error, #{e}")
22
+ end
23
+ alias on_defs on_def
24
+
25
+ private
26
+
27
+ def module_methods(module_name)
28
+ return if module_name.nil?
29
+
30
+ type = rbs_resolver.resolve(rbs_type_name(module_name), context: nil)
31
+ return unless type
32
+
33
+ rbs_builder.build_instance(type).methods
34
+ end
35
+
36
+ def rbs_type_name(string)
37
+ RBS::Namespace.parse(string).yield_self do |namespace|
38
+ last = namespace.path.last
39
+ RBS::TypeName.new(name: last, namespace: namespace.parent)
40
+ end
41
+ end
42
+
43
+ def rbs_environment
44
+ @@rbs_environment ||= begin
45
+ loader = RBS::EnvironmentLoader.new
46
+ loader.add(path: Pathname('sig')) # TODO: use configuration var for sig path
47
+ RBS::Environment.from_loader(loader).resolve_type_names
48
+ end
49
+ end
50
+
51
+ def rbs_resolver
52
+ @@rbs_resolver ||= RBS::Resolver::TypeNameResolver.new(rbs_environment)
53
+ end
54
+
55
+ def rbs_builder
56
+ @@rbs_builder ||= RBS::DefinitionBuilder.new(env: rbs_environment)
57
+ end
58
+
59
+ def check_arity(node, method_args)
60
+ arity = node.arguments.entries.map(&:type).tally
61
+ rbs_args = method_args.first.type
62
+ return if arity_match?(arity, rbs_args)
63
+
64
+ "#{MSG}, expected: #{method_args.join("\n")}"
65
+ end
66
+
67
+ def arity_match?(arity, rbs_args)
68
+ arity_arg_match?(arity, rbs_args) &&
69
+ arity_optarg_match?(arity, rbs_args) &&
70
+ arity_restarg_match?(arity, rbs_args) &&
71
+ arity_kwarg_match?(arity, rbs_args) &&
72
+ arity_kwoptarg_match?(arity, rbs_args) &&
73
+ arity_kwrestarg_match?(arity, rbs_args)
74
+ end
75
+
76
+ def arity_arg_match?(arity, rbs_args)
77
+ arity[:arg].to_i == rbs_args.required_positionals.count
78
+ end
79
+
80
+ def arity_optarg_match?(arity, rbs_args)
81
+ arity[:optarg].to_i == rbs_args.optional_positionals.count
82
+ end
83
+
84
+ def arity_restarg_match?(arity, rbs_args)
85
+ arity[:restarg].to_i.positive? == !rbs_args.rest_positionals.nil?
86
+ end
87
+
88
+ def arity_kwarg_match?(arity, rbs_args)
89
+ arity[:kwarg].to_i == rbs_args.required_keywords.count
90
+ end
91
+
92
+ def arity_kwoptarg_match?(arity, rbs_args)
93
+ arity[:kwoptarg].to_i == rbs_args.optional_keywords.count
94
+ end
95
+
96
+ def arity_kwrestarg_match?(arity, rbs_args)
97
+ arity[:kwrestarg].to_i.positive? == !rbs_args.rest_keywords.nil?
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ require_relative 'rbs/method_signature'
@@ -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 Rbs
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 Rbs
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rbs/version'
4
+
5
+ module RuboCop
6
+ module Rbs
7
+ class Error < StandardError; end
8
+
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,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ require_relative 'rubocop/rbs'
6
+ require_relative 'rubocop/rbs/version'
7
+ require_relative 'rubocop/rbs/inject'
8
+
9
+ RuboCop::Rbs::Inject.defaults!
10
+
11
+ RuboCop::Runner.prepend(Module.new do
12
+ def file_offense_cache(_file)
13
+ # NOTE: skip cache because we need to monitor .rbs and their related .rb
14
+ yield
15
+ end
16
+ end)
17
+
18
+ # RuboCop::Config.prepend(Module.new do
19
+ # def file_to_include?(file)
20
+ # super || File.extname(file) == '.rbs'
21
+ # end
22
+ # end)
23
+
24
+ require_relative 'rubocop/cop/rbs_cops'
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-rbs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mattia Roccoberton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rbs
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
+ description: RuboCop cops to check RBS signatures
42
+ email:
43
+ - mat@blocknot.es
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE.txt
49
+ - README.md
50
+ - config/default.yml
51
+ - lib/rubocop-rbs.rb
52
+ - lib/rubocop/cop/rbs/method_signature.rb
53
+ - lib/rubocop/cop/rbs_cops.rb
54
+ - lib/rubocop/rbs.rb
55
+ - lib/rubocop/rbs/inject.rb
56
+ - lib/rubocop/rbs/version.rb
57
+ homepage: https://github.com/blocknotes/rubocop-rbs
58
+ licenses:
59
+ - MIT
60
+ metadata:
61
+ homepage_uri: https://github.com/blocknotes/rubocop-rbs
62
+ source_code_uri: https://github.com/blocknotes/rubocop-rbs
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 3.0.0
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 3.4.14
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: RuboCop RBS
82
+ test_files: []