Как использовать метапрограммирование DSL с Sinatra - PullRequest
1 голос
/ 17 января 2020

Я пытаюсь работать с DSL для управления разными локалями в рамках одного маршрута, например get "/test".

Это упражнение, чтобы узнать, как расширить Sinatra, поэтому Rack::Locale или аналогичный инструмент не является правильным ответом.

Основано на теле запроса JSON body, предполагая, что я получаю JSON как POST или PUT, я хочу ответить с указанием c locale.

В настоящее время у меня есть сценарий barebone, что мне нужно:

class Locale
  attr_reader :locale_id
  attr_reader :described_class

  alias :current_locale :locale_id

  def initialize(locale_id, &block)
    @locale_id = locale_id
    instance_eval &block
  end

end

def locale(locale_id, &block)
  Locale.new(locale_id, &block)
end

Мне не хватает возможности отвечать на основе локали в request.body JSON, который я получаю в качестве входных данных, и у класса здесь есть что-то еще, чего я пока не вижу, что необходимо или отсутствует.

Примером того, как это может быть использовано, будет:

get '/' do 
   locale 'cs-CS' do 
     "Czech"
     #or db query or string
   end 
   locale 'en-UK' do 
     "British english"
     #or db query or string
   end
end

Поэтому, чтобы попытаться прояснить это еще яснее, я попытаюсь с подходом TDD:

Как пользователь, когда я отправляю JSON, который содержит: "locale": "cs-CS" результат - чешский.

1 Ответ

2 голосов
/ 23 января 2020

Читали ли вы Расширение DSL и раздел Условия README ?

В данный момент вы на самом деле не расширяете DSL. Я бы немного переработал его, потому что похоже, что вы хотите сопоставить оператор case, но это будет означать создание большого количества классов или ужасного оператора сопоставления. Но у Синатры уже есть несколько действительно хороших способов соответствовать на маршрутах и ​​условиях. Итак, что-то вроде этого было бы более идиоматическим c:

post '/', :locale => "Czech" do
  "Czech"
end

post '/', :locale => "British English" do
  "British"
end

или

post '/', :locale => "en-GB" do
  "cs-CS"
end

post '/', :locale => "cs-CS" do
  "cs-CS"
end

Как это сделать? Сначала вам понадобится фильтр для преобразования входящего JSON:

before do
  if request.media_type == "application/json"
    request.body.rewind
    @json = JSON.parse request.body.read
    @locale = @json["locale"] && Locales[@json["locale"]]
  end
end

, а затем вам понадобится условие для проверки:

set(:locale) {|value|
  condition {
    !!@locale && (@locale == value || @json["locale"] == value)
  }
}

Все вместе ( app.rb):

require 'sinatra'

Locales = {
  'cs-CS' => "Czech",
  'en-GB' => "British English"
}

before do
  if request.media_type == "application/json"
    request.body.rewind
    @json = JSON.parse request.body.read
    @locale = @json["locale"] && Locales[@json["locale"]]
  end
end


set(:locale) {|value|
  condition {
    !!@locale && (@locale == value || @json["locale"] == value)
  }
}


post '/', :locale => "en-GB" do
  "cs-CS"
end


post '/', :locale => "cs-CS" do
  "cs-CS"
end

Это работает, но не будет работать как расширение. Итак, опираясь на документы, которые я разместил сверху:

require 'sinatra/base'

module Sinatra
  module Localiser

    Locales = {
      'cs-CS' => "Czech",
      'en-GB' => "British English"
    }

    def localise!(locales=Locales)
      before do
        if request.media_type == "application/json"
          request.body.rewind
          @json = JSON.parse request.body.read
          @locale = @json["locale"] && locales[@json["locale"]]
        end
      end

      set(:locale) {|value|
        condition {
          !!@locale && (@locale == value || @json["locale"] == value)
        }
      }
    end
  end
  register Localiser
end

Теперь он расширит DSL. Например:

require "sinatra/localiser"
class Localised < Sinatra::Base
  register Sinatra::Localiser

  localise!


  post '/', :locale => "Czech" do
    "Czech"
  end


  post '/', :locale => "British English" do
    "British"
  end


  ["get","post"].each{|verb|
    send verb, "/*" do
      "ELSE"
    end
  }

  run! if app_file == $0
end

Надеюсь, это поможет вам кое-что прояснить.

...