1

I created a name generator.

When I try to save the results to a file it either enters a blank line or it says "true". I need it to put and say the generated name in the file.

Here's my code:

def generate_secondname
  dice = rand
  if dice > 0.01 && dice < 0.09
    print "saunders"
  elsif dice > 0.10 && dice < 0.19
    print "winters"
  elsif dice > 0.20 && dice < 0.29
    print "burgess"
  elsif dice > 0.30 && dice < 0.39
    print "webster"
  elsif dice > 0.40 && dice < 0.49
    print "holister"
  elsif dice > 0.50 && dice < 0.59
    print "johnson"
  elsif dice > 0.60 && dice < 0.69
    print "green"
  elsif dice > 0.70 && dice < 0.79
    print "paul"
  elsif dice > 0.80 && dice < 0.89
    print "hendrix"
  else dice > 0.90 && dice < 0.99
  print "luster"
  end
end


def generate_name(generate_secondname)
  dice = rand
  if (dice >= 0.01) && (dice <= 0.09)
    print "ashley"
    print "#{generate_secondname}"
  elsif dice > 0.10 && dice < 0.19
    print "george"
    print "#{generate_secondname}"
  elsif dice > 0.20 && dice < 0.29
    print "nick"
    print "#{generate_secondname}"
  elsif dice > 0.30 && dice < 0.39
    print "sam"
    print "#{generate_secondname}"
  elsif dice > 0.40 && dice < 0.49
    print "roland"
    print "#{generate_secondname}"
  elsif dice > 0.50 && dice < 0.59
    print "preston"
    print "#{generate_secondname}"
  elsif dice > 0.60 && dice < 0.69
    print "brandon"
    print "#{generate_secondname}"
  elsif dice > 0.70 && dice < 0.79
    print "sean"
    print "#{generate_secondname}"
  elsif dice > 0.80 && dice < 0.89
    print "ysabel"
    print "#{generate_secondname}"
  else dice > 0.90 && dice < 0.99
  print "patricia"
  print "#{generate_secondname}"
  end
end

file1 = File.new("randomname.txt", "a")

arr1 = []

name = generate_name(generate_secondname).to_s

file1.puts name.to_s

I tried putting the results into an array and then using:

arr1 << name
file.puts arr1

but it didn't work.

I also tried using hashes like:

file.puts "#{generate_name(generate_secondname)}"

which didn't work.

Inside the functions are just the rand method and a bunch of if/else statements with name strings.

marriedjane875
  • 653
  • 2
  • 10
  • 24
  • The file was already created. @shivam – marriedjane875 Apr 02 '15 at 15:11
  • An I'm just tryng to write to it....didn't know I was suppose to read it as well. @shivam – marriedjane875 Apr 02 '15 at 15:12
  • Did you double check that your `generate_name` function returns something (a name string obviously)? I ask this because you mention that the resulting file contains either a blank line or `true`. – zwippie Apr 02 '15 at 15:15
  • yes, the function print nothing but strings... names inside of quotations.@zwippie – marriedjane875 Apr 02 '15 at 15:23
  • Welcome to Stack Overflow: "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and *the shortest code necessary to reproduce it in the question itself*. Questions without a clear problem statement are not useful to other readers. See: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve)." We can't run your code, so please provide minimal code to allow us to do so. – the Tin Man Apr 02 '15 at 16:36
  • Okie doke, I added the functions code, hopefully that will help :) @theTinMan – marriedjane875 Apr 02 '15 at 21:14
  • @marriedjane875 see the edit to my answer – Mike S Apr 02 '15 at 22:43

2 Answers2

2

Ruby makes it really easy to open a file for appending, write to it and close it. The idiomatic way to do so is:

File.open('randomname.txt', 'a') do |fa|
  fa.puts 'foo'
end

We use the block form because Ruby will automatically close the file as soon as the block exists. That makes our code very clean.

A file opened for appending is just a series of bytes as far as Ruby is concerned. Basically the current file position is set to the end of the file before writing occurs, effectively appending. Nothing else is needed as far as our code is concerned.

Save the code above and run it twice and then look at "randomname.txt" and it will contain

foo
foo

When I try to save the results to a file it either enters a blank line or it says "true".

Then the problem exists elsewhere, not in the I/O section. You don't show us what is in

name = generate_name(generate_secondname).to_s

so it's impossible to debug your black box. Using basic debugging skills, you should break the problem into the smallest steps possible, and prove/disprove whether they are working. That's what the code above does, it proves that appending a fixed string works.

The second step would be to introduce your method which is supposed to generate the string being output. If the string output to the file is wrong then you immediately know the method is wrong, so begin testing there. Or, reverse the process and write code to test only your method, then test it surrounded by the File.open block. Either way, reduce the problem to its smallest steps.


(added after code was added to the question)

Back to your code...

else doesn't take a comparison or code, it only is else, so don't use this:

else dice > 0.90 && dice < 0.99

Instead use:

else

Your code also has some logic errors. rand returns a Float, and your code isn't adequately handling the value ranges possible. Consider this:

rand # => 0.5082475113018177

rand doesn't return a number rounded to 100ths, so its precision is going to squeeze through holes in your conditions:

dice = 0.091
if (dice >= 0.01) && (dice <= 0.09)
  puts "ashley"
elsif dice > 0.10 && dice < 0.19
  puts "george"
# elsif dice > 0.20 && dice < 0.29
#   puts "nick"
# elsif dice > 0.30 && dice < 0.39
#   puts "sam"
# elsif dice > 0.40 && dice < 0.49
#   puts "roland"
# elsif dice > 0.50 && dice < 0.59
#   puts "preston"
# elsif dice > 0.60 && dice < 0.69
#   puts "brandon"
# elsif dice > 0.70 && dice < 0.79
#   puts "sean"
# elsif dice > 0.80 && dice < 0.89
#   puts "ysabel"
else dice > 0.90 && dice < 0.99
  puts "patricia"
end
# >> patricia

dice is larger than 0.09 but less than 0.1, so there's your hole in action. The logic will fall through and hit the else any time the value doesn't match a range you want. (Of course that might be the desired result but you'd have to document that in the code and hope someone doesn't come along later and "fix" the problem because it's highly unintuitive to do it that way.)

Instead you need to close those holes. I'd do it using something like:

dice = 0.091
name = case 
       when dice >= 0.90
         "patricia"
       when dice >= 0.80
         "ysabel"
       when dice >= 0.70
         "sean"
       when dice >= 0.60
         "brandon"
       when dice >= 0.50
         "preston"
       when dice >= 0.40
         "roland"
       when dice >= 0.30
         "sam"
       when dice >= 0.20
         "nick"
       when dice >= 0.10 
         "george"
       else 
         "ashley"
       end
puts name
# >> ashley

By reversing the order of the tests I don't need to set the top boundary for the tests, and I don't have a problem with gaps. It's also a LOT easier to read.

Finally, don't do this:

"#{generate_second_name}"

It's wasting CPU time. generate_second_name already returns a string, so you're stringifying a string:

def generate_second_name()
  'foo'
end
generate_second_name.class # => String
"#{generate_second_name}".class # => String

Instead, use the bare generate_second_name instead.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Did you feel that how I worded this was not clear enough? Your answer is essentially the same content as mine, but you switched the syntax for the file writing. The theme is still breaking the problem down to find the root cause. – Mike S Apr 02 '15 at 22:44
  • 1
    There is a major difference in how you wrote the file handling. While yours works, it isn't idiomatic. Being redundant as far as debugging and breaking down the problem is just that, redundantly reinforcing that the OP needed to do more work to figure out the problem and explaining how to do it. If you're concerned about avoiding redundancy in answers you'll find Stack Overflow frustrating because we harp on some things because they're common sense and need to be emphasized. – the Tin Man Apr 03 '15 at 18:37
  • I'm not overly concerned about avoiding redundancy. I just felt like the answer was very similar. But I see your point about my answer suggesting additional work to figure the problem. I guess I was trying to outline the more general problem solving approach for a file writing issue. Thanks for the response. – Mike S Apr 03 '15 at 20:45
0

You need to break the problem into smaller pieces. First check whether you can write to a file at all. Make sure you don't have the files you're trying to write to already open with an editor.

begin
  file = File.open("/tmp/some_file", "w")
  file.write("your text") 
rescue IOError => e
  #some error occur, dir not writable etc.
ensure
  file.close unless file == nil
end

If that correctly writes "your text" then swap out the "your text" for your generate_name result. Next, you can change the location the file is being opened at. Assuming it still works you have eliminated the possibility that it was caused by a permissions issue. Lastly, try removing the file.close part to see if you can reproduce the same issue.

EDIT:

Upon looking at your generate_secondname method, I believe to fix your issue you simply need to change every instance of the word print to return.

For example:

...
if dice > 0.01 && dice < 0.09
    return "saunders" # you must return the strings, NOT print them
elsif dice > 0.10 && dice < 0.19
...

For generate_name you'll need to combine your strings before returning them. For example:

...
if (dice >= 0.01) && (dice <= 0.09)
  return "ashley #{generate_secondname}" # see how this is now 1 line, instead of 2
elsif dice > 0.10 && dice < 0.19
...
Community
  • 1
  • 1
Mike S
  • 11,329
  • 6
  • 41
  • 76
  • but it doesn't write my function to the file :\ ...Would I use the "#{functionname}" or without quotes? should I add a "to._s" because its still not working. @MikeSlutsky – marriedjane875 Apr 02 '15 at 16:03
  • I would do this: `file.write("#{generate_name(generate_secondname)}")` and on the following line do `puts "#{generate_name(generate_secondname)}"` to make sure that the file is getting the same text that you expect. – Mike S Apr 02 '15 at 16:08
  • nope, none of the functons results are goin inside the file now :\ @MikeSlutsky – marriedjane875 Apr 02 '15 at 16:16
  • What are you seeing outputted in your console when you do `puts "#{generate_name(generate_secondname)}"`? – Mike S Apr 02 '15 at 17:14
  • a blank space ...no entry. @MikeSlutsky – marriedjane875 Apr 02 '15 at 21:30
  • @marriedjane875 then that is your problem, your method is returning a blank space, which means you are *correctly* writing a blank space to the file, we can't help further if you don't show the code in your `generate_name` method – Mike S Apr 02 '15 at 22:37
  • Isn't there a shortcut to change all the "print"s to "return" ? @MikeSlutsky and thank you very much for your answer :) – marriedjane875 Apr 02 '15 at 23:07
  • @marriedjane875 that will depend on your editor, but generally yes you can do a "find and replace all" with pretty much any text editor – Mike S Apr 02 '15 at 23:19