Найдите синтаксическую ошибку Ruby: NameError: неопределенная локальная переменная или метод ` '

Вот две строки Ruby, которые проверяют, сколько элементов в массиве являются «действительными» или «недействительными»:

valid = cr.select { |x| x.valid? }.count
invalid = cr.select { |x| !x.valid? }.count

Может ли кто-нибудь определить, почему во второй строке есть синтаксическая ошибка? Я просмотрел этот код в отладчике, и при попытке выполнить строку invalid = ... возникает исключение. Единственная разница между двумя строками — это !, и я проверил, что !true == false работает. Я в тупике.


Это весь файл кода:

require "colored"

require "address_kit/cli/interactive/command"
require "address_kit/cli/interactive/shell"

module AddressKit
  module CLI
    module Interactive
      module Commands

        class TableValidationStats < TableCommand
          NAME = "table_validation_stats"
          SUMMARY = "Displays statistics about the table address validation"
          HELP_TEXT = <<-TEXT.chomp.reset_indentation
            This command displays how many rows that has been validated, how
            many of those rows were valid, invalid or auto-corrected.
          TEXT

          def execute(context, args)
            super

            shell = context.shell
            results = context.vars[:address_processing_results] || []

            if results.length < 1
              shell.puts_padded "No rows have been processed"
              return
            end

            require "byebug"; byebug

            cr = results.compact
            total_processed = cr.count
            failed_parsing = cr.select { |x| !x.parsed? }.count
            valid = cr.select { |x| x.valid? }.count
            invalid = cr.select { |x| !x.valid? }.count
            corrected = cr.select { |x| x.corrected? }.count

            shell.puts
            shell.puts "Rows processed: #{total_processed.to_s.bold}"
            shell.puts "Parse failures: #{failed_parsing.to_s.bold}"
            shell.puts "Valid addresses: #{valid.to_s.bold}"
            shell.puts "Invalid addresses: #{invalid.to_s.bold}"
            shell.puts "Addresses auto-corrected: #{corrected.to_s.bold}"
            shell.puts
          end
        end

        Shell.register_command TableValidationStats

      end
    end
  end
end

Это ошибка с трассировкой стека (не обращайте внимания на дополнительный текст, мой проект печатает информацию об ошибке вручную):

  AN ERROR HAS OCCURRED!

  The command you just ran produced an unexpected error.
  Your shell session will not be lost, but please report
  the following text to the maintainer of this project:

  Exception: NameError
  Message: undefined local variable or method ` ' for #<AddressKit::CLI::Interactive::Commands::TableValidationStats:0x00000001a6b840>

  Stack trace:
  /home/tomas/Dropbox/Kvantel/Address Kit/lib/address_kit/cli/interactive/commands/table_validation_stats.rb:37:in `block in execute'
  /home/tomas/Dropbox/Kvantel/Address Kit/lib/address_kit/cli/interactive/commands/table_validation_stats.rb:37:in `select'
  /home/tomas/Dropbox/Kvantel/Address Kit/lib/address_kit/cli/interactive/commands/table_validation_stats.rb:37:in `execute'
  /home/tomas/Dropbox/Kvantel/Address Kit/lib/address_kit/cli/interactive/shell.rb:82:in `shell_iteration'
  /home/tomas/Dropbox/Kvantel/Address Kit/lib/address_kit/cli/interactive/shell.rb:46:in `start'
  bin/address_kit_shell:42:in `<main>'

А переменная cr представляет собой массив из AddressProcessingResult объектов. Они выглядят так:

module AddressKit

  # This class represents the end result of the processing of an address,
  # including normalization, parsing, validation and correction.
  class AddressProcessingResult
    attr_accessor :original_address, :parsed_address, :corrected_address, :note
    attr_writer :parsed, :validated, :valid, :corrected

    def initialize(original_address = nil)
      @original_address = original_address
      @parsed_address = nil
      @corrected_address = nil
      @note = ""
      @parsed = false
      @validated = false
      @valid = false
      @corrected = false
    end

    def parsed?; @parsed; end
    def validated?; @validated; end
    def valid?; @valid; end
    def corrected?; @corrected; end

    def readable_summary
      if not parsed?
        "Failed to parse address: #{@original_address}"
      elsif valid?
        "Address is valid: #{@parsed_address}"
      elsif corrected?
        "Address was auto-corrected: #{@corrected_address}: #{@note}"
      else
        "Address was invalid and could not be corrected: #{@corrected_address}"
      end
    end
  end

end

person Hubro    schedule 29.06.2013    source источник
comment
покажите нам ошибку..пожалуйста   -  person Arup Rakshit    schedule 30.06.2013
comment
@Priti: Это было глупо с моей стороны. Я предположил, что это простая и легко обнаруживаемая синтаксическая ошибка, поэтому я не удосужился включить что-либо еще. Я отредактировал вопрос сейчас.   -  person Hubro    schedule 30.06.2013
comment
какая здесь строка bin/address_kit_shell:42:in ‹main›'`?   -  person Arup Rakshit    schedule 30.06.2013
comment
Что будет, если удалить строку invalid = ..., будет ли тогда работать код?   -  person Casper    schedule 30.06.2013


Ответы (1)


Возможно, в вашем коде есть символ пробела Unicode (в результате копирования и вставки из другого места)? Ruby интерпретирует это как допустимое имя переменной! Доказательство:

script = <<-EOF
  #{"\u00A0"} = "foo"
  puts #{"\u00A0"}
EOF

puts "The contents of the script are:"
puts script

puts "The output of the script is:"
eval script

И вывод:

The contents of the script are:
    = "foo"
  puts  
The output of the script is:
foo

Я бы использовал шестнадцатеричный редактор или какой-либо другой скруббер для проверки символов Юникода в исходном коде. Я могу создать такое же сообщение об ошибке, например:

> eval "puts #{"\u00A0"}"
NameError: undefined local variable or method ` ' for main:Object

Вы можете сканировать файл на наличие символов, отличных от ASCII, следующим образом:

def find_nonascii(file)
  p_line = 1; p_char = 0
  open(file, "r").each_char do |char|
    if char.ord == 10
      p_line += 1
      p_char = 0
    end
    p_char += 1
    puts "Found character #{char.ord} (#{char.inspect}) at line #{p_line}, character #{p_char}" if char.ord > 126
  end
end

Это даст вам позицию первого символа, отличного от ascii, в сценарии.

Вы можете найти список пробелов Unicode здесь.

person Chris Heald    schedule 29.06.2013
comment
Почему вы предполагаете, что конец строки будет символом \r? (13.chr == "\r") - person Ian Stapleton Cordasco; 30.06.2013
comment
мозговой удар. Должно быть 10 :-) - person Chris Heald; 30.06.2013
comment
Я могу только предположить, что этот ответ правильный. Я стер и перепечатал каждый пробел в ошибочной строке и две строки выше и ниже, и теперь это работает без проблем. Однако я никогда ничего не вставлял, поэтому я, должно быть, каким-то образом создал странный пробел с помощью какой-то случайной комбинации клавиш. Спасибо за ответ! - person Hubro; 30.06.2013
comment
option-space предоставит вам Unicode NBSP, если вы работаете на Mac. Вероятно, так и произошло; может быть хорошей идеей посмотреть, можете ли вы настроить свой редактор для защиты от этого! - person Chris Heald; 01.07.2013
comment
@ChrisHeald: обновление: оказывается, моя клавиатура действительно производит неразрывные пробелы при нажатии AltGr+Space. Мне удалось отобразить символ NBSP для создания обычного символа пробела в Vim, поэтому проблема в основном исчезла. - person Hubro; 29.11.2013