This is an automated email from the ASF dual-hosted git repository. shiro pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push: new 8704f8b ARROW-4183: [Ruby] Add Arrow::Struct as an element of Arrow::StructArray 8704f8b is described below commit 8704f8bd98f1edcf1f9ecc51d6fb3b4b5b4ecb88 Author: Kouhei Sutou <k...@clear-code.com> AuthorDate: Tue Jan 8 22:32:13 2019 +0900 ARROW-4183: [Ruby] Add Arrow::Struct as an element of Arrow::StructArray Returning Arrow::Array by Arrow::StructArray#[] is deprecated. It'll return Arrow::Struct in the next release. It's for consistency. All Arrow::Array#[] implementations should return an element. Author: Kouhei Sutou <k...@clear-code.com> Closes #3338 from kou/ruby-struct and squashes the following commits: a0561954 <Kouhei Sutou> Add Arrow::Struct as an element of Arrow::StructArray --- ruby/red-arrow/lib/arrow/struct-array-builder.rb | 9 ++- ruby/red-arrow/lib/arrow/struct-array.rb | 34 ++++++++++ ruby/red-arrow/lib/arrow/struct.rb | 68 ++++++++++++++++++++ ruby/red-arrow/test/test-struct-array-builder.rb | 47 +++++++++----- ruby/red-arrow/test/test-struct-array.rb | 58 ++++++++++++----- ruby/red-arrow/test/test-struct.rb | 81 ++++++++++++++++++++++++ 6 files changed, 263 insertions(+), 34 deletions(-) diff --git a/ruby/red-arrow/lib/arrow/struct-array-builder.rb b/ruby/red-arrow/lib/arrow/struct-array-builder.rb index 883ce84..52f75aa 100644 --- a/ruby/red-arrow/lib/arrow/struct-array-builder.rb +++ b/ruby/red-arrow/lib/arrow/struct-array-builder.rb @@ -73,13 +73,20 @@ module Arrow value.each_with_index do |sub_value, i| self[i].append_value(sub_value) end + when Arrow::Struct + append_value_raw + value.values.each_with_index do |sub_value, i| + self[i].append_value(sub_value) + end when Hash append_value_raw value.each do |name, sub_value| self[name].append_value(sub_value) end else - message = "struct value must be nil, Array or Hash: #{value.inspect}" + message = + "struct value must be nil, Array, " + + "Arrow::Struct or Hash: #{value.inspect}" raise ArgumentError, message end else diff --git a/ruby/red-arrow/lib/arrow/struct-array.rb b/ruby/red-arrow/lib/arrow/struct-array.rb index 4f9834c..e55a507 100644 --- a/ruby/red-arrow/lib/arrow/struct-array.rb +++ b/ruby/red-arrow/lib/arrow/struct-array.rb @@ -15,10 +15,44 @@ # specific language governing permissions and limitations # under the License. +require "arrow/struct" + module Arrow class StructArray def [](i) + warn("Use #{self.class}\#find_field instead. " + + "This will returns Arrow::Struct instead of Arrow::Array " + + "since 0.13.0.") get_field(i) end + + def get_value(i) + Struct.new(self, i) + end + + def find_field(index_or_name) + case index_or_name + when String, Symbol + name = index_or_name + (@name_to_field ||= build_name_to_field)[name.to_s] + else + index = index_or_name + cached_fields[index] + end + end + + private + def cached_fields + @fields ||= fields + end + + def build_name_to_field + name_to_field = {} + field_arrays = cached_fields + value_data_type.fields.each_with_index do |field, i| + name_to_field[field.name] = field_arrays[i] + end + name_to_field + end end end diff --git a/ruby/red-arrow/lib/arrow/struct.rb b/ruby/red-arrow/lib/arrow/struct.rb new file mode 100644 index 0000000..4ae12b8 --- /dev/null +++ b/ruby/red-arrow/lib/arrow/struct.rb @@ -0,0 +1,68 @@ +# 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. + +module Arrow + class Struct + attr_accessor :index + def initialize(array, index) + @array = array + @index = index + end + + def [](field_name_or_field_index) + field = @array.find_field(field_name_or_field_index) + return nil if field.nil? + field[@index] + end + + def fields + @array.value_data_type.fields + end + + def values + @array.fields.collect do |field| + field[@index] + end + end + + def to_a + values + end + + def to_h + attributes = {} + field_arrays = @array.fields + fields.each_with_index do |field, i| + attributes[field.name] = field_arrays[i][@index] + end + attributes + end + + def respond_to_missing?(name, include_private) + return true if @array.find_field(name) + super + end + + def method_missing(name, *args, &block) + if args.empty? + field = @array.find_field(name) + return field[@index] if field + end + super + end + end +end diff --git a/ruby/red-arrow/test/test-struct-array-builder.rb b/ruby/red-arrow/test/test-struct-array-builder.rb index 205564c..42e1ded 100644 --- a/ruby/red-arrow/test/test-struct-array-builder.rb +++ b/ruby/red-arrow/test/test-struct-array-builder.rb @@ -31,8 +31,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [nil], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -44,8 +44,23 @@ class StructArrayBuilderTest < Test::Unit::TestCase [1], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, + ]) + end + + test("Arrow::Struct") do + source_array = Arrow::StructArray.new(@data_type, [[true, 1]]) + struct = source_array.get_value(0) + @builder.append_value(struct) + array = @builder.finish + assert_equal([ + [true], + [1], + ], + [ + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -57,8 +72,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [1], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end end @@ -72,8 +87,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [nil], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -85,8 +100,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [1], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -98,8 +113,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [1], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -115,8 +130,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [nil, 1, 2], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end @@ -137,8 +152,8 @@ class StructArrayBuilderTest < Test::Unit::TestCase [1, nil, 3], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end end diff --git a/ruby/red-arrow/test/test-struct-array.rb b/ruby/red-arrow/test/test-struct-array.rb index 986b0a9..5a00434 100644 --- a/ruby/red-arrow/test/test-struct-array.rb +++ b/ruby/red-arrow/test/test-struct-array.rb @@ -31,27 +31,51 @@ class StructArrayTest < Test::Unit::TestCase [1, nil, 2], ], [ - array[0].to_a, - array[1].to_a, + array.find_field(0).to_a, + array.find_field(1).to_a, ]) end end - test("#[]") do - type = Arrow::StructDataType.new([ - Arrow::Field.new("field1", :boolean), - Arrow::Field.new("field2", :uint64), - ]) - builder = Arrow::StructArrayBuilder.new(type) - builder.append - builder.get_field_builder(0).append(true) - builder.get_field_builder(1).append(1) - builder.append - builder.get_field_builder(0).append(false) - builder.get_field_builder(1).append(2) - array = builder.finish + sub_test_case("instance methods") do + def setup + @data_type = Arrow::StructDataType.new(visible: {type: :boolean}, + count: {type: :uint64}) + @values = [ + [true, 1], + [false, 2], + ] + @array = Arrow::StructArray.new(@data_type, @values) + end - assert_equal([[true, false], [1, 2]], - [array[0].to_a, array[1].to_a]) + test("#[]") do + notify("TODO: Returns Arrow::Struct instead.") + assert_equal([[true, false], [1, 2]], + [@array[0].to_a, @array[1].to_a]) + end + + sub_test_case("#find_field") do + test("Integer") do + assert_equal([ + [true, false], + [1, 2], + ], + [ + @array.find_field(0).to_a, + @array.find_field(1).to_a, + ]) + end + + test("String, Symbol") do + assert_equal([ + [true, false], + [1, 2], + ], + [ + @array.find_field("visible").to_a, + @array.find_field(:count).to_a, + ]) + end + end end end diff --git a/ruby/red-arrow/test/test-struct.rb b/ruby/red-arrow/test/test-struct.rb new file mode 100644 index 0000000..412549c --- /dev/null +++ b/ruby/red-arrow/test/test-struct.rb @@ -0,0 +1,81 @@ +# 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 StructTest < Test::Unit::TestCase + def setup + @data_type = Arrow::StructDataType.new(visible: {type: :boolean}, + count: {type: :uint64}) + @values = [ + [true, 1], + [false, 2], + ] + @array = Arrow::StructArray.new(@data_type, @values) + @struct = @array.get_value(0) + end + + sub_test_case("#[]") do + test("Integer") do + assert_equal(true, @struct[0]) + end + + test("String") do + assert_equal(true, @struct["visible"]) + end + + test("Symbol") do + assert_equal(true, @struct[:visible]) + end + end + + test("#fields") do + assert_equal(@data_type.fields, + @struct.fields) + end + + test("#values") do + assert_equal([true, 1], + @struct.values) + end + + test("#to_a") do + assert_equal([true, 1], + @struct.to_a) + end + + test("#to_h") do + assert_equal({ + "visible" => true, + "count" => 1, + }, + @struct.to_h) + end + + test("#respond_to_missing?") do + assert_equal([ + true, + false, + ], + [ + @struct.respond_to?(:visible), + @struct.respond_to?(:nonexistent), + ]) + end + + test("#method_missing?") do + assert_equal(1, @struct.count) + end +end