Ruby 如何在Sinatra中使用DSL元编程
我正在尝试使用DSL来管理同一路线中的不同地区,如Ruby 如何在Sinatra中使用DSL元编程,ruby,sinatra,metaprogramming,Ruby,Sinatra,Metaprogramming,我正在尝试使用DSL来管理同一路线中的不同地区,如get”/test“。 这是一个学习如何扩展Sinatra的练习,因此Rack::Locale或类似工具不是有效的答案 基于请求JSON主体的主体,假设我以POST或PUT的形式接收JSON,我希望使用特定的语言环境进行响应 我目前有一个我认为我需要的赤裸裸的脚本: class Locale attr_reader :locale_id attr_reader :described_class alias :current_loca
get”/test“
。
这是一个学习如何扩展Sinatra的练习,因此Rack::Locale
或类似工具不是有效的答案
基于请求JSON主体的主体,假设我以POST或PUT的形式接收JSON,我希望使用特定的语言环境进行响应
我目前有一个我认为我需要的赤裸裸的脚本:
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
区域设置“cs”do
“捷克语”
#或数据库查询或字符串
结束
地点“en-UK”do
“英国英语”
#或数据库查询或字符串
结束
结束
因此,为了更清楚地澄清,我将尝试采用TDD方法:
作为用户,当我发送一个包含以下内容的JSON时:“locale”:“cs cs”
结果是捷克语。您阅读了吗
现在,您并没有真正扩展DSL。我会稍微重新设计它,因为它看起来像是要匹配case语句,但这意味着要创建大量的类或丑陋的匹配语句。但是,西纳特拉已经有了一些非常好的方式来匹配路线和条件。因此,类似这样的内容更为惯用:
post '/', :locale => "Czech" do
"Czech"
end
post '/', :locale => "British English" do
"British"
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/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
需要“sinatra/定位器”
类本地化“捷克”do
“捷克语”
结束
post'/',:locale=>“英国英语”do
“英国人”
结束
[“get”,“post”]。每个{动词|
发送动词“/*”do
“其他”
结束
}
跑如果应用程序文件==$0
结束
希望这能帮助你澄清一些事情。你能从路线处理程序那里展示你使用它的尝试吗?当然<代码>获取“/”do locale“cs cs”do“捷克”end locale“en UK”do“British english”end很抱歉,我无法在注释中正确设置格式。请勿使用注释添加代码或输入数据或所需结果。评论是针对要求澄清的问题和疑问。编辑您的问题,并将信息放入最初包含的位置。不要使用“已编辑”或“已更新”标记来标记更改,只需添加它,这样问题才有意义。如果必要的话,我们可以看到事情在何时何地发生了变化。非常感谢大家以正确的方式帮助我解决这个问题!哇@iain,非常感谢!这并不能完全满足我的需求,但从总体来看,这是一个很好的开始。问题是,我试图应用于区域设置的行为在Sinatra中,但它是为了扩展我正在研究的另一个DSL。我将更新我的问题以进一步澄清,但您的回答非常详细且具有分析性。@M.Litalek谢谢,我认为您发布了一个有趣的问题。我会继续关注这个问题进行编辑,如果我想到其他有用的东西,我会更新这个。不管怎样,我希望你能找到一个好的解决办法。
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
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