lib/file/bbfile.rb in bblib-0.3.0 vs lib/file/bbfile.rb in bblib-0.4.1
- old
+ new
@@ -1,92 +1,133 @@
-
module BBLib
-
# Takes one or more strings and normalizes slashes to create a consistent file path
# Useful when concating two strings that when you don't know if one or both will end or begin with a slash
- def self.pathify *strings
- start = strings.first.start_with?('/') || strings.first.start_with?('\\')
- (start ? '/' : '' ) + strings.map(&:to_s).msplit('/', '\\').map(&:strip).join('/')
+ def self.pathify(*strings)
+ (strings.first.start_with?('/', '\\') ? '/' : '') + strings.map(&:to_s).msplit('/', '\\').map(&:strip).join('/')
end
# Scan for files and directories. Can be set to be recursive and can also have filters applied.
- def self.scan_dir path = Dir.pwd, filter: nil, recursive: false
- if !filter.nil?
- filter = [filter].flatten.map{ |f| path.to_s + (recursive ? '/**/' : '/') + f.to_s }
- else
- filter = (path.to_s + (recursive ? '/**/*' : '/*')).gsub('//', '/')
- end
- Dir.glob(filter)
+ # @param [String] path The directory to scan files from.
+ # @param [String..., Regexp...] filters A list of filters to apply. Can be regular expressions or strings.
+ # Strings with a * are treated as regular expressions with a .*. If no filters are passed, all files/dirs are returned.
+ # @param [Boolean] recursive When true scan will recursively search directories
+ # @param [Boolean] files If true, paths to files matching the filter will be returned.
+ # @param [Boolean] dirs If true, paths to dirs matching the filter will be returned.
+ def self.scan_dir(path, *filters, recursive: false, files: true, dirs: true, &block)
+ return [] unless Dir.exist?(path)
+ filters = filters.map { |filter| filter.is_a?(Regexp) ? filter : /^#{Regexp.quote(filter).gsub('\\*', '.*')}$/ }
+ Dir.foreach(path).flat_map do |item|
+ next if item =~ /^\.{1,2}$/
+ item = "#{path}/#{item}".gsub('\\', '/')
+ if File.file?(item)
+ if files && (filters.empty? || filters.any? { |filter| item =~ filter })
+ block_given? ? yield(item) : item
+ end
+ elsif File.directory?(item)
+ recur = recursive ? scan_dir(item, *filters, recursive: recursive, files: files, dirs: dirs, &block) : []
+ if dirs && (filters.empty? || filters.any? { |filter| item =~ filter })
+ (block_given? ? yield(item) : [item] + recur)
+ elsif recursive
+ recur
+ end
+ end
+ end.compact
end
- # Uses BBLib.scan_dir but returns only files. Mode can be used to return strings (:path) or File objects (:file)
- def self.scan_files path, filter: nil, recursive: false, mode: :path
- BBLib.scan_dir(path, filter: filter, recursive: recursive).map{ |f| File.file?(f) ? (mode == :file ? File.new(f) : f) : nil}.reject{ |r| r.nil? }
+ # Uses BBLib.scan_dir but returns only files
+ def self.scan_files(path, *filters, recursive: false, &block)
+ scan_dir(path, *filters, recursive: recursive, dirs: false, &block)
end
- # Uses BBLib.scan_dir but returns only directories. Mode can be used to return strings (:path) or Dir objects (:dir)
- def self.scan_dirs path, filter: nil, recursive: false, mode: :path
- BBLib.scan_dir(path, filter: filter, recursive: recursive).map{ |f| File.directory?(f) ? (mode == :dir ? Dir.new(f) : f ) : nil}.reject{ |r| r.nil? }
+ # Uses BBLib.scan_dir but returns only directories.
+ def self.scan_dirs(path, *filters, recursive: false, &block)
+ scan_dir(path, *filters, recursive: recursive, files: false, &block)
end
- # Shorthand method to write a string to disk. By default the path is created if it doesn't exist.
+ # Shorthand method to write a string to disk. By default the
+ # path is created if it doesn't exist.
# Set mode to w to truncate file or leave at a to append.
- def self.string_to_file path, str, mkpath = true, mode: 'a'
- if !Dir.exists?(path) && mkpath
- FileUtils.mkpath File.dirname(path)
- end
- File.write(path, str.to_s, mode:mode)
+ def self.string_to_file(str, path, mkpath: true, mode: 'a')
+ FileUtils.mkpath(File.dirname(path)) if mkpath && !Dir.exist?(path)
+ File.write(path, str.to_s, mode: mode)
end
# A file size parser for strings. Extracts any known patterns for file sizes.
- def self.parse_file_size str, output: :byte
- output = FILE_SIZES.keys.find{ |f| f == output || FILE_SIZES[f][:exp].include?(output.to_s.downcase) } || :byte
+ def self.parse_file_size(str, output: :byte)
+ output = FILE_SIZES.keys.find { |fs| fs == output || FILE_SIZES[fs][:exp].include?(output.to_s.downcase) } || :byte
bytes = 0.0
- FILE_SIZES.each do |k, v|
- v[:exp].each do |e|
- numbers = str.scan(/(?=\w|\D|^)\d*\.?\d+\s*#{e}s?(?=\W|\d|$)/i)
- numbers.each{ |n| bytes+= n.to_f * v[:mult] }
+ FILE_SIZES.each do |_k, v|
+ v[:exp].each do |exp|
+ str.scan(/(?=\w|\D|^)\d*\.?\d+\s*#{exp}s?(?=\W|\d|$)/i)
+ .each { |num| bytes += num.to_f * v[:mult] }
end
end
- return bytes / FILE_SIZES[output][:mult]
+ bytes / FILE_SIZES[output][:mult]
end
- FILE_SIZES = {
- byte: { mult: 1, exp: ['b', 'byt', 'byte'] },
- kilobyte: { mult: 1024, exp: ['kb', 'kilo', 'k', 'kbyte', 'kilobyte'] },
- megabyte: { mult: 1048576, exp: ['mb', 'mega', 'm', 'mib', 'mbyte', 'megabyte'] },
- gigabyte: { mult: 1073741824, exp: ['gb', 'giga', 'g', 'gbyte', 'gigabyte'] },
- terabyte: { mult: 1099511627776, exp: ['tb', 'tera', 't', 'tbyte', 'terabyte'] },
- petabyte: { mult: 1125899906842624, exp: ['pb', 'peta', 'p', 'pbyte', 'petabyte'] },
- exabyte: { mult: 1152921504606846976, exp: ['eb', 'exa', 'e', 'ebyte', 'exabyte'] },
- zettabyte: { mult: 1180591620717411303424, exp: ['zb', 'zetta', 'z', 'zbyte', 'zettabyte'] },
- yottabyte: { mult: 1208925819614629174706176, exp: ['yb', 'yotta', 'y', 'ybyte', 'yottabyte'] }
- }
+ # Takes an integer or float and converts it into a string that represents
+ # a file size (e.g. "5 MB 156 kB")
+ # @param [Integer, Float] num The number of bytes to convert to a file size string.
+ # @param [Symbol] input Sets the value of the input. Default is byte.
+ # @param [Symbol] stop Sets a minimum file size to display.
+ # e.g. If stop is set to :megabyte, :kilobyte and below will be truncated.
+ # @param [Symbol] style The out style, Current options are :short and :long
+ def self.to_file_size(num, input: :byte, stop: :byte, style: :short)
+ return nil unless num.is_a?(Numeric)
+ return '0' if num.zero?
+ style = :short unless [:long, :short].include?(style)
+ expression = []
+ n = num * FILE_SIZES[input.to_sym][:mult]
+ done = false
+ FILE_SIZES.reverse.each do |k, v|
+ next if done
+ done = true if k == stop
+ div = n / v[:mult]
+ next unless div >= 1
+ val = (done ? div.round : div.floor)
+ expression << "#{val}#{v[:styles][style]}#{val > 1 && style != :short ? 's' : nil}"
+ n -= val.to_f * v[:mult]
+ end
+ expression.join(' ')
+ end
+ FILE_SIZES = {
+ byte: { mult: 1, exp: %w(b byt byte), styles: { short: 'B', long: ' byte' } },
+ kilobyte: { mult: 1024, exp: %w(kb kilo k kbyte kilobyte), styles: { short: 'kB', long: ' kilobyte' } },
+ megabyte: { mult: 1024**2, exp: %w(mb mega m mib mbyte megabyte), styles: { short: 'MB', long: ' megabyte' } },
+ gigabyte: { mult: 1024**3, exp: %w(gb giga g gbyte gigabyte), styles: { short: 'GB', long: ' gigabyte' } },
+ terabyte: { mult: 1024**4, exp: %w(tb tera t tbyte terabyte), styles: { short: 'TB', long: ' terabyte' } },
+ petabyte: { mult: 1024**5, exp: %w(pb peta p pbyte petabyte), styles: { short: 'PB', long: ' petabyte' } },
+ exabyte: { mult: 1024**6, exp: %w(eb exa e ebyte exabyte), styles: { short: 'EB', long: ' exabyte' } },
+ zettabyte: { mult: 1024**7, exp: %w(zb zetta z zbyte zettabyte), styles: { short: 'ZB', long: ' zettabyte' } },
+ yottabyte: { mult: 1024**8, exp: %w(yb yotta y ybyte yottabyte), styles: { short: 'YB', long: ' yottabyte' } }
+ }.freeze
end
-class File
- def dirname
- File.dirname(self.path)
+# Monkey patches for the Numeric class
+class Numeric
+ def to_file_size(*args)
+ BBLib.to_file_size(self, *args)
end
end
+# Monkey patches for the String class
class String
- def to_file path, mkpath = true, mode: 'a'
- BBLib.string_to_file path, self, mkpath, mode:mode
+ def to_file(*args)
+ BBLib.string_to_file(self, *args)
end
- def file_name with_extension = true
- self[(self.include?('/') ? self.rindex('/').to_i+1 : 0)..(with_extension ? -1 : self.rindex('.').to_i-1)]
+ def file_name(with_extension = true)
+ with_extension ? File.basename(self) : File.basename(self, File.extname(self))
end
def dirname
- self.scan(/.*(?=\/)/).first
+ File.dirname(self)
end
- def parse_file_size output: :byte
- BBLib.parse_file_size(self, output:output)
+ def parse_file_size(*args)
+ BBLib.parse_file_size(self, *args)
end
def pathify
BBLib.pathify(self)
end