rubocop-dry-import 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: 85d7c48439ed60d9252a754f9f30c10a936d66e7005ee1786ae03c0a14999779
4
+ data.tar.gz: fede65640799eef6f9fc7ab33f9f0d758d9e947057c1a20789220577c3c143ca
5
+ SHA512:
6
+ metadata.gz: a02c84254590d9b1c82bd9a2bf7e0a09e9c41047cee910ead491695bba8f615e91b075c428af636f90dde7733e414931a79989cc288f7b68403e027d7edd672b
7
+ data.tar.gz: 9fc2060a4c3c733a1c076b63dc9bc211ce1f32531254f2582d3d42e4dab536d8eea3d515ad8619299a1d137ee6edeb7b09279c9fac25b047d9e2bb00472ab243
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,23 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-11-08 19:30:09 UTC using RuboCop version 1.81.7.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
11
+ Metrics/AbcSize:
12
+ Max: 18
13
+
14
+ # Offense count: 1
15
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
16
+ # AllowedMethods: refine
17
+ Metrics/BlockLength:
18
+ Max: 65
19
+
20
+ # Offense count: 2
21
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
22
+ Metrics/MethodLength:
23
+ Max: 14
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 seriousdev-gh
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,85 @@
1
+ # RuboCop Dry Import
2
+
3
+ A custom [RuboCop](https://github.com/rubocop/rubocop) extension that detects **unused `Import` dependencies** in classes using [dry-rb’s dependency injection](https://dry-rb.org/gems/dry-auto_inject/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'rubocop-dry-import', require: false
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Add the extension to your `.rubocop.yml`:
16
+
17
+ ```yaml
18
+ require:
19
+ - rubocop-dry-import
20
+
21
+ Dry/UnusedImport:
22
+ Enabled: true
23
+ ImportName: 'Import' # Optional, defaults to "Import"
24
+ ```
25
+
26
+ Run RuboCop as usual:
27
+
28
+ ```bash
29
+ bundle exec rubocop
30
+ ```
31
+
32
+ ## Example
33
+
34
+ ```ruby
35
+ class FooService
36
+ include Import['service_a', 'service_b']
37
+
38
+ def call
39
+ service_b.call
40
+ end
41
+ end
42
+ ```
43
+
44
+ **Offense:**
45
+ ```
46
+ Include Import['service_a', 'service_b']
47
+ ^^^^^^^^^^^ Imported dependency `service_a` is not used in the class.
48
+ ```
49
+
50
+ **Autocorrect:** Not available (yet).
51
+
52
+ ## Development
53
+
54
+ Clone and setup:
55
+
56
+ ```bash
57
+ git clone https://github.com/seriousdev-gh/rubocop-dry-import
58
+ cd rubocop-dry-import
59
+ bundle install
60
+ ```
61
+
62
+ Run tests:
63
+
64
+ ```bash
65
+ bundle exec rspec
66
+ ```
67
+
68
+ Run RuboCop locally:
69
+
70
+ ```bash
71
+ bundle exec rubocop --require rubocop-dry-import path/to/file.rb
72
+ ```
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork the project.
77
+ 2. Create your feature branch (`git checkout -b feature/new-cop`).
78
+ 3. Commit your changes (`git commit -am 'Add new cop'`).
79
+ 4. Push to the branch (`git push origin feature/new-cop`).
80
+ 5. Open a Pull Request.
81
+
82
+ ## License
83
+
84
+ This project is licensed under the [MIT License](LICENSE).
85
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,3 @@
1
+ Dry/UnusedImport:
2
+ Enabled: true
3
+ InjectorName: 'Import'
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Dry
6
+ class UnusedImport < Base
7
+ MSG = 'Imported dependency `%<name>s` is not used in the class.'
8
+
9
+ def_node_matcher :possible_injector_include?, <<~PATTERN
10
+ (send nil? :include
11
+ (send
12
+ (const nil? $_) :[] ...))
13
+ PATTERN
14
+
15
+ # search for method calls
16
+ def on_send(node)
17
+ # search for method calls with specific pattern `include <included_const_name>[<...>]`
18
+ possible_injector_include?(node) do |included_const_name|
19
+ next if included_const_name.to_s != injector_name
20
+
21
+ injector_call_node = node.arguments.first
22
+ class_node = node.parent
23
+
24
+ imported = extract_imported_methods(injector_call_node)
25
+ break if imported.empty?
26
+
27
+ unused = filter_unused_imported_methods(class_node, imported.dup)
28
+ unused.each do |name, import_node|
29
+ add_offense(import_node, message: format(MSG, name:))
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def injector_name
37
+ cop_config['InjectorName'] || 'Import'
38
+ end
39
+
40
+ def extract_imported_methods(injector_call_node)
41
+ imported_methods = {}
42
+
43
+ injector_call_node.arguments.each do |arg|
44
+ case arg.type
45
+ when :str, :sym
46
+ name = arg.value.to_s.split('.').last
47
+ imported_methods[name.to_s] = arg
48
+ when :hash
49
+ arg.pairs.each do |pair_node|
50
+ name = pair_node.key.value
51
+ imported_methods[name.to_s] = pair_node
52
+ end
53
+ end
54
+ end
55
+
56
+ imported_methods
57
+ end
58
+
59
+ def filter_unused_imported_methods(class_node, imported)
60
+ class_node.each_descendant(:send).each do |node|
61
+ break if imported.empty?
62
+
63
+ name = node.method_name.to_s
64
+ imported.delete(name) if imported.key?(name)
65
+ end
66
+
67
+ imported
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCopDryImport
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rubocop_dry_import/version'
4
+ require_relative 'rubocop/cop/dry/unused_import'
5
+
6
+ module RuboCopDryImport
7
+ def self.inject!
8
+ path = File.expand_path(__dir__)
9
+ RuboCop::ConfigLoader.default_configuration = RuboCop::ConfigLoader.default_configuration.merge(
10
+ YAML.safe_load_file(File.join(path, 'config', 'default.yml'), aliases: true)
11
+ )
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/rubocop_dry_import/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'rubocop-dry-import'
7
+ spec.version = RuboCopDryImport::VERSION
8
+ spec.authors = ['seriousdev-gh']
9
+ spec.email = ['borisdrovnin@gmail.com']
10
+
11
+ spec.summary = 'RuboCop extension that detects unused dry-rb Import dependencies.'
12
+ spec.description = 'rubocop-dry-import adds a RuboCop cop (Dry/UnusedImport) that warns when imported ' \
13
+ 'dependencies via dry-rb’s Import or AutoInject are not used within the class.'
14
+ spec.homepage = 'https://github.com/seriousdev-gh/rubocop-dry-import'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 3.2.0'
17
+
18
+ spec.metadata['source_code_uri'] = spec.homepage
19
+ spec.metadata['rubygems_mfa_required'] = 'true'
20
+
21
+ spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
22
+ ls.readlines("\x0", chomp: true).reject do |f|
23
+ f.start_with?(*%w[bin/ Gemfile .gitignore .rspec spec/ .github/ example/ .rubocop.yml])
24
+ end
25
+ end
26
+
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_dependency 'rubocop', '>= 1.0', '< 2.0'
32
+
33
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
34
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-dry-import
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - seriousdev-gh
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rubocop
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '1.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '2.0'
32
+ description: rubocop-dry-import adds a RuboCop cop (Dry/UnusedImport) that warns when
33
+ imported dependencies via dry-rb’s Import or AutoInject are not used within the
34
+ class.
35
+ email:
36
+ - borisdrovnin@gmail.com
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - ".rubocop_todo.yml"
42
+ - LICENSE.txt
43
+ - README.md
44
+ - Rakefile
45
+ - config/default.yml
46
+ - lib/rubocop/cop/dry/unused_import.rb
47
+ - lib/rubocop_dry_import.rb
48
+ - lib/rubocop_dry_import/version.rb
49
+ - rubocop-dry-import.gemspec
50
+ homepage: https://github.com/seriousdev-gh/rubocop-dry-import
51
+ licenses:
52
+ - MIT
53
+ metadata:
54
+ source_code_uri: https://github.com/seriousdev-gh/rubocop-dry-import
55
+ rubygems_mfa_required: 'true'
56
+ allowed_push_host: https://rubygems.org
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.2.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.7.2
72
+ specification_version: 4
73
+ summary: RuboCop extension that detects unused dry-rb Import dependencies.
74
+ test_files: []