Рубиновые Динамические Классы.Как исправить «предупреждение: доступ к переменной класса с верхнего уровня» - PullRequest
13 голосов
/ 05 ноября 2011

Я пытаюсь написать программу, которая динамически определяет классы ruby ​​на основе конфигурации, прочитанной из файла. Я знаю, что могу использовать Class.new, чтобы сделать это. Вот пример программы:

x = [1,2,3]

Test = Class.new do
  @@mylist = x

  def foo
    puts @@mylist
  end
end

Test.new.foo

Когда я запускаю это, я получаю следующий вывод (работает с ruby ​​1.9.3p0):

c:/utils/test.rb:4: warning: class variable access from toplevel
c:/utils/test.rb:7: warning: class variable access from toplevel
1
2
3

Кто-нибудь знает, что вызывает эти предупреждения и как я могу от них избавиться?

Я пытался заменить строку, которая делает

@@mylist = x

с этим

class_variable_set(:@@mylist, x)

Но когда я делаю это, я получаю эту ошибку вместо:

c:/utils/test.rb:7: warning: class variable access from toplevel
c:/utils/test.rb:7:in `foo': uninitialized class variable @@mylist in Object (NameError)
        from c:/utils/test.rb:11:in `'

Заранее спасибо!

Ответы [ 4 ]

18 голосов
/ 23 мая 2012

Это не делает то, что вы думаете, что делает.Поскольку вы не создаете класс с ключевым словом class, ваша переменная класса устанавливается на Object, а не Test.Последствия этого довольно велики, поэтому Руби предупреждает вас.Переменные класса являются общими для предков, а объекты обычно наследуются от Object.

7 голосов
/ 05 ноября 2011

Просто чтобы убрать это предупреждение, вы должны использовать class_variable_set метод:

x = [1,2,3]

Test = Class.new do
  class_variable_set(:@@mylist, x)

  def foo
    puts @@mylist
  end
end
2 голосов
/ 16 октября 2018

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

$VERBOSE = nil

в верхней части вашего кода

2 голосов
/ 05 ноября 2011

Вместо того, чтобы определять переменную класса «mylist» в классе при объявлении класса, вы можете объявить переменные уровня класса позже, как показано ниже. Показаны два разных метода. Первый работает только в 1.9, последний работает в обеих версиях, но менее идиоматичен.

x = [1,2,3]

Test = Class.new do
  def foo
    puts @@mylist
  end
end

# ruby 1.9.2
Test.class_variable_set(:@@mylist, x)   

# ruby 1.8.7
Test.class_eval {
  @@mylist = x
}

Test.new.foo
...