gem-why 0.0.1 → 0.0.2

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: a438508ad05fcd88de1eb11236f4e716cf40679dee3072d79caab4598ef19d4c
4
+ data.tar.gz: 36e198634d2b8db32b26f1a9adf2683dba758a286998d4ef79308db88072b449
5
5
  SHA512:
6
- metadata.gz: 8c61e858acfd0fa46812f0eb8548e4710137b07fd9d551ad2dc7a75fe456655bb6c45817a2799e8770d2a4fcc1e59f1bb026ed9ebaa814a090411611d67929cd
7
- data.tar.gz: bfc45293182646801fc2d3ab7ea7b5f4b464c21c844fd3a7f18743b716e4b4d76b6b0e9e885e036c00774940da1ef6b285b124e10243c4dab296791e4094ec90
6
+ metadata.gz: 88e93410498b664730885114cb7e0dfa9de839785665cae19103a917135d8ce622baf4c226563c8a32e3e10b91e1e2e6e0a6972e40b073a87973936cac09f5dd
7
+ data.tar.gz: cfae3e17bb1a250f617cf749ef6f1a80e9563e6b355b09142691c96bf64631f9343e80742e902a8f0b9f9b24a6c758111b311f1b53d0a6eeb32a11ca9a102689
data/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ 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.2] - 2025-10-11
9
+
10
+ ### Fixed
11
+
12
+ - Add spec memoization to improve performance of recursive analysis
13
+ - Fix terminology: use 'dependents' instead of 'dependencies' in help text
14
+ - Eliminate redundant spec lookups by passing version from analyze
15
+
8
16
  ## [0.0.1] - 2025-10-01
9
17
 
10
18
  ### Added
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,28 @@
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
17
+ .map(&:dependencies).flatten
18
+ .filter { |dep| dep.name.downcase == target_gem_name.downcase }
19
+ .map do |dep|
20
+ Dependent.new(
21
+ name: spec.name,
22
+ version: spec.version.to_s,
23
+ requirement: dep.requirement.to_s
24
+ )
25
+ end.sort_by(&:name)
20
26
  end
21
27
 
22
28
  # Finds all dependency chains leading to the target gem
@@ -65,7 +71,7 @@ module GemWhy
65
71
  end
66
72
 
67
73
  def process_dependency(dep, target_gem, path, new_node, visited)
68
- if dep.name.downcase == target_gem.downcase
74
+ if dep.name.downcase == target_gem
69
75
  [path + [new_node]]
70
76
  else
71
77
  find_paths_to_target(dep.name, target_gem, path + [new_node], visited)
@@ -73,9 +79,11 @@ module GemWhy
73
79
  end
74
80
 
75
81
  def load_gem_spec(gem_name)
76
- Gem::Specification.find_by_name(gem_name)
77
- rescue Gem::MissingSpecError
78
- nil
82
+ @spec_cache.fetch(gem_name) do
83
+ @spec_cache[gem_name] = Gem::Specification.find_by_name(gem_name)
84
+ rescue Gem::MissingSpecError
85
+ @spec_cache[gem_name] = nil
86
+ end
79
87
  end
80
88
 
81
89
  def build_dependency_node(spec, dep)
@@ -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.2"
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.2
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