LoginSignup
17
15

More than 5 years have passed since last update.

rubyのブロック構文の使い道・モジュールとかクラスの設定変更用メソッドを用意する

Posted at

ブロック構文を利用することで、 Rails や RSpec などでおなじみの、次のようなクラスの設定用メソッドなどを作成することができます。

Hoge.configure do |config|
  config.something = "configured!"
end

この記事では、こういうメソッドをどうやって実装すればよいかを2分で説明したいと思います。(割と単純なので2分くらいしかもちません)

基本

基本は単純です。

module Hoge
  class << self
    attr_accessor :something

     def configure
       yield self
     end
  end
end

Hoge.configure do |config|
  config.something = "configured!"
end

puts Hoge.something

まず、クラス変数と something とクラスメソッド configure を用意します。
class << self はそういうイディオムだと思ってください。
(詳細は長くなるので Rubyist Magazine - Ruby 初級者のための class << self の話 (または特異クラスとメタクラス) などを閲覧いただけるとありがたいです)

で、自分自身を引数にとって yield を呼んでやればおしまいです。
これで、 Hoge.configure のブロックパラメータである config には Hoge 自身が渡されます。

ね、簡単でしょ?

なお、本記事においてここから先はすべて蛇足となります。

設定クラス or 設定モジュールを用意しておく

個人的には基本的なやつで十分だと思いますが、設定だけ別のモジュールやクラスに置きたくなることがあるかと思いますが、これも割と単純です。

module Hoge
  class << self
    def configure
      yield config
    end

    def config
      @config ||= Config.new
    end
  end

  class Config
    attr_accessor :something
  end
end

Hoge.configure do |config|
  config.something = "configured!"
end

puts Hoge.config.something

と、このように、 yield の引数に設定クラス (or モジュール) のインスタンスを渡してやるだけです。

ブロック以外の形でも設定できるようにしたい!

本当にする必要があるのでしょうか?

とりあえず Kernel.#block_given? を使えば実現できます。この Kernel.#block_given? は現在のメソッド呼び出しにブロックが渡されていれば真を返します。

module Hoge
  class << self
    attr_accessor :something

    def configure k = nil, v = nil
      if block_given?
        yield self
      elsif !k.nil?
        self.send(k.to_s + "=", v)
      end
    end
  end
end

Hoge.configure do |config|
  config.something = "configure form block"
end

puts Hoge.something

Hoge.configure :something, "configure from method"

puts Hoge.something

こんな感じでいかがでしょうか?

あたりまえではありますが、柔軟にすればするほど、できることも実装も複雑になります。

設定をブロック構文によるこの形をサポートしつつ、設定ファイルもサポートしたうえで、コマンドライン引数からもできるようにしたい

これをしたのが RSpec です。
ですが、 RSpec.configure に限って言えば実装はとても単純です。

core.rb
def self.configure
  yield configuration if block_given?
end

抜粋したソース のように、ブロックが渡されていれば yield を、そうでなければ単純に無視する形となっています。

17
15
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
17
15