[Visual Studio Code] rbenv 使用時のデバッグ実行で syntax error が出る

# 環境

|項目  |バージョン  |
|---|---|
|OS  |Mac Catalina 10.15.6|
|Visual Studio Code  |1.49.0 |
|Ruby| 2.7.1|

Rubyのバージョン管理として、 rbenv を使用していた

# 前提

デバッグに必要な gem は Gemfile に追加しており、インストール済みの状態だった

```
gem "ruby-debug-ide"
gem "debase"
```

# エラー

Visual Studio Code 左側の Run を選択し、 [Add Config] -> [RSpec - active spec file only] を選ぶ

上記の設定でデバッグしたところ、画面下のステータスバーが実行中を示すオレンジ色のまま、何も進まない状態になった

ReRunすると下記のように [OUTPUT] ビューに以下のエラーが出力される

```
Uncaught exception: /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected tSTRING_BEG, expecting do or '{' or '('
[ -n "$RBENV_DEBUG" ] && set -x
     ^
/Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected ']', expecting end-of-input
[ -n "$RBENV_DEBUG" ] && set -x
                    ^

/Users/pldb/.rbenv/versions/2.6.6/bin/rdebug-ide:23:in `load': /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected tSTRING_BEG, expecting do or '{' or '(' (SyntaxError)
[ -n "$RBENV_DEBUG" ] && set -x
     ^
/Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected ']', expecting end-of-input
[ -n "$RBENV_DEBUG" ] && set -x
                    ^
	from /Users/pldb/.rbenv/versions/2.6.6/bin/rdebug-ide:23:in `<main>'
```

# 結果

.vscode/launch.json を以下のように変更した

**変更前**

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "RSpec - active spec file only",
      "type": "Ruby",
      "request": "launch",
      "program": "/Users/pldb/.rbenv/shims/rspec",
      "args": [
        "-I",
        "${workspaceRoot}",
        "${file}"
      ]
    }
  ]
}
```

**変更後**

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "RSpec - active spec file only",
      "type": "Ruby",
      "request": "launch",
      "program": "${workspaceRoot}/bin/rspec",
      "args": [
        "-I",
        "${workspaceRoot}",
        "${file}"
      ]
    }
  ]
}
```

これは Visual Studio Code のデフォルト設定そのままである
ただし、binstub を使用した

# 原因

launch.json を生成した時点の `"program"` は `"${workspaceRoot}/bin/rspec"` だった

ところが使用しているrspecのパスが正しいものと考えて以下のパスに差し替えた

```bash
% which rspec
/Users/pldb/.rbenv/shims/rspec
```

表題のエラーはこれによって発生した

参考: [rspec doesn't execute as a program, it is parsed as if it's a code file.](https://github.com/rubyide/vscode-ruby/issues/344)

実際に参照していた shims配下のrspec の中身はこれである

```bash
#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x

program="${0##*/}"
if [ "$program" = "ruby" ]; then
  for arg; do
    case "$arg" in
    -e* | -- ) break ;;
    */* )
      if [ -f "$arg" ]; then
        export RBENV_DIR="${arg%/*}"
        break
      fi
      ;;
    esac
  done
fi

export RBENV_ROOT="/Users/pldb/.rbenv"
exec "/usr/local/Cellar/rbenv/1.1.2/libexec/rbenv" exec "$program" "$@"
```

これはrbenvが生成した（rspecを参照するための）bashファイルであり、これをそのまま読み込んだ結果エラーになっていた
つまり rspec を十分に理解していないことが原因であった

# 対策

binstub を使用する

参考: [【翻訳+解説】binstubをしっかり理解する: RubyGems、rbenv、bundlerの挙動](https://techracho.bpsinc.jp/hachi8833/2016_08_24/25037)

プロジェクト内で使用するrspecにするために、 binstub で `${workspaceRoot}/bin/rspec` を生成する

`${workspaceRoot}` はVisual Studio Code で展開したディレクトリのフォルダを指す

このディレクトリまで移動してから以下を実行する

```bash
% bundle binstubs rspec-core
% ./bin/rspec -v
RSpec 3.9
  - rspec-core 3.9.2
  - rspec-expectations 3.9.2
  - rspec-mocks 3.9.1
  - rspec-support 3.9.3
```

これでデフォルトの設定のまま実行できる

gem を作成している場合は、（他コントリビュータに影響しないよう）binフォルダを避ける

```bash
% bundle binstubs rspec-core --path exe
% ./exe/rspec -v
RSpec 3.9
  - rspec-core 3.9.2
  - rspec-expectations 3.9.2
  - rspec-mocks 3.9.1
  - rspec-support 3.9.3
```

この場合は launch.json の `"program"` のパスが `${workspaceRoot}/exe/rspec` になる

# 余禄

プロジェクトの rspec のバージョンに拘らない場合は、以下のように `/usr/local/bin/rsepc` を指定しても動作する

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "RSpec - active spec file only",
      "type": "Ruby",
      "request": "launch",
      "program": "/usr/local/bin/rspec",
      "args": [
        "-I",
        "${workspaceRoot}",
        "${file}"
      ]
    }
  ]
}
```

それと、これは別件ではあるが、 launch.json の設定に関してもう一つ取り上げる
gemspec でエンコーディングのエラーが発生した

```
Uncaught exception: 
[!] There was an error parsing `Gemfile`: 
[!] There was an error while loading `xxx.gemspec`: invalid byte sequence in US-ASCII. Bundler cannot continue.
```

見ての通り、エンコーディングの設定が原因である

参考: [Encoding issue when using gem 'xcodeproj'](https://github.com/rubyide/vscode-ruby/issues/43)

gem 開発時にデバッグする場合の launch.json は、最終的に以下のようになった

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "RSpec - active spec file only",
      "type": "Ruby",
      "request": "launch",
      "program": "${workspaceRoot}/exe/rspec",
      "args": [
        "-I",
        "${workspaceRoot}",
        "${file}"
      ],
      "env": {
        "LANG": "en_US.UTF-8",
        "LC_COLLATE": "en_US.UTF-8",
        "LC_CTYPE": "en_US.UTF-8",
        "LC_MESSAGES": "en_US.UTF-8",
        "LC_MONETARY": "en_US.UTF-8",
        "LC_NUMERIC": "en_US.UTF-8",
        "LC_TIME": "en_US.UTF-8",
        "LC_ALL": "en_US.UTF-8"
      }
    }
  ]
}
```