Andreas said:
This is almost impossible in dynamic languages like ruby. Variables can
be defined everywhere, in eval(), conditional code, etc. You don't find
out until you execute it.
I had a feeling that this was the case.
Could you elucidate. Typically this is pretty small stuff - my larger
projects tend to be coded in C, although unit testing can presumably be
applied there.
Heres a slice of code:
,----[ /home/graham/src/hsb/add_logo ]
| #!/usr/bin/env ruby
| #
| =begin
| Parse an input file (which is intended to be an Informix -produced text
| file containing PCL escape sequences) for a pattern which will introduce a
| logo. The pattern looks like this:
|
| .LOGO filename x,y
|
| where .LOGO (uppercase) is the special string, filename is the full path
| to the logo file (/usr/local/logos?) and x and y are optional coordinates
| for the logo which will otherwise be placed at the current file position.
|
|
| Skeleton taken from ttp_merge.
| The -c(onvert_euros) option from ttp_merge is kept, as when we move to
| CUPS,this is a process which will need to be applied, as there is no
| longer an interface file where we can do this.
|
| G.Nicholls : 23 Aug 2004
|
| =end
|
|
| # globals:
| $debug=false
| $verbose=false
| $convert_euros=false
| $progname=$0
| $ver=0.1
|
| # Constants
| USAGE_ERR=1
| BAD_FILE=2
| BAD_ARGS=3
| MISC_ERROR=255
|
| # "main" program
|
|
| def main(argv)
| output_fname = fname = nil
|
| $progname.gsub!(/^.*\//,'') # Get rid of everything in path up to last /
|
| argv.each do |arg|
| case arg
| when /-h(elp)?/
| usage()
| exit (0)
| when /^-c(onvert)?(_euros)?/
| $convert_euros=true
| when /^-f(orce)?/
| $force=true
| when /^-v(erbose)?/
| $verbose=true
| printf("%s version %s\n",$0.sub(/^.*\//,""),$ver)
| when /^-d/
| print("DEBUG: Version #{$ver}\n")
| $debug=true
| when /^-o(\S+)/
| output_fname=Regexp.last_match[1]
| else
| if fname != nil
| usage("Sorry, you can only specify one file to merge")
| exit(BAD_ARGS)
| end
| fname=arg
| end
| end
|
| if fname == nil
| usage("What file do you want me to logoise?\n")
| exit(USAGE_ERR)
| end
|
|
| if output_fname == nil
| output_fname=fname+".out"
| end
| if not $force
| if FileTest::exists?(output_fname)
| abort("Output file #{output_fname} exists already - use -f or -force to
| overwrite it\n") end
| end
|
| if $verbose
| print("#{$progname} : version #{$version} logoising file #{fname}\n")
| print("Writing output to #{output_fname}\n")
| if $force
| print("which will be overwritten if it exists\n")
| end
| end
|
| # OK process the file
| begin
| fdata=IO.readlines(fname)
| rescue => err
| abort("Error reading file #{fname} : #{err}\n",BAD_FILE)
| end
| # Match the pattern & an optional x,y part
| logo_patt=Regexp.compile(/^\s*\.LOGO\s+(\S+)(\s+([0-9]+)\s*
\s*([0-9]+))?.*$/)
| if $convert_euros
| euro_patt=Regexp.compile(/([\$\~][\w\d]+):/)
| end
|
| line_no=0
| fdata.each do |tline|
| line_no+=1
| if $debug
| printf("Line %d: \n[%s]\n",line_no,tline)
| end
| # Before searching for a logo,FIRST replace euros if relevant,
| # as there could be the euro char in the logo, where we do NOT want
| # to replace it as it simply binary data:
| if $convert_euros
| line.tr!(\174,\244)
| else
| line.tr!(\234,\273)
| end
|
|
|
| #
| # Search for the .LOGO lines
| #
| if (refs=logo_patt.match(tline)) != nil
| logo_file=Regexp.last_match[1]
| if $debug
| printf("Found a logo : including [%s]\n",logo_file)
| end
| begin
| # Insert the data from the include file
| logo_data=IO.readlines(logo_file)
| fdata=fdata[0..line_no-2] + logo_data + fdata[line_no..fdata.size()-1]
| rescue =>err
| printf("Error processing include file %s : %s\n",logo_file,err)
| end
| end
| end
|
| # OK, we now have an array with the merged data - write it:
|
| opfile=File.new(output_fname,"w")
| fdata.each do |tline|
| opfile.puts("#{tline}")
| end
| opfile.close
| end
|
| def abort(message=nil,errcode=MISC_ERROR)
| print message if message != nil
| exit(errcode)
| end
|
| def usage(message=nil)
| print message if message != nil
| print("Usage: #{$progname} -v -d -h(elp) -o[output_fname] [filename]\n")
| print("If output filename is not given, a suitable one will be
| constructed\n") end
|
|
##########################################################################################
|
| # OK, call main:
| main(ARGV)
`----
As you can see, theres not much to it - an hours work or so - I'd rather not
have to spend much time writing testing - ISTM its easier to fix a bug when
it rears than spend ages trying to eliminate all possible bugs
Thanks
Graham