如何在动态生成的模块中运行Proc?

时间:2011-07-17 23:37:39

标签: ruby module eval block dsl

这可能听起来令人困惑,但我正在与一个小团队的新人合作,而我正试图用红宝石中的一些东西来抽象,以使事情变得更顺利。我遇到问题的部分是命名空间。

基本上,具有ruby的命名空间可以创建为:

module EIF
  module Core
    module Entities
    #stuff
    end
  end
end

module EIF
end

module EIF::Core
end

module EIF::Core::Entities
#some stuff
end

事实上,这实在是很麻烦。我想要一些类似于C#的东西,你只需将命名空间定义为:

namespace EIF.Core.Entities
{
  #Some stuff
}

完成它。我设法通过使用eval创建模块(在将名称与正则表达式匹配后)得到类似的东西

def namespace(path)
  if path.match(/^([A-Z][a-zA-Z0-9]*)(::[A-Z][a-zA-Z0-9_]*)*$/)
    spaces = path.split("::")
    code = ""
    spaces.each { |m| code << "module #{m}\n" }
    spaces.each { code << "end\n" }
    eval(code)
  else
    raise ArgumentError, "'#{path}' is not a valid namespace"
  end
end

结果是我现在可以执行以下操作:

namespace "EIF::Core::Entities"
class EIF::Core::Entities::Attirbute
  #class code
end

现在进入下一步。我想使用ruby块来使事情更容易阅读,因此它看起来像:

namespace "EIF::Core::Entities" do
  class Attribute
    #class code
  end
end

myAttribute = EIF::Core::Entities::Attribute.new

问题是到目前为止,我发现在运行时创建模块的唯一方法是使用eval,当我尝试将代码块放入eval时,生成的类仍保留在根命名空间中。我已经尝试过instance_eval,module_eval和class_eval,并且由于某种原因没有在模块中创建类。

我能做到这一点吗?我现在不想放弃。

1 个答案:

答案 0 :(得分:2)

完成。

使用module_eval添加类时,似乎如下:

My::Namespace.module_eval do
  class MyClass
  end
end

MyClass的名称空间被解析为::而不管上下文如何。但是,写下:

class self::MyClass

命名空间被解析为当前的命名空间对象,因此生成的类定义将位于My :: Namespace

我不知道为什么会这样,但至少我得到了一些工作。现在的问题是,虽然这个更短,但是自我这个词是违反直觉的。