rebundler 0.3.1 → 0.5.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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +12 -1
- data/README.md +43 -1
- data/exe/rebundle +10 -8
- data/lib/bundler/rebundle.rb +2 -2
- data/lib/rebundler/{writer.rb → formatter.rb} +14 -9
- data/lib/rebundler/gem_declaration.rb +15 -0
- data/lib/rebundler/gem_set.rb +3 -3
- data/lib/rebundler/parser.rb +27 -24
- data/lib/rebundler/serializer.rb +20 -2
- data/lib/rebundler/summarizer.rb +33 -0
- data/lib/rebundler/version.rb +1 -1
- data/lib/rebundler/visitor.rb +26 -9
- data/lib/rebundler.rb +1 -1
- data/mise.toml +2 -0
- metadata +6 -4
- data/lib/rebundler/gem_fetcher.rb +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f39f0bba7935159299bb736312beb6b0452d8997bb1f6c5bf574747b08d05af3
|
|
4
|
+
data.tar.gz: f8920192f0a6bf48ba31f21f67f8cba06d1a682e00196a89750aed089bb392bb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a1144be379a959ed76e26635daf82a9e535dc8e8ac416f2509206c95f9b6673b349f62ed80260f7703e83781cf657d20ef7e0e5ba3b6ef732e7404c6e4cb543
|
|
7
|
+
data.tar.gz: fa7d2a0423b94382e778ac048defebfe6301d994d860f1040f1cac509e9f617903234ea2eea1f2c5400f8d020183d14bd370a8617287fe0c1203a474f039d024
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [0.5.0] - 2026-03-13
|
|
2
|
+
|
|
3
|
+
- Major internal refactor and clean up.
|
|
4
|
+
|
|
5
|
+
You can now instantiate the parser via `Rebundler::Parser.from_file(path)` or directly
|
|
6
|
+
from a string via `Rebundler::Parser.from_string(content)`.
|
|
7
|
+
|
|
8
|
+
## [0.4.0] - 2025-12-21
|
|
9
|
+
|
|
10
|
+
- **Breaking** Rebundler now leaves existing trailing comments intact.
|
|
11
|
+
|
|
12
|
+
You can still overwrite them (the previous behavior) by using the `--force` flag.
|
|
2
13
|
|
|
3
14
|
## [0.3.1] - 2025-12-19
|
|
4
15
|
|
data/README.md
CHANGED
|
@@ -18,7 +18,6 @@ This is a real life example from my own project. That looks a lot better, doesn'
|
|
|
18
18
|
|
|
19
19
|
## Known limitations
|
|
20
20
|
|
|
21
|
-
- **Existing comments will be lost.** At this moment Rebundler does not persist existing comments.
|
|
22
21
|
- **Probably does not work with all possible Gemfile configurations.** It is designed to work with the most common setups right now. If you encounter an issue, please open an issue on GitHub. I strive to support each sensible configuration.
|
|
23
22
|
|
|
24
23
|
## Installation
|
|
@@ -57,6 +56,8 @@ This does **not** load the plugin and means you have to run rebundler yourself b
|
|
|
57
56
|
|
|
58
57
|
```sh
|
|
59
58
|
$ bundle exec rebundle
|
|
59
|
+
Reordering and annotating Gemfile...
|
|
60
|
+
✓ Gemfile has been reordered and annotated
|
|
60
61
|
```
|
|
61
62
|
|
|
62
63
|
### 3. CI mode
|
|
@@ -68,6 +69,47 @@ If there are differences, rebundler will exit with a non-zero status code.
|
|
|
68
69
|
|
|
69
70
|
This does not write to the Gemfile.
|
|
70
71
|
|
|
72
|
+
### Options
|
|
73
|
+
|
|
74
|
+
### `--force`
|
|
75
|
+
|
|
76
|
+
By default, Rebundler preserves existing trailing comments on `gem` defining lines. If you want to overwrite them anyway, use the `--force` flag:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
$ bundle exec rebundle --force
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Interface
|
|
83
|
+
|
|
84
|
+
You can also use Rebundler directly in Ruby rather than via the CLI.
|
|
85
|
+
|
|
86
|
+
### `Parser.from_file(path)`
|
|
87
|
+
|
|
88
|
+
Parses a Gemfile at the given path and returns a `Parser` instance.
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
parser = Rebundler::Parser.from_file("/path/to/Gemfile")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `Parser.from_string(content)`
|
|
95
|
+
|
|
96
|
+
Parses a Gemfile from a string and returns a `Parser` instance.
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
content = File.read("/path/to/Gemfile")
|
|
100
|
+
parser = Rebundler::Parser.from_string(content)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `parser.format(overwrite_comments: false)`
|
|
104
|
+
|
|
105
|
+
Returns the formatted Gemfile content as a string. Does not write to disk.
|
|
106
|
+
|
|
107
|
+
Pass `overwrite_comments: true` to replace existing trailing comments on `gem` lines (equivalent to the `--force` CLI flag):
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
new_content = parser.format(overwrite_comments: true)
|
|
111
|
+
```
|
|
112
|
+
|
|
71
113
|
## Development
|
|
72
114
|
|
|
73
115
|
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/exe/rebundle
CHANGED
|
@@ -5,33 +5,35 @@ require_relative "../lib/rebundler"
|
|
|
5
5
|
|
|
6
6
|
# Parse command line arguments
|
|
7
7
|
ci_mode = ARGV.include?("--ci")
|
|
8
|
+
overwrite_comments = ARGV.include?("--force")
|
|
8
9
|
file = ARGV.reject { |arg| arg.start_with?("--") }[0] || (Dir.pwd + "/Gemfile")
|
|
9
10
|
|
|
10
|
-
puts "Reordering and annotating Gemfile..."
|
|
11
|
-
|
|
12
11
|
begin
|
|
13
12
|
# Load all gems in the Gemfile so we can use them to grab the summary instead of
|
|
14
13
|
# having to hit rubygems.org
|
|
15
14
|
Bundler.setup
|
|
16
|
-
parser = Rebundler::Parser.
|
|
17
|
-
new_content = parser.
|
|
15
|
+
parser = Rebundler::Parser.from_file(file)
|
|
16
|
+
new_content = parser.format(overwrite_comments:)
|
|
18
17
|
|
|
19
18
|
if ci_mode
|
|
20
19
|
# In CI mode, compare the new content with the existing file
|
|
20
|
+
puts "Checking if Gemfile is properly formatted..."
|
|
21
21
|
current_content = File.read(file)
|
|
22
22
|
|
|
23
23
|
if new_content == current_content
|
|
24
|
-
puts "✓ Gemfile is
|
|
24
|
+
puts "\e[32m✓ Gemfile is properly formatted\e[0m"
|
|
25
25
|
exit 0
|
|
26
26
|
else
|
|
27
|
-
puts "✗ Gemfile is not properly formatted"
|
|
28
|
-
puts "Run
|
|
27
|
+
puts "\e[31m✗ Gemfile is not properly formatted\e[0m"
|
|
28
|
+
puts "Run `bundle exec rebundle` to fix formatting issues"
|
|
29
29
|
exit 1
|
|
30
30
|
end
|
|
31
31
|
else
|
|
32
32
|
# In normal mode, write the new content to the file
|
|
33
|
+
puts "Reordering and annotating Gemfile..."
|
|
33
34
|
File.write(file, new_content)
|
|
34
|
-
puts "✓ Gemfile has been reordered and annotated"
|
|
35
|
+
puts "\e[32m✓ Gemfile has been reordered and annotated\e[0m"
|
|
36
|
+
|
|
35
37
|
end
|
|
36
38
|
rescue StandardError => e
|
|
37
39
|
puts "Error parsing Gemfile: #{e.message}"
|
data/lib/bundler/rebundle.rb
CHANGED
|
@@ -25,8 +25,8 @@ module Bundler
|
|
|
25
25
|
# having to hit rubygems.org
|
|
26
26
|
Bundler.setup
|
|
27
27
|
|
|
28
|
-
parser = ::Rebundler::Parser.
|
|
29
|
-
content = parser.
|
|
28
|
+
parser = ::Rebundler::Parser.from_file(file)
|
|
29
|
+
content = parser.format
|
|
30
30
|
|
|
31
31
|
# Use atomic write to prevent corruption if write fails
|
|
32
32
|
Tempfile.create("Gemfile", Bundler.root.to_s) do |tmp|
|
|
@@ -3,31 +3,36 @@
|
|
|
3
3
|
require "forwardable"
|
|
4
4
|
|
|
5
5
|
module Rebundler
|
|
6
|
-
class
|
|
6
|
+
class Formatter
|
|
7
7
|
extend Forwardable
|
|
8
8
|
|
|
9
|
-
def_delegators :@parser, :
|
|
9
|
+
def_delegators :@parser, :directives, :gem_sets, :frozen_string_literal, :comments
|
|
10
10
|
|
|
11
11
|
def initialize(parser)
|
|
12
12
|
@parser = parser
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def format(overwrite_comments: false)
|
|
16
16
|
buffer = []
|
|
17
17
|
|
|
18
18
|
buffer << "# frozen_string_literal: true" if frozen_string_literal
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
directives.each do |node|
|
|
21
21
|
buffer << Serializer.node_to_s(node)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
gem_sets.sort.each do |set|
|
|
25
25
|
gem_content = [set.plugins, set.gems].map do |nodes|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
nodes.sort.map do |gem|
|
|
27
|
+
existing_comment = Serializer.extract_comment(gem.node, comments)
|
|
28
|
+
comment = if existing_comment && !overwrite_comments
|
|
29
|
+
existing_comment
|
|
30
|
+
else
|
|
31
|
+
gem.summary
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
line = +Serializer.node_to_s(gem.node)
|
|
35
|
+
line << " # #{comment}" if comment
|
|
31
36
|
line
|
|
32
37
|
end.join("\n")
|
|
33
38
|
end.reject(&:empty?).join("\n\n")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rebundler
|
|
4
|
+
GemDeclaration = Data.define(:name, :summary, :node) do
|
|
5
|
+
def <=>(other)
|
|
6
|
+
raise ArgumentError, "comparison of GemDeclaration with #{other.class} failed" unless other.is_a?(GemDeclaration)
|
|
7
|
+
|
|
8
|
+
normalized_name <=> other.normalized_name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def normalized_name
|
|
12
|
+
name.tr("-_", "").downcase
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/rebundler/gem_set.rb
CHANGED
|
@@ -16,14 +16,14 @@ module Rebundler
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def <=>(other)
|
|
19
|
-
|
|
19
|
+
raise ArgumentError, "comparison of GemSet with #{other.class} failed" unless other.is_a?(GemSet)
|
|
20
20
|
|
|
21
21
|
# Default first, then sort by name
|
|
22
|
-
[default ? 0 : 1, name] <=> [other.default ? 0 : 1, other.name]
|
|
22
|
+
[default ? 0 : 1, name.to_s] <=> [other.default ? 0 : 1, other.name.to_s]
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def ==(other)
|
|
26
|
-
other.is_a?(GemSet) && other.name == name
|
|
26
|
+
other.is_a?(GemSet) && other.name == name && other.default == default
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
data/lib/rebundler/parser.rb
CHANGED
|
@@ -4,41 +4,44 @@ require "prism"
|
|
|
4
4
|
|
|
5
5
|
module Rebundler
|
|
6
6
|
class Parser
|
|
7
|
-
attr_reader :
|
|
7
|
+
attr_reader :content, :frozen_string_literal, :directives, :gem_sets, :comments
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
@frozen_string_literal = false
|
|
12
|
-
@preamble_nodes = []
|
|
13
|
-
@gem_sets = [GemSet.new(default: true)] # all gems outside a specific block (group, source, etc) will end up here
|
|
14
|
-
end
|
|
9
|
+
def self.from_file(path)
|
|
10
|
+
raise Rebundler::Error, "File not found: #{path}" unless File.exist?(path)
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
GemSet.new(name:, node:).tap do |set|
|
|
18
|
-
@gem_sets << set
|
|
19
|
-
end
|
|
12
|
+
new(File.read(path))
|
|
20
13
|
end
|
|
21
14
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
parsed = Prism.parse(File.read(file))
|
|
15
|
+
def self.from_string(content)
|
|
16
|
+
new(content)
|
|
17
|
+
end
|
|
26
18
|
|
|
27
|
-
|
|
19
|
+
def format(overwrite_comments: false)
|
|
20
|
+
Formatter.new(self).format(overwrite_comments:)
|
|
21
|
+
end
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
parsed.value.accept(visitor)
|
|
23
|
+
private_class_method :new
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
def initialize(content)
|
|
26
|
+
@content = content
|
|
27
|
+
@frozen_string_literal = false
|
|
28
|
+
@directives = []
|
|
29
|
+
@gem_sets = [GemSet.new(default: true)]
|
|
30
|
+
@comments = []
|
|
34
31
|
|
|
35
|
-
def parse_and_write!
|
|
36
32
|
parse!
|
|
37
|
-
Writer.new(self).write!
|
|
38
33
|
end
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def parse!
|
|
38
|
+
parsed = Prism.parse(@content)
|
|
39
|
+
|
|
40
|
+
@frozen_string_literal = parsed.magic_comments.map(&:key).include?("frozen_string_literal")
|
|
41
|
+
@comments = parsed.comments
|
|
42
|
+
|
|
43
|
+
visitor = Visitor.new(self)
|
|
44
|
+
parsed.value.accept(visitor)
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
end
|
data/lib/rebundler/serializer.rb
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
module Rebundler
|
|
4
4
|
class Serializer
|
|
5
|
+
def self.extract_comment(node, comments)
|
|
6
|
+
# Find comments that are on the same line as the node
|
|
7
|
+
node_line = node.location.end_line
|
|
8
|
+
|
|
9
|
+
trailing_comment = comments.find do |comment|
|
|
10
|
+
comment.location.start_line == node_line &&
|
|
11
|
+
comment.location.start_offset > node.location.end_offset
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
return nil unless trailing_comment
|
|
15
|
+
|
|
16
|
+
# Get the comment text (without the # prefix)
|
|
17
|
+
comment_text = trailing_comment.location.slice.sub(/^#\s*/, "").strip
|
|
18
|
+
comment_text.empty? ? nil : comment_text
|
|
19
|
+
end
|
|
20
|
+
|
|
5
21
|
def self.node_to_s(node)
|
|
6
22
|
lines = node.location.slice.lines
|
|
7
23
|
|
|
@@ -24,8 +40,10 @@ module Rebundler
|
|
|
24
40
|
end
|
|
25
41
|
|
|
26
42
|
def self.find_spacing_character(node)
|
|
27
|
-
# Assume it's formatted with tabs if
|
|
28
|
-
node.location.slice.
|
|
43
|
+
# Assume it's formatted with tabs if ANY line starts with a tab.
|
|
44
|
+
any_line_starts_with_tab = node.location.slice.split("\n").any? { it.start_with?("\t") }
|
|
45
|
+
|
|
46
|
+
any_line_starts_with_tab ? "\t" : " "
|
|
29
47
|
end
|
|
30
48
|
end
|
|
31
49
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "timeout"
|
|
4
|
+
|
|
5
|
+
module Rebundler
|
|
6
|
+
class Summarizer
|
|
7
|
+
class << self
|
|
8
|
+
def summarize(name)
|
|
9
|
+
find_loaded_gem_summary(name) || find_external_gem_summary(name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def find_loaded_gem_summary(name)
|
|
15
|
+
gem = Gem::Specification.find_by_name(name)
|
|
16
|
+
|
|
17
|
+
gem.summary
|
|
18
|
+
rescue Gem::MissingSpecError
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def find_external_gem_summary(name)
|
|
23
|
+
spec = Gem::SpecFetcher.fetcher.spec_for_dependency Gem::Dependency.new(name)
|
|
24
|
+
|
|
25
|
+
return if spec.nil? || spec.first.empty?
|
|
26
|
+
|
|
27
|
+
spec.first.first.first.summary
|
|
28
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Timeout::Error => e
|
|
29
|
+
raise Rebundler::Error, "Network error while fetching gem info for '#{name}': #{e.message}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/rebundler/version.rb
CHANGED
data/lib/rebundler/visitor.rb
CHANGED
|
@@ -11,26 +11,43 @@ module Rebundler
|
|
|
11
11
|
def visit_call_node(node)
|
|
12
12
|
case node.name
|
|
13
13
|
when :plugin
|
|
14
|
-
|
|
15
|
-
@current_set.plugins << parsed_gem if parsed_gem
|
|
14
|
+
@current_set.plugins << parse_gem_with_comment(node)
|
|
16
15
|
when :gem
|
|
17
|
-
|
|
18
|
-
@current_set.gems << parsed_gem if parsed_gem
|
|
16
|
+
@current_set.gems << parse_gem_with_comment(node)
|
|
19
17
|
when :git_source
|
|
20
|
-
@parser.
|
|
21
|
-
when *
|
|
18
|
+
@parser.directives << node
|
|
19
|
+
when *DIRECTIVE_AND_BLOCK_NODES
|
|
22
20
|
if node.block
|
|
23
21
|
# Use the full block declaration (e.g., "group :development do") as the unique name
|
|
24
22
|
name = node.location.slice.lines.first.strip
|
|
25
23
|
|
|
26
24
|
previous_set = @current_set
|
|
27
|
-
@current_set =
|
|
28
|
-
node.block.body
|
|
25
|
+
@current_set = find_or_build_set(name:, node:)
|
|
26
|
+
node.block.body.accept(self)
|
|
29
27
|
@current_set = previous_set
|
|
30
28
|
else
|
|
31
|
-
@parser.
|
|
29
|
+
@parser.directives << node
|
|
32
30
|
end
|
|
33
31
|
end
|
|
34
32
|
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def find_or_build_set(name:, node: nil)
|
|
37
|
+
@parser.gem_sets.find { |set| set.name == name } || build_set(name:, node:)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_set(name:, node: nil)
|
|
41
|
+
GemSet.new(name:, node:).tap do |set|
|
|
42
|
+
@parser.gem_sets << set
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def parse_gem_with_comment(node)
|
|
47
|
+
name = node.arguments.child_nodes[0].content
|
|
48
|
+
summary = Summarizer.summarize(name)
|
|
49
|
+
|
|
50
|
+
GemDeclaration.new(name:, summary:, node:)
|
|
51
|
+
end
|
|
35
52
|
end
|
|
36
53
|
end
|
data/lib/rebundler.rb
CHANGED
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rebundler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dennis Paagman
|
|
@@ -25,13 +25,15 @@ files:
|
|
|
25
25
|
- lib/bundler/rebundle.rb
|
|
26
26
|
- lib/rebundler.rb
|
|
27
27
|
- lib/rebundler/Rakefile
|
|
28
|
-
- lib/rebundler/
|
|
28
|
+
- lib/rebundler/formatter.rb
|
|
29
|
+
- lib/rebundler/gem_declaration.rb
|
|
29
30
|
- lib/rebundler/gem_set.rb
|
|
30
31
|
- lib/rebundler/parser.rb
|
|
31
32
|
- lib/rebundler/serializer.rb
|
|
33
|
+
- lib/rebundler/summarizer.rb
|
|
32
34
|
- lib/rebundler/version.rb
|
|
33
35
|
- lib/rebundler/visitor.rb
|
|
34
|
-
-
|
|
36
|
+
- mise.toml
|
|
35
37
|
- plugins.rb
|
|
36
38
|
homepage: https://github.com/dennispaagman/rebundler
|
|
37
39
|
licenses:
|
|
@@ -55,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
55
57
|
- !ruby/object:Gem::Version
|
|
56
58
|
version: '0'
|
|
57
59
|
requirements: []
|
|
58
|
-
rubygems_version:
|
|
60
|
+
rubygems_version: 4.0.3
|
|
59
61
|
specification_version: 4
|
|
60
62
|
summary: Rebundler makes your Gemfile look good.
|
|
61
63
|
test_files: []
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Rebundler
|
|
4
|
-
class GemFetcher
|
|
5
|
-
class << self
|
|
6
|
-
def parse_gem(node)
|
|
7
|
-
return unless node.type == :call_node && SORTABLE_NODES.include?(node.name)
|
|
8
|
-
|
|
9
|
-
gem_name = node.arguments.child_nodes[0].content
|
|
10
|
-
|
|
11
|
-
find_gem(gem_name).merge(node:)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def find_gem(name)
|
|
17
|
-
summary = find_loaded_gem_summary(name) || find_external_gem_summary(name)
|
|
18
|
-
|
|
19
|
-
{ name:, summary: }
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def find_loaded_gem_summary(name)
|
|
23
|
-
gem = Gem::Specification.find_by_name(name)
|
|
24
|
-
|
|
25
|
-
gem.summary
|
|
26
|
-
rescue Gem::MissingSpecError
|
|
27
|
-
nil
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def find_external_gem_summary(name)
|
|
31
|
-
spec = Gem::SpecFetcher.fetcher.spec_for_dependency Gem::Dependency.new(name)
|
|
32
|
-
|
|
33
|
-
return unless spec
|
|
34
|
-
# SpecFetcher returns [[], []] when gem exists but has no versions available
|
|
35
|
-
return if spec == [[], []]
|
|
36
|
-
|
|
37
|
-
spec.first.first.first.summary
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|