対象バージョン
Rails 4.2.6
対象読者
- Rubyの標準ライブラリを拡張したいけど、何でもかんでもlib直下にコードを入れると死ぬ人
- lib/core_ext に標準ライブラリを格納したはいいけど、
CoreExt module
じゃないコードをどうやって autoload させたら良いかわからない人
方法
lib/core_ext/
に拡張コードを実装
lib/core_ext/string.rb
class String
def and_hello
self+" and hello"
end
end
lib 直下を autoload対象にする
config/application.rb
module AppName
class Application < Rails::Application
....
config.autoload_paths += ["#{config.root}/lib/"]
end
end
lib/core_ext.rb
を実装
lib/core_ext/string
を require する
lib/core_ext.rb
require 'core_ext/string'
module CoreExt
end
config/initializers/core_ext.rb
を実装
CoreExt
モジュールを呼び出して、拡張コードを読みこませる
config/initializers/core_ext.rb
CoreExt
Q&A形式の解説
config/initializers
で CoreExt
を呼ぶのは何で?
- Railsのオートロードは、対象のモジュールが呼ばれた時に、初めて読み込まれる
- なので、
config/initializers
でCoreExt
を呼び出すことで、String
の拡張を明示的に読み込ませている
- なので、
lib/core_ext/string
を config/initializers
とかで直接 require しちゃダメなの?
- それでも良いと思うけど、Rails way から中途半端に外れるのは何かと危険と考えているので
- 途中からプロジェクトに参加した人は、そこだけ Rails way から外れているなんて思わない
- 驚きは最小にしたいよね
config/initializers
直下に string.rb 置いちゃったら楽じゃない?
- コードが散逸するのが嫌だ
- 絶対そんなところ探さない自信がある
-
config/initializers
は初期処理や、アプリ固有の設定を置くべき場所 -
CoreExt
を読み込むという初期処理を置くだけにして、責務を分担している
lib直下に、string.rb を置かないのは何で?
- なんでもかんでもlib直下に置くのもよく分からなくなるから
- 標準ライブラリ拡張は、ActiveSupport の様式に従って
core_ext
に置いた
autoload_paths を lib/core_ext
にすれば config/initializers/core_ext.rb
不要じゃない?
- lib以下のディレクトリに、別に module にしたい実装が追加された時に、ややこしいことになりそうなのでやらない
- 例えば、
Util::Hoge
を実装した場合 -
autoload_paths += ['lib', 'lib/core_ext']
とかすると、2回 core_ext がロードされるはず...
- 例えば、
├── core_ext
│ └── string.rb
├── core_ext.rb
└── util
└── hoge.rb
- あと、この方法だと String が拡張されないんだよね...
- module じゃないから、autoload が働かないという解釈でよいのかな?
- おしえてえらいひと
参考
モジュールが読み込めているか確認する時に便利なメソッド
ActiveSupport::Dependencies.autoloaded_constants
- autoloadで読み込まれているモジュールを配列で返す
ActiveSupport::Dependencies.autoload_paths
- autoload対象のpathを配列で返す
参考リンク
-
Declutter your lib directory | Lunar Logic Blog
-
アプリの責務で無いもの、他でも使いまわせるものをlibに置くべき
- libの中でさらに役割をわけてディレクトリを切ると良い
-
lib/core_ext
: 標準ライブラリ拡張 -
lib/hack
: ライブラリのモンキーパッチとか
-
libにはアプリの拡張は置かない
- アプリの責務であるものは、appにサブディレクトリ切ってそこにおくべき
- ちょっとしたアプリの設定は、
config/initializers
-
アプリの責務で無いもの、他でも使いまわせるものをlibに置くべき
-
Railsアプリのモジュールはどこに置くべきか問題 (公開版)
- 上記の翻訳
-
Rails プラグイン作成入門#3.コアクラスを拡張する | Rails ガイド
- ファイル名がわかりづらくて混乱するけど、大体このやり方に準拠した
- Railsでlib以下を読み込ませる方法とその注意点 〜名前重複の死を避けるために〜 - Qiita