steep 1.8.3 → 1.9.0.dev.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -22
  3. data/Steepfile +0 -14
  4. data/lib/steep/cli.rb +47 -5
  5. data/lib/steep/diagnostic/ruby.rb +1 -58
  6. data/lib/steep/drivers/annotations.rb +1 -1
  7. data/lib/steep/drivers/check.rb +107 -1
  8. data/lib/steep/drivers/checkfile.rb +10 -8
  9. data/lib/steep/drivers/print_project.rb +83 -40
  10. data/lib/steep/drivers/utils/driver_helper.rb +5 -3
  11. data/lib/steep/drivers/watch.rb +24 -2
  12. data/lib/steep/index/signature_symbol_provider.rb +8 -8
  13. data/lib/steep/interface/builder.rb +14 -1
  14. data/lib/steep/interface/function.rb +2 -2
  15. data/lib/steep/path_helper.rb +4 -2
  16. data/lib/steep/project/dsl.rb +176 -151
  17. data/lib/steep/project/group.rb +31 -0
  18. data/lib/steep/project/target.rb +32 -6
  19. data/lib/steep/project.rb +38 -10
  20. data/lib/steep/server/delay_queue.rb +0 -3
  21. data/lib/steep/server/interaction_worker.rb +2 -11
  22. data/lib/steep/server/master.rb +93 -278
  23. data/lib/steep/server/target_group_files.rb +205 -0
  24. data/lib/steep/server/type_check_controller.rb +322 -0
  25. data/lib/steep/server/type_check_worker.rb +60 -86
  26. data/lib/steep/services/file_loader.rb +23 -0
  27. data/lib/steep/services/goto_service.rb +40 -31
  28. data/lib/steep/services/hover_provider/singleton_methods.rb +4 -4
  29. data/lib/steep/services/path_assignment.rb +23 -4
  30. data/lib/steep/services/type_check_service.rb +76 -159
  31. data/lib/steep/signature/validator.rb +4 -4
  32. data/lib/steep/subtyping/check.rb +2 -2
  33. data/lib/steep/thread_waiter.rb +24 -16
  34. data/lib/steep/type_construction.rb +1 -1
  35. data/lib/steep/type_inference/block_params.rb +1 -2
  36. data/lib/steep/type_inference/context.rb +1 -1
  37. data/lib/steep/type_inference/type_env.rb +4 -4
  38. data/lib/steep/type_inference/type_env_builder.rb +1 -1
  39. data/lib/steep/version.rb +1 -1
  40. data/lib/steep.rb +6 -4
  41. data/sample/Steepfile +6 -0
  42. data/sample/lib/conference.rb +1 -5
  43. data/steep.gemspec +7 -1
  44. metadata +8 -6
  45. data/lib/steep/drivers/validate.rb +0 -65
@@ -8,9 +8,9 @@ module Steep
8
8
  WorkspaceSymbolJob = _ = Struct.new(:query, :id, keyword_init: true)
9
9
  StatsJob = _ = Struct.new(:id, keyword_init: true)
10
10
  StartTypeCheckJob = _ = Struct.new(:guid, :changes, keyword_init: true)
11
- TypeCheckCodeJob = _ = Struct.new(:guid, :path, keyword_init: true)
12
- ValidateAppSignatureJob = _ = Struct.new(:guid, :path, keyword_init: true)
13
- ValidateLibrarySignatureJob = _ = Struct.new(:guid, :path, keyword_init: true)
11
+ TypeCheckCodeJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
12
+ ValidateAppSignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
13
+ ValidateLibrarySignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
14
14
  class GotoJob < Struct.new(:id, :kind, :params, keyword_init: true)
15
15
  def self.implementation(id:, params:)
16
16
  new(
@@ -111,51 +111,47 @@ module Steep
111
111
  queue << StartTypeCheckJob.new(guid: guid, changes: changes)
112
112
  end
113
113
 
114
- priority_paths = Set.new(params[:priority_uris].map {|uri| Steep::PathHelper.to_pathname(uri) || raise })
115
- library_paths = params[:library_uris].map {|uri| Steep::PathHelper.to_pathname(uri) || raise }
116
- signature_paths = params[:signature_uris].map {|uri| Steep::PathHelper.to_pathname(uri) || raise }
117
- code_paths = params[:code_uris].map {|uri| Steep::PathHelper.to_pathname(uri) || raise }
114
+ targets = project.targets.each.with_object({}) do |target, hash| #$ Hash[String, Project::Target]
115
+ hash[target.name.to_s] = target
116
+ end
118
117
 
119
- library_paths.each do |path|
120
- if priority_paths.include?(path)
121
- Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}" }
122
- queue << ValidateLibrarySignatureJob.new(guid: guid, path: path)
123
- end
118
+ priority_paths = Set.new(params[:priority_uris].map {|uri| Steep::PathHelper.to_pathname!(uri) })
119
+ libraries = params[:library_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
120
+ signatures = params[:signature_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
121
+ codes = params[:code_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
122
+
123
+ priority_libs, non_priority_libs = libraries.partition {|_, path| priority_paths.include?(path) }
124
+ priority_sigs, non_priority_sigs = signatures.partition {|_, path| priority_paths.include?(path) }
125
+ priority_codes, non_priority_codes = codes.partition {|_, path| priority_paths.include?(path) }
126
+
127
+ priority_codes.each do |target, path|
128
+ Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
129
+ queue << TypeCheckCodeJob.new(guid: guid, path: path, target: target)
124
130
  end
125
131
 
126
- code_paths.each do |path|
127
- if priority_paths.include?(path)
128
- Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}" }
129
- queue << TypeCheckCodeJob.new(guid: guid, path: path)
130
- end
132
+ priority_sigs.each do |target, path|
133
+ Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
134
+ queue << ValidateAppSignatureJob.new(guid: guid, path: path, target: target)
131
135
  end
132
136
 
133
- signature_paths.each do |path|
134
- if priority_paths.include?(path)
135
- Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}" }
136
- queue << ValidateAppSignatureJob.new(guid: guid, path: path)
137
- end
137
+ priority_libs.each do |target, path|
138
+ Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
139
+ queue << ValidateLibrarySignatureJob.new(guid: guid, path: path, target: target)
138
140
  end
139
141
 
140
- library_paths.each do |path|
141
- unless priority_paths.include?(path)
142
- Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}" }
143
- queue << ValidateLibrarySignatureJob.new(guid: guid, path: path)
144
- end
142
+ non_priority_codes.each do |target, path|
143
+ Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
144
+ queue << TypeCheckCodeJob.new(guid: guid, path: path, target: target)
145
145
  end
146
146
 
147
- code_paths.each do |path|
148
- unless priority_paths.include?(path)
149
- Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}" }
150
- queue << TypeCheckCodeJob.new(guid: guid, path: path)
151
- end
147
+ non_priority_sigs.each do |target, path|
148
+ Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
149
+ queue << ValidateAppSignatureJob.new(guid: guid, path: path, target: target)
152
150
  end
153
151
 
154
- signature_paths.each do |path|
155
- unless priority_paths.include?(path)
156
- Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}" }
157
- queue << ValidateAppSignatureJob.new(guid: guid, path: path)
158
- end
152
+ non_priority_libs.each do |target, path|
153
+ Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
154
+ queue << ValidateLibrarySignatureJob.new(guid: guid, path: path, target: target)
159
155
  end
160
156
  end
161
157
 
@@ -168,60 +164,37 @@ module Steep
168
164
  when ValidateAppSignatureJob
169
165
  if job.guid == current_type_check_guid
170
166
  Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
171
- service.validate_signature(path: project.relative_path(job.path)) do |path, diagnostics|
172
- formatter = Diagnostic::LSPFormatter.new({}, **{})
173
-
174
- writer.write(
175
- method: :"textDocument/publishDiagnostics",
176
- params: LSP::Interface::PublishDiagnosticsParams.new(
177
- uri: Steep::PathHelper.to_uri(job.path).to_s,
178
- diagnostics: diagnostics.map {|diagnostic|
179
- _ = formatter.format(diagnostic)
180
- }.uniq
181
- )
182
- )
183
- end
184
167
 
185
- typecheck_progress(path: job.path, guid: job.guid)
168
+ formatter = Diagnostic::LSPFormatter.new({}, **{})
169
+
170
+ diagnostics = service.validate_signature(path: project.relative_path(job.path), target: job.target)
171
+
172
+ typecheck_progress(
173
+ path: job.path,
174
+ guid: job.guid,
175
+ target: job.target,
176
+ diagnostics: diagnostics.filter_map { formatter.format(_1) }
177
+ )
186
178
  end
187
179
 
188
180
  when ValidateLibrarySignatureJob
189
181
  if job.guid == current_type_check_guid
190
182
  Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
191
- service.validate_signature(path: job.path) do |path, diagnostics|
192
- formatter = Diagnostic::LSPFormatter.new({}, **{})
193
-
194
- writer.write(
195
- method: :"textDocument/publishDiagnostics",
196
- params: LSP::Interface::PublishDiagnosticsParams.new(
197
- uri: Steep::PathHelper.to_uri(job.path).to_s,
198
- diagnostics: diagnostics.map {|diagnostic| _ = formatter.format(diagnostic) }.uniq.compact
199
- )
200
- )
201
- end
202
183
 
203
- typecheck_progress(path: job.path, guid: job.guid)
184
+ formatter = Diagnostic::LSPFormatter.new({}, **{})
185
+ diagnostics = service.validate_signature(path: job.path, target: job.target)
186
+
187
+ typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics.filter_map { formatter.format(_1) })
204
188
  end
205
189
 
206
190
  when TypeCheckCodeJob
207
191
  if job.guid == current_type_check_guid
208
- Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}" }
209
- service.typecheck_source(path: project.relative_path(job.path)) do |path, diagnostics|
210
- target = project.target_for_source_path(path)
211
- formatter = Diagnostic::LSPFormatter.new(target&.code_diagnostics_config || {})
212
-
213
- writer.write(
214
- method: :"textDocument/publishDiagnostics",
215
- params: LSP::Interface::PublishDiagnosticsParams.new(
216
- uri: Steep::PathHelper.to_uri(job.path).to_s,
217
- diagnostics: diagnostics.map {|diagnostic|
218
- _ = formatter.format(diagnostic)
219
- }.uniq.compact
220
- )
221
- )
222
- end
223
-
224
- typecheck_progress(path: job.path, guid: job.guid)
192
+ Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}, target=#{job.target.name}" }
193
+ group_target = project.group_for_source_path(job.path) || job.target
194
+ formatter = Diagnostic::LSPFormatter.new(group_target.code_diagnostics_config)
195
+ relative_path = project.relative_path(job.path)
196
+ diagnostics = service.typecheck_source(path: relative_path, target: job.target)
197
+ typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics&.filter_map { formatter.format(_1) })
225
198
  end
226
199
 
227
200
  when WorkspaceSymbolJob
@@ -242,16 +215,17 @@ module Steep
242
215
  end
243
216
  end
244
217
 
245
- def typecheck_progress(guid:, path:)
246
- writer.write(CustomMethods::TypeCheck__Progress.notification({ guid: guid, path: path.to_s }))
218
+ def typecheck_progress(guid:, path:, target:, diagnostics:)
219
+ writer.write(CustomMethods::TypeCheck__Progress.notification({ guid: guid, path: path.to_s, target: target.name.to_s, diagnostics: diagnostics }))
247
220
  end
248
221
 
249
222
  def workspace_symbol_result(query)
250
223
  Steep.measure "Generating workspace symbol list for query=`#{query}`" do
251
- indexes = project.targets.map {|target| service.signature_services[target.name].latest_rbs_index }
252
-
253
224
  provider = Index::SignatureSymbolProvider.new(project: project, assignment: assignment)
254
- provider.indexes.push(*indexes)
225
+ project.targets.each do |target|
226
+ index = service.signature_services[target.name].latest_rbs_index
227
+ provider.indexes[target] = index
228
+ end
255
229
 
256
230
  symbols = provider.query_symbol(query)
257
231
 
@@ -282,7 +256,7 @@ module Steep
282
256
  service.source_files.each_value do |file|
283
257
  next unless target.possible_source_file?(file.path)
284
258
  absolute_path = project.absolute_path(file.path)
285
- next unless assignment =~ absolute_path
259
+ next unless assignment =~ [target, absolute_path]
286
260
 
287
261
  stats << calculator.calc_stats(target, file: file)
288
262
  end
@@ -7,6 +7,29 @@ module Steep
7
7
  @base_dir = base_dir
8
8
  end
9
9
 
10
+ def each_path_in_target(target, command_line_patterns = [], &block)
11
+ if block
12
+ done = Set[] #: Set[Pathname]
13
+
14
+ handler = -> (path) do
15
+ unless done.include?(path)
16
+ done << path
17
+ yield path
18
+ end
19
+ end
20
+
21
+ target.groups.each do |group|
22
+ each_path_in_patterns(group.source_pattern, command_line_patterns, &handler)
23
+ each_path_in_patterns(group.signature_pattern, &handler)
24
+ end
25
+
26
+ each_path_in_patterns(target.source_pattern, command_line_patterns, &handler)
27
+ each_path_in_patterns(target.signature_pattern, &handler)
28
+ else
29
+ enum_for :each_path_in_target, target, command_line_patterns
30
+ end
31
+ end
32
+
10
33
  def each_path_in_patterns(pattern, commandline_patterns = [])
11
34
  if block_given?
12
35
  pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
@@ -34,7 +34,7 @@ module Steep
34
34
  end
35
35
 
36
36
  def implementation(path:, line:, column:)
37
- locations = [] #: Array[loc]
37
+ locations = [] #: Array[target_loc]
38
38
 
39
39
  queries = query_at(path: path, line: line, column: column)
40
40
  queries.uniq!
@@ -46,15 +46,15 @@ module Steep
46
46
  when MethodQuery
47
47
  method_locations(query.name, locations: locations, in_ruby: true, in_rbs: false)
48
48
  when TypeNameQuery
49
- type_name_locations(query.name, locations: locations)
49
+ constant_definition_in_ruby(query.name, locations: locations)
50
50
  end
51
51
  end
52
52
 
53
- locations.uniq
53
+ locations.map { _1[1] }.uniq
54
54
  end
55
55
 
56
56
  def definition(path:, line:, column:)
57
- locations = [] #: Array[loc]
57
+ locations = [] #: Array[target_loc]
58
58
 
59
59
  queries = query_at(path: path, line: line, column: column)
60
60
  queries.uniq!
@@ -79,22 +79,24 @@ module Steep
79
79
  # Drop un-assigned paths here.
80
80
  # The path assignment makes sense only for `.rbs` files, because un-assigned `.rb` files are already skipped since they are not type checked.
81
81
  #
82
- locations.uniq.select do |loc|
82
+ locations.filter_map do |target, loc|
83
83
  case loc
84
84
  when RBS::Location
85
- assignment =~ loc.name
85
+ if assignment =~ [target, loc.name]
86
+ loc
87
+ end
86
88
  else
87
- true
89
+ loc
88
90
  end
89
- end
91
+ end.uniq
90
92
  end
91
93
 
92
94
  def type_definition(path:, line:, column:)
93
- locations = [] #: Array[loc]
95
+ locations = [] #: Array[target_loc]
94
96
 
95
97
  relative_path = project.relative_path(path)
96
98
 
97
- target = type_check.source_file?(relative_path) or return []
99
+ target = type_check.project.target_for_path(relative_path) or return []
98
100
  source = type_check.source_files[relative_path]
99
101
  typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
100
102
 
@@ -112,14 +114,16 @@ module Steep
112
114
  type_name_locations(name, locations: locations)
113
115
  end
114
116
 
115
- locations.uniq.select do |loc|
117
+ locations.filter_map do |target, loc|
116
118
  case loc
117
119
  when RBS::Location
118
- assignment =~ loc.name
120
+ if assignment =~ [target, loc.name]
121
+ loc
122
+ end
119
123
  else
120
- true
124
+ loc
121
125
  end
122
- end
126
+ end.uniq
123
127
  end
124
128
 
125
129
  def each_type_name(type, &block)
@@ -158,8 +162,8 @@ module Steep
158
162
  relative_path = project.relative_path(path)
159
163
 
160
164
  case
161
- when target = type_check.source_file?(relative_path)
162
- source = type_check.source_files[relative_path]
165
+ when target = type_check.project.target_for_source_path(relative_path)
166
+ source = type_check.source_files[relative_path] or return []
163
167
  typing, _signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
164
168
  if typing
165
169
  node, *parents = typing.source.find_nodes(line: line, column: column)
@@ -295,23 +299,24 @@ module Steep
295
299
  end
296
300
 
297
301
  def constant_definition_in_rbs(name, locations:)
298
- type_check.signature_services.each_value do |signature|
302
+ project.targets.each do |target|
303
+ signature = type_check.signature_services.fetch(target.name)
299
304
  env = signature.latest_env #: RBS::Environment
300
305
 
301
306
  case entry = env.constant_entry(name)
302
307
  when RBS::Environment::ConstantEntry
303
308
  if entry.decl.location
304
- locations << entry.decl.location[:name]
309
+ locations << [target, entry.decl.location[:name]]
305
310
  end
306
311
  when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
307
312
  entry.decls.each do |d|
308
313
  if d.decl.location
309
- locations << d.decl.location[:name]
314
+ locations << [target, d.decl.location[:name]]
310
315
  end
311
316
  end
312
317
  when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
313
318
  if entry.decl.location
314
- locations << entry.decl.location[:new_name]
319
+ locations << [target, entry.decl.location[:new_name]]
315
320
  end
316
321
  end
317
322
  end
@@ -322,11 +327,12 @@ module Steep
322
327
  def constant_definition_in_ruby(name, locations:)
323
328
  type_check.source_files.each do |path, source|
324
329
  if typing = source.typing
330
+ target = project.target_for_source_path(path) or raise
325
331
  entry = typing.source_index.entry(constant: name)
326
332
  entry.definitions.each do |node|
327
333
  case node.type
328
334
  when :const
329
- locations << node.location.expression
335
+ locations << [target, node.location.expression]
330
336
  when :casgn
331
337
  parent = node.children[0]
332
338
  location =
@@ -335,7 +341,7 @@ module Steep
335
341
  else
336
342
  node.location.name
337
343
  end
338
- locations << location
344
+ locations << [target, location]
339
345
  end
340
346
  end
341
347
  end
@@ -348,6 +354,7 @@ module Steep
348
354
  if in_ruby
349
355
  type_check.source_files.each do |path, source|
350
356
  if typing = source.typing
357
+ target = project.target_for_source_path(path) or raise
351
358
  entry = typing.source_index.entry(method: name)
352
359
 
353
360
  if entry.definitions.empty?
@@ -360,9 +367,9 @@ module Steep
360
367
  entry.definitions.each do |node|
361
368
  case node.type
362
369
  when :def
363
- locations << node.location.name
370
+ locations << [target, node.location.name]
364
371
  when :defs
365
- locations << node.location.name
372
+ locations << [target, node.location.name]
366
373
  end
367
374
  end
368
375
  end
@@ -370,7 +377,8 @@ module Steep
370
377
  end
371
378
 
372
379
  if in_rbs
373
- type_check.signature_services.each_value do |signature|
380
+ project.targets.each do |target|
381
+ signature = type_check.signature_services.fetch(target.name)
374
382
  index = signature.latest_rbs_index
375
383
 
376
384
  entry = index.entry(method_name: name)
@@ -386,15 +394,15 @@ module Steep
386
394
  case decl
387
395
  when RBS::AST::Members::MethodDefinition
388
396
  if decl.location
389
- locations << decl.location[:name]
397
+ locations << [target, decl.location[:name]]
390
398
  end
391
399
  when RBS::AST::Members::Alias
392
400
  if decl.location
393
- locations << decl.location[:new_name]
401
+ locations << [target, decl.location[:new_name]]
394
402
  end
395
403
  when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
396
404
  if decl.location
397
- locations << decl.location[:name]
405
+ locations << [target, decl.location[:name]]
398
406
  end
399
407
  end
400
408
  end
@@ -405,7 +413,8 @@ module Steep
405
413
  end
406
414
 
407
415
  def type_name_locations(name, locations: [])
408
- type_check.signature_services.each_value do |signature|
416
+ project.targets.each do |target|
417
+ signature = type_check.signature_services.fetch(target.name)
409
418
  index = signature.latest_rbs_index
410
419
 
411
420
  entry = index.entry(type_name: name)
@@ -413,11 +422,11 @@ module Steep
413
422
  case decl
414
423
  when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface, RBS::AST::Declarations::TypeAlias
415
424
  if decl.location
416
- locations << decl.location[:name]
425
+ locations << [target, decl.location[:name]]
417
426
  end
418
427
  when RBS::AST::Declarations::AliasDecl
419
428
  if decl.location
420
- locations << decl.location[:new_name]
429
+ locations << [target, decl.location[:new_name]]
421
430
  end
422
431
  else
423
432
  raise
@@ -5,11 +5,11 @@ module Steep
5
5
  def content_for(service:, path:, line:, column:)
6
6
  project = service.project
7
7
 
8
- case (target = project.targets_for_path(path))
9
- when Project::Target
8
+ case
9
+ when target = project.target_for_source_path(path)
10
10
  Ruby.new(service: service).content_for(target: target, path: path, line: line, column: column)
11
- when Array
12
- RBS.new(service: service).content_for(target: target[0], path: path, line: line, column: column)
11
+ when target = project.target_for_signature_path(path)
12
+ RBS.new(service: service).content_for(target: target, path: path, line: line, column: column)
13
13
  end
14
14
  end
15
15
  end
@@ -13,14 +13,33 @@ module Steep
13
13
  new(index: 0, max_index: 1)
14
14
  end
15
15
 
16
- def =~(path)
17
- (cache[path] ||= self.class.index_for(path: path.to_s, max_index: max_index)) == index
16
+ def =~(target_path)
17
+ key = stringify(target_path)
18
+ (cache[key] ||= self.class.index_for(key: key, max_index: max_index)) == index
18
19
  end
19
20
 
20
21
  alias === =~
21
22
 
22
- def self.index_for(path:, max_index:)
23
- Digest::MD5.hexdigest(path).hex % max_index
23
+ def assign!(path, index)
24
+ key = stringify(path)
25
+ cache[key] = index
26
+ self
27
+ end
28
+
29
+ def stringify(target_path)
30
+ target =
31
+ case target_path[0]
32
+ when Project::Target
33
+ target_path[0].name.to_s
34
+ else
35
+ target_path[0].to_s
36
+ end
37
+ path = target_path[1].to_s
38
+ "#{target}::#{path}"
39
+ end
40
+
41
+ def self.index_for(key:, max_index:)
42
+ Digest::MD5.hexdigest(key).hex % max_index
24
43
  end
25
44
  end
26
45
  end