Ruby gemのコードを読んでみよう。(初期設定編)

##概要

ruby gemのコードの中身をデバッグしながら読む方法についてまとめます。

本記事では、binding.pryを埋め込んで任意の場所をデバッグできるところまでの設定部分をまとめます。settingslogicというGemが、ソースの中身も短くリーディング初心者にとっても優しそうだったのでサンプルとして選択しました。

### 環境

mac 11.2.3
ruby 2.7.2
bundler 2.1.4

### 手順

#### 1.リーディング用のディレクトリを作成します。

```ruby
mkdir gemcode_reading
```

### 2.ディレクトリ直下で、bundle initして、Gemfileを作成する。

```ruby
bundle init

# gemcode_reading
 # - Gemfile
```

3.デバッグ用のGemであるpryと、コードリーディングを行いたいGem（今回はsettingslogic）をGemfileに追加。

```ruby
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "pry"
gem "settingslogic"
```

4.bundle installで必要なGemをインストール

```ruby
bundle install
```

5.Gemを使用するためのスクリプトを準備。

```ruby
#settings.rb

#対象のgemを読み込み
require "settingslogic"
#デバッグ用のpryを読み込み
require "pry"

# ソースと名前を指定すれば、設定yamlから任意の値を取得できるClassを作成。
# 取得部分のロジックを、今回ソースをデバッグするsettingslogicが担っています。
class Settings < Settingslogic
  source "config/application.yml"
  namespace "development"
end

p Settings.cool #{"saweet"=>"nested settings"}
p Settings.neat_setting #800
```

```ruby
#config/application.yml

Custom: &defaults
  cool:
    saweet: nested settings
  neat_setting: 24

development:
  <<: *defaults
  neat_setting: 800

test:
  <<: *defaults

production:
  <<: *defaults
```

6.Gemの内部の任意の箇所にbinding.pryを設置

```ruby
#vendor/bundle/ruby/2.7.0/gems/settingslogic-2.0.9/lib/settingslogic.rb

class Settingslogic < Hash
def initialize(hash_or_file = self.class.source, section = nil)
    #デバッグ
　　binding.pry
    case hash_or_file
    when nil
      raise Errno::ENOENT, "No file specified as Settingslogic source"
    when Hash
      self.replace hash_or_file
    else
      file_contents = open(hash_or_file).read
      hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
      if self.class.namespace
        hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
      end
      self.replace hash
    end
    @section = section || self.class.source  # so end of error says "in application.yml"
    create_accessors!
  end
end

```

7.スクリプトを実行

```ruby
bundle exec ruby settings.rb
```

8.デバッグ箇所の表示

```ruby
95: def initialize(hash_or_file = self.class.source, section = nil)
 =>  96: binding.pry
     97:   case hash_or_file
     98:   when nil
     99:     raise Errno::ENOENT, "No file specified as Settingslogic source"
    100:   when Hash
    101:     self.replace hash_or_file
    102:   else
    103:     file_contents = open(hash_or_file).read
    104:     hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
    105:     if self.class.namespace
    106:       hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
    107:     end
    108:     self.replace hash
    109:   end
    110:   @section = section || self.class.source  # so end of error says "in application.yml"
    111:   create_accessors!
    112: end
```

### まとめ
デバッグ用に埋め込んだpryを起点にスクリプトを書き換えたりしながら、ソースの中身を探って行けます。今回は小規模なGemでしたが、ライブラリのコードの中身をしっかり把握するためにコードの重要な箇所は素早く正確に読めるようになりたいです。

### 参考
[RubyGemコードリーディングのすすめ](https://blog.freedom-man.com/try-rubygem-codereading)
[ソースコード・リーディングしよう！](https://morizyun.github.io/blog/library-source-code-reading-acctive-support/index.html)