Ruby
デザインパターン

「Rubyによるデザインパターン」の要点と使いどころ(続き)

More than 3 years have passed since last update.

「Rubyによるデザインパターン」の要点と使いどころの続きです。

Rubyによるデザインパターン』の「第Ⅲ部 Rubyのためのパターン」についてまとめます。第Ⅲ部は、どの章もそれだけで本が1冊書けるような濃い内容なので、本書を足がかりに別の本も合わせて読んだほうが良さそうです。

DSL: ドメイン特化言語

概要

  • DSL: ドメイン特化言語(Domain-Specific Language)とは、あるドメイン(領域)の言葉を用いてプログラミングができる言語。例えば、会計士が会計の事柄をそのまま表現できる言語など。
  • 外部DSL: 会計士の言葉でプログラミングができる会計用DSLがある場合、そのDSLを解析・実行するためにパーサとインタープリタが必要になる。このように、DSLとインタープリタが別々の場合を外部DSLという。
  • 内部DSL: DSLが何らかの言語(例えばRuby)と同じ書き方ができる場合。Rubyはこの内部DSLを簡単に作ることができる。

実装

内部DSLの実装は、DSLで書かれたファイルをevalメソッドで読み込み、Rubyのプログラムとして実行させている。DSLで使用できるキーワード(メソッド等)は、全て本来プログラム側に定義する。

実行ファイル

def output(message)
    puts message
end

eval(File.read('DSLで書かれたファイル'))

DSLで書かれたファイル

output 'メッセージ'

実行結果

メッセージ

メタプログラミング

概要

  • Rubyの柔軟性を活用して、動的なオブジェクトを生成する。

実装

実装例1.インスタンスにメソッドを定義する

def make_object(type)
    object = Object.new
    if type == :a
        def object.type
            'a'
        end
    end
    object
end

obj = make_object(:a)
obj.type # => "a"

実装例2.インスタンスにメソッドをextendする

module M
    def type
        'a'
    end
end

def make_object(type)
    object = Object.new
    if type == :a
        object.extend(M)
    end
    object
end

obj = make_object(:a)
obj.type # => "a"

実装例3.インスタンスにメソッドをclass_eval()で追加する

class Obj
    def self.set_type(member)
        code = %Q{
            def type
                "#{member}"
            end
        }
        class_eval(code)
    end
end

Obj.set_type('a')
obj = Obj.new
obj.type # => "a"

Convention over Configuration

概要

  • "設定よりも規約"というRuby on Railsの思想。
  • 従来の"設定"によるフレームワークでは、規模が大きくなるほど設定が大きくなり、拡張性や保守性に問題があった。CoCの思想では、フレームワークがある規約に則ることで、余分な設定を排除し、拡張性や保守性を高めている。