Ruby Koan: Константы становятся символами

В about_symbols.rb Ruby Koan (https://github.com/edgecase/ruby_koans) у меня есть следующий код:

    RubyConstant = "What is the sound of one hand clapping?"
    def test_constants_become_symbols
      all_symbols = Symbol.all_symbols

      assert_equal true, all_symbols.include?(:"nonexistent")

      assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
      assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
    end

Как есть, тест проходит.

Три вопроса:

  • Почему первое утверждение проходит? :"nonexistent" не следует включать в all_symbols, но он включен, поэтому я должен что-то недопонимать.

  • Когда я комментирую второе утверждение, тест терпит неудачу, потому что "What is the sound of one hand clapping?".to_sym не включен во все_символы, тогда как :"What is the sound of one hand clapping?" включен. Поскольку они эквивалентны, почему последнее утверждение терпит неудачу? Кроме того, почему это происходит, когда второе утверждение не закомментировано? (Почему второе утверждение влияет на третье утверждение?)

  • Насколько я знаю, суть этого Ruby Koan заключалась в том, чтобы продемонстрировать, что константы становятся символами (по крайней мере, то, что я выводил из имени метода). Поскольку RubyConstant является константой со значением "What is the sound of one hand clapping?", почему нет "What is the sound of one hand clapping?".to_sym, включенного в список символов? Единственное объяснение, о котором я могу думать, это то, что, вопреки имени метода, константы фактически не становятся символами.

Спасибо за вашу помощь!

Ответ 1

hoha имеет это право, но я попытаюсь немного расширить и пояснить.

Интерпретатор создает символ :nonexistent, когда он анализирует test_constants_become_symbols. Затем, когда вы запустите его, вызывается Symbol.all_symbols, чтобы получить список всех известных символов, а :nonexistent - в списке. Также обратите внимание, что двойные кавычки на "nonexistent" являются проблемой синтаксиса, а не проблемой внутреннего представления, поэтому :nonexistent и :"nonexistent" - это одно и то же.

Если вы закомментируете это:

  assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")

тогда символ :"What is the sound of one hand clapping?" не будет восприниматься синтаксическим анализатором, поэтому он не будет находиться в массиве all_symbols. Вызов метода .to_sym в следующей строке выполняется, когда выполняется test_constants_become_symbols; поэтому символ :"What is the sound of one hand clapping?" создается после того, как вы получите all_symbols, и это не сработает:

  assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)

Если вы выполните test_constants_become_symbols снова в том же экземпляре интерпретатора (со вторым assert_equal все еще закомментированным), то оба uncommented assert_equal вызова пройдут, так как первый прогон через test_constants_become_symbols приведет к созданию :"What is the sound of one hand clapping?" и второй Symbol.all_symbols будет включать его в возвращенный массив.

Запуск кода в irb без его упаковки в def может помочь вам понять, что происходит.

Ответ 2

Я не гуру Ruby, но похоже, что интерпретатор создал эти символы во время оценки выражения def. Вот почему эти символы уже существуют, когда вы вызываете Symbol.all_symbols. Третий assert выходит из строя, а второй закомментирован, потому что "string".to_sym создает символ во время выполнения методов, т.е. После того, как вы получили доступные символы с all_symbols = Symbol.all_symbols.