1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
module Tins
module FileBinary
module Constants
SEEK_SET = ::File::SEEK_SET
ZERO = "\x00"
BINARY = "\x01-\x1f\x7f-\xff"
if defined?(::Encoding)
ZERO.force_encoding(Encoding::ASCII_8BIT)
BINARY.force_encoding(Encoding::ASCII_8BIT)
end
end
class << self
# Default options can be queried/set via this hash.
attr_accessor :default_options
end
self.default_options = {
offset: 0,
buffer_size: 2 ** 13,
percentage_binary: 30.0,
percentage_zeros: 0.0,
}
# Returns true if this file is considered to be binary, false if it is not
# considered to be binary, and nil if it was empty.
#
# A file is considered to be binary if the percentage of zeros exceeds
# <tt>options[:percentage_zeros]</tt> or the percentage of binary bytes
# (8-th bit is 1) exceeds <tt>options[:percentage_binary]</tt> in the
# buffer of size <tt>options[:buffer_size]</tt> that is checked (beginning
# from offset <tt>options[:offset]</tt>). If an option isn't given the one
# from FileBinary.default_options is used instead.
def binary?(options = {})
options = FileBinary.default_options.merge(options)
old_pos = tell
seek options[:offset], Constants::SEEK_SET
data = read options[:buffer_size]
!data or data.empty? and return nil
data_size = data.size
data.count(Constants::ZERO).to_f / data_size >
options[:percentage_zeros] / 100.0 and return true
data.count(Constants::BINARY).to_f / data_size >
options[:percentage_binary] / 100.0
ensure
old_pos and seek old_pos, Constants::SEEK_SET
end
# Returns true if FileBinary#binary? returns false, false if
# FileBinary#binary? returns true, and nil otherwise. For an explanation of
# +options+, see FileBinary#binary?.
def ascii?(options = {})
case binary?(options)
when true then false
when false then true
end
end
def self.included(modul)
modul.instance_eval do
extend ClassMethods
end
super
end
module ClassMethods
# Returns true if the file with name +name+ is considered to be binary
# using the FileBinary#binary? method.
def binary?(name, options = {})
open(name, 'rb') { |f| f.binary?(options) }
end
# Returns true if the file with name +name+ is considered to be ascii
# using the FileBinary#ascii? method.
def ascii?(name, options = {})
open(name, 'rb') { |f| f.ascii?(options) }
end
end
end
end
require 'tins/alias'
|