Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use lotus router with Rack::Builder::map

Is there a way to use map and the (lotus)router namespacing together? Below is a sample config.ru I'm trying to get running as a demo.

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
like image 813
Krut Avatar asked Mar 13 '14 01:03

Krut


1 Answers

Your problem is due to the precedence of do..end in method calls. In your code the section

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

is parsed by Ruby as

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

In other words the block is passed to run, not to Lotus::Router.new as you intended, and run simply ignores the block.

To fix it you need to ensure the block is associated with the constructor of the router rather than the call to run. There are a couple of ways to do this. You could use {...} rather than do...end, as that has a higher precedence:

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

An alternative would be to assign the router to a local variable, and use that as the argument to run:

router = Lotus::Router.new do
  #...
end
run router
like image 80
matt Avatar answered Sep 19 '22 18:09

matt