polars-df 0.13.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +208 -0
  4. data/Cargo.lock +2556 -0
  5. data/Cargo.toml +6 -0
  6. data/LICENSE-THIRD-PARTY.txt +39278 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +437 -0
  9. data/lib/polars/3.1/polars.so +0 -0
  10. data/lib/polars/3.2/polars.so +0 -0
  11. data/lib/polars/3.3/polars.so +0 -0
  12. data/lib/polars/array_expr.rb +537 -0
  13. data/lib/polars/array_name_space.rb +423 -0
  14. data/lib/polars/batched_csv_reader.rb +104 -0
  15. data/lib/polars/binary_expr.rb +77 -0
  16. data/lib/polars/binary_name_space.rb +66 -0
  17. data/lib/polars/cat_expr.rb +36 -0
  18. data/lib/polars/cat_name_space.rb +88 -0
  19. data/lib/polars/config.rb +530 -0
  20. data/lib/polars/convert.rb +98 -0
  21. data/lib/polars/data_frame.rb +5191 -0
  22. data/lib/polars/data_types.rb +466 -0
  23. data/lib/polars/date_time_expr.rb +1397 -0
  24. data/lib/polars/date_time_name_space.rb +1287 -0
  25. data/lib/polars/dynamic_group_by.rb +52 -0
  26. data/lib/polars/exceptions.rb +38 -0
  27. data/lib/polars/expr.rb +7256 -0
  28. data/lib/polars/expr_dispatch.rb +22 -0
  29. data/lib/polars/functions/aggregation/horizontal.rb +246 -0
  30. data/lib/polars/functions/aggregation/vertical.rb +282 -0
  31. data/lib/polars/functions/as_datatype.rb +271 -0
  32. data/lib/polars/functions/col.rb +47 -0
  33. data/lib/polars/functions/eager.rb +182 -0
  34. data/lib/polars/functions/lazy.rb +1329 -0
  35. data/lib/polars/functions/len.rb +49 -0
  36. data/lib/polars/functions/lit.rb +35 -0
  37. data/lib/polars/functions/random.rb +16 -0
  38. data/lib/polars/functions/range/date_range.rb +136 -0
  39. data/lib/polars/functions/range/datetime_range.rb +149 -0
  40. data/lib/polars/functions/range/int_range.rb +51 -0
  41. data/lib/polars/functions/range/time_range.rb +141 -0
  42. data/lib/polars/functions/repeat.rb +144 -0
  43. data/lib/polars/functions/whenthen.rb +96 -0
  44. data/lib/polars/functions.rb +57 -0
  45. data/lib/polars/group_by.rb +613 -0
  46. data/lib/polars/io/avro.rb +24 -0
  47. data/lib/polars/io/csv.rb +696 -0
  48. data/lib/polars/io/database.rb +73 -0
  49. data/lib/polars/io/ipc.rb +275 -0
  50. data/lib/polars/io/json.rb +29 -0
  51. data/lib/polars/io/ndjson.rb +80 -0
  52. data/lib/polars/io/parquet.rb +233 -0
  53. data/lib/polars/lazy_frame.rb +2708 -0
  54. data/lib/polars/lazy_group_by.rb +181 -0
  55. data/lib/polars/list_expr.rb +791 -0
  56. data/lib/polars/list_name_space.rb +449 -0
  57. data/lib/polars/meta_expr.rb +222 -0
  58. data/lib/polars/name_expr.rb +198 -0
  59. data/lib/polars/plot.rb +109 -0
  60. data/lib/polars/rolling_group_by.rb +35 -0
  61. data/lib/polars/series.rb +4444 -0
  62. data/lib/polars/slice.rb +104 -0
  63. data/lib/polars/sql_context.rb +194 -0
  64. data/lib/polars/string_cache.rb +75 -0
  65. data/lib/polars/string_expr.rb +1495 -0
  66. data/lib/polars/string_name_space.rb +811 -0
  67. data/lib/polars/struct_expr.rb +98 -0
  68. data/lib/polars/struct_name_space.rb +96 -0
  69. data/lib/polars/testing.rb +507 -0
  70. data/lib/polars/utils/constants.rb +9 -0
  71. data/lib/polars/utils/convert.rb +97 -0
  72. data/lib/polars/utils/parse.rb +89 -0
  73. data/lib/polars/utils/various.rb +76 -0
  74. data/lib/polars/utils/wrap.rb +19 -0
  75. data/lib/polars/utils.rb +130 -0
  76. data/lib/polars/version.rb +4 -0
  77. data/lib/polars/whenthen.rb +83 -0
  78. data/lib/polars-df.rb +1 -0
  79. data/lib/polars.rb +91 -0
  80. metadata +138 -0
@@ -0,0 +1,49 @@
1
+ module Polars
2
+ module Functions
3
+ # Return the number of rows in the context.
4
+ #
5
+ # This is similar to `COUNT(*)` in SQL.
6
+ #
7
+ # @return [Expr]
8
+ #
9
+ # @example
10
+ # df = Polars::DataFrame.new(
11
+ # {
12
+ # "a" => [1, 2, nil],
13
+ # "b" => [3, nil, nil],
14
+ # "c" => ["foo", "bar", "foo"]
15
+ # }
16
+ # )
17
+ # df.select(Polars.len)
18
+ # # =>
19
+ # # shape: (1, 1)
20
+ # # ┌─────┐
21
+ # # │ len │
22
+ # # │ --- │
23
+ # # │ u32 │
24
+ # # ╞═════╡
25
+ # # │ 3 │
26
+ # # └─────┘
27
+ #
28
+ # @example Generate an index column by using `len` in conjunction with `int_range`.
29
+ # df.select([
30
+ # Polars.int_range(Polars.len, dtype: Polars::UInt32).alias("index"),
31
+ # Polars.all
32
+ # ])
33
+ # # =>
34
+ # # shape: (3, 4)
35
+ # # ┌───────┬──────┬──────┬─────┐
36
+ # # │ index ┆ a ┆ b ┆ c │
37
+ # # │ --- ┆ --- ┆ --- ┆ --- │
38
+ # # │ u32 ┆ i64 ┆ i64 ┆ str │
39
+ # # ╞═══════╪══════╪══════╪═════╡
40
+ # # │ 0 ┆ 1 ┆ 3 ┆ foo │
41
+ # # │ 1 ┆ 2 ┆ null ┆ bar │
42
+ # # │ 2 ┆ null ┆ null ┆ foo │
43
+ # # └───────┴──────┴──────┴─────┘
44
+ def len
45
+ Utils.wrap_expr(Plr.len)
46
+ end
47
+ alias_method :length, :len
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ module Polars
2
+ module Functions
3
+ # Return an expression representing a literal value.
4
+ #
5
+ # @return [Expr]
6
+ def lit(value, dtype: nil, allow_object: nil)
7
+ if value.is_a?(::Time) || value.is_a?(::DateTime)
8
+ time_unit = dtype&.time_unit || "ns"
9
+ time_zone = dtype.&time_zone
10
+ e = lit(Utils.datetime_to_int(value, time_unit)).cast(Datetime.new(time_unit))
11
+ if time_zone
12
+ return e.dt.replace_time_zone(time_zone.to_s)
13
+ else
14
+ return e
15
+ end
16
+ elsif value.is_a?(::Date)
17
+ return lit(::Time.utc(value.year, value.month, value.day)).cast(Date)
18
+ elsif value.is_a?(Polars::Series)
19
+ name = value.name
20
+ value = value._s
21
+ e = Utils.wrap_expr(Plr.lit(value, allow_object))
22
+ if name == ""
23
+ return e
24
+ end
25
+ return e.alias(name)
26
+ elsif (defined?(Numo::NArray) && value.is_a?(Numo::NArray)) || value.is_a?(::Array)
27
+ return lit(Series.new("", value))
28
+ elsif dtype
29
+ return Utils.wrap_expr(Plr.lit(value, allow_object)).cast(dtype)
30
+ end
31
+
32
+ Utils.wrap_expr(Plr.lit(value, allow_object))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module Polars
2
+ module Functions
3
+ # Set the global random seed for Polars.
4
+ #
5
+ # This random seed is used to determine things such as shuffle ordering.
6
+ #
7
+ # @param seed [Integer]
8
+ # A non-negative integer < 2**64 used to seed the internal global
9
+ # random number generator.
10
+ #
11
+ # @return [nil]
12
+ def set_random_seed(seed)
13
+ Plr.set_random_seed(seed)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,136 @@
1
+ module Polars
2
+ module Functions
3
+ # Create a range of type `Datetime` (or `Date`).
4
+ #
5
+ # @param start [Object]
6
+ # Lower bound of the date range.
7
+ # @param stop [Object]
8
+ # Upper bound of the date range.
9
+ # @param interval [Object]
10
+ # Interval periods. It can be a polars duration string, such as `3d12h4m25s`
11
+ # representing 3 days, 12 hours, 4 minutes, and 25 seconds.
12
+ # @param closed ["both", "left", "right", "none"]
13
+ # Define whether the temporal window interval is closed or not.
14
+ # @param eager [Boolean]
15
+ # Evaluate immediately and return a `Series`.
16
+ # If set to `false` (default), return an expression instead.
17
+ #
18
+ # @return [Object]
19
+ #
20
+ # @note
21
+ # If both `low` and `high` are passed as date types (not datetime), and the
22
+ # interval granularity is no finer than 1d, the returned range is also of
23
+ # type date. All other permutations return a datetime Series.
24
+ #
25
+ # @example Using polars duration string to specify the interval
26
+ # Polars.date_range(Date.new(2022, 1, 1), Date.new(2022, 3, 1), "1mo", eager: true).alias(
27
+ # "date"
28
+ # )
29
+ # # =>
30
+ # # shape: (3,)
31
+ # # Series: 'date' [date]
32
+ # # [
33
+ # # 2022-01-01
34
+ # # 2022-02-01
35
+ # # 2022-03-01
36
+ # # ]
37
+ def date_range(
38
+ start,
39
+ stop,
40
+ interval = "1d",
41
+ closed: "both",
42
+ eager: false
43
+ )
44
+ interval = Utils.parse_interval_argument(interval)
45
+
46
+ start_rbexpr = Utils.parse_into_expression(start)
47
+ end_rbexpr = Utils.parse_into_expression(stop)
48
+
49
+ result = Utils.wrap_expr(
50
+ Plr.date_range(start_rbexpr, end_rbexpr, interval, closed)
51
+ )
52
+
53
+ if eager
54
+ return F.select(result).to_series
55
+ end
56
+
57
+ result
58
+ end
59
+
60
+ # Create a column of date ranges.
61
+ #
62
+ # @param start [Object]
63
+ # Lower bound of the date range.
64
+ # @param stop [Object]
65
+ # Upper bound of the date range.
66
+ # @param interval [Object]
67
+ # Interval of the range periods, specified using the Polars duration string language (see "Notes" section below).
68
+ # @param closed ["both", "left", "right", "none"]
69
+ # Define which sides of the range are closed (inclusive).
70
+ # @param eager [Boolean]
71
+ # Evaluate immediately and return a `Series`.
72
+ # If set to `false` (default), return an expression instead.
73
+ #
74
+ # @return [Object]
75
+ #
76
+ # @note
77
+ # `interval` is created according to the following string language:
78
+ #
79
+ # - 1ns (1 nanosecond)
80
+ # - 1us (1 microsecond)
81
+ # - 1ms (1 millisecond)
82
+ # - 1s (1 second)
83
+ # - 1m (1 minute)
84
+ # - 1h (1 hour)
85
+ # - 1d (1 calendar day)
86
+ # - 1w (1 calendar week)
87
+ # - 1mo (1 calendar month)
88
+ # - 1q (1 calendar quarter)
89
+ # - 1y (1 calendar year)
90
+ #
91
+ # Or combine them:
92
+ # "3d12h4m25s" # 3 days, 12 hours, 4 minutes, and 25 seconds
93
+ #
94
+ # By "calendar day", we mean the corresponding time on the next day (which may
95
+ # not be 24 hours, due to daylight savings). Similarly for "calendar week",
96
+ # "calendar month", "calendar quarter", and "calendar year".
97
+ #
98
+ # @example
99
+ # df = Polars::DataFrame.new(
100
+ # {
101
+ # "start" => [Date.new(2022, 1, 1), Date.new(2022, 1, 2)],
102
+ # "end" => Date.new(2022, 1, 3)
103
+ # }
104
+ # )
105
+ # df.with_columns(date_range: Polars.date_ranges("start", "end"))
106
+ # # =>
107
+ # # shape: (2, 3)
108
+ # # ┌────────────┬────────────┬─────────────────────────────────┐
109
+ # # │ start ┆ end ┆ date_range │
110
+ # # │ --- ┆ --- ┆ --- │
111
+ # # │ date ┆ date ┆ list[date] │
112
+ # # ╞════════════╪════════════╪═════════════════════════════════╡
113
+ # # │ 2022-01-01 ┆ 2022-01-03 ┆ [2022-01-01, 2022-01-02, 2022-… │
114
+ # # │ 2022-01-02 ┆ 2022-01-03 ┆ [2022-01-02, 2022-01-03] │
115
+ # # └────────────┴────────────┴─────────────────────────────────┘
116
+ def date_ranges(
117
+ start,
118
+ stop,
119
+ interval = "1d",
120
+ closed: "both",
121
+ eager: false
122
+ )
123
+ interval = Utils.parse_interval_argument(interval)
124
+ start_rbexpr = Utils.parse_into_expression(start)
125
+ end_rbexpr = Utils.parse_into_expression(stop)
126
+
127
+ result = Utils.wrap_expr(Plr.date_ranges(start_rbexpr, end_rbexpr, interval, closed))
128
+
129
+ if eager
130
+ return F.select(result).to_series
131
+ end
132
+
133
+ result
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,149 @@
1
+ module Polars
2
+ module Functions
3
+ # Generate a datetime range.
4
+ #
5
+ # @param start [Object]
6
+ # Lower bound of the datetime range.
7
+ # @param stop [Object]
8
+ # Upper bound of the datetime range.
9
+ # @param interval [String]
10
+ # Interval of the range periods, specified using the Polars duration string language.
11
+ # @param closed ['both', 'left', 'right', 'none']
12
+ # Define which sides of the range are closed (inclusive).
13
+ # @param time_unit [nil, 'ns', 'us', 'ms']
14
+ # Time unit of the resulting `Datetime` data type.
15
+ # @param time_zone [String]
16
+ # Time zone of the resulting `Datetime` data type.
17
+ # @param eager [Boolean]
18
+ # Evaluate immediately and return a `Series`.
19
+ # If set to `false` (default), return an expression instead.
20
+ #
21
+ # @return [Object]
22
+ #
23
+ # @example Using Polars duration string to specify the interval:
24
+ # Polars.datetime_range(
25
+ # DateTime.new(2022, 1, 1), DateTime.new(2022, 3, 1), "1mo", eager: true
26
+ # ).alias("datetime")
27
+ # # =>
28
+ # # shape: (3,)
29
+ # # Series: 'datetime' [datetime[ns]]
30
+ # # [
31
+ # # 2022-01-01 00:00:00
32
+ # # 2022-02-01 00:00:00
33
+ # # 2022-03-01 00:00:00
34
+ # # ]
35
+ #
36
+ # @example Specifying a time zone:
37
+ # Polars.datetime_range(
38
+ # DateTime.new(2022, 1, 1),
39
+ # DateTime.new(2022, 3, 1),
40
+ # "1mo",
41
+ # time_zone: "America/New_York",
42
+ # eager: true
43
+ # ).alias("datetime")
44
+ # # =>
45
+ # # shape: (3,)
46
+ # # Series: 'datetime' [datetime[ns, America/New_York]]
47
+ # # [
48
+ # # 2022-01-01 00:00:00 EST
49
+ # # 2022-02-01 00:00:00 EST
50
+ # # 2022-03-01 00:00:00 EST
51
+ # # ]
52
+ def datetime_range(
53
+ start,
54
+ stop,
55
+ interval = "1d",
56
+ closed: "both",
57
+ time_unit: nil,
58
+ time_zone: nil,
59
+ eager: false
60
+ )
61
+ interval = Utils.parse_interval_argument(interval)
62
+ if time_unit.nil? && interval.include?("ns")
63
+ time_unit = "ns"
64
+ end
65
+
66
+ start_rbexpr = Utils.parse_into_expression(start)
67
+ end_rbexpr = Utils.parse_into_expression(stop)
68
+ result = Utils.wrap_expr(
69
+ Plr.datetime_range(
70
+ start_rbexpr, end_rbexpr, interval, closed, time_unit, time_zone
71
+ )
72
+ )
73
+
74
+ if eager
75
+ return Polars.select(result).to_series
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ # Create a column of datetime ranges.
82
+ #
83
+ # @param start [Object]
84
+ # Lower bound of the datetime range.
85
+ # @param stop [Object]
86
+ # Upper bound of the datetime range.
87
+ # @param interval [String]
88
+ # Interval of the range periods, specified using the Polars duration string language.
89
+ # @param closed ['both', 'left', 'right', 'none']
90
+ # Define which sides of the range are closed (inclusive).
91
+ # @param time_unit [nil, 'ns', 'us', 'ms']
92
+ # Time unit of the resulting `Datetime` data type.
93
+ # @param time_zone [String]
94
+ # Time zone of the resulting `Datetime` data type.
95
+ # @param eager [Boolean]
96
+ # Evaluate immediately and return a `Series`.
97
+ # If set to `false` (default), return an expression instead.
98
+ #
99
+ # @return [Object]
100
+ #
101
+ # @example
102
+ # df = Polars::DataFrame.new(
103
+ # {
104
+ # "start" => [DateTime.new(2022, 1, 1), DateTime.new(2022, 1, 2)],
105
+ # "end" => DateTime.new(2022, 1, 3),
106
+ # }
107
+ # )
108
+ # df.select(datetime_range: Polars.datetime_ranges("start", "end"))
109
+ # # =>
110
+ # # shape: (2, 1)
111
+ # # ┌─────────────────────────────────┐
112
+ # # │ datetime_range │
113
+ # # │ --- │
114
+ # # │ list[datetime[ns]] │
115
+ # # ╞═════════════════════════════════╡
116
+ # # │ [2022-01-01 00:00:00, 2022-01-… │
117
+ # # │ [2022-01-02 00:00:00, 2022-01-… │
118
+ # # └─────────────────────────────────┘
119
+ def datetime_ranges(
120
+ start,
121
+ stop,
122
+ interval: "1d",
123
+ closed: "both",
124
+ time_unit: nil,
125
+ time_zone: nil,
126
+ eager: false
127
+ )
128
+ interval = Utils.parse_interval_argument(interval)
129
+ if time_unit.nil? && interval.include?("ns")
130
+ time_unit = "ns"
131
+ end
132
+
133
+ start_rbexpr = Utils.parse_into_expression(start)
134
+ end_rbexpr = Utils.parse_into_expression(stop)
135
+
136
+ result = Utils.wrap_expr(
137
+ Plr.datetime_ranges(
138
+ start_rbexpr, end_rbexpr, interval, closed, time_unit, time_zone
139
+ )
140
+ )
141
+
142
+ if eager
143
+ return Polars.select(result).to_series
144
+ end
145
+
146
+ result
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,51 @@
1
+ module Polars
2
+ module Functions
3
+ # Create a range expression (or Series).
4
+ #
5
+ # This can be used in a `select`, `with_column`, etc. Be sure that the resulting
6
+ # range size is equal to the length of the DataFrame you are collecting.
7
+ #
8
+ # @param start [Integer, Expr, Series]
9
+ # Lower bound of range.
10
+ # @param stop [Integer, Expr, Series]
11
+ # Upper bound of range.
12
+ # @param step [Integer]
13
+ # Step size of the range.
14
+ # @param eager [Boolean]
15
+ # If eager evaluation is `True`, a Series is returned instead of an Expr.
16
+ # @param dtype [Symbol]
17
+ # Apply an explicit integer dtype to the resulting expression (default is `Int64`).
18
+ #
19
+ # @return [Expr, Series]
20
+ #
21
+ # @example
22
+ # Polars.arange(0, 3, eager: true)
23
+ # # =>
24
+ # # shape: (3,)
25
+ # # Series: 'arange' [i64]
26
+ # # [
27
+ # # 0
28
+ # # 1
29
+ # # 2
30
+ # # ]
31
+ def int_range(start, stop = nil, step: 1, eager: false, dtype: nil)
32
+ if stop.nil?
33
+ stop = start
34
+ start = 0
35
+ end
36
+
37
+ start = Utils.parse_into_expression(start)
38
+ stop = Utils.parse_into_expression(stop)
39
+ dtype ||= Int64
40
+ dtype = dtype.to_s if dtype.is_a?(Symbol)
41
+ result = Utils.wrap_expr(Plr.int_range(start, stop, step, dtype)).alias("arange")
42
+
43
+ if eager
44
+ return select(result).to_series
45
+ end
46
+
47
+ result
48
+ end
49
+ alias_method :arange, :int_range
50
+ end
51
+ end
@@ -0,0 +1,141 @@
1
+ module Polars
2
+ module Functions
3
+ # Generate a time range.
4
+ #
5
+ # @param start [Object]
6
+ # Lower bound of the time range.
7
+ # @param stop [Object]
8
+ # Upper bound of the time range.
9
+ # @param interval [String]
10
+ # Interval of the range periods, specified using the Polars duration string language.
11
+ # @param closed ['both', 'left', 'right', 'none']
12
+ # Define which sides of the range are closed (inclusive).
13
+ # @param eager [Boolean]
14
+ # Evaluate immediately and return a `Series`.
15
+ # If set to `False` (default), return an expression instead.
16
+ #
17
+ # @return [Object]
18
+ #
19
+ # @example
20
+ # Polars.time_range(
21
+ # time(14, 0),
22
+ # nil,
23
+ # "3h15m",
24
+ # eager: true
25
+ # ).alias("time")
26
+ # # =>
27
+ # # shape: (4,)
28
+ # # Series: 'time' [time]
29
+ # # [
30
+ # # 14:00:00
31
+ # # 17:15:00
32
+ # # 20:30:00
33
+ # # 23:45:00
34
+ # # ]
35
+ def time_range(
36
+ start = nil,
37
+ stop = nil,
38
+ interval = "1h",
39
+ closed: "both",
40
+ eager: false
41
+ )
42
+ interval = Utils.parse_interval_argument(interval)
43
+ ["y", "mo", "w", "d"].each do |unit|
44
+ if interval.include?(unit)
45
+ msg = "invalid interval unit for time_range: found #{unit.inspect}"
46
+ raise ArgumentError, msg
47
+ end
48
+ end
49
+
50
+ if start.nil?
51
+ # start = time(0, 0, 0)
52
+ raise Todo
53
+ end
54
+ if stop.nil?
55
+ # stop = time(23, 59, 59, 999999)
56
+ raise Todo
57
+ end
58
+
59
+ start_rbexpr = Utils.parse_into_expression(start)
60
+ end_rbexpr = Utils.parse_into_expression(stop)
61
+
62
+ result = Utils.wrap_expr(Plr.time_range(start_rbexpr, end_rbexpr, interval, closed))
63
+
64
+ if eager
65
+ return Polars.select(result).to_series
66
+ end
67
+
68
+ result
69
+ end
70
+
71
+ # Create a column of time ranges.
72
+ #
73
+ # @param start [Object]
74
+ # Lower bound of the time range.
75
+ # @param stop [Object]
76
+ # Upper bound of the time range.
77
+ # @param interval [Integer]
78
+ # Interval of the range periods, specified using the Polars duration string language.
79
+ # @param closed ['both', 'left', 'right', 'none']
80
+ # Define which sides of the range are closed (inclusive).
81
+ # @param eager [Boolean]
82
+ # Evaluate immediately and return a `Series`.
83
+ # If set to `false` (default), return an expression instead.
84
+ #
85
+ # @return [Object]
86
+ #
87
+ # @example
88
+ # df = Polars::DataFrame.new(
89
+ # {
90
+ # "start" => [time(9, 0), time(10, 0)],
91
+ # "end" => time(11, 0)
92
+ # }
93
+ # )
94
+ # df.with_columns(time_range: Polars.time_ranges("start", "end"))
95
+ # # =>
96
+ # # shape: (2, 3)
97
+ # # ┌──────────┬──────────┬────────────────────────────────┐
98
+ # # │ start ┆ end ┆ time_range │
99
+ # # │ --- ┆ --- ┆ --- │
100
+ # # │ time ┆ time ┆ list[time] │
101
+ # # ╞══════════╪══════════╪════════════════════════════════╡
102
+ # # │ 09:00:00 ┆ 11:00:00 ┆ [09:00:00, 10:00:00, 11:00:00] │
103
+ # # │ 10:00:00 ┆ 11:00:00 ┆ [10:00:00, 11:00:00] │
104
+ # # └──────────┴──────────┴────────────────────────────────┘
105
+ def time_ranges(
106
+ start = nil,
107
+ stop = nil,
108
+ interval = "1h",
109
+ closed: "both",
110
+ eager: false
111
+ )
112
+ interval = Utils.parse_interval_argument(interval)
113
+ ["y", "mo", "w", "d"].each do |unit|
114
+ if interval.include?(unit)
115
+ msg = "invalid interval unit for time_range: found #{unit.inspect}"
116
+ raise ArgumentError, msg
117
+ end
118
+ end
119
+
120
+ if start.nil?
121
+ # start = time(0, 0, 0)
122
+ raise Todo
123
+ end
124
+ if stop.nil?
125
+ # stop = time(23, 59, 59, 999999)
126
+ raise Todo
127
+ end
128
+
129
+ start_rbexpr = Utils.parse_into_expression(start)
130
+ end_rbexpr = Utils.parse_into_expression(stop)
131
+
132
+ result = Utils.wrap_expr(Plr.time_ranges(start_rbexpr, end_rbexpr, interval, closed))
133
+
134
+ if eager
135
+ return Polars.select(result).to_series
136
+ end
137
+
138
+ result
139
+ end
140
+ end
141
+ end