こんにちは!kossyです!
さて、今回はRubyのbegin-end構文で変数を定義する方法についてブログに残してみたいと思います。
begin-end構文とは?
begin-endは例外処理でよく用いられるイメージですが、例外処理以外の用途でも使うことができるようです。
What is use of ||= begin....end block in Ruby? - Stack Overflow
@valiable ||= begin 処理 end
という構文で使うことができます。
Rails内での使われ方
Railsのコードなら間違いないだろうということで紹介してみます。
rails/engine.rb at 0105fd4a1ec5579fbc824c7a864794ba90351c39 · rails/rails · GitHub
def helpers @helpers ||= begin helpers = Module.new all = ActionController::Base.all_helpers_from_path(helpers_paths) ActionController::Base.modules_for_helpers(all).each do |mod| helpers.include(mod) end helpers end end
@helpersというインスタンス変数を定義するためにbegin-end構文を用いてますね。
もう少し探ってみましょう。
rails/app_updater.rb at 0105fd4a1ec5579fbc824c7a864794ba90351c39 · rails/rails · GitHub
def app_generator @app_generator ||= begin gen = Rails::Generators::AppGenerator.new ["rails"], generator_options, destination_root: Rails.root File.exist?(Rails.root.join("config", "application.rb")) ? gen.send(:app_const) : gen.send(:valid_const?) gen end end
rails/application.rb at 0105fd4a1ec5579fbc824c7a864794ba90351c39 · rails/rails · GitHub
def secrets @secrets ||= begin secrets = ActiveSupport::OrderedOptions.new files = config.paths["config/secrets"].existent files = files.reject { |path| path.end_with?(".enc") } unless config.read_encrypted_secrets secrets.merge! Rails::Secrets.parse(files, env: Rails.env) # Fallback to config.secret_key_base if secrets.secret_key_base isn't set secrets.secret_key_base ||= config.secret_key_base secrets end end
冒頭にも記述した通り、
@valiable ||= begin 処理 end
という構文さえ覚えておけば良さそうです。
ちなみに ||= という式は、
「左辺が偽または未定義であれば、右辺の評価値を代入する」というイディオムになります。
3つほど例を見て気がつきましたが、
インスタンスを生成してインスタンスのattrの値に複雑だったり冗長な処理結果を代入して、インスタンス自身を返り値としたい時に使ってますね。
実務で使う時は上記のシチュエーションに遭遇した時に使えそうです。
勉強になりました。
参考にさせていただいたサイト
GitHub - rails/rails: Ruby on Rails
Ruby で Proc を即時実行する代わりに begin 式で代入する - Qiita