Forum: Ruby Chomping and stomping

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.
John M. (Guest)
on 2006-02-02 17:12
(Received via mailing list)
Chaps,

Here's a short script to keep requesting for input...

#!/usr/bin/ruby -w
def chomper
  xx = gets.chomp!
  until $_ == "qq"
    puts "hit me with a squirell!"
    xx = gets.chomp!
    xx
  end
end

chomper

# this works but surely there must be a way to incoporate a variable
in there?

#!/usr/bin/ruby -w
def chomper
  xx = gets.chomp!
  until xx == "qq"
    puts "hit me with a squirell!"
    xx
  end
end

#this don't work.
Jacob F. (Guest)
on 2006-02-02 19:16
(Received via mailing list)
On 2/2/06, John M. <removed_email_address@domain.invalid> wrote:
> chomper
>   end
> end
>
> #this don't work.

String#chomp! is a "destructive" operation. This means that it acts in
place on its receiver and, in this case, returns nil. So what's
happening here is that Kernel#gets creates a String object, chomp! is
sent to that object, the object is modified in place and nil returned.
That's why xx is nil. As you discovered in your first example, the
String object returned by Kernel#gets is stored in $_. Accessing it
this way isn't a bset practice however.

What you probably want instead is to use the non-destructive twin (the
Good Twin) of String#chomp!, namely String#chomp. Notice the lack of
the bang (!). The bang is generally (but not always) an indicator that
the method is destructive. String#chomp creates a chomped copy of it's
receiver and returns it. Replacing chomp! with chomp it should work:

  #!/usr/bin/ruby -w
  def chomper
    xx = gets.chomp
    until xx == "qq"
      puts "hit me with a squirell!"
      xx
    end
  end

  puts chomper

Jacob F.
William J. (Guest)
on 2006-02-02 19:28
(Received via mailing list)
John M. wrote:
>     xx
>   xx = gets.chomp!
>   until xx == "qq"
>     puts "hit me with a squirell!"
>     xx
>   end
> end
>
> #this don't work.


def chomper
  until (xx = gets.chomp) == 'qq'
    puts "hit me with a squirell!"
  end
  xx
end

puts chomper
unknown (Guest)
on 2006-02-02 19:40
(Received via mailing list)
On Fri, 3 Feb 2006, William J. wrote:

>>     puts "hit me with a squirell!"
>> #!/usr/bin/ruby -w
>
> def chomper
>  until (xx = gets.chomp) == 'qq'
>    puts "hit me with a squirell!"
>  end
>  xx
> end
>
> puts chomper


   harp:~ > cat a.rb
   def chomper
     until (xx = gets.chomp) == 'qq'
       puts "hit me with a squirell!"
     end
     xx
   end

   puts chomper


   harp:~ > ruby a.rb < /dev/null
   a.rb:3:in `chomper': private method `chomp' called for nil:NilClass
(NoMethodError)
           from a.rb:9


nil doesn't like that!  ;-)

-a
Jacob F. (Guest)
on 2006-02-02 20:01
(Received via mailing list)
On 2/2/06, removed_email_address@domain.invalid 
<removed_email_address@domain.invalid> wrote:
>    harp:~ > ruby a.rb < /dev/null
>    a.rb:3:in `chomper': private method `chomp' called for nil:NilClass (NoMethodError)
>            from a.rb:9
>
> nil doesn't like that!  ;-)

Heh, yeah, I glossed over that too. You really need to check the
result of gets before you chomp it. This is the way I'd write John's
original loop (same semantics):

  def chomper
    while xx = gets
      xx.chomp!
      break if xx == 'qq'
      puts "hit me with a squirell!"
    end
    xx
  end

and the way I'd write it for myself (different semantics, mostly same
intent):

  def chomped_gets
    (s = gets) and s.chomp
  end

  def chomper
    loop do
      puts "hit me with a squirell!"
      break unless xx = chomped_gets
      return xx if xx == 'qq'
    end
  end

Jacob F.
John M. (Guest)
on 2006-02-02 20:32
(Received via mailing list)
Chaps,

Thanks for those speedy replies
Following on from

#thanks to you guyson the list for clearing this up
jayeola@tp20$ cat bin/acid/classes/testing/testchomp.rb
#!/usr/bin/ruby -w
def chomper
  xx = gets.chomp
  until (xx= gets.chomp) == "qq"
    puts "hit me with a squirell!"
  end
  xx
end


chomper
# ^^ the above works. :)

# This is supposed to do the same as the above but write to a file...

here's version 1
#!/usr/bin/ruby -w

def  testwrite
  puts "hit me with a squirell!"
  until $_ =="qq"
    gets.chomp!
      if $_ != "qq"
        File.open("testfile", "a") { |file| file.write($_) }
end
end
end
 testwrite

here's version 1

jayeola@tp20$ cat bin/acid/classes/testing/write_file2.rb
#!/usr/bin/ruby -w

def testwrite
  xx = gets.chomp
  until (xx.gets.chomp) == "qq"
    puts "hit me with a squirell!"
    File.open("testfile", "a") { |file| file.write(xx) }
  end
end

testwrite





On Fri, 3 Feb 2006 02:16:11 +0900
James G. (Guest)
on 2006-02-02 20:38
(Received via mailing list)
On Feb 2, 2006, at 11:59 AM, Jacob F. wrote:

> On 2/2/06, removed_email_address@domain.invalid <removed_email_address@domain.invalid> 
wrote:
>>    harp:~ > ruby a.rb < /dev/null
>>    a.rb:3:in `chomper': private method `chomp' called for
>> nil:NilClass (NoMethodError)
>>            from a.rb:9
>>
>> nil doesn't like that!  ;-)
>
> Heh, yeah, I glossed over that too. You really need to check the
> result of gets before you chomp it.

Isn't this why we have iterators in Ruby?  We get to avoid all these
messy loop ending tests...

> This is the way I'd write John's original loop (same semantics):
>
>   def chomper
>     while xx = gets
>       xx.chomp!
>       break if xx == 'qq'
>       puts "hit me with a squirell!"
>     end
>     xx
>   end

def chomper
   $stdin.each do |line|
     line.chomp!

     return line if line == "qq"

     puts "Hit me with a squirrel!"
   end
end

James Edward G. II
William J. (Guest)
on 2006-02-02 21:14
(Received via mailing list)
William J. wrote:
> >     xx = gets.chomp!
> > def chomper
> def chomper
>   until (xx = gets.chomp) == 'qq'
>     puts "hit me with a squirell!"
>   end
>   xx
> end
>
> puts chomper

def chomper
  puts "Hit me!"  while gets  and  $_.chomp! != "qq"
  $_  if $_
end
unknown (Guest)
on 2006-02-02 21:41
(Received via mailing list)
On Fri, 3 Feb 2006, James Edward G. II wrote:

>> Heh, yeah, I glossed over that too. You really need to check the
>>       break if xx == 'qq'
>
>    puts "Hit me with a squirrel!"
>  end
> end

golfing

   def chomper() STDIN.detect{|x| x =~ /^qq/ or puts "hit me"} end

-a
Jacob F. (Guest)
on 2006-02-02 21:44
(Received via mailing list)
On 2/2/06, William J. <removed_email_address@domain.invalid> wrote:
> def chomper
>   puts "Hit me!"  while gets  and  $_.chomp! != "qq"
>   $_  if $_
> end

This will always loop until EOF and then return nil. $_.chomp! (as
opposed to $_.chomp) returns nil, and nil != "qq".

Jacob F.

PS. And let's not golf with this please...
William J. (Guest)
on 2006-02-02 21:44
(Received via mailing list)
removed_email_address@domain.invalid wrote:
> >>   xx = gets.chomp!
> >> in there?
> >> #this don't work.
>
>
>
>    harp:~ > ruby a.rb < /dev/null
>    a.rb:3:in `chomper': private method `chomp' called for nil:NilClass (NoMethodError)
>            from a.rb:9

The error I get in a dos-box is
The system cannot find the path specified.

To produce the error you gave, I must do it this way:
ruby a.rb < nul:

When you post something that depends upon a particular
operating system, you need to make that dependency clear.

It is reasonable to write a program that requires input.
It is not reasonable to expect a program that requires input to
function properly when you deliberately deprive it of input.
William J. (Guest)
on 2006-02-02 21:50
(Received via mailing list)
William J. wrote:
> > >     puts "hit me with a squirell!"
> > > #!/usr/bin/ruby -w
> >
>   puts "Hit me!"  while gets  and  $_.chomp! != "qq"
>   $_  if $_
> end

def chomper
  puts "Hit me!"  while gets  and  $_.chomp! != "qq"
  $_
end
Jacob F. (Guest)
on 2006-02-02 21:53
(Received via mailing list)
On 2/2/06, William J. <removed_email_address@domain.invalid> wrote:
>
> When you post something that depends upon a particular
> operating system, you need to make that dependency clear.

Well, in Ara's defense I would claim that prefixing the command with
"harp:~ >" and using "/dev/null" both should be clear indicators that
he's talking about a *nix system.

> It is reasonable to write a program that requires input.
> It is not reasonable to expect a program that requires input to
> function properly when you deliberately deprive it of input.

This problem is not only due to no input. The same error will arise if
you reach EOF before matching the expected line. Try this:

> echo "Hello" | ruby a.rb

It *is* reasonable to expect a program that requires input to function
properly when invalid input is provided. Maybe the proper action is to
raise an error, but it should be a contextually appropriate error.

Jacob F.
unknown (Guest)
on 2006-02-02 21:59
(Received via mailing list)
On Fri, 3 Feb 2006, William J. wrote:

> The error I get in a dos-box is The system cannot find the path specified.
>
> To produce the error you gave, I must do it this way: ruby a.rb < nul:
>
> When you post something that depends upon a particular operating system, you
> need to make that dependency clear.

indeed.  that's what specifying cat and /dev/null does in and least four
ways:

   cat, the most ubiquitous of unix programs => *nix
   / as file separator                       => *nix
   /dev file system                          => *nix
   /dev/null device                          => *nix

;-)

> It is reasonable to write a program that requires input.  It is not
> reasonable to expect a program that requires input to function properly when
> you deliberately deprive it of input.

that's not what is happening.  reading from /dev/null or nul is the same
as
reading from an empty file.  the key point i was illustrating, and the
bug in
the program, is that is fails at eof regardless if input is given.

for example, if i run this from the shell and type 'ctrl-d' to signal
end of
input (on unix)

   harp:~ > cat a.rb
   def chomper
     until (xx = gets.chomp) == 'qq'
       puts "hit me with a squirell!"
     end
     xx
   end

   puts chomper


   harp:~ > ruby a.rb
   a.rb:2:in `chomper': private method `chomp' called for nil:NilClass
(NoMethodError)
           from a.rb:8


running on an empty file does the same

   harp:~ > touch empty
   harp:~ > ruby a.rb < empty
   a.rb:2:in `chomper': private method `chomp' called for nil:NilClass
(NoMethodError)
           from a.rb:8


as does running with some input

   harp:~ > echo 42 > input

   harp:~ > ruby a.rb < input
   hit me with a squirell!
   a.rb:2:in `chomper': private method `chomp' called for nil:NilClass
(NoMethodError)
           from a.rb:8

in fact, it cannot be made to work with any input

it's important, imho only perhaps, to show working code (best done by
actually
showing a run) unless that code is noted to be un-tested.  i make
efforts to do
this for all examples i post:

   http://groups.google.com/group/comp.lang.ruby/sear...

some probably find it anoying but i make too many mistakes otherwise.

kind regards.

-a
William J. (Guest)
on 2006-02-02 22:09
(Received via mailing list)
Jacob F. wrote:
> On 2/2/06, William J. <removed_email_address@domain.invalid> wrote:
> > def chomper
> >   puts "Hit me!"  while gets  and  $_.chomp! != "qq"
> >   $_  if $_
> > end
>
> This will always loop until EOF and then return nil. $_.chomp! (as
> opposed to $_.chomp) returns nil, and nil != "qq".
>

It works under ruby 1.8.2 (2004-05-19) [i386-mswin32].
Did you test it?   The code you posted earlier doesn't work:

  #!/usr/bin/ruby -w
  def chomper
    xx = gets.chomp
    until xx == "qq"
      puts "hit me with a squirell!"
      xx
    end
  end

  puts chomper

Always test the code that you post, please.

> Jacob F.
>
> PS. And let's not golf with this please...

If you don't like golf, why watch it?

def chomper
  puts "Hit me!"  while gets.chomp! != "qq"
  $_
end
Jacob F. (Guest)
on 2006-02-02 22:36
(Received via mailing list)
On 2/2/06, William J. <removed_email_address@domain.invalid> wrote:
> Jacob F. wrote:
> > PS. And let's not golf with this please...
>
> If you don't like golf, why watch it?

Because the original poster was asking for advice on why it wasn't
working, not for a golfing contest.

Jacob F.
William J. (Guest)
on 2006-02-02 23:09
(Received via mailing list)
Jacob F. wrote:
> On 2/2/06, William J. <removed_email_address@domain.invalid> wrote:
> > Jacob F. wrote:
> > > PS. And let's not golf with this please...
> >
> > If you don't like golf, why watch it?
>
> Because the original poster was asking for advice on why it wasn't
> working, not for a golfing contest.

The fact that his expectations were modest doesn't mean that
I shouldn't give him a bonus.  One never has to ask for a golfing
contest, since those who enjoy programming and who test their
code before they post are always willing to indulge in that pastime.
This topic is locked and can not be replied to.