Forum: Ruby String > Integer Conversion Problem

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4a7e2176f1474dbecd9567cda3ffa3a7?d=identicon&s=25 Matthew Feadler (mfeadler)
on 2005-12-21 23:39
Retro thanks to all who helped me with my last post.  I'm certainly more
comfortable with Ruby now than then, but still a newbie as the following
will surely demonstrate.

Below, you can see that I'm checking command-line arguments to the
program for various conditions.  Unfortunately, because the args are
stored as strings, when I convert them via to_i, empty and non-numerical
strings become 0.  0 is an acceptable element in this program, therefore
I can't use it to test for invalid input.  I've worked around this (sort
of), by creating two sets of variables for the arguments (one set as
strings, one set as integers).  Unfortunately, this complicates the
code, and more importantly, leaves me stumped concerning how to test for
non-numeric values.

So, the program does what I want, except when the args are non-numeric
strings, and the code seems uglier than it ought to be.

Thanks in advance,

-ELf

def gen_chart(max)
  x=0
  y=0
  local_chart = Array.new
  while x<=max
    y+=x
    local_chart[x]=y
    x+=1
  end
  local_chart
end

arg0 = ARGV[0]
arg1 = ARGV[1]

arg0i = ARGV[0].to_i
arg1i = ARGV[1].to_i

if arg0.nil? or (arg0i < 0) or (arg1i < 0)
  #print usage
  print <<-EOS

No args, or bad args!

Usage: #$0 [maxvalue]
       #$0 [minvalue] [maxvalue]
  EOS
elsif arg1.nil?
  #do chart to arg0, print last pair
  chart = gen_chart(arg0i)
  puts arg0i.to_s + ": " + chart[arg0i].to_s
else
  #do chart to arg1, print pairs from arg0 to last
  chart = gen_chart(arg1i)
  x=arg0i
  y=arg1i
  while x<=y
    puts x.to_s + ": " + chart[x].to_s
    x+=1
  end
end
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2005-12-21 23:57
(Received via mailing list)
On Dec 21, 2005, at 4:39 PM, Matthew Feadler wrote:

> Below, you can see that I'm checking command-line arguments to the
> program for various conditions.

See if this gives you some ideas:

if ARGV.all? { |n| n =~ /\A\d+\Z/ }
   puts "Usage..."
   exit
else
   one, two = ARGV.map { |n| Integer(n) }
end

Hope that helps.

James Edward Gray II
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2005-12-22 00:15
(Received via mailing list)
On 12/21/05, Matthew Feadler <matthew@feadler.com> wrote:
> strings, one set as integers).  Unfortunately, this complicates the
> def gen_chart(max)
>
> No args, or bad args!
>   chart = gen_chart(arg1i)
>   x=arg0i
>   y=arg1i
>   while x<=y
>     puts x.to_s + ": " + chart[x].to_s
>     x+=1
>   end
> end

Maybe this will give you an idea or two:

require 'test/unit'

def process_command_line_arguments args
  results = []
  args.each do |arg|
    raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)
    arg = arg.to_i
    results << arg
  end
  results
end

class TestThis < Test::Unit::TestCase
  def test_command_line_processing
    assert_equal [2],    process_command_line_arguments(["2"])
    assert_equal [2, 3], process_command_line_arguments(["2", "3"])
    assert_raise(RuntimeError) { process_command_line_arguments(["-1"])
}
    assert_raise(RuntimeError) { process_command_line_arguments(["1",
"oog"]) }
    assert_raise(RuntimeError) { process_command_line_arguments(["boo",
"oog"])}
  end
end



$ ruby a.rb
Loaded suite a
Started
.
Finished in 0.001163 seconds.

1 tests, 5 assertions, 0 failures, 0 errors
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2005-12-22 00:18
(Received via mailing list)
On 12/21/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > of), by creating two sets of variables for the arguments (one set as
> >
> > end
> >
> >   #do chart to arg1, print pairs from arg0 to last
>
> end
>
>
>
> $ ruby a.rb
> Loaded suite a
> Started
> .
> Finished in 0.001163 seconds.
>
> 1 tests, 5 assertions, 0 failures, 0 errors
>

Whoops, this is probably better:

def process_command_line_arguments args
  args.map do |arg|
    raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)
    arg.to_i
  end
end

Passes all the tests.
37a3c73ffbf864e4b28f7f2384ee12ce?d=identicon&s=25 Timothy Hunter (tim-hunter)
on 2005-12-22 00:18
(Received via mailing list)
Matthew Feadler wrote:
> strings, one set as integers).  Unfortunately, this complicates the
> code, and more importantly, leaves me stumped concerning how to test for
> non-numeric values.

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2005-12-22 00:21
(Received via mailing list)
On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:
> else
>    one, two = ARGV.map { |n| Integer(n) }
> end

Neat, didn't know about Enumerable#all? or about Integer().
Cff9eed5d8099e4c2d34eae663aae87e?d=identicon&s=25 Jacob Fugal (Guest)
on 2005-12-22 01:15
(Received via mailing list)
On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:
> The Integer() method raises ArgumentError if given an empty,
> non-numeric, or otherwise non-well-formed string.

On 12/21/05, James Edward Gray II <james@grayproductions.net> wrote:
> if ARGV.all? { |n| n =~ /\A\d+\Z/ }
>    puts "Usage..."
>    exit
> else
>    one, two = ARGV.map { |n| Integer(n) }
> end

So could we rewrite this as:

begin
  one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
  puts Usage
  exit
end

?

Jacob Fugal
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2005-12-22 01:24
(Received via mailing list)
Hi --

On Thu, 22 Dec 2005, Matthew Feadler wrote:

> strings, one set as integers).  Unfortunately, this complicates the
> code, and more importantly, leaves me stumped concerning how to test for
> non-numeric values.
>
> So, the program does what I want, except when the args are non-numeric
> strings, and the code seems uglier than it ought to be.

In addition to the other suggestions, you might find scanf useful:

   require 'scanf'
   arg0, arg1 = ARGV.join.scanf("%d%d")

or something like that.


David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2005-12-22 01:39
(Received via mailing list)
On Thu, 22 Dec 2005 00:21:39 -0000, <dblack@wobblini.net> wrote:

> In addition to the other suggestions, you might find scanf useful:
>

Me too. I'm definitely getting tunnel vision on the core doc, and
ignoring
the standard library a bit. Thanks for another good lead :)
37a3c73ffbf864e4b28f7f2384ee12ce?d=identicon&s=25 Timothy Hunter (tim-hunter)
on 2005-12-22 01:54
(Received via mailing list)
Jacob Fugal wrote:
> begin
>   one, two = ARGV.map{ |n| Integer(n) }
> rescue ArgumentError
>   puts Usage
>   exit
> end

When the arguments to Integer are strings from the command line, yes. In
the general case Integer() can raise TypeError as well as ArgumentError,
for arguments like Integer([1,2])
Cff9eed5d8099e4c2d34eae663aae87e?d=identicon&s=25 Jacob Fugal (Guest)
on 2005-12-22 02:00
(Received via mailing list)
On 12/21/05, Timothy Hunter <cyclists@nc.rr.com> wrote:
> for arguments like Integer([1,2])
True, but I *was* referring specifically to the command line; vis the
OP's question, and evidenced by my use of ARGV. :)

Jacob Fugal
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2005-12-22 05:21
(Received via mailing list)
On Dec 21, 2005, at 6:13 PM, Jacob Fugal wrote:

>> end
>
> So could we rewrite this as:
>
> begin
>   one, two = ARGV.map{ |n| Integer(n) }
> rescue ArgumentError
>   puts Usage
>   exit
> end

Yeah, that's better.  Neither of our versions checks the number of
arguments though and we probably should...

James Edward Gray II
Ace7fa5337acbdf5897a6fc035897580?d=identicon&s=25 J. Ryan Sobol (Guest)
on 2005-12-22 05:27
(Received via mailing list)
On Dec 21, 2005, at 11:20 PM, James Edward Gray II wrote:

>>   one, two = ARGV.map{ |n| Integer(n) }

Excuse my ruby "newb-ness", but what does this line actually do?
Mainly, what's throwing me off is the "one, two" assignment (or
whatever it is).
Fee23d1fc58edee59e05d7a52dcf172e?d=identicon&s=25 Kevin Brown (Guest)
on 2005-12-22 05:39
(Received via mailing list)
On Wednesday 21 December 2005 22:26, J. Ryan Sobol wrote:
> On Dec 21, 2005, at 11:20 PM, James Edward Gray II wrote:
> >>   one, two = ARGV.map{ |n| Integer(n) }
>
> Excuse my ruby "newb-ness", but what does this line actually do?
> Mainly, what's throwing me off is the "one, two" assignment (or
> whatever it is).

Try:

irb(main):001:0> one, two = 3, 4
=> [3, 4]
irb(main):002:0> one
=> 3
irb(main):003:0> two
=> 4

It's a multiple assignment.  It takes multiple values (or an array) and
spits
them into what's on the left.

Map simply iterates through an array and runs the block (the thing in
braces)
each item, storing the result.

Thus, we're converting everything in the ARGV array to an integer and
stuffing
it into two variables.  The reason everyone else was saying it would be
a
good idea to check the length is the following:

irb(main):004:0> one, two = 3, 4, 5
=> [3, 4, 5]
irb(main):005:0> one
=> 3
irb(main):006:0> two
=> 4

Kinda bad to have mysteriously disappearing command line arguments. :-)
Play
around with it and I'm sure you'll get the hang of it.  Oh, and welcome
to
Ruby! :-D
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2005-12-22 13:35
(Received via mailing list)
On Thu, 22 Dec 2005 04:20:04 -0000, James Edward Gray II
<james@grayproductions.net> wrote:

>>> else
>> end
>
> Yeah, that's better.  Neither of our versions checks the number of
> arguments though and we probably should...
>

I'm just wondering, in Java it's a bit of a no-no using exceptions like
this (since they're pretty heavy to put together). Is it the case in
Ruby?
And does that regexp match balance it out anyway?
E997cf907c21c66a6ca2e1e78cd8ebea?d=identicon&s=25 Dan Hinz (Guest)
on 2005-12-22 14:56
(Received via mailing list)
I see really two things happening here, string->int conversions and
command line parsing. Once you have the conversions understood (a good
thing to know) consider exploring more stuff in the packages.

Let me point you to OptionParser and GetOptLong. They both provide some
very useful command line parsing capabilities. It takes a little
experimentation to really understand what's happening but well worth it
in my opinion.

-dwh-
929f667706d5d2d3513b2c50676ad08c?d=identicon&s=25 jwesley (Guest)
on 2005-12-22 15:08
(Received via mailing list)
I disagree that this particular use of an exception would be a no-no in
Java.  Inability to parse input is justifiably an "exceptional" case.
And the handling of that exceptional case is also appropriate.

The big "no-no" about exception usage is true for any language: "Don't
use exceptions for flow control".

The following code is "wrong" for various reasons as well as violating
the "axiom" above:

begin
  # display 1 through 10
  i = 0
  while true
    unless i > 10
      puts i
    else
      raise "End o' the line"
    end
    i += 1
  end
rescue
end

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

BTW "continuations" (related to exceptions) are a fairly powerful tool
to handle the times when strange flow control might be needed.
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2005-12-22 15:36
(Received via mailing list)
On Thu, 22 Dec 2005 14:07:03 -0000, jwesley <justin.w.smith@gmail.com>
wrote:

> I disagree that this particular use of an exception would be a no-no in
> Java.  Inability to parse input is justifiably an "exceptional" case.
> And the handling of that exceptional case is also appropriate.
>

Agreed, I was referring more to the idea of swapping out flow control
for
exceptions in general. Obviously if the input is an exceptional case,
throw an exception. I have just been wondering about a few examples of
this I've seen in Ruby code, and just picked this as an 'in' to ask
about
it ;)

>     unless i > 10
> exceptions for "normal" conditions is definitely poor style, if not
> worse.
>

Okay, good. That was my feeling too.

> BTW "continuations" (related to exceptions) are a fairly powerful tool
> to handle the times when strange flow control might be needed.
>

I can't wait to find something I can try continuations out on, though I
remember reading somewhere that they too are slow, so one to keep for
those strange cases as you say?

Cheers,
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2005-12-22 15:54
(Received via mailing list)
Hi --

On Thu, 22 Dec 2005, Ross Bamford wrote:

> seen in Ruby code, and just picked this as an 'in' to ask about it ;)
>>  while true
>> Ruby provides enough mechanisms for "controlling the flow" that using
>> exceptions for "normal" conditions is definitely poor style, if not
>> worse.
>>
>
> Okay, good. That was my feeling too.

I agree in general, although... there's one case where I can't resist,
at least sometimes, and that's this:

   if obj.respond_to("meth")
     obj.meth
   else
     <something else>
   end

I really dislike the repetition there, and it also technically isn't
thread-safe:

   a = Object.new
   def a.x; end

   Thread.new do
     sleep 1
     class << a; undef_method("x"); end
   end

   if a.respond_to?("x")
     sleep 2
     a.x
   end

   => undefined method `x' for #<Object:0x1cd508> (NoMethodError)

I don't know any way around it, though, except:

   begin
    obj.meth
   rescue NoMethodError
    <something else>
   end

or some variant thereof.  (Obviously in true duck-typing cases you
just send the message without this kind of check, but there are cases
where the check makes sense.)

I've toyed with the idea of some kind of special "nack" object that
would be returned on these kinds of method calls, but I don't think it
plays well with method_missing.


David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2005-12-22 16:27
(Received via mailing list)
dblack@wobblini.net wrote:
>>>
>>> The following code is "wrong" for various reasons as well as violating
>>>    end
>> Okay, good. That was my feeling too.
>
>
>    obj.meth
>   rescue NoMethodError
>    <something else>
>   end

This has the unfortunate side effect of conflating NoMethodErrors that
are reported for other method calls besides the original obj.meth but
which occur during that method. What's the best way of handling that?
Compare exception.backtrace depth with the current backtrace depth?

It's not really threadsafe either. By the time <something else> is
executed, #meth could have been defined (though you do know it was
undefined at the time of the method call, which is an improvement over
the #respond_to version).
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2005-12-22 17:55
(Received via mailing list)
On Thu, 22 Dec 2005 14:53:54 -0000, <dblack@wobblini.net> wrote:

>>>
>    end
>    end
>    begin
>     obj.meth
>    rescue NoMethodError
>     <something else>
>    end
>
> or some variant thereof.  (Obviously in true duck-typing cases you
> just send the message without this kind of check, but there are cases
> where the check makes sense.)
>

Good point. Now you mention that, I think I'd probably end up going for
the latter style in that case anyway, despite my comments earlier about
exceptions. I guess it's about a balance between being prepared for
exceptions and pre-empting them. Mostly in Java (the only language I've
really used exceptions with) the choice is made, since you have to deal
with (so-called 'checked') exceptions whenever they might be thrown, so
I'm still finding my balance there.

I expect that version also makes refactoring easier later on if you
decide
to move the <something else> further up the chain.

> I've toyed with the idea of some kind of special "nack" object that
> would be returned on these kinds of method calls, but I don't think it
> plays well with method_missing.
>

As a general way for objects to nack method calls? If so, maybe the
default method_missing (or equivalent?) could do that, or you can
provide
your own method_missing to do whatever...?

The implications of the metaprogramming stuff on thread safety is a
subject that, frankly, worries me. When I understand a bit more I'm
looking forward to investigating that side of things.

Cheers,
3b3639fb6a0c490f6292741751000c37?d=identicon&s=25 Rich (Guest)
on 2005-12-22 18:35
(Received via mailing list)
What about something like

{|x| x == x.to_i.to_s}

If the string the above block is applied to is not a number, this
should fail, right?

-Rich
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2005-12-22 18:41
(Received via mailing list)
Hi --

On Fri, 23 Dec 2005, Joel VanderWerf wrote:

> dblack@wobblini.net wrote:
>
>>   begin
>>    obj.meth
>>   rescue NoMethodError
>>    <something else>
>>   end

[Did I really indent by only 1?  It must have been early in the
morning... :-]

> This has the unfortunate side effect of conflating NoMethodErrors that
> are reported for other method calls besides the original obj.meth but
> which occur during that method. What's the best way of handling that?
> Compare exception.backtrace depth with the current backtrace depth?

I guess, but it gets awfully cluttered.  I don't know what the best
way is.  Too bad exceptions don't have a depth property or
something....

> It's not really threadsafe either. By the time <something else> is
> executed, #meth could have been defined (though you do know it was
> undefined at the time of the method call, which is an improvement over
> the #respond_to version).

I guess in a sense anything non-atomic is non-threadsafe, but here at
least you know there won't be a fault-line between knowing whether the
object responds to the message, and asking it to do so.  The method
call happens all at once, and then everything else sort of falls away
from that.


David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
37a3c73ffbf864e4b28f7f2384ee12ce?d=identicon&s=25 Timothy Hunter (tim-hunter)
on 2005-12-22 18:50
(Received via mailing list)
Rich wrote:
> What about something like
>
> {|x| x == x.to_i.to_s}
>
> If the string the above block is applied to is not a number, this
> should fail, right?

It will fail for "012" as well.
Cff9eed5d8099e4c2d34eae663aae87e?d=identicon&s=25 Jacob Fugal (Guest)
on 2005-12-22 19:41
(Received via mailing list)
On 12/22/05, dblack@wobblini.net <dblack@wobblini.net> wrote:
> On Fri, 23 Dec 2005, Joel VanderWerf wrote:
> > This has the unfortunate side effect of conflating NoMethodErrors that
> > are reported for other method calls besides the original obj.meth but
> > which occur during that method. What's the best way of handling that?
> > Compare exception.backtrace depth with the current backtrace depth?
>
> I guess, but it gets awfully cluttered.  I don't know what the best
> way is.  Too bad exceptions don't have a depth property or
> something....

How about something like this:

  class Exception
    def self.local
      primary = self
      localized = Class.new
      klass = (class << localized; self; end)
      klass.send(:define_method, :===) do |other|
        primary === other and other.depth == 1
      end
      localized
    end

    def depth
      self.backtrace.length
    end
  end

Usage:

  begin
    bar()
  rescue NoMethodError.local => e
  end

  def bar
    foo()
  end

  begin
    bar()
  rescue NoMethodError.local => e
  end

First rescue catches the undefined bar since it's local, second rescue
doesn't catch the undefined foo since it's not local.

Jacob Fugal
4a7e2176f1474dbecd9567cda3ffa3a7?d=identicon&s=25 Matthew Feadler (mfeadler)
on 2005-12-22 19:46
First, thanks all very much for the lively discussion thus far.  It's
proven very useful.

Timothy Hunter wrote:
> The Integer() method raises ArgumentError if given an empty,
> non-numeric, or otherwise non-well-formed string.

Hmm...apparently not--at least not w/ 1.8.2 on mswin32.

This:

  begin
    one, two = ARGV.map{ |n| Integer(n) }
  rescue ArgumentError
    puts "Usage..."
    exit
  end

  puts one
  puts two

Outputs:

  nil
  nil

When fed no command-line arguments.  It does work as intended if any of
the args are non-empty strings, however.

Also:

  raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)

I'm a regexp neophyte, without skill or clue.  Any suggestions on
tutorials?

Thanks,

-Matthew
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2005-12-22 20:08
(Received via mailing list)
On Thu, 22 Dec 2005 18:47:04 -0000, Matthew Feadler
<matthew@feadler.com>
wrote:

> I'm a regexp neophyte, without skill or clue.  Any suggestions on
> tutorials?
>

One I've used:

	http://www.regular-expressions.info/tutorial.html

It's not specific to any language.
37a3c73ffbf864e4b28f7f2384ee12ce?d=identicon&s=25 Timothy Hunter (tim-hunter)
on 2005-12-22 22:33
(Received via mailing list)
Matthew Feadler wrote:
>
>   puts two
>
> Outputs:
>
>   nil
>   nil
>
> When fed no command-line arguments.  It does work as intended if any of
> the args are non-empty strings, however.

That would be because Integer is never called. If there are no
command-line arguments, ARGV is empty, there's nothing to map.
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2005-12-22 23:27
(Received via mailing list)
On 12/22/05, Matthew Feadler <matthew@feadler.com> wrote:
>
> Outputs:
>
> I'm a regexp neophyte, without skill or clue.  Any suggestions on
> tutorials?

Dunno about tutorials, but:

the / characters indidicate that whatever is between them is a regular
expression.
^ is the beginning of a line (or string)
\d is a digit (i.e. 0 1 2 3 4 5 6 7 8 or 9)
* means to match 0 or more of the previous thing.
$ is the end of the line.

So, /^\d*$/ means that the entire string from beginning to end is
comprised of zero or more digits.  So, a minus sign ('-') or any
non-digit somewhere in the string would fail the check.
4a7e2176f1474dbecd9567cda3ffa3a7?d=identicon&s=25 Matthew Feadler (mfeadler)
on 2005-12-22 23:35
Timothy Hunter wrote:
> That would be because Integer is never called. If there are no
> command-line arguments, ARGV is empty, there's nothing to map.

That makes perfect sense.  Thanks.

So, after some experimentation I've got the code listed below.  It
successfully checks for:

1.) an empty ARGV (i.e., no command-line args)
2.) more than 2 arguments
3.) non-numeric arguments
4.) negative arguments
5.) first arg greater than second arg

Which is to say, it does everything I want it to.  However, I wonder if
it can be optimized, condensed?

Here be code:

$usage = "Usage"

def print_usage val
  if val=="exit"
    print $usage
    exit
  else
    print $usage
  end
end

if ARGV!=[] and !(ARGV.length > 2)
  begin
    arg0, arg1 = ARGV.map{ |n| Integer(n) }
    if (arg0 < 0) or (arg1 < 0)
      print_usage("exit")
    elsif arg0>arg1
      print_usage("exit")
    end
  rescue ArgumentError
    print_usage("exit")
  end
else
  print_usage("exit")
end
4a7e2176f1474dbecd9567cda3ffa3a7?d=identicon&s=25 Matthew Feadler (mfeadler)
on 2005-12-22 23:46
Matthew Feadler wrote:
> Which is to say, it does everything I want it to.  However, I wonder if
> it can be optimized, condensed?
>

How 'bout corrected first?  Guess my last post is a perfect argument in
favor of my learning how to use test units.

Corrected code be here:

$usage = "Usage:"

def print_usage(val)
  if val=="exit"
    print $usage
    exit
  else
    print $usage
  end
end

if ARGV!=[] and !(ARGV.length > 2)
  begin
    arg0, arg1 = ARGV.map{ |n| Integer(n) }
    if (arg0 < 0) or (!arg1.nil? and (arg1 < 0))
      print_usage("exit")
    elsif !arg1.nil? and (arg0 > arg1)
      print_usage("exit")
    end
  rescue ArgumentError
    print_usage("exit")
  end
else
  print_usage("exit")
end
Cff9eed5d8099e4c2d34eae663aae87e?d=identicon&s=25 Jacob Fugal (Guest)
on 2005-12-22 23:54
(Received via mailing list)
def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if arg0.nil? or arg0 < 0
  raise ArgumentError if arg1.nil? or arg1 < 0
  raise ArgumentError if arg0 > arg1
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments

# Jacob Fugal
4a7e2176f1474dbecd9567cda3ffa3a7?d=identicon&s=25 Matthew Feadler (mfeadler)
on 2005-12-23 00:26
Jacob Fugal wrote:
> def read_arguments
>   arg0, arg1 = ARGV.map{ |n| Integer(n) }
>   raise ArgumentError if arg0.nil? or arg0 < 0
>   raise ArgumentError if arg1.nil? or arg1 < 0
>   raise ArgumentError if arg0 > arg1
>   return arg0, arg1
> rescue ArgumentError
>   print <<-USAGE
> Usage
> USAGE
>   exit
> end
>
> a, b = read_arguments

Very nice.  I like this construction.  However, I believe the above will
throw the exception when I have only one valid arg, which is not what I
want (1 or 2 args is  correct; no more, no less).

So, it should look like this, yes?

def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if (ARGV.length == 0) or (ARGV.length > 2)
  raise ArgumentError if (arg0 < 0) or (!arg1.nil? and (arg1 < 0))
  raise ArgumentError if !arg1.nil? and (arg0 > arg1)
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2005-12-23 01:58
(Received via mailing list)
On 12/22/05, Matthew Feadler <matthew@feadler.com> wrote:
> > USAGE
>
>   exit
> end
>
> a, b = read_arguments

Write the damn tests, man!  :-)

If it passes the tests, it should work, unless you have faulty tests,
in which case you need more/better tests.
This topic is locked and can not be replied to.