rubylens 0.2.0 → 0.2.1

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.
@@ -2,65 +2,75 @@
2
2
 
3
3
  require "rubydex"
4
4
  require "set"
5
- require_relative "../model/dependency_aggregation"
5
+ require_relative "constant_reference_collector"
6
+ require_relative "declaration_collector"
7
+ require_relative "location_index"
6
8
  require_relative "rspec_extractor"
7
- require_relative "source_path"
8
9
 
9
10
  module RubyLens
10
11
  module Index
12
+ # Drives one Rubydex indexing run over the manifest and assembles the
13
+ # snapshot payload from what the collectors return.
14
+ #
15
+ # The snapshot is the privacy boundary: every namespace and dependency star
16
+ # leaves here as a row of integers, and the only strings that survive are
17
+ # namespace names, package names, and the project name.
11
18
  class RubydexAdapter
12
- TEST_SEGMENTS = %w[test tests spec specs feature features].freeze
13
- CONSTANT_REFERENCE_LINK_LIMIT = 1_024
14
- CONSTANT_REFERENCE_ATTRIBUTION_LIMIT = CONSTANT_REFERENCE_LINK_LIMIT * 2
15
-
16
- ReferenceSummary = Data.define(:inbound_counts, :links)
19
+ SCHEMA = "rubylens.snapshot.v9"
20
+ RSPEC_ROW = [0, 1, *Array.new(11, 0)].freeze
17
21
 
22
+ # The manifest is duck-typed: production passes a Manifest, tests pass
23
+ # stubs, and `index` probes it with respond_to? for the optional parts.
24
+ #
25
+ #: (untyped manifest) -> void
18
26
  def initialize(manifest)
19
27
  @manifest = manifest
20
- @source_path_cache = {}
21
- @workspace_location_cache = {}
22
- @definition_scope_by_uri = {}
23
- @package_index_by_uri = {}
24
- @indexed_package_document_paths = Set.new
28
+ @locations = LocationIndex.new(manifest)
25
29
  end
26
30
 
31
+ #: () -> Hash[String, untyped]
27
32
  def index
28
33
  graph = Rubydex::Graph.new(workspace_path: @manifest.root.to_s)
29
34
  index_errors = graph.index_all(@manifest.files)
30
- @indexed_package_document_paths, documents_with_paths = resolve_documents(graph)
35
+ # Documents resolve before `resolve` so package attribution sees exactly
36
+ # the documents Rubydex accepted, not the paths the manifest offered.
37
+ documents_with_paths = @locations.resolve_documents(graph)
31
38
  graph.resolve
32
39
  integrity_failures = graph.check_integrity
33
- collected = collect_declarations(graph.declarations)
40
+
41
+ collected = DeclarationCollector.new(manifest: @manifest, locations: @locations).call(graph.declarations)
34
42
  rspec = RSpecExtractor.new(
35
43
  graph: graph,
36
44
  manifest: @manifest,
37
- package_document_paths: @indexed_package_document_paths,
45
+ package_document_paths: @locations.package_document_paths,
38
46
  documents_with_paths: documents_with_paths,
39
47
  ).call
40
- workspace = workspace_namespaces(
41
- collected.fetch(:workspace_records),
42
- rspec.groups,
43
- collected.fetch(:workspace_definition_ranges),
44
- )
45
- reference_summary = workspace_reference_summary(
46
- graph,
47
- workspace,
48
- collected.fetch(:dependency_ordinal_by_name),
48
+
49
+ namespaces = collected.namespaces
50
+ namespace_names = namespaces.map(&:name) + rspec.groups
51
+ references = ConstantReferenceCollector.new(locations: @locations).call(
52
+ graph: graph,
53
+ namespaces: namespaces,
54
+ definition_ranges: collected.definition_ranges,
55
+ ordinal_by_name: ordinal_by_name(namespaces),
56
+ dependency_ordinal_by_name: collected.dependency_ordinal_by_name,
57
+ namespace_count: namespace_names.length,
49
58
  )
50
- category_stats = collected.fetch(:category_stats)
59
+
60
+ category_stats = collected.category_stats
51
61
  category_stats.fetch("tests")[0] += rspec.groups.length
52
62
  category_stats.fetch("tests")[2] += rspec.method_count
53
63
 
54
64
  {
55
- "schema" => "rubylens.snapshot.v9",
65
+ "schema" => SCHEMA,
56
66
  "project_name" => project_name,
57
- "namespace_names" => workspace.fetch(:namespace_names),
58
- "namespaces" => build_workspace_rows(workspace, reference_summary.inbound_counts),
59
- "constant_reference_links" => reference_summary.links,
67
+ "namespace_names" => namespace_names,
68
+ "namespaces" => namespace_rows(namespaces, references.inbound_counts, rspec.groups.length),
69
+ "constant_reference_links" => references.links,
60
70
  "category_stats" => category_stats,
61
- "dependency_signal_maxima" => collected.fetch(:dependency_signal_maxima),
62
- "packages" => build_package_rows(collected.fetch(:dependency_packages)),
63
- "dependency_systems" => build_dependency_system_rows,
71
+ "dependency_signal_maxima" => collected.dependency_signal_maxima,
72
+ "packages" => package_rows(collected.dependency_packages),
73
+ "dependency_systems" => dependency_system_rows,
64
74
  "dependency_warnings" => @manifest.respond_to?(:dependency_warnings) ? @manifest.dependency_warnings : [],
65
75
  "warning_counts" => {
66
76
  "manifest" => @manifest.warnings.length,
@@ -72,162 +82,86 @@ module RubyLens
72
82
 
73
83
  private
74
84
 
75
- def collect_declarations(declarations)
76
- records = []
77
- category_stats = { "core" => Array.new(4, 0), "tests" => Array.new(4, 0) }
78
- aggregation = Model::DependencyAggregation.new(package_count: @manifest.packages.length)
79
- workspace_definition_ranges = Hash.new { |hash, uri| hash[uri] = [] }
80
- dependency_positions = {}
81
-
82
- declarations.each do |declaration|
83
- name = declaration.name
84
- next unless model_eligible_declaration?(declaration, name)
85
-
86
- is_namespace = declaration.is_a?(Rubydex::Namespace)
87
- construct_index = ruby_construct_index(declaration)
88
- workspace_count, tests_only, canonical_site_keys, canonical_scope, package_site_keys =
89
- summarize_definitions(declaration, is_namespace)
90
- reference_count = safe_length(declaration, :references) if package_site_keys
91
-
92
- if canonical_site_keys
93
- canonical_site_keys = canonical_site_keys.uniq if canonical_site_keys.length > 1
94
- ordinal = records.length
95
- canonical_site_keys.each do |uri, start_line, start_column, end_line, end_column|
96
- workspace_definition_ranges[uri] << [start_line, start_column, end_line, end_column, ordinal]
97
- end
98
- records << [declaration, canonical_site_keys.length, canonical_scope, name]
99
- end
100
- if construct_index && workspace_count.positive?
101
- category_stats.fetch(tests_only ? "tests" : "core")[construct_index] += 1
102
- end
103
- collect_dependency_declaration(
104
- aggregation,
105
- dependency_positions,
106
- declaration,
107
- name,
108
- is_namespace,
109
- construct_index,
110
- package_site_keys,
111
- reference_count,
112
- )
113
- end
114
-
115
- dependency_packages = aggregation.packages
116
- dependency_offsets = []
117
- offset = 0
118
- dependency_packages.each do |package|
119
- dependency_offsets << offset
120
- offset += package.fetch(:declarations).length
121
- end
122
- dependency_ordinal_by_name = dependency_positions.transform_values! do |position|
123
- package_index, local_index = position
124
- dependency_offsets.fetch(package_index) + local_index
125
- end
126
-
127
- {
128
- workspace_records: records,
129
- workspace_definition_ranges:,
130
- category_stats:,
131
- dependency_packages:,
132
- dependency_signal_maxima: aggregation.signal_maxima,
133
- dependency_ordinal_by_name: dependency_ordinal_by_name.freeze,
134
- }
135
- end
136
-
137
- # One pass over a declaration's definitions gathers everything the
138
- # collectors need, so each definition's location and its per-URI
139
- # workspace/scope/package answers cross the Rubydex boundary once.
140
- # Canonical site keys and package site keys stay nil until a definition
141
- # actually contributes to them, since most declarations produce neither.
142
- def summarize_definitions(declaration, is_namespace)
143
- workspace_count = 0
144
- tests_seen = false
145
- core_seen = false
146
- canonical_tests_seen = false
147
- canonical_core_seen = false
148
- canonical_site_keys = nil
149
- package_site_keys = nil
150
-
151
- declaration.definitions.each do |definition|
152
- location = definition.location
153
- site_key = nil
154
- if workspace_location?(location)
155
- workspace_count += 1
156
- scope = definition_scope(location.uri)
157
- if scope == 1
158
- tests_seen = true
159
- elsif scope
160
- core_seen = true
161
- end
162
- if is_namespace && canonical_namespace_definition?(declaration, definition)
163
- (canonical_site_keys ||= []) << (site_key = location.comparable_values)
164
- if scope == 1
165
- canonical_tests_seen = true
166
- elsif scope
167
- canonical_core_seen = true
168
- end
169
- end
170
- end
171
- package_index = package_index_for_location(location)
172
- if package_index
173
- ((package_site_keys ||= {})[package_index] ||= []) << (site_key || location.comparable_values)
174
- end
175
- end
176
-
177
- canonical_scope = canonical_tests_seen ? (canonical_core_seen ? 2 : 1) : 0
178
- [workspace_count, tests_seen && !core_seen, canonical_site_keys, canonical_scope, package_site_keys]
179
- end
180
-
181
- def workspace_namespaces(records, rspec_groups, definition_ranges = {})
182
- namespace_names = []
183
- ordinal_by_name = {}
184
- records.each_with_index do |record, index|
185
- name = record.fetch(3)
186
- namespace_names << name
187
- ordinal_by_name[name] = index
188
- end
189
- {
190
- records: records,
191
- definition_ranges: definition_ranges,
192
- rspec_groups: rspec_groups,
193
- namespace_names: namespace_names + rspec_groups,
194
- ordinal_by_name: ordinal_by_name,
195
- }
196
- end
197
-
198
- def build_workspace_rows(workspace, inbound_references)
199
- ordinal_by_name = workspace.fetch(:ordinal_by_name)
200
- rows = workspace.fetch(:records).each_with_index.map do |record, index|
201
- declaration, sites, scope, name = record
85
+ #: (Array[DeclarationCollector::Namespace]) -> Hash[String, Integer]
86
+ def ordinal_by_name(namespaces)
87
+ ordinals = {}
88
+ namespaces.each_with_index { |namespace, index| ordinals[namespace.name] = index }
89
+ ordinals
90
+ end
91
+
92
+ #: (Array[DeclarationCollector::Namespace], Hash[Integer, Integer], Integer) -> Array[Array[Integer]]
93
+ def namespace_rows(namespaces, inbound_counts, rspec_group_count)
94
+ drawn_names = ordinal_by_name(namespaces)
95
+ rows = namespaces.each_with_index.map do |namespace, index|
96
+ declaration = namespace.declaration
97
+ sites = namespace.definition_sites
98
+ # A namespace only earns a row through a class or module definition,
99
+ # so its own construct is exactly this kind.
100
+ kind = declaration.is_a?(Rubydex::Class) ? DeclarationCollector::CLASS : DeclarationCollector::MODULE
202
101
  descendants = declaration.descendants.count do |descendant|
203
- descendant_name = descendant.name
204
- descendant_name != name && ordinal_by_name.key?(descendant_name)
102
+ name = descendant.name
103
+ name != namespace.name && drawn_names.key?(name)
205
104
  end
206
- member_count, ruby_counts, instance_variable_count = member_statistics(
105
+ members, ruby_counts, instance_variables = member_statistics(
207
106
  declaration,
208
- count_instance_variables: declaration.is_a?(Rubydex::Class) && scope != 1,
107
+ kind: kind,
108
+ # Instance variables read as state on a class; test classes carry
109
+ # fixture state that would misrepresent them next to core classes.
110
+ count_instance_variables: kind == DeclarationCollector::CLASS && namespace.scope != LocationIndex::TEST,
209
111
  )
210
112
  [
211
- declaration.is_a?(Rubydex::Class) ? 0 : 1,
212
- scope,
113
+ kind,
114
+ namespace.scope,
213
115
  [declaration.ancestors.count - 1, 0].max,
214
116
  sites,
215
117
  [sites - 1, 0].max,
216
118
  descendants,
217
- inbound_references.fetch(index, 0),
218
- member_count,
119
+ inbound_counts.fetch(index, 0),
120
+ members,
219
121
  *ruby_counts,
220
- instance_variable_count,
122
+ instance_variables,
221
123
  ]
222
124
  end
223
- rows.concat(workspace.fetch(:rspec_groups).map { build_rspec_row })
125
+ rows.concat(Array.new(rspec_group_count) { RSPEC_ROW.dup })
224
126
  end
225
127
 
226
- def build_rspec_row
227
- [0, 1, *Array.new(11, 0)]
128
+ # One sweep over a namespace's direct and singleton members yields the
129
+ # workspace member count, the method and constant construct counts, and
130
+ # the instance-variable count together, since each of the three otherwise
131
+ # re-reads every member's definitions.
132
+ #
133
+ #: (Rubydex::Namespace, kind: Integer, count_instance_variables: bool) -> [Integer, Array[Integer], Integer]
134
+ def member_statistics(declaration, kind:, count_instance_variables:)
135
+ members = 0
136
+ instance_variables = 0
137
+ ruby_counts = Array.new(4, 0)
138
+ ruby_counts[kind] += 1
139
+
140
+ seen = Set.new
141
+ groups = [[declaration.members, true]]
142
+ singleton = declaration.singleton_class
143
+ groups << [singleton.members, false] if singleton
144
+ groups.each do |group, direct|
145
+ group.each do |member|
146
+ next unless seen.add?(member.name)
147
+ next unless member.definitions.any? { |definition| @locations.workspace?(definition.location) }
148
+
149
+ members += 1
150
+ construct = case member
151
+ when Rubydex::Method then DeclarationCollector::METHOD
152
+ when Rubydex::Constant, Rubydex::ConstantAlias then DeclarationCollector::CONSTANT
153
+ end
154
+ ruby_counts[construct] += 1 if construct
155
+ instance_variables += 1 if direct && count_instance_variables && member.is_a?(Rubydex::InstanceVariable)
156
+ end
157
+ end
158
+ [members, ruby_counts, instance_variables]
159
+ rescue StandardError
160
+ [members, ruby_counts, instance_variables]
228
161
  end
229
162
 
230
- def build_package_rows(aggregates)
163
+ #: (Array[DeclarationCollector::dependency_package]) -> Array[Hash[String, untyped]]
164
+ def package_rows(aggregates)
231
165
  @manifest.packages.each_with_index.map do |package, index|
232
166
  aggregate = aggregates.fetch(index)
233
167
  {
@@ -240,7 +174,8 @@ module RubyLens
240
174
  end
241
175
  end
242
176
 
243
- def build_dependency_system_rows
177
+ #: () -> Array[Hash[String, untyped]]
178
+ def dependency_system_rows
244
179
  return [] unless @manifest.respond_to?(:dependency_systems)
245
180
 
246
181
  @manifest.dependency_systems.map do |system|
@@ -252,282 +187,7 @@ module RubyLens
252
187
  end
253
188
  end
254
189
 
255
- def collect_dependency_declaration(
256
- aggregation,
257
- positions,
258
- declaration,
259
- name,
260
- is_namespace,
261
- construct_index,
262
- package_site_keys,
263
- reference_count
264
- )
265
- return unless package_site_keys
266
-
267
- package_index = nil
268
- site_keys = nil
269
- package_site_keys.each do |index, keys|
270
- if site_keys.nil? || keys.length > site_keys.length ||
271
- (keys.length == site_keys.length && index < package_index)
272
- package_index = index
273
- site_keys = keys
274
- end
275
- end
276
-
277
- sites = site_keys.length > 1 ? site_keys.uniq.length : site_keys.length
278
- row = [
279
- namespace_kind(declaration),
280
- is_namespace ? [declaration.ancestors.count - 1, 0].max : 0,
281
- sites,
282
- [sites - 1, 0].max,
283
- is_namespace ? [declaration.descendants.count - 1, 0].max : 0,
284
- reference_count,
285
- is_namespace ? safe_length(declaration, :members) : 0,
286
- ].freeze
287
- local_index = aggregation.add(
288
- package_index:,
289
- row:,
290
- construct_index:,
291
- )
292
- if reference_count.positive? && constant_reference_target?(declaration, is_namespace)
293
- positions[name] = [package_index, local_index]
294
- end
295
- end
296
-
297
- def workspace_reference_summary(graph, workspace, dependency_ordinal_by_name = {})
298
- ordinal_by_name = workspace.fetch(:ordinal_by_name)
299
- namespace_count = workspace.fetch(:namespace_names, ordinal_by_name).length
300
- workspace_ranges = workspace.fetch(:definition_ranges, {})
301
- inbound_counts = Hash.new(0)
302
- workspace.fetch(:records).each_with_index do |record, index|
303
- record.fetch(0).references.each do |reference|
304
- location = begin
305
- reference.location
306
- rescue StandardError
307
- next
308
- end
309
- inbound_counts[index] += 1 if workspace_location?(location)
310
- end
311
- end
312
- links = []
313
- retained_links = Set.new
314
- attribution_count = 0
315
-
316
- graph.constant_references.each do |reference|
317
- break if links.length >= CONSTANT_REFERENCE_LINK_LIMIT ||
318
- attribution_count >= CONSTANT_REFERENCE_ATTRIBUTION_LIMIT
319
- next unless reference.is_a?(Rubydex::ResolvedConstantReference)
320
-
321
- referenced_name = resolved_constant_reference_name(reference)
322
- next unless referenced_name
323
- referenced_ordinal = ordinal_by_name[referenced_name]
324
- dependency_ordinal = dependency_ordinal_by_name[referenced_name] unless referenced_ordinal
325
- next unless referenced_ordinal || dependency_ordinal
326
-
327
- location = begin
328
- reference.location
329
- rescue StandardError
330
- next
331
- end
332
- next unless workspace_location?(location)
333
-
334
- attribution_count += 1
335
-
336
- referenced_endpoint = referenced_ordinal || namespace_count + dependency_ordinal
337
-
338
- location_values = begin
339
- location.comparable_values
340
- rescue StandardError
341
- next
342
- end
343
- referring_ordinal = enclosing_definition_ordinal(location_values, workspace_ranges)
344
- next unless referring_ordinal
345
- next if referenced_endpoint == referring_ordinal
346
-
347
- link = [referring_ordinal, referenced_endpoint]
348
- next unless retained_links.add?(link)
349
-
350
- links << link
351
- end
352
-
353
- ReferenceSummary.new(inbound_counts.freeze, links.freeze)
354
- end
355
-
356
- def resolved_constant_reference_name(reference)
357
- reference.declaration.name
358
- rescue StandardError
359
- nil
360
- end
361
-
362
- def enclosing_definition_ordinal(location_values, ranges_by_uri)
363
- uri, start_line, start_column, end_line, end_column = location_values
364
- best = nil
365
- ambiguous = false
366
- ranges_by_uri.fetch(uri, []).each do |range|
367
- range_start_line, range_start_column, range_end_line, range_end_column, ordinal = range
368
- next if position_compare(range_start_line, range_start_column, start_line, start_column).positive?
369
- next if position_compare(range_end_line, range_end_column, end_line, end_column).negative?
370
-
371
- start_comparison = best ? position_compare(range_start_line, range_start_column, best[0], best[1]) : 1
372
- end_comparison = best && start_comparison.zero? ? position_compare(range_end_line, range_end_column, best[2], best[3]) : 0
373
- if start_comparison.positive? || (start_comparison.zero? && end_comparison.negative?)
374
- best = range
375
- ambiguous = false
376
- elsif start_comparison.zero? && end_comparison.zero? && ordinal != best[4]
377
- ambiguous = true
378
- end
379
- end
380
-
381
- ambiguous ? nil : best&.fetch(4)
382
- end
383
-
384
- def position_compare(left_line, left_column, right_line, right_column)
385
- line_comparison = left_line <=> right_line
386
- line_comparison.zero? ? left_column <=> right_column : line_comparison
387
- end
388
-
389
- def package_index_for_location(location)
390
- uri = location.uri
391
- @package_index_by_uri.fetch(uri) do
392
- path = source_path(uri)
393
- @package_index_by_uri[uri] =
394
- if path && @indexed_package_document_paths.include?(path)
395
- @manifest.package_index_for(path)
396
- end
397
- end
398
- end
399
-
400
- # One sweep over the indexed documents resolves each URI once, yielding
401
- # both the package-audit set and the [document, path] pairs the RSpec
402
- # extractor reuses without re-enumerating documents or re-parsing URIs.
403
- def resolve_documents(graph)
404
- audited = @manifest.packages.flat_map(&:files).to_set
405
- package_paths = Set.new
406
- documents_with_paths = []
407
- graph.documents.each do |document|
408
- path = source_path(document.uri)
409
- next unless path
410
-
411
- documents_with_paths << [document, path]
412
- package_paths << path if audited.include?(path)
413
- end
414
- [package_paths, documents_with_paths]
415
- end
416
-
417
- # One sweep over a namespace's direct and singleton members yields the
418
- # workspace member count, the method/constant construct counts, and the
419
- # instance-variable count that previously took three walks each re-reading
420
- # every member's definitions. Membership comes from each member's own
421
- # definition locations; the per-URI caches keep that scan cheap.
422
- def member_statistics(declaration, count_instance_variables:)
423
- member_count = 0
424
- instance_variable_count = 0
425
- ruby_counts = Array.new(4, 0)
426
- own_construct = ruby_construct_index(declaration)
427
- ruby_counts[own_construct] += 1 if own_construct == 0 || own_construct == 1
428
-
429
- seen_names = Set.new
430
- member_groups = [[declaration.members, true]]
431
- singleton = declaration.singleton_class
432
- member_groups << [singleton.members, false] if singleton
433
- member_groups.each do |members, direct|
434
- members.each do |member|
435
- next unless seen_names.add?(member.name)
436
- next unless member.definitions.any? { |definition| workspace_location?(definition.location) }
437
-
438
- member_count += 1
439
- construct_index = ruby_construct_index(member)
440
- ruby_counts[construct_index] += 1 if construct_index && construct_index >= 2
441
- if direct && count_instance_variables && member.is_a?(Rubydex::InstanceVariable)
442
- instance_variable_count += 1
443
- end
444
- end
445
- end
446
- [member_count, ruby_counts, instance_variable_count]
447
- rescue StandardError
448
- [member_count, ruby_counts, instance_variable_count]
449
- end
450
-
451
- def workspace_location?(location)
452
- uri = location.uri
453
- @workspace_location_cache.fetch(uri) do
454
- path = source_path(uri)
455
- @workspace_location_cache[uri] = path ? @manifest.workspace_path?(path) : false
456
- end
457
- rescue StandardError
458
- false
459
- end
460
-
461
- # 1 for a test-tree file, 0 for any other workspace file, nil when the
462
- # URI has no workspace-relative path to classify.
463
- def definition_scope(uri)
464
- @definition_scope_by_uri.fetch(uri) do
465
- relative = @manifest.relative_workspace_path(source_path(uri))
466
- @definition_scope_by_uri[uri] =
467
- if relative
468
- relative.split(File::SEPARATOR).any? { |segment| TEST_SEGMENTS.include?(segment) } ? 1 : 0
469
- end
470
- end
471
- end
472
-
473
- def constant_reference_target?(declaration, is_namespace)
474
- is_namespace ||
475
- declaration.is_a?(Rubydex::Constant) ||
476
- declaration.is_a?(Rubydex::ConstantAlias)
477
- end
478
-
479
- def model_eligible_declaration?(declaration, name = declaration.name)
480
- return false if name.nil? || name.empty? || name.include?("<anonymous>")
481
- return false if declaration.is_a?(Rubydex::Todo)
482
- return true unless declaration.is_a?(Rubydex::SingletonClass)
483
-
484
- attached = declaration.attached_class
485
- !attached.is_a?(Rubydex::SingletonClass) && !attached.is_a?(Rubydex::Todo)
486
- end
487
-
488
- def canonical_namespace_definition?(declaration, definition)
489
- (declaration.is_a?(Rubydex::Class) && definition.is_a?(Rubydex::ClassDefinition)) ||
490
- (declaration.is_a?(Rubydex::Module) && definition.is_a?(Rubydex::ModuleDefinition))
491
- end
492
-
493
- def namespace_kind(declaration)
494
- case declaration
495
- when Rubydex::Class then 0
496
- when Rubydex::Module then 1
497
- else 2
498
- end
499
- end
500
-
501
- def ruby_construct_index(declaration)
502
- case declaration
503
- when Rubydex::SingletonClass then nil
504
- when Rubydex::Class then 0
505
- when Rubydex::Module then 1
506
- when Rubydex::Method then 2
507
- when Rubydex::Constant, Rubydex::ConstantAlias then 3
508
- end
509
- end
510
-
511
- def source_path(uri_string)
512
- @source_path_cache.fetch(uri_string) do
513
- @source_path_cache[uri_string] = SourcePath.from_file_uri(uri_string)
514
- end
515
- end
516
-
517
- def safe_length(object, method)
518
- records = object.public_send(method)
519
- size = records.size
520
- size.nil? ? safe_count(records) : size
521
- rescue StandardError
522
- safe_count(records)
523
- end
524
-
525
- def safe_count(records)
526
- records ? records.count : 0
527
- rescue StandardError
528
- 0
529
- end
530
-
190
+ #: () -> String
531
191
  def project_name
532
192
  basename = @manifest.root.basename.to_s
533
193
  return "IRB" if basename.casecmp("irb").zero?
@@ -17,10 +17,12 @@ module RubyLens
17
17
  local_index = @rows[package_index].length
18
18
  @ruby_counts[package_index][construct_index] += 1 if construct_index
19
19
  maxima = @signal_maxima
20
- SIGNAL_COLUMNS.each do |column|
20
+ column = SIGNAL_COLUMNS.begin
21
+ while column <= SIGNAL_COLUMNS.end
21
22
  value = row[column]
22
23
  index = column - 1
23
24
  maxima[index] = value if value > maxima[index]
25
+ column += 1
24
26
  end
25
27
  @rows[package_index] << (row.frozen? ? row : row.dup.freeze)
26
28
  local_index
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLens
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubylens
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - RubyLens contributors
@@ -69,6 +69,10 @@ files:
69
69
  - lib/rubylens/errors.rb
70
70
  - lib/rubylens/generator.rb
71
71
  - lib/rubylens/git_repository.rb
72
+ - lib/rubylens/index/constant_reference_collector.rb
73
+ - lib/rubylens/index/declaration_collector.rb
74
+ - lib/rubylens/index/git_package_source.rb
75
+ - lib/rubylens/index/location_index.rb
72
76
  - lib/rubylens/index/manifest.rb
73
77
  - lib/rubylens/index/rspec_extractor.rb
74
78
  - lib/rubylens/index/rubydex_adapter.rb
@@ -82,12 +86,12 @@ files:
82
86
  - lib/rubylens/showcase_model.rb
83
87
  - lib/rubylens/showcase_writer.rb
84
88
  - lib/rubylens/version.rb
85
- homepage: https://st0012.dev/rails-galaxy/
89
+ homepage: https://st0012.dev/ruby-galaxies/
86
90
  licenses:
87
91
  - MIT
88
92
  metadata:
89
93
  allowed_push_host: https://rubygems.org
90
- homepage_uri: https://st0012.dev/rails-galaxy/
94
+ homepage_uri: https://st0012.dev/ruby-galaxies/
91
95
  rubygems_mfa_required: 'true'
92
96
  rdoc_options: []
93
97
  require_paths: