Модульное приложение Sinatra: можно ли заменить блоки методами?

Успешно ли вы реорганизовали свои приложения Sinatra таким образом ?:

до

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

после?

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

Кажется, я не могу понять, как передать методы UserModule в app.get таким образом, чтобы эти методы вызывались с той же областью, что и простая передача блока (например, как эти методы могут иметь доступ к content_type и другим функциям Sinatra).


ruby 2.0.0

это очень упрощенная версия проблемы


person Pat Newell    schedule 13.02.2015    source источник


Ответы (1)


Прежде всего, чтобы иметь возможность вызывать методы модуля с идиомой Module.method, вы должны объявить их для всего модуля:

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

Теперь вы могли:

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

Имейте в виду, что это приводит к штрафам за производительность.

Дополнительная литература.

person Aleksei Matiushkin    schedule 13.02.2015
comment
yikes ... большое спасибо за ответ @mudasobwa. Это кажется далеко не идеальным, и это еще не конец света, если я не смогу провести рефакторинг этого кода. Спасибо еще раз - person Pat Newell; 13.02.2015