yardmcp 0.1.0 → 0.2.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/yardmcp/version.rb +1 -1
  3. data/lib/yardmcp.rb +57 -21
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0b56fc156ab0bb9d90ec43b123ff1f04673beab24b2e99d08bcb10626c1246b
4
- data.tar.gz: 7bdc59fcd90f8ff1e0ba894bbeef72f84db29b62e535aeb72d38247e2ac63b14
3
+ metadata.gz: 88e4b95aa833c7d4beb6cf789d921410f3ff5d0112a1a10456dff4943ec3561c
4
+ data.tar.gz: 751d12f0deedd21838b34ddf5cc1b4e36585888be3b5a899547d6bc4684462c4
5
5
  SHA512:
6
- metadata.gz: 718150e2c6ea52f8dc5f7edadbc5f7109e70d19246927098011d2341f4d318425b72444dd62de52f48301dc2567a48904e18fbd20dd9eb45c096e2f782f70c94
7
- data.tar.gz: 56c33f901052cdca43f904d48cec5e9f543da349170e0894d3915ff2e5a84b8f71bfa919158e81803e12be866afb1b134ef01e7ee30a6ccf8ccdba6069725b3e
6
+ metadata.gz: f9fbd30f73eaac7a36457ed89ffce04b87c6537641910c71c0f01aeac3bcfe700a8cb3c249c8c1f03f76d365028aec4e51fa355d1360ffaee18d1d0e404ee038
7
+ data.tar.gz: dea12928f18006a12bd44473f55f0e849b65530e9ee7b5dc0a79fab5a321e06368b20222958491080930857beb98e205bd90adee601a77140d9ea2a22571684c
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YardMCP
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/yardmcp.rb CHANGED
@@ -11,6 +11,7 @@ require_relative 'yardmcp/version'
11
11
  # Utility class for YARD operations
12
12
  class YardUtils
13
13
  include Singleton
14
+
14
15
  attr_reader :libraries, :logger, :object_to_gem
15
16
 
16
17
  def initialize
@@ -43,7 +44,7 @@ class YardUtils
43
44
  # Ensures the correct .yardoc is loaded for the given object path
44
45
  def ensure_yardoc_loaded_for_object!(object_path)
45
46
  # TODO: Handle multiple gems for the same object path, use some heuristic to determine the correct gem
46
- gem_name = @object_to_gem[object_path].first
47
+ gem_name = @object_to_gem[object_path]&.first
47
48
  raise "No documentation found for #{object_path}" unless gem_name
48
49
 
49
50
  load_yardoc_for_gem(gem_name)
@@ -275,22 +276,50 @@ class YardUtils
275
276
  (libraries[spec.name] ||= []) << YARD::Server::LibraryVersion.new(spec.name, spec.version.to_s, nil, :gem)
276
277
  end
277
278
 
278
- list_gems.each do |gem_name|
279
- logger.debug "Loading #{gem_name}..."
280
- begin
281
- load_yardoc_for_gem(gem_name)
282
- rescue StandardError => e
283
- logger.error "Error loading #{gem_name}: #{e.message}"
284
- next
285
- end
286
- YARD::Registry.all.each do |obj|
287
- logger.debug "Adding #{obj.path} to #{gem_name}"
288
- (@object_to_gem[obj.path.to_s] ||= []) << gem_name
289
- end
279
+ begin
280
+ require 'parallel'
281
+ logger.info 'Using parallel gem for index building'
282
+
283
+ # Use processes to avoid YARD thread-safety issues
284
+ # Each process returns a hash of object_path => [gem_names]
285
+ results = Parallel.map(list_gems, in_processes: 8) { |gem| process_gem_for_index(gem) }
286
+ merge_gem_results(results)
287
+ rescue LoadError
288
+ logger.warn 'parallel gem not found, falling back to single-threaded processing'
289
+ results = list_gems.map { |gem| process_gem_for_index(gem) }
290
+ merge_gem_results(results)
290
291
  end
291
292
  logger.info "Index built: #{libraries.size} gems, #{@object_to_gem.size} objects"
292
293
  end
293
294
 
295
+ # Merge gem processing results into @object_to_gem
296
+ def merge_gem_results(results)
297
+ results.each do |gem_objects|
298
+ gem_objects.each do |obj_path, gem_names|
299
+ (@object_to_gem[obj_path] ||= []).concat(gem_names)
300
+ end
301
+ end
302
+ end
303
+
304
+ # Process a single gem and return its objects as a hash
305
+ def process_gem_for_index(gem_name)
306
+ logger.debug "Loading #{gem_name}..."
307
+ begin
308
+ load_yardoc_for_gem(gem_name)
309
+ rescue StandardError => e
310
+ logger.error "Error loading #{gem_name}: #{e.message}"
311
+ return {}
312
+ end
313
+
314
+ # Collect all objects for this gem
315
+ gem_objects = {}
316
+ YARD::Registry.all.each do |obj|
317
+ logger.debug "Adding #{obj.path} to #{gem_name}"
318
+ gem_objects[obj.path.to_s] = [gem_name]
319
+ end
320
+ gem_objects
321
+ end
322
+
294
323
  def build_docs(gem_name)
295
324
  logger.info "Building docs for #{gem_name}..."
296
325
  YARD::CLI::Gems.new.run(gem_name)
@@ -302,7 +331,8 @@ class ListGemsTool < FastMcp::Tool
302
331
  description 'List all installed gems that have a .yardoc file'
303
332
 
304
333
  def call
305
- { content: YardUtils.instance.list_gems }
334
+ gems = YardUtils.instance.list_gems
335
+ { content: gems.map { |gem| { text: gem, type: 'gem' } } }
306
336
  end
307
337
  end
308
338
 
@@ -314,7 +344,8 @@ class ListClassesTool < FastMcp::Tool
314
344
  end
315
345
 
316
346
  def call(gem_name:)
317
- { content: YardUtils.instance.list_classes(gem_name) }
347
+ classes = YardUtils.instance.list_classes(gem_name)
348
+ { content: classes.map { |cls| { text: cls, type: 'class' } } }
318
349
  end
319
350
  end
320
351
 
@@ -339,7 +370,8 @@ class ChildrenTool < FastMcp::Tool
339
370
  end
340
371
 
341
372
  def call(path:)
342
- { content: YardUtils.instance.children(path) }
373
+ children = YardUtils.instance.children(path)
374
+ { content: children.map { |child| { text: child, type: 'child' } } }
343
375
  end
344
376
  end
345
377
 
@@ -351,7 +383,8 @@ class MethodsListTool < FastMcp::Tool
351
383
  end
352
384
 
353
385
  def call(path:)
354
- { content: YardUtils.instance.methods_list(path) }
386
+ methods = YardUtils.instance.methods_list(path)
387
+ { content: methods.map { |method| { text: method, type: 'method' } } }
355
388
  end
356
389
  end
357
390
 
@@ -376,7 +409,8 @@ class SearchTool < FastMcp::Tool
376
409
 
377
410
  def call(query:)
378
411
  # Enhanced search: ranked, fuzzy, and full-text
379
- { content: YardUtils.instance.search(query) }
412
+ results = YardUtils.instance.search(query)
413
+ { content: results.map { |result| { text: result[:path], score: result[:score], type: 'search_result' } } }
380
414
  end
381
415
  end
382
416
 
@@ -400,7 +434,8 @@ class CodeSnippetTool < FastMcp::Tool
400
434
  end
401
435
 
402
436
  def call(path:)
403
- YardUtils.instance.code_snippet(path)
437
+ snippet = YardUtils.instance.code_snippet(path)
438
+ { content: { text: snippet, type: 'code_snippet' } }
404
439
  end
405
440
  end
406
441
 
@@ -412,7 +447,8 @@ class AncestorsTool < FastMcp::Tool
412
447
  end
413
448
 
414
449
  def call(path:)
415
- { content: YardUtils.instance.ancestors(path) }
450
+ ancestors = YardUtils.instance.ancestors(path)
451
+ { content: ancestors.map { |ancestor| { text: ancestor, type: 'ancestor' } } }
416
452
  end
417
453
  end
418
454
 
@@ -429,7 +465,7 @@ class RelatedObjectsTool < FastMcp::Tool
429
465
  end
430
466
 
431
467
  module YardMCP
432
- def self.start_server(preload: false)
468
+ def self.start_server(preload: true)
433
469
  YardUtils.instance if preload
434
470
  server = FastMcp::Server.new(name: 'yard-mcp-server', version: YardMCP::VERSION)
435
471
  server.register_tool(ListGemsTool)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yardmcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Shterenzon