2016-01-24 3 views
2

В моем рубиновоге коды, я определить новый хэш:`[] ': нет неявного преобразования символа в Integer (TypeError) для простого рубинового Hash

options = { 
     host: 'localhost', 
     user: nil, 
     file: nil, 
} 

я тогда анализировать хэш с помощью OptionsParser

OptionParser.new do |opts| 
    opts.banner = 'Usage: ruby-remote-tailer.rb [options]' 

    opts.on('-h', '--host', 'The host to run ssh session with') do |host| 
     options[:host] = "#{host}" 
    end 

    opts.on('-h', '--user', 'The user account that will run the session') do |user| 
     options[:user] = "#{user}" 
    end 

    opts.on('-f', '--file', 'The file to run the tail on') do |file| 
     options[:file] = "#{file}" 
    end 
end 

И бежать:

options = ARGV.parse! 
puts options[:host] 

последние кладет результаты строки в ошибки no implicit conversion of Symbol into Integer (TypeError). Я знаю, что ввод, который я вводил, верен, так как работает p options. Есть какие нибудь идеи как это починить?

(Примечание. Я бы предпочел не использовать цикл .each, как предлагается в других ответах, чтобы получить одиночные значения, которые мне нужны).

Спасибо.

+0

Какой выход из 'ставит options'? – Atri

+0

Выход будет остальным ARGV. Элементы, которые не соответствовали какому-либо из блоков .on. См. Мой ответ для полного объяснения. – aef

ответ

1

Вы не используете OptionParser правильно несколькими способами.

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

opts.on('-h', '--host HOST', 'The host to run ssh session with') do |host| 
    options[:host] = "#{host}" 
end 

Другая ошибка состоит в том, что вы определили -h для хоста и опции пользователя. Вам лучше определить другую букву для каждого из них, вы, вероятно, намеревались иметь -u для пользователя в любом случае.

Но основная проблема, вызвавшая ошибку, заключается в том, что вы обрабатываете возвращаемое значение метода #parse!, как если бы оно возвращало анализируемые значения. Но возвращаемое значение фактически является остатком массива ARGV, который не был согласован с синтаксическим анализатором. И поскольку вы пытаетесь получить к нему доступ, как хэш, попросив элемент по символу, он жалуется, что к элементам массива обращаются только значения Integer. Чтобы исправить это, просто сохраните ссылку options и не присваивайте ей возвращаемое значение.

ARGV.parse! 

С этого момента, я дам вам некоторую дополнительную критику, но то, что я буду рекомендовать не должно быть причиной каких-либо ошибок:

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

options = { 
    host: 'localhost' 
} 

Я бы сказал, называя #parse! на аргумент массива ARGV командной строки, в то время как это, кажется, вариант, чтобы сделать это, не очень очевидна. Я бы рекомендовал сохранить ссылку на парсер переменной и вызвать метод в синтаксическом анализаторе.

parser = OptionParser.new do |opts| 
… 
end 

parser.parse!(ARGV) 

Если вы хотите, вы можете даже назвать это без аргумента, он будет использовать ARGV по умолчанию. Но это, по моему мнению, еще раз затруднит понимание вашего кода.

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

opts.on('-h', '--host HOST', 'The host to run ssh session with') do |host| 
    options[:host] = host 
end 

Также обратите внимание, что есть очень, очень распространенное соглашение, что вы используете ровно два пространства для каждого уровня отступа в Ruby-кода. В ваших примерах вы используете четыре и восемь пробелов, которые многим рубистам очень не понравится. Дополнительную информацию см. В разделе The Ruby styleguide.

Вот исправленная версия кода:

#!/usr/bin/env ruby 

require 'optionparser' 

options = { 
    host: 'localhost' 
} 

parser = OptionParser.new do |opts| 
    opts.banner = 'Usage: ruby-remote-tailer.rb [options]' 

    opts.on('-h', '--host HOST', 'The host to run ssh session with') do |host| 
    options[:host] = host 
    end 

    opts.on('-u', '--user USER', 'The user account that will run the session') do |user| 
    options[:user] = user 
    end 

    opts.on('-f', '--file FILE', 'The file to run the tail on') do |file| 
    options[:file] = file 
    end 
end 

parser.parse!(ARGV) 
puts options[:host] 
Смежные вопросы