以任何方式捕获声明中常量的名称?

时间:2018-05-30 20:17:41

标签: ruby

我上课了。我们称之为SomeClass:

class SomeClass
end

我不想以正常的方式定义这个类的实例,而是想使用常量来定义它们:

MyConstant = SomeClass.new

我希望能够捕获某些类的常量名称,这与标准ruby类使用.class方法的方式非常相似。

MyConstant.name #-> "MyConstant"

我希望能够从某些类的所有实例中呈现更好的错误消息,如下所示:

class SomeClass 
  def display_error_message 
    "Error, some class #{self.name} has a problem"
  end
end

MyConstant.display_error_message
#-> "Error, some class MyConstant has a problem"

有什么方法可以做到这一点?

编辑

这是一个澄清我正在拍摄的例子。

(Enum是我正在创建的类的名称,它的作用类似于Swifts的Enum'类型。基本上它设置了一个预定义的选项列表(:pepperoni,:sausage,:mushroom)和raw_value (“Pepperoni”,“Sausage”,“Mushroom”。)显然在这个例子中,用于将符号转换为UpperCamel案例字符串的哈希或简单算法可以工作,但实际上enum类会做更多,但是这个示例显示了它的要点。

class Pizza 
  attr_reader :topping

  Toppings = Enum.new do 
    option(:pepperoni).set("Pepperoni")
    option(:sausage).set("Sausage")
    option(:mushrooms).set("Mushrooms")
  end

  def set_topping(symbol)
    @topping = Toppings[symbol]
  end
end

pizza = Pizza.new

### Happy Case
pizza.set_topping(:pepperoni)

### Sad Case (Error message shown below is what I'm trying to figure out)
pizza.set_topping(:spinach)
#-> Error. enum Toppings has no option spinach

2 个答案:

答案 0 :(得分:4)

变量只是引用对象的一种方式,变量的名称是无关紧要的。如果您说X = YY恰好是一个班级,那么Y班级已经有"Y"名称,因此您无法更改该名称。

就Ruby而言XY无法区分。

如果要更改名称,即使该子类没有做任何不同的操作,也可以创建一个子类:

X = Class.new(Y)
X.name
# => "X"
Z = X
Z.name
# => "X"

这样可以正确保留名称,但仅限于初始化的上下文中。我认为Ruby做了一些偷偷摸摸的事情,如果将一个新类分配给一个常量,它会分配一个名称,但对于普通变量,它不会:

x = Class.new(Y)
x.name
# => nil

所以这是一个特例。

这里的关键是,确实影响名称的子类与不具有变量引用的子类之间存在巨大差异。

还有其他一些奇怪的东西在这里,因为它看起来像某种程度上的类#34;知道"如果它被分配给某个东西,并且如果某个东西是一个常数,它会为自己窃取常数的名称:

z = Class.new
z.name
# => nil
Z = z
z.name
# => "Z"

正如他们在编程中所说:" Wat?"

答案 1 :(得分:1)

您的<div class="dropdown"> <button onclick="myFunction(event)" class="dropbtn">Dropdown</button> <div id="myDropdown" onclick="event.stopPropagation()" class="dropdown-content"> <label><input type="checkbox" value="Vanilla">Vanilla</label> <label><input type="checkbox" value="Chocolate">Chocolate</label> <label><input type="checkbox" value="Strawberry">Strawberry</label> </div> </div> <style> .dropbtn { background-color: #4CAF50; color: white; padding: 16px; font-size: 16px; border: none; cursor: pointer; } .dropbtn:hover { background-color: #3e8e41; } .dropdown { position: relative; display: inline-block; } .dropdown-content { display: none; position: absolute; background-color: #fff; min-width: 230px; overflow: auto; border: 1px solid #ddd; z-index: 1; } label { display: block; padding: 12px 16px; } .show { display:block; } </style> <script> function myFunction(e) { e.stopPropagation(); document.getElementById("myDropdown").classList.toggle("show"); } document.addEventListener('click', () => { document.getElementById("myDropdown").classList.remove("show"); }) </script> 课程可能如下所示:

Enum

现在,您几乎可以保留问题中的语法,并执行以下操作:

class Enum

  def initialize(name, &blk)
    @defined_options = {}
    @name = name.freeze
    instance_eval(&blk)
    @defined_options.freeze
  end

  def [](key)
    if @defined_options.key? key
      @defined_options[key].value
    else
      unfound_option = Option.new(@name, key)
      raise "Option #{unfound_option} not found."
    end
  end

  def to_s
    "#{@name}"
  end

  def inspect
    keys = @defined_options.keys.join(',')
    "#<#{self}::{#{keys}}>"
  end

  class Option
    attr_reader :value

    def initialize(enum_name, key)
      @value_initialized = false
      @enum_name = enum_name
      @key = key
    end

    def set(value)
      if @value_initialized
        raise "Value for #{self} can't be set to #{value} " +
              "because it is already initialized to #{@value}"
      else
        @value_initialized = true
        @value = value.freeze
      end
    end

    def to_s
      "#{@enum_name}::#{@key}"
    end

    def inspect
      "#<#{self}>"
    end

  end

private

  def option(sym)
    unless @defined_options.key? sym
      option = Option.new(@name, sym)
      @defined_options[sym] = option
    end

    @defined_options[sym]
  end

end

这可能会让您了解如何解决此问题。这只是课程的粗略草图,可能会根据您的需要进行调整。