I'm creating a tool that will turn passwords into MD5 hashes within a YAML file, while running my program I'm getting the error:
md5.rb:20:in `encrypt_md5': undefined method `[]=' for nil:NilClass (NoMethodError)
from main.rb:12:in `main'
from main.rb:40:in `<main>'
From this method:
def encrypt_md5
hash = load_file
hash[:users][:"#{prompt('Enter username')}"] =
{password: prompt("Enter password")}
save_file(hash)
exit unless again?('encrypt md5')
end
#Digest::MD5 hasn't been implemented yet
I'm not entirely sure what is happening that's causing the nil:NilClass NoMethodError
, can somebody explain to me what this means and also tell me what I need to change in order for it to work..
Main.rb source:
require_relative 'md5.rb'
def main
puts <<-END.gsub(/^\s*>/, '')
>
>To load information type "L" to quit system type "Q"
>
END
input = gets.chomp.upcase
case input
when "L"
encrypt_md5
when "Q"
exit_system
else
exit_lock
end
end
def exit_system
puts "Exiting..."
exit
end
def exit_lock #Not finished, will lock user out of program
puts "Locked out, please contact system administrator"
exit
end
def again? #Not complete
puts "Encrypt more?"
input = gets.chomp
return input =~ /yes/i
end
def prompt( message )
puts message
gets.chomp
end
main
md5.rb source:
require 'yaml'
require 'digest'
private
def load_file
File.exist?('info.yml') ? YAML.load_file('info.yml') : {passwords: {}}
end
def read_file
File.read('info.yml')
end
def save_file
File.open('info.yml', 'w') { |s| s.write('info.yml')}
end
def encrypt_md5
hash = load_file
hash[:users][:"#{prompt('Enter username')}"] =
{password: prompt("Enter password")}
save_file(hash)
exit unless again?('encrypt md5')
end
The error is probably here:
hash = load_file
hash[:users][:"#{prompt('Enter username')}"] =
{ password: prompt("Enter password") }
You're calling the []=
method on hash[:users]
, but hash[:users]
is nil
. Since you didn't post the contents of info.yml
, I can only guess that you have a YAML file like this:
users:
some_user:
password: foobar
another_user:
password: abcxyz
# ...
When you do YAML.load_file
on that file, you get this Hash:
hash = {
"users" => {
"some_user" => { "password" => "foobar" },
"another_user" => { "password" => "abcxyz" },
# ...
}
}
With this, hash[:users]
is nil
because there's no :users
key, there's only a "users"
key. While you could jump through some hoops to turn your keys into symbols, it will be far easier to just use string keys everywhere:
hash = load_file
hash["users"][prompt('Enter username')] =
{ "password" => prompt("Enter password") }
P.S. There are some more problems with your code, in particular here:
def save_file
File.open('info.yml', 'w') { |s| s.write('info.yml')}
end
Firstly, you call save_file(hash)
, but your save_file
method doesn't take any arguments. This will raise an ArgumentError. Secondly, what the code in this method does is open the file info.yml
and then write the string "info.yml"
to that file. What you probably want is something like this:
def save_file(hash)
File.open('info.yml', 'w') {|f| f.write(hash.to_yaml) }
end