polars-df 0.21.0 → 0.22.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Cargo.lock +55 -48
  4. data/Cargo.toml +3 -0
  5. data/README.md +12 -0
  6. data/ext/polars/Cargo.toml +22 -11
  7. data/ext/polars/src/batched_csv.rs +4 -4
  8. data/ext/polars/src/catalog/unity.rs +96 -94
  9. data/ext/polars/src/conversion/any_value.rs +26 -30
  10. data/ext/polars/src/conversion/chunked_array.rs +32 -28
  11. data/ext/polars/src/conversion/datetime.rs +11 -0
  12. data/ext/polars/src/conversion/mod.rs +307 -34
  13. data/ext/polars/src/dataframe/construction.rs +4 -3
  14. data/ext/polars/src/dataframe/export.rs +17 -15
  15. data/ext/polars/src/dataframe/general.rs +15 -12
  16. data/ext/polars/src/dataframe/io.rs +1 -2
  17. data/ext/polars/src/dataframe/mod.rs +25 -1
  18. data/ext/polars/src/dataframe/serde.rs +23 -8
  19. data/ext/polars/src/exceptions.rs +8 -4
  20. data/ext/polars/src/expr/array.rs +73 -4
  21. data/ext/polars/src/expr/binary.rs +26 -1
  22. data/ext/polars/src/expr/bitwise.rs +39 -0
  23. data/ext/polars/src/expr/categorical.rs +20 -0
  24. data/ext/polars/src/expr/datatype.rs +24 -1
  25. data/ext/polars/src/expr/datetime.rs +58 -14
  26. data/ext/polars/src/expr/general.rs +87 -15
  27. data/ext/polars/src/expr/list.rs +32 -24
  28. data/ext/polars/src/expr/meta.rs +15 -6
  29. data/ext/polars/src/expr/mod.rs +3 -0
  30. data/ext/polars/src/expr/name.rs +19 -14
  31. data/ext/polars/src/expr/rolling.rs +20 -0
  32. data/ext/polars/src/expr/serde.rs +28 -0
  33. data/ext/polars/src/expr/string.rs +64 -10
  34. data/ext/polars/src/expr/struct.rs +9 -1
  35. data/ext/polars/src/file.rs +15 -9
  36. data/ext/polars/src/functions/business.rs +0 -1
  37. data/ext/polars/src/functions/io.rs +25 -3
  38. data/ext/polars/src/functions/lazy.rs +11 -6
  39. data/ext/polars/src/functions/meta.rs +3 -3
  40. data/ext/polars/src/functions/string_cache.rs +3 -3
  41. data/ext/polars/src/interop/arrow/to_ruby.rs +3 -3
  42. data/ext/polars/src/interop/numo/numo_rs.rs +4 -3
  43. data/ext/polars/src/io/mod.rs +6 -0
  44. data/ext/polars/src/lazyframe/general.rs +59 -9
  45. data/ext/polars/src/lazyframe/mod.rs +16 -1
  46. data/ext/polars/src/lazyframe/optflags.rs +58 -0
  47. data/ext/polars/src/lazyframe/serde.rs +27 -3
  48. data/ext/polars/src/lib.rs +261 -19
  49. data/ext/polars/src/map/dataframe.rs +20 -17
  50. data/ext/polars/src/map/lazy.rs +6 -5
  51. data/ext/polars/src/map/series.rs +8 -7
  52. data/ext/polars/src/on_startup.rs +12 -5
  53. data/ext/polars/src/rb_modules.rs +2 -2
  54. data/ext/polars/src/series/aggregation.rs +85 -28
  55. data/ext/polars/src/series/construction.rs +1 -0
  56. data/ext/polars/src/series/export.rs +37 -33
  57. data/ext/polars/src/series/general.rs +120 -21
  58. data/ext/polars/src/series/mod.rs +29 -4
  59. data/lib/polars/array_expr.rb +382 -3
  60. data/lib/polars/array_name_space.rb +281 -0
  61. data/lib/polars/binary_expr.rb +67 -0
  62. data/lib/polars/binary_name_space.rb +43 -0
  63. data/lib/polars/cat_expr.rb +224 -0
  64. data/lib/polars/cat_name_space.rb +138 -0
  65. data/lib/polars/config.rb +2 -2
  66. data/lib/polars/convert.rb +6 -6
  67. data/lib/polars/data_frame.rb +794 -27
  68. data/lib/polars/data_type_expr.rb +52 -0
  69. data/lib/polars/data_types.rb +26 -5
  70. data/lib/polars/date_time_expr.rb +252 -1
  71. data/lib/polars/date_time_name_space.rb +299 -0
  72. data/lib/polars/expr.rb +1248 -206
  73. data/lib/polars/functions/business.rb +95 -0
  74. data/lib/polars/functions/datatype.rb +21 -0
  75. data/lib/polars/functions/lazy.rb +14 -1
  76. data/lib/polars/io/csv.rb +1 -1
  77. data/lib/polars/io/iceberg.rb +27 -0
  78. data/lib/polars/io/json.rb +4 -4
  79. data/lib/polars/io/ndjson.rb +4 -4
  80. data/lib/polars/io/parquet.rb +32 -7
  81. data/lib/polars/io/scan_options.rb +4 -1
  82. data/lib/polars/lazy_frame.rb +1028 -28
  83. data/lib/polars/list_expr.rb +217 -17
  84. data/lib/polars/list_name_space.rb +231 -22
  85. data/lib/polars/meta_expr.rb +89 -0
  86. data/lib/polars/name_expr.rb +36 -0
  87. data/lib/polars/query_opt_flags.rb +50 -0
  88. data/lib/polars/scan_cast_options.rb +20 -1
  89. data/lib/polars/schema.rb +79 -3
  90. data/lib/polars/selector.rb +72 -0
  91. data/lib/polars/selectors.rb +3 -3
  92. data/lib/polars/series.rb +1053 -54
  93. data/lib/polars/string_expr.rb +436 -32
  94. data/lib/polars/string_name_space.rb +736 -50
  95. data/lib/polars/struct_expr.rb +103 -0
  96. data/lib/polars/struct_name_space.rb +19 -1
  97. data/lib/polars/utils/serde.rb +17 -0
  98. data/lib/polars/utils/various.rb +22 -1
  99. data/lib/polars/utils.rb +5 -1
  100. data/lib/polars/version.rb +1 -1
  101. data/lib/polars.rb +6 -0
  102. metadata +11 -1
@@ -1,4 +1,4 @@
1
- use magnus::{IntoValue, RArray, TryConvert, Value, class, prelude::*, typed_data::Obj};
1
+ use magnus::{IntoValue, RArray, Ruby, TryConvert, Value, prelude::*, typed_data::Obj};
2
2
  use polars::prelude::*;
3
3
  use polars_core::frame::row::{Row, rows_to_schema_first_non_null};
4
4
  use polars_core::series::SeriesIter;
@@ -6,14 +6,14 @@ use polars_core::series::SeriesIter;
6
6
  use super::*;
7
7
  use crate::{RbDataFrame, RbPolarsErr, RbSeries, Wrap};
8
8
 
9
- fn get_iters(df: &DataFrame) -> Vec<SeriesIter> {
9
+ fn get_iters(df: &DataFrame) -> Vec<SeriesIter<'_>> {
10
10
  df.get_columns()
11
11
  .iter()
12
12
  .map(|s| s.as_materialized_series().iter())
13
13
  .collect()
14
14
  }
15
15
 
16
- fn get_iters_skip(df: &DataFrame, skip: usize) -> Vec<std::iter::Skip<SeriesIter>> {
16
+ fn get_iters_skip(df: &DataFrame, skip: usize) -> Vec<std::iter::Skip<SeriesIter<'_>>> {
17
17
  df.get_columns()
18
18
  .iter()
19
19
  .map(|s| s.as_materialized_series().iter().skip(skip))
@@ -25,32 +25,35 @@ pub fn apply_lambda_unknown<'a>(
25
25
  lambda: Value,
26
26
  inference_size: usize,
27
27
  ) -> RbResult<(Value, bool)> {
28
+ let ruby = Ruby::get_with(lambda);
28
29
  let mut null_count = 0;
29
30
  let mut iters = get_iters(df);
30
31
 
31
32
  for _ in 0..df.height() {
32
33
  let iter = iters.iter_mut().map(|it| Wrap(it.next().unwrap()));
33
- let arg = (RArray::from_iter(iter),);
34
+ let arg = (ruby.ary_from_iter(iter),);
34
35
  let out: Value = lambda.funcall("call", arg)?;
35
36
 
36
37
  if out.is_nil() {
37
38
  null_count += 1;
38
39
  continue;
39
- } else if out.is_kind_of(class::true_class()) || out.is_kind_of(class::false_class()) {
40
+ } else if out.is_kind_of(ruby.class_true_class())
41
+ || out.is_kind_of(ruby.class_false_class())
42
+ {
40
43
  let first_value = bool::try_convert(out).ok();
41
44
  return Ok((
42
- Obj::wrap(RbSeries::new(
45
+ ruby.obj_wrap(RbSeries::new(
43
46
  apply_lambda_with_bool_out_type(df, lambda, null_count, first_value)
44
47
  .into_series(),
45
48
  ))
46
49
  .as_value(),
47
50
  false,
48
51
  ));
49
- } else if out.is_kind_of(class::float()) {
52
+ } else if out.is_kind_of(ruby.class_float()) {
50
53
  let first_value = f64::try_convert(out).ok();
51
54
 
52
55
  return Ok((
53
- Obj::wrap(RbSeries::new(
56
+ ruby.obj_wrap(RbSeries::new(
54
57
  apply_lambda_with_primitive_out_type::<Float64Type>(
55
58
  df,
56
59
  lambda,
@@ -62,10 +65,10 @@ pub fn apply_lambda_unknown<'a>(
62
65
  .as_value(),
63
66
  false,
64
67
  ));
65
- } else if out.is_kind_of(class::integer()) {
68
+ } else if out.is_kind_of(ruby.class_integer()) {
66
69
  let first_value = i64::try_convert(out).ok();
67
70
  return Ok((
68
- Obj::wrap(RbSeries::new(
71
+ ruby.obj_wrap(RbSeries::new(
69
72
  apply_lambda_with_primitive_out_type::<Int64Type>(
70
73
  df,
71
74
  lambda,
@@ -77,7 +80,7 @@ pub fn apply_lambda_unknown<'a>(
77
80
  .as_value(),
78
81
  false,
79
82
  ));
80
- // } else if out.is_kind_of(class::string()) {
83
+ // } else if out.is_kind_of(ruby.class_string()) {
81
84
  // let first_value = String::try_convert(out).ok();
82
85
  // return Ok((
83
86
  // RbSeries::new(
@@ -92,7 +95,7 @@ pub fn apply_lambda_unknown<'a>(
92
95
  let series = rb_rbseries.series.borrow();
93
96
  let dt = series.dtype();
94
97
  return Ok((
95
- Obj::wrap(RbSeries::new(
98
+ ruby.obj_wrap(RbSeries::new(
96
99
  apply_lambda_with_list_out_type(df, lambda, null_count, Some(&series), dt)?
97
100
  .into_series(),
98
101
  ))
@@ -102,7 +105,7 @@ pub fn apply_lambda_unknown<'a>(
102
105
  } else if Wrap::<Row<'a>>::try_convert(out).is_ok() {
103
106
  let first_value = Wrap::<Row<'a>>::try_convert(out).unwrap().0;
104
107
  return Ok((
105
- Obj::wrap(RbDataFrame::from(
108
+ ruby.obj_wrap(RbDataFrame::from(
106
109
  apply_lambda_with_rows_output(
107
110
  df,
108
111
  lambda,
@@ -115,7 +118,7 @@ pub fn apply_lambda_unknown<'a>(
115
118
  .as_value(),
116
119
  true,
117
120
  ));
118
- } else if out.is_kind_of(class::array()) {
121
+ } else if out.is_kind_of(ruby.class_array()) {
119
122
  return Err(RbPolarsErr::Other(
120
123
  "A list output type is invalid. Do you mean to create polars List Series?\
121
124
  Then return a Series object."
@@ -141,7 +144,7 @@ where
141
144
  let mut iters = get_iters_skip(df, init_null_count + skip);
142
145
  ((init_null_count + skip)..df.height()).map(move |_| {
143
146
  let iter = iters.iter_mut().map(|it| Wrap(it.next().unwrap()));
144
- let tpl = (RArray::from_iter(iter),);
147
+ let tpl = (Ruby::get_with(lambda).ary_from_iter(iter),);
145
148
  match lambda.funcall::<_, _, Value>("call", tpl) {
146
149
  Ok(val) => T::try_convert(val).ok(),
147
150
  Err(e) => panic!("ruby function failed {e}"),
@@ -237,7 +240,7 @@ pub fn apply_lambda_with_list_out_type(
237
240
  let mut iters = get_iters_skip(df, init_null_count + skip);
238
241
  let iter = ((init_null_count + skip)..df.height()).map(|_| {
239
242
  let iter = iters.iter_mut().map(|it| Wrap(it.next().unwrap()));
240
- let tpl = (RArray::from_iter(iter),);
243
+ let tpl = (Ruby::get_with(lambda).ary_from_iter(iter),);
241
244
  match lambda.funcall::<_, _, Value>("call", tpl) {
242
245
  Ok(val) => match val.funcall::<_, _, Value>("_s", ()) {
243
246
  Ok(val) => Obj::<RbSeries>::try_convert(val)
@@ -281,7 +284,7 @@ pub fn apply_lambda_with_rows_output<'a>(
281
284
  let mut iters = get_iters_skip(df, init_null_count + skip);
282
285
  let mut row_iter = ((init_null_count + skip)..df.height()).map(|_| {
283
286
  let iter = iters.iter_mut().map(|it| Wrap(it.next().unwrap()));
284
- let tpl = (RArray::from_iter(iter),);
287
+ let tpl = (Ruby::get_with(lambda).ary_from_iter(iter),);
285
288
  match lambda.funcall::<_, _, Value>("call", tpl) {
286
289
  Ok(val) => {
287
290
  match RArray::try_convert(val).ok() {
@@ -1,17 +1,18 @@
1
- use magnus::{RArray, Value, prelude::*};
1
+ use magnus::{Ruby, Value, prelude::*};
2
2
  use polars::prelude::*;
3
3
 
4
4
  use crate::rb_modules::*;
5
5
  use crate::{RbExpr, RbSeries, Wrap};
6
6
 
7
7
  fn to_series(v: Value, name: &str) -> PolarsResult<Series> {
8
+ let ruby = Ruby::get_with(v);
8
9
  let rb_rbseries = match v.funcall("_s", ()) {
9
10
  Ok(s) => s,
10
11
  // the lambda did not return a series, we try to create a new Ruby Series
11
12
  _ => {
12
- let data = RArray::new();
13
+ let data = ruby.ary_new();
13
14
  data.push(v).unwrap();
14
- let res = series().funcall::<_, _, Value>("new", (name.to_string(), data));
15
+ let res = pl_series().funcall::<_, _, Value>("new", (name.to_string(), data));
15
16
 
16
17
  match res {
17
18
  Ok(ruby_s) => ruby_s.funcall::<_, _, &RbSeries>("_s", ()).unwrap(),
@@ -34,8 +35,8 @@ pub fn binary_lambda(lambda: Value, a: Series, b: Series) -> PolarsResult<Option
34
35
  let rbseries_b = RbSeries::new(b);
35
36
 
36
37
  // Wrap this RbSeries object in the Ruby side Series wrapper
37
- let ruby_series_wrapper_a: Value = utils().funcall("wrap_s", (rbseries_a,)).unwrap();
38
- let ruby_series_wrapper_b: Value = utils().funcall("wrap_s", (rbseries_b,)).unwrap();
38
+ let ruby_series_wrapper_a: Value = pl_utils().funcall("wrap_s", (rbseries_a,)).unwrap();
39
+ let ruby_series_wrapper_b: Value = pl_utils().funcall("wrap_s", (rbseries_b,)).unwrap();
39
40
 
40
41
  // call the lambda and get a Ruby side Series wrapper
41
42
  let result_series_wrapper: Value =
@@ -1,4 +1,4 @@
1
- use magnus::{IntoValue, TryConvert, Value, class, prelude::*, typed_data::Obj};
1
+ use magnus::{IntoValue, Ruby, TryConvert, Value, prelude::*, typed_data::Obj};
2
2
  use polars::prelude::*;
3
3
 
4
4
  use super::*;
@@ -12,12 +12,13 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>(
12
12
  out: Value,
13
13
  null_count: usize,
14
14
  ) -> RbResult<RbSeries> {
15
- if out.is_kind_of(class::true_class()) || out.is_kind_of(class::false_class()) {
15
+ let ruby = Ruby::get_with(lambda);
16
+ if out.is_kind_of(ruby.class_true_class()) || out.is_kind_of(ruby.class_false_class()) {
16
17
  let first_value = bool::try_convert(out).unwrap();
17
18
  applyer
18
19
  .apply_lambda_with_bool_out_type(lambda, null_count, Some(first_value))
19
20
  .map(|ca| ca.into_series().into())
20
- } else if out.is_kind_of(class::float()) {
21
+ } else if out.is_kind_of(ruby.class_float()) {
21
22
  let first_value = f64::try_convert(out).unwrap();
22
23
  applyer
23
24
  .apply_lambda_with_primitive_out_type::<Float64Type>(
@@ -26,7 +27,7 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>(
26
27
  Some(first_value),
27
28
  )
28
29
  .map(|ca| ca.into_series().into())
29
- } else if out.is_kind_of(class::string()) {
30
+ } else if out.is_kind_of(ruby.class_string()) {
30
31
  let first_value = String::try_convert(out).unwrap();
31
32
  applyer
32
33
  .apply_lambda_with_utf8_out_type(lambda, null_count, Some(first_value.as_str()))
@@ -38,9 +39,9 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>(
38
39
  applyer
39
40
  .apply_lambda_with_list_out_type(lambda, null_count, &series, dt)
40
41
  .map(|ca| ca.into_series().into())
41
- } else if out.is_kind_of(class::array()) {
42
+ } else if out.is_kind_of(ruby.class_array()) {
42
43
  todo!()
43
- } else if out.is_kind_of(class::hash()) {
44
+ } else if out.is_kind_of(ruby.class_hash()) {
44
45
  let first = Wrap::<AnyValue<'_>>::try_convert(out)?;
45
46
  applyer.apply_into_struct(lambda, null_count, first.0)
46
47
  }
@@ -999,7 +1000,7 @@ impl<'a> ApplyLambda<'a> for StringChunked {
999
1000
  }
1000
1001
  }
1001
1002
 
1002
- fn iter_struct(ca: &StructChunked) -> impl Iterator<Item = AnyValue> {
1003
+ fn iter_struct(ca: &StructChunked) -> impl Iterator<Item = AnyValue<'_>> {
1003
1004
  (0..ca.len()).map(|i| unsafe { ca.get_any_value_unchecked(i) })
1004
1005
  }
1005
1006
 
@@ -2,15 +2,23 @@ use std::any::Any;
2
2
  use std::sync::Arc;
3
3
  use std::sync::OnceLock;
4
4
 
5
- use magnus::IntoValue;
5
+ use magnus::{IntoValue, Ruby, Value, prelude::*};
6
6
  use polars::prelude::*;
7
7
  use polars_core::chunked_array::object::builder::ObjectChunkedBuilder;
8
8
  use polars_core::chunked_array::object::registry;
9
9
  use polars_core::chunked_array::object::registry::AnonymousObjectBuilder;
10
10
  use polars_core::prelude::AnyValue;
11
+ use polars_error::PolarsWarning;
11
12
 
12
13
  use crate::Wrap;
13
14
  use crate::prelude::ObjectValue;
15
+ use crate::rb_modules::pl_utils;
16
+
17
+ fn warning_function(msg: &str, _warning: PolarsWarning) {
18
+ if let Err(e) = pl_utils().funcall::<_, _, Value>("_polars_warn", (msg.to_string(),)) {
19
+ eprintln!("{e}")
20
+ }
21
+ }
14
22
 
15
23
  static POLARS_REGISTRY_INIT_LOCK: OnceLock<()> = OnceLock::new();
16
24
 
@@ -23,12 +31,12 @@ pub(crate) fn register_startup_deps() {
23
31
 
24
32
  let object_converter = Arc::new(|av: AnyValue| {
25
33
  let object = ObjectValue {
26
- inner: Wrap(av).into_value().into(),
34
+ inner: Wrap(av).into_value_with(&Ruby::get().unwrap()).into(),
27
35
  };
28
36
  Box::new(object) as Box<dyn Any>
29
37
  });
30
38
  let rbobject_converter = Arc::new(|av: AnyValue| {
31
- let object = Wrap(av).into_value();
39
+ let object = Wrap(av).into_value_with(&Ruby::get().unwrap());
32
40
  Box::new(object) as Box<dyn Any>
33
41
  });
34
42
 
@@ -40,8 +48,7 @@ pub(crate) fn register_startup_deps() {
40
48
  rbobject_converter,
41
49
  physical_dtype,
42
50
  );
43
- // TODO
44
51
  // Register warning function for `polars_warn!`.
45
- // polars_error::set_warning_function(warning_function);
52
+ polars_error::set_warning_function(warning_function);
46
53
  });
47
54
  }
@@ -9,13 +9,13 @@ pub(crate) fn polars() -> RModule {
9
9
  static SERIES: Lazy<RClass> =
10
10
  Lazy::new(|ruby| ruby.get_inner(&POLARS).const_get("Series").unwrap());
11
11
 
12
- pub(crate) fn series() -> RClass {
12
+ pub(crate) fn pl_series() -> RClass {
13
13
  Ruby::get().unwrap().get_inner(&SERIES)
14
14
  }
15
15
 
16
16
  static UTILS: Lazy<RModule> = Lazy::new(|ruby| ruby.get_inner(&POLARS).const_get("Utils").unwrap());
17
17
 
18
- pub(crate) fn utils() -> RModule {
18
+ pub(crate) fn pl_utils() -> RModule {
19
19
  Ruby::get().unwrap().get_inner(&UTILS)
20
20
  }
21
21
 
@@ -1,7 +1,12 @@
1
1
  use crate::error::RbPolarsErr;
2
2
  use crate::prelude::*;
3
3
  use crate::{RbResult, RbSeries};
4
- use magnus::{IntoValue, Value};
4
+ use magnus::{IntoValue, Ruby, Value};
5
+
6
+ fn scalar_to_rb(scalar: RbResult<Scalar>) -> RbResult<Value> {
7
+ let ruby = Ruby::get().unwrap();
8
+ Ok(Wrap(scalar?.as_any_value()).into_value_with(&ruby))
9
+ }
5
10
 
6
11
  impl RbSeries {
7
12
  pub fn any(&self, ignore_nulls: bool) -> RbResult<Option<bool>> {
@@ -32,40 +37,44 @@ impl RbSeries {
32
37
  self.series.borrow().arg_min()
33
38
  }
34
39
 
35
- pub fn max(&self) -> RbResult<Value> {
40
+ pub fn max(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
36
41
  Ok(Wrap(
37
- self.series
42
+ rb_self
43
+ .series
38
44
  .borrow()
39
45
  .max_reduce()
40
46
  .map_err(RbPolarsErr::from)?
41
47
  .as_any_value(),
42
48
  )
43
- .into_value())
49
+ .into_value_with(ruby))
44
50
  }
45
51
 
46
- pub fn mean(&self) -> RbResult<Value> {
47
- match self.series.borrow().dtype() {
52
+ pub fn mean(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
53
+ match rb_self.series.borrow().dtype() {
48
54
  DataType::Boolean => Ok(Wrap(
49
- self.series
55
+ rb_self
56
+ .series
50
57
  .borrow()
51
58
  .cast(&DataType::UInt8)
52
59
  .unwrap()
53
60
  .mean_reduce()
54
61
  .as_any_value(),
55
62
  )
56
- .into_value()),
63
+ .into_value_with(ruby)),
57
64
  // For non-numeric output types we require mean_reduce.
58
- dt if dt.is_temporal() => {
59
- Ok(Wrap(self.series.borrow().mean_reduce().as_any_value()).into_value())
60
- }
61
- _ => Ok(self.series.borrow().mean().into_value()),
65
+ dt if dt.is_temporal() => Ok(Wrap(
66
+ rb_self.series.borrow().mean_reduce().as_any_value(),
67
+ )
68
+ .into_value_with(ruby)),
69
+ _ => Ok(rb_self.series.borrow().mean().into_value_with(ruby)),
62
70
  }
63
71
  }
64
72
 
65
- pub fn median(&self) -> RbResult<Value> {
66
- match self.series.borrow().dtype() {
73
+ pub fn median(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
74
+ match rb_self.series.borrow().dtype() {
67
75
  DataType::Boolean => Ok(Wrap(
68
- self.series
76
+ rb_self
77
+ .series
69
78
  .borrow()
70
79
  .cast(&DataType::UInt8)
71
80
  .unwrap()
@@ -73,49 +82,97 @@ impl RbSeries {
73
82
  .map_err(RbPolarsErr::from)?
74
83
  .as_any_value(),
75
84
  )
76
- .into_value()),
85
+ .into_value_with(ruby)),
77
86
  // For non-numeric output types we require median_reduce.
78
87
  dt if dt.is_temporal() => Ok(Wrap(
79
- self.series
88
+ rb_self
89
+ .series
80
90
  .borrow()
81
91
  .median_reduce()
82
92
  .map_err(RbPolarsErr::from)?
83
93
  .as_any_value(),
84
94
  )
85
- .into_value()),
86
- _ => Ok(self.series.borrow().median().into_value()),
95
+ .into_value_with(ruby)),
96
+ _ => Ok(rb_self.series.borrow().median().into_value_with(ruby)),
87
97
  }
88
98
  }
89
99
 
90
- pub fn min(&self) -> RbResult<Value> {
100
+ pub fn min(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
91
101
  Ok(Wrap(
92
- self.series
102
+ rb_self
103
+ .series
93
104
  .borrow()
94
105
  .min_reduce()
95
106
  .map_err(RbPolarsErr::from)?
96
107
  .as_any_value(),
97
108
  )
98
- .into_value())
109
+ .into_value_with(ruby))
99
110
  }
100
111
 
101
- pub fn quantile(&self, quantile: f64, interpolation: Wrap<QuantileMethod>) -> RbResult<Value> {
102
- let bind = self
112
+ pub fn quantile(
113
+ ruby: &Ruby,
114
+ rb_self: &Self,
115
+ quantile: f64,
116
+ interpolation: Wrap<QuantileMethod>,
117
+ ) -> RbResult<Value> {
118
+ let bind = rb_self
103
119
  .series
104
120
  .borrow()
105
121
  .quantile_reduce(quantile, interpolation.0);
106
122
  let sc = bind.map_err(RbPolarsErr::from)?;
107
123
 
108
- Ok(Wrap(sc.as_any_value()).into_value())
124
+ Ok(Wrap(sc.as_any_value()).into_value_with(ruby))
109
125
  }
110
126
 
111
- pub fn sum(&self) -> RbResult<Value> {
127
+ pub fn sum(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
112
128
  Ok(Wrap(
113
- self.series
129
+ rb_self
130
+ .series
114
131
  .borrow()
115
132
  .sum_reduce()
116
133
  .map_err(RbPolarsErr::from)?
117
134
  .as_any_value(),
118
135
  )
119
- .into_value())
136
+ .into_value_with(ruby))
137
+ }
138
+
139
+ pub fn first(&self) -> RbResult<Value> {
140
+ scalar_to_rb(Ok(self.series.borrow().first()))
141
+ }
142
+
143
+ pub fn last(&self) -> RbResult<Value> {
144
+ scalar_to_rb(Ok(self.series.borrow().last()))
145
+ }
146
+
147
+ pub fn approx_n_unique(&self) -> RbResult<IdxSize> {
148
+ Ok(self
149
+ .series
150
+ .borrow()
151
+ .approx_n_unique()
152
+ .map_err(RbPolarsErr::from)?)
153
+ }
154
+
155
+ pub fn bitwise_and(&self) -> RbResult<Value> {
156
+ scalar_to_rb(Ok(self
157
+ .series
158
+ .borrow()
159
+ .and_reduce()
160
+ .map_err(RbPolarsErr::from)?))
161
+ }
162
+
163
+ pub fn bitwise_or(&self) -> RbResult<Value> {
164
+ scalar_to_rb(Ok(self
165
+ .series
166
+ .borrow()
167
+ .or_reduce()
168
+ .map_err(RbPolarsErr::from)?))
169
+ }
170
+
171
+ pub fn bitwise_xor(&self) -> RbResult<Value> {
172
+ scalar_to_rb(Ok(self
173
+ .series
174
+ .borrow()
175
+ .xor_reduce()
176
+ .map_err(RbPolarsErr::from)?))
120
177
  }
121
178
  }
@@ -79,6 +79,7 @@ init_method_opt!(new_opt_i8, Int8Type, i8);
79
79
  init_method_opt!(new_opt_i16, Int16Type, i16);
80
80
  init_method_opt!(new_opt_i32, Int32Type, i32);
81
81
  init_method_opt!(new_opt_i64, Int64Type, i64);
82
+ init_method_opt!(new_opt_i128, Int128Type, i128);
82
83
  init_method_opt!(new_opt_f32, Float32Type, f32);
83
84
  init_method_opt!(new_opt_f64, Float64Type, f64);
84
85
 
@@ -1,4 +1,4 @@
1
- use magnus::{IntoValue, RArray, Value, value::qnil};
1
+ use magnus::{IntoValue, Ruby, Value, value::ReprValue};
2
2
  use polars_core::prelude::*;
3
3
 
4
4
  use crate::RbSeries;
@@ -11,42 +11,43 @@ impl RbSeries {
11
11
  let series = &self.series.borrow();
12
12
 
13
13
  fn to_a_recursive(series: &Series) -> Value {
14
+ let ruby = Ruby::get().unwrap();
14
15
  let rblist = match series.dtype() {
15
- DataType::Boolean => RArray::from_iter(series.bool().unwrap()).into_value(),
16
- DataType::UInt8 => RArray::from_iter(series.u8().unwrap()).into_value(),
17
- DataType::UInt16 => RArray::from_iter(series.u16().unwrap()).into_value(),
18
- DataType::UInt32 => RArray::from_iter(series.u32().unwrap()).into_value(),
19
- DataType::UInt64 => RArray::from_iter(series.u64().unwrap()).into_value(),
20
- DataType::Int8 => RArray::from_iter(series.i8().unwrap()).into_value(),
21
- DataType::Int16 => RArray::from_iter(series.i16().unwrap()).into_value(),
22
- DataType::Int32 => RArray::from_iter(series.i32().unwrap()).into_value(),
23
- DataType::Int64 => RArray::from_iter(series.i64().unwrap()).into_value(),
24
- DataType::Int128 => todo!(),
25
- DataType::Float32 => RArray::from_iter(series.f32().unwrap()).into_value(),
26
- DataType::Float64 => RArray::from_iter(series.f64().unwrap()).into_value(),
16
+ DataType::Boolean => ruby.ary_from_iter(series.bool().unwrap()).as_value(),
17
+ DataType::UInt8 => ruby.ary_from_iter(series.u8().unwrap()).as_value(),
18
+ DataType::UInt16 => ruby.ary_from_iter(series.u16().unwrap()).as_value(),
19
+ DataType::UInt32 => ruby.ary_from_iter(series.u32().unwrap()).as_value(),
20
+ DataType::UInt64 => ruby.ary_from_iter(series.u64().unwrap()).as_value(),
21
+ DataType::Int8 => ruby.ary_from_iter(series.i8().unwrap()).as_value(),
22
+ DataType::Int16 => ruby.ary_from_iter(series.i16().unwrap()).as_value(),
23
+ DataType::Int32 => ruby.ary_from_iter(series.i32().unwrap()).as_value(),
24
+ DataType::Int64 => ruby.ary_from_iter(series.i64().unwrap()).as_value(),
25
+ DataType::Int128 => ruby.ary_from_iter(series.i128().unwrap()).as_value(),
26
+ DataType::Float32 => ruby.ary_from_iter(series.f32().unwrap()).as_value(),
27
+ DataType::Float64 => ruby.ary_from_iter(series.f64().unwrap()).as_value(),
27
28
  DataType::Categorical(_, _) | DataType::Enum(_, _) => {
28
29
  with_match_categorical_physical_type!(series.dtype().cat_physical().unwrap(), |$C| {
29
- RArray::from_iter(series.cat::<$C>().unwrap().iter_str()).into_value()
30
+ ruby.ary_from_iter(series.cat::<$C>().unwrap().iter_str()).as_value()
30
31
  })
31
32
  }
32
33
  DataType::Object(_) => {
33
- let v = RArray::with_capacity(series.len());
34
+ let v = ruby.ary_new_capa(series.len());
34
35
  for i in 0..series.len() {
35
36
  let obj: Option<&ObjectValue> = series.get_object(i).map(|any| any.into());
36
37
  match obj {
37
38
  Some(val) => v.push(val.to_value()).unwrap(),
38
- None => v.push(qnil()).unwrap(),
39
+ None => v.push(ruby.qnil()).unwrap(),
39
40
  };
40
41
  }
41
- v.into_value()
42
+ v.as_value()
42
43
  }
43
44
  DataType::List(_) => {
44
- let v = RArray::new();
45
+ let v = ruby.ary_new();
45
46
  let ca = series.list().unwrap();
46
47
  for opt_s in ca.amortized_iter() {
47
48
  match opt_s {
48
49
  None => {
49
- v.push(qnil()).unwrap();
50
+ v.push(ruby.qnil()).unwrap();
50
51
  }
51
52
  Some(s) => {
52
53
  let rblst = to_a_recursive(s.as_ref());
@@ -54,15 +55,15 @@ impl RbSeries {
54
55
  }
55
56
  }
56
57
  }
57
- v.into_value()
58
+ v.as_value()
58
59
  }
59
60
  DataType::Array(_, _) => {
60
- let v = RArray::new();
61
+ let v = ruby.ary_new();
61
62
  let ca = series.array().unwrap();
62
63
  for opt_s in ca.amortized_iter() {
63
64
  match opt_s {
64
65
  None => {
65
- v.push(qnil()).unwrap();
66
+ v.push(ruby.qnil()).unwrap();
66
67
  }
67
68
  Some(s) => {
68
69
  let rblst = to_a_recursive(s.as_ref());
@@ -70,39 +71,39 @@ impl RbSeries {
70
71
  }
71
72
  }
72
73
  }
73
- v.into_value()
74
+ v.as_value()
74
75
  }
75
76
  DataType::Date => {
76
77
  let ca = series.date().unwrap();
77
- return Wrap(ca).into_value();
78
+ return Wrap(ca).into_value_with(&ruby);
78
79
  }
79
80
  DataType::Time => {
80
81
  let ca = series.time().unwrap();
81
- return Wrap(ca).into_value();
82
+ return Wrap(ca).into_value_with(&ruby);
82
83
  }
83
84
  DataType::Datetime(_, _) => {
84
85
  let ca = series.datetime().unwrap();
85
- return Wrap(ca).into_value();
86
+ return Wrap(ca).into_value_with(&ruby);
86
87
  }
87
88
  DataType::Decimal(_, _) => {
88
89
  let ca = series.decimal().unwrap();
89
- return Wrap(ca).into_value();
90
+ return Wrap(ca).into_value_with(&ruby);
90
91
  }
91
92
  DataType::String => {
92
93
  let ca = series.str().unwrap();
93
- return Wrap(ca).into_value();
94
+ return Wrap(ca).into_value_with(&ruby);
94
95
  }
95
96
  DataType::Struct(_) => {
96
97
  let ca = series.struct_().unwrap();
97
- return Wrap(ca).into_value();
98
+ return Wrap(ca).into_value_with(&ruby);
98
99
  }
99
100
  DataType::Duration(_) => {
100
101
  let ca = series.duration().unwrap();
101
- return Wrap(ca).into_value();
102
+ return Wrap(ca).into_value_with(&ruby);
102
103
  }
103
104
  DataType::Binary => {
104
105
  let ca = series.binary().unwrap();
105
- return Wrap(ca).into_value();
106
+ return Wrap(ca).into_value_with(&ruby);
106
107
  }
107
108
  DataType::Null => {
108
109
  let null: Option<u8> = None;
@@ -125,7 +126,10 @@ impl RbSeries {
125
126
  }
126
127
  impl ExactSizeIterator for NullIter {}
127
128
 
128
- RArray::from_iter(NullIter { iter, n }).into_value()
129
+ Ruby::get()
130
+ .unwrap()
131
+ .ary_from_iter(NullIter { iter, n })
132
+ .as_value()
129
133
  }
130
134
  DataType::Unknown(_) => {
131
135
  panic!("to_a not implemented for unknown")
@@ -134,7 +138,7 @@ impl RbSeries {
134
138
  unreachable!()
135
139
  }
136
140
  };
137
- rblist.into_value()
141
+ rblist.as_value()
138
142
  }
139
143
 
140
144
  to_a_recursive(series)