How to check syntax

Apologies if its a FAQ, but is there a way I can check my syntax for errors
that would otherwise only appear at runtime? You know the sort of thing:

        some code
        rescue => err
                exit (LOGIC_ERR)

        end

which when run fails because LOGIC_ERR is undefined, but will only fail when
this code is being run (ie in the rescue clause, which may be difficult to
simulate).

Thanks
Graham

···

--
The answer's always "Yes". Now, what's the question?

Graham Nicholls wrote:

Apologies if its a FAQ, but is there a way I can check my syntax for errors
that would otherwise only appear at runtime? You know the sort of thing:

        some code rescue => err
                exit (LOGIC_ERR)

        end

which when run fails because LOGIC_ERR is undefined

This is no syntax error, and it can only be detected at runtime.

"Andreas Schwarz" <usenet@andreas-s.net> schrieb im Newsbeitrag
news:4129dc1a$0$6639$9b4e6d93@newsread4.arcor-online.net...

Graham Nicholls wrote:
> Apologies if its a FAQ, but is there a way I can check my syntax for

errors

> that would otherwise only appear at runtime? You know the sort of

thing:

>
> some code
> rescue => err
> exit (LOGIC_ERR)
>
> end
>
> which when run fails because LOGIC_ERR is undefined

This is no syntax error, and it can only be detected at runtime.

Exactly!

For completeness reasons: syntax can be checked by doing "ruby -c".

Kind regards

    robert

Robert Klemme wrote:

"Andreas Schwarz" <usenet@andreas-s.net> schrieb im Newsbeitrag
news:4129dc1a$0$6639$9b4e6d93@newsread4.arcor-online.net...

Graham Nicholls wrote:
> Apologies if its a FAQ, but is there a way I can check my syntax for

errors

> that would otherwise only appear at runtime? You know the sort of

thing:

>
> some code
> rescue => err
> exit (LOGIC_ERR)
>
> end
>
> which when run fails because LOGIC_ERR is undefined

This is no syntax error, and it can only be detected at runtime.

Exactly!

For completeness reasons: syntax can be checked by doing "ruby -c".

Kind regards

    robert

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc. Now, I realize that this may be hard as
its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know what
I mean, python, perl(ugh!) Ruby & the like)
Ta.
Graham

···

--
The answer's always "Yes". Now, what's the question?

Graham Nicholls wrote:

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc.

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.

> Now, I realize that this may be hard as

its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know what
I mean, python, perl(ugh!) Ruby & the like)

Use unit tests.

Andreas Schwarz wrote:

Graham Nicholls wrote:

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc.

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.

> Now, I realize that this may be hard as

its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know
what I mean, python, perl(ugh!) Ruby & the like)

Use unit tests.

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

--
The answer's always "Yes". Now, what's the question?

Andreas Schwarz wrote:

Graham Nicholls wrote:

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc.

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.

> Now, I realize that this may be hard as

its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know what
I mean, python, perl(ugh!) Ruby & the like)

Use unit tests.

Just what I was going to suggest. I'm (re)writing Copland right now, refactoring to make unit testing easier, and unit testing has been a GODSEND. I've found bugs doing unit testing that I wouldn't have found otherwise until much, much later, bugs much like what the OP was asking about.

Admittedly, if you've never done unit testing before, it is something of a learning curve to (1) figure out the API (though it is wonderfully clean and straightforward compared to JUnit), and (2) learn how to write code that can be unit tested. However, TAKE THE TIME TO LEARN HOW TO DO IT! It will repay you many (many!) times over in time saved debugging difficult problems.

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

"I use octal until I get to 8, and then I switch to decimal."

Graham Nicholls wrote:

Andreas Schwarz wrote:

Graham Nicholls wrote:

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc.

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.

> Now, I realize that this may be hard as

its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know
what I mean, python, perl(ugh!) Ruby & the like)

Use unit tests.

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:

[...]

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

Your example seems to be very easy to test; feed it a few different files and compare the output to the expected result. This is especially helpful to make sure that you break anything when you change the code.

Jamis Buck wrote:

Andreas Schwarz wrote:

Graham Nicholls wrote:

Admittedly, if you've never done unit testing before, it is something of
a learning curve to (1) figure out the API (though it is wonderfully
clean and straightforward compared to JUnit), and (2) learn how to write
code that can be unit tested. However, TAKE THE TIME TO LEARN HOW TO DO
IT! It will repay you many (many!) times over in time saved debugging
difficult problems.

Where do I start, then (sigh!). Is this something I need simply to write
scripts to do - a la makefiles? - in fact ISTM that a make file would be
ideal - or am I missing something?
Ta
Graham

···

--
The answer's always "Yes". Now, what's the question?

Andreas Schwarz wrote:

Graham Nicholls wrote:

Andreas Schwarz wrote:

Graham Nicholls wrote:

OK, so its not a syntax error. Pedants :slight_smile: There ought to be a utility to
look for variable references, etc.

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.

> Now, I realize that this may be hard as

its presumably akin to part of writing a compile. What I'd like to know,
then is how to avoid the above - its a real nuisance in "scripting
languages" (Oh and if you don't like that term, get over it - you know
what I mean, python, perl(ugh!) Ruby & the like)

Use unit tests.

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:

[...]

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

Your example seems to be very easy to test; feed it a few different files and compare the output to the expected result. This is especially helpful to make sure that you

DON'T

···

break anything when you change the code.

Andreas Schwarz wrote:

Graham Nicholls wrote:
[...]

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

Your example seems to be very easy to test; feed it a few different files and compare the output to the expected result. This is especially helpful to make sure that you break anything when you change the code.

Bugs may not rear their heads until some notable damage is done in a production setting. Unit tests do more than help trap syntax errors or demonstrate that the code will actually run. The help show that your code is really doing what you intended it to do, not just what you told it to do. (This is not only an issue for so-called "scripting" languages; successful compilation of statically-typed code won't tell you if the program is well-behaved, only that you have served the gods of syntax.)

When you *do* find a bug in production code, unit tests help you make the fix without introducing new problems. I find that this is where tests offer the biggest the benefit. (Well, that and helping to guide API design.) As code grows, tests help speed up development by providing near-instant feedback, which helps keep you from introducing subtle execution errors that are time-consuming to track down.

James

Graham Nicholls (spam_filtered) wrote:

Jamis Buck wrote:

Andreas Schwarz wrote:

Graham Nicholls wrote:

Admittedly, if you've never done unit testing before, it is something of
a learning curve to (1) figure out the API (though it is wonderfully
clean and straightforward compared to JUnit), and (2) learn how to write
code that can be unit tested. However, TAKE THE TIME TO LEARN HOW TO DO
IT! It will repay you many (many!) times over in time saved debugging
difficult problems.

Where do I start, then (sigh!). Is this something I need simply to write
scripts to do - a la makefiles? - in fact ISTM that a make file would be
ideal - or am I missing something?
Ta
Graham

To start, I'd check out Nathaniel Talbott's documentation on test/unit:

   http://testunit.talbott.ws/doc/index.html

About halfway down the page (under Usage) it starts talking about how to use test/unit. Beyond that, I don't know of any resources for learning unit testing, although you should look at other libraries to see how they do their testing. ActiveRecord is a good one; I've also used unit tests in my SQLite/Ruby module. In a few days (hopefully) Copland 0.5.0 will be released and it has a pretty comprehensive unit testing suite as well.

Anyone know of any good resources for learning how to do unit testing in Ruby?

- Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

"I use octal until I get to 8, and then I switch to decimal."

Jamis Buck wrote:

Admittedly, if you've never done unit testing before, it is something of
a learning curve [...]

Graham Nicholls said:

Where do I start, then (sigh!). Is this something I need simply to write
scripts to do - a la makefiles? - in fact ISTM that a make file would be
ideal - or am I missing something?

The second volume of the Pragmatic Starter Kit covers unit testing, and it
comes from our very own Dave Thomas / Andy Hunt team! It covers JUnit,
but the principles carry over to Ruby's Test::Unit fairly directly.
Highly recommended.

Regarding makefiles ... I use Rake to handle make-like tasks. I almost
always make the test target the default in Rake, for I run the tests far
more than anything else. Rake does have some libraries for making run
test suites fairly painless (not that it has to do much, its pretty
painless already).

···

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Andreas Schwarz wrote:

Andreas Schwarz wrote:

Your example seems to be very easy to test; feed it a few different
files and compare the output to the expected result. This is especially
helpful to make sure that you

DON'T

break anything when you change the code.

In terms of the programs function, this is of course true, however I ran it
in an error (missing file ) condition, and found IIRC that I'd not defined
BAD_FILE, or it was BAD_FIEL, or something. This is a pain as it means for
a small script a lot of testing, potentially, unless I just get lazy and
write teh same exit code for everything, which is sort of OK, but this
applies to all sorts of things - even a small program has many branches.
Graham

···

--
The answer's always "Yes". Now, what's the question?

The second volume of the Pragmatic Starter Kit covers unit testing, and it
comes from our very own Dave Thomas / Andy Hunt team! It covers JUnit,
but the principles carry over to Ruby's Test::Unit fairly directly.
Highly recommended.

Sigh... must read...

Regarding makefiles ... I use Rake to handle make-like tasks. I almost
always make the test target the default in Rake, for I run the tests far
more than anything else. Rake does have some libraries for making run
test suites fairly painless (not that it has to do much, its pretty
painless already).

I disagree with that last statement. Ensuring that you're accessing
the correct library code when you run your tests is not painless IMO.
That's where Rake helps.

Gavin

···

On Tuesday, August 24, 2004, 4:01:40 AM, Jim wrote:

* Jamis Buck <jgb3@email.byu.edu> [0837 17:37]:

Graham Nicholls (spam_filtered) wrote:

>Where do I start, then (sigh!). Is this something I need simply to write
>scripts to do - a la makefiles? - in fact ISTM that a make file would be
>ideal - or am I missing something?

To start, I'd check out Nathaniel Talbott's documentation on test/unit:

  http://testunit.talbott.ws/doc/index.html

About halfway down the page (under Usage) it starts talking about how to
use test/unit. Beyond that, I don't know of any resources for learning
unit testing,

Theres' a good tutorial/talk by Nate here too:

http://rubycentral.org/2001/talks/testinginreverse/

I also bought the 'test driven development' book - it's java centric, but
still useful (although it becomes obvious fairly quickly that most
of the various java TDD tools only exist because of shortcomings in the
language...)

···

--
I could dance till the cows come home. On second thought, I'd rather
dance with the cows till you come home.
    -- Groucho Marx
Rasputin :: Jack of All Trades - Master of Nuns