【问题标题】:Very simple DSL in RubyRuby 中非常简单的 DSL
【发布时间】:2014-11-22 17:32:07
【问题描述】:

我想写一个像这样工作的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。那么我应该如何解决这个问题。欢迎任何想法和帮助。

【问题讨论】:

  • 我添加了一个“垂直”写入方法。

标签: ruby metaprogramming dsl


【解决方案1】:

您可以通过多种不同的方式来实现这样的功能。为简单起见,您只需评估新 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}"

【讨论】:

  • 感谢您的回答。多亏了这一点,我才能实现label 的所有功能。我还有一件事要问。我应该如何实现vertical 方法,以便它像这样工作:screen = Screen.write do// vertical do// label text: '1'// label text: '2'// label text: '3'// end// end//。抱歉,// 的格式是这样的。这应该产生字符串screen.to_s = "1\n2\n3\n"。我不知道该怎么做,因为我必须遍历不同的标签哈希,但我给出了一个块?
  • pesho,用我用过的方法:str = Screen.write do; label text: '1\n'; label text: '2\n'; label text: '3\n'; end?即puts str #=&gt; 1\n2\n3\n
  • @CarySwoveland 对不起,但我必须这样做,就像我展示的那样。我知道使用1\n 会更容易,但我想要这样,以便我以后可以将它与horizontal 方法结合使用并使用bout 的组合。第一个 horizontalvertical 或相反。
【解决方案2】:

我认为没有理由拥有任何实例方法。我错过了什么吗?

代码

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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    相关资源
    最近更新 更多