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 # options[:percentage_zeros] or the percentage of binary bytes # (8-th bit is 1) exceeds options[:percentage_binary] in the # buffer of size options[:buffer_size] that is checked (beginning # from offset options[:offset]). 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'