polars-df 0.8.0 → 0.10.0

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -1
  3. data/Cargo.lock +159 -66
  4. data/Cargo.toml +0 -3
  5. data/LICENSE.txt +1 -1
  6. data/README.md +3 -2
  7. data/ext/polars/Cargo.toml +18 -8
  8. data/ext/polars/src/batched_csv.rs +7 -5
  9. data/ext/polars/src/conversion/anyvalue.rs +186 -0
  10. data/ext/polars/src/conversion/chunked_array.rs +140 -0
  11. data/ext/polars/src/{conversion.rs → conversion/mod.rs} +273 -342
  12. data/ext/polars/src/dataframe.rs +108 -66
  13. data/ext/polars/src/expr/array.rs +78 -0
  14. data/ext/polars/src/expr/datetime.rs +29 -58
  15. data/ext/polars/src/expr/general.rs +83 -36
  16. data/ext/polars/src/expr/list.rs +58 -6
  17. data/ext/polars/src/expr/meta.rs +48 -0
  18. data/ext/polars/src/expr/rolling.rs +1 -0
  19. data/ext/polars/src/expr/string.rs +62 -11
  20. data/ext/polars/src/expr/struct.rs +8 -4
  21. data/ext/polars/src/file.rs +158 -11
  22. data/ext/polars/src/functions/aggregation.rs +6 -0
  23. data/ext/polars/src/functions/lazy.rs +120 -50
  24. data/ext/polars/src/functions/meta.rs +45 -1
  25. data/ext/polars/src/functions/string_cache.rs +14 -0
  26. data/ext/polars/src/functions/whenthen.rs +47 -17
  27. data/ext/polars/src/{lazyframe.rs → lazyframe/mod.rs} +195 -40
  28. data/ext/polars/src/lib.rs +246 -179
  29. data/ext/polars/src/map/dataframe.rs +17 -9
  30. data/ext/polars/src/series/aggregation.rs +20 -0
  31. data/ext/polars/src/series/mod.rs +35 -4
  32. data/lib/polars/array_expr.rb +453 -0
  33. data/lib/polars/array_name_space.rb +346 -0
  34. data/lib/polars/batched_csv_reader.rb +4 -2
  35. data/lib/polars/cat_expr.rb +24 -0
  36. data/lib/polars/cat_name_space.rb +75 -0
  37. data/lib/polars/config.rb +2 -2
  38. data/lib/polars/data_frame.rb +306 -96
  39. data/lib/polars/data_types.rb +191 -28
  40. data/lib/polars/date_time_expr.rb +41 -18
  41. data/lib/polars/date_time_name_space.rb +9 -3
  42. data/lib/polars/exceptions.rb +12 -1
  43. data/lib/polars/expr.rb +898 -215
  44. data/lib/polars/functions/aggregation/horizontal.rb +246 -0
  45. data/lib/polars/functions/aggregation/vertical.rb +282 -0
  46. data/lib/polars/functions/as_datatype.rb +248 -0
  47. data/lib/polars/functions/col.rb +47 -0
  48. data/lib/polars/functions/eager.rb +182 -0
  49. data/lib/polars/functions/lazy.rb +1280 -0
  50. data/lib/polars/functions/len.rb +49 -0
  51. data/lib/polars/functions/lit.rb +35 -0
  52. data/lib/polars/functions/random.rb +16 -0
  53. data/lib/polars/functions/range/date_range.rb +103 -0
  54. data/lib/polars/functions/range/int_range.rb +51 -0
  55. data/lib/polars/functions/repeat.rb +144 -0
  56. data/lib/polars/functions/whenthen.rb +96 -0
  57. data/lib/polars/functions.rb +29 -416
  58. data/lib/polars/group_by.rb +2 -2
  59. data/lib/polars/io.rb +36 -31
  60. data/lib/polars/lazy_frame.rb +405 -88
  61. data/lib/polars/list_expr.rb +158 -8
  62. data/lib/polars/list_name_space.rb +102 -0
  63. data/lib/polars/meta_expr.rb +175 -7
  64. data/lib/polars/series.rb +282 -41
  65. data/lib/polars/string_cache.rb +75 -0
  66. data/lib/polars/string_expr.rb +413 -96
  67. data/lib/polars/string_name_space.rb +4 -4
  68. data/lib/polars/testing.rb +507 -0
  69. data/lib/polars/utils.rb +106 -8
  70. data/lib/polars/version.rb +1 -1
  71. data/lib/polars/whenthen.rb +83 -0
  72. data/lib/polars.rb +16 -4
  73. metadata +37 -8
  74. data/lib/polars/lazy_functions.rb +0 -1181
  75. data/lib/polars/when.rb +0 -16
  76. data/lib/polars/when_then.rb +0 -19
@@ -1,20 +1,167 @@
1
- use magnus::{exception, prelude::*, Error, RString, Value};
2
- use polars::io::mmap::MmapBytesReader;
3
1
  use std::fs::File;
4
- use std::io::Cursor;
2
+ use std::io;
3
+ use std::io::{BufReader, Cursor, Read, Seek, SeekFrom, Write};
5
4
  use std::path::PathBuf;
6
5
 
6
+ use magnus::{exception, prelude::*, Error, RString, Value};
7
+ use polars::io::mmap::MmapBytesReader;
8
+
9
+ use crate::error::RbPolarsErr;
10
+ use crate::prelude::resolve_homedir;
7
11
  use crate::RbResult;
8
12
 
9
- pub fn get_file_like(f: Value, truncate: bool) -> RbResult<File> {
10
- let str_slice = PathBuf::try_convert(f)?;
11
- let f = if truncate {
12
- File::create(str_slice)
13
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?
13
+ #[derive(Clone)]
14
+ pub struct RbFileLikeObject {
15
+ inner: Value,
16
+ }
17
+
18
+ /// Wraps a `Value`, and implements read, seek, and write for it.
19
+ impl RbFileLikeObject {
20
+ /// Creates an instance of a `RbFileLikeObject` from a `Value`.
21
+ /// To assert the object has the required methods methods,
22
+ /// instantiate it with `RbFileLikeObject::require`
23
+ pub fn new(object: Value) -> Self {
24
+ RbFileLikeObject { inner: object }
25
+ }
26
+
27
+ pub fn as_buffer(&self) -> std::io::Cursor<Vec<u8>> {
28
+ let data = self.as_file_buffer().into_inner();
29
+ std::io::Cursor::new(data)
30
+ }
31
+
32
+ pub fn as_file_buffer(&self) -> Cursor<Vec<u8>> {
33
+ let bytes = self
34
+ .inner
35
+ .funcall::<_, _, RString>("read", ())
36
+ .expect("no read method found");
37
+
38
+ let buf = unsafe { bytes.as_slice() }.to_vec();
39
+
40
+ Cursor::new(buf)
41
+ }
42
+
43
+ /// Same as `RbFileLikeObject::new`, but validates that the underlying
44
+ /// ruby object has a `read`, `write`, and `seek` methods in respect to parameters.
45
+ /// Will return a `TypeError` if object does not have `read`, `seek`, and `write` methods.
46
+ pub fn with_requirements(object: Value, read: bool, write: bool, seek: bool) -> RbResult<Self> {
47
+ if read && !object.respond_to("read", false)? {
48
+ return Err(Error::new(
49
+ exception::type_error(),
50
+ "Object does not have a .read() method.",
51
+ ));
52
+ }
53
+
54
+ if seek && !object.respond_to("seek", false)? {
55
+ return Err(Error::new(
56
+ exception::type_error(),
57
+ "Object does not have a .seek() method.",
58
+ ));
59
+ }
60
+
61
+ if write && !object.respond_to("write", false)? {
62
+ return Err(Error::new(
63
+ exception::type_error(),
64
+ "Object does not have a .write() method.",
65
+ ));
66
+ }
67
+
68
+ Ok(RbFileLikeObject::new(object))
69
+ }
70
+ }
71
+
72
+ /// Extracts a string repr from, and returns an IO error to send back to rust.
73
+ fn rberr_to_io_err(e: Error) -> io::Error {
74
+ io::Error::new(io::ErrorKind::Other, e.to_string())
75
+ }
76
+
77
+ impl Read for RbFileLikeObject {
78
+ fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, io::Error> {
79
+ let bytes = self
80
+ .inner
81
+ .funcall::<_, _, RString>("read", (buf.len(),))
82
+ .map_err(rberr_to_io_err)?;
83
+
84
+ buf.write_all(unsafe { bytes.as_slice() })?;
85
+
86
+ Ok(bytes.len())
87
+ }
88
+ }
89
+
90
+ impl Write for RbFileLikeObject {
91
+ fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
92
+ let rbbytes = RString::from_slice(buf);
93
+
94
+ let number_bytes_written = self
95
+ .inner
96
+ .funcall::<_, _, usize>("write", (rbbytes,))
97
+ .map_err(rberr_to_io_err)?;
98
+
99
+ Ok(number_bytes_written)
100
+ }
101
+
102
+ fn flush(&mut self) -> Result<(), io::Error> {
103
+ self.inner
104
+ .funcall::<_, _, Value>("flush", ())
105
+ .map_err(rberr_to_io_err)?;
106
+
107
+ Ok(())
108
+ }
109
+ }
110
+
111
+ impl Seek for RbFileLikeObject {
112
+ fn seek(&mut self, pos: SeekFrom) -> Result<u64, io::Error> {
113
+ let (whence, offset) = match pos {
114
+ SeekFrom::Start(i) => (0, i as i64),
115
+ SeekFrom::Current(i) => (1, i),
116
+ SeekFrom::End(i) => (2, i),
117
+ };
118
+
119
+ let new_position = self
120
+ .inner
121
+ .funcall("seek", (offset, whence))
122
+ .map_err(rberr_to_io_err)?;
123
+
124
+ Ok(new_position)
125
+ }
126
+ }
127
+
128
+ pub trait FileLike: Read + Write + Seek {}
129
+
130
+ impl FileLike for File {}
131
+ impl FileLike for RbFileLikeObject {}
132
+
133
+ pub enum EitherRustRubyFile {
134
+ Rb(RbFileLikeObject),
135
+ Rust(BufReader<File>),
136
+ }
137
+
138
+ ///
139
+ /// # Arguments
140
+ /// * `truncate` - open or create a new file.
141
+ pub fn get_either_file(rb_f: Value, truncate: bool) -> RbResult<EitherRustRubyFile> {
142
+ if let Ok(rstring) = RString::try_convert(rb_f) {
143
+ let s = unsafe { rstring.as_str() }?;
144
+ let file_path = std::path::Path::new(&s);
145
+ let file_path = resolve_homedir(file_path);
146
+ let f = if truncate {
147
+ File::create(file_path).map_err(RbPolarsErr::io)?
148
+ } else {
149
+ polars_utils::open_file(&file_path).map_err(RbPolarsErr::from)?
150
+ };
151
+ let reader = BufReader::new(f);
152
+ Ok(EitherRustRubyFile::Rust(reader))
14
153
  } else {
15
- File::open(str_slice).map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?
16
- };
17
- Ok(f)
154
+ let f = RbFileLikeObject::with_requirements(rb_f, !truncate, truncate, !truncate)?;
155
+ Ok(EitherRustRubyFile::Rb(f))
156
+ }
157
+ }
158
+
159
+ pub fn get_file_like(f: Value, truncate: bool) -> RbResult<Box<dyn FileLike>> {
160
+ use EitherRustRubyFile::*;
161
+ match get_either_file(f, truncate)? {
162
+ Rb(f) => Ok(Box::new(f)),
163
+ Rust(f) => Ok(Box::new(f.into_inner())),
164
+ }
18
165
  }
19
166
 
20
167
  pub fn get_mmap_bytes_reader(rb_f: Value) -> RbResult<Box<dyn MmapBytesReader>> {
@@ -33,3 +33,9 @@ pub fn sum_horizontal(exprs: RArray) -> RbResult<RbExpr> {
33
33
  let e = dsl::sum_horizontal(exprs).map_err(RbPolarsErr::from)?;
34
34
  Ok(e.into())
35
35
  }
36
+
37
+ pub fn mean_horizontal(exprs: RArray) -> RbResult<RbExpr> {
38
+ let exprs = rb_exprs_to_exprs(exprs)?;
39
+ let e = dsl::mean_horizontal(exprs).map_err(RbPolarsErr::from)?;
40
+ Ok(e.into())
41
+ }
@@ -17,9 +17,62 @@ macro_rules! set_unwrapped_or_0 {
17
17
  };
18
18
  }
19
19
 
20
- pub fn arg_sort_by(by: RArray, descending: Vec<bool>) -> RbResult<RbExpr> {
20
+ pub fn rolling_corr(
21
+ x: &RbExpr,
22
+ y: &RbExpr,
23
+ window_size: IdxSize,
24
+ min_periods: IdxSize,
25
+ ddof: u8,
26
+ ) -> RbExpr {
27
+ dsl::rolling_corr(
28
+ x.inner.clone(),
29
+ y.inner.clone(),
30
+ RollingCovOptions {
31
+ min_periods,
32
+ window_size,
33
+ ddof,
34
+ },
35
+ )
36
+ .into()
37
+ }
38
+
39
+ pub fn rolling_cov(
40
+ x: &RbExpr,
41
+ y: &RbExpr,
42
+ window_size: IdxSize,
43
+ min_periods: IdxSize,
44
+ ddof: u8,
45
+ ) -> RbExpr {
46
+ dsl::rolling_cov(
47
+ x.inner.clone(),
48
+ y.inner.clone(),
49
+ RollingCovOptions {
50
+ min_periods,
51
+ window_size,
52
+ ddof,
53
+ },
54
+ )
55
+ .into()
56
+ }
57
+
58
+ pub fn arg_sort_by(
59
+ by: RArray,
60
+ descending: Vec<bool>,
61
+ nulls_last: bool,
62
+ multithreaded: bool,
63
+ maintain_order: bool,
64
+ ) -> RbResult<RbExpr> {
21
65
  let by = rb_exprs_to_exprs(by)?;
22
- Ok(dsl::arg_sort_by(by, &descending).into())
66
+ Ok(dsl::arg_sort_by(
67
+ by,
68
+ SortMultipleOptions {
69
+ descending,
70
+ nulls_last,
71
+ multithreaded,
72
+ maintain_order,
73
+ },
74
+ )
75
+ .into())
23
76
  }
24
77
 
25
78
  pub fn arg_where(condition: &RbExpr) -> RbExpr {
@@ -83,6 +136,47 @@ pub fn concat_lf(
83
136
  Ok(lf.into())
84
137
  }
85
138
 
139
+ pub fn concat_list(s: RArray) -> RbResult<RbExpr> {
140
+ let s = rb_exprs_to_exprs(s)?;
141
+ let expr = dsl::concat_list(s).map_err(RbPolarsErr::from)?;
142
+ Ok(expr.into())
143
+ }
144
+
145
+ pub fn concat_str(s: RArray, separator: String, ignore_nulls: bool) -> RbResult<RbExpr> {
146
+ let s = rb_exprs_to_exprs(s)?;
147
+ Ok(dsl::concat_str(s, &separator, ignore_nulls).into())
148
+ }
149
+
150
+ pub fn len() -> RbExpr {
151
+ dsl::len().into()
152
+ }
153
+
154
+ pub fn cov(a: &RbExpr, b: &RbExpr, ddof: u8) -> RbExpr {
155
+ polars::lazy::dsl::cov(a.inner.clone(), b.inner.clone(), ddof).into()
156
+ }
157
+
158
+ pub fn arctan2(y: &RbExpr, x: &RbExpr) -> RbExpr {
159
+ y.inner.clone().arctan2(x.inner.clone()).into()
160
+ }
161
+
162
+ pub fn arctan2d(y: &RbExpr, x: &RbExpr) -> RbExpr {
163
+ y.inner.clone().arctan2(x.inner.clone()).degrees().into()
164
+ }
165
+
166
+ pub fn cum_fold(
167
+ acc: &RbExpr,
168
+ lambda: Value,
169
+ exprs: RArray,
170
+ include_init: bool,
171
+ ) -> RbResult<RbExpr> {
172
+ let exprs = rb_exprs_to_exprs(exprs)?;
173
+ let lambda = Opaque::from(lambda);
174
+
175
+ let func =
176
+ move |a: Series, b: Series| binary_lambda(Ruby::get().unwrap().get_inner(lambda), a, b);
177
+ Ok(dsl::cum_fold_exprs(acc.inner.clone(), func, exprs, include_init).into())
178
+ }
179
+
86
180
  pub fn concat_lf_diagonal(
87
181
  lfs: RArray,
88
182
  rechunk: bool,
@@ -110,6 +204,19 @@ pub fn concat_lf_diagonal(
110
204
  Ok(lf.into())
111
205
  }
112
206
 
207
+ pub fn dtype_cols(dtypes: Vec<DataType>) -> RbExpr {
208
+ dsl::dtype_cols(dtypes).into()
209
+ }
210
+
211
+ pub fn dtype_cols2(dtypes: RArray) -> RbResult<RbExpr> {
212
+ let dtypes = dtypes
213
+ .each()
214
+ .map(|v| Wrap::<DataType>::try_convert(v?))
215
+ .collect::<RbResult<Vec<Wrap<DataType>>>>()?;
216
+ let dtypes = vec_extract_wrapped(dtypes);
217
+ Ok(crate::functions::lazy::dtype_cols(dtypes))
218
+ }
219
+
113
220
  #[allow(clippy::too_many_arguments)]
114
221
  pub fn duration(
115
222
  weeks: Option<&RbExpr>,
@@ -146,38 +253,21 @@ pub fn duration(
146
253
  dsl::duration(args).into()
147
254
  }
148
255
 
149
- pub fn count() -> RbExpr {
150
- dsl::count().into()
151
- }
152
-
153
256
  pub fn first() -> RbExpr {
154
257
  dsl::first().into()
155
258
  }
156
259
 
157
- pub fn last() -> RbExpr {
158
- dsl::last().into()
159
- }
160
-
161
- pub fn dtype_cols(dtypes: Vec<DataType>) -> RbExpr {
162
- dsl::dtype_cols(dtypes).into()
163
- }
164
-
165
260
  pub fn fold(acc: &RbExpr, lambda: Value, exprs: RArray) -> RbResult<RbExpr> {
166
261
  let exprs = rb_exprs_to_exprs(exprs)?;
167
262
  let lambda = Opaque::from(lambda);
168
263
 
169
264
  let func =
170
265
  move |a: Series, b: Series| binary_lambda(Ruby::get().unwrap().get_inner(lambda), a, b);
171
- Ok(polars::lazy::dsl::fold_exprs(acc.inner.clone(), func, exprs).into())
266
+ Ok(dsl::fold_exprs(acc.inner.clone(), func, exprs).into())
172
267
  }
173
268
 
174
- pub fn cumfold(acc: &RbExpr, lambda: Value, exprs: RArray, include_init: bool) -> RbResult<RbExpr> {
175
- let exprs = rb_exprs_to_exprs(exprs)?;
176
- let lambda = Opaque::from(lambda);
177
-
178
- let func =
179
- move |a: Series, b: Series| binary_lambda(Ruby::get().unwrap().get_inner(lambda), a, b);
180
- Ok(polars::lazy::dsl::cum_fold_exprs(acc.inner.clone(), func, exprs, include_init).into())
269
+ pub fn last() -> RbExpr {
270
+ dsl::last().into()
181
271
  }
182
272
 
183
273
  pub fn lit(value: Value, allow_object: bool) -> RbResult<RbExpr> {
@@ -219,6 +309,10 @@ pub fn lit(value: Value, allow_object: bool) -> RbResult<RbExpr> {
219
309
  }
220
310
  }
221
311
 
312
+ pub fn pearson_corr(a: &RbExpr, b: &RbExpr, ddof: u8) -> RbExpr {
313
+ dsl::pearson_corr(a.inner.clone(), b.inner.clone(), ddof).into()
314
+ }
315
+
222
316
  pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbResult<RbExpr> {
223
317
  let mut value = value.inner.clone();
224
318
  let n = n.inner.clone();
@@ -228,7 +322,7 @@ pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbRe
228
322
  }
229
323
 
230
324
  if let Expr::Literal(lv) = &value {
231
- let av = lv.to_anyvalue().unwrap();
325
+ let av = lv.to_any_value().unwrap();
232
326
  // Integer inputs that fit in Int32 are parsed as such
233
327
  if let DataType::Int64 = av.dtype() {
234
328
  let int_value = av.try_extract::<i64>().unwrap();
@@ -240,35 +334,11 @@ pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbRe
240
334
  Ok(dsl::repeat(value, n).into())
241
335
  }
242
336
 
243
- pub fn pearson_corr(a: &RbExpr, b: &RbExpr, ddof: u8) -> RbExpr {
244
- polars::lazy::dsl::pearson_corr(a.inner.clone(), b.inner.clone(), ddof).into()
245
- }
246
-
247
337
  pub fn spearman_rank_corr(a: &RbExpr, b: &RbExpr, ddof: u8, propagate_nans: bool) -> RbExpr {
248
- polars::lazy::dsl::spearman_rank_corr(a.inner.clone(), b.inner.clone(), ddof, propagate_nans)
249
- .into()
250
- }
251
-
252
- pub fn cov(a: &RbExpr, b: &RbExpr, ddof: u8) -> RbExpr {
253
- polars::lazy::dsl::cov(a.inner.clone(), b.inner.clone(), ddof).into()
254
- }
255
-
256
- pub fn concat_str(s: RArray, sep: String) -> RbResult<RbExpr> {
257
- let s = rb_exprs_to_exprs(s)?;
258
- Ok(dsl::concat_str(s, &sep).into())
338
+ dsl::spearman_rank_corr(a.inner.clone(), b.inner.clone(), ddof, propagate_nans).into()
259
339
  }
260
340
 
261
- pub fn concat_lst(s: RArray) -> RbResult<RbExpr> {
262
- let s = rb_exprs_to_exprs(s)?;
263
- let expr = dsl::concat_list(s).map_err(RbPolarsErr::from)?;
341
+ pub fn sql_expr(sql: String) -> RbResult<RbExpr> {
342
+ let expr = polars::sql::sql_expr(sql).map_err(RbPolarsErr::from)?;
264
343
  Ok(expr.into())
265
344
  }
266
-
267
- pub fn dtype_cols2(dtypes: RArray) -> RbResult<RbExpr> {
268
- let dtypes = dtypes
269
- .each()
270
- .map(|v| Wrap::<DataType>::try_convert(v?))
271
- .collect::<RbResult<Vec<Wrap<DataType>>>>()?;
272
- let dtypes = vec_extract_wrapped(dtypes);
273
- Ok(crate::functions::lazy::dtype_cols(dtypes))
274
- }
@@ -7,7 +7,7 @@ use polars_core::POOL;
7
7
  use crate::conversion::Wrap;
8
8
  use crate::{RbResult, RbValueError};
9
9
 
10
- pub fn get_idx_type() -> Value {
10
+ pub fn get_index_type() -> Value {
11
11
  Wrap(IDX_DTYPE).into_value()
12
12
  }
13
13
 
@@ -36,3 +36,47 @@ pub fn get_float_fmt() -> RbResult<String> {
36
36
  };
37
37
  Ok(strfmt.to_string())
38
38
  }
39
+
40
+ pub fn set_float_precision(precision: Option<usize>) -> RbResult<()> {
41
+ use polars_core::fmt::set_float_precision;
42
+ set_float_precision(precision);
43
+ Ok(())
44
+ }
45
+
46
+ pub fn get_float_precision() -> RbResult<Option<usize>> {
47
+ use polars_core::fmt::get_float_precision;
48
+ Ok(get_float_precision())
49
+ }
50
+
51
+ pub fn set_thousands_separator(sep: Option<char>) -> RbResult<()> {
52
+ use polars_core::fmt::set_thousands_separator;
53
+ set_thousands_separator(sep);
54
+ Ok(())
55
+ }
56
+
57
+ pub fn get_thousands_separator() -> RbResult<Option<String>> {
58
+ use polars_core::fmt::get_thousands_separator;
59
+ Ok(Some(get_thousands_separator()))
60
+ }
61
+
62
+ pub fn set_decimal_separator(sep: Option<char>) -> RbResult<()> {
63
+ use polars_core::fmt::set_decimal_separator;
64
+ set_decimal_separator(sep);
65
+ Ok(())
66
+ }
67
+
68
+ pub fn get_decimal_separator() -> RbResult<Option<char>> {
69
+ use polars_core::fmt::get_decimal_separator;
70
+ Ok(Some(get_decimal_separator()))
71
+ }
72
+
73
+ pub fn set_trim_decimal_zeros(trim: Option<bool>) -> RbResult<()> {
74
+ use polars_core::fmt::set_trim_decimal_zeros;
75
+ set_trim_decimal_zeros(trim);
76
+ Ok(())
77
+ }
78
+
79
+ pub fn get_trim_decimal_zeros() -> RbResult<Option<bool>> {
80
+ use polars_core::fmt::get_trim_decimal_zeros;
81
+ Ok(Some(get_trim_decimal_zeros()))
82
+ }
@@ -1,3 +1,7 @@
1
+ use crate::RbResult;
2
+ use magnus::{RArray, Ruby, Value};
3
+ use polars_core::StringCacheHolder;
4
+
1
5
  pub fn enable_string_cache() {
2
6
  polars_core::enable_string_cache()
3
7
  }
@@ -9,3 +13,13 @@ pub fn disable_string_cache() {
9
13
  pub fn using_string_cache() -> bool {
10
14
  polars_core::using_string_cache()
11
15
  }
16
+
17
+ #[magnus::wrap(class = "Polars::RbStringCacheHolder")]
18
+ pub struct RbStringCacheHolder {}
19
+
20
+ impl RbStringCacheHolder {
21
+ pub fn hold() -> RbResult<Value> {
22
+ let _hold = StringCacheHolder::hold();
23
+ Ruby::get().unwrap().yield_splat(RArray::new())
24
+ }
25
+ }
@@ -2,42 +2,72 @@ use polars::lazy::dsl;
2
2
 
3
3
  use crate::RbExpr;
4
4
 
5
+ pub fn when(condition: &RbExpr) -> RbWhen {
6
+ RbWhen {
7
+ inner: dsl::when(condition.inner.clone()),
8
+ }
9
+ }
10
+
5
11
  #[magnus::wrap(class = "Polars::RbWhen")]
6
12
  #[derive(Clone)]
7
13
  pub struct RbWhen {
8
14
  pub inner: dsl::When,
9
15
  }
10
16
 
11
- impl From<dsl::When> for RbWhen {
12
- fn from(inner: dsl::When) -> Self {
13
- RbWhen { inner }
14
- }
15
- }
16
-
17
- #[magnus::wrap(class = "Polars::RbWhenThen")]
17
+ #[magnus::wrap(class = "Polars::RbThen")]
18
18
  #[derive(Clone)]
19
19
  pub struct RbThen {
20
20
  pub inner: dsl::Then,
21
21
  }
22
22
 
23
- impl From<dsl::Then> for RbThen {
24
- fn from(inner: dsl::Then) -> Self {
25
- RbThen { inner }
26
- }
23
+ #[magnus::wrap(class = "Polars::RbChainedWhen")]
24
+ #[derive(Clone)]
25
+ pub struct RbChainedWhen {
26
+ pub inner: dsl::ChainedWhen,
27
+ }
28
+
29
+ #[magnus::wrap(class = "Polars::RbChainedThen")]
30
+ #[derive(Clone)]
31
+ pub struct RbChainedThen {
32
+ pub inner: dsl::ChainedThen,
27
33
  }
28
34
 
29
35
  impl RbWhen {
30
- pub fn then(&self, expr: &RbExpr) -> RbThen {
31
- self.inner.clone().then(expr.inner.clone()).into()
36
+ pub fn then(&self, statement: &RbExpr) -> RbThen {
37
+ RbThen {
38
+ inner: self.inner.clone().then(statement.inner.clone()),
39
+ }
32
40
  }
33
41
  }
34
42
 
35
43
  impl RbThen {
36
- pub fn overwise(&self, expr: &RbExpr) -> RbExpr {
37
- self.inner.clone().otherwise(expr.inner.clone()).into()
44
+ pub fn when(&self, condition: &RbExpr) -> RbChainedWhen {
45
+ RbChainedWhen {
46
+ inner: self.inner.clone().when(condition.inner.clone()),
47
+ }
48
+ }
49
+
50
+ pub fn otherwise(&self, statement: &RbExpr) -> RbExpr {
51
+ self.inner.clone().otherwise(statement.inner.clone()).into()
38
52
  }
39
53
  }
40
54
 
41
- pub fn when(predicate: &RbExpr) -> RbWhen {
42
- dsl::when(predicate.inner.clone()).into()
55
+ impl RbChainedWhen {
56
+ pub fn then(&self, statement: &RbExpr) -> RbChainedThen {
57
+ RbChainedThen {
58
+ inner: self.inner.clone().then(statement.inner.clone()),
59
+ }
60
+ }
61
+ }
62
+
63
+ impl RbChainedThen {
64
+ pub fn when(&self, condition: &RbExpr) -> RbChainedWhen {
65
+ RbChainedWhen {
66
+ inner: self.inner.clone().when(condition.inner.clone()),
67
+ }
68
+ }
69
+
70
+ pub fn otherwise(&self, statement: &RbExpr) -> RbExpr {
71
+ self.inner.clone().otherwise(statement.inner.clone()).into()
72
+ }
43
73
  }