2012-04-09 2 views
4

Я изучаю Ruby, и у меня есть ошибка, которую я не могу понять. У меня есть метод, который принимает массив строк (строк) и удаляет все строки до определенной строки, содержащей шаблон. Метод выглядит следующим образом:Ошибка Ruby: неопределенный метод `[] 'для nil: NilClass

def removeHeaderLines(lines) 
    pattern = "..." # Some pattern. 

    # If the pattern is not there, do not drop any lines. 
    prefix = lines.take_while {|line| (not line.match(pattern))} 
    if prefix.length == lines.length then 
    return prefix 
    end 

    # The pattern is there: remove all line preceding it, as well as the line 
    # containing it. 
    suffix = (lines.drop_while {|line| (not line.match(pattern))}).drop(1) 
    return suffix 
end 

Это прекрасно работает, и получившиеся строки (строки) будут корректно отображаться на веб-странице Я генерирующего.

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

def removeHeaderLines(lines) 
    pattern = "..." # Some pattern. 

    # If the pattern is not there, do not drop any lines. 
    prefix = lines.take_while {|line| (not line.match(pattern))} 
    if prefix.length == lines.length then 
    return prefix 
    end 

    # The pattern is there: remove all line preceding it, as well as the line 
    # containing it. 
    suffix = (lines.drop_while {|line| (not line.match(pattern))}).drop(1) 

    # Remove leading non-empty lines. 
    # ADDING THIS INTRODUCES A BUG. 
    body = suffix.drop_while {|line| (line != "")} 
    return body 
end 

Очень удивительно (по крайней мере, для меня) это не работает. На сгенерированной веб-странице вместо содержимого я вижу сообщение об ошибке: Ошибка жидкости: неопределенный метод `[] 'для nil: NilClass.

Я не могу понять это сообщение. Насколько я понимаю, некоторый код, вызывающий мой код, пытался получить доступ к объекту без массива, как если бы он был массивом. Но обе версии моего метода возвращают массив строк (оба суффикса переменных и тела установлены в массив строк), так почему же должна быть разница?

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

Не видите ли кто-либо ошибку в приведенном выше коде? В качестве альтернативы, есть ли у кого-нибудь какие-либо намеки относительно того, что может вызвать ошибку «неопределенный метод» [] для nil: NilClass?

EDIT

Дополнительная информация. Я расширяю код, который я сам не написал (он исходит от Octopress, файлы plugins/include_code.rb). Оригинальный код рендеринга выглядит следующим образом:

def render(context) 
    code_dir = (context.registers[:site].config['code_dir'].sub(/^\//,'') || 'downloads/code') 
    code_path = (Pathname.new(context.registers[:site].source) + code_dir).expand_path 
    file = code_path + @file 

    if File.symlink?(code_path) 
    return "Code directory '#{code_path}' cannot be a symlink" 
    end 

    unless file.file? 
    return "File #{file} could not be found" 
    end 

    Dir.chdir(code_path) do 

    ################################## 
    # I have replaced the line below # 
    ################################## 
    code = file.read 

    @filetype = file.extname.sub('.','') if @filetype.nil? 
    title = @title ? "#{@title} (#{file.basename})" : file.basename 
    url = "/#{code_dir}/#{@file}" 
    source = "<figure class='code'><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n" 
    source += " #{highlight(code, @filetype)}</figure>" 
    safe_wrap(source) 
    end 
end 

я заменил линию

code = file.read 

с

code = linesToString(removeHeaderLines(stringToLines(file.read))) 

, где два недостающих методы:

def stringToLines(string) 
    ar = Array.new 
    string.each_line {|line| ar.push(line)} 

    return ar 
end 

def linesToString(lines) 
    s = "" 
    lines.each {|line| s.concat(line)} 

    return s 
end 

Я надеюсь это поможет.

EDIT 2

Благодаря намеком Хасана (использовать метод присоединиться) Я нашел эту проблему! Параллельно методу соединения существует метод разделения. Так

"A\nB\n".split(/\n/) 

дает

["A", "B"] 

В то время как с помощью each_line (как я), один получает каждую строку с '\ п' в конце. Как следствие

suffix.drop_while {|line| (line != "")} 

удаляет все строки. Результатом стала пустая строка, которая, по-видимому, сбой библиотеки , которую я использую. Благодаря Хасану для обозначения более идиоматического решения. У меня есть :

def removeHeaderLines(code) 
    lines = code.split(/\r?\n/) 
    pat = /.../ # Some pattern. 
    index = lines.index {|line| line =~ pat} 
    lines = lines.drop(index + 1).drop_while {|line| line != ""} unless index.nil? 

    lines.join "\n" 
end 

и он отлично работает.

+0

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

+0

Какая версия рубина? – DanS

+0

Текст является исходным C-файлом. В начале каждого исходного файла в комментарии может быть добавлена ​​лицензия GNU. Этот комментарий должен быть удален. Вторая строка этого комментария содержит строку «www.gnu.org». Поэтому мой план состоит в том, чтобы удалить все ведущие строки до www.gnu.org, а затем все непустые строки (например, * ..., * /). После окончания главного комментария есть, по крайней мере, одна пустая строка перед началом реального кода. – Giorgio

ответ

0

Я не знаю, что вызывает исключение, но ваш код может выглядеть так:

def remove_header_lines(lines) 
    pattern = /some pat/ 
    index = lines.index {|lines| lines =~ pattern} 

    lines = lines.drop(index+1).drop_while {|lines| line != ""} unless index.nil? 

    lines.join 
end 
1

Это исключение возникает при попытке использовать nil как массив (или хэш):

irb(main):001:0> nil[0] 
NoMethodError: undefined method `[]' for nil:NilClass 
     from (irb):1 
     from /home/mslade/rubygems1.9/bin/irb:12:in `<main>' 

или использовать переменную как массив (или хэш), когда он не был инициализирован:

irb(main):005:0> @b[0] 
NoMethodError: undefined method `[]' for nil:NilClass 
     from (irb):5 
     from /home/mslade/rubygems1.9/bin/irb:12:in `<main>' 

Ищут, где вы пренебрегли для инициализации массива, с чем-то вроде @b = []

Если вы на самом деле не с помощью массива, т возможно, что функция, которую вы вызываете, ожидает. Просканируйте дамп стакада, начиная сверху, пока он не укажет строку вашего кода. Затем исследуйте эту строку, чтобы увидеть, что вы, возможно, пропустили.

+0

В чем смысл @ перед именем переменной? Нужно ли это с массивами? – Giorgio

+0

Переменные с префиксом '@' являются переменными экземпляра. –

Смежные вопросы