This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 5d286d47dc4 GH-50832: [Ruby] Add
`ArrowFormat::FixedSizeBinaryArray.new(byte_width, values)` (#50854)
5d286d47dc4 is described below
commit 5d286d47dc45e934879d7432fe2b390b98f99427
Author: takuya kodama <[email protected]>
AuthorDate: Mon Aug 24 16:47:20 2026 +0800
GH-50832: [Ruby] Add `ArrowFormat::FixedSizeBinaryArray.new(byte_width,
values)` (#50854)
### Rationale for this change
Building a fixed size binary Arrow array from Ruby objects is convenient.
### What changes are included in this PR?
Accept:
* `ArrowFormat::FixedSizeBinaryArray.new(byte_width, values)`
* `ArrowFormat::FixedSizeBinaryArray.new(type, values)`
`ArrowFormat::FixedSizeBinaryType.try_convert` is added for the byte width
shorthand, in the same way as `ArrowFormat::Time32Array.new(unit, values)`. The
existing 4 arguments form is kept.
Decimal arrays are out of scope. `ArrowFormat::DecimalArray#to_a` returns
`BigDecimal`, so building one from Ruby objects needs a conversion between
`BigDecimal` and two's complement. I would like to open a separate issue for it.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
Yes.
* GitHub Issue: #50832
Authored-by: otegami <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
ruby/red-arrow-format/lib/arrow-format/array.rb | 54 ++++++++++++++-
ruby/red-arrow-format/lib/arrow-format/type.rb | 14 ++++
.../test/test-fixed-size-binary-array.rb | 79 ++++++++++++++++++++++
3 files changed, 146 insertions(+), 1 deletion(-)
diff --git a/ruby/red-arrow-format/lib/arrow-format/array.rb
b/ruby/red-arrow-format/lib/arrow-format/array.rb
index d190cc29923..20929493e90 100644
--- a/ruby/red-arrow-format/lib/arrow-format/array.rb
+++ b/ruby/red-arrow-format/lib/arrow-format/array.rb
@@ -852,7 +852,21 @@ module ArrowFormat
end
class FixedSizeBinaryArray < Array
- def initialize(type, size, validity_buffer, values_buffer)
+ include BufferAlignable
+
+ def initialize(type, *args)
+ unless type.is_a?(Type)
+ type = FixedSizeBinaryType.try_convert(type) || type
+ end
+ if args.size == 1
+ args = build_data(args.first, type)
+ elsif args.size != 3
+ raise ArgumentError,
+ "wrong number of arguments (given #{args.size + 1}, expected 2
or 4)"
+ end
+
+ size, validity_buffer, values_buffer = args
+
super(type, size, validity_buffer)
@values_buffer = values_buffer
end
@@ -875,6 +889,44 @@ module ArrowFormat
end
apply_validity(values)
end
+
+ private
+ def build_data(data, type)
+ n = 0
+ validity_buffer_builder = nil
+
+ values = +"".b
+ byte_width = type.byte_width
+ null_value = "\x00" * byte_width
+
+ data.each_with_index do |value, i|
+ if value.nil?
+ validity_buffer_builder ||= SparseBitmapBuilder.new
+ validity_buffer_builder.unset(i)
+ values.append_as_bytes(null_value)
+ else
+ unless value.bytesize == byte_width
+ message = "value size must be #{byte_width}: #{value.inspect}"
+ raise ArgumentError, message
+ end
+ values.append_as_bytes(value)
+ end
+
+ n += 1
+ end
+
+ validity_buffer = validity_buffer_builder&.finish(n)
+
+ pad!(values, buffer_padding_size(values))
+ values.freeze
+ values_buffer = IO::Buffer.for(values)
+
+ [
+ n,
+ validity_buffer,
+ values_buffer,
+ ]
+ end
end
class DecimalArray < FixedSizeBinaryArray
diff --git a/ruby/red-arrow-format/lib/arrow-format/type.rb
b/ruby/red-arrow-format/lib/arrow-format/type.rb
index b52136769d4..9a6d1f3ed06 100644
--- a/ruby/red-arrow-format/lib/arrow-format/type.rb
+++ b/ruby/red-arrow-format/lib/arrow-format/type.rb
@@ -911,6 +911,20 @@ module ArrowFormat
end
class FixedSizeBinaryType < Type
+ class << self
+ def try_convert(value)
+ case value
+ when Integer
+ byte_width = value
+ new(byte_width)
+ when self
+ value
+ else
+ nil
+ end
+ end
+ end
+
attr_reader :byte_width
def initialize(byte_width)
super()
diff --git a/ruby/red-arrow-format/test/test-fixed-size-binary-array.rb
b/ruby/red-arrow-format/test/test-fixed-size-binary-array.rb
new file mode 100644
index 00000000000..bee0ae1f8ee
--- /dev/null
+++ b/ruby/red-arrow-format/test/test-fixed-size-binary-array.rb
@@ -0,0 +1,79 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+class TestFixedSizeBinaryArray < Test::Unit::TestCase
+ sub_test_case("#initialize") do
+ def test_no_null
+ values = ["0124".b, "abcd".b]
+ assert_equal(values,
+ ArrowFormat::FixedSizeBinaryArray.new(4, values).to_a)
+ end
+
+ def test_mixed
+ values = ["0124".b, nil, "abcd".b]
+ assert_equal(values,
+ ArrowFormat::FixedSizeBinaryArray.new(4, values).to_a)
+ end
+
+ def test_type
+ type = ArrowFormat::FixedSizeBinaryType.new(4)
+ values = ["0124".b, nil, "abcd".b]
+ assert_equal(values,
+ ArrowFormat::FixedSizeBinaryArray.new(type, values).to_a)
+ end
+
+ def test_too_small_value_size
+ error = ArgumentError.new("value size must be 4: \"012\"")
+ assert_raise(error) do
+ ArrowFormat::FixedSizeBinaryArray.new(4, ["012".b])
+ end
+ end
+
+ def test_too_large_value_size
+ error = ArgumentError.new("value size must be 4: \"01245\"")
+ assert_raise(error) do
+ ArrowFormat::FixedSizeBinaryArray.new(4, ["01245".b])
+ end
+ end
+ end
+
+ sub_test_case("#==") do
+ def test_no_slice
+ values = ["0124".b, nil, "abcd".b]
+ array1 = ArrowFormat::FixedSizeBinaryArray.new(4, values)
+ array2 = ArrowFormat::FixedSizeBinaryArray.new(4, values)
+ assert_equal(array1, array2)
+ end
+
+ def test_sliced
+ pad = "0000".b
+ values = ["0124".b, nil, "abcd".b]
+ array1 = ArrowFormat::FixedSizeBinaryArray.new(4, values)
+ array2 = ArrowFormat::FixedSizeBinaryArray.new(4, [pad, *values, pad])
+ assert_equal(array1, array2.slice(1, 3))
+ end
+
+ def test_sliced_different_content
+ pad = "0000".b
+ values = ["0124".b, nil, "abcd".b]
+ array1 = ArrowFormat::FixedSizeBinaryArray.new(4, values)
+ array2 = ArrowFormat::FixedSizeBinaryArray.new(4,
+ [pad, pad, *values, pad])
+ assert_not_equal(array1, array2.slice(1, 3))
+ end
+ end
+end