From 28cd6f123e58e9d24e41c4f79d3c2e67994581df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mislav=20Marohni=C4=87?= <git@mislav.net>
Date: Thu, 6 May 2021 13:25:06 +0200
Subject: [PATCH] :nail_care: Clean up version sorting and add test

---
 libexec/rbenv-versions | 79 +++++++++++++++++-------------------------
 test/test_helper.bash  |  2 +-
 test/versions.bats     |  8 +++--
 3 files changed, 39 insertions(+), 50 deletions(-)

diff --git a/libexec/rbenv-versions b/libexec/rbenv-versions
index 28c3cdc3..9b7d7570 100755
--- a/libexec/rbenv-versions
+++ b/libexec/rbenv-versions
@@ -63,62 +63,47 @@ if [ -d "$versions_dir" ]; then
   versions_dir="$(realpath "$versions_dir")"
 fi
 
-if [ -n "$bare" ]; then
-  hit_prefix=""
-  miss_prefix=""
-  current_version=""
-  include_system=""
-else
-  hit_prefix="* "
-  miss_prefix="  "
-  current_version="$(rbenv-version-name || true)"
-  include_system="1"
-fi
-
-num_versions=0
-
-print_version() {
-  if [ "$1" == "$current_version" ]; then
-    echo "${hit_prefix}$(rbenv-version 2>/dev/null)"
-  else
-    echo "${miss_prefix}$1"
-  fi
-  num_versions=$((num_versions + 1))
+list_versions() {
+  shopt -s nullglob
+  for path in "$versions_dir"/*; do
+    if [ -d "$path" ]; then
+      if [ -n "$skip_aliases" ] && [ -L "$path" ]; then
+        target="$(realpath "$path")"
+        [ "${target%/*}" != "$versions_dir" ] || continue
+      fi
+      echo "${path##*/}"
+    fi
+  done
+  shopt -u nullglob
 }
 
+if [ -n "$bare" ]; then
+  list_versions
+  exit 0
+fi
+
 sort_versions() {
   sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z.\1/; s/$/.z/; G; s/\n/ /' | \
     LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}'
 }
 
-# Include "system" in the non-bare output, if it exists
-if [ -n "$include_system" ] && RBENV_VERSION=system rbenv-which ruby >/dev/null 2>&1; then
-  print_version system
-fi
-
-shopt -s nullglob
-
-versions=($(
-for path in "$versions_dir"/*; do
-  if [ -d "$path" ]; then
-    if [ -n "$skip_aliases" ] && [ -L "$path" ]; then
-      target="$(realpath "$path")"
-      [ "${target%/*}" != "$versions_dir" ] || continue
-    fi
-    echo "${path##*/}"
+versions="$(
+  if RBENV_VERSION=system rbenv-which ruby >/dev/null 2>&1; then
+    echo system
   fi
-done
-))
+  list_versions | sort_versions
+)"
 
-sorted_versions=($(printf "%s\n" ${versions[@]} | sort_versions))
-
-for version in ${sorted_versions[@]}; do
-  print_version $version
-done
-
-shopt -u nullglob
-
-if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then
+if [ -z "$versions" ]; then
   echo "Warning: no Ruby detected on the system" >&2
   exit 1
 fi
+
+current_version="$(rbenv-version-name || true)"
+while read -r version; do
+  if [ "$version" == "$current_version" ]; then
+    echo "* $(rbenv-version 2>/dev/null)"
+  else
+    echo "  $version"
+  fi
+done <<<"$versions"
diff --git a/test/test_helper.bash b/test/test_helper.bash
index aef883a4..6e40d6cb 100644
--- a/test/test_helper.bash
+++ b/test/test_helper.bash
@@ -119,7 +119,7 @@ path_without() {
     if [ "$found" != "${RBENV_ROOT}/shims" ]; then
       alt="${RBENV_TEST_DIR}/$(echo "${found#/}" | tr '/' '-')"
       mkdir -p "$alt"
-      for util in bash head cut readlink greadlink; do
+      for util in bash head cut readlink greadlink sed sort awk; do
         if [ -x "${found}/$util" ]; then
           ln -s "${found}/$util" "${alt}/$util"
         fi
diff --git a/test/versions.bats b/test/versions.bats
index 71d98871..e083ffab 100644
--- a/test/versions.bats
+++ b/test/versions.bats
@@ -56,15 +56,19 @@ OUT
 @test "multiple versions" {
   stub_system_ruby
   create_version "1.8.7"
-  create_version "1.9.3"
+  create_version "1.9.3-p13"
+  create_version "1.9.3-p2"
   create_version "2.2.10"
   create_version "2.2.3"
+  create_version "2.2.3-pre.2"
   run rbenv-versions
   assert_success
   assert_output <<OUT
 * system
   1.8.7
-  1.9.3
+  1.9.3-p2
+  1.9.3-p13
+  2.2.3-pre.2
   2.2.3
   2.2.10
 OUT