rubydex 0.1.0.beta11 → 0.1.0.beta13

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +23 -23
  3. data/README.md +125 -125
  4. data/THIRD_PARTY_LICENSES.html +2018 -945
  5. data/exe/rdx +47 -47
  6. data/ext/rubydex/declaration.c +453 -388
  7. data/ext/rubydex/declaration.h +23 -23
  8. data/ext/rubydex/definition.c +284 -197
  9. data/ext/rubydex/definition.h +28 -28
  10. data/ext/rubydex/diagnostic.c +6 -6
  11. data/ext/rubydex/diagnostic.h +11 -11
  12. data/ext/rubydex/document.c +97 -98
  13. data/ext/rubydex/document.h +10 -10
  14. data/ext/rubydex/extconf.rb +146 -127
  15. data/ext/rubydex/graph.c +701 -512
  16. data/ext/rubydex/graph.h +10 -10
  17. data/ext/rubydex/handle.h +44 -44
  18. data/ext/rubydex/location.c +22 -22
  19. data/ext/rubydex/location.h +15 -15
  20. data/ext/rubydex/reference.c +123 -104
  21. data/ext/rubydex/reference.h +15 -16
  22. data/ext/rubydex/rubydex.c +22 -22
  23. data/ext/rubydex/utils.c +108 -86
  24. data/ext/rubydex/utils.h +34 -28
  25. data/lib/rubydex/comment.rb +17 -17
  26. data/lib/rubydex/declaration.rb +11 -0
  27. data/lib/rubydex/diagnostic.rb +21 -21
  28. data/lib/rubydex/failures.rb +15 -15
  29. data/lib/rubydex/graph.rb +98 -92
  30. data/lib/rubydex/keyword.rb +17 -0
  31. data/lib/rubydex/keyword_parameter.rb +13 -0
  32. data/lib/rubydex/location.rb +90 -90
  33. data/lib/rubydex/mixin.rb +22 -0
  34. data/lib/rubydex/version.rb +5 -5
  35. data/lib/rubydex.rb +24 -20
  36. data/rbi/rubydex.rbi +425 -310
  37. data/rust/Cargo.lock +1851 -1851
  38. data/rust/Cargo.toml +29 -29
  39. data/rust/about.toml +10 -10
  40. data/rust/{about.hbs → about_templates/about.hbs} +81 -78
  41. data/rust/about_templates/mingw_licenses.hbs +1071 -0
  42. data/rust/rubydex/Cargo.toml +42 -42
  43. data/rust/rubydex/src/compile_assertions.rs +13 -13
  44. data/rust/rubydex/src/diagnostic.rs +110 -109
  45. data/rust/rubydex/src/errors.rs +28 -28
  46. data/rust/rubydex/src/indexing/local_graph.rs +224 -224
  47. data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -1554
  48. data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -6753
  49. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
  50. data/rust/rubydex/src/indexing.rs +210 -210
  51. data/rust/rubydex/src/integrity.rs +279 -278
  52. data/rust/rubydex/src/job_queue.rs +199 -205
  53. data/rust/rubydex/src/lib.rs +17 -17
  54. data/rust/rubydex/src/listing.rs +371 -272
  55. data/rust/rubydex/src/main.rs +160 -160
  56. data/rust/rubydex/src/model/built_in.rs +83 -0
  57. data/rust/rubydex/src/model/comment.rs +24 -24
  58. data/rust/rubydex/src/model/declaration.rs +679 -588
  59. data/rust/rubydex/src/model/definitions.rs +1682 -1602
  60. data/rust/rubydex/src/model/document.rs +222 -252
  61. data/rust/rubydex/src/model/encoding.rs +22 -22
  62. data/rust/rubydex/src/model/graph.rs +3782 -3556
  63. data/rust/rubydex/src/model/id.rs +110 -110
  64. data/rust/rubydex/src/model/identity_maps.rs +58 -58
  65. data/rust/rubydex/src/model/ids.rs +60 -38
  66. data/rust/rubydex/src/model/keywords.rs +256 -256
  67. data/rust/rubydex/src/model/name.rs +298 -298
  68. data/rust/rubydex/src/model/references.rs +111 -111
  69. data/rust/rubydex/src/model/string_ref.rs +50 -50
  70. data/rust/rubydex/src/model/visibility.rs +41 -41
  71. data/rust/rubydex/src/model.rs +15 -14
  72. data/rust/rubydex/src/offset.rs +147 -147
  73. data/rust/rubydex/src/position.rs +6 -6
  74. data/rust/rubydex/src/query.rs +1841 -1700
  75. data/rust/rubydex/src/resolution.rs +1852 -5895
  76. data/rust/rubydex/src/resolution_tests.rs +4701 -0
  77. data/rust/rubydex/src/stats/memory.rs +71 -71
  78. data/rust/rubydex/src/stats/orphan_report.rs +264 -263
  79. data/rust/rubydex/src/stats/timer.rs +127 -127
  80. data/rust/rubydex/src/stats.rs +11 -11
  81. data/rust/rubydex/src/test_utils/context.rs +226 -226
  82. data/rust/rubydex/src/test_utils/graph_test.rs +730 -679
  83. data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -602
  84. data/rust/rubydex/src/test_utils.rs +52 -52
  85. data/rust/rubydex/src/visualization/dot.rs +192 -176
  86. data/rust/rubydex/src/visualization.rs +6 -6
  87. data/rust/rubydex/tests/cli.rs +185 -167
  88. data/rust/rubydex-mcp/Cargo.toml +28 -28
  89. data/rust/rubydex-mcp/src/main.rs +48 -48
  90. data/rust/rubydex-mcp/src/server.rs +1145 -1145
  91. data/rust/rubydex-mcp/src/tools.rs +49 -49
  92. data/rust/rubydex-mcp/tests/mcp.rs +302 -302
  93. data/rust/rubydex-sys/Cargo.toml +20 -20
  94. data/rust/rubydex-sys/build.rs +14 -14
  95. data/rust/rubydex-sys/cbindgen.toml +12 -12
  96. data/rust/rubydex-sys/src/declaration_api.rs +485 -469
  97. data/rust/rubydex-sys/src/definition_api.rs +443 -352
  98. data/rust/rubydex-sys/src/diagnostic_api.rs +99 -99
  99. data/rust/rubydex-sys/src/document_api.rs +85 -54
  100. data/rust/rubydex-sys/src/graph_api.rs +1017 -700
  101. data/rust/rubydex-sys/src/lib.rs +79 -9
  102. data/rust/rubydex-sys/src/location_api.rs +79 -79
  103. data/rust/rubydex-sys/src/name_api.rs +187 -135
  104. data/rust/rubydex-sys/src/reference_api.rs +267 -195
  105. data/rust/rubydex-sys/src/utils.rs +70 -70
  106. data/rust/rustfmt.toml +2 -2
  107. metadata +16 -9
  108. data/lib/rubydex/librubydex_sys.so +0 -0
data/ext/rubydex/utils.c CHANGED
@@ -1,86 +1,108 @@
1
- #include "utils.h"
2
- #include "declaration.h"
3
- #include "reference.h"
4
- #include "rustbindings.h"
5
-
6
- // Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
7
- // This copies the data so it must be freed
8
- char **rdxi_str_array_to_char(VALUE array, size_t length) {
9
- char **converted_array = malloc(length * sizeof(char *));
10
-
11
- for (size_t i = 0; i < length; i++) {
12
- VALUE item = rb_ary_entry(array, i);
13
- const char *string = StringValueCStr(item);
14
-
15
- converted_array[i] = malloc(strlen(string) + 1);
16
- strcpy(converted_array[i], string);
17
- }
18
-
19
- return converted_array;
20
- }
21
-
22
- // Free a char** array allocated by rdxi_str_array_to_char
23
- void rdxi_free_str_array(char **array, size_t length) {
24
- if (array != NULL) {
25
- for (size_t i = 0; i < length; i++) {
26
- free(array[i]);
27
- }
28
- free(array);
29
- }
30
- }
31
-
32
- // Verify that the Ruby object is an array of strings or raise `TypeError`
33
- void rdxi_check_array_of_strings(VALUE array) {
34
- Check_Type(array, T_ARRAY);
35
-
36
- for (long i = 0; i < RARRAY_LEN(array); i++) {
37
- VALUE item = rb_ary_entry(array, i);
38
- Check_Type(item, T_STRING);
39
- }
40
- }
41
-
42
- // Yield body for iterating over declarations
43
- VALUE rdxi_declarations_yield(VALUE args) {
44
- VALUE self = rb_ary_entry(args, 0);
45
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
46
-
47
- CDeclaration decl;
48
- while (rdx_graph_declarations_iter_next(iter, &decl)) {
49
- VALUE decl_class = rdxi_declaration_class_for_kind(decl.kind);
50
- VALUE argv[] = {self, ULL2NUM(decl.id)};
51
- VALUE handle = rb_class_new_instance(2, argv, decl_class);
52
- rb_yield(handle);
53
- }
54
-
55
- return Qnil;
56
- }
57
-
58
- // Ensure function for iterating over declarations to always free the iterator
59
- VALUE rdxi_declarations_ensure(VALUE args) {
60
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
61
- rdx_graph_declarations_iter_free(iter);
62
- return Qnil;
63
- }
64
-
65
- // Yield body for iterating over references
66
- VALUE rdxi_references_yield(VALUE args) {
67
- VALUE graph_obj = rb_ary_entry(args, 0);
68
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
69
-
70
- CReference cref;
71
- while (rdx_references_iter_next(iter, &cref)) {
72
- VALUE ref_class = rdxi_reference_class_for_kind(cref.kind);
73
- VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
74
- VALUE obj = rb_class_new_instance(2, argv, ref_class);
75
- rb_yield(obj);
76
- }
77
-
78
- return Qnil;
79
- }
80
-
81
- // Ensure function for iterating over references to always free the iterator
82
- VALUE rdxi_references_ensure(VALUE args) {
83
- void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
84
- rdx_references_iter_free(iter);
85
- return Qnil;
86
- }
1
+ #include "utils.h"
2
+ #include "declaration.h"
3
+ #include "reference.h"
4
+ #include "rustbindings.h"
5
+
6
+ // Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
7
+ // This copies the data so it must be freed
8
+ char **rdxi_str_array_to_char(VALUE array, size_t length) {
9
+ char **converted_array = malloc(length * sizeof(char *));
10
+
11
+ for (size_t i = 0; i < length; i++) {
12
+ VALUE item = rb_ary_entry(array, i);
13
+ const char *string = StringValueCStr(item);
14
+
15
+ converted_array[i] = malloc(strlen(string) + 1);
16
+ strcpy(converted_array[i], string);
17
+ }
18
+
19
+ return converted_array;
20
+ }
21
+
22
+ // Free a char** array allocated by rdxi_str_array_to_char
23
+ void rdxi_free_str_array(char **array, size_t length) {
24
+ if (array != NULL) {
25
+ for (size_t i = 0; i < length; i++) {
26
+ free(array[i]);
27
+ }
28
+ free(array);
29
+ }
30
+ }
31
+
32
+ // Verify that the Ruby object is an array of strings or raise `TypeError`
33
+ void rdxi_check_array_of_strings(VALUE array) {
34
+ Check_Type(array, T_ARRAY);
35
+
36
+ for (long i = 0; i < RARRAY_LEN(array); i++) {
37
+ VALUE item = rb_ary_entry(array, i);
38
+ Check_Type(item, T_STRING);
39
+ }
40
+ }
41
+
42
+ // Yield body for iterating over declarations
43
+ VALUE rdxi_declarations_yield(VALUE args) {
44
+ VALUE self = rb_ary_entry(args, 0);
45
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
46
+
47
+ CDeclaration decl;
48
+ while (rdx_graph_declarations_iter_next(iter, &decl)) {
49
+ VALUE decl_class = rdxi_declaration_class_for_kind(decl.kind);
50
+ VALUE argv[] = {self, ULL2NUM(decl.id)};
51
+ VALUE handle = rb_class_new_instance(2, argv, decl_class);
52
+ rb_yield(handle);
53
+ }
54
+
55
+ return Qnil;
56
+ }
57
+
58
+ // Ensure function for iterating over declarations to always free the iterator
59
+ VALUE rdxi_declarations_ensure(VALUE args) {
60
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
61
+ rdx_graph_declarations_iter_free(iter);
62
+ return Qnil;
63
+ }
64
+
65
+ // Yield body for iterating over constant references
66
+ VALUE rdxi_constant_references_yield(VALUE args) {
67
+ VALUE graph_obj = rb_ary_entry(args, 0);
68
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
69
+
70
+ CConstantReference cref;
71
+ while (rdx_constant_references_iter_next(iter, &cref)) {
72
+ VALUE ref_class = (cref.declaration_id == 0)
73
+ ? cUnresolvedConstantReference
74
+ : cResolvedConstantReference;
75
+ VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
76
+ VALUE obj = rb_class_new_instance(2, argv, ref_class);
77
+ rb_yield(obj);
78
+ }
79
+ return Qnil;
80
+ }
81
+
82
+ // Ensure function for iterating over constant references to always free the iterator
83
+ VALUE rdxi_constant_references_ensure(VALUE args) {
84
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
85
+ rdx_constant_references_iter_free(iter);
86
+ return Qnil;
87
+ }
88
+
89
+ // Yield body for iterating over method references
90
+ VALUE rdxi_method_references_yield(VALUE args) {
91
+ VALUE graph_obj = rb_ary_entry(args, 0);
92
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
93
+
94
+ CMethodReference cref;
95
+ while (rdx_method_references_iter_next(iter, &cref)) {
96
+ VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
97
+ VALUE obj = rb_class_new_instance(2, argv, cMethodReference);
98
+ rb_yield(obj);
99
+ }
100
+ return Qnil;
101
+ }
102
+
103
+ // Ensure function for iterating over method references to always free the iterator
104
+ VALUE rdxi_method_references_ensure(VALUE args) {
105
+ void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
106
+ rdx_method_references_iter_free(iter);
107
+ return Qnil;
108
+ }
data/ext/rubydex/utils.h CHANGED
@@ -1,28 +1,34 @@
1
- #ifndef RUBYDEX_UTILS_H
2
- #define RUBYDEX_UTILS_H
3
-
4
- #include "ruby.h"
5
-
6
- // Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
7
- // This copies the data so it must be freed with rdxi_free_str_array
8
- char **rdxi_str_array_to_char(VALUE array, size_t length);
9
-
10
- // Free a char** array allocated by rdxi_str_array_to_char
11
- void rdxi_free_str_array(char **array, size_t length);
12
-
13
- // Verify that the Ruby object is an array of strings or raise `TypeError`
14
- void rdxi_check_array_of_strings(VALUE array);
15
-
16
- // Yield body for iterating over declarations
17
- VALUE rdxi_declarations_yield(VALUE args);
18
-
19
- // Ensure function for iterating over declarations to always free the iterator
20
- VALUE rdxi_declarations_ensure(VALUE args);
21
-
22
- // Yield body for iterating over references
23
- VALUE rdxi_references_yield(VALUE args);
24
-
25
- // Ensure function for iterating over references to always free the iterator
26
- VALUE rdxi_references_ensure(VALUE args);
27
-
28
- #endif // RUBYDEX_UTILS_H
1
+ #ifndef RUBYDEX_UTILS_H
2
+ #define RUBYDEX_UTILS_H
3
+
4
+ #include "ruby.h"
5
+
6
+ // Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
7
+ // This copies the data so it must be freed with rdxi_free_str_array
8
+ char **rdxi_str_array_to_char(VALUE array, size_t length);
9
+
10
+ // Free a char** array allocated by rdxi_str_array_to_char
11
+ void rdxi_free_str_array(char **array, size_t length);
12
+
13
+ // Verify that the Ruby object is an array of strings or raise `TypeError`
14
+ void rdxi_check_array_of_strings(VALUE array);
15
+
16
+ // Yield body for iterating over declarations
17
+ VALUE rdxi_declarations_yield(VALUE args);
18
+
19
+ // Ensure function for iterating over declarations to always free the iterator
20
+ VALUE rdxi_declarations_ensure(VALUE args);
21
+
22
+ // Yield body for iterating over constant references
23
+ VALUE rdxi_constant_references_yield(VALUE args);
24
+
25
+ // Ensure function for iterating over constant references
26
+ VALUE rdxi_constant_references_ensure(VALUE args);
27
+
28
+ // Yield body for iterating over method references
29
+ VALUE rdxi_method_references_yield(VALUE args);
30
+
31
+ // Ensure function for iterating over method references
32
+ VALUE rdxi_method_references_ensure(VALUE args);
33
+
34
+ #endif // RUBYDEX_UTILS_H
@@ -1,17 +1,17 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubydex
4
- class Comment
5
- #: String
6
- attr_reader :string
7
-
8
- #: Location
9
- attr_reader :location
10
-
11
- #: (?string: String, ?location: Location) -> void
12
- def initialize(string:, location:)
13
- @string = string
14
- @location = location
15
- end
16
- end
17
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Comment
5
+ #: String
6
+ attr_reader :string
7
+
8
+ #: Location
9
+ attr_reader :location
10
+
11
+ #: (?string: String, ?location: Location) -> void
12
+ def initialize(string:, location:)
13
+ @string = string
14
+ @location = location
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Declaration
5
+ # @abstract
6
+ #: () -> Enumerable[Reference]
7
+ def references
8
+ raise NotImplementedError, "Subclasses must implement #references"
9
+ end
10
+ end
11
+ end
@@ -1,21 +1,21 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubydex
4
- class Diagnostic
5
- #: Symbol
6
- attr_reader :rule
7
-
8
- #: String
9
- attr_reader :message
10
-
11
- #: Location
12
- attr_reader :location
13
-
14
- #: (rule: Symbol, message: String, location: Location) -> void
15
- def initialize(rule:, message:, location:)
16
- @rule = rule
17
- @message = message
18
- @location = location
19
- end
20
- end
21
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Diagnostic
5
+ #: Symbol
6
+ attr_reader :rule
7
+
8
+ #: String
9
+ attr_reader :message
10
+
11
+ #: Location
12
+ attr_reader :location
13
+
14
+ #: (rule: Symbol, message: String, location: Location) -> void
15
+ def initialize(rule:, message:, location:)
16
+ @rule = rule
17
+ @message = message
18
+ @location = location
19
+ end
20
+ end
21
+ end
@@ -1,15 +1,15 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubydex
4
- class Failure
5
- #: String
6
- attr_reader :message
7
-
8
- #: (String) -> void
9
- def initialize(message)
10
- @message = message
11
- end
12
- end
13
-
14
- class IntegrityFailure < Failure; end
15
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Failure
5
+ #: String
6
+ attr_reader :message
7
+
8
+ #: (String) -> void
9
+ def initialize(message)
10
+ @message = message
11
+ end
12
+ end
13
+
14
+ class IntegrityFailure < Failure; end
15
+ end
data/lib/rubydex/graph.rb CHANGED
@@ -1,92 +1,98 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubydex
4
- # The global graph representing all declarations and their relationships for the workspace
5
- #
6
- # Note: this class is partially defined in C to integrate with the Rust backend
7
- class Graph
8
- IGNORED_DIRECTORIES = [
9
- ".bundle",
10
- ".git",
11
- ".github",
12
- "node_modules",
13
- "tmp",
14
- ].freeze
15
-
16
- #: String
17
- attr_accessor :workspace_path
18
-
19
- #: (?workspace_path: String) -> void
20
- def initialize(workspace_path: Dir.pwd)
21
- @workspace_path = workspace_path
22
- end
23
-
24
- # Index all files and dependencies of the workspace that exists in `@workspace_path`
25
- #: -> Array[String]
26
- def index_workspace
27
- index_all(workspace_paths)
28
- end
29
-
30
- # Returns all workspace paths that should be indexed, excluding directories that we don't need to descend into such
31
- # as `.git`, `node_modules`. Also includes any top level Ruby files
32
- #
33
- #: -> Array[String]
34
- def workspace_paths
35
- paths = []
36
-
37
- Dir.each_child(@workspace_path) do |entry|
38
- full_path = File.join(@workspace_path, entry)
39
-
40
- if File.directory?(full_path)
41
- paths << full_path unless IGNORED_DIRECTORIES.include?(entry)
42
- elsif File.extname(entry) == ".rb"
43
- paths << full_path
44
- end
45
- end
46
-
47
- add_workspace_dependency_paths(paths)
48
- add_core_rbs_definition_paths(paths)
49
- paths.uniq!
50
- paths
51
- end
52
-
53
- private
54
-
55
- # Gathers the paths we have to index for all workspace dependencies
56
- #: (Array[String]) -> void
57
- def add_workspace_dependency_paths(paths)
58
- specs = Bundler.locked_gems&.specs
59
- return unless specs
60
-
61
- specs.each do |lazy_spec|
62
- spec = Gem::Specification.find_by_name(lazy_spec.name)
63
- spec.require_paths.each do |path|
64
- # For native extensions, RubyGems inserts an absolute require path pointing to
65
- # `gems/some-gem-1.0.0/extensions`. Those paths don't actually include any Ruby files inside, so we can skip
66
- # descending them
67
- next if File.absolute_path?(path)
68
-
69
- paths << File.join(spec.full_gem_path, path)
70
- end
71
- rescue Gem::MissingSpecError
72
- nil
73
- end
74
- end
75
-
76
- # Searches for the latest installation of the `rbs` gem and adds the paths for the core and stdlib RBS definitions
77
- # to the list of paths. This method does not require `rbs` to be a part of the bundle. It searches for whatever
78
- # latest installation of `rbs` exists in the system and fails silently if we can't find one
79
- #
80
- #: (Array[String]) -> void
81
- def add_core_rbs_definition_paths(paths)
82
- rbs_gem_path = Gem.path
83
- .flat_map { |path| Dir.glob(File.join(path, "gems", "rbs-[0-9]*/")) }
84
- .max_by { |path| Gem::Version.new(File.basename(path).delete_prefix("rbs-")) }
85
-
86
- return unless rbs_gem_path
87
-
88
- paths << File.join(rbs_gem_path, "core")
89
- paths << File.join(rbs_gem_path, "stdlib")
90
- end
91
- end
92
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ # The global graph representing all declarations and their relationships for the workspace
5
+ #
6
+ # Note: this class is partially defined in C to integrate with the Rust backend
7
+ class Graph
8
+ IGNORED_DIRECTORIES = [
9
+ ".bundle",
10
+ ".claude",
11
+ ".git",
12
+ ".github",
13
+ ".ruby-lsp",
14
+ ".vscode",
15
+ "log",
16
+ "node_modules",
17
+ "tmp",
18
+ ].freeze
19
+
20
+ #: String
21
+ attr_accessor :workspace_path
22
+
23
+ #: (?workspace_path: String) -> void
24
+ def initialize(workspace_path: Dir.pwd)
25
+ @workspace_path = workspace_path
26
+
27
+ exclude_paths(IGNORED_DIRECTORIES.map { |dir| File.join(@workspace_path, dir) })
28
+ end
29
+
30
+ # Index all files and dependencies of the workspace that exists in `@workspace_path`
31
+ #: -> Array[String]
32
+ def index_workspace
33
+ index_all(workspace_paths)
34
+ end
35
+
36
+ # Returns all workspace paths that should be indexed, excluding directories that we don't need to descend into such
37
+ # as `.git`, `node_modules`. Also includes any top level Ruby files
38
+ #
39
+ #: -> Array[String]
40
+ def workspace_paths
41
+ paths = []
42
+
43
+ Dir.each_child(@workspace_path) do |entry|
44
+ full_path = File.join(@workspace_path, entry)
45
+
46
+ if File.directory?(full_path)
47
+ paths << full_path unless IGNORED_DIRECTORIES.include?(entry)
48
+ elsif File.extname(entry) == ".rb"
49
+ paths << full_path
50
+ end
51
+ end
52
+
53
+ add_workspace_dependency_paths(paths)
54
+ add_core_rbs_definition_paths(paths)
55
+ paths.uniq!
56
+ paths
57
+ end
58
+
59
+ private
60
+
61
+ # Gathers the paths we have to index for all workspace dependencies
62
+ #: (Array[String]) -> void
63
+ def add_workspace_dependency_paths(paths)
64
+ specs = Bundler.locked_gems&.specs
65
+ return unless specs
66
+
67
+ specs.each do |lazy_spec|
68
+ spec = Gem::Specification.find_by_name(lazy_spec.name)
69
+ spec.require_paths.each do |path|
70
+ # For native extensions, RubyGems inserts an absolute require path pointing to
71
+ # `gems/some-gem-1.0.0/extensions`. Those paths don't actually include any Ruby files inside, so we can skip
72
+ # descending them
73
+ next if File.absolute_path?(path)
74
+
75
+ paths << File.join(spec.full_gem_path, path)
76
+ end
77
+ rescue Gem::MissingSpecError
78
+ nil
79
+ end
80
+ end
81
+
82
+ # Searches for the latest installation of the `rbs` gem and adds the paths for the core and stdlib RBS definitions
83
+ # to the list of paths. This method does not require `rbs` to be a part of the bundle. It searches for whatever
84
+ # latest installation of `rbs` exists in the system and fails silently if we can't find one
85
+ #
86
+ #: (Array[String]) -> void
87
+ def add_core_rbs_definition_paths(paths)
88
+ rbs_gem_path = Gem.path
89
+ .flat_map { |path| Dir.glob(File.join(path, "gems", "rbs-[0-9]*/")) }
90
+ .max_by { |path| Gem::Version.new(File.basename(path).delete_prefix("rbs-")) }
91
+
92
+ return unless rbs_gem_path
93
+
94
+ paths << File.join(rbs_gem_path, "core")
95
+ paths << File.join(rbs_gem_path, "stdlib")
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Keyword
5
+ #: String
6
+ attr_reader :name
7
+
8
+ #: String
9
+ attr_reader :documentation
10
+
11
+ #: (String name, String documentation) -> void
12
+ def initialize(name, documentation)
13
+ @name = name
14
+ @documentation = documentation
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class KeywordParameter
5
+ #: String
6
+ attr_reader :name
7
+
8
+ #: (String name) -> void
9
+ def initialize(name)
10
+ @name = name
11
+ end
12
+ end
13
+ end