読者です 読者をやめる 読者になる 読者になる

kitak.blog

Kみたいなエンジニアになりたいブログ

RubyでDSL書くときのちょっとした工夫?

ほっ・・・(意味なし) 最近、Rubyで内部DSLの設計を勉強しているkitakです。
DSLの設計でこうしたらいいんじゃね?と思ったのでご紹介。

こんなかんじのDSLを書くとする。

# coding: utf-8

class Link
  attr_accessor :band_width, :delay, :queue_size

  def initialize
    yield self
  end
end

# ここがDSLだよ!
link = Link.new do |l|
  l.band_width = '100Mb'
  l.delay = '20ms'
  l.queue_size = 5
end

puts link.band_width
puts link.delay
puts link.queue_size

インスタンスを生成して、プロパティを設定しています。 initializeメソッドではなく、 ブロックを使っているところがミソです。
設定する項目が増えたときは、こっちのほうが読みやすいと思います。
だけど、 ブロックにインスタンス自身(self)を渡さないとダメなんですよね... インスタンスを渡さずに設定できたらいいなぁと思ってたんですが、この前ひらめいたのは
instance_evalを使えばいいじゃないか!

改良したやつ

class Link
  def initialize(&block)
    self.instance_eval &block
  end

  def params
    [@band_width, @delay, @queue_size].each do |param|
      puts "#{param}"
    end
  end

  private
  def band_width(param)
    @band_width = param
  end

  def delay(param)
    @delay = param
  end

  def queue_size(param)
    @queue_size = param
  end
end

link = Link.new do
  band_width '100Mb'
  delay      '20ms'
  queue_size 5
end

link.params

あかん...なんかおかしいことしてる気がする。
ブロック内はメソッド呼び出しの形にしたい(@をつけて代入はしたくない)。
うーむ、もっと良い方法がありそうだ、要調査