@@ -4,6 +4,8 @@ module Solargraph
4
4
# A collection of pins generated from required gems.
5
5
#
6
6
class DocMap
7
+ include Logging
8
+
7
9
# @return [Array<String>]
8
10
attr_reader :requires
9
11
@@ -28,12 +30,12 @@ def initialize(requires, preferences, rbs_path = nil)
28
30
29
31
# @return [Array<Gem::Specification>]
30
32
def gemspecs
31
- @gemspecs ||= required_gem_map . values . compact
33
+ @gemspecs ||= required_gems_map . values . compact . flatten
32
34
end
33
35
34
36
# @return [Array<String>]
35
37
def unresolved_requires
36
- @unresolved_requires ||= required_gem_map . select { |_ , gemspec | gemspec . nil? } . keys
38
+ @unresolved_requires ||= required_gems_map . select { |_ , gemspecs | gemspecs . nil? } . keys
37
39
end
38
40
39
41
# @return [Hash{Gem::Specification => Array[Pin::Base]}]
@@ -52,20 +54,22 @@ def dependencies
52
54
def generate
53
55
@pins = [ ]
54
56
@uncached_gemspecs = [ ]
55
- required_gem_map . each do |path , gemspec |
56
- if gemspec
57
- try_cache gemspec
58
- else
57
+ required_gems_map . each do |path , gemspecs |
58
+ if gemspecs . nil?
59
59
try_stdlib_map path
60
+ else
61
+ gemspecs . each do |gemspec |
62
+ try_cache gemspec
63
+ end
60
64
end
61
65
end
62
66
dependencies . each { |dep | try_cache dep }
63
67
@uncached_gemspecs . uniq!
64
68
end
65
69
66
- # @return [Hash{String => Gem::Specification, nil }]
67
- def required_gem_map
68
- @required_gem_map ||= requires . to_h { |path | [ path , resolve_path_to_gemspec ( path ) ] }
70
+ # @return [Hash{String => Array< Gem::Specification> }]
71
+ def required_gems_map
72
+ @required_gems_map ||= requires . to_h { |path | [ path , resolve_path_to_gemspecs ( path ) ] }
69
73
end
70
74
71
75
# @return [Hash{String => Gem::Specification}]
@@ -125,10 +129,26 @@ def update_from_collection gemspec, gempins
125
129
end
126
130
127
131
# @param path [String]
128
- # @return [Gem::Specification, nil]
129
- def resolve_path_to_gemspec path
132
+ # @return [::Array< Gem::Specification> , nil]
133
+ def resolve_path_to_gemspecs path
130
134
return nil if path . empty?
131
135
136
+ if path == 'bundler/require'
137
+ # find only the gems bundler is now using
138
+ gemspecs = Bundler . definition . locked_gems . specs . flat_map do |lazy_spec |
139
+ logger . info "Handling #{ lazy_spec . name } :#{ lazy_spec . version } from #{ path } "
140
+ [ Gem ::Specification . find_by_name ( lazy_spec . name , lazy_spec . version ) ]
141
+ rescue Gem ::MissingSpecError => e
142
+ logger . info ( "Could not find #{ lazy_spec . name } :#{ lazy_spec . version } with find_by_name, falling back to guess" )
143
+ # can happen in local filesystem references
144
+ specs = resolve_path_to_gemspecs lazy_spec . name
145
+ logger . info "Gem #{ lazy_spec . name } #{ lazy_spec . version } from bundle not found: #{ e } " if specs . nil?
146
+ next specs
147
+ end . compact
148
+
149
+ return gemspecs
150
+ end
151
+
132
152
gemspec = Gem ::Specification . find_by_path ( path )
133
153
if gemspec . nil?
134
154
gem_name_guess = path . split ( '/' ) . first
@@ -142,16 +162,17 @@ def resolve_path_to_gemspec path
142
162
gemspec = potential_gemspec if potential_gemspec . files . any? { |gemspec_file | file == gemspec_file }
143
163
rescue Gem ::MissingSpecError
144
164
Solargraph . logger . debug "Require path #{ path } could not be resolved to a gem via find_by_path or guess of #{ gem_name_guess } "
145
- nil
165
+ [ ]
146
166
end
147
167
end
148
- gemspec_or_preference gemspec
168
+ return nil if gemspec . nil?
169
+ [ gemspec_or_preference ( gemspec ) ]
149
170
end
150
171
151
- # @param gemspec [Gem::Specification, nil ]
152
- # @return [Gem::Specification, nil ]
172
+ # @param gemspec [Gem::Specification]
173
+ # @return [Gem::Specification]
153
174
def gemspec_or_preference gemspec
154
- return gemspec unless gemspec && preference_map . key? ( gemspec . name )
175
+ return gemspec unless preference_map . key? ( gemspec . name )
155
176
return gemspec if gemspec . version == preference_map [ gemspec . name ] . version
156
177
157
178
change_gemspec_version gemspec , preference_map [ by_path . name ] . version
@@ -170,12 +191,15 @@ def change_gemspec_version gemspec, version
170
191
# @param gemspec [Gem::Specification]
171
192
# @return [Array<Gem::Specification>]
172
193
def fetch_dependencies gemspec
194
+ # @param spec [Gem::Dependency]
173
195
only_runtime_dependencies ( gemspec ) . each_with_object ( Set . new ) do |spec , deps |
174
196
Solargraph . logger . info "Adding #{ spec . name } dependency for #{ gemspec . name } "
175
- dep = Gem ::Specification . find_by_name ( spec . name , spec . requirement )
197
+ dep = Gem . loaded_specs [ spec . name ]
198
+ # @todo is next line necessary?
199
+ dep ||= Gem ::Specification . find_by_name ( spec . name , spec . requirement )
176
200
deps . merge fetch_dependencies ( dep ) if deps . add? ( dep )
177
201
rescue Gem ::MissingSpecError
178
- Solargraph . logger . warn "Gem dependency #{ spec . name } #{ spec . requirements } for #{ gemspec . name } not found."
202
+ Solargraph . logger . warn "Gem dependency #{ spec . name } #{ spec . requirement } for #{ gemspec . name } not found."
179
203
end . to_a
180
204
end
181
205
0 commit comments