lib/bio/command.rb in bio-1.4.2 vs lib/bio/command.rb in bio-1.4.3

- old
+ new

@@ -230,23 +230,41 @@ # --- # *Arguments*: # * (required) _cmd_: Array containing String objects # * (optional) _options_: Hash # *Returns*:: (undefined) - def call_command_popen(cmd, options = {}) + def call_command_popen(cmd, options = {}, &block) if RUBY_VERSION >= "1.9.0" then - # For Ruby 1.9 or later, using command line array with options. - dir = options[:chdir] - cmd = safe_command_line_array(cmd) - if dir then - cmd = cmd + [ { :chdir => dir } ] + if RUBY_ENGINE == 'jruby' then + _call_command_popen_jruby19(cmd, options, &block) + else + _call_command_popen_ruby19(cmd, options, &block) end - r = IO.popen(cmd, "r+") do |io| - yield io - end - return r + else + _call_command_popen_ruby18(cmd, options, &block) end + end + + # This method is internally called from the call_command method. + # In normal case, use call_command, and do not call this method directly. + # + # Executes the program via IO.popen. + # A block must be given. An IO object is passed to the block. + # + # See the document of call_command for available options. + # + # The method is written for Ruby 1.8. + # + # In Ruby 1.8, although shell unsafe characters are escaped, + # if inescapable characters exists, it raises RuntimeError. + # + # --- + # *Arguments*: + # * (required) _cmd_: Array containing String objects + # * (optional) _options_: Hash + # *Returns*:: (undefined) + def _call_command_popen_ruby18(cmd, options = {}) # For Ruby 1.8, using command line string. str = make_command_line(cmd) # processing options if dir = options[:chdir] then if windows_platform? @@ -265,14 +283,74 @@ IO.popen(str, "w+") do |io| io.sync = true yield io end end + private :_call_command_popen_ruby18 # This method is internally called from the call_command method. # In normal case, use call_command, and do not call this method directly. # + # Executes the program via IO.popen. + # A block must be given. An IO object is passed to the block. + # + # See the document of call_command for available options. + # + # The method can be run only on Ruby (MRI) 1.9 or later versions. + # + # --- + # *Arguments*: + # * (required) _cmd_: Array containing String objects + # * (optional) _options_: Hash + # *Returns*:: (undefined) + def _call_command_popen_ruby19(cmd, options = {}) + # For Ruby 1.9 or later, using command line array with options. + dir = options[:chdir] + cmd = safe_command_line_array(cmd) + if dir then + cmd = cmd + [ { :chdir => dir } ] + end + r = IO.popen(cmd, "r+") do |io| + yield io + end + return r + end + private :_call_command_popen_ruby19 + + # This method is internally called from the call_command method. + # In normal case, use call_command, and do not call this method directly. + # + # Executes the program via IO.popen. + # A block must be given. An IO object is passed to the block. + # + # See the document of call_command for available options. + # + # The method is written for the workaround of the JRuby bugs: + # * {JRUBY-6195}[http://jira.codehaus.org/browse/JRUBY-6195] Process.spawn + # (and related methods) ignore option hash + # * {JRUBY-6818}[http://jira.codehaus.org/browse/JRUBY-6818] Kernel.exec, + # Process.spawn (and IO.popen etc.) raise error when program is an array + # containing two strings + # This method may be removed after the bugs are resolved. + # + # --- + # *Arguments*: + # * (required) _cmd_: Array containing String objects + # * (optional) _options_: Hash + # *Returns*:: (undefined) + def _call_command_popen_jruby19(cmd, options = {}, &block) + if !options.empty? or cmd.size == 1 then + _call_command_popen_ruby18(cmd, options, &block) + else + _call_command_popen_ruby19(cmd, options, &block) + end + end + private :_call_command_popen_jruby19 + + # This method is internally called from the call_command method. + # In normal case, use call_command, and do not call this method directly. + # # Executes the program via fork (by using IO.popen("-")) and exec. # A block must be given. An IO object is passed to the block. # # See the document of call_command for available options. # @@ -545,37 +623,41 @@ # is destroyed by GC. # # BioRuby library internal use only. class Tmpdir - # Returns finalizer object for Tmpdir class. - # Internal use only. Users should not call this method directly. - # - # Acknowledgement: The essense of the code is taken from tempfile.rb - # in Ruby 1.8.7. + # Internal use only. Users should not use this class directly. # - # --- - # *Arguments*: - # * (required) _data_: Array containing internal data - # *Returns*:: Proc object - def self.callback(data) - pid = $$ - lambda { - path, = *data - if pid == $$ - $stderr.print "removing ", path, " ..." if $DEBUG - if path and !path.empty? and - File.directory?(path) and - !File.symlink?(path) then - Bio::Command.remove_entry_secure(path) - $stderr.print "done\n" if $DEBUG - else - $stderr.print "skipped\n" if $DEBUG - end + # Bio::Command::Tmpdir::Remover is a class to remove temporary + # directory. + # + # Acknowledgement: The essense of the code is taken from tempfile.rb + # in Ruby trunk (svn 34413) and in Ruby 1.8.7. + class Remover + # Internal use only. Users should not call this method. + def initialize(data) + @pid = $$ + @data = data + end + + # Internal use only. Users should not call this method. + def call(*args) + return if @pid != $$ + + path, = *@data + + STDERR.print "removing ", path, "..." if $DEBUG + if path and !path.empty? and + File.directory?(path) and + !File.symlink?(path) then + Bio::Command.remove_entry_secure(path) + $stderr.print "done\n" if $DEBUG + else + $stderr.print "skipped\n" if $DEBUG end - } - end + end + end #class Remover # Creates a new Tmpdir object. # The arguments are the same as Bio::Command.mktmpdir. # # --- @@ -583,10 +665,10 @@ # * (optional) <em>prefix_suffix</em>: String (or Array) # * (optional) <em>tmpdir</em>: String: temporary directory's path # *Returns*:: Tmpdir object def initialize(prefix_suffix = nil, tmpdir = nil) @data = [] - @clean_proc = self.class.callback(@data) + @clean_proc = Remover.new(@data) ObjectSpace.define_finalizer(self, @clean_proc) @data.push(@path = Bio::Command.mktmpdir(prefix_suffix, tmpdir).freeze) end # Path to the temporay directory