対象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.yml
とsettings.local.yml
がアプリ内の各パスに複製されます。
directory
メソッドは、::Rails::Generators::Base
の継承元であるThor gemに実装されています。
この処理はlib/generators/config/templates/settings
ディレクトリを、その中に含まれるファイル含めてアプリ内に複製しています。
ここで、Config.file_name
とConfig.dir_name
はlib/config.rbで初期値が設定されています。
Configの設定値であるConfig::Configuration
はlib/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_name
やConfig.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
というモジュールメソッドが実行されています。
setup
はlib/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
について知ることができました。
参考