baml-cc 0.208.5

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.
@@ -0,0 +1,142 @@
1
+ use baml_types::{BamlMedia, BamlMediaType, BamlValue};
2
+ use magnus::{class, function, Module, Object, RModule};
3
+
4
+ use crate::Result;
5
+
6
+ pub(crate) trait CloneAsBamlValue {
7
+ fn clone_as_baml_value(&self) -> BamlValue;
8
+ }
9
+
10
+ #[magnus::wrap(class = "Baml::Ffi::Image", free_immediately, size)]
11
+ pub(crate) struct Image {
12
+ pub(crate) inner: baml_types::BamlMedia,
13
+ }
14
+
15
+ impl Image {
16
+ pub fn from_url(url: String, media_type: Option<String>) -> Self {
17
+ Self {
18
+ inner: BamlMedia::url(BamlMediaType::Image, url, media_type),
19
+ }
20
+ }
21
+
22
+ pub fn from_base64(media_type: String, base64: String) -> Self {
23
+ Self {
24
+ inner: BamlMedia::base64(BamlMediaType::Image, base64, Some(media_type)),
25
+ }
26
+ }
27
+
28
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
29
+ let cls = module.define_class("Image", class::object())?;
30
+ cls.define_singleton_method("from_url", function!(Image::from_url, 2))?;
31
+ cls.define_singleton_method("from_base64", function!(Image::from_base64, 2))?;
32
+
33
+ Ok(())
34
+ }
35
+ }
36
+
37
+ impl CloneAsBamlValue for Image {
38
+ fn clone_as_baml_value(&self) -> BamlValue {
39
+ BamlValue::Media(self.inner.clone())
40
+ }
41
+ }
42
+
43
+ #[magnus::wrap(class = "Baml::Ffi::Audio", free_immediately, size)]
44
+ pub(crate) struct Audio {
45
+ pub(crate) inner: BamlMedia,
46
+ }
47
+
48
+ impl Audio {
49
+ pub fn from_url(url: String, media_type: Option<String>) -> Self {
50
+ Self {
51
+ inner: BamlMedia::url(BamlMediaType::Audio, url, media_type),
52
+ }
53
+ }
54
+ pub fn from_base64(media_type: String, base64: String) -> Self {
55
+ Self {
56
+ inner: BamlMedia::base64(BamlMediaType::Audio, base64, Some(media_type)),
57
+ }
58
+ }
59
+
60
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
61
+ let cls = module.define_class("Audio", class::object())?;
62
+ cls.define_singleton_method("from_url", function!(Audio::from_url, 2))?;
63
+ cls.define_singleton_method("from_base64", function!(Audio::from_base64, 2))?;
64
+
65
+ Ok(())
66
+ }
67
+ }
68
+
69
+ impl CloneAsBamlValue for Audio {
70
+ fn clone_as_baml_value(&self) -> BamlValue {
71
+ BamlValue::Media(self.inner.clone())
72
+ }
73
+ }
74
+
75
+ #[magnus::wrap(class = "Baml::Ffi::Pdf", free_immediately, size)]
76
+ pub(crate) struct Pdf {
77
+ pub(crate) inner: BamlMedia,
78
+ }
79
+
80
+ impl Pdf {
81
+ pub fn from_url(url: String) -> Self {
82
+ Self {
83
+ inner: BamlMedia::url(BamlMediaType::Pdf, url, Some("application/pdf".to_string())),
84
+ }
85
+ }
86
+
87
+ pub fn from_base64(base64: String) -> Self {
88
+ Self {
89
+ inner: BamlMedia::base64(
90
+ BamlMediaType::Pdf,
91
+ base64,
92
+ Some("application/pdf".to_string()),
93
+ ),
94
+ }
95
+ }
96
+
97
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
98
+ let cls = module.define_class("Pdf", class::object())?;
99
+ cls.define_singleton_method("from_url", function!(Pdf::from_url, 1))?;
100
+ cls.define_singleton_method("from_base64", function!(Pdf::from_base64, 1))?;
101
+
102
+ Ok(())
103
+ }
104
+ }
105
+
106
+ impl CloneAsBamlValue for Pdf {
107
+ fn clone_as_baml_value(&self) -> BamlValue {
108
+ BamlValue::Media(self.inner.clone())
109
+ }
110
+ }
111
+
112
+ #[magnus::wrap(class = "Baml::Ffi::Video", free_immediately, size)]
113
+ pub(crate) struct Video {
114
+ pub(crate) inner: BamlMedia,
115
+ }
116
+
117
+ impl Video {
118
+ pub fn from_url(url: String, media_type: Option<String>) -> Self {
119
+ Self {
120
+ inner: BamlMedia::url(BamlMediaType::Video, url, media_type),
121
+ }
122
+ }
123
+ pub fn from_base64(media_type: String, base64: String) -> Self {
124
+ Self {
125
+ inner: BamlMedia::base64(BamlMediaType::Video, base64, Some(media_type)),
126
+ }
127
+ }
128
+
129
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
130
+ let cls = module.define_class("Video", class::object())?;
131
+ cls.define_singleton_method("from_url", function!(Video::from_url, 2))?;
132
+ cls.define_singleton_method("from_base64", function!(Video::from_base64, 2))?;
133
+
134
+ Ok(())
135
+ }
136
+ }
137
+
138
+ impl CloneAsBamlValue for Video {
139
+ fn clone_as_baml_value(&self) -> BamlValue {
140
+ BamlValue::Media(self.inner.clone())
141
+ }
142
+ }
@@ -0,0 +1,8 @@
1
+ pub(crate) mod client_registry;
2
+ mod lang_wrapper;
3
+ pub(crate) mod log_collector;
4
+ pub(crate) mod media;
5
+ pub(crate) mod request;
6
+ pub(crate) mod response;
7
+ pub(crate) mod runtime_ctx_manager;
8
+ pub(crate) mod type_builder;
@@ -0,0 +1,107 @@
1
+ use magnus::{class, method, r_array::TypedArray, Error, Module, RModule, Ruby};
2
+
3
+ use crate::Result;
4
+
5
+ crate::lang_wrapper!(
6
+ HTTPRequest,
7
+ "Baml::Ffi::HTTPRequest",
8
+ baml_types::tracing::events::HTTPRequest,
9
+ clone_safe
10
+ );
11
+
12
+ crate::lang_wrapper!(
13
+ HTTPBody,
14
+ "Baml::Ffi::HTTPBody",
15
+ baml_types::tracing::events::HTTPBody,
16
+ clone_safe
17
+ );
18
+
19
+ impl HTTPRequest {
20
+ pub fn to_s(&self) -> String {
21
+ format!(
22
+ "HTTPRequest(url={}, method={}, headers={}, body={})",
23
+ self.inner.url(),
24
+ self.inner.method(),
25
+ serde_json::to_string_pretty(&self.inner.headers()).unwrap_or_default(),
26
+ serde_json::to_string_pretty(&self.inner.body().as_serde_value()).unwrap_or_default()
27
+ )
28
+ }
29
+
30
+ pub fn id(&self) -> String {
31
+ self.inner.id().to_string()
32
+ }
33
+
34
+ pub fn url(&self) -> String {
35
+ self.inner.url().to_string()
36
+ }
37
+
38
+ pub fn method(&self) -> String {
39
+ self.inner.method().to_string()
40
+ }
41
+
42
+ pub fn headers(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
43
+ // Convert headers to Ruby hash
44
+ serde_magnus::serialize(&rb_self.inner.headers())
45
+ .map_err(|e| Error::new(ruby.exception_runtime_error(), format!("{e:?}")))
46
+ }
47
+
48
+ pub fn body(&self) -> HTTPBody {
49
+ // TODO: Avoid clone.
50
+ HTTPBody::from(self.inner.body().clone())
51
+ }
52
+
53
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
54
+ let cls = module.define_class("HTTPRequest", class::object())?;
55
+
56
+ cls.define_method("to_s", method!(HTTPRequest::to_s, 0))?;
57
+ cls.define_method("id", method!(HTTPRequest::id, 0))?;
58
+ cls.define_method("url", method!(HTTPRequest::url, 0))?;
59
+ cls.define_method("method", method!(HTTPRequest::method, 0))?;
60
+ cls.define_method("headers", method!(HTTPRequest::headers, 0))?;
61
+ cls.define_method("body", method!(HTTPRequest::body, 0))?;
62
+
63
+ Ok(())
64
+ }
65
+ }
66
+
67
+ impl HTTPBody {
68
+ pub fn raw(ruby: &Ruby, rb_self: &Self) -> Result<TypedArray<u8>> {
69
+ let array = ruby.typed_ary_new();
70
+
71
+ // TODO: Can we avoid cloning or at least do this faster than byte by
72
+ // byte?
73
+ for byte in rb_self.inner.raw() {
74
+ array.push(*byte)?;
75
+ }
76
+
77
+ Ok(array)
78
+ }
79
+
80
+ pub fn text(ruby: &Ruby, rb_self: &Self) -> Result<String> {
81
+ rb_self.inner.text().map(String::from).map_err(|e| {
82
+ Error::new(
83
+ ruby.exception_runtime_error(),
84
+ format!("Failed to get text from HTTP body:\n{e:?}"),
85
+ )
86
+ })
87
+ }
88
+
89
+ pub fn json(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
90
+ serde_magnus::serialize(&rb_self.inner.json().map_err(|e| {
91
+ Error::new(
92
+ ruby.exception_runtime_error(),
93
+ format!("Failed deserializing HTTP body as JSON:\n{e:?}"),
94
+ )
95
+ })?)
96
+ }
97
+
98
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
99
+ let cls = module.define_class("HTTPBody", class::object())?;
100
+
101
+ cls.define_method("raw", method!(HTTPBody::raw, 0))?;
102
+ cls.define_method("text", method!(HTTPBody::text, 0))?;
103
+ cls.define_method("json", method!(HTTPBody::json, 0))?;
104
+
105
+ Ok(())
106
+ }
107
+ }
@@ -0,0 +1,48 @@
1
+ use magnus::{class, method, Error, Module, RModule, Ruby};
2
+
3
+ use super::request::HTTPBody;
4
+ use crate::Result;
5
+
6
+ crate::lang_wrapper!(
7
+ HTTPResponse,
8
+ "Baml::Ffi::HTTPResponse",
9
+ baml_types::tracing::events::HTTPResponse,
10
+ clone_safe
11
+ );
12
+
13
+ impl HTTPResponse {
14
+ pub fn to_s(&self) -> String {
15
+ format!(
16
+ "HTTPResponse(status={}, headers={}, body={})",
17
+ self.inner.status,
18
+ serde_json::to_string_pretty(&self.inner.headers()).unwrap_or_default(),
19
+ serde_json::to_string_pretty(&self.inner.body.as_serde_value()).unwrap_or_default()
20
+ )
21
+ }
22
+
23
+ pub fn status(&self) -> u16 {
24
+ self.inner.status
25
+ }
26
+
27
+ pub fn headers(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
28
+ // Convert headers to Ruby hash
29
+ serde_magnus::serialize(&rb_self.inner.headers())
30
+ .map_err(|e| Error::new(ruby.exception_runtime_error(), format!("{e:?}")))
31
+ }
32
+
33
+ pub fn body(&self) -> HTTPBody {
34
+ // TODO: Avoid clone.
35
+ HTTPBody::from(self.inner.body.clone())
36
+ }
37
+
38
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
39
+ let cls = module.define_class("HTTPResponse", class::object())?;
40
+
41
+ cls.define_method("to_s", method!(HTTPResponse::to_s, 0))?;
42
+ cls.define_method("status", method!(HTTPResponse::status, 0))?;
43
+ cls.define_method("headers", method!(HTTPResponse::headers, 0))?;
44
+ cls.define_method("body", method!(HTTPResponse::body, 0))?;
45
+
46
+ Ok(())
47
+ }
48
+ }
@@ -0,0 +1,18 @@
1
+ use magnus::{class, prelude::*, RModule};
2
+
3
+ use crate::Result;
4
+
5
+ #[magnus::wrap(class = "Baml::Ffi::RuntimeContextManager", free_immediately, size)]
6
+ pub struct RuntimeContextManager {
7
+ pub inner: baml_runtime::RuntimeContextManager,
8
+ }
9
+ impl RuntimeContextManager {
10
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
11
+ module.define_class("RuntimeContextManager", class::object())?;
12
+
13
+ //cls.define_method("upsert_tags", method!(RuntimeContextManager::upsert_tags, 1))?;
14
+ //cls.define_method("deep_clone", method!(RuntimeContextManager::deep_clone, 0))?;
15
+
16
+ Ok(())
17
+ }
18
+ }
@@ -0,0 +1,334 @@
1
+ #![allow(dead_code)]
2
+
3
+ use baml_runtime::type_builder::{self, WithMeta};
4
+ use baml_types::{ir_type::UnionConstructor, BamlValue};
5
+ use magnus::{
6
+ class, function, method, scan_args::scan_args, try_convert::TryConvertOwned, Module, Object,
7
+ RModule, Value,
8
+ };
9
+
10
+ use crate::Result;
11
+
12
+ #[magnus::wrap(class = "Baml::Ffi::TypeBuilder", free_immediately, size)]
13
+ pub(crate) struct TypeBuilder {
14
+ pub(crate) inner: type_builder::TypeBuilder,
15
+ }
16
+
17
+ crate::lang_wrapper!(EnumBuilder, "Baml::Ffi::EnumBuilder", type_builder::EnumBuilder, sync_thread_safe, name: String);
18
+ crate::lang_wrapper!(ClassBuilder, "Baml::Ffi::ClassBuilder", type_builder::ClassBuilder, sync_thread_safe, name: String);
19
+ crate::lang_wrapper!(
20
+ EnumValueBuilder,
21
+ "Baml::Ffi::EnumValueBuilder",
22
+ type_builder::EnumValueBuilder,
23
+ sync_thread_safe
24
+ );
25
+ crate::lang_wrapper!(
26
+ ClassPropertyBuilder,
27
+ "Baml::Ffi::ClassPropertyBuilder",
28
+ type_builder::ClassPropertyBuilder,
29
+ sync_thread_safe
30
+ );
31
+ crate::lang_wrapper!(
32
+ FieldType,
33
+ "Baml::Ffi::FieldType",
34
+ baml_types::TypeIR,
35
+ sync_thread_safe
36
+ );
37
+
38
+ impl TypeBuilder {
39
+ pub fn new() -> Self {
40
+ Self {
41
+ inner: type_builder::TypeBuilder::new(),
42
+ }
43
+ }
44
+
45
+ pub fn reset(&self) {
46
+ self.inner.reset();
47
+ }
48
+
49
+ pub fn r#enum(&self, name: String) -> EnumBuilder {
50
+ EnumBuilder {
51
+ inner: self.inner.upsert_enum(name.as_str()),
52
+ name: name.to_string(),
53
+ }
54
+ }
55
+
56
+ pub fn class(&self, name: String) -> ClassBuilder {
57
+ ClassBuilder {
58
+ inner: self.inner.upsert_class(name.as_str()),
59
+ name: name.to_string(),
60
+ }
61
+ }
62
+
63
+ pub fn list(&self, inner: &FieldType) -> FieldType {
64
+ inner.inner.lock().unwrap().clone().as_list().into()
65
+ }
66
+
67
+ pub fn optional(&self, inner: &FieldType) -> FieldType {
68
+ inner.inner.lock().unwrap().clone().as_optional().into()
69
+ }
70
+
71
+ pub fn string(&self) -> FieldType {
72
+ baml_types::TypeIR::string().into()
73
+ }
74
+
75
+ pub fn literal_string(&self, value: String) -> FieldType {
76
+ baml_types::TypeIR::literal_string(value).into()
77
+ }
78
+
79
+ pub fn literal_int(&self, value: i64) -> FieldType {
80
+ baml_types::TypeIR::literal_int(value).into()
81
+ }
82
+
83
+ pub fn literal_bool(&self, value: bool) -> FieldType {
84
+ baml_types::TypeIR::literal_bool(value).into()
85
+ }
86
+
87
+ pub fn int(&self) -> FieldType {
88
+ baml_types::TypeIR::int().into()
89
+ }
90
+
91
+ pub fn float(&self) -> FieldType {
92
+ baml_types::TypeIR::float().into()
93
+ }
94
+
95
+ pub fn bool(&self) -> FieldType {
96
+ baml_types::TypeIR::bool().into()
97
+ }
98
+
99
+ pub fn null(&self) -> FieldType {
100
+ baml_types::TypeIR::null().into()
101
+ }
102
+
103
+ pub fn map(&self, key: &FieldType, value: &FieldType) -> FieldType {
104
+ baml_types::TypeIR::map(
105
+ key.inner.lock().unwrap().clone(),
106
+ value.inner.lock().unwrap().clone(),
107
+ )
108
+ .into()
109
+ }
110
+
111
+ pub fn union(&self, args: &[Value]) -> Result<FieldType> {
112
+ let args = scan_args::<(), (), _, (), (), ()>(args)?;
113
+ let types: Vec<&FieldType> = args.splat;
114
+ Ok(baml_types::TypeIR::union(
115
+ types
116
+ .into_iter()
117
+ .map(|t| t.inner.lock().unwrap().clone())
118
+ .collect(),
119
+ )
120
+ .into())
121
+ }
122
+
123
+ pub fn add_baml(
124
+ ruby: &magnus::Ruby,
125
+ rb_self: &TypeBuilder,
126
+ baml: String,
127
+ runtime: &crate::BamlRuntimeFfi,
128
+ ) -> Result<()> {
129
+ rb_self
130
+ .inner
131
+ .add_baml(&baml, runtime.inner.internal())
132
+ .map_err(|e| magnus::Error::new(ruby.exception_runtime_error(), e.to_string()))
133
+ }
134
+
135
+ // this implements ruby's friendly to_s method for converting objects to strings
136
+ // when someone calls .to_s on a typebuilder in ruby, this method gets called
137
+ // under the hood, it uses rust's display trait to format everything nicely
138
+ // by using the same display logic across languages, we keep things consistent
139
+ // this helps make debugging and logging work the same way everywhere :D
140
+ pub fn to_s(&self) -> String {
141
+ self.inner.to_string()
142
+ }
143
+
144
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
145
+ let cls = module.define_class("TypeBuilder", class::object())?;
146
+
147
+ cls.define_singleton_method("new", function!(TypeBuilder::new, 0))?;
148
+ cls.define_method("to_s", method!(TypeBuilder::to_s, 0))?;
149
+ cls.define_method("enum", method!(TypeBuilder::r#enum, 1))?;
150
+ // TODO: Not exposed, Ruby doesn't work right now.
151
+ // cls.define_method("reset", method!(TypeBuilder::reset, 0))?;
152
+ // "class" is used by Kernel: https://ruby-doc.org/core-3.0.2/Kernel.html#method-i-class
153
+ cls.define_method("class_", method!(TypeBuilder::class, 1))?;
154
+ cls.define_method("list", method!(TypeBuilder::list, 1))?;
155
+ cls.define_method("optional", method!(TypeBuilder::optional, 1))?;
156
+ cls.define_method("string", method!(TypeBuilder::string, 0))?;
157
+ cls.define_method("int", method!(TypeBuilder::int, 0))?;
158
+ cls.define_method("float", method!(TypeBuilder::float, 0))?;
159
+ cls.define_method("bool", method!(TypeBuilder::bool, 0))?;
160
+ cls.define_method("null", method!(TypeBuilder::null, 0))?;
161
+ cls.define_method("map", method!(TypeBuilder::map, 2))?;
162
+ cls.define_method("union", method!(TypeBuilder::union, -1))?;
163
+ cls.define_method("literal_string", method!(TypeBuilder::literal_string, 1))?;
164
+ cls.define_method("literal_int", method!(TypeBuilder::literal_int, 1))?;
165
+ cls.define_method("literal_bool", method!(TypeBuilder::literal_bool, 1))?;
166
+ cls.define_method("add_baml", method!(TypeBuilder::add_baml, 2))?;
167
+
168
+ Ok(())
169
+ }
170
+ }
171
+
172
+ impl FieldType {
173
+ pub fn list(&self) -> FieldType {
174
+ self.inner.lock().unwrap().clone().as_list().into()
175
+ }
176
+
177
+ pub fn optional(&self) -> FieldType {
178
+ self.inner.lock().unwrap().clone().as_optional().into()
179
+ }
180
+
181
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
182
+ let cls = module.define_class("FieldType", class::object())?;
183
+
184
+ cls.define_method("list", method!(FieldType::list, 0))?;
185
+ cls.define_method("optional", method!(FieldType::optional, 0))?;
186
+
187
+ Ok(())
188
+ }
189
+ }
190
+
191
+ // magnus makes it non-ergonomic to convert a ScanArgsSplat into a Vec<&T> because Vec puts
192
+ // stuff on the heap, and moving Ruby-owned objects to the heap is very unsafe. It does so
193
+ // by bounding ScanArgsSplat using TryConvertOwned, which is not implemented for &TypedData,
194
+ // so we have to implement it ourselves. This is perfectly safe to do because FieldType does
195
+ // not have any references to Ruby objects.
196
+ unsafe impl TryConvertOwned for &FieldType {}
197
+
198
+ impl EnumBuilder {
199
+ pub fn value(&self, name: String) -> EnumValueBuilder {
200
+ self.inner
201
+ .lock()
202
+ .unwrap()
203
+ .upsert_value(name.as_str())
204
+ .into()
205
+ }
206
+
207
+ pub fn alias(&self, alias: Option<String>) -> Self {
208
+ self.inner.lock().unwrap().with_meta(
209
+ "alias",
210
+ alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
211
+ );
212
+ self.inner.clone().into()
213
+ }
214
+
215
+ pub fn field(&self) -> FieldType {
216
+ baml_types::TypeIR::r#enum(&self.name).into()
217
+ }
218
+
219
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
220
+ let cls = module.define_class("EnumBuilder", class::object())?;
221
+
222
+ cls.define_method("value", method!(EnumBuilder::value, 1))?;
223
+ cls.define_method("alias", method!(EnumBuilder::alias, 1))?;
224
+ cls.define_method("field", method!(EnumBuilder::field, 0))?;
225
+
226
+ Ok(())
227
+ }
228
+ }
229
+
230
+ impl EnumValueBuilder {
231
+ pub fn alias(&self, alias: Option<String>) -> Self {
232
+ self.inner.lock().unwrap().with_meta(
233
+ "alias",
234
+ alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
235
+ );
236
+ self.inner.clone().into()
237
+ }
238
+
239
+ pub fn skip(&self, skip: Option<bool>) -> Self {
240
+ self.inner
241
+ .lock()
242
+ .unwrap()
243
+ .with_meta("skip", skip.map_or(BamlValue::Null, BamlValue::Bool));
244
+ self.inner.clone().into()
245
+ }
246
+
247
+ pub fn description(&self, description: Option<String>) -> Self {
248
+ self.inner.lock().unwrap().with_meta(
249
+ "description",
250
+ description.map_or(baml_types::BamlValue::Null, BamlValue::String),
251
+ );
252
+ self.inner.clone().into()
253
+ }
254
+
255
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
256
+ let cls = module.define_class("EnumValueBuilder", class::object())?;
257
+
258
+ cls.define_method("alias", method!(EnumValueBuilder::alias, 1))?;
259
+ cls.define_method("skip", method!(EnumValueBuilder::skip, 1))?;
260
+ cls.define_method("description", method!(EnumValueBuilder::description, 1))?;
261
+
262
+ Ok(())
263
+ }
264
+ }
265
+
266
+ impl ClassBuilder {
267
+ pub fn reset(&self) {
268
+ self.inner.lock().unwrap().reset();
269
+ }
270
+
271
+ pub fn remove_property(&self, name: String) {
272
+ self.inner.lock().unwrap().remove_property(name.as_str());
273
+ }
274
+
275
+ pub fn field(&self) -> FieldType {
276
+ baml_types::TypeIR::class(&self.name).into()
277
+ }
278
+
279
+ pub fn property(&self, name: String) -> ClassPropertyBuilder {
280
+ self.inner
281
+ .lock()
282
+ .unwrap()
283
+ .upsert_property(name.as_str())
284
+ .into()
285
+ }
286
+
287
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
288
+ let cls = module.define_class("ClassBuilder", class::object())?;
289
+
290
+ cls.define_method("field", method!(ClassBuilder::field, 0))?;
291
+ cls.define_method("property", method!(ClassBuilder::property, 1))?;
292
+ // TODO: Not exposed, Ruby doesn't work right now.
293
+ // cls.define_method("reset", method!(ClassBuilder::reset, 0))?;
294
+ // cls.define_method("remove_property", method!(ClassBuilder::remove_property, 1))?;
295
+
296
+ Ok(())
297
+ }
298
+ }
299
+
300
+ impl ClassPropertyBuilder {
301
+ pub fn r#type(&self, r#type: &FieldType) -> Self {
302
+ self.inner
303
+ .lock()
304
+ .unwrap()
305
+ .set_type(r#type.inner.lock().unwrap().clone());
306
+ self.inner.clone().into()
307
+ }
308
+
309
+ pub fn alias(&self, alias: Option<String>) -> Self {
310
+ self.inner.lock().unwrap().with_meta(
311
+ "alias",
312
+ alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
313
+ );
314
+ self.inner.clone().into()
315
+ }
316
+
317
+ pub fn description(&self, description: Option<String>) -> Self {
318
+ self.inner.lock().unwrap().with_meta(
319
+ "description",
320
+ description.map_or(baml_types::BamlValue::Null, BamlValue::String),
321
+ );
322
+ self.inner.clone().into()
323
+ }
324
+
325
+ pub fn define_in_ruby(module: &RModule) -> Result<()> {
326
+ let cls = module.define_class("ClassPropertyBuilder", class::object())?;
327
+
328
+ cls.define_method("type", method!(ClassPropertyBuilder::r#type, 1))?;
329
+ cls.define_method("alias", method!(ClassPropertyBuilder::alias, 1))?;
330
+ cls.define_method("description", method!(ClassPropertyBuilder::description, 1))?;
331
+
332
+ Ok(())
333
+ }
334
+ }