polars-df 0.25.0 → 0.26.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/Cargo.lock +270 -97
  4. data/LICENSE.txt +1 -1
  5. data/README.md +1 -3
  6. data/ext/polars/Cargo.toml +19 -18
  7. data/ext/polars/src/catalog/unity.rs +15 -20
  8. data/ext/polars/src/conversion/any_value.rs +53 -29
  9. data/ext/polars/src/conversion/chunked_array.rs +58 -56
  10. data/ext/polars/src/conversion/datetime.rs +58 -7
  11. data/ext/polars/src/conversion/mod.rs +200 -150
  12. data/ext/polars/src/dataframe/export.rs +15 -12
  13. data/ext/polars/src/dataframe/general.rs +25 -7
  14. data/ext/polars/src/dataframe/map.rs +6 -4
  15. data/ext/polars/src/error.rs +1 -1
  16. data/ext/polars/src/expr/array.rs +0 -24
  17. data/ext/polars/src/expr/datatype.rs +13 -3
  18. data/ext/polars/src/expr/datetime.rs +4 -4
  19. data/ext/polars/src/expr/general.rs +35 -15
  20. data/ext/polars/src/expr/list.rs +0 -26
  21. data/ext/polars/src/expr/rolling.rs +24 -0
  22. data/ext/polars/src/functions/business.rs +2 -2
  23. data/ext/polars/src/functions/io.rs +4 -3
  24. data/ext/polars/src/functions/lazy.rs +65 -46
  25. data/ext/polars/src/functions/meta.rs +6 -5
  26. data/ext/polars/src/functions/mod.rs +0 -1
  27. data/ext/polars/src/functions/range.rs +13 -0
  28. data/ext/polars/src/functions/utils.rs +4 -2
  29. data/ext/polars/src/interop/arrow/mod.rs +4 -2
  30. data/ext/polars/src/interop/arrow/to_rb.rs +1 -1
  31. data/ext/polars/src/interop/numo/to_numo_series.rs +26 -25
  32. data/ext/polars/src/io/scan_options.rs +6 -3
  33. data/ext/polars/src/io/sink_options.rs +2 -0
  34. data/ext/polars/src/lazyframe/general.rs +243 -17
  35. data/ext/polars/src/lazyframe/optflags.rs +2 -1
  36. data/ext/polars/src/lib.rs +39 -35
  37. data/ext/polars/src/map/lazy.rs +5 -2
  38. data/ext/polars/src/map/series.rs +19 -18
  39. data/ext/polars/src/on_startup.rs +25 -6
  40. data/ext/polars/src/ruby/numo.rs +3 -4
  41. data/ext/polars/src/ruby/plan_callback.rs +1 -4
  42. data/ext/polars/src/ruby/rb_modules.rs +2 -4
  43. data/ext/polars/src/ruby/ruby_udf.rs +7 -9
  44. data/ext/polars/src/ruby/utils.rs +12 -1
  45. data/ext/polars/src/series/aggregation.rs +13 -1
  46. data/ext/polars/src/series/construction.rs +31 -50
  47. data/ext/polars/src/series/export.rs +33 -38
  48. data/ext/polars/src/series/general.rs +6 -6
  49. data/ext/polars/src/series/map.rs +3 -2
  50. data/ext/polars/src/series/scatter.rs +4 -4
  51. data/ext/polars/src/utils.rs +31 -7
  52. data/lib/polars/array_expr.rb +23 -7
  53. data/lib/polars/array_name_space.rb +16 -2
  54. data/lib/polars/binary_name_space.rb +32 -0
  55. data/lib/polars/collect_batches.rb +4 -0
  56. data/lib/polars/data_frame.rb +144 -11
  57. data/lib/polars/data_type_group.rb +5 -0
  58. data/lib/polars/date_time_expr.rb +91 -3
  59. data/lib/polars/date_time_name_space.rb +7 -1
  60. data/lib/polars/expr.rb +247 -44
  61. data/lib/polars/functions/business.rb +2 -2
  62. data/lib/polars/functions/datatype.rb +30 -0
  63. data/lib/polars/functions/eager.rb +80 -7
  64. data/lib/polars/functions/lazy.rb +97 -2
  65. data/lib/polars/functions/range/linear_space.rb +118 -0
  66. data/lib/polars/io/csv.rb +27 -5
  67. data/lib/polars/io/database.rb +2 -3
  68. data/lib/polars/io/ipc.rb +2 -2
  69. data/lib/polars/io/lines.rb +172 -0
  70. data/lib/polars/io/parquet.rb +1 -1
  71. data/lib/polars/io/sink_options.rb +5 -2
  72. data/lib/polars/lazy_frame.rb +517 -14
  73. data/lib/polars/list_expr.rb +21 -7
  74. data/lib/polars/list_name_space.rb +16 -2
  75. data/lib/polars/query_opt_flags.rb +23 -5
  76. data/lib/polars/selectors.rb +2 -2
  77. data/lib/polars/series.rb +176 -19
  78. data/lib/polars/sql_context.rb +2 -2
  79. data/lib/polars/string_cache.rb +19 -72
  80. data/lib/polars/string_expr.rb +1 -7
  81. data/lib/polars/string_name_space.rb +1 -7
  82. data/lib/polars/utils/construction/series.rb +24 -39
  83. data/lib/polars/utils/convert.rb +16 -6
  84. data/lib/polars/utils/parse.rb +7 -0
  85. data/lib/polars/utils/reduce_balanced.rb +43 -0
  86. data/lib/polars/utils/various.rb +5 -0
  87. data/lib/polars/version.rb +1 -1
  88. data/lib/polars.rb +2 -1
  89. metadata +4 -17
  90. data/ext/polars/src/functions/string_cache.rs +0 -24
@@ -25,6 +25,10 @@ mod testing;
25
25
  mod timeout;
26
26
  mod utils;
27
27
 
28
+ use crate::conversion::Wrap;
29
+
30
+ pub type RbDataType = Wrap<polars_core::datatypes::DataType>;
31
+
28
32
  use catalog::unity::RbCatalogClient;
29
33
  use conversion::*;
30
34
  use dataframe::RbDataFrame;
@@ -32,7 +36,6 @@ use error::RbPolarsErr;
32
36
  use expr::RbExpr;
33
37
  use expr::datatype::RbDataTypeExpr;
34
38
  use expr::selector::RbSelector;
35
- use functions::string_cache::RbStringCacheHolder;
36
39
  use functions::whenthen::{RbChainedThen, RbChainedWhen, RbThen, RbWhen};
37
40
  use interop::arrow::to_rb::{RbArrowArrayStream, RbArrowSchema};
38
41
  use lazyframe::{RbCollectBatches, RbInProcessQuery, RbLazyFrame, RbOptFlags};
@@ -151,7 +154,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
151
154
  class.define_method("hash_rows", method!(RbDataFrame::hash_rows, 4))?;
152
155
  class.define_method("transpose", method!(RbDataFrame::transpose, 2))?;
153
156
  class.define_method("upsample", method!(RbDataFrame::upsample, 4))?;
154
- class.define_method("to_struct", method!(RbDataFrame::to_struct, 1))?;
157
+ class.define_method("to_struct", method!(RbDataFrame::to_struct, 2))?;
155
158
  class.define_method("clear", method!(RbDataFrame::clear, 0))?;
156
159
  class.define_method(
157
160
  "serialize_binary",
@@ -189,6 +192,8 @@ fn init(ruby: &Ruby) -> RbResult<()> {
189
192
  class.define_method("is_not_nan", method!(RbExpr::is_not_nan, 0))?;
190
193
  class.define_method("min", method!(RbExpr::min, 0))?;
191
194
  class.define_method("max", method!(RbExpr::max, 0))?;
195
+ class.define_method("min_by", method!(RbExpr::min_by, 1))?;
196
+ class.define_method("max_by", method!(RbExpr::max_by, 1))?;
192
197
  class.define_method("nan_max", method!(RbExpr::nan_max, 0))?;
193
198
  class.define_method("nan_min", method!(RbExpr::nan_min, 0))?;
194
199
  class.define_method("mean", method!(RbExpr::mean, 0))?;
@@ -201,7 +206,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
201
206
  class.define_method("first", method!(RbExpr::first, 1))?;
202
207
  class.define_method("last", method!(RbExpr::last, 1))?;
203
208
  class.define_method("item", method!(RbExpr::item, 1))?;
204
- class.define_method("implode", method!(RbExpr::implode, 0))?;
209
+ class.define_method("implode", method!(RbExpr::implode, 1))?;
205
210
  class.define_method("quantile", method!(RbExpr::quantile, 2))?;
206
211
  class.define_method("cut", method!(RbExpr::cut, 4))?;
207
212
  class.define_method("qcut", method!(RbExpr::qcut, 5))?;
@@ -227,7 +232,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
227
232
  class.define_method("arg_min", method!(RbExpr::arg_min, 0))?;
228
233
  class.define_method("index_of", method!(RbExpr::index_of, 1))?;
229
234
  class.define_method("search_sorted", method!(RbExpr::search_sorted, 3))?;
230
- class.define_method("gather", method!(RbExpr::gather, 1))?;
235
+ class.define_method("gather", method!(RbExpr::gather, 2))?;
231
236
  class.define_method("get", method!(RbExpr::get, 2))?;
232
237
  class.define_method("sort_by", method!(RbExpr::sort_by, 5))?;
233
238
  class.define_method("shift", method!(RbExpr::shift, 2))?;
@@ -258,6 +263,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
258
263
  class.define_method("rechunk", method!(RbExpr::rechunk, 0))?;
259
264
  class.define_method("round", method!(RbExpr::round, 2))?;
260
265
  class.define_method("round_sig_figs", method!(RbExpr::round_sig_figs, 1))?;
266
+ class.define_method("truncate", method!(RbExpr::truncate, 1))?;
261
267
  class.define_method("floor", method!(RbExpr::floor, 0))?;
262
268
  class.define_method("ceil", method!(RbExpr::ceil, 0))?;
263
269
  class.define_method("clip", method!(RbExpr::clip, 2))?;
@@ -335,13 +341,8 @@ fn init(ruby: &Ruby) -> RbResult<()> {
335
341
  class.define_method("arr_var", method!(RbExpr::arr_var, 1))?;
336
342
  class.define_method("arr_mean", method!(RbExpr::arr_mean, 0))?;
337
343
  class.define_method("arr_median", method!(RbExpr::arr_median, 0))?;
338
- class.define_method("arr_unique", method!(RbExpr::arr_unique, 1))?;
339
- class.define_method("arr_n_unique", method!(RbExpr::arr_n_unique, 0))?;
340
344
  class.define_method("arr_to_list", method!(RbExpr::arr_to_list, 0))?;
341
- class.define_method("arr_all", method!(RbExpr::arr_all, 0))?;
342
- class.define_method("arr_any", method!(RbExpr::arr_any, 0))?;
343
345
  class.define_method("arr_sort", method!(RbExpr::arr_sort, 2))?;
344
- class.define_method("arr_reverse", method!(RbExpr::arr_reverse, 0))?;
345
346
  class.define_method("arr_arg_min", method!(RbExpr::arr_arg_min, 0))?;
346
347
  class.define_method("arr_arg_max", method!(RbExpr::arr_arg_max, 0))?;
347
348
  class.define_method("arr_get", method!(RbExpr::arr_get, 2))?;
@@ -477,7 +478,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
477
478
  class.define_method("dt_replace", method!(RbExpr::dt_replace, 8))?;
478
479
  class.define_method("dt_combine", method!(RbExpr::dt_combine, 2))?;
479
480
  class.define_method("dot", method!(RbExpr::dot, 1))?;
480
- class.define_method("reinterpret", method!(RbExpr::reinterpret, 1))?;
481
+ class.define_method("reinterpret", method!(RbExpr::reinterpret, 2))?;
481
482
  class.define_method("mode", method!(RbExpr::mode, 1))?;
482
483
  class.define_method("interpolate", method!(RbExpr::interpolate, 1))?;
483
484
  class.define_method("interpolate_by", method!(RbExpr::interpolate_by, 1))?;
@@ -504,6 +505,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
504
505
  class.define_method("rolling_rank_by", method!(RbExpr::rolling_rank_by, 6))?;
505
506
  class.define_method("rolling_skew", method!(RbExpr::rolling_skew, 4))?;
506
507
  class.define_method("rolling_kurtosis", method!(RbExpr::rolling_kurtosis, 5))?;
508
+ class.define_method("rolling_map", method!(RbExpr::rolling_map, 5))?;
507
509
  class.define_method("lower_bound", method!(RbExpr::lower_bound, 0))?;
508
510
  class.define_method("upper_bound", method!(RbExpr::upper_bound, 0))?;
509
511
  class.define_method("list_max", method!(RbExpr::list_max, 0))?;
@@ -524,16 +526,11 @@ fn init(ruby: &Ruby) -> RbResult<()> {
524
526
  class.define_method("list_var", method!(RbExpr::list_var, 1))?;
525
527
  class.define_method("list_tail", method!(RbExpr::list_tail, 1))?;
526
528
  class.define_method("list_sort", method!(RbExpr::list_sort, 2))?;
527
- class.define_method("list_reverse", method!(RbExpr::list_reverse, 0))?;
528
- class.define_method("list_n_unique", method!(RbExpr::list_n_unique, 0))?;
529
- class.define_method("list_unique", method!(RbExpr::list_unique, 1))?;
530
529
  class.define_method("list_set_operation", method!(RbExpr::list_set_operation, 2))?;
531
530
  class.define_method("list_get", method!(RbExpr::list_get, 2))?;
532
531
  class.define_method("list_join", method!(RbExpr::list_join, 2))?;
533
532
  class.define_method("list_arg_min", method!(RbExpr::list_arg_min, 0))?;
534
533
  class.define_method("list_arg_max", method!(RbExpr::list_arg_max, 0))?;
535
- class.define_method("list_all", method!(RbExpr::list_all, 0))?;
536
- class.define_method("list_any", method!(RbExpr::list_any, 0))?;
537
534
  class.define_method("list_diff", method!(RbExpr::list_diff, 2))?;
538
535
  class.define_method("list_shift", method!(RbExpr::list_shift, 1))?;
539
536
  class.define_method("list_slice", method!(RbExpr::list_slice, 2))?;
@@ -567,6 +564,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
567
564
  class.define_method("extend_constant", method!(RbExpr::extend_constant, 2))?;
568
565
  class.define_method("any", method!(RbExpr::any, 1))?;
569
566
  class.define_method("all", method!(RbExpr::all, 1))?;
567
+ class.define_method("is_empty", method!(RbExpr::is_empty, 1))?;
570
568
  class.define_method(
571
569
  "struct_field_by_name",
572
570
  method!(RbExpr::struct_field_by_name, 1),
@@ -590,7 +588,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
590
588
  class.define_method("exp", method!(RbExpr::exp, 0))?;
591
589
  class.define_method("entropy", method!(RbExpr::entropy, 2))?;
592
590
  class.define_method("_hash", method!(RbExpr::hash, 4))?;
593
- class.define_method("set_sorted_flag", method!(RbExpr::set_sorted_flag, 1))?;
591
+ class.define_method("set_sorted_flag", method!(RbExpr::set_sorted_flag, 2))?;
594
592
  class.define_method("replace", method!(RbExpr::replace, 2))?;
595
593
  class.define_method("replace_strict", method!(RbExpr::replace_strict, 4))?;
596
594
  class.define_method("hist", method!(RbExpr::hist, 4))?;
@@ -764,6 +762,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
764
762
  function!(functions::io::read_parquet_schema, 1),
765
763
  )?;
766
764
  class.define_singleton_method("collect_all", function!(functions::lazy::collect_all, 3))?;
765
+ class.define_singleton_method("explain_all", function!(functions::lazy::explain_all, 2))?;
767
766
  class.define_singleton_method(
768
767
  "collect_all_lazy",
769
768
  function!(functions::lazy::collect_all_lazy, 2),
@@ -780,6 +779,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
780
779
  )?;
781
780
  class.define_singleton_method("time_range", function!(functions::range::time_range, 4))?;
782
781
  class.define_singleton_method("time_ranges", function!(functions::range::time_ranges, 4))?;
782
+ class.define_singleton_method("linear_space", function!(functions::range::linear_space, 4))?;
783
783
  class.define_singleton_method(
784
784
  "linear_spaces",
785
785
  function!(functions::range::linear_spaces, 5),
@@ -796,18 +796,6 @@ fn init(ruby: &Ruby) -> RbResult<()> {
796
796
  "thread_pool_size",
797
797
  function!(functions::meta::thread_pool_size, 0),
798
798
  )?;
799
- class.define_singleton_method(
800
- "enable_string_cache",
801
- function!(functions::string_cache::enable_string_cache, 0),
802
- )?;
803
- class.define_singleton_method(
804
- "disable_string_cache",
805
- function!(functions::string_cache::disable_string_cache, 0),
806
- )?;
807
- class.define_singleton_method(
808
- "using_string_cache",
809
- function!(functions::string_cache::using_string_cache, 0),
810
- )?;
811
799
  class.define_singleton_method(
812
800
  "set_float_fmt",
813
801
  function!(functions::meta::set_float_fmt, 1),
@@ -904,6 +892,10 @@ fn init(ruby: &Ruby) -> RbResult<()> {
904
892
  function!(RbLazyFrame::new_from_parquet, 6),
905
893
  )?;
906
894
  class.define_singleton_method("new_from_ipc", function!(RbLazyFrame::new_from_ipc, 3))?;
895
+ class.define_singleton_method(
896
+ "new_from_scan_lines",
897
+ function!(RbLazyFrame::new_from_scan_lines, 3),
898
+ )?;
907
899
  class.define_method("describe_plan", method!(RbLazyFrame::describe_plan, 0))?;
908
900
  class.define_method(
909
901
  "describe_optimized_plan",
@@ -938,6 +930,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
938
930
  class.define_method("sink_ipc", method!(RbLazyFrame::sink_ipc, 6))?;
939
931
  class.define_method("sink_csv", method!(RbLazyFrame::sink_csv, -1))?;
940
932
  class.define_method("sink_ndjson", method!(RbLazyFrame::sink_ndjson, 5))?;
933
+ class.define_method("sink_batches", method!(RbLazyFrame::sink_batches, 3))?;
941
934
  class.define_method("filter", method!(RbLazyFrame::filter, 1))?;
942
935
  class.define_method("remove", method!(RbLazyFrame::remove, 1))?;
943
936
  class.define_method("select", method!(RbLazyFrame::select, 1))?;
@@ -951,12 +944,18 @@ fn init(ruby: &Ruby) -> RbResult<()> {
951
944
  class.define_method("join_asof", method!(RbLazyFrame::join_asof, 14))?;
952
945
  class.define_method("join", method!(RbLazyFrame::join, 11))?;
953
946
  class.define_method("join_where", method!(RbLazyFrame::join_where, 3))?;
947
+ class.define_method("gather", method!(RbLazyFrame::gather, 2))?;
954
948
  class.define_method("with_column", method!(RbLazyFrame::with_column, 1))?;
955
949
  class.define_method("with_columns", method!(RbLazyFrame::with_columns, 1))?;
956
950
  class.define_method(
957
951
  "with_columns_seq",
958
952
  method!(RbLazyFrame::with_columns_seq, 1),
959
953
  )?;
954
+ class.define_method("match_to_schema", method!(RbLazyFrame::match_to_schema, 7))?;
955
+ class.define_method(
956
+ "pipe_with_schema",
957
+ method!(RbLazyFrame::pipe_with_schema, 1),
958
+ )?;
960
959
  class.define_method("rename", method!(RbLazyFrame::rename, 3))?;
961
960
  class.define_method("reverse", method!(RbLazyFrame::reverse, 0))?;
962
961
  class.define_method("shift", method!(RbLazyFrame::shift, 2))?;
@@ -976,7 +975,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
976
975
  class.define_method("drop_nulls", method!(RbLazyFrame::drop_nulls, 1))?;
977
976
  class.define_method("slice", method!(RbLazyFrame::slice, 2))?;
978
977
  class.define_method("tail", method!(RbLazyFrame::tail, 1))?;
979
- class.define_method("pivot", method!(RbLazyFrame::pivot, 7))?;
978
+ class.define_method("pivot", method!(RbLazyFrame::pivot, 8))?;
980
979
  class.define_method("unpivot", method!(RbLazyFrame::unpivot, 4))?;
981
980
  class.define_method("with_row_index", method!(RbLazyFrame::with_row_index, 2))?;
982
981
  class.define_method("map_batches", method!(RbLazyFrame::map_batches, 7))?;
@@ -987,7 +986,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
987
986
  class.define_method("collect_schema", method!(RbLazyFrame::collect_schema, 0))?;
988
987
  class.define_method("unnest", method!(RbLazyFrame::unnest, 2))?;
989
988
  class.define_method("count", method!(RbLazyFrame::count, 0))?;
990
- class.define_method("merge_sorted", method!(RbLazyFrame::merge_sorted, 2))?;
989
+ class.define_method("merge_sorted", method!(RbLazyFrame::merge_sorted, 3))?;
991
990
  class.define_method("hint_sorted", method!(RbLazyFrame::hint_sorted, 3))?;
992
991
  class.define_method(
993
992
  "collect_concurrently",
@@ -996,6 +995,10 @@ fn init(ruby: &Ruby) -> RbResult<()> {
996
995
 
997
996
  let class = module.define_class("RbCollectBatches", ruby.class_object())?;
998
997
  class.define_method("next", method!(RbCollectBatches::next, 0))?;
998
+ class.define_method(
999
+ "arrow_c_stream",
1000
+ method!(RbCollectBatches::__arrow_c_stream__, 0),
1001
+ )?;
999
1002
 
1000
1003
  let class = module.define_class("RbInProcessQuery", ruby.class_object())?;
1001
1004
  class.define_method("cancel", method!(RbInProcessQuery::cancel, 0))?;
@@ -1040,7 +1043,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
1040
1043
  class.define_singleton_method("new_null", function!(RbSeries::new_null, 3))?;
1041
1044
  class.define_singleton_method("new_object", function!(RbSeries::new_object, 3))?;
1042
1045
  class.define_singleton_method("new_series_list", function!(RbSeries::new_series_list, 3))?;
1043
- class.define_singleton_method("new_array", function!(RbSeries::new_array, 5))?;
1046
+ class.define_singleton_method("new_array", function!(RbSeries::new_array, 4))?;
1044
1047
  class.define_singleton_method("new_decimal", function!(RbSeries::new_decimal, 3))?;
1045
1048
  class.define_singleton_method(
1046
1049
  "from_arrow_c_stream",
@@ -1105,6 +1108,7 @@ fn init(ruby: &Ruby) -> RbResult<()> {
1105
1108
  class.define_method("slice", method!(RbSeries::slice, 2))?;
1106
1109
  class.define_method("any", method!(RbSeries::any, 1))?;
1107
1110
  class.define_method("all", method!(RbSeries::all, 1))?;
1111
+ class.define_method("is_empty", method!(RbSeries::is_empty, 1))?;
1108
1112
  class.define_method("arg_min", method!(RbSeries::arg_min, 0))?;
1109
1113
  class.define_method("arg_max", method!(RbSeries::arg_max, 0))?;
1110
1114
  class.define_method(
@@ -1336,10 +1340,6 @@ fn init(ruby: &Ruby) -> RbResult<()> {
1336
1340
  class.define_method("register", method!(RbSQLContext::register, 2))?;
1337
1341
  class.define_method("unregister", method!(RbSQLContext::unregister, 1))?;
1338
1342
 
1339
- // string cache
1340
- let class = module.define_class("RbStringCacheHolder", ruby.class_object())?;
1341
- class.define_singleton_method("hold", function!(RbStringCacheHolder::hold, 0))?;
1342
-
1343
1343
  // arrow array stream
1344
1344
  let class = module.define_class("ArrowArrayStream", ruby.class_object())?;
1345
1345
  class.define_method("to_i", method!(RbArrowArrayStream::to_i, 0))?;
@@ -1397,6 +1397,10 @@ fn init(ruby: &Ruby) -> RbResult<()> {
1397
1397
  class.define_singleton_method("of_expr", function!(RbDataTypeExpr::of_expr, 1))?;
1398
1398
  class.define_singleton_method("self_dtype", function!(RbDataTypeExpr::self_dtype, 0))?;
1399
1399
  class.define_method("collect_dtype", method!(RbDataTypeExpr::collect_dtype, 1))?;
1400
+ class.define_singleton_method(
1401
+ "struct_with_fields",
1402
+ function!(RbDataTypeExpr::struct_with_fields, 1),
1403
+ )?;
1400
1404
 
1401
1405
  // selector
1402
1406
  let class = module.define_class("RbSelector", ruby.class_object())?;
@@ -4,7 +4,7 @@ use polars::prelude::*;
4
4
  use crate::expr::ToExprs;
5
5
  use crate::expr::datatype::RbDataTypeExpr;
6
6
  use crate::ruby::ruby_udf::{RubyUdfExpression, RubyUdfExt};
7
- use crate::ruby::utils::to_pl_err;
7
+ use crate::ruby::utils::{TryIntoValue, to_pl_err};
8
8
  use crate::{RbExpr, RbResult, RbSeries, Wrap};
9
9
 
10
10
  pub(crate) fn call_lambda_with_series(
@@ -17,7 +17,10 @@ pub(crate) fn call_lambda_with_series(
17
17
 
18
18
  // Set return_dtype in kwargs
19
19
  let dict = rb.hash_new();
20
- let output_dtype = output_dtype.map(Wrap);
20
+ let output_dtype = output_dtype
21
+ .map(|v| Wrap(v).try_into_value_with(rb))
22
+ .transpose()
23
+ .map_err(to_pl_err)?;
21
24
  dict.aset(rb.sym_new("return_dtype"), output_dtype)
22
25
  .map_err(to_pl_err)?;
23
26
 
@@ -4,6 +4,7 @@ use super::*;
4
4
  use crate::Wrap;
5
5
  use crate::error::RbPolarsErr;
6
6
  use crate::prelude::ObjectValue;
7
+ use crate::ruby::utils::TryIntoValue;
7
8
 
8
9
  pub trait ApplyLambdaGeneric {
9
10
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series>;
@@ -25,7 +26,7 @@ fn call_and_collect_anyvalues<T, I>(
25
26
  skip_nulls: bool,
26
27
  ) -> RbResult<Vec<AnyValue<'static>>>
27
28
  where
28
- T: IntoValue,
29
+ T: TryIntoValue,
29
30
  I: Iterator<Item = Option<T>>,
30
31
  {
31
32
  let mut avs = Vec::with_capacity(len);
@@ -36,7 +37,7 @@ where
36
37
  continue;
37
38
  }
38
39
  None => rb.qnil().into_value_with(rb),
39
- Some(val) => val.into_value_with(rb),
40
+ Some(val) => val.try_into_value_with(rb)?,
40
41
  };
41
42
  let av: Option<Wrap<AnyValue>> = lambda.funcall("call", (arg,))?;
42
43
  avs.push(av.map(|w| w.0).unwrap_or(AnyValue::Null));
@@ -46,7 +47,7 @@ where
46
47
 
47
48
  impl ApplyLambdaGeneric for BooleanChunked {
48
49
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
49
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
50
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
50
51
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
51
52
  }
52
53
 
@@ -57,7 +58,7 @@ impl ApplyLambdaGeneric for BooleanChunked {
57
58
  datatype: &DataType,
58
59
  skip_nulls: bool,
59
60
  ) -> RbResult<Series> {
60
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
61
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
61
62
  Ok(
62
63
  Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
63
64
  .map_err(RbPolarsErr::from)?,
@@ -71,7 +72,7 @@ where
71
72
  T::Native: IntoValue + TryConvert,
72
73
  {
73
74
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
74
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
75
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
75
76
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
76
77
  }
77
78
 
@@ -82,7 +83,7 @@ where
82
83
  datatype: &DataType,
83
84
  skip_nulls: bool,
84
85
  ) -> RbResult<Series> {
85
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
86
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
86
87
  Ok(
87
88
  Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
88
89
  .map_err(RbPolarsErr::from)?,
@@ -92,7 +93,7 @@ where
92
93
 
93
94
  impl ApplyLambdaGeneric for StringChunked {
94
95
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
95
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
96
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
96
97
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
97
98
  }
98
99
 
@@ -103,7 +104,7 @@ impl ApplyLambdaGeneric for StringChunked {
103
104
  datatype: &DataType,
104
105
  skip_nulls: bool,
105
106
  ) -> RbResult<Series> {
106
- let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.into_iter(), skip_nulls)?;
107
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
107
108
  Ok(
108
109
  Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
109
110
  .map_err(RbPolarsErr::from)?,
@@ -113,7 +114,7 @@ impl ApplyLambdaGeneric for StringChunked {
113
114
 
114
115
  impl ApplyLambdaGeneric for ListChunked {
115
116
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
116
- let it = self.into_iter().map(|opt_s| opt_s.map(Wrap));
117
+ let it = self.series_iter().map(|opt_s| opt_s.map(Wrap));
117
118
  let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
118
119
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
119
120
  }
@@ -125,7 +126,7 @@ impl ApplyLambdaGeneric for ListChunked {
125
126
  datatype: &DataType,
126
127
  skip_nulls: bool,
127
128
  ) -> RbResult<Series> {
128
- let it = self.into_iter().map(|opt_s| opt_s.map(Wrap));
129
+ let it = self.series_iter().map(|opt_s| opt_s.map(Wrap));
129
130
  let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
130
131
  Ok(
131
132
  Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
@@ -136,7 +137,7 @@ impl ApplyLambdaGeneric for ListChunked {
136
137
 
137
138
  impl ApplyLambdaGeneric for ArrayChunked {
138
139
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
139
- let it = self.into_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
140
+ let it = self.series_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
140
141
  let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
141
142
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
142
143
  }
@@ -148,7 +149,7 @@ impl ApplyLambdaGeneric for ArrayChunked {
148
149
  datatype: &DataType,
149
150
  skip_nulls: bool,
150
151
  ) -> RbResult<Series> {
151
- let it = self.into_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
152
+ let it = self.series_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
152
153
  let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
153
154
  Ok(
154
155
  Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
@@ -159,12 +160,12 @@ impl ApplyLambdaGeneric for ArrayChunked {
159
160
 
160
161
  impl ApplyLambdaGeneric for ObjectChunked<ObjectValue> {
161
162
  fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
162
- // TODO improve into_iter
163
+ // TODO improve iter
163
164
  let avs = call_and_collect_anyvalues(
164
165
  rb,
165
166
  lambda,
166
167
  self.len(),
167
- self.into_iter().map(|v| v.cloned()),
168
+ self.iter().map(|v| v.cloned()),
168
169
  skip_nulls,
169
170
  )?;
170
171
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
@@ -177,12 +178,12 @@ impl ApplyLambdaGeneric for ObjectChunked<ObjectValue> {
177
178
  datatype: &DataType,
178
179
  skip_nulls: bool,
179
180
  ) -> RbResult<Series> {
180
- // TODO improve into_iter
181
+ // TODO improve iter
181
182
  let avs = call_and_collect_anyvalues(
182
183
  rb,
183
184
  lambda,
184
185
  self.len(),
185
- self.into_iter().map(|v| v.cloned()),
186
+ self.iter().map(|v| v.cloned()),
186
187
  skip_nulls,
187
188
  )?;
188
189
  Ok(
@@ -223,7 +224,7 @@ impl ApplyLambdaGeneric for BinaryChunked {
223
224
  rb,
224
225
  lambda,
225
226
  self.len(),
226
- self.into_iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
227
+ self.iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
227
228
  skip_nulls,
228
229
  )?;
229
230
  Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
@@ -240,7 +241,7 @@ impl ApplyLambdaGeneric for BinaryChunked {
240
241
  rb,
241
242
  lambda,
242
243
  self.len(),
243
- self.into_iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
244
+ self.iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
244
245
  skip_nulls,
245
246
  )?;
246
247
  Ok(
@@ -5,6 +5,7 @@ use std::sync::OnceLock;
5
5
 
6
6
  use arrow::array::Array;
7
7
  use magnus::{IntoValue, Ruby, Value, prelude::*, value::Opaque};
8
+ use polars::chunked_array::object::ObjectArray;
8
9
  use polars::prelude::*;
9
10
  use polars_core::chunked_array::object::builder::ObjectChunkedBuilder;
10
11
  use polars_core::chunked_array::object::registry;
@@ -23,7 +24,7 @@ use crate::ruby::gvl::GvlExt;
23
24
  use crate::ruby::ruby_convert_registry::{FromRubyConvertRegistry, RubyConvertRegistry};
24
25
  use crate::ruby::ruby_udf;
25
26
  use crate::ruby::thread::{is_non_ruby_thread, run_in_ruby_thread};
26
- use crate::ruby::utils::to_pl_err;
27
+ use crate::ruby::utils::{TryIntoValue, to_pl_err};
27
28
  use crate::series::RbSeries;
28
29
 
29
30
  fn ruby_function_caller_series(
@@ -86,16 +87,23 @@ pub unsafe fn register_startup_deps(catch_keyboard_interrupt: bool) {
86
87
 
87
88
  let object_converter = Arc::new(|av: AnyValue| {
88
89
  let object = Ruby::attach(|rb| ObjectValue {
89
- inner: Wrap(av).into_value_with(rb).into(),
90
+ inner: Wrap(av).try_into_value_with(rb).unwrap().into(),
90
91
  });
91
92
  Box::new(object) as Box<dyn Any>
92
93
  });
93
94
  let rbobject_converter = Arc::new(|av: AnyValue| {
94
- let object = Ruby::attach(|rb| Wrap(av).into_value_with(rb));
95
+ let object = Ruby::attach(|rb| Wrap(av).try_into_value_with(rb).unwrap());
95
96
  Box::new(object) as Box<dyn Any>
96
97
  });
97
- fn object_array_getter(_arr: &dyn Array, _idx: usize) -> Option<AnyValue<'_>> {
98
- todo!();
98
+ fn object_array_getter(arr: &dyn Array, idx: usize) -> Option<AnyValue<'_>> {
99
+ let arr = arr
100
+ .as_any()
101
+ .downcast_ref::<ObjectArray<ObjectValue>>()
102
+ .unwrap();
103
+ arr.get(idx).map(|v| AnyValue::Object(v))
104
+ }
105
+ fn with_gil(f: &mut dyn FnMut()) {
106
+ Ruby::attach(|_| f())
99
107
  }
100
108
 
101
109
  crate::ruby::ruby_convert_registry::register_converters(RubyConvertRegistry {
@@ -168,7 +176,17 @@ pub unsafe fn register_startup_deps(catch_keyboard_interrupt: bool) {
168
176
  .into_value_with(rb))
169
177
  })
170
178
  }),
171
- schema: Arc::new(|_schema| Ruby::attach(|_rb| todo!())),
179
+ schema: Arc::new(|schema| {
180
+ Ruby::attach(|rb| {
181
+ Wrap(
182
+ schema
183
+ .downcast_ref::<polars_core::schema::Schema>()
184
+ .unwrap()
185
+ .clone(),
186
+ )
187
+ .try_into_value_with(rb)
188
+ })
189
+ }),
172
190
  },
173
191
  });
174
192
 
@@ -180,6 +198,7 @@ pub unsafe fn register_startup_deps(catch_keyboard_interrupt: bool) {
180
198
  rbobject_converter,
181
199
  physical_dtype,
182
200
  Arc::new(object_array_getter),
201
+ Arc::new(with_gil),
183
202
  );
184
203
 
185
204
  // Register SERIES UDF.
@@ -40,14 +40,13 @@ where
40
40
  pub struct RbArray1<T>(T);
41
41
 
42
42
  impl<T: Element> RbArray1<T> {
43
- pub fn from_iter<I>(values: I) -> RbResult<Value>
43
+ pub fn from_iter<I>(rb: &Ruby, values: I) -> RbResult<Value>
44
44
  where
45
45
  I: IntoIterator<Item = T>,
46
46
  {
47
- let ruby = Ruby::get().unwrap();
48
- ruby.class_object()
47
+ rb.class_object()
49
48
  .const_get::<_, RModule>("Numo")?
50
49
  .const_get::<_, RClass>(T::class_name())?
51
- .funcall("cast", (ruby.ary_from_iter(values),))
50
+ .funcall("cast", (rb.ary_from_iter(values),))
52
51
  }
53
52
  }
@@ -1,7 +1,4 @@
1
- use std::sync::Arc;
2
-
3
1
  use magnus::{Ruby, Value, value::Opaque, value::ReprValue};
4
- use polars_plan::dsl::SpecialEq;
5
2
  use polars_plan::prelude::PlanCallback;
6
3
 
7
4
  use crate::RbResult;
@@ -196,6 +193,6 @@ impl<Args: PlanCallbackArgs + Send + 'static, Out: PlanCallbackOut + Send + 'sta
196
193
  f(args, *udf.0)
197
194
  };
198
195
 
199
- Self::Rust(SpecialEq::new(Arc::new(f) as _))
196
+ Self::new(f)
200
197
  }
201
198
  }
@@ -1,12 +1,10 @@
1
1
  use magnus::{Module, RClass, Ruby, value::Lazy};
2
2
 
3
- static BIGDECIMAL: Lazy<RClass> =
4
- Lazy::new(|rb| rb.class_object().const_get("BigDecimal").unwrap());
5
3
  static DATE: Lazy<RClass> = Lazy::new(|rb| rb.class_object().const_get("Date").unwrap());
6
4
  static DATETIME: Lazy<RClass> = Lazy::new(|rb| rb.class_object().const_get("DateTime").unwrap());
7
5
 
8
- pub(crate) fn bigdecimal(rb: &Ruby) -> RClass {
9
- rb.get_inner(&BIGDECIMAL)
6
+ pub(crate) fn bigdecimal(rb: &Ruby) -> Option<RClass> {
7
+ rb.class_object().const_get("BigDecimal").ok()
10
8
  }
11
9
 
12
10
  pub(crate) fn date(rb: &Ruby) -> RClass {
@@ -82,15 +82,13 @@ impl AnonymousColumnsUdf for RubyUdfExpression {
82
82
 
83
83
  fn deep_clone(self: Arc<Self>) -> Arc<dyn AnonymousColumnsUdf> {
84
84
  Arc::new(Self {
85
- ruby_function: ArcValue::new(
86
- Ruby::attach(|rb| {
87
- // TODO fix
88
- rb.get_inner(*self.ruby_function.0)
89
- .funcall::<_, _, Value>("dup", ())
90
- .map(Opaque::from)
91
- })
92
- .unwrap(),
93
- ),
85
+ ruby_function: ArcValue::new(Ruby::attach(|rb| {
86
+ // TODO fix
87
+ rb.get_inner(*self.ruby_function.0)
88
+ .funcall::<_, _, Value>("dup", ())
89
+ .map(Opaque::from)
90
+ .unwrap()
91
+ })),
94
92
  output_type: self.output_type.clone(),
95
93
  materialized_field: OnceLock::new(),
96
94
  is_elementwise: self.is_elementwise,
@@ -1,8 +1,9 @@
1
1
  use std::sync::Arc;
2
2
 
3
- use magnus::{Error, Ruby, Value, gc, value::Opaque};
3
+ use magnus::{Error, IntoValue, Ruby, Value, gc, value::Opaque};
4
4
  use polars::error::PolarsError;
5
5
 
6
+ use crate::RbResult;
6
7
  use crate::ruby::gvl::GvlExt;
7
8
 
8
9
  pub(crate) fn to_pl_err(e: Error) -> PolarsError {
@@ -26,3 +27,13 @@ impl Drop for ArcValue {
26
27
  Ruby::attach(|_| gc::unregister_address(&*self.0));
27
28
  }
28
29
  }
30
+
31
+ pub trait TryIntoValue {
32
+ fn try_into_value_with(self, ruby: &Ruby) -> RbResult<Value>;
33
+ }
34
+
35
+ impl<T: IntoValue> TryIntoValue for T {
36
+ fn try_into_value_with(self, ruby: &Ruby) -> RbResult<Value> {
37
+ Ok(self.into_value_with(ruby))
38
+ }
39
+ }
@@ -3,11 +3,12 @@ use magnus::{IntoValue, Ruby, Value};
3
3
  use polars::prelude::*;
4
4
 
5
5
  use crate::prelude::*;
6
+ use crate::ruby::utils::TryIntoValue;
6
7
  use crate::utils::EnterPolarsExt;
7
8
  use crate::{RbResult, RbSeries};
8
9
 
9
10
  fn scalar_to_rb(scalar: RbResult<Scalar>, rb: &Ruby) -> RbResult<Value> {
10
- Ok(Wrap(scalar?.as_any_value()).into_value_with(rb))
11
+ Wrap(scalar?.as_any_value()).try_into_value_with(rb)
11
12
  }
12
13
 
13
14
  impl RbSeries {
@@ -35,6 +36,17 @@ impl RbSeries {
35
36
  })
36
37
  }
37
38
 
39
+ pub fn is_empty(rb: &Ruby, self_: &Self, ignore_nulls: bool) -> RbResult<bool> {
40
+ rb.enter_polars(|| {
41
+ let s = self_.series.read();
42
+ PolarsResult::Ok(if ignore_nulls {
43
+ s.is_full_null()
44
+ } else {
45
+ s.is_empty()
46
+ })
47
+ })
48
+ }
49
+
38
50
  pub fn arg_max(rb: &Ruby, self_: &Self) -> RbResult<Option<usize>> {
39
51
  rb.enter_polars_ok(|| self_.series.read().arg_max())
40
52
  }