LoginSignup
2
2

More than 5 years have passed since last update.

Sinatraのverbメソッドとインスタンスメソッドを関連づけるSinatra Extensionを書いた

Posted at

Sinatraのverbメソッドとインスタンスメソッドを関連づけるSinatra Extensionを書いた

Sinatraが提供するDSLは非常に簡潔でわかりやすいが、実体はクラスメソッドの実行文のため、モジュールなどに切り分けて後からincludeするなどといったことが困難である。

この問題は、数十個・数百個のルートを一つのアプリケーション上に定義することになったときに、混沌としたルーティングコードが出来上がることにつながってくる。

Padrinoが用意するcontrollerや、sinatra-contribの中のSinatra::Namespaceは、その問題を解決するに十分な機能だと言えるが、今回紹介するSinatra Extensionもまた、それに対する新たな解決策となる(かもしれない)。

namusyaka/sinatra-bind

考え方

Sinatraでは、getpostなどのverbメソッド(と自分は呼んでいる)に渡されたブロックを一旦、Sinatra::Baseのインスタンスメソッドとして定義する。そしてすぐにそれをinstance_methodを用いてUnboundMethodとして取り出し、自身の条件に当てはまるリクエストを受け取る度に、都度生成されるアプリケーションオブジェクトをレシーバとしてbind後、実行するようになっている。

内部的にブロックをメソッドに変換して管理しているということは、同様に正規の方法で定義されたインスタンスメソッドもルーティングに対して使えるだろうということで、今回のアイデアを思いついた。

ちなみにこの「ブロックをメソッドとして定義する」というプロセスを踏んでいることで、sinatraの代表的な機能の一つとも言えるルート間でのインスタンス変数の共有(や、その他たくさんの便利機能)を実現している。

使い方

registerキーワードを使ってSinatraにSinatra::Bindを登録することで、新たにonというルート定義用のメソッドが追加される。

class App < Sinatra::Base
  register Sinatra::Bind

  def index
    "Hello World"
  end

  on "/", to: :index
end

リクエストメソッドの指定

:typeオプションに指定することでそのように定義される。

class App < Sinatra::Base
  register Sinatra::Bind

  def index
    "Hello World"
  end

  on "/", to: :index, type: :post
end

beforeafterフィルター

:typeオプションに:before:afterを指定することで、フィルターとして定義される。

おわりに

面白い試みではあると思う反面、ぶっちゃけ邪道っぽい。

おわり。

2
2
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
2
2