polars-df 0.15.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -0,0 +1,173 @@
1
+ module Polars
2
+ # DataFrame.plot namespace.
3
+ class DataFramePlot
4
+ # @private
5
+ def initialize(df)
6
+ require "vega"
7
+
8
+ @df = df
9
+ end
10
+
11
+ # Draw line plot.
12
+ #
13
+ # @param x [String]
14
+ # Column with x-coordinates of lines.
15
+ # @param y [String]
16
+ # Column with y-coordinates of lines.
17
+ # @param color [String]
18
+ # Column to color lines by.
19
+ #
20
+ # @return [Vega::LiteChart]
21
+ def line(x, y, color: nil, _type: "line")
22
+ data = @df[[x, y, color].compact.map(&:to_s).uniq].rows(named: true)
23
+
24
+ x_type =
25
+ if @df[x].dtype.numeric?
26
+ "quantitative"
27
+ elsif @df[x].dtype.temporal?
28
+ "temporal"
29
+ else
30
+ "nominal"
31
+ end
32
+
33
+ scale = x_type == "temporal" ? {type: "utc"} : {}
34
+ encoding = {
35
+ x: {field: x, type: x_type, scale: scale},
36
+ y: {field: y, type: "quantitative"}
37
+ }
38
+ encoding[:color] = {field: color} if color
39
+
40
+ Vega.lite
41
+ .data(data)
42
+ .mark(type: _type, tooltip: true, interpolate: "cardinal", point: {size: 60})
43
+ .encoding(encoding)
44
+ .config(axis: {labelFontSize: 12})
45
+ end
46
+
47
+ # Draw area plot.
48
+ #
49
+ # @param x [String]
50
+ # Column with x-coordinates of lines.
51
+ # @param y [String]
52
+ # Column with y-coordinates of lines.
53
+ # @param color [String]
54
+ # Column to color lines by.
55
+ #
56
+ # @return [Vega::LiteChart]
57
+ def area(x, y, color: nil)
58
+ line(x, y, color: color, _type: "area")
59
+ end
60
+
61
+ # Draw pie chart.
62
+ #
63
+ # @param x [String]
64
+ # Column with label of slice.
65
+ # @param y [String]
66
+ # Column with size of slice.
67
+ #
68
+ # @return [Vega::LiteChart]
69
+ def pie(x, y)
70
+ data = @df[[x, y].map(&:to_s).uniq].rows(named: true)
71
+
72
+ Vega.lite
73
+ .data(data)
74
+ .mark(type: "arc", tooltip: true)
75
+ .encoding(
76
+ color: {field: x, type: "nominal", sort: "none", axis: {title: nil}, legend: {labelFontSize: 12}},
77
+ theta: {field: y, type: "quantitative"}
78
+ )
79
+ .view(stroke: nil)
80
+ end
81
+
82
+ # Draw column plot.
83
+ #
84
+ # @param x [String]
85
+ # Column with x-coordinates of columns.
86
+ # @param y [String]
87
+ # Column with y-coordinates of columns.
88
+ # @param color [String]
89
+ # Column to color columns by.
90
+ # @param stacked [Boolean]
91
+ # Stack columns.
92
+ #
93
+ # @return [Vega::LiteChart]
94
+ def column(x, y, color: nil, stacked: nil)
95
+ data = @df[[x, y, color].compact.map(&:to_s).uniq].rows(named: true)
96
+
97
+ encoding = {
98
+ x: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
99
+ y: {field: y, type: "quantitative"}
100
+ }
101
+ if color
102
+ encoding[:color] = {field: color}
103
+ encoding[:xOffset] = {field: color} unless stacked
104
+ end
105
+
106
+ Vega.lite
107
+ .data(data)
108
+ .mark(type: "bar", tooltip: true)
109
+ .encoding(encoding)
110
+ .config(axis: {labelFontSize: 12})
111
+ end
112
+
113
+ # Draw bar plot.
114
+ #
115
+ # @param x [String]
116
+ # Column with x-coordinates of bars.
117
+ # @param y [String]
118
+ # Column with y-coordinates of bars.
119
+ # @param color [String]
120
+ # Column to color bars by.
121
+ # @param stacked [Boolean]
122
+ # Stack bars.
123
+ #
124
+ # @return [Vega::LiteChart]
125
+ def bar(x, y, color: nil, stacked: nil)
126
+ data = @df[[x, y, color].compact.map(&:to_s).uniq].rows(named: true)
127
+
128
+ encoding = {
129
+ # TODO determine label angle
130
+ y: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
131
+ x: {field: y, type: "quantitative"}
132
+ }
133
+ if color
134
+ encoding[:color] = {field: color}
135
+ encoding[:yOffset] = {field: color} unless stacked
136
+ end
137
+
138
+ Vega.lite
139
+ .data(data)
140
+ .mark(type: "bar", tooltip: true)
141
+ .encoding(encoding)
142
+ .config(axis: {labelFontSize: 12})
143
+ end
144
+
145
+ # Draw scatter plot.
146
+ #
147
+ # @param x [String]
148
+ # Column with x-coordinates of points.
149
+ # @param y [String]
150
+ # Column with y-coordinates of points.
151
+ # @param color [String]
152
+ # Column to color points by.
153
+ #
154
+ # @return [Vega::LiteChart]
155
+ def scatter(x, y, color: nil)
156
+ data = @df[[x, y, color].compact.map(&:to_s).uniq].rows(named: true)
157
+
158
+ encoding = {
159
+ x: {field: x, type: "quantitative", scale: {zero: false}},
160
+ y: {field: y, type: "quantitative", scale: {zero: false}},
161
+ size: {value: 60}
162
+ }
163
+ encoding[:color] = {field: color} if color
164
+
165
+ Vega.lite
166
+ .data(data)
167
+ .mark(type: "circle", tooltip: true)
168
+ .encoding(encoding)
169
+ .config(axis: {labelFontSize: 12})
170
+ end
171
+ alias_method :point, :scatter
172
+ end
173
+ end
@@ -0,0 +1,52 @@
1
+ module Polars
2
+ # A lazily instantiated `DataType` that can be used in an `Expr`.
3
+ class DataTypeExpr
4
+ # @private
5
+ attr_accessor :_rbdatatype_expr
6
+
7
+ # @private
8
+ def self._from_rbdatatype_expr(rbdatatype_expr)
9
+ slf = new
10
+ slf._rbdatatype_expr = rbdatatype_expr
11
+ slf
12
+ end
13
+
14
+ # Materialize the `DataTypeExpr` in a specific context.
15
+ #
16
+ # This is a useful function when debugging datatype expressions.
17
+ #
18
+ # @return [DataType]
19
+ #
20
+ # @example
21
+ # lf = Polars::LazyFrame.new(
22
+ # {
23
+ # "a" => [1, 2, 3]
24
+ # }
25
+ # )
26
+ # Polars.dtype_of("a").collect_dtype(lf)
27
+ # # => Polars::Int64
28
+ #
29
+ # @example
30
+ # Polars.dtype_of("a").collect_dtype({"a" => Polars::String})
31
+ # # => Polars::String
32
+ def collect_dtype(
33
+ context
34
+ )
35
+ schema = nil
36
+ if context.is_a?(Schema)
37
+ schema = context
38
+ elsif context.is_a?(Hash)
39
+ schema = Schema.new(context)
40
+ elsif context.is_a?(DataFrame)
41
+ schema = context.schema
42
+ elsif context.is_a?(LazyFrame)
43
+ schema = context.collect_schema
44
+ else
45
+ msg = "DataTypeExpr.collect_dtype did not expect #{context.inspect}"
46
+ raise TypeError, msg
47
+ end
48
+
49
+ _rbdatatype_expr.collect_dtype(schema.to_h)
50
+ end
51
+ end
52
+ end
@@ -1,7 +1,9 @@
1
1
  module Polars
2
+ # @private
2
3
  class DataTypeGroup < Set
3
4
  end
4
5
 
6
+ # @private
5
7
  SIGNED_INTEGER_DTYPES = DataTypeGroup.new(
6
8
  [
7
9
  Int8,
@@ -10,6 +12,7 @@ module Polars
10
12
  Int64
11
13
  ]
12
14
  )
15
+ # @private
13
16
  UNSIGNED_INTEGER_DTYPES = DataTypeGroup.new(
14
17
  [
15
18
  UInt8,
@@ -18,10 +21,13 @@ module Polars
18
21
  UInt64
19
22
  ]
20
23
  )
24
+ # @private
21
25
  INTEGER_DTYPES = (
22
26
  SIGNED_INTEGER_DTYPES | UNSIGNED_INTEGER_DTYPES
23
27
  )
28
+ # @private
24
29
  FLOAT_DTYPES = DataTypeGroup.new([Float32, Float64])
30
+ # @private
25
31
  NUMERIC_DTYPES = DataTypeGroup.new(
26
32
  FLOAT_DTYPES + INTEGER_DTYPES | [Decimal]
27
33
  )
@@ -99,12 +99,34 @@ module Polars
99
99
  self < NestedType
100
100
  end
101
101
 
102
+ # Return a `DataTypeExpr` with a static `DataType`.
103
+ #
104
+ # @return [Expr]
105
+ #
106
+ # @example
107
+ # Polars::Int16.new.to_dtype_expr.collect_dtype({})
108
+ # # => Polars::Int16
109
+ def self.to_dtype_expr
110
+ DataTypeExpr._from_rbdatatype_expr(RbDataTypeExpr.from_dtype(self))
111
+ end
112
+
102
113
  [:numeric?, :decimal?, :integer?, :signed_integer?, :unsigned_integer?, :float?, :temporal?, :nested?].each do |v|
103
114
  define_method(v) do
104
115
  self.class.public_send(v)
105
116
  end
106
117
  end
107
118
 
119
+ # Return a `DataTypeExpr` with a static `DataType`.
120
+ #
121
+ # @return [Expr]
122
+ #
123
+ # @example
124
+ # Polars::Int16.new.to_dtype_expr.collect_dtype({})
125
+ # # => Polars::Int16
126
+ def to_dtype_expr
127
+ DataTypeExpr._from_rbdatatype_expr(RbDataTypeExpr.from_dtype(self))
128
+ end
129
+
108
130
  # Returns a string representing the data type.
109
131
  #
110
132
  # @return [String]
@@ -167,6 +189,10 @@ module Polars
167
189
  class Int64 < SignedIntegerType
168
190
  end
169
191
 
192
+ # 128-bit signed integer type.
193
+ class Int128 < SignedIntegerType
194
+ end
195
+
170
196
  # 8-bit unsigned integer type.
171
197
  class UInt8 < UnsignedIntegerType
172
198
  end
@@ -183,6 +209,14 @@ module Polars
183
209
  class UInt64 < UnsignedIntegerType
184
210
  end
185
211
 
212
+ # 128-bit unsigned integer type.
213
+ class UInt128 < UnsignedIntegerType
214
+ end
215
+
216
+ # 16-bit floating point type.
217
+ class Float16 < FloatType
218
+ end
219
+
186
220
  # 32-bit floating point type.
187
221
  class Float32 < FloatType
188
222
  end
@@ -197,7 +231,11 @@ module Polars
197
231
  class Decimal < NumericType
198
232
  attr_reader :precision, :scale
199
233
 
200
- def initialize(precision, scale)
234
+ def initialize(precision = nil, scale = 0)
235
+ if precision.nil?
236
+ precision = 38
237
+ end
238
+
201
239
  @precision = precision
202
240
  @scale = scale
203
241
  end
@@ -244,7 +282,6 @@ module Polars
244
282
  # Calendar date and time type.
245
283
  class Datetime < TemporalType
246
284
  attr_reader :time_unit, :time_zone
247
- alias_method :tu, :time_unit
248
285
 
249
286
  def initialize(time_unit = "us", time_zone = nil)
250
287
  @time_unit = time_unit || "us"
@@ -269,7 +306,6 @@ module Polars
269
306
  # Time duration/delta type.
270
307
  class Duration < TemporalType
271
308
  attr_reader :time_unit
272
- alias_method :tu, :time_unit
273
309
 
274
310
  def initialize(time_unit = "us")
275
311
  @time_unit = time_unit
@@ -290,12 +326,55 @@ module Polars
290
326
  end
291
327
  end
292
328
 
329
+ # A named collection of categories for `Categorical`.
330
+ #
331
+ # Two categories are considered equal (and will use the same physical mapping of
332
+ # categories to strings) if they have the same name, namespace and physical backing
333
+ # type, even if they are created in separate calls to `Categories`.
334
+ #
335
+ # @note
336
+ # This functionality is currently considered **unstable**. It may be
337
+ # changed at any point without it being considered a breaking change.
338
+ class Categories
339
+ attr_accessor :_categories
340
+
341
+ def initialize(name = nil)
342
+ if name.nil? || name == ""
343
+ self._categories = RbCategories.global_categories
344
+ return
345
+ end
346
+
347
+ raise Todo
348
+ end
349
+
350
+ # @private
351
+ def self._from_rb_categories(rb_categories)
352
+ slf = new
353
+ slf._categories = rb_categories
354
+ slf
355
+ end
356
+ end
357
+
293
358
  # A categorical encoding of a set of strings.
294
359
  class Categorical < DataType
295
- attr_reader :ordering
360
+ attr_reader :ordering, :categories
296
361
 
297
- def initialize(ordering = "physical")
298
- @ordering = ordering
362
+ def initialize(ordering = "physical", **kwargs)
363
+ if ordering.is_a?(Categories)
364
+ @ordering = "lexical"
365
+ @categories = ordering
366
+ # assert kwargs.length == 0
367
+ return
368
+ end
369
+
370
+ @ordering = "lexical"
371
+ if kwargs[:categories]
372
+ # assert kwargs.length == 1
373
+ @categories = kwargs[:categories]
374
+ else
375
+ # assert kwargs.length == 0
376
+ @categories = Categories.new
377
+ end
299
378
  end
300
379
  end
301
380
 
@@ -311,7 +390,7 @@ module Polars
311
390
  end
312
391
 
313
392
  if categories.empty?
314
- self.categories = Series.new("category", [], dtype: String)
393
+ @categories = Series.new("category", [], dtype: String)
315
394
  return
316
395
  end
317
396
 
@@ -353,7 +432,7 @@ module Polars
353
432
  class Object < DataType
354
433
  end
355
434
 
356
- # Type representing Null / None values.
435
+ # Type representing Null / nil values.
357
436
  class Null < DataType
358
437
  end
359
438
 
@@ -366,7 +445,7 @@ module Polars
366
445
  attr_reader :inner
367
446
 
368
447
  def initialize(inner)
369
- @inner = Utils.rb_type_to_dtype(inner)
448
+ @inner = Utils.parse_into_dtype(inner)
370
449
  end
371
450
 
372
451
  def ==(other)
@@ -386,21 +465,42 @@ module Polars
386
465
 
387
466
  # Nested list/array type.
388
467
  class Array < NestedType
389
- attr_reader :inner, :width
468
+ attr_reader :inner, :size, :shape
390
469
 
391
- def initialize(inner, width)
392
- if width.is_a?(DataType) || (width.is_a?(Class) && width < DataType)
393
- inner, width = width, inner
470
+ def initialize(inner, shape)
471
+ if shape.nil?
472
+ msg = "Array constructor is missing the required argument `shape`"
473
+ raise TypeError, msg
474
+ end
475
+
476
+ inner_parsed = Utils.parse_into_dtype(inner)
477
+ inner_shape = inner_parsed.is_a?(Array) ? inner_parsed.shape : []
478
+
479
+ if shape.is_a?(Integer)
480
+ @inner = inner_parsed
481
+ @size = shape
482
+ @shape = [shape] + inner_shape
483
+
484
+ elsif shape.is_a?(::Array) && shape[0].is_a?(Integer)
485
+ if shape.length > 1
486
+ inner_parsed = Array.new(inner_parsed, shape[1..])
487
+ end
488
+
489
+ @inner = inner_parsed
490
+ @size = shape[0]
491
+ @shape = shape + inner_shape
492
+
493
+ else
494
+ msg = "invalid input for shape: #{shape.inspect}"
495
+ raise TypeError, msg
394
496
  end
395
- @inner = Utils.rb_type_to_dtype(inner) if inner
396
- @width = width
397
497
  end
398
498
 
399
499
  def ==(other)
400
500
  if other.eql?(Array)
401
501
  true
402
502
  elsif other.is_a?(Array)
403
- if @width != other.width
503
+ if @shape != other.shape
404
504
  false
405
505
  elsif @inner.nil? || other.inner.nil?
406
506
  true
@@ -413,7 +513,7 @@ module Polars
413
513
  end
414
514
 
415
515
  def to_s
416
- "#{self.class.name}(#{inner}, width: #{width.inspect})"
516
+ "#{self.class.name}(#{inner}, shape: #{shape.inspect})"
417
517
  end
418
518
  end
419
519
 
@@ -423,7 +523,7 @@ module Polars
423
523
 
424
524
  def initialize(name, dtype)
425
525
  @name = name
426
- @dtype = Utils.rb_type_to_dtype(dtype)
526
+ @dtype = Utils.parse_into_dtype(dtype)
427
527
  end
428
528
 
429
529
  def ==(other)