You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by we...@apache.org on 2018/05/25 01:13:44 UTC

[arrow] branch master updated: ARROW-2537: [Ruby] Import

This is an automated email from the ASF dual-hosted git repository.

wesm 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 338e597  ARROW-2537: [Ruby] Import
338e597 is described below

commit 338e597dfba612ee26618d26302c6ead7bd5c12a
Author: Kouhei Sutou <ko...@clear-code.com>
AuthorDate: Thu May 24 21:13:38 2018 -0400

    ARROW-2537: [Ruby] Import
    
    Imported from:
    
    * https://github.com/red-data-tools/red-arrow
    * https://github.com/red-data-tools/red-arrow-gpu
    
    Author: Kouhei Sutou <ko...@clear-code.com>
    
    Closes #1990 from kou/ruby-import and squashes the following commits:
    
    cb41c7a8 <Kouhei Sutou>  Import
---
 .travis.yml                                        |  16 +-
 ci/detect-changes.py                               |   7 +-
 ci/travis_before_script_ruby.sh                    |  31 ++
 ci/travis_env_common.sh                            |   1 +
 ci/travis_script_ruby.sh                           |  53 ++
 ruby/README.md                                     |  26 +
 ruby/red-arrow-gpu/.gitignore                      |  20 +
 ruby/red-arrow-gpu/Gemfile                         |  22 +
 ruby/red-arrow-gpu/LICENSE.txt                     | 585 +++++++++++++++++++++
 ruby/red-arrow-gpu/README.md                       |  60 +++
 ruby/red-arrow-gpu/Rakefile                        |  41 ++
 ruby/red-arrow-gpu/dependency-check/Rakefile       |  43 ++
 ruby/red-arrow-gpu/lib/arrow-gpu.rb                |  29 +
 .../lib/arrow-gpu/cuda-device-manager.rb           |  25 +
 ruby/red-arrow-gpu/lib/arrow-gpu/loader.rb         |  35 ++
 ruby/red-arrow-gpu/red-arrow-gpu.gemspec           |  50 ++
 ruby/red-arrow-gpu/test/helper.rb                  |  22 +
 ruby/red-arrow-gpu/test/run-test.rb                |  37 ++
 ruby/red-arrow-gpu/test/test-cuda.rb               |  38 ++
 ruby/red-arrow-gpu/version.rb                      |  71 +++
 ruby/red-arrow/.gitignore                          |  20 +
 ruby/red-arrow/Gemfile                             |  22 +
 ruby/red-arrow/LICENSE.txt                         | 585 +++++++++++++++++++++
 ruby/red-arrow/README.md                           |  52 ++
 ruby/red-arrow/Rakefile                            |  41 ++
 ruby/red-arrow/dependency-check/Rakefile           |  43 ++
 ruby/red-arrow/doc/text/development.md             |  34 ++
 ruby/red-arrow/example/read-file.rb                |  36 ++
 ruby/red-arrow/example/read-stream.rb              |  36 ++
 ruby/red-arrow/example/write-file.rb               |  63 +++
 ruby/red-arrow/example/write-stream.rb             |  63 +++
 ruby/red-arrow/image/red-arrow.png                 | Bin 0 -> 7165 bytes
 ruby/red-arrow/lib/arrow.rb                        |  29 +
 ruby/red-arrow/lib/arrow/array-builder.rb          | 124 +++++
 ruby/red-arrow/lib/arrow/array.rb                  |  63 +++
 ruby/red-arrow/lib/arrow/block-closable.rb         |  31 ++
 ruby/red-arrow/lib/arrow/chunked-array.rb          |  84 +++
 ruby/red-arrow/lib/arrow/column.rb                 |  50 ++
 ruby/red-arrow/lib/arrow/csv-loader.rb             | 250 +++++++++
 ruby/red-arrow/lib/arrow/csv-reader.rb             |  54 ++
 ruby/red-arrow/lib/arrow/date32-array-builder.rb   |  32 ++
 ruby/red-arrow/lib/arrow/date32-array.rb           |  30 ++
 ruby/red-arrow/lib/arrow/date64-array-builder.rb   |  33 ++
 ruby/red-arrow/lib/arrow/date64-array.rb           |  29 +
 ruby/red-arrow/lib/arrow/field.rb                  |  34 ++
 ruby/red-arrow/lib/arrow/group.rb                  | 175 ++++++
 ruby/red-arrow/lib/arrow/loader.rb                 |  93 ++++
 .../lib/arrow/record-batch-file-reader.rb          |  28 +
 .../lib/arrow/record-batch-stream-reader.rb        |  30 ++
 ruby/red-arrow/lib/arrow/record-batch.rb           |  45 ++
 ruby/red-arrow/lib/arrow/record-containable.rb     |  73 +++
 ruby/red-arrow/lib/arrow/record.rb                 |  57 ++
 ruby/red-arrow/lib/arrow/rolling-window.rb         |  48 ++
 ruby/red-arrow/lib/arrow/slicer.rb                 | 454 ++++++++++++++++
 ruby/red-arrow/lib/arrow/table-formatter.rb        |  66 +++
 ruby/red-arrow/lib/arrow/table-list-formatter.rb   |  39 ++
 ruby/red-arrow/lib/arrow/table-loader.rb           | 120 +++++
 ruby/red-arrow/lib/arrow/table-saver.rb            |  96 ++++
 ruby/red-arrow/lib/arrow/table-table-formatter.rb  |  73 +++
 ruby/red-arrow/lib/arrow/table.rb                  | 381 ++++++++++++++
 ruby/red-arrow/lib/arrow/tensor.rb                 |  24 +
 .../red-arrow/lib/arrow/timestamp-array-builder.rb |  46 ++
 ruby/red-arrow/lib/arrow/timestamp-array.rb        |  54 ++
 ruby/red-arrow/red-arrow.gemspec                   |  54 ++
 ruby/red-arrow/test/fixture/float-integer.csv      |  20 +
 ruby/red-arrow/test/fixture/integer-float.csv      |  20 +
 .../test/fixture/null-with-double-quote.csv        |  20 +
 .../test/fixture/null-without-double-quote.csv     |  20 +
 ruby/red-arrow/test/fixture/with-header-float.csv  |  20 +
 ruby/red-arrow/test/fixture/with-header.csv        |  20 +
 .../test/fixture/without-header-float.csv          |  19 +
 ruby/red-arrow/test/fixture/without-header.csv     |  19 +
 ruby/red-arrow/test/helper.rb                      |  27 +
 ruby/red-arrow/test/helper/fixture.rb              |  28 +
 ruby/red-arrow/test/run-test.rb                    |  35 ++
 ruby/red-arrow/test/test-array-builder.rb          | 112 ++++
 ruby/red-arrow/test/test-array.rb                  |  38 ++
 ruby/red-arrow/test/test-chunked-array.rb          |  65 +++
 ruby/red-arrow/test/test-column.rb                 |  43 ++
 ruby/red-arrow/test/test-csv-loader.rb             | 118 +++++
 ruby/red-arrow/test/test-csv-reader.rb             |  34 ++
 ruby/red-arrow/test/test-date32-array.rb           |  24 +
 ruby/red-arrow/test/test-date64-array.rb           |  25 +
 ruby/red-arrow/test/test-group.rb                  | 156 ++++++
 .../test/test-record-batch-file-reader.rb          | 115 ++++
 ruby/red-arrow/test/test-record-batch.rb           |  57 ++
 ruby/red-arrow/test/test-rolling-window.rb         |  33 ++
 ruby/red-arrow/test/test-slicer.rb                 | 446 ++++++++++++++++
 ruby/red-arrow/test/test-table.rb                  | 464 ++++++++++++++++
 ruby/red-arrow/test/test-timestamp-array.rb        |  26 +
 ruby/red-arrow/version.rb                          |  71 +++
 91 files changed, 7073 insertions(+), 8 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 34ab5c1..7918eb8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -151,7 +151,7 @@ matrix:
     - $TRAVIS_BUILD_DIR/ci/travis_before_script_js.sh
     script:
     - $TRAVIS_BUILD_DIR/ci/travis_script_js.sh
-  # C++ & glib w/ gcc 4.9
+  # C++ & GLib & Ruby w/ gcc 4.9
   - compiler: gcc
     language: cpp
     os: linux
@@ -160,13 +160,15 @@ matrix:
     - CC="gcc-4.9"
     - CXX="g++-4.9"
     before_script:
-    - if [ $ARROW_CI_C_GLIB_AFFECTED != "1" ]; then exit; fi
+    - if [ $ARROW_CI_RUBY_AFFECTED != "1" ]; then exit; fi
     - $TRAVIS_BUILD_DIR/ci/travis_install_linux.sh
     - $TRAVIS_BUILD_DIR/ci/travis_before_script_cpp.sh --only-library
     - $TRAVIS_BUILD_DIR/ci/travis_before_script_c_glib.sh
+    - $TRAVIS_BUILD_DIR/ci/travis_before_script_ruby.sh
     script:
-    - $TRAVIS_BUILD_DIR/ci/travis_script_c_glib.sh
-  # [OS X] C++ & glib w/ XCode 8.3 & homebrew
+    - if [ $ARROW_CI_C_GLIB_AFFECTED = "1" ]; then $TRAVIS_BUILD_DIR/ci/travis_script_c_glib.sh; fi
+    - $TRAVIS_BUILD_DIR/ci/travis_script_ruby.sh
+  # [OS X] C++ & GLib & Ruby w/ XCode 8.3 & homebrew
   - compiler: clang
     osx_image: xcode8.3
     os: osx
@@ -174,12 +176,14 @@ matrix:
     addons:
     rvm: 2.2
     before_script:
-    - if [ $ARROW_CI_C_GLIB_AFFECTED != "1" ]; then exit; fi
+    - if [ $ARROW_CI_RUBY_AFFECTED != "1" ]; then exit; fi
     - $TRAVIS_BUILD_DIR/ci/travis_install_osx.sh
     - $TRAVIS_BUILD_DIR/ci/travis_before_script_cpp.sh --only-library --homebrew
     - $TRAVIS_BUILD_DIR/ci/travis_before_script_c_glib.sh
+    - $TRAVIS_BUILD_DIR/ci/travis_before_script_ruby.sh
     script:
-    - $TRAVIS_BUILD_DIR/ci/travis_script_c_glib.sh
+    - if [ $ARROW_CI_C_GLIB_AFFECTED = "1" ]; then $TRAVIS_BUILD_DIR/ci/travis_script_c_glib.sh; fi
+    - $TRAVIS_BUILD_DIR/ci/travis_script_ruby.sh
   # Rust
   - language: rust
     cache: cargo
diff --git a/ci/detect-changes.py b/ci/detect-changes.py
index fce2ba5..b2b8720 100644
--- a/ci/detect-changes.py
+++ b/ci/detect-changes.py
@@ -26,7 +26,7 @@ import subprocess
 
 perr = functools.partial(print, file=sys.stderr)
 
-LANGUAGE_TOPICS = ['c_glib', 'cpp', 'java', 'js', 'python', 'rust']
+LANGUAGE_TOPICS = ['c_glib', 'cpp', 'java', 'js', 'python', 'ruby', 'rust']
 
 ALL_TOPICS = LANGUAGE_TOPICS + ['integration', 'site']
 
@@ -141,7 +141,10 @@ def get_affected_topics(affected_files):
         elif p in ('java', 'js'):
             affected[p] = True
             affected['integration'] = True
-        elif p in ('c_glib', 'integration', 'python', 'site', 'rust'):
+        elif p in ('c_glib'):
+            affected[p] = True
+            affected['ruby'] = True
+        elif p in ('integration', 'python', 'site', 'ruby', 'rust'):
             affected[p] = True
 
     return affected
diff --git a/ci/travis_before_script_ruby.sh b/ci/travis_before_script_ruby.sh
new file mode 100755
index 0000000..c701687
--- /dev/null
+++ b/ci/travis_before_script_ruby.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# 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.
+
+set -e
+
+source $TRAVIS_BUILD_DIR/ci/travis_env_common.sh
+
+pushd $ARROW_RUBY_DIR/red-arrow
+bundle install
+popd
+
+# TODO: GPU required
+# pushd $ARROW_RUBY_DIR/red-arrow-gpu
+# bundle install
+# popd
diff --git a/ci/travis_env_common.sh b/ci/travis_env_common.sh
index 42a3bbc..8704bd4 100755
--- a/ci/travis_env_common.sh
+++ b/ci/travis_env_common.sh
@@ -29,6 +29,7 @@ export ARROW_C_GLIB_DIR=$TRAVIS_BUILD_DIR/c_glib
 export ARROW_JAVA_DIR=${TRAVIS_BUILD_DIR}/java
 export ARROW_JS_DIR=${TRAVIS_BUILD_DIR}/js
 export ARROW_INTEGRATION_DIR=$TRAVIS_BUILD_DIR/integration
+export ARROW_RUBY_DIR=$TRAVIS_BUILD_DIR/ruby
 export ARROW_RUST_DIR=${TRAVIS_BUILD_DIR}/rust
 
 if [ $ARROW_TRAVIS_COVERAGE == "1" ]; then
diff --git a/ci/travis_script_ruby.sh b/ci/travis_script_ruby.sh
new file mode 100755
index 0000000..57ca652
--- /dev/null
+++ b/ci/travis_script_ruby.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+# 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.
+
+set -e
+
+source $TRAVIS_BUILD_DIR/ci/travis_env_common.sh
+
+arrow_ruby_run_test()
+{
+  local arrow_c_glib_lib_dir=$1
+
+  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$arrow_c_glib_lib_dir
+  export GI_TYPELIB_PATH=$arrow_c_glib_lib_dir/girepository-1.0
+  test/run-test.rb
+}
+
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ARROW_CPP_INSTALL/lib
+export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$ARROW_CPP_INSTALL/lib/pkgconfig
+
+pushd $ARROW_RUBY_DIR/red-arrow
+(arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_AUTOTOOLS/lib)
+if [ -d $ARROW_C_GLIB_INSTALL_MESON/lib/$(arch)-linux-gnu ]; then
+  (arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_MESON/lib/$(arch)-linux-gnu)
+# else # TODO: Enable this
+#   (arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_MESON/lib)
+fi
+popd
+
+# TODO: GPU required
+# pushd $ARROW_RUBY_DIR/red-arrow-gpu
+# (arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_AUTOTOOLS/lib)
+# if [ -d $ARROW_C_GLIB_INSTALL_MESON/lib/$(arch)-linux-gnu ]; then
+#   (arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_MESON/lib/$(arch)-linux-gnu)
+# # else # TODO: Enable this
+# #   (arrow_ruby_run_test $ARROW_C_GLIB_INSTALL_MESON/lib)
+# fi
+# popd
diff --git a/ruby/README.md b/ruby/README.md
new file mode 100644
index 0000000..aac714e
--- /dev/null
+++ b/ruby/README.md
@@ -0,0 +1,26 @@
+<!---
+  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.
+-->
+
+# Apache Arrow Ruby
+
+There are the official Ruby bindings for Apache Arrow.
+
+[Red Arrow](https://github.com/apache/arrow/tree/master/ruby/red-arrow) is the base Apache Arrow bindings.
+
+[Red Arrow GPU](https://github.com/apache/arrow/tree/master/ruby/red-arrow-gpu) is the Apache Arrow bindings of GPU part.
diff --git a/ruby/red-arrow-gpu/.gitignore b/ruby/red-arrow-gpu/.gitignore
new file mode 100644
index 0000000..161ac05
--- /dev/null
+++ b/ruby/red-arrow-gpu/.gitignore
@@ -0,0 +1,20 @@
+# 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.
+
+/lib/arrow-gpu/version.rb
+
+/pkg/
diff --git a/ruby/red-arrow-gpu/Gemfile b/ruby/red-arrow-gpu/Gemfile
new file mode 100644
index 0000000..3907918
--- /dev/null
+++ b/ruby/red-arrow-gpu/Gemfile
@@ -0,0 +1,22 @@
+# -*- ruby -*-
+#
+# 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.
+
+source "https://rubygems.org/"
+
+gemspec
diff --git a/ruby/red-arrow-gpu/LICENSE.txt b/ruby/red-arrow-gpu/LICENSE.txt
new file mode 100644
index 0000000..30966d3
--- /dev/null
+++ b/ruby/red-arrow-gpu/LICENSE.txt
@@ -0,0 +1,585 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
+--------------------------------------------------------------------------------
+
+src/plasma/fling.cc and src/plasma/fling.h: Apache 2.0
+
+Copyright 2013 Sharvil Nanavati
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/ae: Modified / 3-Clause BSD
+
+Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+ * Neither the name of Redis nor the names of its contributors may be used
+   to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/dlmalloc.c: CC0
+
+This is a version (aka dlmalloc) of malloc/free/realloc written by
+Doug Lea and released to the public domain, as explained at
+http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
+comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/xxhash: BSD 2-Clause License
+
+xxHash - Fast Hash algorithm
+Copyright (C) 2012-2016, Yann Collet
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- xxHash homepage: http://www.xxhash.com
+- xxHash source repository : https://github.com/Cyan4973/xxHash
+
+--------------------------------------------------------------------------------
+
+src/arrow/util (some portions): Apache 2.0, and 3-clause BSD
+
+Some portions of this module are derived from code in the Chromium project,
+copyright (c) Google inc and (c) The Chromium Authors and licensed under the
+Apache 2.0 License or the under the 3-clause BSD license:
+
+  Copyright (c) 2013 The Chromium Authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+     * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+     * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from Daniel Lemire's FrameOfReference project.
+
+https://github.com/lemire/FrameOfReference/blob/6ccaf9e97160f9a3b299e23a8ef739e711ef0c71/src/bpacking.cpp
+
+Copyright: 2013 Daniel Lemire
+Home page: http://lemire.me/en/
+Project page: https://github.com/lemire/FrameOfReference
+License: Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
+
+--------------------------------------------------------------------------------
+
+This project includes code from the TensorFlow project
+
+Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the NumPy project.
+
+https://github.com/numpy/numpy/blob/e1f191c46f2eebd6cb892a4bfe14d9dd43a06c4e/numpy/core/src/multiarray/multiarraymodule.c#L2910
+
+https://github.com/numpy/numpy/blob/68fd82271b9ea5a9e50d4e761061dfcca851382a/numpy/core/src/multiarray/datetime.c
+
+Copyright (c) 2005-2017, NumPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials provided
+       with the distribution.
+
+    * Neither the name of the NumPy Developers nor the names of any
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the Boost project
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the mapbox/variant project, BSD 3-clause
+license
+
+Copyright (c) MapBox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+- Neither the name "MapBox" nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the Boost project
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the mapbox/variant project, BSD 3-clause
+license
+
+Copyright (c) MapBox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+- Neither the name "MapBox" nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the FlatBuffers project
+
+Copyright 2014 Google Inc.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the tslib project
+
+Copyright 2015 Microsoft Corporation. All rights reserved.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the jemalloc project
+
+https://github.com/jemalloc/jemalloc
+
+Copyright (C) 2002-2017 Jason Evans <ja...@canonware.com>.
+All rights reserved.
+Copyright (C) 2007-2012 Mozilla Foundation.  All rights reserved.
+Copyright (C) 2009-2017 Facebook, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice(s),
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice(s),
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------------
diff --git a/ruby/red-arrow-gpu/README.md b/ruby/red-arrow-gpu/README.md
new file mode 100644
index 0000000..236cf78
--- /dev/null
+++ b/ruby/red-arrow-gpu/README.md
@@ -0,0 +1,60 @@
+<!---
+  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.
+-->
+
+# Red Arrow GPU - Apache Arrow GPU Ruby
+
+Red Arrow GPU is the Ruby bindings of Apache Arrow GPU. Red Arrow GPU is based on GObject Introspection.
+
+[Apache Arrow GPU](https://arrow.apache.org/) is an in-memory columnar data store on GPU.
+
+[GObject Introspection](https://wiki.gnome.org/action/show/Projects/GObjectIntrospection) is a middleware for language bindings of C library. GObject Introspection can generate language bindings automatically at runtime.
+
+Red Arrow GPU uses [Apache Arrow GPU GLib](https://github.com/apache/arrow/tree/master/c_glib) and [gobject-introspection gem](https://rubygems.org/gems/gobject-introspection) to generate Ruby bindings of Apache Arrow GPU.
+
+Apache Arrow GPU GLib is a C wrapper for [Apache Arrow GPU C++](https://github.com/apache/arrow/tree/master/cpp). GObject Introspection can't use Apache Arrow GPU C++ directly. Apache Arrow GPU GLib is a bridge between Apache Arrow GPU C++ and GObject Introspection.
+
+gobject-introspection gem is a Ruby bindings of GObject Introspection. Red Arrow GPU uses GObject Introspection via gobject-introspection gem.
+
+## Install
+
+Install Apache Arrow GPU GLib before install Red Arrow GPU. Use [packages.red-data-tools.org](https://github.com/red-data-tools/packages.red-data-tools.org) for installing Apache Arrow GPU GLib.
+
+Install Red Arrow GPU after you install Apache Arrow GPU GLib:
+
+```text
+% gem install red-arrow-gpu
+```
+
+## Usage
+
+```ruby
+require "arrow-gpu"
+
+manager = ArrowGPU::CUDADeviceManager.new
+if manager.n_devices.zero?
+  raise "No GPU is found"
+end
+
+context = manager[0]
+buffer = ArrowGPU::CUDABuffer.new(context, 128)
+ArrowGPU::CUDABufferOutputStream.open(buffer) do |stream|
+  stream.write("Hello World")
+end
+puts buffer.copy_to_host(0, 11) # => "Hello World"
+```
diff --git a/ruby/red-arrow-gpu/Rakefile b/ruby/red-arrow-gpu/Rakefile
new file mode 100644
index 0000000..0c7321c
--- /dev/null
+++ b/ruby/red-arrow-gpu/Rakefile
@@ -0,0 +1,41 @@
+# -*- ruby -*-
+#
+# 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.
+
+require "rubygems"
+require "bundler/gem_helper"
+
+base_dir = File.join(File.dirname(__FILE__))
+
+helper = Bundler::GemHelper.new(base_dir)
+def helper.version_tag
+  version
+end
+
+helper.install
+spec = helper.gemspec
+
+desc "Run tests"
+task :test do
+  cd("dependency-check") do
+    ruby("-S", "rake")
+  end
+  ruby("test/run-test.rb")
+end
+
+task default: :test
diff --git a/ruby/red-arrow-gpu/dependency-check/Rakefile b/ruby/red-arrow-gpu/dependency-check/Rakefile
new file mode 100644
index 0000000..0c22848
--- /dev/null
+++ b/ruby/red-arrow-gpu/dependency-check/Rakefile
@@ -0,0 +1,43 @@
+# -*- ruby -*-
+#
+# 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.
+
+require "pkg-config"
+require "native-package-installer"
+
+case RUBY_PLATFORM
+when /mingw|mswin/
+  task :default => "nothing"
+else
+  task :default => "dependency:check"
+end
+
+task :nothing do
+end
+
+namespace :dependency do
+  desc "Check dependency"
+  task :check do
+    unless PKGConfig.check_version?("arrow-gpu-glib")
+      unless NativePackageInstaller.install(:debian => "libarrow-gpu-glib-dev",
+                                            :redhat => "arrow-gpu-glib-devel")
+        exit(false)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow-gpu/lib/arrow-gpu.rb b/ruby/red-arrow-gpu/lib/arrow-gpu.rb
new file mode 100644
index 0000000..10fdcc3
--- /dev/null
+++ b/ruby/red-arrow-gpu/lib/arrow-gpu.rb
@@ -0,0 +1,29 @@
+# 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.
+
+require "arrow"
+
+require "arrow-gpu/version"
+
+require "arrow-gpu/loader"
+
+module ArrowGPU
+  class Error < StandardError
+  end
+
+  Loader.load
+end
diff --git a/ruby/red-arrow-gpu/lib/arrow-gpu/cuda-device-manager.rb b/ruby/red-arrow-gpu/lib/arrow-gpu/cuda-device-manager.rb
new file mode 100644
index 0000000..163128b
--- /dev/null
+++ b/ruby/red-arrow-gpu/lib/arrow-gpu/cuda-device-manager.rb
@@ -0,0 +1,25 @@
+# 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 ArrowGPU
+  class CUDADeviceManager
+    # Experimental.
+    #
+    # Can we think device manager is a container of contexts?
+    alias_method :[], :get_context
+  end
+end
diff --git a/ruby/red-arrow-gpu/lib/arrow-gpu/loader.rb b/ruby/red-arrow-gpu/lib/arrow-gpu/loader.rb
new file mode 100644
index 0000000..b9dc57c
--- /dev/null
+++ b/ruby/red-arrow-gpu/lib/arrow-gpu/loader.rb
@@ -0,0 +1,35 @@
+# 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 ArrowGPU
+  class Loader < GObjectIntrospection::Loader
+    class << self
+      def load
+        super("ArrowGPU", ArrowGPU)
+      end
+    end
+
+    private
+    def post_load(repository, namespace)
+      require_libraries
+    end
+
+    def require_libraries
+      require "arrow-gpu/cuda-device-manager"
+    end
+  end
+end
diff --git a/ruby/red-arrow-gpu/red-arrow-gpu.gemspec b/ruby/red-arrow-gpu/red-arrow-gpu.gemspec
new file mode 100644
index 0000000..d50641b
--- /dev/null
+++ b/ruby/red-arrow-gpu/red-arrow-gpu.gemspec
@@ -0,0 +1,50 @@
+# -*- ruby -*-
+#
+# 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.
+
+require_relative "version"
+
+Gem::Specification.new do |spec|
+  spec.name = "red-arrow-gpu"
+  version_components = [
+    ArrowGPU::Version::MAJOR.to_s,
+    ArrowGPU::Version::MINOR.to_s,
+    ArrowGPU::Version::MICRO.to_s,
+    # "beta1",
+  ]
+  spec.version = version_components.join(".")
+  spec.homepage = "https://arrow.apache.org/"
+  spec.authors = ["Apache Arrow Developers"]
+  spec.email = ["dev@arrow.apache.org"]
+
+  spec.summary = "Red Arrow GPU is the Ruby bindings of Apache Arrow GPU"
+  spec.description =
+    "Apache Arrow GPU is a common in-memory columnar data store on GPU. " +
+    "It's useful to share and process large data."
+  spec.license = "Apache-2.0"
+  spec.files = ["README.md", "Rakefile", "Gemfile", "#{spec.name}.gemspec"]
+  spec.files += Dir.glob("lib/**/*.rb")
+  spec.test_files += Dir.glob("test/**/*")
+  spec.extensions = ["dependency-check/Rakefile"]
+
+  spec.add_runtime_dependency("red-arrow")
+
+  spec.add_development_dependency("bundler")
+  spec.add_development_dependency("rake")
+  spec.add_development_dependency("test-unit")
+end
diff --git a/ruby/red-arrow-gpu/test/helper.rb b/ruby/red-arrow-gpu/test/helper.rb
new file mode 100644
index 0000000..6bed605
--- /dev/null
+++ b/ruby/red-arrow-gpu/test/helper.rb
@@ -0,0 +1,22 @@
+# 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.
+
+require_relative "../version"
+
+require "arrow-gpu"
+
+require "test-unit"
diff --git a/ruby/red-arrow-gpu/test/run-test.rb b/ruby/red-arrow-gpu/test/run-test.rb
new file mode 100755
index 0000000..b826f3e
--- /dev/null
+++ b/ruby/red-arrow-gpu/test/run-test.rb
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+$VERBOSE = true
+
+require "pathname"
+
+base_dir = Pathname.new(__dir__).parent.expand_path
+arrow_base_dir = base_dir.parent + "red-arrow"
+
+lib_dir = base_dir + "lib"
+test_dir = base_dir + "test"
+
+arrow_lib_dir = arrow_base_dir + "lib"
+
+$LOAD_PATH.unshift(arrow_lib_dir.to_s)
+$LOAD_PATH.unshift(lib_dir.to_s)
+
+require_relative "helper"
+
+exit(Test::Unit::AutoRunner.run(true, test_dir.to_s))
diff --git a/ruby/red-arrow-gpu/test/test-cuda.rb b/ruby/red-arrow-gpu/test/test-cuda.rb
new file mode 100644
index 0000000..05fd6cc
--- /dev/null
+++ b/ruby/red-arrow-gpu/test/test-cuda.rb
@@ -0,0 +1,38 @@
+# 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 TestCUDA < Test::Unit::TestCase
+  def setup
+    @manager = ArrowGPU::CUDADeviceManager.new
+    omit("At least one GPU is required") if @manager.n_devices.zero?
+    @context = @manager[0]
+  end
+
+  sub_test_case("BufferOutputStream") do
+    def setup
+      super
+      @buffer = ArrowGPU::CUDABuffer.new(@context, 128)
+    end
+
+    def test_new
+      ArrowGPU::CUDABufferOutputStream.open(@buffer) do |stream|
+        stream.write("Hello World")
+      end
+      assert_equal("Hello World", @buffer.copy_to_host(0, 11).to_s)
+    end
+  end
+end
diff --git a/ruby/red-arrow-gpu/version.rb b/ruby/red-arrow-gpu/version.rb
new file mode 100644
index 0000000..fc0d37e
--- /dev/null
+++ b/ruby/red-arrow-gpu/version.rb
@@ -0,0 +1,71 @@
+# 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.
+
+require "pathname"
+
+version_rb_path = Pathname.new(__FILE__)
+base_dir = version_rb_path.dirname
+pom_xml_path = base_dir.join("..", "..", "java", "pom.xml")
+lib_version_rb_path = base_dir.join("lib", "arrow-gpu", "version.rb")
+
+need_update = false
+if not lib_version_rb_path.exist?
+  need_update = true
+elsif version_rb_path.mtime > lib_version_rb_path.mtime
+  need_update = true
+elsif pom_xml_path.exist? and pom_xml_path.mtime > lib_version_rb_path.mtime
+  need_update = true
+end
+
+if need_update
+  version = pom_xml_path.read.scan(/^  <version>(.+?)<\/version>/)[0][0]
+  major, minor, micro, tag = version.split(/[.-]/)
+  lib_version_rb_path.open("w") do |lib_version_rb|
+    lib_version_rb.puts(<<-RUBY)
+# 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 ArrowGPU
+  module Version
+    MAJOR = #{major}
+    MINOR = #{minor}
+    MICRO = #{micro}
+    TAG = #{tag ? tag.dump : nil}
+    STRING = #{version.dump}
+  end
+
+  VERSION = Version::STRING
+end
+    RUBY
+  end
+end
+
+require_relative "lib/arrow-gpu/version"
diff --git a/ruby/red-arrow/.gitignore b/ruby/red-arrow/.gitignore
new file mode 100644
index 0000000..9fcc9cd
--- /dev/null
+++ b/ruby/red-arrow/.gitignore
@@ -0,0 +1,20 @@
+# 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.
+
+/lib/arrow/version.rb
+
+/pkg/
diff --git a/ruby/red-arrow/Gemfile b/ruby/red-arrow/Gemfile
new file mode 100644
index 0000000..3907918
--- /dev/null
+++ b/ruby/red-arrow/Gemfile
@@ -0,0 +1,22 @@
+# -*- ruby -*-
+#
+# 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.
+
+source "https://rubygems.org/"
+
+gemspec
diff --git a/ruby/red-arrow/LICENSE.txt b/ruby/red-arrow/LICENSE.txt
new file mode 100644
index 0000000..30966d3
--- /dev/null
+++ b/ruby/red-arrow/LICENSE.txt
@@ -0,0 +1,585 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
+--------------------------------------------------------------------------------
+
+src/plasma/fling.cc and src/plasma/fling.h: Apache 2.0
+
+Copyright 2013 Sharvil Nanavati
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/ae: Modified / 3-Clause BSD
+
+Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+ * Neither the name of Redis nor the names of its contributors may be used
+   to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/dlmalloc.c: CC0
+
+This is a version (aka dlmalloc) of malloc/free/realloc written by
+Doug Lea and released to the public domain, as explained at
+http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
+comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+--------------------------------------------------------------------------------
+
+src/plasma/thirdparty/xxhash: BSD 2-Clause License
+
+xxHash - Fast Hash algorithm
+Copyright (C) 2012-2016, Yann Collet
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- xxHash homepage: http://www.xxhash.com
+- xxHash source repository : https://github.com/Cyan4973/xxHash
+
+--------------------------------------------------------------------------------
+
+src/arrow/util (some portions): Apache 2.0, and 3-clause BSD
+
+Some portions of this module are derived from code in the Chromium project,
+copyright (c) Google inc and (c) The Chromium Authors and licensed under the
+Apache 2.0 License or the under the 3-clause BSD license:
+
+  Copyright (c) 2013 The Chromium Authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+     * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+     * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from Daniel Lemire's FrameOfReference project.
+
+https://github.com/lemire/FrameOfReference/blob/6ccaf9e97160f9a3b299e23a8ef739e711ef0c71/src/bpacking.cpp
+
+Copyright: 2013 Daniel Lemire
+Home page: http://lemire.me/en/
+Project page: https://github.com/lemire/FrameOfReference
+License: Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
+
+--------------------------------------------------------------------------------
+
+This project includes code from the TensorFlow project
+
+Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the NumPy project.
+
+https://github.com/numpy/numpy/blob/e1f191c46f2eebd6cb892a4bfe14d9dd43a06c4e/numpy/core/src/multiarray/multiarraymodule.c#L2910
+
+https://github.com/numpy/numpy/blob/68fd82271b9ea5a9e50d4e761061dfcca851382a/numpy/core/src/multiarray/datetime.c
+
+Copyright (c) 2005-2017, NumPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials provided
+       with the distribution.
+
+    * Neither the name of the NumPy Developers nor the names of any
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the Boost project
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the mapbox/variant project, BSD 3-clause
+license
+
+Copyright (c) MapBox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+- Neither the name "MapBox" nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the Boost project
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the mapbox/variant project, BSD 3-clause
+license
+
+Copyright (c) MapBox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+- Neither the name "MapBox" nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the FlatBuffers project
+
+Copyright 2014 Google Inc.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the tslib project
+
+Copyright 2015 Microsoft Corporation. All rights reserved.
+
+Licensed 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.
+
+--------------------------------------------------------------------------------
+
+This project includes code from the jemalloc project
+
+https://github.com/jemalloc/jemalloc
+
+Copyright (C) 2002-2017 Jason Evans <ja...@canonware.com>.
+All rights reserved.
+Copyright (C) 2007-2012 Mozilla Foundation.  All rights reserved.
+Copyright (C) 2009-2017 Facebook, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice(s),
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice(s),
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------------
diff --git a/ruby/red-arrow/README.md b/ruby/red-arrow/README.md
new file mode 100644
index 0000000..9b47662
--- /dev/null
+++ b/ruby/red-arrow/README.md
@@ -0,0 +1,52 @@
+<!---
+  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.
+-->
+
+# Red Arrow - Apache Arrow Ruby
+
+Red Arrow is the Ruby bindings of Apache Arrow. Red Arrow is based on GObject Introspection.
+
+[Apache Arrow](https://arrow.apache.org/) is an in-memory columnar data store. It's used by many products for data analytics.
+
+[GObject Introspection](https://wiki.gnome.org/action/show/Projects/GObjectIntrospection) is a middleware for language bindings of C library. GObject Introspection can generate language bindings automatically at runtime.
+
+Red Arrow uses [Apache Arrow GLib](https://github.com/apache/arrow/tree/master/c_glib) and [gobject-introspection gem](https://rubygems.org/gems/gobject-introspection) to generate Ruby bindings of Apache Arrow.
+
+Apache Arrow GLib is a C wrapper for [Apache Arrow C++](https://github.com/apache/arrow/tree/master/cpp). GObject Introspection can't use Apache Arrow C++ directly. Apache Arrow GLib is a bridge between Apache Arrow C++ and GObject Introspection.
+
+gobject-introspection gem is a Ruby bindings of GObject Introspection. Red Arrow uses GObject Introspection via gobject-introspection gem.
+
+## Install
+
+Install Apache Arrow GLib before install Red Arrow. Use [packages.red-data-tools.org](https://github.com/red-data-tools/packages.red-data-tools.org) for installing Apache Arrow GLib.
+
+Install Red Arrow after you install Apache Arrow GLib:
+
+```text
+% gem install red-arrow
+```
+
+## Usage
+
+```ruby
+require "arrow"
+
+table = Arrow::Table.load("/dev/shm/data.arrow")
+# Process data in table
+table.save("/dev/shm/data-processed.arrow")
+```
diff --git a/ruby/red-arrow/Rakefile b/ruby/red-arrow/Rakefile
new file mode 100644
index 0000000..4380ba5
--- /dev/null
+++ b/ruby/red-arrow/Rakefile
@@ -0,0 +1,41 @@
+# -*- ruby -*-
+#
+# 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.
+
+require "rubygems"
+require "bundler/gem_helper"
+
+base_dir = File.join(__dir__)
+
+helper = Bundler::GemHelper.new(base_dir)
+def helper.version_tag
+  version
+end
+
+helper.install
+spec = helper.gemspec
+
+desc "Run tests"
+task :test do
+  cd("dependency-check") do
+    ruby("-S", "rake")
+  end
+  ruby("test/run-test.rb")
+end
+
+task default: :test
diff --git a/ruby/red-arrow/dependency-check/Rakefile b/ruby/red-arrow/dependency-check/Rakefile
new file mode 100644
index 0000000..e80e732
--- /dev/null
+++ b/ruby/red-arrow/dependency-check/Rakefile
@@ -0,0 +1,43 @@
+# -*- ruby -*-
+#
+# 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.
+
+require "pkg-config"
+require "native-package-installer"
+
+case RUBY_PLATFORM
+when /mingw|mswin/
+  task :default => "nothing"
+else
+  task :default => "dependency:check"
+end
+
+task :nothing do
+end
+
+namespace :dependency do
+  desc "Check dependency"
+  task :check do
+    unless PKGConfig.check_version?("arrow-glib", 0, 9, 0)
+      unless NativePackageInstaller.install(:debian => "libarrow-glib-dev",
+                                            :redhat => "arrow-glib-devel")
+        exit(false)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/doc/text/development.md b/ruby/red-arrow/doc/text/development.md
new file mode 100644
index 0000000..cc86de3
--- /dev/null
+++ b/ruby/red-arrow/doc/text/development.md
@@ -0,0 +1,34 @@
+<!---
+  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.
+-->
+
+# Development
+
+## Naming convention
+
+### Reader and Writer
+
+Reader and Writer require an opened IO stream.
+
+### Loader and Saver
+
+Loader and Saver require a path. They are convenient classes.
+
+Loader opens the path and reads data by Reader.
+
+Writer opens the path and writes data by Writer.
diff --git a/ruby/red-arrow/example/read-file.rb b/ruby/red-arrow/example/read-file.rb
new file mode 100755
index 0000000..9a99d33
--- /dev/null
+++ b/ruby/red-arrow/example/read-file.rb
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+require "arrow"
+
+Arrow::MemoryMappedInputStream.open("/tmp/file.arrow") do |input|
+  reader = Arrow::RecordBatchFileReader.new(input)
+  fields = reader.schema.fields
+  reader.each_with_index do |record_batch, i|
+    puts("=" * 40)
+    puts("record-batch[#{i}]:")
+    fields.each do |field|
+      field_name = field.name
+      values = record_batch.collect do |record|
+        record[field_name]
+      end
+      puts("  #{field_name}: #{values.inspect}")
+    end
+  end
+end
diff --git a/ruby/red-arrow/example/read-stream.rb b/ruby/red-arrow/example/read-stream.rb
new file mode 100755
index 0000000..c719712
--- /dev/null
+++ b/ruby/red-arrow/example/read-stream.rb
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+require "arrow"
+
+Arrow::MemoryMappedInputStream.open("/tmp/stream.arrow") do |input|
+  reader = Arrow::RecordBatchStreamReader.new(input)
+  fields = reader.schema.fields
+  reader.each_with_index do |record_batch, i|
+    puts("=" * 40)
+    puts("record-batch[#{i}]:")
+    fields.each do |field|
+      field_name = field.name
+      values = record_batch.collect do |record|
+        record[field_name]
+      end
+      puts("  #{field_name}: #{values.inspect}")
+    end
+  end
+end
diff --git a/ruby/red-arrow/example/write-file.rb b/ruby/red-arrow/example/write-file.rb
new file mode 100755
index 0000000..c55ab2e
--- /dev/null
+++ b/ruby/red-arrow/example/write-file.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+require "arrow"
+
+fields = [
+  Arrow::Field.new("uint8",  :uint8),
+  Arrow::Field.new("uint16", :uint16),
+  Arrow::Field.new("uint32", :uint32),
+  Arrow::Field.new("uint64", :uint64),
+  Arrow::Field.new("int8",   :int8),
+  Arrow::Field.new("int16",  :int16),
+  Arrow::Field.new("int32",  :int32),
+  Arrow::Field.new("int64",  :int64),
+  Arrow::Field.new("float",  :float),
+  Arrow::Field.new("double", :double),
+]
+schema = Arrow::Schema.new(fields)
+
+Arrow::FileOutputStream.open("/tmp/file.arrow", false) do |output|
+  Arrow::RecordBatchFileWriter.open(output, schema) do |writer|
+    uints = [1, 2, 4, 8]
+    ints = [1, -2, 4, -8]
+    floats = [1.1, -2.2, 4.4, -8.8]
+    columns = [
+      Arrow::UInt8Array.new(uints),
+      Arrow::UInt16Array.new(uints),
+      Arrow::UInt32Array.new(uints),
+      Arrow::UInt64Array.new(uints),
+      Arrow::Int8Array.new(ints),
+      Arrow::Int16Array.new(ints),
+      Arrow::Int32Array.new(ints),
+      Arrow::Int64Array.new(ints),
+      Arrow::FloatArray.new(floats),
+      Arrow::DoubleArray.new(floats),
+    ]
+
+    record_batch = Arrow::RecordBatch.new(schema, 4, columns)
+    writer.write_record_batch(record_batch)
+
+    sliced_columns = columns.collect do |column|
+      column.slice(1, 3)
+    end
+    record_batch = Arrow::RecordBatch.new(schema, 3, sliced_columns)
+    writer.write_record_batch(record_batch)
+  end
+end
diff --git a/ruby/red-arrow/example/write-stream.rb b/ruby/red-arrow/example/write-stream.rb
new file mode 100755
index 0000000..fde4862
--- /dev/null
+++ b/ruby/red-arrow/example/write-stream.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+require "arrow"
+
+fields = [
+  Arrow::Field.new("uint8",  :uint8),
+  Arrow::Field.new("uint16", :uint16),
+  Arrow::Field.new("uint32", :uint32),
+  Arrow::Field.new("uint64", :uint64),
+  Arrow::Field.new("int8",   :int8),
+  Arrow::Field.new("int16",  :int16),
+  Arrow::Field.new("int32",  :int32),
+  Arrow::Field.new("int64",  :int64),
+  Arrow::Field.new("float",  :float),
+  Arrow::Field.new("double", :double),
+]
+schema = Arrow::Schema.new(fields)
+
+Arrow::FileOutputStream.open("/tmp/stream.arrow", false) do |output|
+  Arrow::RecordBatchStreamWriter.open(output, schema) do |writer|
+    uints = [1, 2, 4, 8]
+    ints = [1, -2, 4, -8]
+    floats = [1.1, -2.2, 4.4, -8.8]
+    columns = [
+      Arrow::UInt8Array.new(uints),
+      Arrow::UInt16Array.new(uints),
+      Arrow::UInt32Array.new(uints),
+      Arrow::UInt64Array.new(uints),
+      Arrow::Int8Array.new(ints),
+      Arrow::Int16Array.new(ints),
+      Arrow::Int32Array.new(ints),
+      Arrow::Int64Array.new(ints),
+      Arrow::FloatArray.new(floats),
+      Arrow::DoubleArray.new(floats),
+    ]
+
+    record_batch = Arrow::RecordBatch.new(schema, 4, columns)
+    writer.write_record_batch(record_batch)
+
+    sliced_columns = columns.collect do |column|
+      column.slice(1, 3)
+    end
+    record_batch = Arrow::RecordBatch.new(schema, 3, sliced_columns)
+    writer.write_record_batch(record_batch)
+  end
+end
diff --git a/ruby/red-arrow/image/red-arrow.png b/ruby/red-arrow/image/red-arrow.png
new file mode 100644
index 0000000..6db9b4b
Binary files /dev/null and b/ruby/red-arrow/image/red-arrow.png differ
diff --git a/ruby/red-arrow/lib/arrow.rb b/ruby/red-arrow/lib/arrow.rb
new file mode 100644
index 0000000..95dabee
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow.rb
@@ -0,0 +1,29 @@
+# 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.
+
+require "gobject-introspection"
+
+require "arrow/version"
+
+require "arrow/loader"
+
+module Arrow
+  class Error < StandardError
+  end
+
+  Loader.load
+end
diff --git a/ruby/red-arrow/lib/arrow/array-builder.rb b/ruby/red-arrow/lib/arrow/array-builder.rb
new file mode 100644
index 0000000..8edb3c4
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/array-builder.rb
@@ -0,0 +1,124 @@
+# 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.
+
+require "date"
+
+module Arrow
+  class ArrayBuilder
+    class << self
+      def build(values)
+        if self != ArrayBuilder
+          builder = new
+          return builder.build(values)
+        end
+
+        builder_class = nil
+        values.each do |value|
+          case value
+          when nil
+            # Ignore
+          when true, false
+            return BooleanArray.new(values)
+          when String
+            return StringArray.new(values)
+          when Float
+            return DoubleArray.new(values)
+          when Integer
+            if value < 0
+              builder = IntArrayBuilder.new
+              return builder.build(values)
+            else
+              builder_class = UIntArrayBuilder
+            end
+          when Time
+            data_type = TimestampDataType.new(:nano)
+            builder = TimestampArrayBuilder.new(data_type)
+            return builder.build(values)
+          when DateTime
+            return Date64Array.new(values)
+          when Date
+            return Date32Array.new(values)
+          else
+            return StringArray.new(values)
+          end
+        end
+        if builder_class
+          builder_class.new.build(values)
+        else
+          Arrow::StringArray.new(values)
+        end
+      end
+    end
+
+    def build(values)
+      value_convertable = respond_to?(:convert_to_arrow_value, true)
+      start_index = 0
+      current_index = 0
+      status = :value
+
+      values.each do |value|
+        if value.nil?
+          if status == :value
+            if start_index != current_index
+              target_values = values[start_index...current_index]
+              if value_convertable
+                target_values = target_values.collect do |v|
+                  convert_to_arrow_value(v)
+                end
+              end
+              append_values(target_values, nil)
+              start_index = current_index
+            end
+            status = :null
+          end
+        else
+          if status == :null
+            append_nulls(current_index - start_index)
+            start_index = current_index
+            status = :value
+          end
+        end
+        current_index += 1
+      end
+      if start_index != current_index
+        if status == :value
+          if start_index == 0 and current_index == values.size
+            target_values = values
+          else
+            target_values = values[start_index...current_index]
+          end
+          if value_convertable
+            target_values = target_values.collect do |v|
+              convert_to_arrow_value(v)
+            end
+          end
+          append_values(target_values, nil)
+        else
+          append_nulls(current_index - start_index)
+        end
+      end
+
+      finish
+    end
+
+    def append_nulls(n)
+      n.times do
+        append_null
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/array.rb b/ruby/red-arrow/lib/arrow/array.rb
new file mode 100644
index 0000000..7a0d053
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/array.rb
@@ -0,0 +1,63 @@
+# 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 Array
+    include Enumerable
+
+    class << self
+      def new(values)
+        builder_class_name = "#{name}Builder"
+        if const_defined?(builder_class_name)
+          builder_class = const_get(builder_class_name)
+          builder_class.build(values)
+        else
+          super
+        end
+      end
+    end
+
+    def [](i)
+      i += length if i < 0
+      if null?(i)
+        nil
+      else
+        get_value(i)
+      end
+    end
+
+    def each
+      return to_enum(__method__) unless block_given?
+
+      length.times do |i|
+        yield(self[i])
+      end
+    end
+
+    def reverse_each
+      return to_enum(__method__) unless block_given?
+
+      (length - 1).downto(0) do |i|
+        yield(self[i])
+      end
+    end
+
+    def to_arrow
+      self
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/block-closable.rb b/ruby/red-arrow/lib/arrow/block-closable.rb
new file mode 100644
index 0000000..473ee14
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/block-closable.rb
@@ -0,0 +1,31 @@
+# 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
+  module BlockClosable
+    def open(*args, &block)
+      io = new(*args)
+      return io unless block
+
+      begin
+        yield(io)
+      ensure
+        io.close
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/chunked-array.rb b/ruby/red-arrow/lib/arrow/chunked-array.rb
new file mode 100644
index 0000000..c720d22
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/chunked-array.rb
@@ -0,0 +1,84 @@
+# 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 ChunkedArray
+    include Enumerable
+
+    alias_method :chunks_raw, :chunks
+    def chunks
+      @chunks ||= chunks_raw
+    end
+
+    def null?(i)
+      chunks.each do |array|
+        return array.null?(i) if i < array.length
+        i -= array.length
+      end
+      nil
+    end
+
+    def valid?(i)
+      chunks.each do |array|
+        return array.valid?(i) if i < array.length
+        i -= array.length
+      end
+      nil
+    end
+
+    def [](i)
+      i += length if i < 0
+      chunks.each do |array|
+        return array[i] if i < array.length
+        i -= array.length
+      end
+      nil
+    end
+
+    def each(&block)
+      return to_enum(__method__) unless block_given?
+
+      chunks.each do |array|
+        array.each(&block)
+      end
+    end
+
+    def reverse_each(&block)
+      return to_enum(__method__) unless block_given?
+
+      chunks.reverse_each do |array|
+        array.reverse_each(&block)
+      end
+    end
+
+    def each_chunk(&block)
+      chunks.each(&block)
+    end
+
+    def pack
+      first_chunk = chunks.first
+      data_type = first_chunk.value_data_type
+      case data_type
+      when TimestampDataType
+        builder = TimestampArrayBuilder.new(data_type)
+        builder.build(to_a)
+      else
+        first_chunk.class.new(to_a)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/column.rb b/ruby/red-arrow/lib/arrow/column.rb
new file mode 100644
index 0000000..de385c0
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/column.rb
@@ -0,0 +1,50 @@
+# 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 Column
+    include Enumerable
+
+    def null?(i)
+      data.null?(i)
+    end
+
+    def valid?(i)
+      data.valid?(i)
+    end
+
+    def [](i)
+      data[i]
+    end
+
+    def each(&block)
+      return to_enum(__method__) unless block_given?
+
+      data.each(&block)
+    end
+
+    def reverse_each(&block)
+      return to_enum(__method__) unless block_given?
+
+      data.reverse_each(&block)
+    end
+
+    def pack
+      self.class.new(field, data.pack)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/csv-loader.rb b/ruby/red-arrow/lib/arrow/csv-loader.rb
new file mode 100644
index 0000000..f3ad6ce
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/csv-loader.rb
@@ -0,0 +1,250 @@
+# 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.
+
+require "csv"
+require "pathname"
+require "time"
+
+module Arrow
+  class CSVLoader
+    class << self
+      def load(path_or_data, **options)
+        new(path_or_data, **options).load
+      end
+    end
+
+    def initialize(path_or_data, **options)
+      @path_or_data = path_or_data
+      @options = options
+    end
+
+    def load
+      case @path_or_data
+      when Pathname
+        load_from_path(@path_or_data.to_path)
+      when /\A.+\.csv\z/i
+        load_from_path(@path_or_data)
+      else
+        load_data(@path_or_data)
+      end
+    end
+
+    private
+    def open_csv(path, **options)
+      CSV.open(path, **options) do |csv|
+        yield(csv)
+      end
+    end
+
+    def parse_csv_data(data, **options)
+      csv = CSV.new(data, **options)
+      begin
+        yield(csv)
+      ensure
+        csv.close
+      end
+    end
+
+    def read_csv(csv)
+      reader = CSVReader.new(csv)
+      reader.read
+    end
+
+    def load_from_path(path)
+      options = update_csv_parse_options(@options, :open_csv, path)
+      open_csv(path, **options) do |csv|
+        read_csv(csv)
+      end
+    end
+
+    def load_data(data)
+      options = update_csv_parse_options(@options, :parse_csv_data, data)
+      parse_csv_data(data, **options) do |csv|
+        read_csv(csv)
+      end
+    end
+
+    def selective_converter(target_index)
+      lambda do |field, field_info|
+        if target_index.nil? or field_info.index == target_index
+          yield(field)
+        else
+          field
+        end
+      end
+    end
+
+    BOOLEAN_CONVERTER = lambda do |field|
+      begin
+        encoded_field = field.encode(CSV::ConverterEncoding)
+      rescue EncodingError
+        field
+      else
+        case encoded_field
+        when "true"
+          true
+        when "false"
+          false
+        else
+          field
+        end
+      end
+    end
+
+    ISO8601_CONVERTER = lambda do |field|
+      begin
+        encoded_field = field.encode(CSV::ConverterEncoding)
+      rescue EncodingError
+        field
+      else
+        begin
+          Time.iso8601(encoded_field)
+        rescue ArgumentError
+          field
+        end
+      end
+    end
+
+    def update_csv_parse_options(options, create_csv, *args)
+      if options.key?(:converters)
+        new_options = options.dup
+      else
+        converters = [:all, BOOLEAN_CONVERTER, ISO8601_CONVERTER]
+        new_options = options.merge(converters: converters)
+      end
+
+      unless options.key?(:headers)
+        __send__(create_csv, *args, **new_options) do |csv|
+          new_options[:headers] = have_header?(csv)
+        end
+      end
+      unless options.key?(:converters)
+        __send__(create_csv, *args, **new_options) do |csv|
+          new_options[:converters] = detect_robust_converters(csv)
+        end
+      end
+
+      new_options
+    end
+
+    def have_header?(csv)
+      if @options.key?(:headers)
+        return @options[:headers]
+      end
+
+      row1 = csv.shift
+      return false if row1.nil?
+      return false if row1.any?(&:nil?)
+
+      row2 = csv.shift
+      return nil if row2.nil?
+      return true if row2.any?(&:nil?)
+
+      return false if row1.any? {|value| not value.is_a?(String)}
+
+      if row1.collect(&:class) != row2.collect(&:class)
+        return true
+      end
+
+      nil
+    end
+
+    def detect_robust_converters(csv)
+      column_types = []
+      csv.each do |row|
+        if row.is_a?(CSV::Row)
+          each_value = Enumerator.new do |yielder|
+            row.each do |_name, value|
+              yielder << value
+            end
+          end
+        else
+          each_value = row.each
+        end
+        each_value.with_index do |value, i|
+          current_column_type = column_types[i]
+          next if current_column_type == :string
+
+          candidate_type = nil
+          case value
+          when nil
+            next
+          when "true", "false", true, false
+            candidate_type = :boolean
+          when Integer
+            candidate_type = :integer
+            if current_column_type == :float
+              candidate_type = :float
+            end
+          when Float
+            candidate_type = :float
+            if current_column_type == :integer
+              column_types[i] = candidate_type
+            end
+          when Time
+            candidate_type = :time
+          when DateTime
+            candidate_type = :date_time
+          when Date
+            candidate_type = :date
+          when String
+            next if value.empty?
+            candidate_type = :string
+          else
+            candidate_type = :string
+          end
+
+          column_types[i] ||= candidate_type
+          if column_types[i] != candidate_type
+            column_types[i] = :string
+          end
+        end
+      end
+
+      converters = []
+      column_types.each_with_index do |type, i|
+        case type
+        when :boolean
+          converters << selective_converter(i, &BOOLEAN_CONVERTER)
+        when :integer
+          converters << selective_converter(i) do |field|
+            if field.nil? or field.empty?
+              nil
+            else
+              CSV::Converters[:integer].call(field)
+            end
+          end
+        when :float
+          converters << selective_converter(i) do |field|
+            if field.nil? or field.empty?
+              nil
+            else
+              CSV::Converters[:float].call(field)
+            end
+          end
+        when :time
+          converters << selective_converter(i, &ISO8601_CONVERTER)
+        when :date_time
+          converters << selective_converter(i, &CSV::Converters[:date_time])
+        when :date
+          converters << selective_converter(i, &CSV::Converters[:date])
+        end
+      end
+      converters
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/csv-reader.rb b/ruby/red-arrow/lib/arrow/csv-reader.rb
new file mode 100644
index 0000000..4a596f0
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/csv-reader.rb
@@ -0,0 +1,54 @@
+# 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.
+
+require "csv"
+
+module Arrow
+  class CSVReader
+    def initialize(csv)
+      @csv = csv
+    end
+
+    def read
+      values_set = []
+      @csv.each do |row|
+        if row.is_a?(CSV::Row)
+          row = row.collect(&:last)
+        end
+        row.each_with_index do |value, i|
+          values = (values_set[i] ||= [])
+          values << value
+        end
+      end
+      return nil if values_set.empty?
+
+      arrays = values_set.collect.with_index do |values, i|
+        ArrayBuilder.build(values)
+      end
+      if @csv.headers
+        names = @csv.headers
+      else
+        names = arrays.size.times.collect(&:to_s)
+      end
+      raw_table = {}
+      names.each_with_index do |name, i|
+        raw_table[name] = arrays[i]
+      end
+      Table.new(raw_table)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/date32-array-builder.rb b/ruby/red-arrow/lib/arrow/date32-array-builder.rb
new file mode 100644
index 0000000..dedbba8
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/date32-array-builder.rb
@@ -0,0 +1,32 @@
+# 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 Date32ArrayBuilder
+    private
+    UNIX_EPOCH = Date.new(1970, 1, 1)
+    def convert_to_arrow_value(value)
+      value = value.to_date if value.respond_to?(:to_date)
+
+      if value.is_a?(Date)
+        (value - UNIX_EPOCH).to_i
+      else
+        value
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/date32-array.rb b/ruby/red-arrow/lib/arrow/date32-array.rb
new file mode 100644
index 0000000..121dbcb
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/date32-array.rb
@@ -0,0 +1,30 @@
+# 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 Date32Array
+    def get_value(i)
+      to_date(get_raw_value(i))
+    end
+
+    private
+    UNIX_EPOCH = 2440588
+    def to_date(raw_value)
+      Date.jd(UNIX_EPOCH + raw_value)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/date64-array-builder.rb b/ruby/red-arrow/lib/arrow/date64-array-builder.rb
new file mode 100644
index 0000000..d9ab30f
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/date64-array-builder.rb
@@ -0,0 +1,33 @@
+# 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 Date64ArrayBuilder
+    private
+    def convert_to_arrow_value(value)
+      if value.respond_to?(:to_time) and not value.is_a?(Time)
+        value = value.to_time
+      end
+
+      if value.is_a?(Time)
+        value.to_i * 1_000 + value.usec / 1_000
+      else
+        value
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/date64-array.rb b/ruby/red-arrow/lib/arrow/date64-array.rb
new file mode 100644
index 0000000..8feae42
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/date64-array.rb
@@ -0,0 +1,29 @@
+# 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 Date64Array
+    def get_value(i)
+      to_datetime(get_raw_value(i))
+    end
+
+    private
+    def to_datetime(raw_value)
+      Time.at(*raw_value.divmod(1_000)).to_datetime
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/field.rb b/ruby/red-arrow/lib/arrow/field.rb
new file mode 100644
index 0000000..b1ed114
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/field.rb
@@ -0,0 +1,34 @@
+# 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 Field
+    alias_method :initialize_raw, :initialize
+    def initialize(name, data_type)
+      case data_type
+      when String, Symbol
+        data_type_name = data_type.to_s.capitalize.gsub(/\AUint/, "UInt")
+        data_type_class_name = "#{data_type_name}DataType"
+        if Arrow.const_defined?(data_type_class_name)
+          data_type_class = Arrow.const_get(data_type_class_name)
+          data_type = data_type_class.new
+        end
+      end
+      initialize_raw(name, data_type)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/group.rb b/ruby/red-arrow/lib/arrow/group.rb
new file mode 100644
index 0000000..7ef8dc3
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/group.rb
@@ -0,0 +1,175 @@
+# 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
+  # Experimental
+  #
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class Group
+    def initialize(table, keys)
+      @table = table
+      @keys = keys
+    end
+
+    def count
+      key_names = @keys.collect(&:to_s)
+      target_columns = @table.columns.reject do |column|
+        key_names.include?(column.name)
+      end
+      aggregate(target_columns) do |column, indexes|
+        n = 0
+        indexes.each do |index|
+          n += 1 unless column.null?(index)
+        end
+        n
+      end
+    end
+
+    def sum
+      key_names = @keys.collect(&:to_s)
+      target_columns = @table.columns.reject do |column|
+        key_names.include?(column.name) or
+          not column.data_type.is_a?(NumericDataType)
+      end
+      aggregate(target_columns) do |column, indexes|
+        n = 0
+        indexes.each do |index|
+          value = column[index]
+          n += value unless value.nil?
+        end
+        n
+      end
+    end
+
+    def average
+      key_names = @keys.collect(&:to_s)
+      target_columns = @table.columns.reject do |column|
+        key_names.include?(column.name) or
+          not column.data_type.is_a?(NumericDataType)
+      end
+      aggregate(target_columns) do |column, indexes|
+        average = 0.0
+        n = 0
+        indexes.each do |index|
+          value = column[index]
+          unless value.nil?
+            n += 1
+            average += (value - average) / n
+          end
+        end
+        average
+      end
+    end
+
+    def min
+      key_names = @keys.collect(&:to_s)
+      target_columns = @table.columns.reject do |column|
+        key_names.include?(column.name) or
+          not column.data_type.is_a?(NumericDataType)
+      end
+      aggregate(target_columns) do |column, indexes|
+        n = nil
+        indexes.each do |index|
+          value = column[index]
+          next if value.nil?
+          n ||= value
+          n = value if value < n
+        end
+        n
+      end
+    end
+
+    def max
+      key_names = @keys.collect(&:to_s)
+      target_columns = @table.columns.reject do |column|
+        key_names.include?(column.name) or
+          not column.data_type.is_a?(NumericDataType)
+      end
+      aggregate(target_columns) do |column, indexes|
+        n = nil
+        indexes.each do |index|
+          value = column[index]
+          next if value.nil?
+          n ||= value
+          n = value if value > n
+        end
+        n
+      end
+    end
+
+    private
+    def aggregate(target_columns)
+      sort_values = @table.n_rows.times.collect do |i|
+        key_values = @keys.collect do |key|
+          @table[key][i]
+        end
+        [key_values, i]
+      end
+      sorted = sort_values.sort_by do |key_values, i|
+        key_values
+      end
+
+      grouped_keys = []
+      aggregated_arrays_raw = []
+      target_columns.size.times do
+        aggregated_arrays_raw << []
+      end
+      indexes = []
+      sorted.each do |key_values, i|
+        if grouped_keys.empty?
+          grouped_keys << key_values
+          indexes.clear
+          indexes << i
+        else
+          if key_values == grouped_keys.last
+            indexes << i
+          else
+            grouped_keys << key_values
+            target_columns.each_with_index do |column, j|
+              aggregated_arrays_raw[j] << yield(column, indexes)
+            end
+            indexes.clear
+            indexes << i
+          end
+        end
+      end
+      target_columns.each_with_index do |column, j|
+        aggregated_arrays_raw[j] << yield(column, indexes)
+      end
+
+      grouped_key_arrays_raw = grouped_keys.transpose
+      columns = @keys.collect.with_index do |key, i|
+        key_column = @table[key]
+        key_column_array_class = key_column.data.chunks.first.class
+        if key_column_array_class == TimestampArray
+          builder = TimestampArrayBuilder.new(key_column.data_type)
+          key_column_array = builder.build(grouped_key_arrays_raw[i])
+        else
+          key_column_array =
+            key_column_array_class.new(grouped_key_arrays_raw[i])
+        end
+        Column.new(key_column.field, key_column_array)
+      end
+      target_columns.each_with_index do |column, i|
+        array = ArrayBuilder.build(aggregated_arrays_raw[i])
+        field = Field.new(column.name, array.value_data_type)
+        columns << Column.new(field, array)
+      end
+      Table.new(columns)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/loader.rb b/ruby/red-arrow/lib/arrow/loader.rb
new file mode 100644
index 0000000..2366393
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/loader.rb
@@ -0,0 +1,93 @@
+# 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.
+
+require "arrow/block-closable"
+
+module Arrow
+  class Loader < GObjectIntrospection::Loader
+    class << self
+      def load
+        super("Arrow", Arrow)
+      end
+    end
+
+    private
+    def post_load(repository, namespace)
+      require_libraries
+    end
+
+    def require_libraries
+      require "arrow/array"
+      require "arrow/array-builder"
+      require "arrow/chunked-array"
+      require "arrow/column"
+      require "arrow/csv-loader"
+      require "arrow/csv-reader"
+      require "arrow/date32-array"
+      require "arrow/date32-array-builder"
+      require "arrow/date64-array"
+      require "arrow/date64-array-builder"
+      require "arrow/field"
+      require "arrow/record"
+      require "arrow/record-batch"
+      require "arrow/rolling-window"
+      require "arrow/slicer"
+      require "arrow/table"
+      require "arrow/table-formatter"
+      require "arrow/table-list-formatter"
+      require "arrow/table-table-formatter"
+      require "arrow/table-loader"
+      require "arrow/table-saver"
+      require "arrow/tensor"
+      require "arrow/timestamp-array"
+      require "arrow/timestamp-array-builder"
+
+      require "arrow/record-batch-file-reader"
+      require "arrow/record-batch-stream-reader"
+    end
+
+    def load_object_info(info)
+      super
+
+      klass = @base_module.const_get(rubyish_class_name(info))
+      if klass.method_defined?(:close)
+        klass.extend(BlockClosable)
+      end
+    end
+
+    def load_method_info(info, klass, method_name)
+      case klass.name
+      when "Arrow::StringArray"
+        case method_name
+        when "get_value"
+          method_name = "get_raw_value"
+        when "get_string"
+          method_name = "get_value"
+        end
+        super(info, klass, method_name)
+      when "Arrow::TimestampArray", "Arrow::Date32Array", "Arrow::Date64Array"
+        case method_name
+        when "get_value"
+          method_name = "get_raw_value"
+        end
+        super(info, klass, method_name)
+      else
+       super
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/record-batch-file-reader.rb b/ruby/red-arrow/lib/arrow/record-batch-file-reader.rb
new file mode 100644
index 0000000..86a757e
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/record-batch-file-reader.rb
@@ -0,0 +1,28 @@
+# 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 RecordBatchFileReader
+    include Enumerable
+
+    def each
+      n_record_batches.times do |i|
+        yield(get_record_batch(i))
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/record-batch-stream-reader.rb b/ruby/red-arrow/lib/arrow/record-batch-stream-reader.rb
new file mode 100644
index 0000000..fa15c80
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/record-batch-stream-reader.rb
@@ -0,0 +1,30 @@
+# 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 RecordBatchStreamReader
+    include Enumerable
+
+    def each
+      loop do
+        record_batch = next_record_batch
+        break if record_batch.nil?
+        yield(record_batch)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/record-batch.rb b/ruby/red-arrow/lib/arrow/record-batch.rb
new file mode 100644
index 0000000..f5f8ea2
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/record-batch.rb
@@ -0,0 +1,45 @@
+# 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.
+
+require "arrow/record-containable"
+
+module Arrow
+  class RecordBatch
+    include RecordContainable
+    include Enumerable
+
+    alias_method :each, :each_record
+
+    alias_method :columns_raw, :columns
+    def columns
+      @columns ||= columns_raw
+    end
+
+    def respond_to_missing?(name, include_private)
+      return true if find_column(name)
+      super
+    end
+
+    def method_missing(name, *args, &block)
+      if args.empty?
+        column = find_column(name)
+        return column if column
+      end
+      super
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/record-containable.rb b/ruby/red-arrow/lib/arrow/record-containable.rb
new file mode 100644
index 0000000..f73d1a8
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/record-containable.rb
@@ -0,0 +1,73 @@
+# 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
+  module RecordContainable
+    def each_column(&block)
+      return to_enum(__method__) unless block_given?
+
+      columns.each(&block)
+    end
+
+    def each_record(reuse_record: false)
+      unless block_given?
+        return to_enum(__method__, reuse_record: reuse_record)
+      end
+
+      if reuse_record
+        record = Record.new(self, nil)
+        n_rows.times do |i|
+          record.index = i
+          yield(record)
+        end
+      else
+        n_rows.times do |i|
+          yield(Record.new(self, i))
+        end
+      end
+    end
+
+    def find_column(name_or_index)
+      case name_or_index
+      when String, Symbol
+        name = name_or_index.to_s
+        index = resolve_column_name(name)
+        return nil if index.nil?
+        columns[index]
+      when Integer
+        index = name_or_index
+        columns[index]
+      else
+        message = "column name or index must be String, Symbol or Integer"
+        raise ArgumentError, message
+      end
+    end
+
+    private
+    def resolve_column_name(name)
+      (@column_name_to_index ||= build_column_name_resolve_table)[name]
+    end
+
+    def build_column_name_resolve_table
+      table = {}
+      schema.fields.each_with_index do |field, i|
+        table[field.name] = i
+      end
+      table
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/record.rb b/ruby/red-arrow/lib/arrow/record.rb
new file mode 100644
index 0000000..70bd215
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/record.rb
@@ -0,0 +1,57 @@
+# 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 Record
+    attr_accessor :index
+    def initialize(record_container, index)
+      @record_container = record_container
+      @index = index
+    end
+
+    def [](column_name_or_column_index)
+      column = @record_container.find_column(column_name_or_column_index)
+      return nil if column.nil?
+      column[@index]
+    end
+
+    def columns
+      @record_container.columns
+    end
+
+    def to_h
+      attributes = {}
+      @record_container.schema.fields.each_with_index do |field, i|
+        attributes[field.name] = self[i]
+      end
+      attributes
+    end
+
+    def respond_to_missing?(name, include_private)
+      return true if @record_container.find_column(name)
+      super
+    end
+
+    def method_missing(name, *args, &block)
+      if args.empty?
+        column = @record_container.find_column(name)
+        return column[@index] if column
+      end
+      super
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/rolling-window.rb b/ruby/red-arrow/lib/arrow/rolling-window.rb
new file mode 100644
index 0000000..1db03bb
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/rolling-window.rb
@@ -0,0 +1,48 @@
+# 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
+  # Experimental
+  #
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class RollingWindow
+    def initialize(table, size)
+      @table = table
+      @size = size
+    end
+
+    def lag(key, diff: 1)
+      column = @table[key]
+      if @size
+        windows = column.each_slice(@size)
+      else
+        windows = column
+      end
+      lag_values = [nil] * diff
+      windows.each_cons(diff + 1) do |values|
+        target = values[0]
+        current = values[1]
+        if target.nil? or current.nil?
+          lag_values << nil
+        else
+          lag_values << current - target
+        end
+      end
+      ArrayBuilder.build(lag_values)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/slicer.rb b/ruby/red-arrow/lib/arrow/slicer.rb
new file mode 100644
index 0000000..fd2033d
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/slicer.rb
@@ -0,0 +1,454 @@
+# 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
+  # Experimental
+  #
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class Slicer
+    def initialize(table)
+      @table = table
+    end
+
+    def [](column_name)
+      column = @table[column_name]
+      return nil if column.nil?
+      ColumnCondition.new(column)
+    end
+
+    def respond_to_missing?(name, include_private)
+      return true if self[name]
+      super
+    end
+
+    def method_missing(name, *args, &block)
+      if args.empty?
+        column_condition = self[name]
+        return column_condition if column_condition
+      end
+      super
+    end
+
+    class Condition
+      def evaluate
+        message = "Slicer::Condition must define \#evaluate: #{inspect}"
+        raise NotImplementedError.new(message)
+      end
+
+      def &(condition)
+        AndCondition.new(self, condition)
+      end
+
+      def |(condition)
+        OrCondition.new(self, condition)
+      end
+
+      def ^(condition)
+        XorCondition.new(self, condition)
+      end
+    end
+
+    class LogicalCondition < Condition
+      def initialize(condition1, condition2)
+        @condition1 = condition1
+        @condition2 = condition2
+      end
+
+      def evaluate
+        values1 = @condition1.evaluate.each
+        values2 = @condition2.evaluate.each
+        raw_array = []
+        begin
+          loop do
+            value1 = values1.next
+            value2 = values2.next
+            if value1.nil? or value2.nil?
+              raw_array << nil
+            else
+              raw_array << evaluate_value(value1, value2)
+            end
+          end
+        rescue StopIteration
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class AndCondition < LogicalCondition
+      private
+      def evaluate_value(value1, value2)
+        value1 and value2
+      end
+    end
+
+    class OrCondition < LogicalCondition
+      private
+      def evaluate_value(value1, value2)
+        value1 or value2
+      end
+    end
+
+    class XorCondition < LogicalCondition
+      private
+      def evaluate_value(value1, value2)
+        value1 ^ value2
+      end
+    end
+
+    class ColumnCondition < Condition
+      def initialize(column)
+        @column = column
+      end
+
+      def evaluate
+        data = @column.data
+
+        case @column.data_type
+        when BooleanDataType
+          data
+        else
+          if data.n_chunks == 1
+            data.get_chunk(0).cast(BooleanDataType.new, nil)
+          else
+            arrays = data.each_chunk.collect do |chunk|
+              chunk.cast(BooleanDataType.new, nil)
+            end
+            ChunkedArray.new(arrays)
+          end
+        end
+      end
+
+      def !@
+        NotColumnCondition.new(@column)
+      end
+
+      def null?
+        self == nil
+      end
+
+      def valid?
+        self != nil
+      end
+
+      def ==(value)
+        EqualCondition.new(@column, value)
+      end
+
+      def !=(value)
+        NotEqualCondition.new(@column, value)
+      end
+
+      def <(value)
+        LessCondition.new(@column, value)
+      end
+
+      def <=(value)
+        LessEqualCondition.new(@column, value)
+      end
+
+      def >(value)
+        GreaterCondition.new(@column, value)
+      end
+
+      def >=(value)
+        GreaterEqualCondition.new(@column, value)
+      end
+
+      def in?(values)
+        InCondition.new(@column, values)
+      end
+
+      def select(&block)
+        SelectCondition.new(@column, block)
+      end
+
+      def reject(&block)
+        RejectCondition.new(@column, block)
+      end
+    end
+
+    class NotColumnCondition < Condition
+      def initialize(column)
+        @column = column
+      end
+
+      def evaluate
+        data = @column.data
+        raw_array = []
+        data.each_chunk do |chunk|
+          if chunk.is_a?(BooleanArray)
+            boolean_array = chunk
+          else
+            boolean_array = chunk.cast(BooleanDataType.new, nil)
+          end
+          boolean_array.each do |value|
+            if value.nil?
+              raw_array << value
+            else
+              raw_array << !value
+            end
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+
+      def !@
+        ColumnCondition.new(@column)
+      end
+    end
+
+    class EqualCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        NotEqualCondition.new(@column, @value)
+      end
+
+      def evaluate
+        case @value
+        when nil
+          raw_array = @column.collect(&:nil?)
+          BooleanArray.new(raw_array)
+        else
+          raw_array = @column.collect do |value|
+            if value.nil?
+              nil
+            else
+              @value == value
+            end
+          end
+          BooleanArray.new(raw_array)
+        end
+      end
+    end
+
+    class NotEqualCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        EqualCondition.new(@column, @value)
+      end
+
+      def evaluate
+        case @value
+        when nil
+          if @column.n_nulls.zero?
+            raw_array = [true] * @column.length
+          else
+            raw_array = @column.length.times.collect do |i|
+              @column.valid?(i)
+            end
+          end
+          BooleanArray.new(raw_array)
+        else
+          raw_array = @column.collect do |value|
+            if value.nil?
+              nil
+            else
+              @value != value
+            end
+          end
+          BooleanArray.new(raw_array)
+        end
+      end
+    end
+
+    class LessCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        GreaterEqualCondition.new(@column, @value)
+      end
+
+      def evaluate
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            @value > value
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class LessEqualCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        GreaterCondition.new(@column, @value)
+      end
+
+      def evaluate
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            @value >= value
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class GreaterCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        LessEqualCondition.new(@column, @value)
+      end
+
+      def evaluate
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            @value < value
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class GreaterEqualCondition < Condition
+      def initialize(column, value)
+        @column = column
+        @value = value
+      end
+
+      def !@
+        LessCondition.new(@column, @value)
+      end
+
+      def evaluate
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            @value <= value
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class InCondition < Condition
+      def initialize(column, values)
+        @column = column
+        @values = values
+      end
+
+      def !@
+        NotInCondition.new(@column, @values)
+      end
+
+      def evaluate
+        values_index = {}
+        @values.each do |value|
+          values_index[value] = true
+        end
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            values_index.key?(value)
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class NotInCondition < Condition
+      def initialize(column, values)
+        @column = column
+        @values = values
+      end
+
+      def !@
+        InCondition.new(@column, @values)
+      end
+
+      def evaluate
+        values_index = {}
+        @values.each do |value|
+          values_index[value] = true
+        end
+        raw_array = @column.collect do |value|
+          if value.nil?
+            nil
+          else
+            not values_index.key?(value)
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+
+    class SelectCondition < Condition
+      def initialize(column, block)
+        @column = column
+        @block = block
+      end
+
+      def !@
+        RejectCondition.new(@column, @block)
+      end
+
+      def evaluate
+        BooleanArray.new(@column.collect(&@block))
+      end
+    end
+
+    class RejectCondition < Condition
+      def initialize(column, block)
+        @column = column
+        @block = block
+      end
+
+      def !@
+        SelectCondition.new(@column, @block)
+      end
+
+      def evaluate
+        raw_array = @column.collect do |value|
+          evaluated_value = @block.call(value)
+          if evaluated_value.nil?
+            nil
+          else
+            not evaluated_value
+          end
+        end
+        BooleanArray.new(raw_array)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table-formatter.rb b/ruby/red-arrow/lib/arrow/table-formatter.rb
new file mode 100644
index 0000000..280f189
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table-formatter.rb
@@ -0,0 +1,66 @@
+# 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
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class TableFormatter
+    def initialize(table, options={})
+      @table = table
+      @options = options
+    end
+
+    def format
+      text = ""
+      columns = @table.columns
+      format_header(text, columns)
+
+      n_rows = @table.n_rows
+      return text if n_rows.zero?
+
+      border = @options[:border] || 10
+      n_digits = (Math.log10(n_rows) + 1).truncate
+      head_limit = [border, n_rows].min
+      head_column_values = columns.collect do |column|
+        column.each.take(head_limit)
+      end
+      format_rows(text,
+                  columns,
+                  head_column_values.transpose,
+                  n_digits,
+                  0)
+      return text if n_rows <= border
+
+      tail_start = [border, n_rows - border].max
+      tail_limit = n_rows - tail_start
+      tail_column_values = columns.collect do |column|
+        column.reverse_each.take(tail_limit).reverse
+      end
+
+      if head_limit != tail_start
+        format_ellipsis(text)
+      end
+
+      format_rows(text,
+                  columns,
+                  tail_column_values.transpose,
+                  n_digits,
+                  tail_start)
+
+      text
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table-list-formatter.rb b/ruby/red-arrow/lib/arrow/table-list-formatter.rb
new file mode 100644
index 0000000..8a41b1b
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table-list-formatter.rb
@@ -0,0 +1,39 @@
+# 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
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class TableListFormatter < TableFormatter
+    private
+    def format_header(text, columns)
+    end
+
+    def format_rows(text, columns, rows, n_digits, start_offset)
+      rows.each_with_index do |row, nth_row|
+        text << ("=" * 20 + " #{start_offset + nth_row} " + "=" * 20 + "\n")
+        row.each_with_index do |column_value, nth_column|
+          column = columns[nth_column]
+          text << "#{column.name}: #{column_value}\n"
+        end
+      end
+    end
+
+    def format_ellipsis(text)
+      text << "...\n"
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table-loader.rb b/ruby/red-arrow/lib/arrow/table-loader.rb
new file mode 100644
index 0000000..985999e
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table-loader.rb
@@ -0,0 +1,120 @@
+# 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 TableLoader
+    class << self
+      def load(path, options={})
+        new(path, options).load
+      end
+    end
+
+    def initialize(path, options={})
+      @path = path
+      @options = options
+    end
+
+    def load
+      path = @path
+      path = path.to_path if path.respond_to?(:to_path)
+      format = @options[:format] || guess_format(path) || :arrow
+
+      custom_load_method = "load_as_#{format}"
+      unless respond_to?(custom_load_method, true)
+        available_formats = []
+        (methods(true) | private_methods(true)).each do |name|
+          match_data = /\Aload_as_/.match(name.to_s)
+          if match_data
+            available_formats << match_data.post_match
+          end
+        end
+        message = "Arrow::Table load format must be one of ["
+        message << available_formats.join(", ")
+        message << "]: #{format.inspect}"
+        raise ArgumentError, message
+      end
+      __send__(custom_load_method, path)
+    end
+
+    private
+    def guess_format(path)
+      extension = ::File.extname(path).gsub(/\A\./, "").downcase
+      return nil if extension.empty?
+
+      return extension if respond_to?("load_as_#{extension}", true)
+
+      nil
+    end
+
+    def load_raw(input, reader)
+      schema = reader.schema
+      chunked_arrays = []
+      reader.each do |record_batch|
+        record_batch.columns.each_with_index do |array, i|
+          chunked_array = (chunked_arrays[i] ||= [])
+          chunked_array << array
+        end
+      end
+      columns = schema.fields.collect.with_index do |field, i|
+        Column.new(field, ChunkedArray.new(chunked_arrays[i]))
+      end
+      table = Table.new(schema, columns)
+      table.instance_variable_set(:@input, input)
+      table
+    end
+
+    def load_as_arrow(path)
+      input = nil
+      reader = nil
+      error = nil
+      reader_class_candidates = [
+        RecordBatchFileReader,
+        RecordBatchStreamReader,
+      ]
+      reader_class_candidates.each do |reader_class_candidate|
+        input = MemoryMappedInputStream.new(path)
+        begin
+          reader = reader_class_candidate.new(input)
+        rescue Arrow::Error
+          error = $!
+        else
+          break
+        end
+      end
+      raise error if reader.nil?
+      load_raw(input, reader)
+    end
+
+    def load_as_batch(path)
+      input = MemoryMappedInputStream.new(path)
+      reader = RecordBatchFileReader.new(input)
+      load_raw(input, reader)
+    end
+
+    def load_as_stream(path)
+      input = MemoryMappedInputStream.new(path)
+      reader = RecordBatchStreamReader.new(input)
+      load_raw(input, reader)
+    end
+
+    def load_as_csv(path)
+      options = @options.dup
+      options.delete(:format)
+      CSVLoader.load(Pathname.new(path), options)
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table-saver.rb b/ruby/red-arrow/lib/arrow/table-saver.rb
new file mode 100644
index 0000000..d388702
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table-saver.rb
@@ -0,0 +1,96 @@
+# 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 TableSaver
+    class << self
+      def save(table, path, options={})
+        new(table, path, options).save
+      end
+    end
+
+    def initialize(table, path, options={})
+      @table = table
+      @path = path
+      @options = options
+    end
+
+    def save
+      path = @path
+      path = path.to_path if path.respond_to?(:to_path)
+      format = @options[:format] || guess_format(path) || :arrow
+
+      custom_save_method = "save_as_#{format}"
+      unless respond_to?(custom_save_method, true)
+        available_formats = []
+        (methods(true) | private_methods(true)).each do |name|
+          match_data = /\Asave_as_/.match(name.to_s)
+          if match_data
+            available_formats << match_data.post_match
+          end
+        end
+        message = "Arrow::Table save format must be one of ["
+        message << available_formats.join(", ")
+        message << "]: #{format.inspect}"
+        raise ArgumentError, message
+      end
+      __send__(custom_save_method, path)
+    end
+
+    private
+    def guess_format(path)
+      extension = ::File.extname(path).gsub(/\A\./, "").downcase
+      return nil if extension.empty?
+
+      return extension if respond_to?("save_as_#{extension}", true)
+
+      nil
+    end
+
+    def save_raw(writer_class, path)
+      FileOutputStream.open(path, false) do |output|
+        writer_class.open(output, @table.schema) do |writer|
+          writer.write_table(@table)
+        end
+      end
+    end
+
+    def save_as_arrow(path)
+      save_as_batch(path)
+    end
+
+    def save_as_batch(path)
+      save_raw(RecordBatchFileWriter, path)
+    end
+
+    def save_as_stream(path)
+      save_raw(RecordBatchStreamWriter, path)
+    end
+
+    def save_as_csv(path)
+      CSV.open(path, "w") do |csv|
+        names = @table.schema.fields.collect(&:name)
+        csv << names
+        @table.each_record(reuse_record: true) do |record|
+          csv << names.collect do |name|
+            record[name]
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table-table-formatter.rb b/ruby/red-arrow/lib/arrow/table-table-formatter.rb
new file mode 100644
index 0000000..07d78b7
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table-table-formatter.rb
@@ -0,0 +1,73 @@
+# 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.
+
+require "time"
+
+module Arrow
+  # TODO: Almost codes should be implemented in Apache Arrow C++.
+  class TableTableFormatter < TableFormatter
+    private
+    def format_header(text, columns)
+      columns.each do |column|
+        text << "\t"
+        text << format_column_name(column)
+      end
+      text << "\n"
+    end
+
+    FLOAT_N_DIGITS = 10
+    def format_column_name(column)
+      case column.data_type
+      when TimestampDataType
+        "%*s" % [Time.now.iso8601.size, column.name]
+      when FloatDataType, DoubleDataType
+        "%*s" % [FLOAT_N_DIGITS, column.name]
+      else
+        column.name
+      end
+    end
+
+    def format_rows(text, columns, rows, n_digits, start_offset)
+      rows.each_with_index do |row, nth_row|
+        text << ("%*d" % [n_digits, start_offset + nth_row])
+        row.each_with_index do |column_value, nth_column|
+          text << "\t"
+          column = columns[nth_column]
+          text << format_column_value(column, column_value)
+        end
+        text << "\n"
+      end
+    end
+
+    def format_column_value(column, value)
+      case value
+      when Time
+        value.iso8601
+      when Float
+        "%*f" % [[column.name.size, FLOAT_N_DIGITS].max, value]
+      when Integer
+        "%*d" % [column.name.size, value]
+      else
+        "%-*s" % [column.name.size, value.to_s]
+      end
+    end
+
+    def format_ellipsis(text)
+      text << "...\n"
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/table.rb b/ruby/red-arrow/lib/arrow/table.rb
new file mode 100644
index 0000000..8cc3e3c
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/table.rb
@@ -0,0 +1,381 @@
+# 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.
+
+require "arrow/group"
+require "arrow/record-containable"
+
+module Arrow
+  class Table
+    include RecordContainable
+
+    class << self
+      def load(path, options={})
+        TableLoader.load(path, options)
+      end
+    end
+
+    alias_method :initialize_raw, :initialize
+    def initialize(schema_or_raw_table_or_columns, columns=nil)
+      if columns.nil?
+        if schema_or_raw_table_or_columns[0].is_a?(Column)
+          columns = schema_or_raw_table_or_columns
+          fields = columns.collect(&:field)
+          schema = Schema.new(fields)
+        else
+          raw_table = schema_or_raw_table_or_columns
+          fields = []
+          columns = []
+          raw_table.each do |name, array|
+            field = Field.new(name.to_s, array.value_data_type)
+            fields << field
+            columns << Column.new(field, array)
+          end
+          schema = Schema.new(fields)
+        end
+      else
+        schema = schema_or_raw_table_or_columns
+      end
+      initialize_raw(schema, columns)
+    end
+
+    def columns
+      @columns ||= n_columns.times.collect {|i| get_column(i)}
+    end
+
+    def each_record_batch
+      return to_enum(__method__) unless block_given?
+
+      reader = TableBatchReader.new(self)
+      while record_batch = reader.read_next
+        yield(record_batch)
+      end
+    end
+
+    alias_method :size, :n_rows
+    alias_method :length, :n_rows
+
+    alias_method :[], :find_column
+
+    # TODO
+    #
+    # @return [Arrow::Table]
+    def slice(*args)
+      slicers = []
+      expected_n_args = nil
+      case args.size
+      when 0
+        expected_n_args = "1..2" unless block_given?
+      when 1
+        slicers << args[0]
+      when 2
+        from, to = args
+        slicers << (from...(from + to))
+      else
+        if block_given?
+          expected_n_args = "0..2"
+        else
+          expected_n_args = "1..2"
+        end
+      end
+      if expected_n_args
+        message = "wrong number of arguments " +
+          "(given #{args.size}, expected #{expected_n_args})"
+        raise ArgumentError, message
+      end
+
+      if block_given?
+        block_slicer = yield(Slicer.new(self))
+        case block_slicer
+        when nil
+          # Ignore
+        when ::Array
+          slicers.concat(block_slicer)
+        else
+          slicers << block_slicer
+        end
+      end
+
+      ranges = []
+      slicers.each do |slicer|
+        slicer = slicer.evaluate if slicer.respond_to?(:evaluate)
+        case slicer
+        when Integer
+          slicer += n_rows if slicer < 0
+          ranges << [slicer, slicer]
+        when Range
+          from = slicer.first
+          to = slicer.last
+          to -= 1 if slicer.exclude_end?
+          from += n_rows if from < 0
+          to += n_rows if to < 0
+          ranges << [from, to]
+        when ::Array
+          boolean_array_to_slice_ranges(slicer, 0, ranges)
+        when ChunkedArray
+          offset = 0
+          slicer.each_chunk do |array|
+            boolean_array_to_slice_ranges(array, offset, ranges)
+            offset += array.length
+          end
+        when BooleanArray
+          boolean_array_to_slice_ranges(slicer, 0, ranges)
+        else
+          message = "slicer must be Integer, Range, (from, to), " +
+            "Arrow::ChunkedArray of Arrow::BooleanArray, " +
+            "Arrow::BooleanArray or Arrow::Slicer::Condition: #{slicer.inspect}"
+          raise ArgumentError, message
+        end
+      end
+      slice_by_ranges(ranges)
+    end
+
+    # TODO
+    #
+    # @return [Arrow::Table]
+    def merge(other)
+      added_columns = {}
+      removed_columns = {}
+
+      case other
+      when Hash
+        other.each do |name, value|
+          name = name.to_s
+          if value
+            added_columns[name] = ensure_column(name, value)
+          else
+            removed_columns[name] = true
+          end
+        end
+      when Table
+        added_columns = {}
+        other.columns.each do |column|
+          added_columns[column.name] = column
+        end
+      else
+        message = "merge target must be Hash or Arrow::Table: " +
+          "<#{other.inspect}>: #{inspect}"
+        raise ArgumentError, message
+      end
+
+      new_columns = []
+      columns.each do |column|
+        column_name = column.name
+        new_column = added_columns.delete(column_name)
+        if new_column
+          new_columns << new_column
+          next
+        end
+        next if removed_columns.key?(column_name)
+        new_columns << column
+      end
+      added_columns.each do |name, new_column|
+        new_columns << new_column
+      end
+      new_fields = new_columns.collect do |new_column|
+        new_column.field
+      end
+      self.class.new(Schema.new(new_fields), new_columns)
+    end
+
+    alias_method :remove_column_raw, :remove_column
+    def remove_column(name_or_index)
+      case name_or_index
+      when String, Symbol
+        name = name_or_index.to_s
+        index = columns.index {|column| column.name == name}
+        if index.nil?
+          message = "unknown column: #{name_or_index.inspect}: #{inspect}"
+          raise KeyError.new(message)
+        end
+      else
+        index = name_or_index
+        index += n_columns if index < 0
+        if index < 0 or index >= n_columns
+          message = "out of index (0..#{n_columns - 1}): " +
+            "#{name_or_index.inspect}: #{inspect}"
+          raise IndexError.new(message)
+        end
+      end
+      remove_column_raw(index)
+    end
+
+    # TODO
+    #
+    # @return [Arrow::Table]
+    def select_columns(*selectors, &block)
+      if selectors.empty?
+        return to_enum(__method__) unless block_given?
+        selected_columns = columns.select(&block)
+      else
+        selected_columns = []
+        selectors.each do |selector|
+          case selector
+          when String, Symbol
+            column = find_column(selector)
+            if column.nil?
+              message = "unknown column: #{selector.inspect}: #{inspect}"
+              raise KeyError.new(message)
+            end
+            selected_columns << column
+          when Range
+            selected_columns.concat(columns[selector])
+          else
+            column = columns[selector]
+            if column.nil?
+              message = "out of index (0..#{n_columns - 1}): " +
+              "#{selector.inspect}: #{inspect}"
+              raise IndexError.new(message)
+            end
+            selected_columns << column
+          end
+        end
+        selected_columns = selected_columns.select(&block) if block_given?
+      end
+      self.class.new(selected_columns)
+    end
+
+    # Experimental
+    def group(*keys)
+      Group.new(self, keys)
+    end
+
+    # Experimental
+    def window(size: nil)
+      RollingWindow.new(self, size)
+    end
+
+    def save(path, options={})
+      saver = TableSaver.new(self, path, options)
+      saver.save
+    end
+
+    def pack
+      packed_columns = columns.collect do |column|
+        column.pack
+      end
+      self.class.new(schema, packed_columns)
+    end
+
+    def to_s(options={})
+      case options[:format]
+      when :list
+        formatter_class = TableListFormatter
+      else
+        formatter_class = TableTableFormatter
+      end
+      formatter = formatter_class.new(self, options)
+      formatter.format
+    end
+
+    def inspect
+      "#{super}\n#{to_s}"
+    end
+
+    def respond_to_missing?(name, include_private)
+      return true if find_column(name)
+      super
+    end
+
+    def method_missing(name, *args, &block)
+      if args.empty?
+        column = find_column(name)
+        return column if column
+      end
+      super
+    end
+
+    private
+    def boolean_array_to_slice_ranges(array, offset, ranges)
+      in_target = false
+      target_start = nil
+      array.each_with_index do |is_target, i|
+        if is_target
+          unless in_target
+            target_start = offset + i
+            in_target = true
+          end
+        else
+          if in_target
+            ranges << [target_start, offset + i - 1]
+            target_start = nil
+            in_target = false
+          end
+        end
+      end
+      if in_target
+        ranges << [target_start, offset + array.length - 1]
+      end
+    end
+
+    # TODO: Almost codes should be implemented in Apache Arrow C++.
+    def slice_by_ranges(ranges)
+      sliced_columns = columns.collect do |column|
+        chunks = []
+        arrays = column.data.each_chunk.to_a
+        offset = 0
+        offset_in_array = 0
+        ranges.each do |from, to|
+          range_size = to - from + 1
+          while range_size > 0
+            while offset + arrays.first.length - offset_in_array < from
+              offset += arrays.first.length - offset_in_array
+              arrays.shift
+              offset_in_array = 0
+            end
+            if offset < from
+              skipped_size = from - offset
+              offset += skipped_size
+              offset_in_array += skipped_size
+            end
+            array = arrays.first
+            array_length = array.length
+            rest_length = array_length - offset_in_array
+            if rest_length <= range_size
+              chunks << array.slice(offset_in_array, array_length)
+              offset += rest_length
+              range_size -= rest_length
+              offset_in_array = 0
+              arrays.shift
+            else
+              chunks << array.slice(offset_in_array, range_size)
+              offset += range_size
+              offset_in_array += range_size
+              range_size = 0
+            end
+          end
+        end
+        Column.new(column.field, ChunkedArray.new(chunks))
+      end
+
+      self.class.new(schema, sliced_columns)
+    end
+
+    def ensure_column(name, data)
+      case data
+      when Array
+        field = Field.new(name, data.value_data_type)
+        Column.new(field, data)
+      when Column
+        data
+      else
+        message = "column must be Arrow::Array or Arrow::Column: " +
+          "<#{name}>: <#{data.inspect}>: #{inspect}"
+        raise ArgumentError, message
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/tensor.rb b/ruby/red-arrow/lib/arrow/tensor.rb
new file mode 100644
index 0000000..fdcc6c1
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/tensor.rb
@@ -0,0 +1,24 @@
+# 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 Tensor
+    def to_arrow
+      self
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/timestamp-array-builder.rb b/ruby/red-arrow/lib/arrow/timestamp-array-builder.rb
new file mode 100644
index 0000000..4b22682
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/timestamp-array-builder.rb
@@ -0,0 +1,46 @@
+# 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 TimestampArrayBuilder
+    private
+    def unit_id
+      @unit_id ||= value_data_type.unit.nick.to_sym
+    end
+
+    def convert_to_arrow_value(value)
+      if value.respond_to?(:to_time) and not value.is_a?(Time)
+        value = value.to_time
+      end
+
+      if value.is_a?(Time)
+        case unit_id
+        when :second
+          value.to_i
+        when :milli
+          value.to_i * 1_000 + value.usec / 1_000
+        when :micro
+          value.to_i * 1_000_000 + value.usec
+        else
+          value.to_i * 1_000_000_000 + value.nsec
+        end
+      else
+        value
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/lib/arrow/timestamp-array.rb b/ruby/red-arrow/lib/arrow/timestamp-array.rb
new file mode 100644
index 0000000..6cffb8c
--- /dev/null
+++ b/ruby/red-arrow/lib/arrow/timestamp-array.rb
@@ -0,0 +1,54 @@
+# 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 TimestampArray
+    class << self
+      def new(unit, values)
+        data_type = TimestampDataType.new(unit)
+        builder = TimestampArrayBuilder.new(data_type)
+        builder.build(values)
+      end
+    end
+
+    def get_value(i)
+      to_time(get_raw_value(i))
+    end
+
+    def unit
+      @unit ||= value_data_type.unit
+    end
+
+    private
+    def unit_id
+      @unit_id ||= unit.nick.to_sym
+    end
+
+    def to_time(raw_value)
+      case unit_id
+      when :second
+        Time.at(raw_value)
+      when :milli
+        Time.at(*raw_value.divmod(1_000))
+      when :micro
+        Time.at(*raw_value.divmod(1_000_000))
+      else
+        Time.at(raw_value / 1_000_000_000.0)
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/red-arrow.gemspec b/ruby/red-arrow/red-arrow.gemspec
new file mode 100644
index 0000000..1bfaf9c
--- /dev/null
+++ b/ruby/red-arrow/red-arrow.gemspec
@@ -0,0 +1,54 @@
+# -*- ruby -*-
+#
+# 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.
+
+require_relative "version"
+
+Gem::Specification.new do |spec|
+  spec.name = "red-arrow"
+  version_components = [
+    Arrow::Version::MAJOR.to_s,
+    Arrow::Version::MINOR.to_s,
+    Arrow::Version::MICRO.to_s,
+    # "beta1",
+  ]
+  spec.version = version_components.join(".")
+  spec.homepage = "https://arrow.apache.org/"
+  spec.authors = ["Apache Arrow Developers"]
+  spec.email = ["dev@arrow.apache.org"]
+
+  spec.summary = "Red Arrow is the Ruby bindings of Apache Arrow"
+  spec.description =
+    "Apache Arrow is a common in-memory columnar data store. " +
+    "It's useful to share and process large data."
+  spec.license = "Apache-2.0"
+  spec.files = ["README.md", "Rakefile", "Gemfile", "#{spec.name}.gemspec"]
+  spec.files += Dir.glob("lib/**/*.rb")
+  spec.files += Dir.glob("image/*.*")
+  spec.files += Dir.glob("doc/text/*")
+  spec.test_files += Dir.glob("test/**/*")
+  spec.extensions = ["dependency-check/Rakefile"]
+
+  spec.add_runtime_dependency("gobject-introspection", ">= 3.1.1")
+  spec.add_runtime_dependency("pkg-config")
+  spec.add_runtime_dependency("native-package-installer")
+
+  spec.add_development_dependency("bundler")
+  spec.add_development_dependency("rake")
+  spec.add_development_dependency("test-unit")
+end
diff --git a/ruby/red-arrow/test/fixture/float-integer.csv b/ruby/red-arrow/test/fixture/float-integer.csv
new file mode 100644
index 0000000..5eae562
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/float-integer.csv
@@ -0,0 +1,20 @@
+# 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.
+score
+2.9
+10
+-1.1
diff --git a/ruby/red-arrow/test/fixture/integer-float.csv b/ruby/red-arrow/test/fixture/integer-float.csv
new file mode 100644
index 0000000..da76141
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/integer-float.csv
@@ -0,0 +1,20 @@
+# 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.
+score
+10
+2.9
+-1.1
diff --git a/ruby/red-arrow/test/fixture/null-with-double-quote.csv b/ruby/red-arrow/test/fixture/null-with-double-quote.csv
new file mode 100644
index 0000000..d845459
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/null-with-double-quote.csv
@@ -0,0 +1,20 @@
+# 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.
+name,score
+alice,10
+bob,""
+chris,-1
diff --git a/ruby/red-arrow/test/fixture/null-without-double-quote.csv b/ruby/red-arrow/test/fixture/null-without-double-quote.csv
new file mode 100644
index 0000000..c91c888
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/null-without-double-quote.csv
@@ -0,0 +1,20 @@
+# 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.
+name,score
+alice,10
+bob,
+chris,-1
diff --git a/ruby/red-arrow/test/fixture/with-header-float.csv b/ruby/red-arrow/test/fixture/with-header-float.csv
new file mode 100644
index 0000000..f62fc00
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/with-header-float.csv
@@ -0,0 +1,20 @@
+# 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.
+name,score
+alice,10.1
+bob,29.2
+chris,-1.3
diff --git a/ruby/red-arrow/test/fixture/with-header.csv b/ruby/red-arrow/test/fixture/with-header.csv
new file mode 100644
index 0000000..a93fc5a
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/with-header.csv
@@ -0,0 +1,20 @@
+# 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.
+name,score
+alice,10
+bob,29
+chris,-1
diff --git a/ruby/red-arrow/test/fixture/without-header-float.csv b/ruby/red-arrow/test/fixture/without-header-float.csv
new file mode 100644
index 0000000..584a209
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/without-header-float.csv
@@ -0,0 +1,19 @@
+# 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.
+alice,10.1
+bob,29.2
+chris,-1.3
diff --git a/ruby/red-arrow/test/fixture/without-header.csv b/ruby/red-arrow/test/fixture/without-header.csv
new file mode 100644
index 0000000..1f775ea
--- /dev/null
+++ b/ruby/red-arrow/test/fixture/without-header.csv
@@ -0,0 +1,19 @@
+# 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.
+alice,10
+bob,29
+chris,-1
diff --git a/ruby/red-arrow/test/helper.rb b/ruby/red-arrow/test/helper.rb
new file mode 100644
index 0000000..c51f8ba
--- /dev/null
+++ b/ruby/red-arrow/test/helper.rb
@@ -0,0 +1,27 @@
+# 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.
+
+require_relative "../version"
+
+require "arrow"
+
+require "pathname"
+require "tempfile"
+
+require "test-unit"
+
+require_relative "helper/fixture"
diff --git a/ruby/red-arrow/test/helper/fixture.rb b/ruby/red-arrow/test/helper/fixture.rb
new file mode 100644
index 0000000..24445a7
--- /dev/null
+++ b/ruby/red-arrow/test/helper/fixture.rb
@@ -0,0 +1,28 @@
+# 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 Helper
+  module Fixture
+    def fixture_dir
+      Pathname.new(__dir__).join("..", "fixture").expand_path
+    end
+
+    def fixture_path(*components)
+      fixture_dir.join(*components)
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/run-test.rb b/ruby/red-arrow/test/run-test.rb
new file mode 100755
index 0000000..957bb3a
--- /dev/null
+++ b/ruby/red-arrow/test/run-test.rb
@@ -0,0 +1,35 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+ENV["TZ"] = "Asia/Tokyo"
+
+$VERBOSE = true
+
+require "pathname"
+
+base_dir = Pathname.new(__dir__).parent.expand_path
+
+lib_dir = base_dir + "lib"
+test_dir = base_dir + "test"
+
+$LOAD_PATH.unshift(lib_dir.to_s)
+
+require_relative "helper"
+
+exit(Test::Unit::AutoRunner.run(true, test_dir.to_s))
diff --git a/ruby/red-arrow/test/test-array-builder.rb b/ruby/red-arrow/test/test-array-builder.rb
new file mode 100644
index 0000000..97badd1
--- /dev/null
+++ b/ruby/red-arrow/test/test-array-builder.rb
@@ -0,0 +1,112 @@
+# 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 ArrayBuilderTest < Test::Unit::TestCase
+  sub_test_case(".build") do
+    def assert_build(builder_class, raw_array)
+      array = builder_class.build(raw_array)
+      assert_equal(raw_array, array.to_a)
+    end
+
+    sub_test_case("generic builder") do
+      test("strings") do
+        assert_build(Arrow::ArrayBuilder,
+                     ["Hello", nil, "World"])
+      end
+
+      test("boolean") do
+        assert_build(Arrow::ArrayBuilder,
+                     [true, nil, false])
+      end
+
+      test("positive integers") do
+        assert_build(Arrow::ArrayBuilder,
+                     [1, nil, 2, nil, 3])
+      end
+
+      test("negative integers") do
+        assert_build(Arrow::ArrayBuilder,
+                     [nil, -1, nil, -2, nil, -3])
+      end
+
+      test("times") do
+        assert_build(Arrow::ArrayBuilder,
+                     [Time.at(0), Time.at(1), Time.at(2)])
+      end
+
+      test("dates") do
+        assert_build(Arrow::ArrayBuilder,
+                     [Date.new(2018, 1, 4), Date.new(2018, 1, 5)])
+      end
+
+      test("datetimes") do
+        assert_build(Arrow::ArrayBuilder,
+                     [
+                       DateTime.new(2018, 1, 4, 23, 18, 23),
+                       DateTime.new(2018, 1, 5, 0, 23, 21),
+                     ])
+      end
+    end
+
+    sub_test_case("specific builder") do
+      test("empty") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [])
+      end
+
+      test("values") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [1, -2])
+      end
+
+      test("values, nils") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [1, -2, nil, nil])
+      end
+
+      test("values, nils, values") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [1, -2, nil, nil, 3, -4])
+      end
+
+      test("values, nils, values, nils") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [1, -2, nil, nil, 3, -4, nil, nil])
+      end
+
+      test("nils") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [nil, nil])
+      end
+
+      test("nils, values") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [nil, nil, 3, -4])
+      end
+
+      test("nils, values, nil") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [nil, nil, 3, -4, nil, nil])
+      end
+
+      test("nils, values, nil, values") do
+        assert_build(Arrow::Int32ArrayBuilder,
+                     [nil, nil, 3, -4, nil, nil, 5, -6])
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-array.rb b/ruby/red-arrow/test/test-array.rb
new file mode 100644
index 0000000..31e6eaf
--- /dev/null
+++ b/ruby/red-arrow/test/test-array.rb
@@ -0,0 +1,38 @@
+# 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 ArrayTest < Test::Unit::TestCase
+  sub_test_case(".new") do
+    test("Boolean") do
+      array = Arrow::BooleanArray.new([true, false, true])
+      assert_equal([true, false, true],
+                   array.to_a)
+    end
+  end
+
+  test("#each") do
+    array = Arrow::BooleanArray.new([true, false, nil, true])
+    assert_equal([true, false, nil, true],
+                 array.to_a)
+  end
+
+  test("#[]") do
+    array = Arrow::BooleanArray.new([true, false, nil, true])
+    assert_equal([true, false, nil, true],
+                 [array[0], array[1], array[2], array[3]])
+  end
+end
diff --git a/ruby/red-arrow/test/test-chunked-array.rb b/ruby/red-arrow/test/test-chunked-array.rb
new file mode 100644
index 0000000..2344d80
--- /dev/null
+++ b/ruby/red-arrow/test/test-chunked-array.rb
@@ -0,0 +1,65 @@
+# 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 ChunkedArrayTest < Test::Unit::TestCase
+  test("#each") do
+    arrays = [
+      Arrow::BooleanArray.new([true, false]),
+      Arrow::BooleanArray.new([nil, true]),
+    ]
+    chunked_array = Arrow::ChunkedArray.new(arrays)
+    assert_equal([true, false, nil, true],
+                 chunked_array.to_a)
+  end
+
+  sub_test_case("#pack") do
+    test("basic array") do
+      arrays = [
+        Arrow::BooleanArray.new([true, false]),
+        Arrow::BooleanArray.new([nil, true]),
+      ]
+      chunked_array = Arrow::ChunkedArray.new(arrays)
+      packed_chunked_array = chunked_array.pack
+      assert_equal([
+                     Arrow::BooleanArray,
+                     [true, false, nil, true],
+                   ],
+                   [
+                     packed_chunked_array.class,
+                     packed_chunked_array.to_a,
+                   ])
+    end
+
+    test("TimestampArray") do
+      type = Arrow::TimestampDataType.new(:nano)
+      arrays = [
+        Arrow::TimestampArrayBuilder.new(type).build([Time.at(0)]),
+        Arrow::TimestampArrayBuilder.new(type).build([Time.at(1)]),
+      ]
+      chunked_array = Arrow::ChunkedArray.new(arrays)
+      packed_chunked_array = chunked_array.pack
+      assert_equal([
+                     Arrow::TimestampArray,
+                     [Time.at(0), Time.at(1)],
+                   ],
+                   [
+                     packed_chunked_array.class,
+                     packed_chunked_array.to_a,
+                   ])
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-column.rb b/ruby/red-arrow/test/test-column.rb
new file mode 100644
index 0000000..c6bf827
--- /dev/null
+++ b/ruby/red-arrow/test/test-column.rb
@@ -0,0 +1,43 @@
+# 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 ColumnTest < Test::Unit::TestCase
+  test("#each") do
+    arrays = [
+      Arrow::BooleanArray.new([true, false]),
+      Arrow::BooleanArray.new([nil, true]),
+    ]
+    chunked_array = Arrow::ChunkedArray.new(arrays)
+    column = Arrow::Column.new(Arrow::Field.new("visible", :boolean),
+                               chunked_array)
+    assert_equal([true, false, nil, true],
+                 column.to_a)
+  end
+
+  test("#pack") do
+    arrays = [
+      Arrow::BooleanArray.new([true, false]),
+      Arrow::BooleanArray.new([nil, true]),
+    ]
+    chunked_array = Arrow::ChunkedArray.new(arrays)
+    column = Arrow::Column.new(Arrow::Field.new("visible", :boolean),
+                               chunked_array)
+    packed_column = column.pack
+    assert_equal([1, [true, false, nil, true]],
+                 [packed_column.data.n_chunks, packed_column.to_a])
+  end
+end
diff --git a/ruby/red-arrow/test/test-csv-loader.rb b/ruby/red-arrow/test/test-csv-loader.rb
new file mode 100644
index 0000000..26ea497
--- /dev/null
+++ b/ruby/red-arrow/test/test-csv-loader.rb
@@ -0,0 +1,118 @@
+# 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 CSVLoaderTest < Test::Unit::TestCase
+  include Helper::Fixture
+
+  def load_csv(input)
+    Arrow::CSVLoader.load(input, skip_lines: /^#/)
+  end
+
+  sub_test_case(".load") do
+    test("String: data: with header") do
+      data = fixture_path("with-header-float.csv").read
+      assert_equal(<<-TABLE, load_csv(data).to_s)
+	name	     score
+0	alice	 10.100000
+1	bob 	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("String: data: without header") do
+      data = fixture_path("without-header-float.csv").read
+      assert_equal(<<-TABLE, load_csv(data).to_s)
+	0	         1
+0	alice	 10.100000
+1	bob	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("String: path: with header") do
+      path = fixture_path("with-header-float.csv").to_s
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	name	     score
+0	alice	 10.100000
+1	bob 	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("String: path: without header") do
+      path = fixture_path("without-header-float.csv").to_s
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	0	         1
+0	alice	 10.100000
+1	bob	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("Pathname: with header") do
+      path = fixture_path("with-header-float.csv")
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	name	     score
+0	alice	 10.100000
+1	bob 	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("Pathname: without header") do
+      path = fixture_path("without-header-float.csv")
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	0	         1
+0	alice	 10.100000
+1	bob	 29.200000
+2	chris	 -1.300000
+      TABLE
+    end
+
+    test("null: with double quote") do
+      path = fixture_path("null-with-double-quote.csv").to_s
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	name	score
+0	alice	   10
+1	bob 	     
+2	chris	   -1
+      TABLE
+    end
+
+    test("null: without double quote") do
+      path = fixture_path("null-without-double-quote.csv").to_s
+      assert_equal(<<-TABLE, load_csv(path).to_s)
+	name	score
+0	alice	   10
+1	bob 	     
+2	chris	   -1
+      TABLE
+    end
+
+    test("number: float, integer") do
+      path = fixture_path("float-integer.csv").to_s
+      assert_equal([2.9, 10, -1.1],
+                   load_csv(path)[:score].to_a)
+    end
+
+    test("number: integer, float") do
+      path = fixture_path("integer-float.csv").to_s
+      assert_equal([10.0, 2.9, -1.1],
+                   load_csv(path)[:score].to_a)
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-csv-reader.rb b/ruby/red-arrow/test/test-csv-reader.rb
new file mode 100644
index 0000000..765a178
--- /dev/null
+++ b/ruby/red-arrow/test/test-csv-reader.rb
@@ -0,0 +1,34 @@
+# 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 CSVReaderTest < Test::Unit::TestCase
+  include Helper::Fixture
+
+  test("#read") do
+    CSV.open(fixture_path("with-header.csv").to_s,
+             headers: true,
+             skip_lines: /^#/) do |csv|
+      reader = Arrow::CSVReader.new(csv)
+      assert_equal(<<-TABLE, reader.read.to_s)
+	name	score
+0	alice	10   
+1	bob 	29   
+2	chris	-1   
+      TABLE
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-date32-array.rb b/ruby/red-arrow/test/test-date32-array.rb
new file mode 100644
index 0000000..6918b48
--- /dev/null
+++ b/ruby/red-arrow/test/test-date32-array.rb
@@ -0,0 +1,24 @@
+# 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 Date32ArrayTest < Test::Unit::TestCase
+  test("#[]") do
+    n_days_since_epoch = 17406 # 2017-08-28
+    array = Arrow::Date32Array.new([n_days_since_epoch])
+    assert_equal(Date.new(2017, 8, 28), array[0])
+  end
+end
diff --git a/ruby/red-arrow/test/test-date64-array.rb b/ruby/red-arrow/test/test-date64-array.rb
new file mode 100644
index 0000000..ec1c6db
--- /dev/null
+++ b/ruby/red-arrow/test/test-date64-array.rb
@@ -0,0 +1,25 @@
+# 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 Date64ArrayTest < Test::Unit::TestCase
+  test("#[]") do
+    n_msecs_since_epoch = 1503878400000 # 2017-08-28T00:00:00Z
+    array = Arrow::Date64Array.new([n_msecs_since_epoch])
+    assert_equal(DateTime.new(2017, 8, 28, 0, 0, 0),
+                 array[0])
+  end
+end
diff --git a/ruby/red-arrow/test/test-group.rb b/ruby/red-arrow/test/test-group.rb
new file mode 100644
index 0000000..5e7aabf
--- /dev/null
+++ b/ruby/red-arrow/test/test-group.rb
@@ -0,0 +1,156 @@
+# 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 GroupTest < Test::Unit::TestCase
+  include Helper::Fixture
+
+  def setup
+    raw_table = {
+      :group_key1 => Arrow::UInt8Array.new([1, 1, 2, 3, 3, 3]),
+      :group_key2 => Arrow::UInt8Array.new([1, 1, 1, 1, 2, 2]),
+      :int => Arrow::Int32Array.new([-1, -2, nil, -4, -5, -6]),
+      :uint => Arrow::UInt32Array.new([1, nil, 3, 4, 5, 6]),
+      :float => Arrow::FloatArray.new([nil, 2.2, 3.3, 4.4, 5.5, 6.6]),
+      :string => Arrow::StringArray.new(["a", "b", "c", nil, "e", "f"]),
+    }
+    @table = Arrow::Table.new(raw_table)
+  end
+
+  sub_test_case("key") do
+    test("Time") do
+      time_values = [
+        Time.parse("2018-01-29"),
+        Time.parse("2018-01-30"),
+      ]
+      raw_table = {
+        :time => Arrow::ArrayBuilder.build(time_values),
+        :int => Arrow::Int32Array.new([-1, -2]),
+      }
+      table = Arrow::Table.new(raw_table)
+      assert_equal(<<-TABLE, table.group(:time).count.to_s)
+	                     time	int
+0	2018-01-29T00:00:00+09:00	  1
+1	2018-01-30T00:00:00+09:00	  1
+      TABLE
+    end
+  end
+
+  sub_test_case("#count") do
+    test("single") do
+      assert_equal(<<-TABLE, @table.group(:group_key1).count.to_s)
+	group_key1	group_key2	int	uint	float	string
+0	         1	         2	  2	   1	    1	     2
+1	         2	         1	  0	   1	    1	     1
+2	         3	         3	  3	   3	    3	     2
+      TABLE
+    end
+
+    test("multiple") do
+      assert_equal(<<-TABLE, @table.group(:group_key1, :group_key2).count.to_s)
+	group_key1	group_key2	int	uint	float	string
+0	         1	         1	  2	   1	    1	     2
+1	         2	         1	  0	   1	    1	     1
+2	         3	         1	  1	   1	    1	     0
+3	         3	         2	  2	   2	    2	     2
+      TABLE
+    end
+  end
+
+  sub_test_case("#sum") do
+    test("single") do
+      assert_equal(<<-TABLE, @table.group(:group_key1).sum.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         2	 -3	   1	  2.200000
+1	         2	         1	  0	   3	  3.300000
+2	         3	         5	-15	  15	 16.500000
+      TABLE
+    end
+
+    test("multiple") do
+      assert_equal(<<-TABLE, @table.group(:group_key1, :group_key2).sum.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         1	 -3	   1	  2.200000
+1	         2	         1	  0	   3	  3.300000
+2	         3	         1	 -4	   4	  4.400000
+3	         3	         2	-11	  11	 12.100000
+      TABLE
+    end
+  end
+
+  sub_test_case("#average") do
+    test("single") do
+      assert_equal(<<-TABLE, @table.group(:group_key1).average.to_s)
+	group_key1	group_key2	       int	      uint	     float
+0	         1	  1.000000	 -1.500000	  1.000000	  2.200000
+1	         2	  1.000000	  0.000000	  3.000000	  3.300000
+2	         3	  1.666667	 -5.000000	  5.000000	  5.500000
+      TABLE
+    end
+
+    test("multiple") do
+      assert_equal(<<-TABLE, @table.group(:group_key1, :group_key2).average.to_s)
+	group_key1	group_key2	       int	      uint	     float
+0	         1	         1	 -1.500000	  1.000000	  2.200000
+1	         2	         1	  0.000000	  3.000000	  3.300000
+2	         3	         1	 -4.000000	  4.000000	  4.400000
+3	         3	         2	 -5.500000	  5.500000	  6.050000
+      TABLE
+    end
+  end
+
+  sub_test_case("#min") do
+    test("single") do
+      assert_equal(<<-TABLE, @table.group(:group_key1).min.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         1	 -2	   1	  2.200000
+1	         2	         1	   	   3	  3.300000
+2	         3	         1	 -6	   4	  4.400000
+      TABLE
+    end
+
+    test("multiple") do
+      assert_equal(<<-TABLE, @table.group(:group_key1, :group_key2).min.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         1	 -2	   1	  2.200000
+1	         2	         1	   	   3	  3.300000
+2	         3	         1	 -4	   4	  4.400000
+3	         3	         2	 -6	   5	  5.500000
+      TABLE
+    end
+  end
+
+  sub_test_case("#max") do
+    test("single") do
+      assert_equal(<<-TABLE, @table.group(:group_key1).max.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         1	 -1	   1	  2.200000
+1	         2	         1	   	   3	  3.300000
+2	         3	         2	 -4	   6	  6.600000
+      TABLE
+    end
+
+    test("multiple") do
+      assert_equal(<<-TABLE, @table.group(:group_key1, :group_key2).max.to_s)
+	group_key1	group_key2	int	uint	     float
+0	         1	         1	 -1	   1	  2.200000
+1	         2	         1	   	   3	  3.300000
+2	         3	         1	 -4	   4	  4.400000
+3	         3	         2	 -5	   6	  6.600000
+      TABLE
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-record-batch-file-reader.rb b/ruby/red-arrow/test/test-record-batch-file-reader.rb
new file mode 100644
index 0000000..57b02ab
--- /dev/null
+++ b/ruby/red-arrow/test/test-record-batch-file-reader.rb
@@ -0,0 +1,115 @@
+# 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 RecordBatchFileReaderTest < Test::Unit::TestCase
+  test("write/read") do
+    fields = [
+      Arrow::Field.new("uint8",  :uint8),
+      Arrow::Field.new("uint16", :uint16),
+      Arrow::Field.new("uint32", :uint32),
+      Arrow::Field.new("uint64", :uint64),
+      Arrow::Field.new("int8",   :int8),
+      Arrow::Field.new("int16",  :int16),
+      Arrow::Field.new("int32",  :int32),
+      Arrow::Field.new("int64",  :int64),
+      Arrow::Field.new("float",  :float),
+      Arrow::Field.new("double", :double),
+    ]
+    schema = Arrow::Schema.new(fields)
+
+    tempfile = Tempfile.new(["batch", ".arrow"])
+    Arrow::FileOutputStream.open(tempfile.path, false) do |output|
+      Arrow::RecordBatchFileWriter.open(output, schema) do |writer|
+        uints = [1, 2, 4, 8]
+        ints = [1, -2, 4, -8]
+        floats = [1.1, -2.2, 4.4, -8.8]
+        columns = [
+          Arrow::UInt8Array.new(uints),
+          Arrow::UInt16Array.new(uints),
+          Arrow::UInt32Array.new(uints),
+          Arrow::UInt64Array.new(uints),
+          Arrow::Int8Array.new(ints),
+          Arrow::Int16Array.new(ints),
+          Arrow::Int32Array.new(ints),
+          Arrow::Int64Array.new(ints),
+          Arrow::FloatArray.new(floats),
+          Arrow::DoubleArray.new(floats),
+        ]
+
+        record_batch = Arrow::RecordBatch.new(schema, 4, columns)
+        writer.write_record_batch(record_batch)
+      end
+    end
+
+    Arrow::MemoryMappedInputStream.open(tempfile.path) do |input|
+      reader = Arrow::RecordBatchFileReader.new(input)
+      reader.each do |record_batch|
+        assert_equal([
+                       {
+                         "uint8"  => 1,
+                         "uint16" => 1,
+                         "uint32" => 1,
+                         "uint64" => 1,
+                         "int8"   => 1,
+                         "int16"  => 1,
+                         "int32"  => 1,
+                         "int64"  => 1,
+                         "float"  => 1.100000023841858,
+                         "double" => 1.1,
+                       },
+                       {
+                         "uint8"  => 2,
+                         "uint16" => 2,
+                         "uint32" => 2,
+                         "uint64" => 2,
+                         "int8"   => -2,
+                         "int16"  => -2,
+                         "int32"  => -2,
+                         "int64"  => -2,
+                         "float"  => -2.200000047683716,
+                         "double" => -2.2,
+                       },
+                       {
+                         "uint8"  => 4,
+                         "uint16" => 4,
+                         "uint32" => 4,
+                         "uint64" => 4,
+                         "int8"   => 4,
+                         "int16"  => 4,
+                         "int32"  => 4,
+                         "int64"  => 4,
+                         "float"  => 4.400000095367432,
+                         "double" => 4.4,
+                       },
+                       {
+                         "uint8"  => 8,
+                         "uint16" => 8,
+                         "uint32" => 8,
+                         "uint64" => 8,
+                         "int8"   => -8,
+                         "int16"  => -8,
+                         "int32"  => -8,
+                         "int64"  => -8,
+                         "float"  => -8.800000190734863,
+                         "double" => -8.8,
+                       },
+                     ],
+                     record_batch.collect(&:to_h))
+      end
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-record-batch.rb b/ruby/red-arrow/test/test-record-batch.rb
new file mode 100644
index 0000000..994b16d
--- /dev/null
+++ b/ruby/red-arrow/test/test-record-batch.rb
@@ -0,0 +1,57 @@
+# 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 RecordBatchTest < Test::Unit::TestCase
+  sub_test_case(".each") do
+    setup do
+      fields = [
+        Arrow::Field.new("count", :uint32),
+      ]
+      @schema = Arrow::Schema.new(fields)
+      @counts = Arrow::UInt32Array.new([1, 2, 4, 8])
+      @record_batch = Arrow::RecordBatch.new(@schema, @counts.length, [@counts])
+    end
+
+    test("default") do
+      records = []
+      @record_batch.each do |record|
+        records << [record, record.index]
+      end
+      assert_equal([
+                     [0, 0],
+                     [1, 1],
+                     [2, 2],
+                     [3, 3],
+                   ],
+                   records.collect {|record, i| [record.index, i]})
+    end
+
+    test("reuse_record: true") do
+      records = []
+      @record_batch.each(reuse_record: true) do |record|
+        records << [record, record.index]
+      end
+      assert_equal([
+                     [3, 0],
+                     [3, 1],
+                     [3, 2],
+                     [3, 3],
+                   ],
+                   records.collect {|record, i| [record.index, i]})
+    end
+  end
+end
diff --git a/ruby/red-arrow/test/test-rolling-window.rb b/ruby/red-arrow/test/test-rolling-window.rb
new file mode 100644
index 0000000..497a083
--- /dev/null
+++ b/ruby/red-arrow/test/test-rolling-window.rb
@@ -0,0 +1,33 @@
+# 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 RollingWindowTest < Test::Unit::TestCase
+  include Helper::Fixture
+
+  def setup
+    raw_table = {
+      :number => Arrow::Int32Array.new([1, -2, nil, 4, 6, 3]),
+    }
+    @table = Arrow::Table.new(raw_table)
+  end
+
+  test("#lag") do
+    assert_equal(<<-ARRAY.chomp, @table.window.lag(:number).to_s)
+[null, -3, null, null, 2, -3]
+    ARRAY
+  end
+end
diff --git a/ruby/red-arrow/test/test-slicer.rb b/ruby/red-arrow/test/test-slicer.rb
new file mode 100644
index 0000000..ba035b6
--- /dev/null
+++ b/ruby/red-arrow/test/test-slicer.rb
@@ -0,0 +1,446 @@
+# 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 SlicerTest < Test::Unit::TestCase
+  def setup
+    @count_field = Arrow::Field.new("count", :uint32)
+    @visible_field = Arrow::Field.new("visible", :boolean)
+    schema = Arrow::Schema.new([@count_field, @visible_field])
+    count_arrays = [
+      Arrow::UInt32Array.new([0, 1, 2]),
+      Arrow::UInt32Array.new([4, 8, 16]),
+      Arrow::UInt32Array.new([32, 64, nil]),
+      Arrow::UInt32Array.new([256]),
+    ]
+    visible_arrays = [
+      Arrow::BooleanArray.new([nil, true, false, nil]),
+      Arrow::BooleanArray.new([true]),
+      Arrow::BooleanArray.new([true, false]),
+      Arrow::BooleanArray.new([nil]),
+      Arrow::BooleanArray.new([nil]),
+      Arrow::BooleanArray.new([true]),
+    ]
+    @count_array = Arrow::ChunkedArray.new(count_arrays)
+    @visible_array = Arrow::ChunkedArray.new(visible_arrays)
+    @count_column = Arrow::Column.new(@count_field, @count_array)
+    @visible_column = Arrow::Column.new(@visible_field, @visible_array)
+    @table = Arrow::Table.new(schema, [@count_column, @visible_column])
+  end
+
+  sub_test_case("column") do
+    test("BooleanArray") do
+      sliced_table = @table.slice do |slicer|
+        slicer.visible
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    8	true   
+2	   16	true   
+3	  256	true   
+      TABLE
+    end
+
+    test("not BooleanArray") do
+      sliced_table = @table.slice do |slicer|
+        slicer.count
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    2	false  
+2	    4	       
+3	    8	true   
+4	   16	true   
+5	   32	false  
+6	   64	       
+7	  256	true   
+      TABLE
+    end
+  end
+
+  sub_test_case("!column") do
+    test("BooleanArray") do
+      sliced_table = @table.slice do |slicer|
+        !slicer.visible
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    2	false  
+1	   32	false  
+      TABLE
+    end
+
+    test("not BooleanArray") do
+      sliced_table = @table.slice do |slicer|
+        !slicer.count
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+      TABLE
+    end
+  end
+
+  test("column.null?") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible.null?
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    4	       
+2	   64	       
+3	     	       
+    TABLE
+  end
+
+  test("column.valid?") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible.valid?
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    2	false  
+2	    8	true   
+3	   16	true   
+4	   32	false  
+5	  256	true   
+    TABLE
+  end
+
+  sub_test_case("column ==") do
+    test("nil") do
+      sliced_table = @table.slice do |slicer|
+        slicer.visible == nil
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    4	       
+2	   64	       
+3	     	       
+      TABLE
+    end
+
+    test("value") do
+      sliced_table = @table.slice do |slicer|
+        slicer.visible == true
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    8	true   
+2	   16	true   
+3	  256	true   
+      TABLE
+    end
+  end
+
+  sub_test_case("!(column ==)") do
+    test("nil") do
+      sliced_table = @table.slice do |slicer|
+        !(slicer.visible == nil)
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    2	false  
+2	    8	true   
+3	   16	true   
+4	   32	false  
+5	  256	true   
+      TABLE
+    end
+
+    test("value") do
+      sliced_table = @table.slice do |slicer|
+        !(slicer.visible == true)
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    2	false  
+1	   32	false  
+      TABLE
+    end
+  end
+
+  sub_test_case("column !=") do
+    test("nil") do
+      sliced_table = @table.slice do |slicer|
+        slicer.visible != nil
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    2	false  
+2	    8	true   
+3	   16	true   
+4	   32	false  
+5	  256	true   
+      TABLE
+    end
+
+    test("value") do
+      sliced_table = @table.slice do |slicer|
+        slicer.visible != true
+      end
+      assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    2	false  
+1	   32	false  
+      TABLE
+    end
+  end
+
+  test("column < value") do
+    sliced_table = @table.slice do |slicer|
+      slicer.count < 16
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    2	false  
+3	    4	       
+4	    8	true   
+    TABLE
+  end
+
+  test("!(column < value)") do
+    sliced_table = @table.slice do |slicer|
+      !(slicer.count < 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	   16	true   
+1	   32	false  
+2	   64	       
+3	  256	true   
+    TABLE
+  end
+
+  test("column <= value") do
+    sliced_table = @table.slice do |slicer|
+      slicer.count <= 16
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    2	false  
+3	    4	       
+4	    8	true   
+5	   16	true   
+    TABLE
+  end
+
+  test("!(column <= value)") do
+    sliced_table = @table.slice do |slicer|
+      !(slicer.count <= 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	   32	false  
+1	   64	       
+2	  256	true   
+    TABLE
+  end
+
+  test("column > value") do
+    sliced_table = @table.slice do |slicer|
+      slicer.count > 16
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	   32	false  
+1	   64	       
+2	  256	true   
+    TABLE
+  end
+
+  test("!(column > value)") do
+    sliced_table = @table.slice do |slicer|
+      !(slicer.count > 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    2	false  
+3	    4	       
+4	    8	true   
+5	   16	true   
+    TABLE
+  end
+
+  test("column >= value") do
+    sliced_table = @table.slice do |slicer|
+      slicer.count >= 16
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	   16	true   
+1	   32	false  
+2	   64	       
+3	  256	true   
+    TABLE
+  end
+
+  test("!(column >= value)") do
+    sliced_table = @table.slice do |slicer|
+      !(slicer.count >= 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    2	false  
+3	    4	       
+4	    8	true   
+    TABLE
+  end
+
+  test("column.in") do
+    sliced_table = @table.slice do |slicer|
+      slicer.count.in?([1, 4, 16, 64])
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    4	       
+2	   16	true   
+3	   64	       
+    TABLE
+  end
+
+  test("!column.in") do
+    sliced_table = @table.slice do |slicer|
+      !slicer.count.in?([1, 4, 16, 64])
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    2	false  
+2	    8	true   
+3	   32	false  
+4	  256	true   
+    TABLE
+  end
+
+  test("condition & condition") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible & (slicer.count >= 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	   16	true   
+1	  256	true   
+    TABLE
+  end
+
+  test("condition | condition") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible | (slicer.count >= 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    8	true   
+2	   16	true   
+3	   32	false  
+4	  256	true   
+    TABLE
+  end
+
+  test("condition ^ condition") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible ^ (slicer.count >= 16)
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    1	true   
+1	    8	true   
+2	   32	false  
+    TABLE
+  end
+
+  test("select") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible.select do |value|
+        value.nil? or value
+      end
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    4	       
+3	    8	true   
+4	   16	true   
+5	   64	       
+6	     	       
+7	  256	true   
+    TABLE
+  end
+
+  test("!select") do
+    sliced_table = @table.slice do |slicer|
+      !slicer.visible.select do |value|
+        value.nil? or value
+      end
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    2	false  
+1	   32	false  
+    TABLE
+  end
+
+  test("reject") do
+    sliced_table = @table.slice do |slicer|
+      slicer.visible.reject do |value|
+        value.nil? or value
+      end
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    2	false  
+1	   32	false  
+    TABLE
+  end
+
+  test("!reject") do
+    sliced_table = @table.slice do |slicer|
+      !slicer.visible.reject do |value|
+        value.nil? or value
+      end
+    end
+    assert_equal(<<-TABLE, sliced_table.to_s)
+	count	visible
+0	    0	       
+1	    1	true   
+2	    4	       
+3	    8	true   
+4	   16	true   
+5	   64	       
+6	     	       
+7	  256	true   
+    TABLE
+  end
+end
diff --git a/ruby/red-arrow/test/test-table.rb b/ruby/red-arrow/test/test-table.rb
new file mode 100644
index 0000000..65cc2a1
--- /dev/null
+++ b/ruby/red-arrow/test/test-table.rb
@@ -0,0 +1,464 @@
+# 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 TableTest < Test::Unit::TestCase
+  include Helper::Fixture
+
+  def setup
+    @count_field = Arrow::Field.new("count", :uint8)
+    @visible_field = Arrow::Field.new("visible", :boolean)
+    schema = Arrow::Schema.new([@count_field, @visible_field])
+    count_arrays = [
+      Arrow::UInt8Array.new([1, 2]),
+      Arrow::UInt8Array.new([4, 8, 16]),
+      Arrow::UInt8Array.new([32, 64]),
+      Arrow::UInt8Array.new([128]),
+    ]
+    visible_arrays = [
+      Arrow::BooleanArray.new([true, false, nil]),
+      Arrow::BooleanArray.new([true]),
+      Arrow::BooleanArray.new([true, false]),
+      Arrow::BooleanArray.new([nil]),
+      Arrow::BooleanArray.new([nil]),
+    ]
+    @count_array = Arrow::ChunkedArray.new(count_arrays)
+    @visible_array = Arrow::ChunkedArray.new(visible_arrays)
+    @count_column = Arrow::Column.new(@count_field, @count_array)
+    @visible_column = Arrow::Column.new(@visible_field, @visible_array)
+    @table = Arrow::Table.new(schema, [@count_column, @visible_column])
+  end
+
+  test("#columns") do
+    assert_equal(["count", "visible"],
+                 @table.columns.collect(&:name))
+  end
+
+  sub_test_case("#slice") do
+    test("Arrow::BooleanArray") do
+      target_rows_raw = [nil, true, true, false, true, false, true, true]
+      target_rows = Arrow::BooleanArray.new(target_rows_raw)
+      assert_equal(<<-TABLE, @table.slice(target_rows).to_s)
+	count	visible
+0	    2	false  
+1	    4	       
+2	   16	true   
+3	   64	       
+4	  128	       
+      TABLE
+    end
+
+    test("Array: boolean") do
+      target_rows_raw = [nil, true, true, false, true, false, true, true]
+      assert_equal(<<-TABLE, @table.slice(target_rows_raw).to_s)
+	count	visible
+0	    2	false  
+1	    4	       
+2	   16	true   
+3	   64	       
+4	  128	       
+      TABLE
+    end
+
+    test("Integer: positive") do
+      assert_equal(<<-TABLE, @table.slice(2).to_s)
+	count	visible
+0	    4	       
+      TABLE
+    end
+
+    test("Integer: negative") do
+      assert_equal(<<-TABLE, @table.slice(-1).to_s)
+	count	visible
+0	  128	       
+      TABLE
+    end
+
+    test("Range: positive: include end") do
+      assert_equal(<<-TABLE, @table.slice(2..4).to_s)
+	count	visible
+0	    4	       
+1	    8	true   
+2	   16	true   
+      TABLE
+    end
+
+    test("Range: positive: exclude end") do
+      assert_equal(<<-TABLE, @table.slice(2...4).to_s)
+	count	visible
+0	    4	       
+1	    8	true   
+      TABLE
+    end
+
+    test("Range: negative: include end") do
+      assert_equal(<<-TABLE, @table.slice(-4..-2).to_s)
+	count	visible
+0	   16	true   
+1	   32	false  
+2	   64	       
+      TABLE
+    end
+
+    test("Range: negative: exclude end") do
+      assert_equal(<<-TABLE, @table.slice(-4...-2).to_s)
+	count	visible
+0	   16	true   
+1	   32	false  
+      TABLE
+    end
+
+    test("[from, to]: positive") do
+      assert_equal(<<-TABLE, @table.slice(0, 2).to_s)
+	count	visible
+0	    1	true   
+1	    2	false  
+      TABLE
+    end
+
+    test("[from, to]: negative") do
+      assert_equal(<<-TABLE, @table.slice(-4, 2).to_s)
+	count	visible
+0	   16	true   
+1	   32	false  
+      TABLE
+    end
+
+    sub_test_case("wrong argument") do
+      test("no arguments") do
+        message = "wrong number of arguments (given 0, expected 1..2)"
+        assert_raise(ArgumentError.new(message)) do
+          @table.slice
+        end
+      end
+
+      test("too many arguments: with block") do
+        message = "wrong number of arguments (given 3, expected 1..2)"
+        assert_raise(ArgumentError.new(message)) do
+          @table.slice(1, 2, 3)
+        end
+      end
+
+      test("too many arguments: without block") do
+        message = "wrong number of arguments (given 3, expected 0..2)"
+        assert_raise(ArgumentError.new(message)) do
+          @table.slice(1, 2, 3) {}
+        end
+      end
+    end
+  end
+
+  sub_test_case("#[]") do
+    test("[String]") do
+      assert_equal(@count_column, @table["count"])
+    end
+
+    test("[Symbol]") do
+      assert_equal(@visible_column, @table[:visible])
+    end
+  end
+
+  sub_test_case("#merge") do
+    sub_test_case("Hash") do
+      test("add") do
+        name_array = Arrow::StringArray.new(["a", "b", "c", "d", "e", "f", "g", "h"])
+        assert_equal(<<-TABLE, @table.merge(:name => name_array).to_s)
+	count	visible	name
+0	    1	true   	a   
+1	    2	false  	b   
+2	    4	       	c   
+3	    8	true   	d   
+4	   16	true   	e   
+5	   32	false  	f   
+6	   64	       	g   
+7	  128	       	h   
+        TABLE
+      end
+
+      test("remove") do
+        assert_equal(<<-TABLE, @table.merge(:visible => nil).to_s)
+	count
+0	    1
+1	    2
+2	    4
+3	    8
+4	   16
+5	   32
+6	   64
+7	  128
+        TABLE
+      end
+
+      test("replace") do
+        visible_array = Arrow::Int32Array.new([1] * @visible_array.length)
+        assert_equal(<<-TABLE, @table.merge(:visible => visible_array).to_s)
+	count	visible
+0	    1	      1
+1	    2	      1
+2	    4	      1
+3	    8	      1
+4	   16	      1
+5	   32	      1
+6	   64	      1
+7	  128	      1
+        TABLE
+      end
+    end
+
+    sub_test_case("Arrow::Table") do
+      test("add") do
+        name_array = Arrow::StringArray.new(["a", "b", "c", "d", "e", "f", "g", "h"])
+        table = Arrow::Table.new("name" => name_array)
+        assert_equal(<<-TABLE, @table.merge(table).to_s)
+	count	visible	name
+0	    1	true   	a   
+1	    2	false  	b   
+2	    4	       	c   
+3	    8	true   	d   
+4	   16	true   	e   
+5	   32	false  	f   
+6	   64	       	g   
+7	  128	       	h   
+        TABLE
+      end
+
+      test("replace") do
+        visible_array = Arrow::Int32Array.new([1] * @visible_array.length)
+        table = Arrow::Table.new("visible" => visible_array)
+        assert_equal(<<-TABLE, @table.merge(table).to_s)
+	count	visible
+0	    1	      1
+1	    2	      1
+2	    4	      1
+3	    8	      1
+4	   16	      1
+5	   32	      1
+6	   64	      1
+7	  128	      1
+        TABLE
+      end
+    end
+  end
+
+  test("column name getter") do
+    assert_equal(@visible_column, @table.visible)
+  end
+
+  sub_test_case("#remove_column") do
+    test("String") do
+      assert_equal(<<-TABLE, @table.remove_column("visible").to_s)
+	count
+0	    1
+1	    2
+2	    4
+3	    8
+4	   16
+5	   32
+6	   64
+7	  128
+      TABLE
+    end
+
+    test("Symbol") do
+      assert_equal(<<-TABLE, @table.remove_column(:visible).to_s)
+	count
+0	    1
+1	    2
+2	    4
+3	    8
+4	   16
+5	   32
+6	   64
+7	  128
+      TABLE
+    end
+
+    test("unknown column name") do
+      assert_raise(KeyError) do
+        @table.remove_column(:nonexistent)
+      end
+    end
+
+    test("Integer") do
+      assert_equal(<<-TABLE, @table.remove_column(1).to_s)
+	count
+0	    1
+1	    2
+2	    4
+3	    8
+4	   16
+5	   32
+6	   64
+7	  128
+      TABLE
+    end
+
+    test("negative integer") do
+      assert_equal(<<-TABLE, @table.remove_column(-1).to_s)
+	count
+0	    1
+1	    2
+2	    4
+3	    8
+4	   16
+5	   32
+6	   64
+7	  128
+      TABLE
+    end
+
+    test("too small index") do
+      assert_raise(IndexError) do
+        @table.remove_column(-3)
+      end
+    end
+
+    test("too large index") do
+      assert_raise(IndexError) do
+        @table.remove_column(2)
+      end
+    end
+  end
+
+  sub_test_case("#select_columns") do
+    def setup
+      raw_table = {
+        :a => Arrow::UInt8Array.new([1]),
+        :b => Arrow::UInt8Array.new([1]),
+        :c => Arrow::UInt8Array.new([1]),
+        :d => Arrow::UInt8Array.new([1]),
+        :e => Arrow::UInt8Array.new([1]),
+      }
+      @table = Arrow::Table.new(raw_table)
+    end
+
+    test("names") do
+      assert_equal(<<-TABLE, @table.select_columns(:c, :a).to_s)
+	c	a
+0	1	1
+      TABLE
+    end
+
+    test("range") do
+      assert_equal(<<-TABLE, @table.select_columns(2...4).to_s)
+	c	d
+0	1	1
+      TABLE
+    end
+
+    test("indexes") do
+      assert_equal(<<-TABLE, @table.select_columns(0, -1, 2).to_s)
+	a	e	c
+0	1	1	1
+      TABLE
+    end
+
+    test("mixed") do
+      assert_equal(<<-TABLE, @table.select_columns(:a, -1, 2..3).to_s)
+	a	e	c	d
+0	1	1	1	1
+      TABLE
+    end
+
+    test("block") do
+      selected_table = @table.select_columns.with_index do |column, i|
+        column.name == "a" or i.odd?
+      end
+      assert_equal(<<-TABLE, selected_table.to_s)
+	a	b	d
+0	1	1	1
+      TABLE
+    end
+
+    test("names, indexes and block") do
+      selected_table = @table.select_columns(:a, -1) do |column|
+        column.name == "a"
+      end
+      assert_equal(<<-TABLE, selected_table.to_s)
+	a
+0	1
+      TABLE
+    end
+  end
+
+  sub_test_case("#save and .load") do
+    sub_test_case(":format") do
+      test("default") do
+        file = Tempfile.new(["red-arrow", ".arrow"])
+        @table.save(file.path)
+        assert_equal(@table, Arrow::Table.load(file.path))
+      end
+
+      test(":batch") do
+        file = Tempfile.new(["red-arrow", ".arrow"])
+        @table.save(file.path, :format => :batch)
+        assert_equal(@table, Arrow::Table.load(file.path, :format => :batch))
+      end
+
+      test(":stream") do
+        file = Tempfile.new(["red-arrow", ".arrow"])
+        @table.save(file.path, :format => :stream)
+        assert_equal(@table, Arrow::Table.load(file.path, :format => :stream))
+      end
+
+      test(":csv") do
+        file = Tempfile.new(["red-arrow", ".csv"])
+        @table.save(file.path, :format => :csv)
+        assert_equal(@table, Arrow::Table.load(file.path, :format => :csv))
+      end
+
+      sub_test_case("load: auto detect") do
+        test(":batch") do
+          file = Tempfile.new(["red-arrow", ".arrow"])
+          @table.save(file.path, :format => :batch)
+          assert_equal(@table, Arrow::Table.load(file.path))
+        end
+
+        test(":stream") do
+          file = Tempfile.new(["red-arrow", ".arrow"])
+          @table.save(file.path, :format => :stream)
+          assert_equal(@table, Arrow::Table.load(file.path))
+        end
+
+        test(":csv") do
+          path = fixture_path("with-header.csv")
+          assert_equal(<<-TABLE, Arrow::Table.load(path, skip_lines: /^#/).to_s)
+	name	score
+0	alice	   10
+1	bob 	   29
+2	chris	   -1
+          TABLE
+        end
+      end
+    end
+  end
+
+  test("#pack") do
+    packed_table = @table.pack
+    column_n_chunks = packed_table.columns.collect {|c| c.data.n_chunks}
+    assert_equal([[1, 1], <<-TABLE], [column_n_chunks, packed_table.to_s])
+	count	visible
+0	    1	true   
+1	    2	false  
+2	    4	       
+3	    8	true   
+4	   16	true   
+5	   32	false  
+6	   64	       
+7	  128	       
+    TABLE
+  end
+end
diff --git a/ruby/red-arrow/test/test-timestamp-array.rb b/ruby/red-arrow/test/test-timestamp-array.rb
new file mode 100644
index 0000000..b24f8d4
--- /dev/null
+++ b/ruby/red-arrow/test/test-timestamp-array.rb
@@ -0,0 +1,26 @@
+# 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 TimestampArrayTest < Test::Unit::TestCase
+  test("#[]") do
+    sec = 1513267750
+    usec = 914509
+    array = Arrow::TimestampArray.new(:micro, [sec * (10 ** 6) + usec])
+    time = Time.at(sec, usec)
+    assert_equal(time, array[0])
+  end
+end
diff --git a/ruby/red-arrow/version.rb b/ruby/red-arrow/version.rb
new file mode 100644
index 0000000..e8f043f
--- /dev/null
+++ b/ruby/red-arrow/version.rb
@@ -0,0 +1,71 @@
+# 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.
+
+require "pathname"
+
+version_rb_path = Pathname.new(__FILE__)
+base_dir = version_rb_path.dirname
+pom_xml_path = base_dir.join("..", "..", "java", "pom.xml")
+lib_version_rb_path = base_dir.join("lib", "arrow", "version.rb")
+
+need_update = false
+if not lib_version_rb_path.exist?
+  need_update = true
+elsif version_rb_path.mtime > lib_version_rb_path.mtime
+  need_update = true
+elsif pom_xml_path.exist? and pom_xml_path.mtime > lib_version_rb_path.mtime
+  need_update = true
+end
+
+if need_update
+  version = pom_xml_path.read.scan(/^  <version>(.+?)<\/version>/)[0][0]
+  major, minor, micro, tag = version.split(/[.-]/)
+  lib_version_rb_path.open("w") do |lib_version_rb|
+    lib_version_rb.puts(<<-RUBY)
+# 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
+  module Version
+    MAJOR = #{major}
+    MINOR = #{minor}
+    MICRO = #{micro}
+    TAG = #{tag ? tag.dump : nil}
+    STRING = #{version.dump}
+  end
+
+  VERSION = Version::STRING
+end
+    RUBY
+  end
+end
+
+require_relative "lib/arrow/version"

-- 
To stop receiving notification emails like this one, please contact
wesm@apache.org.