Morton Goldberg
11/23/2007 5:09:00 PM
On Nov 23, 2007, at 7:40 AM, Peter Vanderhaden wrote:
> I wrote a script that gets user input like this:
>
> $stdout.print "Do you want to change something else? (y/n): "
> $changeSE = gets.chomp
> if $changeSE =~ /^y/
> changeSomethingElse
> end
>
> After the prompt is printed, the script waits for the user to enter
> yes
> or no via stdinput. The script was written in a procedural format as
> opposed to OO. (I did that only because I'm in the process of
> learning
> OO, and needed the script asap.) I decided to rewrite the script
> using
> OO. Unfortunately, this part of the script doesn't work anymore. The
> prompt prints, then the script keeps going on its merry way. I've
> included the source for the script below. Can anyone (or everyone)
> see
> what I'm not doing correctly? If so, I'd appreciate it if you could
> explain how to correct the problem. I'd be extremely grateful for any
> and all comments and assistance.
> PV
>
> 1 #!/usr/bin/ruby
> 2 #
> 3 # fix1.rb - Fix common unitization file errors.
> 4 # 1. Remove header line.
> 5 # 2. Populate vendor label field with "NULL".
> 6 # 3. Change .TIF extension to lower case.
> 7 #
> 8 class Record
> 9
> 10 # Constructor.
> 11 def initialize (record_string)
> 12 @record = record_string
> 13 end
> 14
> 15 # Populates the volume label.
> 16 # regex: Start at the beginning of the line, match
> 17 # all non-comma characters, followed by 2 commas.
> 18 def fix_volume_label
> 19 # @record.sub!(/\d,,/,',NULL,')
> 20 @record.sub!(/^([^,]*),,/, '\1,NULL,')
> 21 end
> 22
> 23 # Change file extension to lowercase.
> 24 def fix_extension_case
> 25 @record.sub!('.TIF','.tif')
> 26 end
> 27
> 28 # Allow user to do a generic fix.
> 29 def changeSomethingElse
> 30 @record.sub!(before,after)
> 31 end
> 32
> 33 # Returns fixed record as a string
> 34 def to_str
> 35 @record
> 36 end
> 37
> 38 end
> 39
> 40 # Main thread of execution.
> 41 class FixOpt
> 42
> 43 def initialize
> 44
> 45 @ARGV = $* # list of arguments passed to the
> script
> 46 @header_regex = /BegBates,Volume,Path/
> 47
> 48 @in_file = nil
> 49 # @out_file = nil
> 50 unless arguments_valid? @ARGV
> 51 usage
> 52 exit -1
> 53 end
> 54
> 55 # Does user want to change something else?
> 56 def checkChange
> 57 puts "Do you want to change something else (y/N): "
> 58 changeIt = gets
> 59 if changeIt =~ /^[yY]/
> 60 puts "Enter string to change: "
> 61 before = gets.chomp
> 62 puts "Enter new string: "
> 63 after = gets.chomp
> 64 puts "Global change? (N/y): "
> 65 global = gets.chomp
> 66 end
> 67 end # End checkChange method.
> 68
> 69 begin
> 70 @in_file = File.new @ARGV[0], "r"
> 71 rescue IOError
> 72 @in_file.close
> 73 puts "Error opening input file, terminating"
> 74 exit -1
> 75 end
> 76
> 77 end # End initialize method.
> 78
> 79 # Runs the program - the [C]ontroller portion of the MVC pattern.
> 80 def run
> 81 begin
> 82 checkChange
> 83 @in_file.each do |record_line|
> 84 next if record_line =~ @header_regex
> 85 record = Record.new(record_line)
> 86 record.fix_volume_label
> 87 record.fix_extension_case
> 88 if changeIt =~ /^[yY]/
> 89 record.changeSomethingElse
> 90 end
> 91 puts record.to_str
> 92 end
> 93 rescue IOError
> 94 @in_file.close
> 95 puts "Error reading from input file, terminating"
> 96 exit -1
> 97 end
> 98 @in_file.close
> 99 exit 0 # success!
> 100 end
> 101
> 102 # these methods are marked :private becuase they are never
> to be
> called
> 103 # from anywhere outside of the class itself.
> 104 :private
> 105
> 106 # Validates command line arguments.
> 107 def arguments_valid? (argv)
> 108 # readable assumes the file exists, but doesn't check for it.
> 109 # File.stat(ARGV[0]).readable?
> 110 # Returns true if the named file exists and is a regular file.
> 111 File.file?(ARGV[0])
> 112 end
> 113
> 114 # Prints the usage message
> 115 def usage
> 116 puts
> 117 puts "Invalid filename entered: #{ARGV[0]}"
> 118 puts "Syntax: fix1.rb <filename>"
> 119 puts
> 120 end
> 121
> 122 end
> 123 fix_opt = FixOpt.new
> 124 fix_opt.run
>
> If I use gets, the script just prints the prompt and seems to end.
> If I use gets.chomp I get the following error:
> $ ruby d:/scripts/ruby/fix1.rb 99999.opt
> Do you want to change something else (y/N):
> d:/scripts/ruby/fix1.rb:58:in `checkChange': private method `chomp'
> called for nil:NilClass (NoMethodEr
> ror)
> from d:/scripts/ruby/fix1.rb:82:in `run'
> from d:/scripts/ruby/fix1.rb:124
I can not reproduce your problem. When I run
<code>
class Foo
def checkChange
puts "Do you want to change something else (y/N): "
changeIt = gets.chomp
if changeIt =~ /^[yY]/
puts "Enter string to change: "
before = gets.chomp
puts "Enter new string: "
after = gets.chomp
puts "Global change? (N/y): "
global = gets.chomp
end
p [changeIt, before, after, global]
end
end
Foo.new.checkChange
</code>
I see the following
<result>
Do you want to change something else (y/N):
Enter string to change:
Enter new string:
Global change? (N/y):
["y", "foo", "bar", "n"]
</result>
I will note the variables changeIt, before, after, and global are
local variables and will not available outside of the checkChange
method. That may be part of your problem.
Regards, Morton