matthewarnold
matthewarnold

Reputation: 55

Outputting hash to text file

I am having trouble outputting the contents of my hash to a file. The program is one that manages a list of student records, including their StudentID, first name, last name, Major, and catalog year. Once the user is finished adding records, it is then added to the hash.

Everything in the program works perfectly, except when I try running the quit_program function, it doesn't save the contents in the file. Additionally, i am not getting any errors, any ideas?

could it potentially not be working because it is having trouble with converting the text in my hash, which is alphanumeric, into the text file?

def quit_program()

puts "Save Changes? y/n"

@changes = gets().chomp

if @changes=="y"


    @fh=File.open(@file_name, 'w')
    @this_string=""

    @sDB.each do |key, store_account_data| #line 50

    puts "#{key}: #{store_account_data.join(',')}"
    end
    end 

@fh.puts(@this_string)
@fh.close()     

end 

Upvotes: 1

Views: 1318

Answers (4)

the Tin Man
the Tin Man

Reputation: 160551

Your question is missing essential input data, so there's no way to test our suggested changes.

Here's untested code I'd work from:

def quit_program
  puts "Save Changes? y/n"
  if gets.chomp.downcase == 'y'
    File.write(
      @file_name,
      @s_db.map{ |k, v| "#{ k }: #{ v.join(',') }" }.join("\n")
    )
  end 
end 

Note:

  • @sDB isn't a proper variable name in Ruby. We use snake_case, not camelCase for variables and method names. ItsAMatterOfReadability. Follow the convention or suffer the wrath of your team members the first time you have a code review.
  • Don't add empty parenthesis to method names (quit_program()) or calls (gets()) unless it's essential to tell the difference between a variable and a method invocation. You should also never name a variable the same as a method because it'll confuse everyone working on the code, so that should never be a consideration.
  • Don't create a variable (@changes) you use once and throw away, unless what you're doing is so complex you need to break down the operation into smaller chunks. And, if you're doing that, it'd be a really good candidate for refactoring into separate methods, so again, just don't.
  • When comparing user-input to something you expect, fold the case of their input to match what you expect. (gets.chomp.downcase == 'y'). It really irritates users to enter "y" and fail because you insisted on "Y".
  • While you can use File.open to create or write to a file, there's less visual noise to use File.write. open is great when you need to use various options for the mode but for plain text write is sufficient.
  • The whole block used for writing looks like it can be cleaned up to a single map and join, which coerces the data into an array of strings then into a single string.

Upvotes: 1

madmax
madmax

Reputation: 26

The answer is given in the error message: undefined local variable or method 'sDB'. (Which you have since removed from your question making the edited version next to impossible to answer.) Where and when is sDB defined in your program? You are evidently attempting to quit before initializing it.

In any case it is not a good thing to be accessing instance variables directly inside other methods. You should use accessor (getter and setter) methods instead. That would have probably prevented this situation from biting you in the first place.

def sdb
  @sDB ||= Hash.new
end

def sdb=( key, value )
  sdb
  @sDB[ key ] = value
end
. . .

You are not properly writing to a file even if @sDB is defined. See Ruby - Printing a hash to txt file for an example.

Upvotes: 1

7stud
7stud

Reputation: 48599

it doesn't save the contents in the file.

The following is NOT how you write to a file:

puts "#{key}: #{store_account_data.join(',')}"

That is how you write to your terminal/console window.

And this code:

    @this_string=""

@fh.puts(@this_string)

writes a blank string to the file.

Here is how you write to a file:

class Student

  def initialize(sDB, filename)
    @sDB = sDB
    @filename = filename
  end

  def save_changes()
    puts "Save Changes? y/n"
    user_answer = gets().chomp

    if user_answer == "y"

      File.open(@file_name, 'w') do |f|
        @sDB.each do |key, store_account_data| #line 50
          f.puts "#{key}: #{store_account_data.join(',')}"
        end
      end

    end 

end 

could it potentially not be working because it is having trouble with converting the text in my hash, which is alphanumeric, into the text file?

No. Here is a concrete example you can try:

data = {
  "John" => ['a', 123, 'b', 456],
  "Sally" => ['c', 789, 'b', 0]
}

File.open('data.txt', 'w') do |f|
  data.each do |name, data|
    f.puts "#{name}: #{data.join(',')}"
  end
end

$ ruby myprog.rb 
$ cat data.txt
John: a,123,b,456
Sally: c,789,b,0

Also, ruby indenting is 2 spaces--not 0 spaces or 3 spaces, or anything else.

Upvotes: 1

rohit89
rohit89

Reputation: 5773

You're not writing anything to the file. The string @this_string is empty. You should do

@sDB.each do |key, store_account_data|
  @fh.puts "#{key}: #{store_account_data.join(',')}"
end

Upvotes: 1

Related Questions