我想写一个像这样的DSL
。
text = Screen.write do
label text: 'Something'
label text: 'stupid'
end
puts text => Somethingstupid
我不太了解元编程(我现在开始学习它),在线DSL教程并不是很好。我想我应该有这样的事情:
class Screen
attr_accessor :content
def initialize
@content = ""
end
def self.draw (&block)
self.instance_eval(&block)
@content
end
问题是我不知道label text:
部分。这可能是最重要的部分,因为我稍后应该添加label text: 'border', border: '|' => |border|
和label text: 'UPCASE', style: :downcase => upcase
等功能。那么我应该如何解决这个问题呢。欢迎任何想法和帮助。
答案 0 :(得分:3)
您可以通过许多不同的方式实现此类内容。为了简单起见,您只需在新的Screen
对象中评估块并返回结果。
class Screen
attr_reader :texts
def initialize
@texts = []
end
def label(hash)
# Validation + check for other keys
texts << hash[:text]
end
def to_s
texts.join
end
def self.write(&block)
raise "No block given" unless block_given?
Screen.new.tap do |s|
s.instance_eval(&block)
end
end
end
text = Screen.write do
label text: 'Something'
label text: 'stupid'
end
p "Rendered: #{text}"
答案 1 :(得分:0)
我认为没有理由拥有任何实例方法。我错过了什么吗?
<强>代码强>
class Screen
def self.hwrite(&block) write(false, &block) end
def self.vwrite(&block) write(true, &block) end
private
def self.write(vlabel, &block)
@str = ''
@vlabel = vlabel
instance_eval &block
end
def self.label(h)
@str << h[:text]
@str << '\n' if @vlabel
@str
end
end
BasicObject#instance_eval将块中的self
更改为Screen
。
<强>实施例强>
str = Screen.hwrite do
label text: 'Something '
label text: 'is amiss'
end
#=> "Something is amiss"
str = Screen.vwrite do
label text: 'Something is rotten in '
label text: 'the state of Denmark'
end
#=> "Something is rotten in \\nthe state of Denmark\\n"