bblib 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +11 -10
  3. data/.rspec +2 -2
  4. data/.travis.yml +4 -4
  5. data/CODE_OF_CONDUCT.md +13 -13
  6. data/Gemfile +4 -4
  7. data/LICENSE.txt +21 -21
  8. data/README.md +247 -757
  9. data/Rakefile +6 -6
  10. data/bblib.gemspec +34 -34
  11. data/bin/console +14 -14
  12. data/bin/setup +7 -7
  13. data/lib/array/bbarray.rb +71 -29
  14. data/lib/bblib.rb +12 -12
  15. data/lib/bblib/version.rb +3 -3
  16. data/lib/class/effortless.rb +23 -0
  17. data/lib/error/abstract.rb +3 -0
  18. data/lib/file/bbfile.rb +93 -52
  19. data/lib/hash/bbhash.rb +130 -46
  20. data/lib/hash/hash_struct.rb +24 -0
  21. data/lib/hash/tree_hash.rb +364 -0
  22. data/lib/hash_path/hash_path.rb +210 -0
  23. data/lib/hash_path/part.rb +83 -0
  24. data/lib/hash_path/path_hash.rb +84 -0
  25. data/lib/hash_path/proc.rb +93 -0
  26. data/lib/hash_path/processors.rb +239 -0
  27. data/lib/html/bbhtml.rb +2 -0
  28. data/lib/html/builder.rb +34 -0
  29. data/lib/html/tag.rb +49 -0
  30. data/lib/logging/bblogging.rb +42 -0
  31. data/lib/mixins/attrs.rb +422 -0
  32. data/lib/mixins/bbmixins.rb +7 -0
  33. data/lib/mixins/bridge.rb +17 -0
  34. data/lib/mixins/family_tree.rb +41 -0
  35. data/lib/mixins/hooks.rb +139 -0
  36. data/lib/mixins/logger.rb +31 -0
  37. data/lib/mixins/serializer.rb +71 -0
  38. data/lib/mixins/simple_init.rb +160 -0
  39. data/lib/number/bbnumber.rb +15 -7
  40. data/lib/object/bbobject.rb +46 -19
  41. data/lib/opal/bbopal.rb +0 -4
  42. data/lib/os/bbos.rb +24 -16
  43. data/lib/os/bbsys.rb +60 -43
  44. data/lib/string/bbstring.rb +165 -66
  45. data/lib/string/cases.rb +37 -29
  46. data/lib/string/fuzzy_matcher.rb +48 -50
  47. data/lib/string/matching.rb +43 -30
  48. data/lib/string/pluralization.rb +156 -0
  49. data/lib/string/regexp.rb +45 -0
  50. data/lib/string/roman.rb +17 -30
  51. data/lib/system/bbsystem.rb +42 -0
  52. data/lib/time/bbtime.rb +79 -58
  53. data/lib/time/cron.rb +174 -132
  54. data/lib/time/task_timer.rb +86 -70
  55. metadata +27 -10
  56. data/lib/gem/bbgem.rb +0 -28
  57. data/lib/hash/hash_path.rb +0 -344
  58. data/lib/hash/hash_path_proc.rb +0 -256
  59. data/lib/hash/path_hash.rb +0 -81
  60. data/lib/object/attr.rb +0 -182
  61. data/lib/object/hooks.rb +0 -69
  62. data/lib/object/lazy_class.rb +0 -73
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -1,34 +1,34 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'bblib/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "bblib"
8
- spec.version = BBLib::VERSION
9
- spec.authors = ["Brandon Black"]
10
- spec.email = ["d2sm10@hotmail.com"]
11
-
12
- spec.summary = %q{A library containing many reusable, basic functions.}
13
- spec.description = %q{A library containing many reusable, basic functions.}
14
- spec.homepage = "https://github.com/bblack16/bblib-ruby"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
- # delete this section to allow pushing this gem to any host.
19
- # if spec.respond_to?(:metadata)
20
- # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
- # else
22
- # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
- # end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.end_with?('.gem') }
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 1.10"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency "rspec"
33
- spec.add_development_dependency "simplecov"
34
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bblib/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bblib"
8
+ spec.version = BBLib::VERSION
9
+ spec.authors = ["Brandon Black"]
10
+ spec.email = ["d2sm10@hotmail.com"]
11
+
12
+ spec.summary = %q{A library containing many reusable, basic functions.}
13
+ spec.description = %q{A library containing many reusable, basic functions.}
14
+ spec.homepage = "https://github.com/bblack16/bblib-ruby"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.end_with?('.gem') }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.10"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec"
33
+ spec.add_development_dependency "simplecov"
34
+ end
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "bblib"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "bblib"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup CHANGED
@@ -1,7 +1,7 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -1,50 +1,92 @@
1
-
1
+ # frozen_string_literal: true
2
2
  module BBLib
3
-
4
- # Takes two arrays (can be of different length) and interleaves them like [a[0], b[0], a[1], b[1]...]
5
- def self.interleave a, b
6
- ary = Array.new
7
- [a.size, b.size].max.times do |i|
8
- ary.push(a[i]) if i < a.size
9
- ary.push(b[i]) if i < b.size
3
+ # Takes two arrays (can be of different length) and interleaves
4
+ # them like [a[0], b[0], a[1], b[1]...]
5
+ def self.interleave(ary_a, ary_b)
6
+ ary = []
7
+ [ary_a.size, ary_b.size].max.times do |indx|
8
+ ary.push(ary_a[indx]) if indx < ary_a.size
9
+ ary.push(ary_b[indx]) if indx < ary_b.size
10
10
  end
11
11
  ary
12
12
  end
13
13
 
14
+ # Returns the element that occurs the most frequently in an array or
15
+ def self.most_frequent(*args)
16
+ totals = args.each_with_object(Hash.new(0)) { |elem, hash| hash[elem] += 1 }
17
+ max = totals.values.max
18
+ totals.keys.find { |key| totals[key] == max }
19
+ end
20
+
21
+ # Returns the most commonly occurring string in an arrray of params.
22
+ # Elements that are not strings are converted to their string representations.
23
+ #
24
+ # @param [TrueClass, FalseClass] case_insensitive Compare strings case isensitively.
25
+ def self.most_frequent_str(*args, case_insensitive: false)
26
+ most_frequent(*args.map { |arg| case_insensitive ? arg.to_s.downcase : arg.to_s })
27
+ end
28
+
29
+ # Takes an array and averages all of the floats and integers within it.
30
+ # Non numeric values are ignored.
31
+ def self.average(ary)
32
+ numbers = ary.select { |v| BBLib.is_a?(v, Integer, Float) }
33
+ numbers.inject(0) do |sum, x|
34
+ sum += x
35
+ end / numbers.size.to_f
36
+ end
14
37
  end
15
38
 
39
+ # Monkey Patches for the Array class
16
40
  class Array
41
+ # Splits all elements in an array using a list of delimiters.
42
+ def msplit(*delims)
43
+ map { |elem| elem.msplit(*delims) if elem.respond_to?(:msplit) }.flatten
44
+ end
45
+
46
+ alias multi_split msplit
47
+
48
+ # Converts all keys in nested hashes to symbols.
49
+ def keys_to_sym(clean: false)
50
+ map { |elem| elem.respond_to?(:keys_to_sym) ? elem.keys_to_sym(clean: clean) : elem }
51
+ end
17
52
 
18
- def msplit *delims, keep_empty: false
19
- self.map{ |i| i.msplit(delims, keep_empty:keep_empty)}.flatten
53
+ # Converts all keys in nested hashes to strings.
54
+ def keys_to_s
55
+ map { |v| v.respond_to?(:keys_to_s) ? v.keys_to_s : v }
20
56
  end
21
- alias_method :multi_split, :msplit
22
57
 
23
- def keys_to_sym clean: false
24
- self.map{ |v| v.is_a?(Hash) || v.is_a?(Array) ? v.keys_to_sym(clean:clean) : v }
58
+ # Takes two arrays (can be of different length) and interleaves
59
+ # them like [a[0], b[0], a[1], b[1]...]
60
+ def interleave(ary)
61
+ BBLib.interleave(self, ary)
25
62
  end
26
63
 
27
- def keys_to_s clean: false
28
- self.map{ |v| v.is_a?(Hash) || v.is_a?(Array) ? v.keys_to_s : v }
64
+ # Displays all elements between this hash and another hash that are different.
65
+ # @param [Array] ary The ary to compare elements to.
66
+ def diff(ary)
67
+ (self - ary) + (ary - self)
29
68
  end
30
69
 
31
- def to_xml level: 0, key:nil
32
- map do |v|
33
- nested = v.respond_to?(:to_xml)
34
- value = nested ? v.to_xml(level:level + 1, key:key) : v
35
- "\t" * level + "<#{key}>\n" +
36
- (nested ? '' : "\t"*(level+1)) +
37
- "#{value}\n" +
38
- "\t"*level + "</#{key}>\n"
39
- end.join
70
+ # Creates a tree hash wrapper for this array.
71
+ def to_tree_hash
72
+ TreeHash.new(self)
40
73
  end
41
74
 
42
- def interleave b
43
- BBLib.interleave self, b
75
+ # Conventient way to join an array into a comma seperated list with the last two elements
76
+ # seperated by a word like 'and' or 'or'.
77
+ # @param seperator [String] The term or phrase to seperate the last two elements by
78
+ # @param delimiter [String] The delimiter used in the join. This allows something other than ', ' to be used
79
+ # @param encapsulate [String] This will optionally encapsulate each element with a character or string. Useful to wrap all elements in quotes.
80
+ # @returns [String] By default returns a comma seperated list with the final elements seperated by an 'and'. Behavior can be overriden using the params.
81
+ def join_terms(seperator = :and, delimiter: ', ', encapsulate: nil)
82
+ elements = (encapsulate ? map { |element| element.to_s.encapsulate(encapsulate) } : self)
83
+ return elements.join(delimiter) if size <= 1
84
+ return elements.join(" #{seperator} ") if size == 2
85
+ [elements[0..-2].join(delimiter), elements.last].join(" #{seperator} ")
44
86
  end
45
87
 
46
- def diff b
47
- (self-b) + (b-self)
88
+ def hmap
89
+ return map unless block_given?
90
+ map { |v| yield(v) }.to_h
48
91
  end
49
-
50
92
  end
@@ -1,27 +1,27 @@
1
1
  require_relative 'bblib/version'
2
2
  require_relative 'opal/bbopal'
3
3
  require_relative 'object/bbobject'
4
- require_relative 'object/lazy_class'
4
+ require_relative 'hash/bbhash'
5
+ require_relative 'mixins/bbmixins'
6
+ require_relative 'class/effortless'
7
+ require_relative 'hash_path/hash_path'
5
8
  require_relative 'string/bbstring'
6
9
  require_relative 'file/bbfile'
7
10
  require_relative 'time/bbtime'
8
- require_relative 'hash/bbhash'
9
- require_relative 'gem/bbgem'
10
11
  require_relative 'number/bbnumber'
11
12
  require_relative 'array/bbarray'
13
+ require_relative 'system/bbsystem'
14
+ require_relative 'logging/bblogging'
15
+ require_relative 'error/abstract'
16
+ require_relative 'html/bbhtml'
12
17
 
13
- non_opal = ['os/bbos', 'gem/bbgem']
14
-
15
- unless BBLib::in_opal?
16
- non_opal.each{ |i| require_relative i }
17
- end
18
+ non_opal = ['os/bbos']
18
19
 
20
+ non_opal.each { |i| require_relative i } unless BBLib.in_opal?
19
21
 
20
22
  require 'fileutils'
21
- # require 'uri'
23
+ require 'time'
22
24
 
23
25
  module BBLib
24
-
25
- CONFIGS_PATH = 'config/'
26
-
26
+ CONFIGS_PATH = 'config/'.freeze
27
27
  end
@@ -1,3 +1,3 @@
1
- module BBLib
2
- VERSION = "0.3.0"
3
- end
1
+ module BBLib
2
+ VERSION = '0.4.1'.freeze
3
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module BBLib
3
+ module Effortless
4
+ def self.included(base)
5
+ base.extend(BBLib::Attrs)
6
+ base.extend(BBLib::Hooks)
7
+ base.singleton_class.extend(BBLib::Hooks)
8
+ base.extend(BBLib::FamilyTree) unless BBLib.in_opal?
9
+ base.extend(BBLib::Bridge)
10
+ base.send(:include, BBLib::Serializer)
11
+ base.send(:include, BBLib::SimpleInit)
12
+ base.send(:include, BBLib::Logger)
13
+ end
14
+
15
+ def _attrs
16
+ self.class._attrs
17
+ end
18
+ end
19
+
20
+ class EffortlessClass
21
+ include Effortless
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ class AbstractError < StandardError
2
+ # Enhance at some point
3
+ end
@@ -1,91 +1,132 @@
1
1
 
2
-
3
2
  module BBLib
4
-
5
3
  # Takes one or more strings and normalizes slashes to create a consistent file path
6
4
  # Useful when concating two strings that when you don't know if one or both will end or begin with a slash
7
- def self.pathify *strings
8
- start = strings.first.start_with?('/') || strings.first.start_with?('\\')
9
- (start ? '/' : '' ) + strings.map(&:to_s).msplit('/', '\\').map(&:strip).join('/')
5
+ def self.pathify(*strings)
6
+ (strings.first.start_with?('/', '\\') ? '/' : '') + strings.map(&:to_s).msplit('/', '\\').map(&:strip).join('/')
10
7
  end
11
8
 
12
9
  # Scan for files and directories. Can be set to be recursive and can also have filters applied.
13
- def self.scan_dir path = Dir.pwd, filter: nil, recursive: false
14
- if !filter.nil?
15
- filter = [filter].flatten.map{ |f| path.to_s + (recursive ? '/**/' : '/') + f.to_s }
16
- else
17
- filter = (path.to_s + (recursive ? '/**/*' : '/*')).gsub('//', '/')
18
- end
19
- Dir.glob(filter)
10
+ # @param [String] path The directory to scan files from.
11
+ # @param [String..., Regexp...] filters A list of filters to apply. Can be regular expressions or strings.
12
+ # Strings with a * are treated as regular expressions with a .*. If no filters are passed, all files/dirs are returned.
13
+ # @param [Boolean] recursive When true scan will recursively search directories
14
+ # @param [Boolean] files If true, paths to files matching the filter will be returned.
15
+ # @param [Boolean] dirs If true, paths to dirs matching the filter will be returned.
16
+ def self.scan_dir(path, *filters, recursive: false, files: true, dirs: true, &block)
17
+ return [] unless Dir.exist?(path)
18
+ filters = filters.map { |filter| filter.is_a?(Regexp) ? filter : /^#{Regexp.quote(filter).gsub('\\*', '.*')}$/ }
19
+ Dir.foreach(path).flat_map do |item|
20
+ next if item =~ /^\.{1,2}$/
21
+ item = "#{path}/#{item}".gsub('\\', '/')
22
+ if File.file?(item)
23
+ if files && (filters.empty? || filters.any? { |filter| item =~ filter })
24
+ block_given? ? yield(item) : item
25
+ end
26
+ elsif File.directory?(item)
27
+ recur = recursive ? scan_dir(item, *filters, recursive: recursive, files: files, dirs: dirs, &block) : []
28
+ if dirs && (filters.empty? || filters.any? { |filter| item =~ filter })
29
+ (block_given? ? yield(item) : [item] + recur)
30
+ elsif recursive
31
+ recur
32
+ end
33
+ end
34
+ end.compact
20
35
  end
21
36
 
22
- # Uses BBLib.scan_dir but returns only files. Mode can be used to return strings (:path) or File objects (:file)
23
- def self.scan_files path, filter: nil, recursive: false, mode: :path
24
- BBLib.scan_dir(path, filter: filter, recursive: recursive).map{ |f| File.file?(f) ? (mode == :file ? File.new(f) : f) : nil}.reject{ |r| r.nil? }
37
+ # Uses BBLib.scan_dir but returns only files
38
+ def self.scan_files(path, *filters, recursive: false, &block)
39
+ scan_dir(path, *filters, recursive: recursive, dirs: false, &block)
25
40
  end
26
41
 
27
- # Uses BBLib.scan_dir but returns only directories. Mode can be used to return strings (:path) or Dir objects (:dir)
28
- def self.scan_dirs path, filter: nil, recursive: false, mode: :path
29
- BBLib.scan_dir(path, filter: filter, recursive: recursive).map{ |f| File.directory?(f) ? (mode == :dir ? Dir.new(f) : f ) : nil}.reject{ |r| r.nil? }
42
+ # Uses BBLib.scan_dir but returns only directories.
43
+ def self.scan_dirs(path, *filters, recursive: false, &block)
44
+ scan_dir(path, *filters, recursive: recursive, files: false, &block)
30
45
  end
31
46
 
32
- # Shorthand method to write a string to disk. By default the path is created if it doesn't exist.
47
+ # Shorthand method to write a string to disk. By default the
48
+ # path is created if it doesn't exist.
33
49
  # Set mode to w to truncate file or leave at a to append.
34
- def self.string_to_file path, str, mkpath = true, mode: 'a'
35
- if !Dir.exists?(path) && mkpath
36
- FileUtils.mkpath File.dirname(path)
37
- end
38
- File.write(path, str.to_s, mode:mode)
50
+ def self.string_to_file(str, path, mkpath: true, mode: 'a')
51
+ FileUtils.mkpath(File.dirname(path)) if mkpath && !Dir.exist?(path)
52
+ File.write(path, str.to_s, mode: mode)
39
53
  end
40
54
 
41
55
  # A file size parser for strings. Extracts any known patterns for file sizes.
42
- def self.parse_file_size str, output: :byte
43
- output = FILE_SIZES.keys.find{ |f| f == output || FILE_SIZES[f][:exp].include?(output.to_s.downcase) } || :byte
56
+ def self.parse_file_size(str, output: :byte)
57
+ output = FILE_SIZES.keys.find { |fs| fs == output || FILE_SIZES[fs][:exp].include?(output.to_s.downcase) } || :byte
44
58
  bytes = 0.0
45
- FILE_SIZES.each do |k, v|
46
- v[:exp].each do |e|
47
- numbers = str.scan(/(?=\w|\D|^)\d*\.?\d+\s*#{e}s?(?=\W|\d|$)/i)
48
- numbers.each{ |n| bytes+= n.to_f * v[:mult] }
59
+ FILE_SIZES.each do |_k, v|
60
+ v[:exp].each do |exp|
61
+ str.scan(/(?=\w|\D|^)\d*\.?\d+\s*#{exp}s?(?=\W|\d|$)/i)
62
+ .each { |num| bytes += num.to_f * v[:mult] }
49
63
  end
50
64
  end
51
- return bytes / FILE_SIZES[output][:mult]
65
+ bytes / FILE_SIZES[output][:mult]
52
66
  end
53
67
 
54
- FILE_SIZES = {
55
- byte: { mult: 1, exp: ['b', 'byt', 'byte'] },
56
- kilobyte: { mult: 1024, exp: ['kb', 'kilo', 'k', 'kbyte', 'kilobyte'] },
57
- megabyte: { mult: 1048576, exp: ['mb', 'mega', 'm', 'mib', 'mbyte', 'megabyte'] },
58
- gigabyte: { mult: 1073741824, exp: ['gb', 'giga', 'g', 'gbyte', 'gigabyte'] },
59
- terabyte: { mult: 1099511627776, exp: ['tb', 'tera', 't', 'tbyte', 'terabyte'] },
60
- petabyte: { mult: 1125899906842624, exp: ['pb', 'peta', 'p', 'pbyte', 'petabyte'] },
61
- exabyte: { mult: 1152921504606846976, exp: ['eb', 'exa', 'e', 'ebyte', 'exabyte'] },
62
- zettabyte: { mult: 1180591620717411303424, exp: ['zb', 'zetta', 'z', 'zbyte', 'zettabyte'] },
63
- yottabyte: { mult: 1208925819614629174706176, exp: ['yb', 'yotta', 'y', 'ybyte', 'yottabyte'] }
64
- }
68
+ # Takes an integer or float and converts it into a string that represents
69
+ # a file size (e.g. "5 MB 156 kB")
70
+ # @param [Integer, Float] num The number of bytes to convert to a file size string.
71
+ # @param [Symbol] input Sets the value of the input. Default is byte.
72
+ # @param [Symbol] stop Sets a minimum file size to display.
73
+ # e.g. If stop is set to :megabyte, :kilobyte and below will be truncated.
74
+ # @param [Symbol] style The out style, Current options are :short and :long
75
+ def self.to_file_size(num, input: :byte, stop: :byte, style: :short)
76
+ return nil unless num.is_a?(Numeric)
77
+ return '0' if num.zero?
78
+ style = :short unless [:long, :short].include?(style)
79
+ expression = []
80
+ n = num * FILE_SIZES[input.to_sym][:mult]
81
+ done = false
82
+ FILE_SIZES.reverse.each do |k, v|
83
+ next if done
84
+ done = true if k == stop
85
+ div = n / v[:mult]
86
+ next unless div >= 1
87
+ val = (done ? div.round : div.floor)
88
+ expression << "#{val}#{v[:styles][style]}#{val > 1 && style != :short ? 's' : nil}"
89
+ n -= val.to_f * v[:mult]
90
+ end
91
+ expression.join(' ')
92
+ end
65
93
 
94
+ FILE_SIZES = {
95
+ byte: { mult: 1, exp: %w(b byt byte), styles: { short: 'B', long: ' byte' } },
96
+ kilobyte: { mult: 1024, exp: %w(kb kilo k kbyte kilobyte), styles: { short: 'kB', long: ' kilobyte' } },
97
+ megabyte: { mult: 1024**2, exp: %w(mb mega m mib mbyte megabyte), styles: { short: 'MB', long: ' megabyte' } },
98
+ gigabyte: { mult: 1024**3, exp: %w(gb giga g gbyte gigabyte), styles: { short: 'GB', long: ' gigabyte' } },
99
+ terabyte: { mult: 1024**4, exp: %w(tb tera t tbyte terabyte), styles: { short: 'TB', long: ' terabyte' } },
100
+ petabyte: { mult: 1024**5, exp: %w(pb peta p pbyte petabyte), styles: { short: 'PB', long: ' petabyte' } },
101
+ exabyte: { mult: 1024**6, exp: %w(eb exa e ebyte exabyte), styles: { short: 'EB', long: ' exabyte' } },
102
+ zettabyte: { mult: 1024**7, exp: %w(zb zetta z zbyte zettabyte), styles: { short: 'ZB', long: ' zettabyte' } },
103
+ yottabyte: { mult: 1024**8, exp: %w(yb yotta y ybyte yottabyte), styles: { short: 'YB', long: ' yottabyte' } }
104
+ }.freeze
66
105
  end
67
106
 
68
- class File
69
- def dirname
70
- File.dirname(self.path)
107
+ # Monkey patches for the Numeric class
108
+ class Numeric
109
+ def to_file_size(*args)
110
+ BBLib.to_file_size(self, *args)
71
111
  end
72
112
  end
73
113
 
114
+ # Monkey patches for the String class
74
115
  class String
75
- def to_file path, mkpath = true, mode: 'a'
76
- BBLib.string_to_file path, self, mkpath, mode:mode
116
+ def to_file(*args)
117
+ BBLib.string_to_file(self, *args)
77
118
  end
78
119
 
79
- def file_name with_extension = true
80
- self[(self.include?('/') ? self.rindex('/').to_i+1 : 0)..(with_extension ? -1 : self.rindex('.').to_i-1)]
120
+ def file_name(with_extension = true)
121
+ with_extension ? File.basename(self) : File.basename(self, File.extname(self))
81
122
  end
82
123
 
83
124
  def dirname
84
- self.scan(/.*(?=\/)/).first
125
+ File.dirname(self)
85
126
  end
86
127
 
87
- def parse_file_size output: :byte
88
- BBLib.parse_file_size(self, output:output)
128
+ def parse_file_size(*args)
129
+ BBLib.parse_file_size(self, *args)
89
130
  end
90
131
 
91
132
  def pathify