スキップしてメイン コンテンツに移動

Rubyで作る宣言的DSL

Rubyで作る宣言的DSL

Ruby応用でDSL作成の基礎

Rubyはその柔軟な構文とブロック機能により、Domain Specific Language(DSL)を簡単に作成できる言語です。DSLは特定のドメインに特化した表現力を提供し、コードの可読性と保守性を大幅に向上させます。まずは簡単な構文を定義し、メソッドチェーンで直感的に記述できるようにします。

class Config
  def initialize(&block)
    instance_eval(&block)
  end

  def set(key, value)
    instance_variable_set("@#{key}", value)
  end

  def get(key)
    instance_variable_get("@#{key}")
  end
end

config = Config.new do
  set :host, 'localhost'
  set :port, 8080
end

puts config.get(:host)  # => localhost

ドメイン特化言語の設計原則

DSLを設計する際の主な原則は「宣言的記述」と「実装の隠蔽」です。宣言的記述により、何をしたいかを記述し、Rubyが内部でどう実装するかを隠します。これにより、ドメインエキスパートがコードを理解しやすくなります。また、メソッド名やキーワードはドメイン語彙に合わせることで表現力を高めます。

  • ドメイン語彙を採用
  • 副作用を最小化
  • エラーハンドリングを明示的に

宣言的記述とブロック活用

RubyのブロックはDSLの核です。ブロックを渡すことで、構造化された設定やルールを宣言的に記述できます。以下は、テストフレームワークのようにブロックでテストケースを定義する例です。

class TestSuite
  def initialize(name, &block)
    @name = name
    @tests = []
    instance_eval(&block)
  end

  def test(name, &block)
    @tests << { name: name, block: block }
  end

  def run
    puts "Running #{@name}"
    @tests.each do |t|
      puts "  #{t[:name]}"
      t[:block].call
    end
  end
end

suite = TestSuite.new('Math Tests') do
  test 'addition' do
    raise 'fail' unless 1 + 1 == 2
  end
  test 'multiplication' do
    raise 'fail' unless 2 * 3 == 6
  end
end

suite.run

設定ファイルと表現力の向上

DSLを設定ファイルとして利用することで、アプリケーションの構成をコード化せずに柔軟に変更できます。RubyのYAMLやJSONと組み合わせると、設定を読み込みつつ、DSLで表現したロジックを実行できます。以下はYAMLを読み込み、DSLで処理を定義する例です。

require 'yaml'

class Router
  def initialize(routes)
    @routes = routes
  end

  def route(path, &block)
    @routes[path] = block
  end

  def dispatch(path)
    if @routes.key?(path)
      @routes[path].call
    else
      puts "404 Not Found"
    end
  end
end

routes = YAML.load_file('routes.yml')
router = Router.new(routes)

router.dispatch('/home')

このように、設定ファイルとDSLを組み合わせることで、表現力を最大化し、運用コストを低減できます。

この記事はAIによって作成されました。

コメント