Как использовать лотос-роутер с Rack::Builder::map

Есть ли способ использовать карту и пространство имен роутера (lotus) вместе? Ниже образец config.ru Я пытаюсь запустить как демо.

require 'bundler'
Bundler.require

module Demo

  class Application

    def initialize
      @app = Rack::Builder.new do
        map '/this_works' do
          run  Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["this_works"]]}
        end
        map '/api' do
          run Lotus::Router.new do
            get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
            get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
          end
        end
      end
    end

    def call(env)
      @app.call(env)
    end
  end  
end

run Demo::Application.new

1 ответ

Решение

Ваша проблема связана с приоритетом do..end в вызовах методов. В вашем коде раздел

run Lotus::Router.new do
  get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
  get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
end

анализируется Руби как

run(Lotus::Router.new) do
  get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
  get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
end

Другими словами, блок передается runне Lotus::Router.new как вы и хотели run просто игнорирует блок.

Чтобы исправить это, вам нужно убедиться, что блок связан с конструктором маршрутизатора, а не с вызовом run, Есть несколько способов сделать это. Вы могли бы использовать {...} скорее, чем do...end, поскольку это имеет более высокий приоритет:

run Lotus::Router.new {
  #...
}

Альтернативой было бы назначить маршрутизатор локальной переменной и использовать его в качестве аргумента run:

router = Lotus::Router.new do
  #...
end
run router
Другие вопросы по тегам