Time to Read
2分
なんか twitter でそういう声があったのでざっくり試したよ。
Rack::URLMap を使う
なんと! Rack::URLMap は、 env["PATH_INFO"] をよしなにしてはくれません。/sub サブディレクトリにマウントしたアプリケ~ションにも、 /sub が付いたまま渡ります。なので、自分で削除する Rack Middleware 書いたった。
app1.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | require 'rubygems' require 'bundler/setup' Bundler.require class SubApp < Sinatra::Base get '/' do "Sub::Index!" end get '/foo' do "Sub::Foo!" end end class App < Sinatra::Base get '/' do "Index!" end get '/hoge' do "Hoge!" end end class PrefixDeleter def initialize(app, prefix) @app, @prefix = app, prefix end def call(env) env["PATH_INFO"].sub! /^#{@prefix}/, '' @app.call(env) end end App1 = Rack::Builder.app do map('/') { run App.new } map('/sub') do use PrefixDeleter, '/sub' run SubApp.new end end |
config.ru:
1 2 | require './app1' run App1 |
結論: ダ、ダサい。。。 Rack 組み込みのものは最低限の機能しかないんだな~と。
Padrino::Routing を使う
Padrino framework の一部、 Padrino::Routing を使う。このモジュールは padrino-core gems で定義されているので、 Gemfile 的には
1 | gem 'padrino-core' |
これだけ追記する。
app2.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | require 'rubygems' require 'bundler/setup' Bundler.require class App2 < Sinatra::Base register Padrino::Routing controller :index do get :index do "Index!" end get :hoge do "Hoge!" end end controller :sub do get :index do "Sub::Index!" end get :foo do "Sub::Foo!" end end end App2.run! if __FILE__ == $0 |
あと、さっきの URLMap の奴と違い、 ruby app2.rb で立ち上がる。 Sinatra 感出てる。
若干書き方がすっきりしたが、あくまでも「コントローラを導入する」拡張なので大仰な気がする。
Sinatra::Namespace ってのがあるじゃん!
sinatrarb.com 公式でもリンクされている。 README をみる限り、割と多機能。
Gemfile:
1 | gem 'sinatra-namespace', require: 'sinatra/namespace' |
app3.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | require 'rubygems' require 'bundler/setup' Bundler.require class App3 < Sinatra::Base register Sinatra::Namespace get '/' do "Index!" end get '/hoge' do "Hoge!" end namespace "/sub" do get do "Sub::Index!" end get '/foo' do "Sub::Foo!" end end end App3.run! if __FILE__ == $0 |
いいね~
Sinatra::Namespace は、ホスト名でも振り分けとか何とかしてくれたりするんで便利かもしれない。
あと、たとえば Padrino framework を便利だから使いたいけど、コントローラを導入するのは大仰だなあ、みたいな時に代用として使えると思う。 Padrino::Application を継承したあなたのアプリケーションに register Sinatra::Namespace 宣言を追記すれば大丈夫? かな?
おまけ、今回のテストケース
Gemfile:
1 2 3 | group :test do gem 'rack-test', require: 'rack/test' end |
apps_testall.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | require 'minitest/unit' ['app1', 'app2', 'app3'].each {|app| require "./#{app}" } Bundler.require :test MiniTest::Unit.autorun module AppTest module Base include Rack::Test::Methods def test_access_root get '/' assert last_response.body =~ /Index!/ end def test_access_hoge get '/hoge' assert last_response.body =~ /Hoge!/ end def test_access_sub get '/sub' assert last_response.body =~ /Sub::Index!/ end def test_access_sub_foo get '/sub/foo' assert last_response.body =~ /Sub::Foo!/ end end class AppTest < MiniTest::Unit::TestCase include Base def app App1 end end class App2Test < MiniTest::Unit::TestCase include Base def app App2.new end end class App3Test < MiniTest::Unit::TestCase include Base def app App3.new end end end |
言い忘れていたけれど、全部 Ruby 1.9 系でないと動かないです、文法の差異を吸収すれば動くかも。




