systemu-2.6.5/0000755000175000017500000000000012524363464012246 5ustar lucaslucassystemu-2.6.5/README0000644000175000017500000000735312524363464013136 0ustar lucaslucasNAME systemu SYNOPSIS universal capture of stdout and stderr and handling of child process pid for windows, *nix, etc. URIS http://github.com/ahoward/systemu http://rubyforge.org/projects/codeforpeople/ INSTALL gem install systemu HISTORY 2.0.0 - versioning issue. new gem release. 1.3.1 - updates for ruby 1.9.1 1.3.0 - move to github 1.2.0 - fixed handling of background thread management - needed Thread.current.abort_on_exception = true - fixed reporting of child pid, it was reported as the parent's pid before SAMPLES <========< samples/a.rb >========> ~ > cat samples/a.rb # # systemu can be used on any platform to return status, stdout, and stderr of # any command. unlike other methods like open3/popen4 there is zero danger of # full pipes or threading issues hanging your process or subprocess. # require 'systemu' date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " ) status, stdout, stderr = systemu date p [ status, stdout, stderr ] ~ > ruby samples/a.rb [#, "2011-12-11 22:07:30 -0700\n", "2011-12-11 22:07:30 -0700\n"] <========< samples/b.rb >========> ~ > cat samples/b.rb # # quite a few keys can be passed to the command to alter it's behaviour. if # either stdout or stderr is supplied those objects should respond_to? '<<' # and only status will be returned # require 'systemu' date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " ) stdout, stderr = '', '' status = systemu date, 'stdout' => stdout, 'stderr' => stderr p [ status, stdout, stderr ] ~ > ruby samples/b.rb [#, "2011-12-11 22:07:30 -0700\n", "2011-12-11 22:07:30 -0700\n"] <========< samples/c.rb >========> ~ > cat samples/c.rb # # of course stdin can be supplied too. synonyms for 'stdin' include '0' and # 0. the other stdio streams have similar shortcuts # require 'systemu' cat = %q( ruby -e" ARGF.each{|line| puts line} " ) status = systemu cat, 0=>'the stdin for cat', 1=>stdout='' puts stdout ~ > ruby samples/c.rb the stdin for cat <========< samples/d.rb >========> ~ > cat samples/d.rb # # the cwd can be supplied # require 'systemu' require 'tmpdir' pwd = %q( ruby -e" STDERR.puts Dir.pwd " ) status = systemu pwd, 2=>(stderr=''), :cwd=>Dir.tmpdir puts stderr ~ > ruby samples/d.rb /private/var/folders/sp/nwtflj890qnb6z4b53dqxvlw0000gp/T <========< samples/e.rb >========> ~ > cat samples/e.rb # # any environment vars specified are merged into the child's environment # require 'systemu' env = %q( ruby -r yaml -e" puts ENV[ 'answer' ] " ) status = systemu env, 1=>stdout='', 'env'=>{ 'answer' => 0b101010 } puts stdout ~ > ruby samples/e.rb 42 <========< samples/f.rb >========> ~ > cat samples/f.rb # # if a block is specified then it is passed the child pid and run in a # background thread. note that this thread will __not__ be blocked during the # execution of the command so it may do useful work such as killing the child # if execution time passes a certain threshold # require 'systemu' looper = %q( ruby -e" loop{ STDERR.puts Time.now.to_i; sleep 1 } " ) status, stdout, stderr = systemu looper do |cid| sleep 3 Process.kill 9, cid end p status p stderr ~ > ruby samples/f.rb # "1323666451\n1323666452\n1323666453\n" systemu-2.6.5/samples/0000755000175000017500000000000012524363464013712 5ustar lucaslucassystemu-2.6.5/samples/b.rb0000644000175000017500000000062612524363464014464 0ustar lucaslucas# # quite a few keys can be passed to the command to alter it's behaviour. if # either stdout or stderr is supplied those objects should respond_to? '<<' # and only status will be returned # require 'systemu' date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " ) stdout, stderr = '', '' status = systemu date, 'stdout' => stdout, 'stderr' => stderr p [ status, stdout, stderr ] systemu-2.6.5/samples/f.rb0000644000175000017500000000076212524363464014471 0ustar lucaslucas# # if a block is specified then it is passed the child pid and run in a # background thread. note that this thread will __not__ be blocked during the # execution of the command so it may do useful work such as killing the child # if execution time passes a certain threshold # require 'systemu' looper = %q( ruby -e" loop{ STDERR.puts Time.now.to_i; sleep 1 } " ) status, stdout, stderr = systemu looper do |cid| sleep 3 Process.kill 9, cid end p status p stderr systemu-2.6.5/samples/d.rb0000644000175000017500000000027612524363464014467 0ustar lucaslucas# # the cwd can be supplied # require 'systemu' require 'tmpdir' pwd = %q( ruby -e" STDERR.puts Dir.pwd " ) status = systemu pwd, 2=>(stderr=''), :cwd=>Dir.tmpdir puts stderr systemu-2.6.5/samples/c.rb0000644000175000017500000000043612524363464014464 0ustar lucaslucas# # of course stdin can be supplied too. synonyms for 'stdin' include '0' and # 0. the other stdio streams have similar shortcuts # require 'systemu' cat = %q( ruby -e" ARGF.each{|line| puts line} " ) status = systemu cat, 0=>'the stdin for cat', 1=>stdout='' puts stdout systemu-2.6.5/samples/a.rb0000644000175000017500000000061212524363464014456 0ustar lucaslucas# # systemu can be used on any platform to return status, stdout, and stderr of # any command. unlike other methods like open3/popen4 there is zero danger of # full pipes or threading issues hanging your process or subprocess. # require 'systemu' date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " ) status, stdout, stderr = systemu date p [ status, stdout, stderr ] systemu-2.6.5/samples/e.rb0000644000175000017500000000035612524363464014467 0ustar lucaslucas# # any environment vars specified are merged into the child's environment # require 'systemu' env = %q( ruby -r yaml -e" puts ENV[ 'answer' ] " ) status = systemu env, 1=>stdout='', 'env'=>{ 'answer' => 0b101010 } puts stdout systemu-2.6.5/BSDL0000644000175000017500000000242012524363464012713 0ustar lucaslucasCopyright (c) 2010, Ara T. Howard All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. systemu-2.6.5/lib/0000755000175000017500000000000012524363464013014 5ustar lucaslucassystemu-2.6.5/lib/systemu.rb0000644000175000017500000002074412524363464015061 0ustar lucaslucas# encoding: utf-8 require 'tmpdir' require 'socket' require 'fileutils' require 'rbconfig' require 'thread' class Object def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end end class SystemUniversal # # constants # SystemUniversal::VERSION = '2.6.5' unless SystemUniversal.send(:const_defined?, :VERSION) def SystemUniversal.version() SystemUniversal::VERSION end def version() SystemUniversal::VERSION end def SystemUniversal.description "universal capture of stdout and stderr and handling of child process pid for windows, *nix, etc." end # # class methods # @host = Socket.gethostname @ppid = Process.ppid @pid = Process.pid @turd = ENV['SYSTEMU_TURD'] @ruby = nil def self.ruby return @ruby if @ruby c = begin; ::RbConfig::CONFIG; rescue NameError; ::Config::CONFIG; end ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT'] @ruby = if system('%s -e 42' % ruby) ruby else system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG') end end class << SystemUniversal %w( host ppid pid turd ).each{|a| attr_accessor a} def quote(*words) words.map{|word| word.inspect}.join(' ') end end # # instance methods # def initialize argv, opts = {}, &block getopt = getopts opts @argv = argv @block = block @stdin = getopt[ ['stdin', 'in', '0', 0] ] @stdout = getopt[ ['stdout', 'out', '1', 1] ] @stderr = getopt[ ['stderr', 'err', '2', 2] ] @env = getopt[ 'env' ] @cwd = getopt[ 'cwd' ] @host = getopt[ 'host', self.class.host ] @ppid = getopt[ 'ppid', self.class.ppid ] @pid = getopt[ 'pid', self.class.pid ] @ruby = getopt[ 'ruby', self.class.ruby ] end def systemu tmpdir do |tmp| c = child_setup tmp status = nil begin thread = nil quietly{ IO.popen "#{ quote(@ruby) } #{ quote(c['program']) }", 'rb+' do |pipe| line = pipe.gets case line when %r/^pid: \d+$/ cid = Integer line[%r/\d+/] else begin buf = pipe.read buf = "#{ line }#{ buf }" e = Marshal.load buf raise unless Exception === e raise e rescue raise "systemu: Error - process interrupted!\n#{ buf }\n" end end thread = new_thread cid, @block if @block pipe.read rescue nil end } status = $? ensure if thread begin class << status attr 'thread' end status.instance_eval{ @thread = thread } rescue 42 end end end if @stdout or @stderr open(c['stdout'], 'rb'){|f| relay f => @stdout} if @stdout open(c['stderr'], 'rb'){|f| relay f => @stderr} if @stderr status else [status, open(c['stdout'], 'rb'){|f| f.read}, open(c['stderr'], 'rb'){|f| f.read}] end end end def quote *args, &block SystemUniversal.quote(*args, &block) end def new_thread child_pid, block q = Queue.new Thread.new(child_pid) do |cid| current = Thread.current current.abort_on_exception = true q.push current block.call cid end q.pop end def child_setup tmp stdin = File.expand_path(File.join(tmp, 'stdin')) stdout = File.expand_path(File.join(tmp, 'stdout')) stderr = File.expand_path(File.join(tmp, 'stderr')) program = File.expand_path(File.join(tmp, 'program')) config = File.expand_path(File.join(tmp, 'config')) if @stdin open(stdin, 'wb'){|f| relay @stdin => f} else FileUtils.touch stdin end FileUtils.touch stdout FileUtils.touch stderr c = {} c['argv'] = @argv c['env'] = @env c['cwd'] = @cwd c['stdin'] = stdin c['stdout'] = stdout c['stderr'] = stderr c['program'] = program open(config, 'wb'){|f| Marshal.dump(c, f)} open(program, 'wb'){|f| f.write child_program(config)} c end def quietly v = $VERBOSE $VERBOSE = nil yield ensure $VERBOSE = v end def child_program config <<-program # encoding: utf-8 PIPE = STDOUT.dup begin config = Marshal.load(IO.read('#{ config }',:mode=>"rb")) argv = config['argv'] env = config['env'] cwd = config['cwd'] stdin = config['stdin'] stdout = config['stdout'] stderr = config['stderr'] Dir.chdir cwd if cwd env.each{|k,v| ENV[k.to_s] = v.to_s} if env STDIN.reopen stdin STDOUT.reopen stdout STDERR.reopen stderr PIPE.puts "pid: \#{ Process.pid }" PIPE.flush ### the process is ready yo! PIPE.close exec *argv rescue Exception => e PIPE.write Marshal.dump(e) rescue nil exit 42 end program end def relay srcdst src, dst, _ = srcdst.to_a.first if src.respond_to? 'read' while((buffer = src.read(8192))); dst << buffer; end else if src.respond_to?(:each_line) src.each_line{|buf| dst << buf} else src.each{|buf| dst << buf} end end end def slug_for(*args) options = args.last.is_a?(Hash) ? args.pop : {} join = (options[:join] || options['join'] || '_').to_s string = args.flatten.compact.join(join) words = string.to_s.scan(%r|[/\w]+|) words.map!{|word| word.gsub %r|[^/0-9a-zA-Z_-]|, ''} words.delete_if{|word| word.nil? or word.strip.empty?} words.join(join).downcase.gsub('/', (join * 2)) end def tmpdir d = Dir.tmpdir, max = 42, &b i = -1 and loop{ i += 1 tmp = File.join(d, slug_for("systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }")) begin Dir.mkdir tmp rescue Errno::EEXIST raise if i >= max next end break( if b begin b.call tmp ensure FileUtils.rm_rf tmp unless SystemU.turd end else tmp end ) } end def getopts opts = {} lambda do |*args| keys, default, _ = args catch(:opt) do [keys].flatten.each do |key| [key, key.to_s, key.to_s.intern].each do |k| throw :opt, opts[k] if opts.has_key?(k) end end default end end end end # some monkeypatching for JRuby if defined? JRUBY_VERSION require 'jruby' java_import org.jruby.RubyProcess class SystemUniversal def systemu split_argv = JRuby::PathHelper.smart_split_command @argv process = java.lang.Runtime.runtime.exec split_argv.to_java(:string) stdout, stderr = [process.input_stream, process.error_stream].map do |stream| StreamReader.new(stream) end field = process.get_class.get_declared_field("pid") field.set_accessible(true) pid = field.get(process) thread = new_thread pid, @block if @block exit_code = process.wait_for [ RubyProcess::RubyStatus.new_process_status(JRuby.runtime, exit_code, pid), stdout.join, stderr.join ] end class StreamReader def initialize(stream) @data = "" @thread = Thread.new do reader = java.io.BufferedReader.new java.io.InputStreamReader.new(stream) while line = reader.read_line @data << line << "\n" end end end def join @thread.join @data end end end end SystemU = SystemUniversal unless defined? SystemU Systemu = SystemUniversal unless defined? Systemu if $0 == __FILE__ # # date # date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " ) status, stdout, stderr = systemu date p [status, stdout, stderr] status = systemu date, 1=>(stdout = '') p [status, stdout] status = systemu date, 2=>(stderr = '') p [status, stderr] # # sleep # sleep = %q( ruby -e" p(sleep(1)) " ) status, stdout, stderr = systemu sleep p [status, stdout, stderr] sleep = %q( ruby -e" p(sleep(42)) " ) status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid} p [status, stdout, stderr] # # env # env = %q( ruby -e" p ENV['A'] " ) status, stdout, stderr = systemu env, :env => {'A' => 42} p [status, stdout, stderr] # # cwd # env = %q( ruby -e" p Dir.pwd " ) status, stdout, stderr = systemu env, :cwd => Dir.tmpdir p [status, stdout, stderr] end systemu-2.6.5/systemu.gemspec0000644000175000017500000000157612524363464015335 0ustar lucaslucas## systemu.gemspec # Gem::Specification::new do |spec| spec.name = "systemu" spec.version = "2.6.5" spec.platform = Gem::Platform::RUBY spec.summary = "systemu" spec.description = "universal capture of stdout and stderr and handling of child process pid for windows, *nix, etc." spec.license = "Ruby" spec.files = ["BSDL", "LICENSE", "README", "README.erb", "Rakefile", "lib", "lib/systemu.rb", "samples", "samples/a.rb", "samples/b.rb", "samples/c.rb", "samples/d.rb", "samples/e.rb", "samples/f.rb", "systemu.gemspec", "test", "test/systemu_test.rb", "test/testing.rb"] spec.executables = [] spec.require_path = "lib" spec.test_files = nil spec.extensions.push(*[]) spec.rubyforge_project = "codeforpeople" spec.author = "Ara T. Howard" spec.email = "ara.t.howard@gmail.com" spec.homepage = "https://github.com/ahoward/systemu" end systemu-2.6.5/metadata.yml0000644000175000017500000000226612524363464014557 0ustar lucaslucas--- !ruby/object:Gem::Specification name: systemu version: !ruby/object:Gem::Version version: 2.6.5 platform: ruby authors: - Ara T. Howard autorequire: bindir: bin cert_chain: [] date: 2015-03-19 00:00:00.000000000 Z dependencies: [] description: universal capture of stdout and stderr and handling of child process pid for windows, *nix, etc. email: ara.t.howard@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - BSDL - LICENSE - README - README.erb - Rakefile - lib/systemu.rb - samples/a.rb - samples/b.rb - samples/c.rb - samples/d.rb - samples/e.rb - samples/f.rb - systemu.gemspec - test/systemu_test.rb - test/testing.rb homepage: https://github.com/ahoward/systemu licenses: - Ruby metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: codeforpeople rubygems_version: 2.0.3 signing_key: specification_version: 4 summary: systemu test_files: [] systemu-2.6.5/LICENSE0000644000175000017500000000471712524363464013264 0ustar lucaslucassystemu is copyrighted free software by Ara T. Howard . You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. systemu-2.6.5/test/0000755000175000017500000000000012524363464013225 5ustar lucaslucassystemu-2.6.5/test/testing.rb0000644000175000017500000001045312524363464015232 0ustar lucaslucasrequire 'test/unit' testdir = File.expand_path(File.dirname(__FILE__)) rootdir = File.dirname(testdir) libdir = File.join(rootdir, 'lib') STDOUT.sync = true $:.unshift(testdir) unless $:.include?(testdir) $:.unshift(libdir) unless $:.include?(libdir) $:.unshift(rootdir) unless $:.include?(rootdir) class Testing class Slug < ::String def Slug.for(*args) string = args.flatten.compact.join('-') words = string.to_s.scan(%r/\w+/) words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''} words.delete_if{|word| word.nil? or word.strip.empty?} new(words.join('-').downcase) end end class Context attr_accessor :name def initialize(name, *args) @name = name end def to_s Slug.for(name) end end end def Testing(*args, &block) Class.new(::Test::Unit::TestCase) do ## class methods # class << self def contexts @contexts ||= [] end def context(*args, &block) return contexts.last if(args.empty? and block.nil?) context = Testing::Context.new(*args) contexts.push(context) begin block.call(context) ensure contexts.pop end end def slug_for(*args) string = [context, args].flatten.compact.join('-') words = string.to_s.scan(%r/\w+/) words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''} words.delete_if{|word| word.nil? or word.strip.empty?} words.join('-').downcase.sub(/_$/, '') end def name() const_get(:Name) end def testno() '%05d' % (@testno ||= 0) ensure @testno += 1 end def testing(*args, &block) method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_') define_method(method, &block) end def test(*args, &block) testing(*args, &block) end def setup(&block) define_method(:setup, &block) if block end def teardown(&block) define_method(:teardown, &block) if block end def prepare(&block) @prepare ||= [] @prepare.push(block) if block @prepare end def cleanup(&block) @cleanup ||= [] @cleanup.push(block) if block @cleanup end end ## configure the subclass! # const_set(:Testno, '0') slug = slug_for(*args).gsub(%r/-/,'_') name = ['TESTING', '%03d' % const_get(:Testno), slug].delete_if{|part| part.empty?}.join('_') name = name.upcase! const_set(:Name, name) const_set(:Missing, Object.new.freeze) ## instance methods # alias_method('__assert__', 'assert') def assert(*args, &block) if args.size == 1 and args.first.is_a?(Hash) options = args.first expected = getopt(:expected, options){ missing } actual = getopt(:actual, options){ missing } if expected == missing and actual == missing actual, expected, *ignored = options.to_a.flatten end expected = expected.call() if expected.respond_to?(:call) actual = actual.call() if actual.respond_to?(:call) assert_equal(expected, actual) end if block label = "assert(#{ args.join(' ') })" result = nil assert_nothing_raised{ result = block.call } __assert__(result, label) result else result = args.shift label = "assert(#{ args.join(' ') })" __assert__(result, label) result end end def missing self.class.const_get(:Missing) end def getopt(opt, hash, options = nil, &block) [opt.to_s, opt.to_s.to_sym].each do |key| return hash[key] if hash.has_key?(key) end default = if block block.call else options.is_a?(Hash) ? options[:default] : nil end return default end def subclass_of exception class << exception def ==(other) super or self > other end end exception end ## # module_eval(&block) self.setup() self.prepare.each{|b| b.call()} at_exit{ self.teardown() self.cleanup.each{|b| b.call()} } self end end if $0 == __FILE__ Testing 'Testing' do testing('foo'){ assert true } test{ assert true } p instance_methods.grep(/test/) end end systemu-2.6.5/test/systemu_test.rb0000644000175000017500000000342212524363464016323 0ustar lucaslucas Testing SystemU do ## # testing 'that simple usage works' do status, stdout, stderr = assert{ systemu :bin/:ls } assert{ status == 0 } assert{ stdout['lib'] } assert{ stderr.strip.empty? } end testing 'program with stdin' do stdin = '42' status, stdout, stderr = assert{ systemu :bin/:cat, :stdin => stdin } assert{ status == 0 } assert{ stdout == stdin } end testing 'silly hostnames' do host = SystemU.instance_variable_get('@host') silly_hostname = "silly's hostname with spaces" begin SystemU.instance_variable_set('@host', silly_hostname) assert{ SystemU.instance_variable_get('@host') == silly_hostname } stdin = '42' status, stdout, stderr = assert{ systemu :bin/:cat, :stdin => stdin } assert{ status == 0 } ensure assert{ SystemU.instance_variable_set('@host', host) } end end end BEGIN { # silly hax to build commands we can shell out to on any platform. since # tests might run on windoze we assume only that 'ruby' is available and build # other command-line programs from it. # module Kernel private def bin(which, options = {}, &block) case which.to_s when 'ls' %| ruby -e'puts Dir.glob("*").sort' | when 'cat' %| ruby -e'STDOUT.write(ARGF.read)' | when 'find' %| ruby -e'puts Dir.glob("**/**").sort' | end end end # just let's us write: :bin/:ls # class Symbol def / other, options = {}, &block eval "#{ self }(:#{ other }, options, &block)" end end testdir = File.dirname(File.expand_path(__FILE__)) rootdir = File.dirname(testdir) libdir = File.join(rootdir, 'lib') require File.join(libdir, 'systemu') require File.join(testdir, 'testing') Dir.chdir(rootdir) } systemu-2.6.5/README.erb0000644000175000017500000000112612524363464013675 0ustar lucaslucasNAME systemu SYNOPSIS univeral capture of stdout and stderr and handling of child process pid for windows, *nix, etc. URIS http://github.com/ahoward/systemu http://rubyforge.org/projects/codeforpeople/ INSTALL gem install systemu HISTORY 2.0.0 - versioning issue. new gem release. 1.3.1 - updates for ruby 1.9.1 1.3.0 - move to github 1.2.0 - fixed handling of background thread management - needed Thread.current.abort_on_exception = true - fixed reporting of child pid, it was reported as the parent's pid before SAMPLES <%= samples %> systemu-2.6.5/Rakefile0000644000175000017500000002364212524363464013722 0ustar lucaslucasThis.rubyforge_project = 'codeforpeople' This.author = "Ara T. Howard" This.email = "ara.t.howard@gmail.com" This.homepage = "https://github.com/ahoward/#{ This.lib }" task :license do open('LICENSE', 'w'){|fd| fd.puts "Ruby"} end task :default do puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort) end task :test do run_tests! end namespace :test do task(:unit){ run_tests!(:unit) } task(:functional){ run_tests!(:functional) } task(:integration){ run_tests!(:integration) } end def run_tests!(which = nil) which ||= '**' test_dir = File.join(This.dir, "test") test_glob ||= File.join(test_dir, "#{ which }/**_test.rb") test_rbs = Dir.glob(test_glob).sort div = ('=' * 119) line = ('-' * 119) test_rbs.each_with_index do |test_rb, index| testno = index + 1 command = "#{ This.ruby } -w -I ./lib -I ./test/lib #{ test_rb }" puts say(div, :color => :cyan, :bold => true) say("@#{ testno } => ", :bold => true, :method => :print) say(command, :color => :cyan, :bold => true) say(line, :color => :cyan, :bold => true) system(command) say(line, :color => :cyan, :bold => true) status = $?.exitstatus if status.zero? say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print) say("SUCCESS", :color => :green, :bold => true) else say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print) say("FAILURE", :color => :red, :bold => true) end say(line, :color => :cyan, :bold => true) exit(status) unless status.zero? end end task :gemspec do ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem'] ignore_directories = ['pkg'] ignore_files = ['test/log'] shiteless = lambda do |list| list.delete_if do |entry| next unless test(?e, entry) extension = File.basename(entry).split(%r/[.]/).last ignore_extensions.any?{|ext| ext === extension} end list.delete_if do |entry| next unless test(?d, entry) dirname = File.expand_path(entry) ignore_directories.any?{|dir| File.expand_path(dir) == dirname} end list.delete_if do |entry| next unless test(?f, entry) filename = File.expand_path(entry) ignore_files.any?{|file| File.expand_path(file) == filename} end end lib = This.lib object = This.object version = This.version files = shiteless[Dir::glob("**/**")] executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)} #has_rdoc = true #File.exist?('doc') test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb") summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass" description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass" license = object.respond_to?(:license) ? object.license : "Ruby" if This.extensions.nil? This.extensions = [] extensions = This.extensions %w( Makefile configure extconf.rb ).each do |ext| extensions << ext if File.exists?(ext) end end extensions = [extensions].flatten.compact if This.dependencies.nil? dependencies = [] else case This.dependencies when Hash dependencies = This.dependencies.values when Array dependencies = This.dependencies end end template = if test(?e, 'gemspec.erb') Template{ IO.read('gemspec.erb') } else Template { <<-__ ## <%= lib %>.gemspec # Gem::Specification::new do |spec| spec.name = <%= lib.inspect %> spec.version = <%= version.inspect %> spec.platform = Gem::Platform::RUBY spec.summary = <%= lib.inspect %> spec.description = <%= description.inspect %> spec.license = <%= license.inspect %> spec.files =\n<%= files.sort.pretty_inspect %> spec.executables = <%= executables.inspect %> spec.require_path = "lib" spec.test_files = <%= test_files.inspect %> <% dependencies.each do |lib_version| %> spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>) <% end %> spec.extensions.push(*<%= extensions.inspect %>) spec.rubyforge_project = <%= This.rubyforge_project.inspect %> spec.author = <%= This.author.inspect %> spec.email = <%= This.email.inspect %> spec.homepage = <%= This.homepage.inspect %> end __ } end Fu.mkdir_p(This.pkgdir) gemspec = "#{ lib }.gemspec" open(gemspec, "w"){|fd| fd.puts(template)} This.gemspec = gemspec end task :gem => [:clean, :gemspec] do Fu.mkdir_p(This.pkgdir) before = Dir['*.gem'] cmd = "gem build #{ This.gemspec }" `#{ cmd }` after = Dir['*.gem'] gem = ((after - before).first || after.first) or abort('no gem!') Fu.mv(gem, This.pkgdir) This.gem = File.join(This.pkgdir, File.basename(gem)) end task :readme do samples = '' prompt = '~ > ' lib = This.lib version = This.version Dir['sample*/*'].sort.each do |sample| samples << "\n" << " <========< #{ sample } >========>" << "\n\n" cmd = "cat #{ sample }" samples << Util.indent(prompt + cmd, 2) << "\n\n" samples << Util.indent(`#{ cmd }`, 4) << "\n" cmd = "ruby #{ sample }" samples << Util.indent(prompt + cmd, 2) << "\n\n" cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'" samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n" end template = if test(?e, 'README.erb') Template{ IO.read('README.erb') } else Template { <<-__ NAME #{ lib } DESCRIPTION INSTALL gem install #{ lib } SAMPLES #{ samples } __ } end open("README", "w"){|fd| fd.puts template} end task :clean do Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)} end task :release => [:clean, :gemspec, :gem] do gems = Dir[File.join(This.pkgdir, '*.gem')].flatten raise "which one? : #{ gems.inspect }" if gems.size > 1 raise "no gems?" if gems.size < 1 cmd = "gem push #{ This.gem }" puts cmd puts system(cmd) abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero? cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }" puts cmd puts system(cmd) abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero? end BEGIN { # support for this rakefile # $VERBOSE = nil require 'ostruct' require 'erb' require 'fileutils' require 'rbconfig' require 'pp' # fu shortcut # Fu = FileUtils # cache a bunch of stuff about this rakefile/environment # This = OpenStruct.new This.file = File.expand_path(__FILE__) This.dir = File.dirname(This.file) This.pkgdir = File.join(This.dir, 'pkg') # grok lib # lib = ENV['LIB'] unless lib lib = File.basename(Dir.pwd).sub(/[-].*$/, '') end This.lib = lib # grok version # version = ENV['VERSION'] unless version require "./lib/#{ This.lib }" This.name = lib.capitalize This.object = eval(This.name) version = This.object.send(:version) end This.version = version # see if dependencies are export by the module # if This.object.respond_to?(:dependencies) This.dependencies = This.object.dependencies end # we need to know the name of the lib an it's version # abort('no lib') unless This.lib abort('no version') unless This.version # discover full path to this ruby executable # c = RbConfig::CONFIG bindir = c["bindir"] || c['BINDIR'] ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby' ruby_ext = c['EXEEXT'] || '' ruby = File.join(bindir, (ruby_install_name + ruby_ext)) This.ruby = ruby # some utils # module Util def indent(s, n = 2) s = unindent(s) ws = ' ' * n s.gsub(%r/^/, ws) end def unindent(s) indent = nil s.each_line do |line| next if line =~ %r/^\s*$/ indent = line[%r/^\s*/] and break end indent ? s.gsub(%r/^#{ indent }/, "") : s end extend self end # template support # class Template def initialize(&block) @block = block @template = block.call.to_s end def expand(b=nil) ERB.new(Util.unindent(@template)).result((b||@block).binding) end alias_method 'to_s', 'expand' end def Template(*args, &block) Template.new(*args, &block) end # colored console output support # This.ansi = { :clear => "\e[0m", :reset => "\e[0m", :erase_line => "\e[K", :erase_char => "\e[P", :bold => "\e[1m", :dark => "\e[2m", :underline => "\e[4m", :underscore => "\e[4m", :blink => "\e[5m", :reverse => "\e[7m", :concealed => "\e[8m", :black => "\e[30m", :red => "\e[31m", :green => "\e[32m", :yellow => "\e[33m", :blue => "\e[34m", :magenta => "\e[35m", :cyan => "\e[36m", :white => "\e[37m", :on_black => "\e[40m", :on_red => "\e[41m", :on_green => "\e[42m", :on_yellow => "\e[43m", :on_blue => "\e[44m", :on_magenta => "\e[45m", :on_cyan => "\e[46m", :on_white => "\e[47m" } def say(phrase, *args) options = args.last.is_a?(Hash) ? args.pop : {} options[:color] = args.shift.to_s.to_sym unless args.empty? keys = options.keys keys.each{|key| options[key.to_s.to_sym] = options.delete(key)} color = options[:color] bold = options.has_key?(:bold) parts = [phrase] parts.unshift(This.ansi[color]) if color parts.unshift(This.ansi[:bold]) if bold parts.push(This.ansi[:clear]) if parts.size > 1 method = options[:method] || :puts Kernel.send(method, parts.join) end # always run out of the project dir # Dir.chdir(This.dir) }