Newbie Problem with Shell#transact

Back from the conference and eager to learn Ruby, I’m trying to write a
tool for grepping the table of contents of jar files. (I have a similar
Bourne shell script, but I want to add some features and start small
learning Ruby). I have something working, but in trying to restructure
it, I’ve encountered a problem with Shell#transact when using it inside
an instance method of a class. In both cases, I’ve used
Shell#def_system_command to define jar and grepcmd like this:

Shell.def_system_command "jar"
Shell.def_system_command "grepcmd", "grep"

If I have a “plain” script (i.e. no class definition or methods), I have
no problem with the following:

sh = Shell.new
ARGV.each { |jarfile|
  sh.transact do
    results = jar("tf", jarfile) | grepcmd(pattern)
    puts results
  end
}

However, if I try to put this in an instance method (see next code
snippet), it never returns and starts taking 100% of my CPU until I kill
it.

class JarGrepper
  attr_writer :pattern
  def jartoc(jarfile)
    sh = Shell.new
    sh.transact do
      results = jar("tf", jarfile) | grepcmd(@pattern)
      puts results
    end
  end
end

If I take out the transact (see next code snippet), it works, but I get
warnings:

class JarGrepper
  attr_writer :pattern
  def jartoc(jarfile)
    sh = Shell.new
    results = sh.jar("tf", jarfile) | sh.grepcmd(@pattern)
    puts results
  end
end

Here are the warnings:

shell: notice: Process finishing...
       wait for Job[grep:#6293] to finish.
       You can use Shell#transact or Shell#check_point for more safe
       execution.
shell: notice: Process finishing...
       wait for Job[jar:#6292] to finish.
       You can use Shell#transact or Shell#check_point for more safe
       execution.

What I’d like to be able to do is to get the results of ‘jar(“tf”,
jarfile) | grepcmd(@pattern)’ from within an instance method and without
warnings.

In case it’s relevant, I’m running Ruby 1.6.7 on Red Hat Linux 7.2.

Thanks in advance for any help or explanations,
Xandy

Write it like this

    class JarGrepper
      attr_writer :pattern
      def jartoc(jarfile)
        sh = Shell.new

           pattern = @pattern

        sh.transact do
          results = jar("tf", jarfile) | grepcmd(@pattern)

             results = jar("tf", jarfile) | grepcmd(pattern)

          puts results
        end
      end
    end

Guy Decoux

OK. That works, but the more important question is, “Why?” Is there a
general principle I can apply here? Should it be considered a bug? At
least for me, it violates the Principle Of Least Surprise, but my Ruby
intuition is not yet well trained.

Thanks,
Xandy

···

On Tue, 2002-11-05 at 04:54, ts wrote:

Write it like this

class JarGrepper
  attr_writer :pattern
  def jartoc(jarfile)
    sh = Shell.new
       pattern = @pattern
    sh.transact do
      results = jar("tf", jarfile) | grepcmd(@pattern)
         results = jar("tf", jarfile) | grepcmd(pattern)
      puts results
    end
  end
end

Guy Decoux

"Why?"

#transact use #instance_eval

With

    sh.transact do
         results = jar("tf", jarfile) | grepcmd(@pattern)

@pattern is interpreted as an instance variable of `sh' and not an
instance variable of JarGrepper object, i.e.

pigeon% ruby
class A; attr_accessor :a; end
a = A.new
a.a = 12
@a = 24
a.instance_eval do
   p @a
end
^D
12
pigeon%

Guy Decoux