2023年6月2日金曜日

Sinatraのルーティングをクラスとして定義する方法

Sinatraのルーティングをクラスとして定義する方法

概要

Sinatra のルーティングをクラスとして定義する方法を紹介します
Sinatra::Base を使うのは当然なのですがルーティングの定義などもすべてインスタンスメソッドとして定義します

環境

  • macOS 11.7.6
  • Ruby 3.2.1
    • sinatra 3.0.6

サンプルコード

  • vim app.rb
# frozen_string_literal: true

require 'sinatra'

# / を管理するクラス
class MyApp < Sinatra::Base
  def initialize(path)
    super()
    @path = path
    routing
  end

  def routing
    MyApp.get @path do
      'hello'
    end
  end

  # 例えばルーティングに関する情報を使って何かを生成することもできる
  def to_h
    {
      path: @path
    }
  end
end

config.ru

  • vim config.ru
# frozen_string_literal: true

require 'rack'
require './app'

run Rack::URLMap.new(
  {
    '/home' => MyApp.new('/') # ここを /fuga などにすると /home/fuga にアクセスできる
  }
)

動作確認

  • bundle exec rackup config.ru

ツールとして使う

Web アプリとしてではなくルーティング内に定義したインスタンスメソッドを別のツールとして使うこともできます

  • vim export.rb
# frozen_string_literal: true

require './app'

app = MyApp.new!('/')
puts app.to_h

ポイントは new! を使って強制的にインスタンス化して使います
rackup を挟んでいないので通常のクラスとして使えます

メリット

ルーティングをクラスとして定義することで複数のルーティングを定義した場合に共通の処理を親クラスに抽象化することができます
Mix-in なども使えます (そもそも Sinatra にはミドルウェアという機能があるのでそれと同じように使える)

逆に同じようなページを生成するのであればすでにあるルーティング用のクラスを使って同じページを生成できます

またルーティングに必要な情報 (パスやリクエストパラメータ、テンプレートに与える情報、ヘッダ、認証情報) などをクラス内で管理することができるようになるのでコードの可読性も上がります

デメリット

ルーティングを追加するのにわざわざクラスを一つ追加する必要があります

またせっかく DSL で簡単にアプリを定義できるのにクラス化するためのコードを増えるので記述量は多くなります
Rails っぽくなってしまうというのもあるかなと思います

最後に

使用するかどうかは開発するプロダクトの規模の大きさにもよるかもしれません

これにデータベースが絡んで来る場合などはむしろ Sinatra ではなく Rails を使ったほうがいいまであります

0 件のコメント:

コメントを投稿