0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

gemを読む[3]: Config gemを導入して`rails generate`に思いを馳せる

Posted at

対象gem

今回はConfig gemを読んでいきます。

READMEでは、以下のように説明されています。

概要
Configは、環境ごとに特定の設定を簡単かつ使いやすい方法で管理するのに役立ちます。

特徴

  • シンプルなYAML設定ファイル
  • 設定ファイルはERBをサポート
  • 設定ファイルは継承と複数の環境をサポート
  • 設定情報に便利なオブジェクトメンバーノーテーションでアクセス
  • 複数レベルの設定をサポート (Settings.group.subgroup.setting)
  • コードをコミットする際にローカルの開発者設定を無視

rails g config:installは何をするのか

Config gemを使用するには、bundle installしたあとにrails g config:installを実行する必要があります。
これにより、configディレクトリ内に設定ファイルt複数のymlファイルが作成されます。

実装箇所

generateコマンドによって実行される処理は、lib/generators/config/install_generator.rbで実装されています。

InstallGeneratorクラスは::Rails::Generators::Baseクラスを継承しています。
継承元のクラスはRails側に実装されています。

::Rails::Generators::Baseクラスの深堀りは別の機会に取っておきます。
メモ: ここにgenerateメソッドが実装されている

さらに::Rails::Generators::BaseクラスはThor::Groupを継承しています。

実行される処理

rails g config:installコマンドを実行すると、以下の結果を得ることができます。

% rails g config:install
  create  config/initializers/config.rb
  create  config/settings.yml
  create  config/settings.local.yml
  create  config/settings
  create  config/settings/development.yml
  create  config/settings/production.yml
  create  config/settings/test.yml
  append  .gitignore

このコマンドにより、InstallGeneratorオブジェクトを新たに作成し、そのオブジェクトに対して以下のインスタンスメソッドが順に実行されます。

  • copy_initializer
  • copy_settings
  • modify_gitignore

各メソッドの中身を見ていきましょう。

copy_initializer

def copy_initializer
  template "config.rb", "config/initializers/config.rb"
end

templateメソッドは::Rails::Generators::Baseの継承元であるThor gemに実装されています。

この処理により、lib/generators/config/templates/config.rbがアプリ内のconfig/initializers/config.rbにコピーされます。

copy_settings

def copy_settings
  template "settings.yml", "config/#{Config.file_name}.yml"
  template "settings.local.yml", "config/#{Config.file_name}.local.yml"
  directory "settings", "config/#{Config.dir_name}"
end

copy_initializerと同様に、templateメソッドによりsettings.ymlsettings.local.ymlがアプリ内の各パスに複製されます。

directoryメソッドは、::Rails::Generators::Baseの継承元であるThor gemに実装されています。
この処理はlib/generators/config/templates/settingsディレクトリを、その中に含まれるファイル含めてアプリ内に複製しています。

ここで、Config.file_nameConfig.dir_namelib/config.rbで初期値が設定されています。
Configの設定値であるConfig::Configurationlib/config/configuration.rbに定義されています。

modify_gitignore

def modify_gitignore
  create_file '.gitignore' unless File.exist? '.gitignore'

  append_to_file '.gitignore' do
    "\n"                                      +
    "config/#{Config.file_name}.local.yml\n"  +
    "config/#{Config.dir_name}/*.local.yml\n" +
    "config/environments/*.local.yml\n"
  end
end

ここでは、.gitignoreにローカル用のsettings.ymlを追加しています。

append_to_fileメソッドもやはり、Thor gemに実装されています。

設定ファイルを読んでみる

copy_initializerメソッドにより、config/initializers/config.rb設定ファイルが作成されます。
このファイルでConfig.file_nameConfig.dir_nameを設定することができます。

Config.setup do |config|
  # Name of the constant exposing loaded settings
  config.const_name = 'Settings'

  # (中略)

  # Name of directory and file to store config keys
  #
  # config.file_name = 'settings'
  # config.dir_name = 'settings'
end

Configモジュールに対してsetupというモジュールメソッドが実行されています。
setuplib/config.rbに定義されています。

def self.setup
  yield self unless @_ran_once
  @_ran_once = true
end

自己yieldによって、Config自身のインスタンス変数を書き換える処理をおこなっています。
デフォルトでは設定ファイル内の多くの項目がコメントアウトされているので、以下のように値を変更してコメントを外します。

  config.file_name = 'filename'
  config.dir_name = 'dirname'

これを再びrails g config:installしてみました。

           % rails g config:install
    conflict  config/initializers/config.rb
Overwrite /Users/app_path/config/initializers/config.rb? (enter "h" for help) [Ynaqdhm] y
       force  config/initializers/config.rb
      create  config/filename.yml
      create  config/filename.local.yml
      create  config/dirname
      create  config/dirname/development.yml
      create  config/dirname/production.yml
      create  config/dirname/test.yml
      append  .gitignore

generatorコマンドにより再度処理が実行されるため、config/initializers/config.rbの重複が発生します。
オーバーライドするか聞かれているので、yで回答すると、以下の処理がおこなわれました。

  • config/initializers/config.rb のオーバーライド
    • templateの値に戻る
    • オーバーライドをnにすると、この処理はスキップされる
  • file_nameに応じたymlファイルの作成
  • dir_nameに応じたディレクトリと、その配下へのymlファイルの作成

@_ran_onceについて

set_upメソッド内で出現する@_ran_onceは、yield selfが一度だけ実行されることを保証するインスタンス変数です。
これにより、設定ファイルの意図しない上書きを防いでいます。

これはset_upそのものの処理を1度にするだけで、generateコマンドは何度も実行することができます。

まとめ

今回はConfig gemの導入部分についてコードリーディングしてみました。
rails generateコマンドで実行されるクラスや、自己yield、@_ran_onceについて知ることができました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?