On Wed, 2011-12-28 at 22:56 -0700, Michael Havens wrote:
> I hate it when you are trying to learn something and what you are
> learning from is incomplete or wrong. This is the beginning of a ruby
> script I am writing which will (in the section shown) erase a file.
> ruby tells me that line 15 is wrong! It says:
>
> ex16.rb:15: undefined local variable or method `file' for
> main:Object (NameError)
>
> I am guessing that what line 15 is doing is telling the program to
> make file 'target' smaller but it needs to know how small and the guy
> who writes Learn Code the Hard Way forgot to include that in his
> tutorial. Or else I'm wrong and in that case please show me where I
> am wrong.
>
> 1 filename = ARGV.first #argument at command line is given a name
> 2 script = $0 #script is now titled file's name
> 3
> 4 puts "We're going to erase the contents of #{filename}."
> 5 puts "If you don't want to do that hit CTRL-C."
> 6 puts "If you do want to do that then hit RETURN."
> 7
> 8 print "? "
> 9 STDIN.gets #it waits for input before going on
> 10
> 11 puts "Opening the file..."
> 12 target = File.open(filename, 'w') #tells it to open filename or to
> write it if non-existant
> 13
> ^^^^is this right?^^^^^^^^^^
> 14 puts "Truncating the file. Goodbye!"
> 15 target.truncate(target.size)
My Diagnostic process:
First I input your program without any comments:
---------------------------------------------------------------------------
#!/usr/bin/env ruby
filename = ARGV.first
script = $0
puts "We're going to erase the contents of #{filename}"
puts "If you don't want to do that hit CTRL-C"
puts "If you want to do that then hit ENTER"
print "?"
STDIN.gets
puts "Opening the file..."
target = File.open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(target.size)
---------------------------------------------------------------------------
Then I ran it without any parameters:
---------------------------------------------------------------------------
kfries@kfries-laptop:Kevin$ ./sample.rb
We're going to erase the contents of
If you don't want to do that hit CTRL-C
If you want to do that then hit ENTER
?
Opening the file...
./sample.rb:14:in `initialize': can't convert nil into String
(TypeError)
from ./sample.rb:14:in `open'
from ./sample.rb:14
kfries@kfries-laptop:Kevin$
---------------------------------------------------------------------------
OK not good form, added a line after the filename = as such:
raise "Missing parameter\n\n\tUseage: $0 <filename>" if filename.nil?
ran again with no parameter:
---------------------------------------------------------------------------
kfries@kfries-laptop:Kevin$ ./sample.rb
./sample.rb:4: Missing parameter (RuntimeError)
Useage: $0 <filename>
kfries@kfries-laptop:Kevin$
---------------------------------------------------------------------------
Much better, always remember, any time you ask for input, then use it
(as
opposed to press enter to continue), validate it. In this case, I just
verified
that something was entered, not that it was correct.
Next I generated a sample file by doing an ls on /usr/bin, then tried to
truncate
that file with your program.
---------------------------------------------------------------------------
kfries@kfries-laptop:Kevin$ ls /usr/bin > junk.txt
kfries@kfries-laptop:Kevin$ ./sample.rb junk.txt
We're going to erase the contents of junk.txt
If you don't want to do that hit CTRL-C
If you want to do that then hit ENTER
?
Opening the file...
Truncating the file. Goodbye!
./sample.rb:18: undefined method `size' for #<File:junk.txt>
(NoMethodError)
kfries@kfries-laptop:Kevin$ ls -l
total 4
-rw-rw-r-- 1 kfries kfries 0 2011-12-29 09:30 junk.txt
-rwxrwxr-x 1 kfries kfries 425 2011-12-29 09:27 sample.rb
kfries@kfries-laptop:Kevin$
---------------------------------------------------------------------------
OK, better, it did what it was supposed to do, but then errored out.
The error states that the method .size does not exist on the object
File.
Lets see (using Ruby) what it does support:
---------------------------------------------------------------------------
kfries@kfries-laptop:Kevin$ irb
irb(main):001:0> target = File.open("junk.txt", "w")
=> #<File:junk.txt>
irb(main):002:0> target.size
NoMethodError: undefined method `size' for #<File:junk.txt>
from (irb):2
from :0
irb(main):003:0> target.methods
=> ["stat", "fileno", "find", "inspect", "tty?", "tap", "seek", "<<",
"print", "clone", "binmode", "take", "object_id", "__send__",
"public_methods", "read_nonblock", "reject", "lines", "ctime",
"instance_variable_defined?", "pos", "minmax", "readlines", "freeze",
"equal?", "closed?", "member?", "each", "sort", "extend", "partition",
"getc", "each_cons", "readbyte", "send", "pos=", "close_read", "any?",
"each_with_index", "methods", "lstat", "to_io", "detect", "hash",
"putc", "dup", "take_while", "sysseek", "instance_variables", "to_enum",
"bytes", "write_nonblock", "collect", "eof", "min_by", "eql?", "reopen",
"sort_by", "enum_cons", "ungetc", "group_by", "id", "instance_eval",
"truncate", "flock", "close_write", "one?", "enum_with_index", "to_i",
"singleton_methods", "each_line", "fsync", "find_index", "puts",
"taint", "ioctl", "drop", "instance_variable_get", "frozen?",
"enum_for", "chars", "chmod", "readpartial", "map", "display",
"instance_of?", "max_by", "method", "syswrite", "grep", "to_a", "flush",
"first", "instance_exec", "type", "isatty", "none?", "reverse_each",
"protected_methods", "find_all", "each_byte", "atime", "sync", "==",
"min", "gets", "===", "eof?", "fcntl", "drop_while",
"instance_variable_set", "path", "write", "each_slice", "chown",
"sync=", "getbyte", "inject", "respond_to?", "kind_of?", "minmax_by",
"close", "to_s", "sysread", "count", "printf", "tell", "class", "zip",
"private_methods", "=~", "tainted?", "__id__", "each_char", "mtime",
"lineno", "select", "readline", "rewind", "max", "untaint", "nil?",
"entries", "pid", "cycle", "enum_slice", "lineno=", "readchar",
"reduce", "read", "include?", "is_a?", "all?"]
irb(main):004:0> quit
kfries@kfries-laptop:Kevin$
---------------------------------------------------------------------------
OK, using IRB, I can confirm that the truncate command should work, and
the error message did not indicate a problem with that. It also does
not support size, and your error message did indicate that. So, the
error message is telling you, that size does not make sense on the File
object, and IRB, and the methods command confirms this.
So, what should be in there?
Well, RubyDoc is your friend, far more than any book can be. I looked
up File::truncate for ruby 1.8.7 (the version on my Ubuntu system) at
the following URL:
http://ruby-doc.org/core-1.8.7/File.html#method-c-truncate
And it gave me this:
---------------------------------------------------------------------------
truncate(file_name, integer) => 0
Truncates the file file_name to be at most integer bytes long. Not
available on all platforms.
f = File.new("out", "w")
f.write("1234567890") #=> 10
f.close #=> nil
File.truncate("out", 5) #=> 0
File.size("out") #=> 5
---------------------------------------------------------------------------
So, it is looking for an integer, to indicate how large you want the
file. It also shows the file method being used! So what went wrong???
IRB is showing no size method, and the documents shows it valid?
Well, you fell into a common problem of understanding scope. All
languages deal with this problem, and it manifests itself in lots of
different ways.
In this case, size() is a class method, not an instance method. What
this means is that, I can call size() against the class, and feed it a
filename, but it is not defined in a derived object. So, instead of
target.size, use File.size(filename).
Making this change the the program gives me this:
---------------------------------------------------------------------------
#!/usr/bin/env ruby
filename = ARGV.first
raise "Missing parameter\n\n\tUseage: $0 <filename>" if filename.nil?
script = $0
puts "We're going to erase the contents of #{filename}"
puts "If you don't want to do that hit CTRL-C"
puts "If you want to do that then hit ENTER"
print "?"
STDIN.gets
puts "Opening the file..."
target = File.open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(File.size(filename))
---------------------------------------------------------------------------
Now lets test it:
---------------------------------------------------------------------------
kfries@kfries-laptop:Kevin$ ls /usr/bin > junk.txt
kfries@kfries-laptop:Kevin$ ls -la
total 36
drwxrwxr-x 2 kfries kfries 4096 2011-12-29 10:00 .
drwxrwxrwt 22 root root 4096 2011-12-29 09:46 ..
-rw-rw-r-- 1 kfries kfries 22634 2011-12-29 10:02 junk.txt
-rwxrwxr-x 1 kfries kfries 433 2011-12-29 10:00 sample.rb
kfries@kfries-laptop:Kevin$ ./sample.rb junk.txt
We're going to erase the contents of junk.txt
If you don't want to do that hit CTRL-C
If you want to do that then hit ENTER
?
Opening the file...
Truncating the file. Goodbye!
kfries@kfries-laptop:Kevin$ ls -l
total 4
-rw-rw-r-- 1 kfries kfries 0 2011-12-29 10:03 junk.txt
-rwxrwxr-x 1 kfries kfries 433 2011-12-29 10:00 sample.rb
kfries@kfries-laptop:Kevin$
---------------------------------------------------------------------------
SUCCESS!!
I hope seeing me step through the debugging was helpful to you
Kevin
---------------------------------------------------
PLUG-discuss mailing list -
PLUG-discuss@lists.plug.phoenix.az.us
To subscribe, unsubscribe, or to change your mail settings:
http://lists.PLUG.phoenix.az.us/mailman/listinfo/plug-discuss