@@ -10,8 +10,8 @@ def self.build
1010 i
1111 end
1212
13- attr_reader :specs , :all_specs , :sources
14- protected :specs , :all_specs
13+ attr_reader :specs , :duplicates , :sources
14+ protected :specs , :duplicates
1515
1616 RUBY = "ruby"
1717 NULL = "\0 "
@@ -20,20 +20,20 @@ def initialize
2020 @sources = [ ]
2121 @cache = { }
2222 @specs = Hash . new { |h , k | h [ k ] = { } }
23- @all_specs = Hash . new { | h , k | h [ k ] = EMPTY_SEARCH }
23+ @duplicates = { }
2424 end
2525
2626 def initialize_copy ( o )
2727 @sources = o . sources . dup
2828 @cache = { }
2929 @specs = Hash . new { |h , k | h [ k ] = { } }
30- @all_specs = Hash . new { | h , k | h [ k ] = EMPTY_SEARCH }
30+ @duplicates = { }
3131
3232 o . specs . each do |name , hash |
3333 @specs [ name ] = hash . dup
3434 end
35- o . all_specs . each do |name , array |
36- @all_specs [ name ] = array . dup
35+ o . duplicates . each do |name , array |
36+ @duplicates [ name ] = array . dup
3737 end
3838 end
3939
@@ -47,7 +47,9 @@ def empty?
4747 end
4848
4949 def search_all ( name )
50- all_matches = local_search ( name ) + @all_specs [ name ]
50+ all_matches = specs_by_name ( name ) # always returns a new Array
51+ dupes = @duplicates [ name ]
52+ all_matches . concat ( dupes ) if dupes
5153 @sources . each do |source |
5254 all_matches . concat ( source . search_all ( name ) )
5355 end
@@ -78,10 +80,11 @@ def local_search(query)
7880
7981 alias_method :[] , :search
8082
81- def << ( spec )
83+ def add ( spec )
8284 @specs [ spec . name ] [ spec . full_name ] = spec
8385 spec
8486 end
87+ alias_method :<< , :add
8588
8689 def each ( &blk )
8790 return enum_for ( :each ) unless blk
@@ -115,15 +118,25 @@ def dependency_names
115118 names . uniq
116119 end
117120
118- def use ( other , override_dupes = false )
121+ # Combines indexes proritizing existing specs, like `Hash#reverse_merge!`
122+ # Duplicate specs found in `other` are stored in `@duplicates`.
123+ def use ( other )
119124 return unless other
120- other . each do |s |
121- if ( dupes = search_by_spec ( s ) ) && !dupes . empty?
122- # safe to << since it's a new array when it has contents
123- @all_specs [ s . name ] = dupes << s
124- next unless override_dupes
125+ other . each do |spec |
126+ exist? ( spec ) ? add_duplicate ( spec ) : add ( spec )
127+ end
128+ self
129+ end
130+
131+ # Combines indexes proritizing specs from `other`, like `Hash#merge!`
132+ # Duplicate specs found in `self` are saved in `@duplicates`.
133+ def merge! ( other )
134+ return unless other
135+ other . each do |spec |
136+ if existing = find_by_spec ( spec )
137+ add_duplicate ( existing )
125138 end
126- self << s
139+ add spec
127140 end
128141 self
129142 end
@@ -157,6 +170,10 @@ def add_source(index)
157170
158171 private
159172
173+ def add_duplicate ( spec )
174+ ( @duplicates [ spec . name ] ||= [ ] ) << spec
175+ end
176+
160177 def specs_by_name_and_version ( name , version )
161178 specs_by_name ( name ) . select { |spec | spec . version == version }
162179 end
@@ -168,8 +185,16 @@ def specs_by_name(name)
168185 EMPTY_SEARCH = [ ] . freeze
169186
170187 def search_by_spec ( spec )
171- spec = @specs [ spec . name ] [ spec . full_name ]
188+ spec = find_by_spec ( spec )
172189 spec ? [ spec ] : EMPTY_SEARCH
173190 end
191+
192+ def find_by_spec ( spec )
193+ @specs [ spec . name ] [ spec . full_name ]
194+ end
195+
196+ def exist? ( spec )
197+ @specs [ spec . name ] . key? ( spec . full_name )
198+ end
174199 end
175200end
0 commit comments