gem-why 0.0.1 → 0.0.3

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: 427248f88372106860306d895e33b9323628582c6bee05b5b83fed9ce5c1b416
4
- data.tar.gz: 4e6fec4a6b52226de621ea6d3486e79780c68e3a6e2ba4bcc6e6e843c9bcd0de
3
+ metadata.gz: f8ba999ce8e8f05e3b7c8ea0ff6d811442fd223f89b4dd0fd5747760434d4198
4
+ data.tar.gz: be059d49572cc4642a30959e2dd3fc85d0f6814856a42e0f66d68165778e0295
5
5
  SHA512:
6
- metadata.gz: 8c61e858acfd0fa46812f0eb8548e4710137b07fd9d551ad2dc7a75fe456655bb6c45817a2799e8770d2a4fcc1e59f1bb026ed9ebaa814a090411611d67929cd
7
- data.tar.gz: bfc45293182646801fc2d3ab7ea7b5f4b464c21c844fd3a7f18743b716e4b4d76b6b0e9e885e036c00774940da1ef6b285b124e10243c4dab296791e4094ec90
6
+ metadata.gz: 664dfb44d822edfbc6b25843358a19de6070b5bc6436c649e5ef245d73f083260ab008fc1c7c3769238e9b187939a11ebe0d4b56d3ce3357e1637fa4ee4493ea
7
+ data.tar.gz: '0187270f93fb7a24f2249c973ae0b06740d51c2d3092eabd196aac15c5a43592995b6108c2e3d9dcbaf4b9c5c3fa555462c9d676f153219089dd671cde507909'
data/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.0.3] - 2026-02-12
9
+
10
+ ### Fixed
11
+
12
+ - Fix checking direct dependencies
13
+
14
+ ## [0.0.2] - 2025-10-11
15
+
16
+ ### Fixed
17
+
18
+ - Add spec memoization to improve performance of recursive analysis
19
+ - Fix terminology: use 'dependents' instead of 'dependencies' in help text
20
+ - Eliminate redundant spec lookups by passing version from analyze
21
+
8
22
  ## [0.0.1] - 2025-10-01
9
23
 
10
24
  ### Added
@@ -21,4 +35,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
35
  - RuboCop compliance with default settings
22
36
  - Complete documentation in README
23
37
 
24
- [0.0.1]: https://github.com/vitaly/gem-why/releases/tag/v0.0.1
38
+ [0.0.2]: https://github.com/vitallium/gem-why/releases/tag/v0.0.2
39
+ [0.0.1]: https://github.com/vitallium/gem-why/releases/tag/v0.0.1
data/README.md CHANGED
@@ -53,6 +53,8 @@ To see which gems depend on a specific gem:
53
53
  gem why GEMNAME [options]
54
54
  ```
55
55
 
56
+ **Bonus:** If you add this gem to your project, you can use the `bundle exec gem why` command to understand the dependencies of your gems in your project.
57
+
56
58
  ### Examples
57
59
 
58
60
  #### Default Behavior - Deep Dependencies
@@ -128,6 +130,7 @@ No gems depend on nonexistent-gem
128
130
  | (none) | | Show full dependency chains (default) |
129
131
  | `--direct` | `-d` | Show only direct dependencies |
130
132
  | `--tree` | `-t` | Display as a visual tree |
133
+ | `--json` | | Output in JSON format |
131
134
  | `--help` | `-h` | Show help message |
132
135
  | `--verbose` | `-V` | Verbose output |
133
136
 
@@ -1,22 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "dependent"
4
+
3
5
  module GemWhy
4
6
  # Analyzes gem dependencies to find dependents and dependency chains
5
7
  class Analyzer
8
+ def initialize
9
+ @spec_cache = {}
10
+ end
11
+
6
12
  # Finds all gems that directly depend on the target gem
7
13
  # @param target_gem_name [String] the gem to find dependents for
8
- # @return [Array<Array(String, String)>] array of [gem_name, requirement] pairs
14
+ # @return [Array<Dependent>] array of Dependent objects
9
15
  def find_direct_dependents(target_gem_name)
10
- dependents = []
11
- normalized_target = target_gem_name.downcase
12
-
13
- Gem::Specification.each do |spec|
14
- spec.dependencies.each do |dep|
15
- dependents << [spec.name, dep.requirement.to_s] if dep.name.downcase == normalized_target
16
- end
17
- end
18
-
19
- dependents.sort_by(&:first)
16
+ Gem::Specification.flat_map do |spec|
17
+ direct_dependents_for_spec(spec, target_gem_name)
18
+ end.sort_by(&:name)
20
19
  end
21
20
 
22
21
  # Finds all dependency chains leading to the target gem
@@ -65,7 +64,7 @@ module GemWhy
65
64
  end
66
65
 
67
66
  def process_dependency(dep, target_gem, path, new_node, visited)
68
- if dep.name.downcase == target_gem.downcase
67
+ if dep.name.downcase == target_gem
69
68
  [path + [new_node]]
70
69
  else
71
70
  find_paths_to_target(dep.name, target_gem, path + [new_node], visited)
@@ -73,9 +72,11 @@ module GemWhy
73
72
  end
74
73
 
75
74
  def load_gem_spec(gem_name)
76
- Gem::Specification.find_by_name(gem_name)
77
- rescue Gem::MissingSpecError
78
- nil
75
+ @spec_cache.fetch(gem_name) do
76
+ @spec_cache[gem_name] = Gem::Specification.find_by_name(gem_name)
77
+ rescue Gem::MissingSpecError
78
+ @spec_cache[gem_name] = nil
79
+ end
79
80
  end
80
81
 
81
82
  def build_dependency_node(spec, dep)
@@ -85,5 +86,13 @@ module GemWhy
85
86
  requirement = dep.requirement.to_s
86
87
  { name:, version:, dependency:, requirement: }
87
88
  end
89
+
90
+ def direct_dependents_for_spec(spec, target_gem_name)
91
+ spec.runtime_dependencies
92
+ .filter { |dep| dep.name.downcase == target_gem_name.downcase }
93
+ .map do |dep|
94
+ Dependent.new(name: spec.name, version: spec.version.to_s, requirement: dep.requirement.to_s)
95
+ end
96
+ end
88
97
  end
89
98
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemWhy
4
+ # Represents a gem that depends on a target gem
5
+ Dependent = Data.define(:name, :version, :requirement) do
6
+ # Returns the dependent as a hash
7
+ # @return [Hash] hash representation
8
+ def to_h
9
+ { name:, version:, requirement: }
10
+ end
11
+ end
12
+ end
@@ -8,7 +8,7 @@ module GemWhy
8
8
  class DirectFormatter < BaseFormatter
9
9
  # Formats and displays direct dependencies
10
10
  # @param gem_name [String] the target gem name
11
- # @param dependents [Array<Array(String, String)>] the dependent gems
11
+ # @param dependents [Array<Dependent>] the dependent gems
12
12
  # @return [void]
13
13
  def format(gem_name, dependents)
14
14
  return say "No gems depend on #{colorize(gem_name, :yellow)}" if dependents.empty?
@@ -21,9 +21,9 @@ module GemWhy
21
21
  private
22
22
 
23
23
  def print_direct_dependents(dependents, gem_name)
24
- dependents.each do |dependent_name, requirement|
25
- spec = Gem::Specification.find_by_name(dependent_name)
26
- say " #{colorize(dependent_name, :blue)} (#{spec.version}) requires #{gem_name} #{requirement}"
24
+ dependents.each do |dependent|
25
+ say " #{colorize(dependent.name,
26
+ :blue)} (#{dependent.version}) requires #{gem_name} #{dependent.requirement}"
27
27
  end
28
28
  end
29
29
  end
@@ -14,17 +14,13 @@ module GemWhy
14
14
 
15
15
  # Outputs direct dependencies as JSON
16
16
  # @param gem_name [String] the target gem name
17
- # @param dependents [Array<Array(String, String)>] the dependent gems
17
+ # @param dependents [Array<Dependent>] the dependent gems
18
18
  # @return [void]
19
19
  def output_direct(gem_name, dependents)
20
20
  target = gem_name
21
21
  mode = "direct"
22
22
  total = dependents.size
23
- dependents_data = dependents.map do |name, requirement|
24
- spec = Gem::Specification.find_by_name(name)
25
- version = spec.version.to_s
26
- { name:, version:, requirement: }
27
- end
23
+ dependents_data = dependents.map(&:to_h)
28
24
  output = { target:, mode:, dependents: dependents_data, total: }
29
25
  say JSON.pretty_generate(output)
30
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GemWhy
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.3"
5
5
  end
@@ -14,8 +14,8 @@ module Gem
14
14
  # Command to show which gems depend on a specific gem
15
15
  #
16
16
  # This command helps identify dependency relationships by showing:
17
- # - Direct dependencies (--direct): immediate dependents only
18
- # - Deep dependencies (default): full dependency chains
17
+ # - Direct dependents (--direct): immediate dependents only
18
+ # - Deep dependency chains (default): full dependency chains
19
19
  # - Tree visualization (--tree): hierarchical view
20
20
  #
21
21
  # @example Show all dependency chains
@@ -73,7 +73,7 @@ module Gem
73
73
  end
74
74
 
75
75
  def setup_direct_option
76
- add_option("-d", "--direct", "Show only direct dependencies") do |value, options|
76
+ add_option("-d", "--direct", "Show only direct dependents") do |value, options|
77
77
  options[:direct] = value
78
78
  end
79
79
  end
@@ -130,7 +130,7 @@ module Gem
130
130
  end
131
131
  end
132
132
 
133
- # Shows direct dependencies only
133
+ # Shows direct dependents only
134
134
  # @param gem_name [String] the target gem name
135
135
  # @return [void]
136
136
  def show_direct_dependencies(gem_name)
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem-why
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vitaly Slobodin
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -36,6 +36,7 @@ files:
36
36
  - README.md
37
37
  - Rakefile
38
38
  - lib/gem_why/analyzer.rb
39
+ - lib/gem_why/dependent.rb
39
40
  - lib/gem_why/formatters/base_formatter.rb
40
41
  - lib/gem_why/formatters/deep_formatter.rb
41
42
  - lib/gem_why/formatters/direct_formatter.rb
@@ -67,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
68
  - !ruby/object:Gem::Version
68
69
  version: '0'
69
70
  requirements: []
70
- rubygems_version: 3.6.9
71
+ rubygems_version: 4.0.6
71
72
  specification_version: 4
72
73
  summary: A RubyGems plugin to show which gems depend on a specific gem
73
74
  test_files: []