I want to write a DSL
that works like this.
text = Screen.write do
label text: 'Something'
label text: 'stupid'
end
puts text => Somethingstupid
I don't know much metaprogramming ( I'm starting to learn it now) and the DSL tutorials online weren't really good. I think I should have something like this:
class Screen
attr_accessor :content
def initialize
@content = ""
end
def self.draw (&block)
self.instance_eval(&block)
@content
end
The problem is I have no idea about the label text:
part. This is maybe the most important part becasue I should later add functionality to it like label text: 'border', border: '|' => |border|
label text: 'border', border: '|' => |border|
and label text: 'UPCASE', style: :downcase => upcase
. So how should I tackle this problem. Any ideas and help are welcomed.
There're many different ways in which you can implement something like this. To keep it simple, you can just evaluate the block within a new Screen
object and return the result.
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}"
I see no reason to have any instance methods. Am I missing something?
Code
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 changes self
within the block to Screen
.
Examples
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"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.