Pat Newell
Pat Newell

Reputation: 2294

Modular Sinatra App: Can I Replace Blocks with Methods?

Have you had success refactoring your Sinatra Apps in this way?:

before

require 'sinatra/base'

class UserApp < Sinatra::Base
  get '/' do
    content_type :json
    User.all.to_json
  end

  get '/:id' do |id|
    content_type :json
    User.find(id).to_json
  end

  # etc, etc.  (there are many routes)
end

after?

require 'sinatra/base'
require 'user_routes'

class UserApp < Sinatra::Base
  register UserRoutes
end

# ----- a separate file -----
module UserRoutes
  def list
    content_type :json
    User.all.to_json
  end

  def find(id)
    content_type :json
    User.find(id).to_json
  end

  def self.registered(app)
    app.get '/', &UserRoutes.list # <-- this is the piece I cannot figure out
    app.get '/:id', &UserRoutes.find # <-- this is the piece I cannot figure out

    # etc, etc.  (there are many routes)
  end
end

I cannot seem to figure out how to pass the UserModule's methods to app.get in such a way that those methods are called with the same scope as simply passing a block (e.g., how can those methods have access to content_type and other Sinatra features).


ruby 2.0.0

this is a very simplified version of the problem

Upvotes: 0

Views: 73

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

First of all, to be able to call module methods with Module.method idiom you should declare them module-wide:

module UserRoutes
  #   ⇓⇓⇓⇓⇓
  def self.list
    content_type :json
    User.all.to_json
  end
  ...
end

Now you could:

app.get '/', &proc{ |_, *args| UserRoutes.send(:list, *args) }

Please be aware, that results in performance penalties.

Further reading.

Upvotes: 1

Related Questions