module BitGirder::Io
Constants
- ORDER_BIG_ENDIAN
- ORDER_LITTLE_ENDIAN
Private Class Methods
# File lib/bitgirder/io.rb, line 36 def as_encoded( str, enc ) not_nil( str, :str ) not_nil( enc, :enc ) str.encoding == enc ? str : str.encode( enc ) end
# File lib/bitgirder/io.rb, line 220 def as_json( obj ); JSON.generate( not_nil( obj, :obj ) ); end
# File lib/bitgirder/io.rb, line 207 def as_read_src( obj ) not_nil( obj, :obj ) case obj when IO, Tempfile then yield( obj ) when String then File.open( file_exists( obj ) ) { |io| yield( io ) } else raise TypeError, "Unkown read src: #{obj.class}" end end
# File lib/bitgirder/io.rb, line 194 def as_write_dest( obj ) not_nil( obj, :obj ) case obj when IO, Tempfile then yield( obj ) when String then File.open( obj, "w" ) { |io| yield( io ) } else raise TypeError, "Unknown write dest: #{obj.class}" end end
# File lib/bitgirder/io.rb, line 387 def can_connect?( *argv ) raise "Need at least a port" if argv.empty? host = argv.first.is_a?( String ) ? argv.shift : "127.0.0.1" raise "Need a port" if argv.empty? unless ( port = argv.shift ).is_a?( Integer ) raise TypeError, "Invalid host or port value: #{port.class}" end begin TCPSocket::new( host, port ).close true rescue Errno::ECONNREFUSED, Errno::ECONNRESET false end end
# File lib/bitgirder/io.rb, line 359 def debug_kill( sig, pid, opts = {} ) not_nil( opts, "opts" ) msg = "Sending #{sig} to #{pid}" msg += " (#{opts[ :name ]})" if opts.key?( :name ) BitGirderLogger.get_logger.code( msg ) Process.kill( sig, pid ) end
# File lib/bitgirder/io.rb, line 335 def debug_wait2( opts ) not_nil( opts, "opts" ) pid = has_key( opts, :pid ) name = opts[ :name ] name_str = name ? "#{name} (pid #{pid})" : pid.to_s code( "Waiting on #{name_str}" ) pid, status = Process::wait2( pid ) msg = "Process #{pid} exited with status #{status.exitstatus}" if status.success? code( msg ) else opts[ :check_status ] ? ( raise msg ) : warn( msg ) end [ pid, status ] end
# File lib/bitgirder/io.rb, line 71 def digest_file( opts ) dig_cls, file = has_keys( opts, :digest_type, :file ) buf_sz = opts[ :buffer_size ] || 50 * ( 1 << 10 ) # Set this now so we can fail before reading file if need be out_func = case ot = opts[ :output_type ] when nil, :binary then lambda { |dig| dig } when :base64 then lambda { |dig| strict_encode64( dig ) } else raise "Unhandled output type: #{ot}" end dig = dig_cls.new File.open( file ) do |io| buf = "" while buf = io.read( buf_sz, buf ) dig.update( buf ) end end out_func.call( dig.digest ) end
# File lib/bitgirder/io.rb, line 228 def dump_json( obj, file ) not_nil( obj, :obj ) not_nil( file, :file ) json = as_json( obj ) as_write_dest( file ) { |io| io.print( json ) } end
# File lib/bitgirder/io.rb, line 248 def dump_yaml( obj, dest = nil ) not_nil( obj, :obj ) if dest as_write_dest( dest ) { |io| YAML.dump( obj, io ) } else YAML.dump( obj ) end end
Lazily load and assert presence of utf8 encoding
# File lib/bitgirder/io.rb, line 22 def enc_utf8 @@enc_utf8 ||= ( Encoding.find( "utf-8" ) or raise "No utf-8 encoding found (?!)" ) end
Effectively enables mdkir_p as an inline function to enable statements like:
some_dir = ensure_dir( some_dir )
# File lib/bitgirder/io.rb, line 285 def ensure_dir( d ) fu().mkdir_p( d ) unless File.exist?( d ) d end
# File lib/bitgirder/io.rb, line 301 def ensure_dirs( *dirs ) dirs.each { |dir| ensure_dir( dir ) } end
Ensures that the directory referred to as dirname( file ) exists, and returns file itself (not the parent). Fails if dirname does not return anything meaningful for file.
# File lib/bitgirder/io.rb, line 310 def ensure_parent( file ) parent = File.dirname( file ) raise "No parent exists for #{file}" unless parent ensure_dir( parent ) file end
# File lib/bitgirder/io.rb, line 293 def ensure_wiped( d ) fu().rm_rf( d ) ensure_dir( d ) end
# File lib/bitgirder/io.rb, line 122 def file_exists( d ) raise "File or directory #{d} does not exist" unless File.exist?( d ) d end
# File lib/bitgirder/io.rb, line 166 def first_line( file ) File.open( file ) { |io| io.readline.chomp } end
# File lib/bitgirder/io.rb, line 142 def fsize( obj ) stat = case obj when File, Tempfile then File.stat( obj.path ) when String then File.stat( obj ) else raise TypeError, "Unhandled type for fsize: #{obj.class}" end stat.size end
# File lib/bitgirder/io.rb, line 30 def fu() BitGirderLogger.get_logger.is_debug? ? FileUtils::Verbose : FileUtils end
Returns i as a little-endian 2’s complement byte array; Algorithm is from stackoverflow.com/questions/5284369/ruby-return-byte-array-containing-twos-complement-representation-of-bignum-fi (with some cosmetic differences, including the return val’s endianness).
Though not stated there, it’s worth noting that the reason for the end condition test of the 7th (sign) bit is to avoid stopping prematurely on inputs such as 0xff00, dropping the sign information from the result
# File lib/bitgirder/io.rb, line 106 def int_to_byte_array( i ) not_nil( i, :i ) res = [] begin res << ( i & 0xff ) i >>= 8 end until ( i == 0 || i == -1 ) && ( res[ -1 ][ 7 ] == i[ 7 ] ) res end
# File lib/bitgirder/io.rb, line 270 def is_executable( file ) file_exists( file ) raise "Not an executable: #{file}" unless File.executable?( file ) file end
# File lib/bitgirder/io.rb, line 240 def load_json( file ) not_nil( file, :file ) as_read_src( file ) { |io| parse_json( slurp( io ) ) } end
# File lib/bitgirder/io.rb, line 261 def load_yaml( src ) not_nil( src, :src ) as_read_src( src ) { |io| YAML.load( io ) } end
# File lib/bitgirder/io.rb, line 136 def mktmpdir( *argv, &blk ) Dir.mktmpdir( *argv, &blk ) end
# File lib/bitgirder/io.rb, line 130 def open_tempfile( basename = nil, *rest, &blk ) basename ||= [ "bg-tmp-", ".tmp" ] Tempfile::open( basename, *rest, &blk ) end
# File lib/bitgirder/io.rb, line 224 def parse_json( str ); JSON.parse( not_nil( str, :str ) ); end
# File lib/bitgirder/io.rb, line 372 def read_full( io, len, buf = nil ) args = [ len ] args << buf if buf buf = io.read( *args ) if ( sz = buf == nil ? 0 : buf.bytesize ) < len raise EOFError.new( "EOF after #{sz} bytes (wanted #{len})" ) end buf end
# File lib/bitgirder/io.rb, line 183 def slurp( io, blk_sz = 4096 ) case io when IO, Tempfile then slurp_io( io, blk_sz ) when String then File.open( io ) { |io2| slurp_io( io2, blk_sz ) } else raise "Unknown slurp target: #{io} (#{io.class})" end end
# File lib/bitgirder/io.rb, line 172 def slurp_io( io, blk_sz = 4096 ) not_nil( io, :io ) while s = io.read( blk_sz ); res = res ? res << s : s; end res end
Despite the name, this method only enforces strictness when running in a ruby >= 1.9 for now, though we may backport and handcode integrity checks at some point for other rubies
# File lib/bitgirder/io.rb, line 60 def strict_decode64( str ) if RUBY_VERSION >= "1.9" Base64.strict_decode64( str ) else Base64.decode64( str ) end end
# File lib/bitgirder/io.rb, line 46 def strict_encode64( str ) if RUBY_VERSION >= "1.9" Base64.strict_encode64( str ) else Base64.encode64( str ).split( /\n/ ).join( "" ) end end
# File lib/bitgirder/io.rb, line 322 def which( cmd, fail_on_miss = false ) not_nil( cmd, "cmd" ) if ( f = `which #{cmd}`.strip ) and f.empty? raise "Cannot find command #{cmd.inspect} in path" if fail_on_miss else f end end
# File lib/bitgirder/io.rb, line 158 def write_file( text, file ) fu().mkdir_p( File.dirname( file ) ) File.open( file, "w" ) { |io| io.print text } end
Private Instance Methods
# File lib/bitgirder/io.rb, line 36 def as_encoded( str, enc ) not_nil( str, :str ) not_nil( enc, :enc ) str.encoding == enc ? str : str.encode( enc ) end
# File lib/bitgirder/io.rb, line 220 def as_json( obj ); JSON.generate( not_nil( obj, :obj ) ); end
# File lib/bitgirder/io.rb, line 207 def as_read_src( obj ) not_nil( obj, :obj ) case obj when IO, Tempfile then yield( obj ) when String then File.open( file_exists( obj ) ) { |io| yield( io ) } else raise TypeError, "Unkown read src: #{obj.class}" end end
# File lib/bitgirder/io.rb, line 194 def as_write_dest( obj ) not_nil( obj, :obj ) case obj when IO, Tempfile then yield( obj ) when String then File.open( obj, "w" ) { |io| yield( io ) } else raise TypeError, "Unknown write dest: #{obj.class}" end end
# File lib/bitgirder/io.rb, line 387 def can_connect?( *argv ) raise "Need at least a port" if argv.empty? host = argv.first.is_a?( String ) ? argv.shift : "127.0.0.1" raise "Need a port" if argv.empty? unless ( port = argv.shift ).is_a?( Integer ) raise TypeError, "Invalid host or port value: #{port.class}" end begin TCPSocket::new( host, port ).close true rescue Errno::ECONNREFUSED, Errno::ECONNRESET false end end
# File lib/bitgirder/io.rb, line 359 def debug_kill( sig, pid, opts = {} ) not_nil( opts, "opts" ) msg = "Sending #{sig} to #{pid}" msg += " (#{opts[ :name ]})" if opts.key?( :name ) BitGirderLogger.get_logger.code( msg ) Process.kill( sig, pid ) end
# File lib/bitgirder/io.rb, line 335 def debug_wait2( opts ) not_nil( opts, "opts" ) pid = has_key( opts, :pid ) name = opts[ :name ] name_str = name ? "#{name} (pid #{pid})" : pid.to_s code( "Waiting on #{name_str}" ) pid, status = Process::wait2( pid ) msg = "Process #{pid} exited with status #{status.exitstatus}" if status.success? code( msg ) else opts[ :check_status ] ? ( raise msg ) : warn( msg ) end [ pid, status ] end
# File lib/bitgirder/io.rb, line 71 def digest_file( opts ) dig_cls, file = has_keys( opts, :digest_type, :file ) buf_sz = opts[ :buffer_size ] || 50 * ( 1 << 10 ) # Set this now so we can fail before reading file if need be out_func = case ot = opts[ :output_type ] when nil, :binary then lambda { |dig| dig } when :base64 then lambda { |dig| strict_encode64( dig ) } else raise "Unhandled output type: #{ot}" end dig = dig_cls.new File.open( file ) do |io| buf = "" while buf = io.read( buf_sz, buf ) dig.update( buf ) end end out_func.call( dig.digest ) end
# File lib/bitgirder/io.rb, line 228 def dump_json( obj, file ) not_nil( obj, :obj ) not_nil( file, :file ) json = as_json( obj ) as_write_dest( file ) { |io| io.print( json ) } end
# File lib/bitgirder/io.rb, line 248 def dump_yaml( obj, dest = nil ) not_nil( obj, :obj ) if dest as_write_dest( dest ) { |io| YAML.dump( obj, io ) } else YAML.dump( obj ) end end
Lazily load and assert presence of utf8 encoding
# File lib/bitgirder/io.rb, line 22 def enc_utf8 @@enc_utf8 ||= ( Encoding.find( "utf-8" ) or raise "No utf-8 encoding found (?!)" ) end
Effectively enables mdkir_p as an inline function to enable statements like:
some_dir = ensure_dir( some_dir )
# File lib/bitgirder/io.rb, line 285 def ensure_dir( d ) fu().mkdir_p( d ) unless File.exist?( d ) d end
# File lib/bitgirder/io.rb, line 301 def ensure_dirs( *dirs ) dirs.each { |dir| ensure_dir( dir ) } end
Ensures that the directory referred to as dirname( file ) exists, and returns file itself (not the parent). Fails if dirname does not return anything meaningful for file.
# File lib/bitgirder/io.rb, line 310 def ensure_parent( file ) parent = File.dirname( file ) raise "No parent exists for #{file}" unless parent ensure_dir( parent ) file end
# File lib/bitgirder/io.rb, line 293 def ensure_wiped( d ) fu().rm_rf( d ) ensure_dir( d ) end
# File lib/bitgirder/io.rb, line 122 def file_exists( d ) raise "File or directory #{d} does not exist" unless File.exist?( d ) d end
# File lib/bitgirder/io.rb, line 166 def first_line( file ) File.open( file ) { |io| io.readline.chomp } end
# File lib/bitgirder/io.rb, line 142 def fsize( obj ) stat = case obj when File, Tempfile then File.stat( obj.path ) when String then File.stat( obj ) else raise TypeError, "Unhandled type for fsize: #{obj.class}" end stat.size end
# File lib/bitgirder/io.rb, line 30 def fu() BitGirderLogger.get_logger.is_debug? ? FileUtils::Verbose : FileUtils end
Returns i as a little-endian 2’s complement byte array; Algorithm is from stackoverflow.com/questions/5284369/ruby-return-byte-array-containing-twos-complement-representation-of-bignum-fi (with some cosmetic differences, including the return val’s endianness).
Though not stated there, it’s worth noting that the reason for the end condition test of the 7th (sign) bit is to avoid stopping prematurely on inputs such as 0xff00, dropping the sign information from the result
# File lib/bitgirder/io.rb, line 106 def int_to_byte_array( i ) not_nil( i, :i ) res = [] begin res << ( i & 0xff ) i >>= 8 end until ( i == 0 || i == -1 ) && ( res[ -1 ][ 7 ] == i[ 7 ] ) res end
# File lib/bitgirder/io.rb, line 270 def is_executable( file ) file_exists( file ) raise "Not an executable: #{file}" unless File.executable?( file ) file end
# File lib/bitgirder/io.rb, line 240 def load_json( file ) not_nil( file, :file ) as_read_src( file ) { |io| parse_json( slurp( io ) ) } end
# File lib/bitgirder/io.rb, line 261 def load_yaml( src ) not_nil( src, :src ) as_read_src( src ) { |io| YAML.load( io ) } end
# File lib/bitgirder/io.rb, line 136 def mktmpdir( *argv, &blk ) Dir.mktmpdir( *argv, &blk ) end
# File lib/bitgirder/io.rb, line 130 def open_tempfile( basename = nil, *rest, &blk ) basename ||= [ "bg-tmp-", ".tmp" ] Tempfile::open( basename, *rest, &blk ) end
# File lib/bitgirder/io.rb, line 224 def parse_json( str ); JSON.parse( not_nil( str, :str ) ); end
# File lib/bitgirder/io.rb, line 372 def read_full( io, len, buf = nil ) args = [ len ] args << buf if buf buf = io.read( *args ) if ( sz = buf == nil ? 0 : buf.bytesize ) < len raise EOFError.new( "EOF after #{sz} bytes (wanted #{len})" ) end buf end
# File lib/bitgirder/io.rb, line 183 def slurp( io, blk_sz = 4096 ) case io when IO, Tempfile then slurp_io( io, blk_sz ) when String then File.open( io ) { |io2| slurp_io( io2, blk_sz ) } else raise "Unknown slurp target: #{io} (#{io.class})" end end
# File lib/bitgirder/io.rb, line 172 def slurp_io( io, blk_sz = 4096 ) not_nil( io, :io ) while s = io.read( blk_sz ); res = res ? res << s : s; end res end
Despite the name, this method only enforces strictness when running in a ruby >= 1.9 for now, though we may backport and handcode integrity checks at some point for other rubies
# File lib/bitgirder/io.rb, line 60 def strict_decode64( str ) if RUBY_VERSION >= "1.9" Base64.strict_decode64( str ) else Base64.decode64( str ) end end
# File lib/bitgirder/io.rb, line 46 def strict_encode64( str ) if RUBY_VERSION >= "1.9" Base64.strict_encode64( str ) else Base64.encode64( str ).split( /\n/ ).join( "" ) end end
# File lib/bitgirder/io.rb, line 322 def which( cmd, fail_on_miss = false ) not_nil( cmd, "cmd" ) if ( f = `which #{cmd}`.strip ) and f.empty? raise "Cannot find command #{cmd.inspect} in path" if fail_on_miss else f end end
# File lib/bitgirder/io.rb, line 158 def write_file( text, file ) fu().mkdir_p( File.dirname( file ) ) File.open( file, "w" ) { |io| io.print text } end