[feature] Expand built-in utilities for Essentials (#166)

* Refactor hash and add small string utility
* Add utilities for `Color` object
* Add `.findDirectory` to `PluginManager`
* Add extra file and directory utilities
* Add `CallbackWrapper` utility
* Fix hash `deep_merge`
* Refactor hash `deep_merge` to simplify
* Fix hash merging
* Fix ruby utilities
This commit is contained in:
Luka S.J
2022-03-01 00:32:25 +01:00
committed by GitHub
parent fe6b87c075
commit fe159419f7
3 changed files with 177 additions and 15 deletions

View File

@@ -43,6 +43,42 @@ class Dir
return ret
end
#-----------------------------------------------------------------------------
# Creates all the required directories for filename path
#-----------------------------------------------------------------------------
def self.create(path)
path.gsub!("\\", "/") # Windows compatibility
# get path tree
dirs = path.split("/")
full = ""
for dir in dirs
full += dir + "/"
# creates directories
self.mkdir(full) if !self.safe?(full)
end
end
#-----------------------------------------------------------------------------
# Generates entire folder tree from a certain directory
#-----------------------------------------------------------------------------
def self.all_dirs(dir)
# sets variables for starting
dirs = []
for file in self.get(dir, "*", true)
# engages in recursion to read the entire folder tree
dirs += self.all_dirs(file) if self.safe?(file)
end
# returns all found directories
return dirs.length > 0 ? (dirs + [dir]) : [dir]
end
#-----------------------------------------------------------------------------
# Deletes all the files in a directory and all the sub directories (allows for non-empty dirs)
#-----------------------------------------------------------------------------
def self.delete_all(dir)
# delete all files in dir
self.all(dir).each { |f| File.delete(f) }
# delete all dirs in dir
self.all_dirs(dir).each { |f| Dir.delete(f) }
end
#-----------------------------------------------------------------------------
end
@@ -60,6 +96,14 @@ class File
return ret
end
#-----------------------------------------------------------------------------
# Checks for existing .rxdata file
#-----------------------------------------------------------------------------
def self.safeData?(file)
ret = false
ret = (load_data(file) ? true : false) rescue false
return ret
end
#-----------------------------------------------------------------------------
end

View File

@@ -50,6 +50,10 @@ class String
end
return new_string
end
def numeric?
return !self[/^[+-]?([0-9]+)(?:\.[0-9]+)?$/].nil?
end
end
#===============================================================================
@@ -94,26 +98,19 @@ end
#===============================================================================
class Hash
def deep_merge(hash)
h = self.clone
# failsafe
return h if !hash.is_a?(Hash)
hash.each_key do |key|
if self[key].is_a?(Hash)
h.deep_merge!(hash[key])
else
h = hash[key]
end
end
return h
merged_hash = self.clone
merged_hash.deep_merge!(hash) if hash.is_a?(Hash)
return merged_hash
end
def deep_merge!(hash)
return if !hash.is_a?(Hash)
hash.each_key do |key|
# failsafe
return unless hash.is_a?(Hash)
hash.each do |key, val|
if self[key].is_a?(Hash)
self[key].deep_merge!(hash[key])
self[key].deep_merge!(val)
else
self[key] = hash[key]
self[key] = val
end
end
end
@@ -162,6 +159,112 @@ class File
end
end
#===============================================================================
# class Color
#===============================================================================
class Color
# alias for old constructor
alias init_original initialize unless self.private_method_defined?(:init_original)
# New constructor, accepts RGB values as well as a hex number or string value.
def initialize(*args)
pbPrintException("Wrong number of arguments! At least 1 is needed!") if args.length < 1
if args.length == 1
if args.first.is_a?(Fixnum)
hex = args.first.to_s(16)
elsif args.first.is_a?(String)
try_rgb_format = args.first.split(",")
return init_original(*try_rgb_format.map(&:to_i)) if try_rgb_format.length.between?(3, 4)
hex = args.first.delete("#")
end
pbPrintException("Wrong type of argument given!") if !hex
r = hex[0...2].to_i(16)
g = hex[2...4].to_i(16)
b = hex[4...6].to_i(16)
elsif args.length == 3
r, g, b = *args
end
return init_original(r, g, b) if r && g && b
return init_original(*args)
end
# Returns this color as a hex string like "#RRGGBB".
def to_hex
r = sprintf("%02X", self.red)
g = sprintf("%02X", self.green)
b = sprintf("%02X", self.blue)
return ("#" + r + g + b).upcase
end
# Returns this color as a 24-bit color integer.
def to_i
return self.to_hex.delete("#").to_i(16)
end
# Converts the provided hex string/24-bit integer to RGB values.
def self.hex_to_rgb(hex)
hex = hex.delete("#") if hex.is_a?(String)
hex = hex.to_s(16) if hex.is_a?(Numeric)
r = hex[0...2].to_i(16)
g = hex[2...4].to_i(16)
b = hex[4...6].to_i(16)
return r, g, b
end
# Parses the input as a Color and returns a Color object made from it.
def self.parse(color)
case color
when Color
return color
when String, Numeric
return Color.new(color)
end
# returns nothing if wrong input
return nil
end
# Returns color object for some commonly used colors
def self.red; return Color.new(255, 0, 0); end
def self.green; return Color.new( 0, 255, 0); end
def self.blue; return Color.new( 0, 0, 255); end
def self.black; return Color.new( 0, 0, 0); end
def self.white; return Color.new(255, 255, 255); end
def self.yellow; return Color.new(255, 255, 0); end
def self.magenta; return Color.new(255, 0, 255); end
def self.teal; return Color.new( 0, 255, 255); end
def self.orange; return Color.new(255, 155, 0); end
def self.purple; return Color.new(155, 0, 255); end
def self.brown; return Color.new(112, 72, 32); end
end
#===============================================================================
# Wrap code blocks in a class which passes data accessible as instance variables
# within the code block.
#
# wrapper = CallbackWrapper.new { puts @test }
# wrapper.set(test: "Hi")
# wrapper.execute #=> "Hi"
#===============================================================================
class CallbackWrapper
@params = {}
def initialize(&block)
@code_block = block
end
def execute(given_block = nil, *args)
execute_block = given_block || @code_block
@params.each do |key, value|
args.instance_variable_set("@#{key.to_s}", value)
end
args.instance_eval(&execute_block)
end
def set(params = {})
@params = params
end
end
#===============================================================================
# Kernel methods
#===============================================================================

View File

@@ -727,4 +727,19 @@ module PluginManager
end
end
#-----------------------------------------------------------------------------
# Get plugin dir from name based on meta entries
#-----------------------------------------------------------------------------
def self.findDirectory(name)
# go through the plugins folder
Dir.get("Plugins").each do |dir|
next if !Dir.safe?(dir)
next if !safeExists?(dir + "/meta.txt")
# read meta
meta = self.readMeta(dir, "meta.txt")
return dir if meta[:name] == name
end
# return nil if no plugin dir found
return nil
end
#-----------------------------------------------------------------------------
end