ruby,为DSL创建类型而不会污染全局命名空间

时间:2015-11-25 13:22:34

标签: ruby types dsl

我有一个使用自定义类型的DSL(从基元继承的对象,即String),但我不想用它们污染全局命名空间,因为它们仅用于一些地方,没有其他地方。

如果我尝试将Types包装在与DSL执行上下文相同的模块名称空间中,我会得到NameErroruninitialized constant。我还试过包含包装类型的模块,甚至对Object类使用了改进,但没有任何作用。

由于问题的(相对)复杂性,我不确定这是否是你需要帮助我的,所以我猜测。

module Forms
  class Define
    class << self
      attr_accessor :forms
      def draw name, &script
        @forms[name] = new(&script)
      end
    end

    def initialize &description
      @meta = {}
      @section_counter = 0
      self.tree = Tree.new
      instance_eval &description
    end
  end
end

并像这样使用:

Forms::Define.draw 'Register' do
  #some dsl code...
end
编辑:谢谢,没有任何方式注意到错字。

由于人们似乎并不理解&#34;我有一个使用自定义类型的DSL&#34;并且&#34;我不想用它们污染全局命名空间&#34;我将更具体地说明问题。

我说我的类型是这样的:

class Some_Custom_Type < String
end

但是这样做会污染全局命名空间,所以如果我命名这样的类型:

module Forms
  class Some_Custom_Type < String
  end
end

然后尝试使用它:

Forms::Define.draw 'Register' do
  some_code_using Some_Custom_Type
  #some dsl code...
end

它会报错uninitialized constant Some_Custom_Type (NameError)

所以我再一次问清楚,在没有污染全局命名空间的情况下,如何确保Some_Custom_Type可用,而不会污染全局命名空间?

2 个答案:

答案 0 :(得分:1)

我不确定我是否理解这个问题,但可能会有所帮助:

@forms[name] = const_set(
  name, 
  Class.new(Object) do |c|
    c.send :define_method, :initialize, *args, &script
  end
)

致电Forms::Define.draw 'Register'后,您将获得一个班级Forms::Define::Register,可以随时随地使用。

答案 1 :(得分:1)

我通过创建界面解决了这个问题。

从OP中的例子给出:

module Forms
  module Types
    class Some_Custom_Type < String
    end
  end
end

我补充说:

module Forms
  module Types_Wrapper
    def some_custom_type
      Some_Custom_Type
    end
  end

  def self.included(child)
    child.include Types_Wrapper
  end
end

像这样添加:

module Forms
  class Define
    include Types
  end
end

可以像这样使用:

Forms::Define.draw 'Register' do
  some_code_using some_custom_type
  #some dsl code...
end

在:

Forms::Define.draw 'Register' do
  some_code_using Some_Custom_Type
  #some dsl code...
end

差异很小,但现在可以运行,而且我感觉更像DSL。