How to check syntax

G

Graham Nicholls

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
 
A

Andreas Schwarz

Graham said:
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.
 
R

Robert Klemme

Andreas Schwarz said:
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
 
G

Graham Nicholls

Robert said:
Exactly!

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

Kind regards

robert
OK, so its not a syntax error. Pedants :) 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
 
A

Andreas Schwarz

Graham said:
OK, so its not a syntax error. Pedants :) 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.
 
G

Graham Nicholls

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.
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
 
A

Andreas Schwarz

Graham said:
Andreas Schwarz wrote:

Graham Nicholls wrote:



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.
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.
 
A

Andreas Schwarz

Andreas said:
Graham said:
Andreas Schwarz wrote:

Graham Nicholls wrote:


OK, so its not a syntax error. Pedants :) 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.
 
J

Jamis Buck

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.




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
(e-mail address removed)
http://www.jamisbuck.org/jamis

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

James Britt

Andreas said:
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
 
G

Graham Nicholls

Andreas said:
Andreas Schwarz wrote:

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
 
G

Graham Nicholls

Jamis said:
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
 
J

Jamis Buck

Graham said:
Jamis Buck 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?
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
(e-mail address removed)
http://www.jamisbuck.org/jamis

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

Jim Weirich

Jamis said:
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).
 
G

Gavin Sinclair

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
 
D

Dick Davies

* Jamis Buck said:
Graham Nicholls (spam_filtered) wrote:
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...)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,408
Latest member
AlenaRay88

Latest Threads

Top