каким-либо образом захватить имя константы при объявлении - PullRequest
0 голосов
/ 30 мая 2018

У меня есть класс.Давайте назовем это 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 - это имя создаваемого мною класса, который должен действовать аналогично типу Swift '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 голосов
/ 31 мая 2018

Ваш 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

Теперь вы можете почти сохранить синтаксис, который у вас есть в вашем вопросе, и сделать следующее:

class Pizza 
  attr_reader :topping

  # I had to add the name in the initializer for better error reporting.
  Toppings = Enum.new('Toppings') 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)
#=> "Pepperoni"

### Sad Case (Error message shown below is what I'm trying to figure out)
pizza.set_topping(:spinach)
#=> RuntimeError: Option Toppings::spinach not found.

Это может дать вам представление о том, как решить эту проблему.Это всего лишь приблизительный набросок класса, и, возможно, его можно настроить в соответствии с вашими потребностями.

0 голосов
/ 30 мая 2018

Переменная - это просто способ ссылки на объект, и имя переменной не имеет значения.Если вы говорите, что X = Y и Y являются классом, то класс Y уже имеет имя "Y", поэтому вы не можете его изменить.

Что касается RubyX и Y неразличимы.

Если вы хотите изменить имя, вы можете создать подкласс, даже если этот подкласс не делает ничего другого:

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

Таким образомсохраняет имя правильно, но только в контексте инициализации.Я думаю, что Ruby делает что-то подлое, и если новый класс присваивается константе, он присваивает имя, но для обычных переменных это не так:

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

Так что это особый случай.

Ключевым моментом здесь является то, что существует огромная разница между подклассом, который влияет на имя, и ссылкой на переменную, которая этого не делает.

Здесь происходят некоторые другие странные вещи, которые выглядят каккласс каким-то образом «знает», когда он назначается чему-то, и если это что-то является константой, он крадет имя константы для себя:

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

Как говорят в программировании: «Ват?»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...