rubydex 0.2.5 → 0.2.7

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -16
  3. data/THIRD_PARTY_LICENSES.html +45 -12
  4. data/exe/rdx +2 -0
  5. data/ext/rubydex/declaration.c +115 -106
  6. data/ext/rubydex/definition.c +123 -72
  7. data/ext/rubydex/diagnostic.c +5 -0
  8. data/ext/rubydex/document.c +51 -23
  9. data/ext/rubydex/extconf.rb +1 -1
  10. data/ext/rubydex/graph.c +253 -66
  11. data/ext/rubydex/handle.h +34 -5
  12. data/ext/rubydex/location.c +5 -0
  13. data/ext/rubydex/reference.c +51 -46
  14. data/ext/rubydex/rubydex.c +5 -0
  15. data/ext/rubydex/signature.c +5 -0
  16. data/ext/rubydex/utils.c +13 -0
  17. data/ext/rubydex/utils.h +4 -0
  18. data/lib/rubydex/bin/rubydex_mcp.exe +0 -0
  19. data/lib/rubydex/errors.rb +11 -0
  20. data/lib/rubydex/graph.rb +9 -28
  21. data/lib/rubydex/location.rb +24 -0
  22. data/lib/rubydex/version.rb +1 -1
  23. data/lib/rubydex.rb +1 -0
  24. data/rbi/rubydex.rbi +40 -15
  25. data/rust/Cargo.lock +122 -17
  26. data/rust/rubydex/Cargo.toml +26 -2
  27. data/rust/rubydex/benches/graph_memory.rs +46 -0
  28. data/rust/rubydex/src/config.rs +275 -0
  29. data/rust/rubydex/src/dot.rs +609 -0
  30. data/rust/rubydex/src/errors.rs +2 -0
  31. data/rust/rubydex/src/indexing/rbs_indexer.rs +19 -1
  32. data/rust/rubydex/src/indexing/ruby_indexer.rs +4 -0
  33. data/rust/rubydex/src/lib.rs +8 -1
  34. data/rust/rubydex/src/main.rs +8 -5
  35. data/rust/rubydex/src/model/built_in.rs +5 -2
  36. data/rust/rubydex/src/model/comment.rs +2 -0
  37. data/rust/rubydex/src/model/declaration.rs +13 -51
  38. data/rust/rubydex/src/model/definitions.rs +13 -1
  39. data/rust/rubydex/src/model/document.rs +2 -0
  40. data/rust/rubydex/src/model/encoding.rs +2 -0
  41. data/rust/rubydex/src/model/graph.rs +88 -27
  42. data/rust/rubydex/src/model/identity_maps.rs +3 -0
  43. data/rust/rubydex/src/model/keywords.rs +3 -0
  44. data/rust/rubydex/src/model/name.rs +2 -0
  45. data/rust/rubydex/src/model/string_ref.rs +2 -0
  46. data/rust/rubydex/src/model/visibility.rs +3 -0
  47. data/rust/rubydex/src/operation/applier.rs +1 -0
  48. data/rust/rubydex/src/operation/mod.rs +1 -0
  49. data/rust/rubydex/src/operation/ruby_builder.rs +4 -0
  50. data/rust/rubydex/src/query.rs +114 -33
  51. data/rust/rubydex/src/resolution.rs +18 -20
  52. data/rust/rubydex/src/resolution_tests.rs +132 -0
  53. data/rust/rubydex/tests/cli.rs +17 -61
  54. data/rust/rubydex-mcp/Cargo.toml +9 -3
  55. data/rust/rubydex-sys/Cargo.toml +9 -2
  56. data/rust/rubydex-sys/src/definition_api.rs +72 -2
  57. data/rust/rubydex-sys/src/document_api.rs +28 -0
  58. data/rust/rubydex-sys/src/graph_api.rs +74 -6
  59. metadata +6 -4
  60. data/rust/rubydex/src/visualization/dot.rs +0 -192
  61. data/rust/rubydex/src/visualization.rs +0 -6
data/ext/rubydex/graph.c CHANGED
@@ -8,6 +8,11 @@
8
8
  #include "rustbindings.h"
9
9
  #include "utils.h"
10
10
 
11
+ /*
12
+ * RDoc parser workaround for https://github.com/ruby/rdoc/issues/1744:
13
+ * mRubydex = rb_define_module("Rubydex")
14
+ */
15
+
11
16
  static VALUE cGraph;
12
17
  static VALUE mRubydex;
13
18
  static VALUE cKeyword;
@@ -16,17 +21,20 @@ static VALUE cKeywordParameter;
16
21
  // Interned once in `rdxi_initialize_graph` to avoid repeated symbol-table lookups on hot completion paths.
17
22
  static ID id_self_receiver;
18
23
 
19
- // Extracts the optional `self_receiver:` kwarg from `opts`. Returns NULL when the kwarg is
20
- // absent or nil; raises ArgumentError when the value is the wrong type or empty.
24
+ // Extracts the required `self_receiver:` kwarg from `opts`. Returns NULL when the value is `nil`,
25
+ // which means "no self-type to walk" (e.g., empty class body where the singleton class hasn't
26
+ // been created). Raises ArgumentError if the kwarg is absent, of the wrong type, or an empty
27
+ // string. The kwarg is required so that callers commit to a self type — there is no implicit
28
+ // default.
21
29
  static const char *extract_self_receiver(VALUE opts) {
22
30
  if (NIL_P(opts)) {
23
- return NULL;
31
+ rb_raise(rb_eArgError, "missing keyword: self_receiver");
24
32
  }
25
33
 
26
34
  VALUE kwarg_val;
27
- rb_get_kwargs(opts, &id_self_receiver, 0, 1, &kwarg_val);
35
+ rb_get_kwargs(opts, &id_self_receiver, 1, 0, &kwarg_val);
28
36
 
29
- if (kwarg_val == Qundef || NIL_P(kwarg_val)) {
37
+ if (NIL_P(kwarg_val)) {
30
38
  return NULL;
31
39
  }
32
40
 
@@ -45,7 +53,18 @@ static void graph_free(void *ptr) {
45
53
  }
46
54
  }
47
55
 
48
- const rb_data_type_t graph_type = {"Graph", {0, graph_free, 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY};
56
+ const rb_data_type_t graph_type = {
57
+ .wrap_struct_name = "Graph",
58
+ .function = {
59
+ .dmark = NULL,
60
+ .dfree = graph_free,
61
+ .dsize = NULL,
62
+ .dcompact = NULL,
63
+ },
64
+ .parent = NULL,
65
+ .data = NULL,
66
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
67
+ };
49
68
 
50
69
  // Custom allocator for the Graph class. Calls into Rust to create a new `Arc<Mutex<Graph>>` that gets stored internally
51
70
  // as a void pointer
@@ -54,8 +73,12 @@ static VALUE rdxr_graph_alloc(VALUE klass) {
54
73
  return TypedData_Wrap_Struct(klass, &graph_type, graph);
55
74
  }
56
75
 
57
- // Graph#index_all: (Array[String] file_paths) -> Array[String]
58
- // Returns an array of IO error messages encountered during indexing
76
+ /*
77
+ * call-seq:
78
+ * index_all(file_paths) -> Array[String]
79
+ *
80
+ * Returns an array of I/O error messages encountered during indexing.
81
+ */
59
82
  static VALUE rdxr_graph_index_all(VALUE self, VALUE file_paths) {
60
83
  rdxi_check_array_of_strings(file_paths);
61
84
 
@@ -85,9 +108,12 @@ static VALUE rdxr_graph_index_all(VALUE self, VALUE file_paths) {
85
108
  return array;
86
109
  }
87
110
 
88
- // Indexes a single source string in memory, dispatching to the appropriate indexer based on language_id
89
- //
90
- // Graph#index_source: (String uri, String source, String language_id) -> void
111
+ /*
112
+ * call-seq:
113
+ * index_source(uri, source, language_id) -> nil
114
+ *
115
+ * Indexes a single source string in memory, dispatching to the appropriate indexer based on language_id.
116
+ */
91
117
  static VALUE rdxr_graph_index_source(VALUE self, VALUE uri, VALUE source, VALUE language_id) {
92
118
  Check_Type(uri, T_STRING);
93
119
  Check_Type(source, T_STRING);
@@ -134,8 +160,12 @@ static VALUE graph_declarations_size(VALUE self, VALUE _args, VALUE _eobj) {
134
160
  return SIZET2NUM(len);
135
161
  }
136
162
 
137
- // Graph#declarations: () -> Enumerator[Declaration]
138
- // Returns an enumerator that yields all declarations lazily
163
+ /*
164
+ * call-seq:
165
+ * declarations -> Enumerator[Rubydex::Declaration]
166
+ *
167
+ * Returns an enumerator that yields all declarations lazily.
168
+ */
139
169
  static VALUE rdxr_graph_declarations(VALUE self) {
140
170
  if (!rb_block_given_p()) {
141
171
  return rb_enumeratorize_with_size(self, rb_str_new2("declarations"), 0, NULL, graph_declarations_size);
@@ -164,8 +194,12 @@ static VALUE rdxr_graph_yield_search_results(VALUE self, void *iter) {
164
194
  return self;
165
195
  }
166
196
 
167
- // Graph#search: (String query) -> Enumerator[Declaration]
168
- // Returns an enumerator that yields declarations matching the query exactly (substring match)
197
+ /*
198
+ * call-seq:
199
+ * search(query) -> Enumerator[Rubydex::Declaration]
200
+ *
201
+ * Returns an enumerator that yields declarations matching the query exactly by substring.
202
+ */
169
203
  static VALUE rdxr_graph_search(VALUE self, VALUE query) {
170
204
  Check_Type(query, T_STRING);
171
205
 
@@ -179,8 +213,12 @@ static VALUE rdxr_graph_search(VALUE self, VALUE query) {
179
213
  return rdxr_graph_yield_search_results(self, rdx_graph_declarations_search(graph, StringValueCStr(query)));
180
214
  }
181
215
 
182
- // Graph#fuzzy_search: (String query) -> Enumerator[Declaration]
183
- // Returns an enumerator that yields declarations matching the query fuzzily
216
+ /*
217
+ * call-seq:
218
+ * fuzzy_search(query) -> Enumerator[Rubydex::Declaration]
219
+ *
220
+ * Returns an enumerator that yields declarations matching the query fuzzily.
221
+ */
184
222
  static VALUE rdxr_graph_fuzzy_search(VALUE self, VALUE query) {
185
223
  Check_Type(query, T_STRING);
186
224
 
@@ -229,8 +267,12 @@ static VALUE graph_documents_size(VALUE self, VALUE _args, VALUE _eobj) {
229
267
  return SIZET2NUM(len);
230
268
  }
231
269
 
232
- // Graph#documents: () -> Enumerator[Document]
233
- // Returns an enumerator that yields all documents lazily
270
+ /*
271
+ * call-seq:
272
+ * documents -> Enumerator[Rubydex::Document]
273
+ *
274
+ * Returns an enumerator that yields all documents lazily.
275
+ */
234
276
  static VALUE rdxr_graph_documents(VALUE self) {
235
277
  if (!rb_block_given_p()) {
236
278
  return rb_enumeratorize_with_size(self, rb_str_new2("documents"), 0, NULL, graph_documents_size);
@@ -246,8 +288,12 @@ static VALUE rdxr_graph_documents(VALUE self) {
246
288
  return self;
247
289
  }
248
290
 
249
- // Graph#[]: (String fully_qualified_name) -> Declaration
250
- // Returns a declaration handle for the given ID
291
+ /*
292
+ * call-seq:
293
+ * graph[fully_qualified_name] -> Rubydex::Declaration?
294
+ *
295
+ * Returns the declaration for the fully qualified name, or nil when no declaration exists.
296
+ */
251
297
  static VALUE rdxr_graph_aref(VALUE self, VALUE key) {
252
298
  void *graph;
253
299
  TypedData_Get_Struct(self, void *, &graph_type, graph);
@@ -280,8 +326,12 @@ static VALUE graph_constant_references_size(VALUE self, VALUE _args, VALUE _eobj
280
326
  return SIZET2NUM(len);
281
327
  }
282
328
 
283
- // Graph#constant_references: () -> Enumerator[ConstantReference]
284
- // Returns an enumerator that yields constant references lazily
329
+ /*
330
+ * call-seq:
331
+ * constant_references -> Enumerator[Rubydex::ConstantReference]
332
+ *
333
+ * Returns an enumerator that yields constant references lazily.
334
+ */
285
335
  static VALUE rdxr_graph_constant_references(VALUE self) {
286
336
  if (!rb_block_given_p()) {
287
337
  return rb_enumeratorize_with_size(self, rb_str_new2("constant_references"), 0, NULL,
@@ -310,8 +360,12 @@ static VALUE graph_method_references_size(VALUE self, VALUE _args, VALUE _eobj)
310
360
  return SIZET2NUM(len);
311
361
  }
312
362
 
313
- // Graph#method_references: () -> Enumerator[MethodReference]
314
- // Returns an enumerator that yields method references lazily
363
+ /*
364
+ * call-seq:
365
+ * method_references -> Enumerator[Rubydex::MethodReference]
366
+ *
367
+ * Returns an enumerator that yields method references lazily.
368
+ */
315
369
  static VALUE rdxr_graph_method_references(VALUE self) {
316
370
  if (!rb_block_given_p()) {
317
371
  return rb_enumeratorize_with_size(self, rb_str_new2("method_references"), 0, NULL,
@@ -328,8 +382,12 @@ static VALUE rdxr_graph_method_references(VALUE self) {
328
382
  return self;
329
383
  }
330
384
 
331
- // Graph#document: (String uri) -> Document?
332
- // Returns the Document for the given URI, or nil if it doesn't exist.
385
+ /*
386
+ * call-seq:
387
+ * document(uri) -> Rubydex::Document?
388
+ *
389
+ * Returns the document for the URI, or nil if it does not exist.
390
+ */
333
391
  static VALUE rdxr_graph_document(VALUE self, VALUE uri) {
334
392
  Check_Type(uri, T_STRING);
335
393
 
@@ -346,9 +404,13 @@ static VALUE rdxr_graph_document(VALUE self, VALUE uri) {
346
404
  return rb_class_new_instance(2, argv, cDocument);
347
405
  }
348
406
 
349
- // Graph#delete_document: (String uri) -> Document?
350
- // Deletes a document and all of its definitions from the graph.
351
- // Returns the removed Document or nil if it doesn't exist.
407
+ /*
408
+ * call-seq:
409
+ * delete_document(uri) -> Rubydex::Document?
410
+ *
411
+ * Deletes a document and all of its definitions from the graph. Returns the removed document, or nil if it does not
412
+ * exist.
413
+ */
352
414
  static VALUE rdxr_graph_delete_document(VALUE self, VALUE uri) {
353
415
  Check_Type(uri, T_STRING);
354
416
 
@@ -365,8 +427,12 @@ static VALUE rdxr_graph_delete_document(VALUE self, VALUE uri) {
365
427
  return rb_class_new_instance(2, argv, cDocument);
366
428
  }
367
429
 
368
- // Graph#resolve: () -> self
369
- // Runs the resolver to compute declarations and ownership
430
+ /*
431
+ * call-seq:
432
+ * resolve -> self
433
+ *
434
+ * Runs the resolver to compute declarations and ownership.
435
+ */
370
436
  static VALUE rdxr_graph_resolve(VALUE self) {
371
437
  void *graph;
372
438
  TypedData_Get_Struct(self, void *, &graph_type, graph);
@@ -374,8 +440,12 @@ static VALUE rdxr_graph_resolve(VALUE self) {
374
440
  return self;
375
441
  }
376
442
 
377
- // Graph#encoding=: (String) -> void
378
- // Sets the encoding used for transforming byte offsets into LSP code unit line/column positions
443
+ /*
444
+ * call-seq:
445
+ * encoding=(encoding) -> nil
446
+ *
447
+ * Sets the encoding used for transforming byte offsets into LSP code unit line and column positions.
448
+ */
379
449
  static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
380
450
  Check_Type(encoding, T_STRING);
381
451
 
@@ -390,8 +460,12 @@ static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
390
460
  return Qnil;
391
461
  }
392
462
 
393
- // Graph#resolve_constant: (String, Array[String]) -> Declaration?
394
- // Runs the resolver on a single constant reference to determine what it points to
463
+ /*
464
+ * call-seq:
465
+ * resolve_constant(name, nesting) -> Rubydex::Declaration?
466
+ *
467
+ * Runs the resolver on a single constant reference to determine what it points to.
468
+ */
395
469
  static VALUE rdxr_graph_resolve_constant(VALUE self, VALUE const_name, VALUE nesting) {
396
470
  Check_Type(const_name, T_STRING);
397
471
  rdxi_check_array_of_strings(nesting);
@@ -419,8 +493,12 @@ static VALUE rdxr_graph_resolve_constant(VALUE self, VALUE const_name, VALUE nes
419
493
  return rb_class_new_instance(2, argv, decl_class);
420
494
  }
421
495
 
422
- // Graph#resolve_require_path: (String require_path, Array[String] load_paths) -> Document?
423
- // Resolves a require path to its Document.
496
+ /*
497
+ * call-seq:
498
+ * resolve_require_path(require_path, load_paths) -> Rubydex::Document?
499
+ *
500
+ * Resolves a require path to its document.
501
+ */
424
502
  static VALUE rdxr_graph_resolve_require_path(VALUE self, VALUE require_path, VALUE load_paths) {
425
503
  Check_Type(require_path, T_STRING);
426
504
  rdxi_check_array_of_strings(load_paths);
@@ -445,8 +523,12 @@ static VALUE rdxr_graph_resolve_require_path(VALUE self, VALUE require_path, VAL
445
523
  return rb_class_new_instance(2, argv, cDocument);
446
524
  }
447
525
 
448
- // Graph#require_paths: (Array[String] load_path) -> Array[String]
449
- // Returns all require paths for completion.
526
+ /*
527
+ * call-seq:
528
+ * require_paths(load_paths) -> Array[String]
529
+ *
530
+ * Returns all require paths for completion.
531
+ */
450
532
  static VALUE rdxr_graph_require_paths(VALUE self, VALUE load_path) {
451
533
  rdxi_check_array_of_strings(load_path);
452
534
 
@@ -474,8 +556,12 @@ static VALUE rdxr_graph_require_paths(VALUE self, VALUE load_path) {
474
556
  return array;
475
557
  }
476
558
 
477
- // Graph#check_integrity: () -> Array[Rubydex::IntegrityFailure]
478
- // Returns an array of IntegrityFailure objects, empty if no issues found
559
+ /*
560
+ * call-seq:
561
+ * check_integrity -> Array[Rubydex::IntegrityFailure]
562
+ *
563
+ * Returns an array of integrity failures, or an empty array if no issues were found.
564
+ */
479
565
  static VALUE rdxr_graph_check_integrity(VALUE self) {
480
566
  void *graph;
481
567
  TypedData_Get_Struct(self, void *, &graph_type, graph);
@@ -500,7 +586,12 @@ static VALUE rdxr_graph_check_integrity(VALUE self) {
500
586
  return array;
501
587
  }
502
588
 
503
- // Graph#diagnostics -> Array[Rubydex::Diagnostic]
589
+ /*
590
+ * call-seq:
591
+ * diagnostics -> Array[Rubydex::Diagnostic]
592
+ *
593
+ * Returns diagnostics emitted while indexing or resolving the graph.
594
+ */
504
595
  static VALUE rdxr_graph_diagnostics(VALUE self) {
505
596
  void *graph;
506
597
  TypedData_Get_Struct(self, void *, &graph_type, graph);
@@ -517,7 +608,7 @@ static VALUE rdxr_graph_diagnostics(VALUE self) {
517
608
  for (size_t i = 0; i < array->len; i++) {
518
609
  DiagnosticEntry entry = array->items[i];
519
610
  VALUE message = entry.message == NULL ? Qnil : rb_utf8_str_new_cstr(entry.message);
520
- VALUE rule = rb_str_new2(entry.rule);
611
+ VALUE rule = rb_str_intern(rb_str_new2(entry.rule));
521
612
  VALUE location = rdxi_build_location_value(entry.location);
522
613
 
523
614
  VALUE kwargs = rb_hash_new();
@@ -589,11 +680,13 @@ static VALUE completion_result_to_ruby_array(struct CompletionResult result, VAL
589
680
  return ruby_array;
590
681
  }
591
682
 
592
- // Graph#complete_expression: (Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword]
593
- // Returns completion candidates for an expression context.
594
- // The nesting array represents the lexical scope stack. The optional self_receiver keyword argument
595
- // overrides the self-type (e.g., "Foo::<Foo>" for `def Foo.bar`); when nil, self is derived from
596
- // the innermost nesting element.
683
+ /*
684
+ * call-seq:
685
+ * complete_expression(nesting, self_receiver:) -> Array[Rubydex::Declaration | Rubydex::Keyword]
686
+ *
687
+ * Returns completion candidates for an expression context. The nesting array represents the lexical scope stack. The
688
+ * required self_receiver keyword argument overrides the self type; pass nil when the self type is unknown.
689
+ */
597
690
  static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
598
691
  VALUE nesting, opts;
599
692
  rb_scan_args(argc, argv, "1:", &nesting, &opts);
@@ -614,10 +707,13 @@ static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
614
707
  return completion_result_to_ruby_array(result, self);
615
708
  }
616
709
 
617
- // Graph#complete_namespace_access: (String name, self_receiver: nil) -> Array[Declaration]
618
- // Returns completion candidates after a namespace access operator (e.g., `Foo::`).
619
- // The optional self_receiver kwarg is the caller's runtime self type, used to filter
620
- // visibility-restricted singleton methods (e.g., `private_class_method`).
710
+ /*
711
+ * call-seq:
712
+ * complete_namespace_access(name, self_receiver:) -> Array[Rubydex::Declaration]
713
+ *
714
+ * Returns completion candidates after a namespace access operator such as Foo::. The required self_receiver keyword
715
+ * argument is the caller's runtime self type; pass nil when there is no caller context.
716
+ */
621
717
  static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE self) {
622
718
  VALUE name, opts;
623
719
  rb_scan_args(argc, argv, "1:", &name, &opts);
@@ -633,10 +729,13 @@ static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE s
633
729
  return completion_result_to_ruby_array(result, self);
634
730
  }
635
731
 
636
- // Graph#complete_method_call: (String name, self_receiver: nil) -> Array[Declaration]
637
- // Returns completion candidates after a method call operator (e.g., `foo.`).
638
- // The optional self_receiver kwarg is the caller's runtime self type, used for MRI-style
639
- // visibility checks (private/protected).
732
+ /*
733
+ * call-seq:
734
+ * complete_method_call(name, self_receiver:) -> Array[Rubydex::Method]
735
+ *
736
+ * Returns completion candidates after a method call operator such as foo. The required self_receiver keyword argument
737
+ * is the caller's runtime self type; pass nil when there is no caller context.
738
+ */
640
739
  static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self) {
641
740
  VALUE name, opts;
642
741
  rb_scan_args(argc, argv, "1:", &name, &opts);
@@ -652,9 +751,13 @@ static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self)
652
751
  return completion_result_to_ruby_array(result, self);
653
752
  }
654
753
 
655
- // Graph#complete_method_argument: (String name, Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword | KeywordParameter]
656
- // Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`).
657
- // See complete_expression for semantics of self_receiver.
754
+ /*
755
+ * call-seq:
756
+ * complete_method_argument(name, nesting, self_receiver:) -> Array[Rubydex::Declaration | Rubydex::Keyword | Rubydex::KeywordParameter]
757
+ *
758
+ * Returns completion candidates inside a method call's argument list. See complete_expression for self_receiver
759
+ * semantics.
760
+ */
658
761
  static VALUE rdxr_graph_complete_method_argument(int argc, VALUE *argv, VALUE self) {
659
762
  VALUE name, nesting, opts;
660
763
  rb_scan_args(argc, argv, "2:", &name, &nesting, &opts);
@@ -677,8 +780,12 @@ static VALUE rdxr_graph_complete_method_argument(int argc, VALUE *argv, VALUE se
677
780
  return completion_result_to_ruby_array(result, self);
678
781
  }
679
782
 
680
- // Graph#exclude_paths: (Array[String] paths) -> void
681
- // Excludes the given paths from file discovery during indexing.
783
+ /*
784
+ * call-seq:
785
+ * exclude_paths(paths) -> nil
786
+ *
787
+ * Excludes the paths from file discovery during indexing.
788
+ */
682
789
  static VALUE rdxr_graph_exclude_paths(VALUE self, VALUE paths) {
683
790
  Check_Type(paths, T_ARRAY);
684
791
  rdxi_check_array_of_strings(paths);
@@ -695,8 +802,12 @@ static VALUE rdxr_graph_exclude_paths(VALUE self, VALUE paths) {
695
802
  return Qnil;
696
803
  }
697
804
 
698
- // Graph#excluded_paths: () -> Array[String]
699
- // Returns the list of paths currently excluded from file discovery.
805
+ /*
806
+ * call-seq:
807
+ * excluded_paths -> Array[String]
808
+ *
809
+ * Returns the paths currently excluded from file discovery.
810
+ */
700
811
  static VALUE rdxr_graph_excluded_paths(VALUE self) {
701
812
  void *graph;
702
813
  TypedData_Get_Struct(self, void*, &graph_type, graph);
@@ -717,8 +828,81 @@ static VALUE rdxr_graph_excluded_paths(VALUE self) {
717
828
  return array;
718
829
  }
719
830
 
720
- // Graph#keyword: (String name) -> Keyword?
721
- // Returns a Keyword object for the given keyword name, or nil if it is not a keyword.
831
+ /*
832
+ * call-seq:
833
+ * workspace_path -> String
834
+ *
835
+ * Returns the root directory of the workspace being indexed.
836
+ */
837
+ static VALUE rdxr_graph_workspace_path(VALUE self) {
838
+ void *graph;
839
+ TypedData_Get_Struct(self, void*, &graph_type, graph);
840
+
841
+ const char *result = rdx_graph_workspace_path(graph);
842
+ if (result == NULL) {
843
+ rb_raise(rb_eRuntimeError, "Converting workspace path to Ruby string failed");
844
+ }
845
+
846
+ VALUE path = rdxi_owned_c_string_to_ruby(result);
847
+ return path;
848
+ }
849
+
850
+ /*
851
+ * call-seq:
852
+ * workspace_path=(path) -> void
853
+ *
854
+ * Sets the root directory of the workspace being indexed.
855
+ */
856
+ static VALUE rdxr_graph_set_workspace_path(VALUE self, VALUE path) {
857
+ Check_Type(path, T_STRING);
858
+
859
+ void *graph;
860
+ TypedData_Get_Struct(self, void*, &graph_type, graph);
861
+
862
+ rdx_graph_set_workspace_path(graph, StringValueCStr(path));
863
+ return path;
864
+ }
865
+
866
+ /*
867
+ * call-seq:
868
+ * load_config(config_path = nil) -> void
869
+ *
870
+ * Loads a configuration file for the graph. If `config_path` is nil, loads the default configuration file at
871
+ * `workspace_path/rubydex.toml` if it exists. Will raise on malformed files or if an explicit path is given but the
872
+ * file does not exist.
873
+ */
874
+ static VALUE rdxr_graph_load_config(int argc, VALUE *argv, VALUE self) {
875
+ VALUE config_path;
876
+ rb_scan_args(argc, argv, "01", &config_path);
877
+
878
+ void *graph;
879
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
880
+
881
+ const char *config_path_cstr = NULL;
882
+
883
+ if (!NIL_P(config_path)) {
884
+ Check_Type(config_path, T_STRING);
885
+ config_path_cstr = StringValueCStr(config_path);
886
+ }
887
+
888
+ const char *error = rdx_graph_load_config(graph, config_path_cstr);
889
+ if (error == NULL) {
890
+ return Qnil;
891
+ }
892
+
893
+ VALUE message = rb_utf8_str_new_cstr(error);
894
+ free_c_string(error);
895
+
896
+ VALUE config_error = rb_const_get(mRubydex, rb_intern("ConfigError"));
897
+ rb_exc_raise(rb_exc_new_str(config_error, message));
898
+ }
899
+
900
+ /*
901
+ * call-seq:
902
+ * keyword(name) -> Rubydex::Keyword?
903
+ *
904
+ * Returns the keyword object for the name, or nil if it is not a Ruby keyword.
905
+ */
722
906
  static VALUE rdxr_graph_keyword(VALUE self, VALUE name) {
723
907
  Check_Type(name, T_STRING);
724
908
 
@@ -769,5 +953,8 @@ void rdxi_initialize_graph(VALUE moduleRubydex) {
769
953
  rb_define_method(cGraph, "complete_method_argument", rdxr_graph_complete_method_argument, -1);
770
954
  rb_define_method(cGraph, "exclude_paths", rdxr_graph_exclude_paths, 1);
771
955
  rb_define_method(cGraph, "excluded_paths", rdxr_graph_excluded_paths, 0);
956
+ rb_define_method(cGraph, "workspace_path", rdxr_graph_workspace_path, 0);
957
+ rb_define_method(cGraph, "workspace_path=", rdxr_graph_set_workspace_path, 1);
958
+ rb_define_method(cGraph, "load_config", rdxr_graph_load_config, -1);
772
959
  rb_define_method(cGraph, "keyword", rdxr_graph_keyword, 1);
773
960
  }
data/ext/rubydex/handle.h CHANGED
@@ -1,6 +1,7 @@
1
1
  #ifndef RUBYDEX_HANDLE_H
2
2
  #define RUBYDEX_HANDLE_H
3
3
 
4
+ #include "graph.h"
4
5
  #include "ruby.h"
5
6
 
6
7
  typedef struct {
@@ -22,12 +23,37 @@ static void handle_free(void *ptr) {
22
23
  }
23
24
 
24
25
  static const rb_data_type_t handle_type = {
25
- "RubydexHandle", {handle_mark, handle_free, 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY};
26
+ .wrap_struct_name = "RubydexHandle",
27
+ .function = {
28
+ .dmark = handle_mark,
29
+ .dfree = handle_free,
30
+ .dsize = NULL,
31
+ .dcompact = NULL,
32
+ },
33
+ .parent = NULL,
34
+ .data = NULL,
35
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
36
+ };
37
+
38
+ static inline void *rdxi_graph_from_handle(VALUE self, HandleData **out_data) {
39
+ HandleData *data;
40
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
41
+
42
+ void *graph;
43
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
44
+
45
+ *out_data = data;
46
+
47
+ return graph;
48
+ }
26
49
 
27
50
  static VALUE rdxr_handle_alloc(VALUE klass) {
28
51
  HandleData *data = ALLOC(HandleData);
29
- data->graph_obj = Qnil;
30
- data->id = 0;
52
+
53
+ *data = (HandleData) {
54
+ .graph_obj = Qnil,
55
+ .id = 0,
56
+ };
31
57
 
32
58
  return TypedData_Wrap_Struct(klass, &handle_type, data);
33
59
  }
@@ -35,8 +61,11 @@ static VALUE rdxr_handle_alloc(VALUE klass) {
35
61
  static VALUE rdxr_handle_initialize(VALUE self, VALUE graph_obj, VALUE id_val) {
36
62
  HandleData *data;
37
63
  TypedData_Get_Struct(self, HandleData, &handle_type, data);
38
- data->graph_obj = graph_obj;
39
- data->id = NUM2ULL(id_val);
64
+
65
+ *data = (HandleData) {
66
+ .graph_obj = graph_obj,
67
+ .id = NUM2ULL(id_val),
68
+ };
40
69
 
41
70
  return self;
42
71
  }
@@ -1,5 +1,10 @@
1
1
  #include "location.h"
2
2
 
3
+ /*
4
+ * RDoc parser workaround for https://github.com/ruby/rdoc/issues/1744:
5
+ * mRubydex = rb_define_module("Rubydex")
6
+ */
7
+
3
8
  VALUE cLocation;
4
9
 
5
10
  VALUE rdxi_build_location_value(Location *loc) {