如何在 Sinatra 中使用 DSL 元编程
How to use DSL metaprogramming with Sinatra
我正在尝试使用 DSL 来管理同一路由中的不同区域设置,例如 get "/test"
。
这是学习如何扩展 Sinatra 的练习,因此 Rack::Locale
或类似工具不是有效答案。
根据请求的正文 JSON 正文,假设我收到 JSON 作为 POST 或 PUT,我想用特定的语言环境进行响应。
我目前有一个我认为需要的准系统脚本:
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 中的语言环境进行响应的功能,而这里的 class 还有一些我还没有看到的东西需要或丢失。
如何使用它的一个例子是:
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"
结果是捷克语。
你读过Extending The DSL and the Conditions section of the README了吗?
现在,您并没有真正扩展 DSL。我会稍微重新设计它,因为它看起来像您想要匹配 case 语句,但这意味着创建很多 类 或丑陋的匹配语句。但是,Sinatra 已经有一些非常好的方法来匹配路线和条件。所以,像这样的东西会更惯用:
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 == [=16=]
end
希望这能帮助您澄清一些事情。
我正在尝试使用 DSL 来管理同一路由中的不同区域设置,例如 get "/test"
。
这是学习如何扩展 Sinatra 的练习,因此 Rack::Locale
或类似工具不是有效答案。
根据请求的正文 JSON 正文,假设我收到 JSON 作为 POST 或 PUT,我想用特定的语言环境进行响应。
我目前有一个我认为需要的准系统脚本:
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 中的语言环境进行响应的功能,而这里的 class 还有一些我还没有看到的东西需要或丢失。
如何使用它的一个例子是:
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"
结果是捷克语。
你读过Extending The DSL and the Conditions section of the README了吗?
现在,您并没有真正扩展 DSL。我会稍微重新设计它,因为它看起来像您想要匹配 case 语句,但这意味着创建很多 类 或丑陋的匹配语句。但是,Sinatra 已经有一些非常好的方法来匹配路线和条件。所以,像这样的东西会更惯用:
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 == [=16=]
end
希望这能帮助您澄清一些事情。