class Rubydex::Graph
The global graph representing all declarations and their relationships for the workspace
Note: this class is partially defined in C to integrate with the Rust backend
Constants
- INDEXABLE_EXTENSIONS
Public Class Methods
(?workspace_path: String?) → void
Source
# File lib/rubydex/graph.rb, line 11 def initialize(workspace_path: nil) self.workspace_path = workspace_path if workspace_path end
Public Instance Methods
static VALUE rdxr_graph_aref(VALUE self, VALUE key) {
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
if (TYPE(key) != T_STRING) {
rb_raise(rb_eTypeError, "expected String");
}
const CDeclaration *decl = rdx_graph_get_declaration(graph, StringValueCStr(key));
if (decl == NULL) {
return Qnil;
}
VALUE decl_class = rdxi_declaration_class_for_kind(decl->kind);
VALUE argv[] = {self, ULL2NUM(decl->id)};
free_c_declaration(decl);
return rb_class_new_instance(2, argv, decl_class);
}
Returns the declaration for the fully qualified name, or nil when no declaration exists.
static VALUE rdxr_graph_check_integrity(VALUE self) {
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
size_t error_count = 0;
const char *const *errors = rdx_check_integrity(graph, &error_count);
if (errors == NULL) {
return rb_ary_new();
}
VALUE cIntegrityError = rb_const_get(mRubydex, rb_intern("IntegrityFailure"));
VALUE array = rb_ary_new_capa((long)error_count);
for (size_t i = 0; i < error_count; i++) {
VALUE argv[] = {rb_utf8_str_new_cstr(errors[i])};
VALUE error = rb_class_new_instance(1, argv, cIntegrityError);
rb_ary_push(array, error);
}
free_c_string_array(errors, error_count);
return array;
}
Returns an array of integrity failures, or an empty array if no issues were found.
Source
static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
VALUE nesting, opts;
rb_scan_args(argc, argv, "1:", &nesting, &opts);
rdxi_check_array_of_strings(nesting);
const char *self_receiver = extract_self_receiver(opts);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
size_t nesting_count = RARRAY_LEN(nesting);
char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
struct CompletionResult result =
rdx_graph_complete_expression(graph, (const char *const *)converted_nesting, nesting_count, self_receiver);
rdxi_free_str_array(converted_nesting, nesting_count);
return completion_result_to_ruby_array(result, self);
}
Returns completion candidates for an expression context. The nesting array represents the lexical scope stack. The required self_receiver keyword argument overrides the self type; pass nil when the self type is unknown.
static VALUE rdxr_graph_complete_method_argument(int argc, VALUE *argv, VALUE self) {
VALUE name, nesting, opts;
rb_scan_args(argc, argv, "2:", &name, &nesting, &opts);
Check_Type(name, T_STRING);
rdxi_check_array_of_strings(nesting);
const char *self_receiver = extract_self_receiver(opts);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
size_t nesting_count = RARRAY_LEN(nesting);
char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
struct CompletionResult result = rdx_graph_complete_method_argument(
graph, StringValueCStr(name), (const char *const *)converted_nesting, nesting_count, self_receiver);
rdxi_free_str_array(converted_nesting, nesting_count);
return completion_result_to_ruby_array(result, self);
}
Returns completion candidates inside a method call’s argument list. See complete_expression for self_receiver semantics.
static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self) {
VALUE name, opts;
rb_scan_args(argc, argv, "1:", &name, &opts);
Check_Type(name, T_STRING);
const char *self_receiver = extract_self_receiver(opts);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
struct CompletionResult result =
rdx_graph_complete_method_call(graph, StringValueCStr(name), self_receiver);
return completion_result_to_ruby_array(result, self);
}
Returns completion candidates after a method call operator such as foo. The required self_receiver keyword argument is the caller’s runtime self type; pass nil when there is no caller context.
static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE self) {
VALUE name, opts;
rb_scan_args(argc, argv, "1:", &name, &opts);
Check_Type(name, T_STRING);
const char *self_receiver = extract_self_receiver(opts);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
struct CompletionResult result =
rdx_graph_complete_namespace_access(graph, StringValueCStr(name), self_receiver);
return completion_result_to_ruby_array(result, self);
}
Returns completion candidates after a namespace access operator such as Foo::. The required self_receiver keyword argument is the caller’s runtime self type; pass nil when there is no caller context.
static VALUE rdxr_graph_constant_references(VALUE self) {
if (!rb_block_given_p()) {
return rb_enumeratorize_with_size(self, rb_str_new2("constant_references"), 0, NULL,
graph_constant_references_size);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
void *iter = rdx_graph_constant_references_iter_new(graph);
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
rb_ensure(rdxi_constant_references_yield, args, rdxi_constant_references_ensure, args);
return self;
}
Returns an enumerator that yields constant references lazily.
static VALUE rdxr_graph_declarations(VALUE self) {
if (!rb_block_given_p()) {
return rb_enumeratorize_with_size(self, rb_str_new2("declarations"), 0, NULL, graph_declarations_size);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
void *iter = rdx_graph_declarations_iter_new(graph);
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
rb_ensure(rdxi_declarations_yield, args, rdxi_declarations_ensure, args);
return self;
}
Returns an enumerator that yields all declarations lazily.
static VALUE rdxr_graph_delete_document(VALUE self, VALUE uri) {
Check_Type(uri, T_STRING);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const uint64_t *uri_id = rdx_graph_delete_document(graph, StringValueCStr(uri));
if (uri_id == NULL) {
return Qnil;
}
VALUE argv[] = {self, ULL2NUM(*uri_id)};
free_u64(uri_id);
return rb_class_new_instance(2, argv, cDocument);
}
Deletes a document and all of its definitions from the graph. Returns the removed document, or nil if it does not exist.
static VALUE rdxr_graph_diagnostics(VALUE self) {
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
DiagnosticArray *array = rdx_graph_diagnostics(graph);
if (array == NULL || array->len == 0) {
if (array != NULL) {
rdx_diagnostics_free(array);
}
return rb_ary_new();
}
VALUE diagnostics = rb_ary_new_capa((long)array->len);
for (size_t i = 0; i < array->len; i++) {
DiagnosticEntry entry = array->items[i];
VALUE message = entry.message == NULL ? Qnil : rb_utf8_str_new_cstr(entry.message);
VALUE rule = rb_str_intern(rb_str_new2(entry.rule));
VALUE location = rdxi_build_location_value(entry.location);
VALUE kwargs = rb_hash_new();
rb_hash_aset(kwargs, ID2SYM(rb_intern("rule")), rule);
rb_hash_aset(kwargs, ID2SYM(rb_intern("message")), message);
rb_hash_aset(kwargs, ID2SYM(rb_intern("location")), location);
VALUE diagnostic = rb_class_new_instance_kw(1, &kwargs, cDiagnostic, RB_PASS_KEYWORDS);
rb_ary_push(diagnostics, diagnostic);
}
rdx_diagnostics_free(array);
return diagnostics;
}
Returns diagnostics emitted while indexing or resolving the graph.
static VALUE rdxr_graph_document(VALUE self, VALUE uri) {
Check_Type(uri, T_STRING);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const uint64_t *uri_id = rdx_graph_get_document(graph, StringValueCStr(uri));
if (uri_id == NULL) {
return Qnil;
}
VALUE argv[] = {self, ULL2NUM(*uri_id)};
free_u64(uri_id);
return rb_class_new_instance(2, argv, cDocument);
}
Returns the document for the URI, or nil if it does not exist.
static VALUE rdxr_graph_documents(VALUE self) {
if (!rb_block_given_p()) {
return rb_enumeratorize_with_size(self, rb_str_new2("documents"), 0, NULL, graph_documents_size);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
void *iter = rdx_graph_documents_iter_new(graph);
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
rb_ensure(graph_documents_yield, args, graph_documents_ensure, args);
return self;
}
Returns an enumerator that yields all documents lazily.
Source
static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
Check_Type(encoding, T_STRING);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
char *encoding_string = StringValueCStr(encoding);
if (!rdx_graph_set_encoding(graph, encoding_string)) {
rb_raise(rb_eArgError, "invalid encoding `%s` (should be utf8, utf16 or utf32)", encoding_string);
}
return Qnil;
}
Sets the encoding used for transforming byte offsets into LSP code unit line and column positions.
Source
static VALUE rdxr_graph_exclude_paths(VALUE self, VALUE paths) {
Check_Type(paths, T_ARRAY);
rdxi_check_array_of_strings(paths);
size_t length = RARRAY_LEN(paths);
char **converted_paths = rdxi_str_array_to_char(paths, length);
void *graph;
TypedData_Get_Struct(self, void*, &graph_type, graph);
rdx_graph_exclude_paths(graph, (const char **)converted_paths, length);
rdxi_free_str_array(converted_paths, length);
return Qnil;
}
Excludes the paths from file discovery during indexing.
static VALUE rdxr_graph_excluded_paths(VALUE self) {
void *graph;
TypedData_Get_Struct(self, void*, &graph_type, graph);
size_t out_count = 0;
const char *const *results = rdx_graph_excluded_paths(graph, &out_count);
if (results == NULL) {
return rb_ary_new();
}
VALUE array = rb_ary_new_capa((long)out_count);
for (size_t i = 0; i < out_count; i++) {
rb_ary_push(array, rb_utf8_str_new_cstr(results[i]));
}
free_c_string_array(results, out_count);
return array;
}
Returns the paths currently excluded from file discovery.
static VALUE rdxr_graph_fuzzy_search(VALUE self, VALUE query) {
Check_Type(query, T_STRING);
if (!rb_block_given_p()) {
return rb_enumeratorize(self, rb_str_new2("fuzzy_search"), 1, &query);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
return rdxr_graph_yield_search_results(self, rdx_graph_declarations_fuzzy_search(graph, StringValueCStr(query)));
}
Returns an enumerator that yields declarations matching the query fuzzily.
static VALUE rdxr_graph_index_all(VALUE self, VALUE file_paths) {
rdxi_check_array_of_strings(file_paths);
// Convert the given file paths into a char** array, so that we can pass to Rust
size_t length = RARRAY_LEN(file_paths);
char **converted_file_paths = rdxi_str_array_to_char(file_paths, length);
// Get the underlying graph pointer and then invoke the Rust index all implementation
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
size_t error_count = 0;
const char *const *errors = rdx_index_all(graph, (const char **)converted_file_paths, length, &error_count);
rdxi_free_str_array(converted_file_paths, length);
if (errors == NULL) {
return rb_ary_new();
}
VALUE array = rb_ary_new_capa((long)error_count);
for (size_t i = 0; i < error_count; i++) {
rb_ary_push(array, rb_utf8_str_new_cstr(errors[i]));
}
free_c_string_array(errors, error_count);
return array;
}
Returns an array of I/O error messages encountered during indexing.
static VALUE rdxr_graph_index_source(VALUE self, VALUE uri, VALUE source, VALUE language_id) {
Check_Type(uri, T_STRING);
Check_Type(source, T_STRING);
Check_Type(language_id, T_STRING);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const char *uri_str = StringValueCStr(uri);
const char *language_id_str = StringValueCStr(language_id);
const char *source_str = RSTRING_PTR(source);
size_t source_len = RSTRING_LEN(source);
enum IndexSourceResult result = rdx_index_source(graph, uri_str, source_str, source_len, language_id_str);
switch (result) {
case IndexSourceResult_Success:
break;
case IndexSourceResult_InvalidUri:
rb_raise(rb_eArgError, "invalid URI (not valid UTF-8)");
break;
case IndexSourceResult_InvalidSource:
rb_raise(rb_eArgError, "source is not valid UTF-8");
break;
case IndexSourceResult_InvalidLanguageId:
rb_raise(rb_eArgError, "invalid language_id (not valid UTF-8)");
break;
case IndexSourceResult_UnsupportedLanguageId:
rb_raise(rb_eArgError, "unsupported language_id `%s`", language_id_str);
break;
}
return Qnil;
}
Indexes a single source string in memory, dispatching to the appropriate indexer based on language_id.
→ Array[String]
Source
# File lib/rubydex/graph.rb, line 17 def index_workspace index_all(workspace_paths) end
Index all files and dependencies of the workspace that exists in workspace_path
static VALUE rdxr_graph_keyword(VALUE self, VALUE name) {
Check_Type(name, T_STRING);
const CKeyword *kw = rdx_keyword_get(StringValueCStr(name));
if (kw == NULL) {
return Qnil;
}
VALUE argv[2] = {
rb_utf8_str_new_cstr(kw->name),
rb_utf8_str_new_cstr(kw->documentation),
};
rdx_keyword_free(kw);
return rb_class_new_instance(2, argv, cKeyword);
}
Returns the keyword object for the name, or nil if it is not a Ruby keyword.
static VALUE rdxr_graph_load_config(int argc, VALUE *argv, VALUE self) {
VALUE config_path;
rb_scan_args(argc, argv, "01", &config_path);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const char *config_path_cstr = NULL;
if (!NIL_P(config_path)) {
Check_Type(config_path, T_STRING);
config_path_cstr = StringValueCStr(config_path);
}
const char *error = rdx_graph_load_config(graph, config_path_cstr);
if (error == NULL) {
return Qnil;
}
VALUE message = rb_utf8_str_new_cstr(error);
free_c_string(error);
VALUE config_error = rb_const_get(mRubydex, rb_intern("ConfigError"));
rb_exc_raise(rb_exc_new_str(config_error, message));
}
Loads a configuration file for the graph. If config_path is nil, loads the default configuration file at workspace_path/rubydex.toml if it exists. Will raise on malformed files or if an explicit path is given but the file does not exist.
static VALUE rdxr_graph_method_references(VALUE self) {
if (!rb_block_given_p()) {
return rb_enumeratorize_with_size(self, rb_str_new2("method_references"), 0, NULL,
graph_method_references_size);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
void *iter = rdx_graph_method_references_iter_new(graph);
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
rb_ensure(rdxi_method_references_yield, args, rdxi_method_references_ensure, args);
return self;
}
Returns an enumerator that yields method references lazily.
static VALUE rdxr_graph_require_paths(VALUE self, VALUE load_path) {
rdxi_check_array_of_strings(load_path);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
size_t paths_len = RARRAY_LEN(load_path);
char **converted_paths = rdxi_str_array_to_char(load_path, paths_len);
size_t out_count = 0;
const char *const *results = rdx_require_paths(graph, (const char **)converted_paths, paths_len, &out_count);
rdxi_free_str_array(converted_paths, paths_len);
if (results == NULL) {
return rb_ary_new();
}
VALUE array = rb_ary_new_capa((long)out_count);
for (size_t i = 0; i < out_count; i++) {
rb_ary_push(array, rb_utf8_str_new_cstr(results[i]));
}
free_c_string_array(results, out_count);
return array;
}
Returns all require paths for completion.
Source
static VALUE rdxr_graph_resolve(VALUE self) {
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
rdx_graph_resolve(graph);
return self;
}
Runs the resolver to compute declarations and ownership.
static VALUE rdxr_graph_resolve_constant(VALUE self, VALUE const_name, VALUE nesting) {
Check_Type(const_name, T_STRING);
rdxi_check_array_of_strings(nesting);
// Convert the given file paths into a char** array, so that we can pass to Rust
size_t length = RARRAY_LEN(nesting);
char **converted_file_paths = rdxi_str_array_to_char(nesting, length);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const CDeclaration *decl =
rdx_graph_resolve_constant(graph, StringValueCStr(const_name), (const char **)converted_file_paths, length);
rdxi_free_str_array(converted_file_paths, length);
if (decl == NULL) {
return Qnil;
}
VALUE decl_class = rdxi_declaration_class_for_kind(decl->kind);
VALUE argv[] = {self, ULL2NUM(decl->id)};
free_c_declaration(decl);
return rb_class_new_instance(2, argv, decl_class);
}
Runs the resolver on a single constant reference to determine what it points to.
static VALUE rdxr_graph_resolve_require_path(VALUE self, VALUE require_path, VALUE load_paths) {
Check_Type(require_path, T_STRING);
rdxi_check_array_of_strings(load_paths);
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
const char *path_str = StringValueCStr(require_path);
size_t paths_len = RARRAY_LEN(load_paths);
char **converted_paths = rdxi_str_array_to_char(load_paths, paths_len);
const uint64_t *uri_id = rdx_resolve_require_path(graph, path_str, (const char **)converted_paths, paths_len);
rdxi_free_str_array(converted_paths, paths_len);
if (uri_id == NULL) {
return Qnil;
}
VALUE argv[] = {self, ULL2NUM(*uri_id)};
free_u64(uri_id);
return rb_class_new_instance(2, argv, cDocument);
}
Resolves a require path to its document.
static VALUE rdxr_graph_search(VALUE self, VALUE query) {
Check_Type(query, T_STRING);
if (!rb_block_given_p()) {
return rb_enumeratorize(self, rb_str_new2("search"), 1, &query);
}
void *graph;
TypedData_Get_Struct(self, void *, &graph_type, graph);
return rdxr_graph_yield_search_results(self, rdx_graph_declarations_search(graph, StringValueCStr(query)));
}
Returns an enumerator that yields declarations matching the query exactly by substring.
Source
static VALUE rdxr_graph_workspace_path(VALUE self) {
void *graph;
TypedData_Get_Struct(self, void*, &graph_type, graph);
const char *result = rdx_graph_workspace_path(graph);
if (result == NULL) {
rb_raise(rb_eRuntimeError, "Converting workspace path to Ruby string failed");
}
VALUE path = rdxi_owned_c_string_to_ruby(result);
return path;
}
Returns the root directory of the workspace being indexed.
Source
static VALUE rdxr_graph_set_workspace_path(VALUE self, VALUE path) {
Check_Type(path, T_STRING);
void *graph;
TypedData_Get_Struct(self, void*, &graph_type, graph);
rdx_graph_set_workspace_path(graph, StringValueCStr(path));
return path;
}
Sets the root directory of the workspace being indexed.
→ Array[String]
Source
# File lib/rubydex/graph.rb, line 24 def workspace_paths paths = [] root = workspace_path Dir.each_child(root) do |entry| full_path = File.join(root, entry) if File.directory?(full_path) || INDEXABLE_EXTENSIONS.include?(File.extname(entry)) paths << full_path end end add_workspace_dependency_paths(paths) add_core_rbs_definition_paths(paths) paths.uniq! paths end
Returns all workspace paths that should be indexed