这样的 dsl 很容易实现
build_after :some_server do |server|
server.add_service :my_service
end
如果想改为这样该怎么做呢?
build_after :some_server do
add_service :my_service
end
这样吗?
class Build
def add_service(service)
p "add service #{service}"
end
end
def build_after(server, &block)
Build.new.instance_eval(&block) if block_given?
end
build_after :some_server do
add_service :my_service
end
class Test
def run(sym, &block)
p sym
instance_eval &block
end
def pp(str)
p str
end
end
t = Test.new
t.run :hi do
pp :world
end
然后这样子写就好了
class Server::Configuration
include Qor::Dsl
node :build_after do
node :my_service
end
end
#1 楼 @kenshin54 #2 楼 @saiga 多谢,1 楼的做法可以分离一个 builder 对象,有助于理清关系,2 楼的方法比较简洁 #5 楼 @zhangjinzhu 哈哈,这个也很方便,不过我先试试最原始的方式,然后再简化
太巧了。这正好是我刚刚学习完的 codeschool 中 Ruby Bit 2 中的 dsl part 1 章节的内容。obj.instance_eval(&block) 会将 &block 中的 self 设置为调用他的对象,所以可以省去原来的 server. add_service 的前缀直接调用 add_service, 相当与 self.add_service
我这里有一个统计分析框架 statlysis 配置的实际例子,也是用的 instance_eval
,https://github.com/mvj3/statlysis/blob/master/lib/statlysis.rb#L34
实际效果比如:
Statlysis.setup do
set_database :local_statistic
daily UserRecord.where(item_type: "activity")
end
之前还有一个用来练手的 统计分析 DSL 设计,解决惰性加载 和 作用域 两个问题