rubydex 0.1.0.beta12-aarch64-linux
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +125 -0
- data/THIRD_PARTY_LICENSES.html +4562 -0
- data/exe/rdx +47 -0
- data/ext/rubydex/declaration.c +453 -0
- data/ext/rubydex/declaration.h +23 -0
- data/ext/rubydex/definition.c +284 -0
- data/ext/rubydex/definition.h +28 -0
- data/ext/rubydex/diagnostic.c +6 -0
- data/ext/rubydex/diagnostic.h +11 -0
- data/ext/rubydex/document.c +97 -0
- data/ext/rubydex/document.h +10 -0
- data/ext/rubydex/extconf.rb +138 -0
- data/ext/rubydex/graph.c +681 -0
- data/ext/rubydex/graph.h +10 -0
- data/ext/rubydex/handle.h +44 -0
- data/ext/rubydex/location.c +22 -0
- data/ext/rubydex/location.h +15 -0
- data/ext/rubydex/reference.c +123 -0
- data/ext/rubydex/reference.h +15 -0
- data/ext/rubydex/rubydex.c +22 -0
- data/ext/rubydex/utils.c +108 -0
- data/ext/rubydex/utils.h +34 -0
- data/lib/rubydex/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/comment.rb +17 -0
- data/lib/rubydex/diagnostic.rb +21 -0
- data/lib/rubydex/failures.rb +15 -0
- data/lib/rubydex/graph.rb +98 -0
- data/lib/rubydex/keyword.rb +17 -0
- data/lib/rubydex/keyword_parameter.rb +13 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/location.rb +90 -0
- data/lib/rubydex/mixin.rb +22 -0
- data/lib/rubydex/version.rb +5 -0
- data/lib/rubydex.rb +23 -0
- data/rbi/rubydex.rbi +422 -0
- data/rust/Cargo.lock +1851 -0
- data/rust/Cargo.toml +29 -0
- data/rust/about.hbs +78 -0
- data/rust/about.toml +10 -0
- data/rust/rubydex/Cargo.toml +42 -0
- data/rust/rubydex/src/compile_assertions.rs +13 -0
- data/rust/rubydex/src/diagnostic.rs +110 -0
- data/rust/rubydex/src/errors.rs +28 -0
- data/rust/rubydex/src/indexing/local_graph.rs +224 -0
- data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -0
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
- data/rust/rubydex/src/indexing.rs +210 -0
- data/rust/rubydex/src/integrity.rs +279 -0
- data/rust/rubydex/src/job_queue.rs +205 -0
- data/rust/rubydex/src/lib.rs +17 -0
- data/rust/rubydex/src/listing.rs +371 -0
- data/rust/rubydex/src/main.rs +160 -0
- data/rust/rubydex/src/model/built_in.rs +83 -0
- data/rust/rubydex/src/model/comment.rs +24 -0
- data/rust/rubydex/src/model/declaration.rs +671 -0
- data/rust/rubydex/src/model/definitions.rs +1682 -0
- data/rust/rubydex/src/model/document.rs +222 -0
- data/rust/rubydex/src/model/encoding.rs +22 -0
- data/rust/rubydex/src/model/graph.rs +3754 -0
- data/rust/rubydex/src/model/id.rs +110 -0
- data/rust/rubydex/src/model/identity_maps.rs +58 -0
- data/rust/rubydex/src/model/ids.rs +60 -0
- data/rust/rubydex/src/model/keywords.rs +256 -0
- data/rust/rubydex/src/model/name.rs +298 -0
- data/rust/rubydex/src/model/references.rs +111 -0
- data/rust/rubydex/src/model/string_ref.rs +50 -0
- data/rust/rubydex/src/model/visibility.rs +41 -0
- data/rust/rubydex/src/model.rs +15 -0
- data/rust/rubydex/src/offset.rs +147 -0
- data/rust/rubydex/src/position.rs +6 -0
- data/rust/rubydex/src/query.rs +1841 -0
- data/rust/rubydex/src/resolution.rs +6517 -0
- data/rust/rubydex/src/stats/memory.rs +71 -0
- data/rust/rubydex/src/stats/orphan_report.rs +264 -0
- data/rust/rubydex/src/stats/timer.rs +127 -0
- data/rust/rubydex/src/stats.rs +11 -0
- data/rust/rubydex/src/test_utils/context.rs +226 -0
- data/rust/rubydex/src/test_utils/graph_test.rs +730 -0
- data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -0
- data/rust/rubydex/src/test_utils.rs +52 -0
- data/rust/rubydex/src/visualization/dot.rs +192 -0
- data/rust/rubydex/src/visualization.rs +6 -0
- data/rust/rubydex/tests/cli.rs +185 -0
- data/rust/rubydex-mcp/Cargo.toml +28 -0
- data/rust/rubydex-mcp/src/main.rs +48 -0
- data/rust/rubydex-mcp/src/server.rs +1145 -0
- data/rust/rubydex-mcp/src/tools.rs +49 -0
- data/rust/rubydex-mcp/tests/mcp.rs +302 -0
- data/rust/rubydex-sys/Cargo.toml +20 -0
- data/rust/rubydex-sys/build.rs +14 -0
- data/rust/rubydex-sys/cbindgen.toml +12 -0
- data/rust/rubydex-sys/src/declaration_api.rs +485 -0
- data/rust/rubydex-sys/src/definition_api.rs +443 -0
- data/rust/rubydex-sys/src/diagnostic_api.rs +99 -0
- data/rust/rubydex-sys/src/document_api.rs +85 -0
- data/rust/rubydex-sys/src/graph_api.rs +948 -0
- data/rust/rubydex-sys/src/lib.rs +79 -0
- data/rust/rubydex-sys/src/location_api.rs +79 -0
- data/rust/rubydex-sys/src/name_api.rs +135 -0
- data/rust/rubydex-sys/src/reference_api.rs +267 -0
- data/rust/rubydex-sys/src/utils.rs +70 -0
- data/rust/rustfmt.toml +2 -0
- metadata +159 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
use schemars::JsonSchema;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, serde::Deserialize, JsonSchema)]
|
|
4
|
+
pub struct SearchDeclarationsParams {
|
|
5
|
+
#[schemars(description = "Search query to match against declaration names")]
|
|
6
|
+
pub query: String,
|
|
7
|
+
#[schemars(description = "Filter by declaration kind: Class, Module, Method, Constant, etc.")]
|
|
8
|
+
pub kind: Option<String>,
|
|
9
|
+
#[schemars(
|
|
10
|
+
description = "Matching mode: \"fuzzy\" (default) for LSP-style workspace symbol search, or \"exact\" for precise substring matching"
|
|
11
|
+
)]
|
|
12
|
+
pub match_mode: Option<String>,
|
|
13
|
+
#[schemars(description = "Maximum number of results to return (default 50, max 100)")]
|
|
14
|
+
pub limit: Option<usize>,
|
|
15
|
+
#[schemars(description = "Number of results to skip for pagination (default 0)")]
|
|
16
|
+
pub offset: Option<usize>,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[derive(Debug, serde::Deserialize, JsonSchema)]
|
|
20
|
+
pub struct GetDeclarationParams {
|
|
21
|
+
#[schemars(description = "Fully qualified name of the declaration (e.g. 'Foo::Bar', 'Foo::Bar#baz')")]
|
|
22
|
+
pub name: String,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, serde::Deserialize, JsonSchema)]
|
|
26
|
+
pub struct GetDescendantsParams {
|
|
27
|
+
#[schemars(description = "Fully qualified name of the class or module")]
|
|
28
|
+
pub name: String,
|
|
29
|
+
#[schemars(description = "Maximum number of descendants to return (default 50, max 500)")]
|
|
30
|
+
pub limit: Option<usize>,
|
|
31
|
+
#[schemars(description = "Number of descendants to skip for pagination (default 0)")]
|
|
32
|
+
pub offset: Option<usize>,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Debug, serde::Deserialize, JsonSchema)]
|
|
36
|
+
pub struct FindConstantReferencesParams {
|
|
37
|
+
#[schemars(description = "Fully qualified name of the class, module, or constant to find references for")]
|
|
38
|
+
pub name: String,
|
|
39
|
+
#[schemars(description = "Maximum number of references to return (default 50, max 200)")]
|
|
40
|
+
pub limit: Option<usize>,
|
|
41
|
+
#[schemars(description = "Number of references to skip for pagination (default 0)")]
|
|
42
|
+
pub offset: Option<usize>,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[derive(Debug, serde::Deserialize, JsonSchema)]
|
|
46
|
+
pub struct GetFileDeclarationsParams {
|
|
47
|
+
#[schemars(description = "File path (relative or absolute) to list declarations for")]
|
|
48
|
+
pub file_path: String,
|
|
49
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
use assert_cmd::prelude::*;
|
|
2
|
+
use rubydex::test_utils::with_context;
|
|
3
|
+
use serde_json::{Value, json};
|
|
4
|
+
use std::io::{BufRead, BufReader, Read, Write};
|
|
5
|
+
use std::process::{Command, Stdio};
|
|
6
|
+
|
|
7
|
+
const MAX_INDEXING_RETRIES: u64 = 60;
|
|
8
|
+
|
|
9
|
+
/// Send a JSON-RPC message followed by a newline to the process stdin.
|
|
10
|
+
fn send_message(stdin: &mut impl Write, msg: &Value) {
|
|
11
|
+
let payload = serde_json::to_string(msg).unwrap();
|
|
12
|
+
writeln!(stdin, "{payload}").unwrap();
|
|
13
|
+
stdin.flush().unwrap();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// Read a single JSON-RPC response line from the process stdout.
|
|
17
|
+
fn read_response(reader: &mut BufReader<impl std::io::Read>) -> Value {
|
|
18
|
+
let mut line = String::new();
|
|
19
|
+
reader.read_line(&mut line).unwrap();
|
|
20
|
+
serde_json::from_str(line.trim()).unwrap()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fn send_request(stdin: &mut impl Write, id: u64, method: &str, params: &Value) {
|
|
24
|
+
send_message(
|
|
25
|
+
stdin,
|
|
26
|
+
&json!({
|
|
27
|
+
"jsonrpc": "2.0",
|
|
28
|
+
"id": id,
|
|
29
|
+
"method": method,
|
|
30
|
+
"params": params,
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn read_response_for_id(reader: &mut BufReader<impl Read>, expected_id: u64) -> Value {
|
|
36
|
+
let response = read_response(reader);
|
|
37
|
+
assert_eq!(response["id"], expected_id);
|
|
38
|
+
response
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn call_tool(
|
|
42
|
+
stdin: &mut impl Write,
|
|
43
|
+
reader: &mut BufReader<impl Read>,
|
|
44
|
+
request_id: u64,
|
|
45
|
+
tool_name: &str,
|
|
46
|
+
arguments: &Value,
|
|
47
|
+
) -> Value {
|
|
48
|
+
send_request(
|
|
49
|
+
stdin,
|
|
50
|
+
request_id,
|
|
51
|
+
"tools/call",
|
|
52
|
+
&json!({
|
|
53
|
+
"name": tool_name,
|
|
54
|
+
"arguments": arguments,
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
let response = read_response_for_id(reader, request_id);
|
|
59
|
+
let content_text = response["result"]["content"][0]["text"].as_str().unwrap();
|
|
60
|
+
serde_json::from_str(content_text).unwrap()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn call_next_tool(
|
|
64
|
+
stdin: &mut impl Write,
|
|
65
|
+
reader: &mut BufReader<impl Read>,
|
|
66
|
+
request_id: &mut u64,
|
|
67
|
+
tool_name: &str,
|
|
68
|
+
arguments: &Value,
|
|
69
|
+
) -> Value {
|
|
70
|
+
*request_id += 1;
|
|
71
|
+
call_tool(stdin, reader, *request_id, tool_name, arguments)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn names_from_entries(entries: &[Value]) -> Vec<String> {
|
|
75
|
+
entries
|
|
76
|
+
.iter()
|
|
77
|
+
.filter_map(|entry| entry["name"].as_str().map(ToOwned::to_owned))
|
|
78
|
+
.collect()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn assert_has_name(names: &[String], expected_name: &str, context: &str) {
|
|
82
|
+
assert!(
|
|
83
|
+
names.iter().any(|name| name == expected_name),
|
|
84
|
+
"Expected {context} to include {expected_name}, got: {names:?}"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn initialize_session(stdin: &mut impl Write, reader: &mut BufReader<impl Read>) {
|
|
89
|
+
send_request(
|
|
90
|
+
stdin,
|
|
91
|
+
1,
|
|
92
|
+
"initialize",
|
|
93
|
+
&json!({
|
|
94
|
+
"protocolVersion": "2025-03-26",
|
|
95
|
+
"capabilities": {},
|
|
96
|
+
"clientInfo": { "name": "test-client", "version": "0.1.0" }
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
let response = read_response_for_id(reader, 1);
|
|
101
|
+
assert!(response["result"]["capabilities"]["tools"].is_object());
|
|
102
|
+
|
|
103
|
+
send_message(
|
|
104
|
+
stdin,
|
|
105
|
+
&json!({
|
|
106
|
+
"jsonrpc": "2.0",
|
|
107
|
+
"method": "notifications/initialized"
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn assert_tools_are_registered(stdin: &mut impl Write, reader: &mut BufReader<impl Read>) {
|
|
113
|
+
send_request(stdin, 2, "tools/list", &json!({}));
|
|
114
|
+
|
|
115
|
+
let response = read_response_for_id(reader, 2);
|
|
116
|
+
let tools = response["result"]["tools"].as_array().unwrap();
|
|
117
|
+
let tool_names: Vec<&str> = tools.iter().map(|tool| tool["name"].as_str().unwrap()).collect();
|
|
118
|
+
|
|
119
|
+
assert!(
|
|
120
|
+
tool_names.contains(&"search_declarations"),
|
|
121
|
+
"Missing search_declarations tool"
|
|
122
|
+
);
|
|
123
|
+
assert!(tool_names.contains(&"get_declaration"), "Missing get_declaration tool");
|
|
124
|
+
assert!(tool_names.contains(&"get_descendants"), "Missing get_descendants tool");
|
|
125
|
+
assert!(
|
|
126
|
+
tool_names.contains(&"find_constant_references"),
|
|
127
|
+
"Missing find_constant_references tool"
|
|
128
|
+
);
|
|
129
|
+
assert!(
|
|
130
|
+
tool_names.contains(&"get_file_declarations"),
|
|
131
|
+
"Missing get_file_declarations tool"
|
|
132
|
+
);
|
|
133
|
+
assert!(tool_names.contains(&"codebase_stats"), "Missing codebase_stats tool");
|
|
134
|
+
assert_eq!(tool_names.len(), 6, "Expected exactly 6 tools");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fn wait_for_indexing_to_complete(
|
|
138
|
+
stdin: &mut impl Write,
|
|
139
|
+
reader: &mut BufReader<impl Read>,
|
|
140
|
+
request_id: &mut u64,
|
|
141
|
+
) -> Value {
|
|
142
|
+
for _ in 0..MAX_INDEXING_RETRIES {
|
|
143
|
+
let parsed = call_tool(stdin, reader, *request_id, "codebase_stats", &json!({}));
|
|
144
|
+
if parsed.get("error").is_none() {
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
assert_eq!(
|
|
149
|
+
parsed["error"].as_str(),
|
|
150
|
+
Some("indexing"),
|
|
151
|
+
"Expected transient indexing error while booting, got: {parsed}"
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
*request_id += 1;
|
|
155
|
+
std::thread::sleep(std::time::Duration::from_millis(50));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
panic!("Timed out waiting for indexing to complete");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#[test]
|
|
162
|
+
#[allow(clippy::too_many_lines)]
|
|
163
|
+
fn mcp_server_e2e() {
|
|
164
|
+
with_context(|context| {
|
|
165
|
+
context.write(
|
|
166
|
+
"app.rb",
|
|
167
|
+
r#"
|
|
168
|
+
class Animal
|
|
169
|
+
def speak
|
|
170
|
+
"..."
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
class Dog < Animal
|
|
175
|
+
def speak
|
|
176
|
+
"Woof!"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
module Greetable
|
|
181
|
+
def greet
|
|
182
|
+
"Hello"
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class Kennel
|
|
187
|
+
def build
|
|
188
|
+
Animal.new
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
"#,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
let mut child = Command::cargo_bin("rubydex_mcp")
|
|
195
|
+
.unwrap()
|
|
196
|
+
.args([context.absolute_path().to_str().unwrap()])
|
|
197
|
+
.stdin(Stdio::piped())
|
|
198
|
+
.stdout(Stdio::piped())
|
|
199
|
+
.stderr(Stdio::piped())
|
|
200
|
+
.spawn()
|
|
201
|
+
.unwrap();
|
|
202
|
+
|
|
203
|
+
let mut stdin = child.stdin.take().unwrap();
|
|
204
|
+
let stdout = child.stdout.take().unwrap();
|
|
205
|
+
let mut reader = BufReader::new(stdout);
|
|
206
|
+
|
|
207
|
+
initialize_session(&mut stdin, &mut reader);
|
|
208
|
+
assert_tools_are_registered(&mut stdin, &mut reader);
|
|
209
|
+
|
|
210
|
+
// Wait for indexing readiness before asserting semantic tool results.
|
|
211
|
+
let mut request_id = 3;
|
|
212
|
+
let stats = wait_for_indexing_to_complete(&mut stdin, &mut reader, &mut request_id);
|
|
213
|
+
assert_eq!(stats["files"], 2);
|
|
214
|
+
assert!(stats["declarations"].as_u64().unwrap() > 0);
|
|
215
|
+
|
|
216
|
+
// Semantic query: search declarations.
|
|
217
|
+
let search_response = call_next_tool(
|
|
218
|
+
&mut stdin,
|
|
219
|
+
&mut reader,
|
|
220
|
+
&mut request_id,
|
|
221
|
+
"search_declarations",
|
|
222
|
+
&json!({ "query": "Dog" }),
|
|
223
|
+
);
|
|
224
|
+
let results = search_response["results"].as_array().unwrap();
|
|
225
|
+
let result_names = names_from_entries(results);
|
|
226
|
+
assert_has_name(&result_names, "Dog", "search results");
|
|
227
|
+
assert!(search_response["total"].as_u64().unwrap() > 0);
|
|
228
|
+
|
|
229
|
+
// Semantic query: inspect declaration details.
|
|
230
|
+
let decl = call_next_tool(
|
|
231
|
+
&mut stdin,
|
|
232
|
+
&mut reader,
|
|
233
|
+
&mut request_id,
|
|
234
|
+
"get_declaration",
|
|
235
|
+
&json!({ "name": "Dog" }),
|
|
236
|
+
);
|
|
237
|
+
assert_eq!(decl["name"], "Dog");
|
|
238
|
+
assert_eq!(decl["kind"], "Class");
|
|
239
|
+
assert!(!decl["definitions"].as_array().unwrap().is_empty());
|
|
240
|
+
|
|
241
|
+
// Verify ancestors are included in get_declaration response
|
|
242
|
+
let ancestor_entries = decl["ancestors"].as_array().unwrap();
|
|
243
|
+
let ancestor_names = names_from_entries(ancestor_entries);
|
|
244
|
+
assert_has_name(&ancestor_names, "Animal", "Dog ancestors");
|
|
245
|
+
|
|
246
|
+
// Semantic query: descendants.
|
|
247
|
+
let descendants = call_next_tool(
|
|
248
|
+
&mut stdin,
|
|
249
|
+
&mut reader,
|
|
250
|
+
&mut request_id,
|
|
251
|
+
"get_descendants",
|
|
252
|
+
&json!({ "name": "Animal" }),
|
|
253
|
+
);
|
|
254
|
+
let descendant_entries = descendants["descendants"].as_array().unwrap();
|
|
255
|
+
let descendant_names = names_from_entries(descendant_entries);
|
|
256
|
+
assert_has_name(&descendant_names, "Dog", "Animal descendants");
|
|
257
|
+
assert!(descendants["total"].as_u64().unwrap() > 0);
|
|
258
|
+
|
|
259
|
+
// Semantic query: resolved constant references.
|
|
260
|
+
let references = call_next_tool(
|
|
261
|
+
&mut stdin,
|
|
262
|
+
&mut reader,
|
|
263
|
+
&mut request_id,
|
|
264
|
+
"find_constant_references",
|
|
265
|
+
&json!({ "name": "Animal" }),
|
|
266
|
+
);
|
|
267
|
+
let refs = references["references"].as_array().unwrap();
|
|
268
|
+
assert!(
|
|
269
|
+
!refs.is_empty(),
|
|
270
|
+
"Expected at least one reference to Animal, got: {references}"
|
|
271
|
+
);
|
|
272
|
+
assert!(
|
|
273
|
+
refs.iter().all(|entry| entry["path"].as_str().is_some()),
|
|
274
|
+
"Expected references to include file paths, got: {references}"
|
|
275
|
+
);
|
|
276
|
+
assert!(references["total"].as_u64().unwrap() > 0);
|
|
277
|
+
|
|
278
|
+
// Semantic query: file declarations.
|
|
279
|
+
let file_declarations = call_next_tool(
|
|
280
|
+
&mut stdin,
|
|
281
|
+
&mut reader,
|
|
282
|
+
&mut request_id,
|
|
283
|
+
"get_file_declarations",
|
|
284
|
+
&json!({ "file_path": "app.rb" }),
|
|
285
|
+
);
|
|
286
|
+
assert!(
|
|
287
|
+
file_declarations["file"]
|
|
288
|
+
.as_str()
|
|
289
|
+
.is_some_and(|path| path.ends_with("app.rb")),
|
|
290
|
+
"Expected file path to end with app.rb, got: {file_declarations}"
|
|
291
|
+
);
|
|
292
|
+
let declaration_entries = file_declarations["declarations"].as_array().unwrap();
|
|
293
|
+
let declaration_names = names_from_entries(declaration_entries);
|
|
294
|
+
assert_has_name(&declaration_names, "Animal", "file declarations");
|
|
295
|
+
assert_has_name(&declaration_names, "Dog", "file declarations");
|
|
296
|
+
assert_has_name(&declaration_names, "Greetable", "file declarations");
|
|
297
|
+
|
|
298
|
+
// Clean up: drop stdin to signal EOF, then wait for the process to exit
|
|
299
|
+
drop(stdin);
|
|
300
|
+
let _ = child.wait().unwrap();
|
|
301
|
+
});
|
|
302
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "rubydex-sys"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
|
|
7
|
+
[lib]
|
|
8
|
+
crate-type = ["cdylib", "staticlib"]
|
|
9
|
+
|
|
10
|
+
[dependencies]
|
|
11
|
+
rubydex = { path = "../rubydex" }
|
|
12
|
+
libc = "0.2.174"
|
|
13
|
+
url = "2.5.4"
|
|
14
|
+
line-index = "0.1.2"
|
|
15
|
+
|
|
16
|
+
[build-dependencies]
|
|
17
|
+
cbindgen = "0.29"
|
|
18
|
+
|
|
19
|
+
[lints]
|
|
20
|
+
workspace = true
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
extern crate cbindgen;
|
|
2
|
+
|
|
3
|
+
fn main() {
|
|
4
|
+
cbindgen::generate(".")
|
|
5
|
+
.expect("Unable to generate bindings")
|
|
6
|
+
.write_to_file("rustbindings.h");
|
|
7
|
+
|
|
8
|
+
// Set the install name for macOS dylibs so they can be found via @rpath at runtime.
|
|
9
|
+
// This works for both native and cross-compilation scenarios.
|
|
10
|
+
let target = std::env::var("TARGET").unwrap_or_default();
|
|
11
|
+
if target.contains("apple") {
|
|
12
|
+
println!("cargo::rustc-cdylib-link-arg=-Wl,-install_name,@rpath/librubydex_sys.dylib");
|
|
13
|
+
}
|
|
14
|
+
}
|