From 8f12c29a788655fd1ac9f0fd875f30ae4bd7649a Mon Sep 17 00:00:00 2001 From: narawat Date: Sat, 27 Jun 2026 16:53:55 +0700 Subject: [PATCH] update --- src/interface.jl | 100 ++++++++--------------- src/util.jl | 202 ++++++++++++++++++++++++++--------------------- 2 files changed, 149 insertions(+), 153 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 48fb0c3..029095c 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -150,11 +150,8 @@ end # ---------------------------------------------- 100 --------------------------------------------- # -""" read_textfile_by_index(folder_path::String, read_file_number::Integer=1) - -# What it does - - Reads the x-th text file from a folder, where files are listed by the OS - without explicit sorting. Returns the file number, filename, and content. +""" Reads the x-th text file from a folder, where files are listed by the OS +without explicit sorting. Returns the file number, filename, and content. # Arguments - `folder_path::String` @@ -207,14 +204,12 @@ end """ Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary. - -# What it does - - Walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`, - `Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where - every dictionary-like node is a plain `Dict` and every array-like node is a - `Vector{Any}`. Scalar values (numbers, strings, booleans, `nothing`, etc.) - are returned unchanged. - - Does **not** mutate the input; it always allocates new containers. +The function walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`, +`Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where +every dictionary-like node is a plain `Dict` and every array-like node is a +`Vector{Any}`. Scalar values (numbers, strings, booleans, `nothing`, etc.) +are returned unchanged. +Does **not** mutate the input; it always allocates new containers. # Arguments - `x` @@ -299,14 +294,12 @@ end # ---------------------------------------------- 100 --------------------------------------------- # """ Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary. - -# What it does - - Walks any nested structure composed of AbstractDict (e.g., JSON.Object, - Dict, OrderedDict) and AbstractArray and produces a new tree where - every dictionary-like node is an OrderedDict{Any,Any} and every array-like - node is a Vector{Any}. Scalar values (numbers, strings, booleans, - nothing, etc.) are returned unchanged. - - Does **not** mutate the input; it always allocates new containers. +The function walks any nested structure composed of AbstractDict (e.g., JSON.Object, +Dict, OrderedDict) and AbstractArray and produces a new tree where +every dictionary-like node is an OrderedDict{Any,Any} and every array-like +node is a Vector{Any}. Scalar values (numbers, strings, booleans, +nothing, etc.) are returned unchanged. +Does **not** mutate the input; it always allocates new containers. # Arguments - `x` @@ -474,10 +467,8 @@ function randomChoiceOnTarget(target::AbstractVector, choiceList::AbstractVector end """ Compute the linearly weighted average of an array. - -# What it does - - Assigns weights proportional to position indices (1, 2, 3, ...) to array - elements and returns the weighted average. +The function assigns weights proportional to position indices (1, 2, 3, ...) to array +elements and returns the weighted average. # Arguments - `a::Array` @@ -512,10 +503,8 @@ end """ Convert a variable's value (String) into a Symbol. - -# What it does - - Takes a variable containing a String value and converts it to a Symbol - using Julia's expression interpolation mechanism. +The function takes a variable containing a String value and converts it to a Symbol +using Julia's expression interpolation mechanism. # Arguments - `variable` @@ -585,11 +574,9 @@ end """ Draw unique elements from a list without replacement. - -# What it does - - Randomly selects a specified number of distinct elements from a collection, - optionally excluding certain elements from consideration. Uses in-place - shuffling for efficiency. +The function randomly selects a specified number of distinct elements from a collection, +optionally excluding certain elements from consideration. Uses in-place +shuffling for efficiency. # Arguments - `drawOptions::Array` @@ -789,10 +776,7 @@ function selectRange(d::Dict{Symbol, <:AbstractVector}, range) return newDict end -""" assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign) - -# What it does - - Recursively traverses a nested dictionary structure using a vector of keys +""" Recursively traverses a nested dictionary structure using a vector of keys and assigns a value to the final key. Creates intermediate dictionaries if they don't exist. @@ -852,11 +836,8 @@ function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign) end end -""" iTime(h::Integer, m::Integer) - -# What it does - - Converts hour (0-23) and minute (0-59) into a Julia `Time` object using - 12-hour format with AM/PM indicator. +""" Converts hour (0-23) and minute (0-59) into a Julia `Time` object using +12-hour format with AM/PM indicator. # Arguments - `h::Integer` @@ -931,12 +912,9 @@ function limitvalue(v::Number, lowerbound::Pair, upperbound::Pair) end -""" cartesianAssign!(a, b) - -# What it does - - Assigns elements from matrix `b` to matrix `a` using the Cartesian indices - of `b`. Elements are copied in the order they appear when iterating over `b`, - and placed into `a` at the corresponding Cartesian positions of `b`. +""" Assigns elements from matrix `b` to matrix `a` using the Cartesian indices +of `b`. Elements are copied in the order they appear when iterating over `b`, +and placed into `a` at the corresponding Cartesian positions of `b`. # Arguments - `a` @@ -1350,11 +1328,8 @@ function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char; end -""" mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}}, addkeys::Union{Vector{String}, Vector{Symbol}}, value) - -# What it does - - Recursively creates nested dictionary paths if they do not exist and assigns - a value to the final key. Similar to `mkpath()` but for dictionaries. +""" Recursively creates nested dictionary paths if they do not exist and assigns +a value to the final key. Similar to `mkpath()` but for dictionaries. # Arguments - `dict::Union{Dict{Symbol, Any}, Dict{String, Any}}` @@ -1410,11 +1385,8 @@ function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}}, end -""" getDictPath(dict::Dict, keys::Vector) - -# What it does - - Retrieves a value from a nested dictionary by traversing a vector of keys. - Creates intermediate dictionaries if they don't exist. +""" Retrieves a value from a nested dictionary by traversing a vector of keys. +Creates intermediate dictionaries if they don't exist. # Arguments - `dict::Dict` @@ -1652,12 +1624,10 @@ function textToDict(text::String, detectKeywords::Vector{String}; end """ Recursively convert dictionary into an HTML string representation. - -# What it does - - Walks a nested `AbstractDict` structure and produces a well-formed HTML string - where each dictionary key becomes an HTML tag. Nested dictionaries become - nested tags, and scalar values (numbers, strings, etc.) become the text - content of leaf tags. +The function walks a nested `AbstractDict` structure and produces a well-formed HTML string +where each dictionary key becomes an HTML tag. Nested dictionaries become +nested tags, and scalar values (numbers, strings, etc.) become the text +content of leaf tags. # Arguments - `d::AbstractDict` diff --git a/src/util.jl b/src/util.jl index 3ad8496..2f3da23 100644 --- a/src/util.jl +++ b/src/util.jl @@ -13,31 +13,34 @@ using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames # ---------------------------------------------- 100 --------------------------------------------- # -""" Compute time different between start time and stop time in a given unit. - Unit can be "milliseconds", "seconds", "minutes", "hours". +""" Computes the time difference between two `DateTime` values and returns the +result in a specified unit: milliseconds, seconds, minutes, or hours. # Arguments - - `starttime::DateTime` - start time - - `stoptime::DateTime` - stop time - - `unit::String` - unit of time difference +- `starttime::DateTime` + The starting `DateTime` value. +- `stoptime::DateTime` + The ending `DateTime` value. +- `unit::String` + The unit for the result. Must be one of: `"milliseconds"`, `"seconds"`, + `"minutes"`, `"hours"`. # Return - - time difference in given unit +- `Integer`: The time difference converted to the specified unit. -# Example +# Notes +- The function computes `stoptime - starttime` and converts the result to the + requested unit using integer division. +- Errors with `ArgumentError` if an invalid unit is specified. + +# Examples ```jldoctest -julia> using Revise julia> using GeneralUtils, Dates julia> a = Dates.now() -julia> b = a + Dates.Day(5) # add 5 days -julia> GeneralUtils.timedifference(a, b, "hours") +julia> b = a + Dates.Day(5) +julia> timedifference(a, b, "hours") 120 ``` - -# Signature """ function timedifference(starttime::DateTime, stoptime::DateTime, unit::String)::Integer diff = stoptime - starttime @@ -184,21 +187,27 @@ end -""" Get uuid4 with snake case - -# Return - - `uuid4::String` - uuid4 with snake case +""" Generates a UUID4 (version 4) identifier and converts it to snake case by +replacing hyphens with underscores. -# Example +# Arguments +- This function takes no arguments. + +# Return +- `String`: A UUID4 string with underscores instead of hyphens (e.g., + `"0f6e4f_568c_4df4_8c79_1d7a58072f4a"`). + +# Notes +- Uses the `uuid4()` function from the UUIDs standard library to generate a + random UUID. +- The underscore character replaces all hyphens in the UUID string. + +# Examples ```jldoctest -julia> using Revise julia> using GeneralUtils -julia> GeneralUtils.uuid4snakecase() +julia> uuid4snakecase() "0f6e4f_568c_4df4_8c79_1d7a58072f4a" ``` - -# Signature """ function uuid4snakecase()::String _id = string(uuid4()) @@ -207,32 +216,37 @@ function uuid4snakecase()::String end -""" Replace a dictionary key with the new key +""" Replaces keys in a dictionary according to a mapping, returning a new +dictionary with updated keys while preserving the original values. # Arguments - - `d::Dict` - The input dictionary that you want to modify - - `replacementMap::Dict` - A dictionary that maps old keys to new keys +- `d::Dict` + The input dictionary to modify. +- `replacementMap::Dict` + A dictionary mapping old keys to new keys. Keys not present in this map are + left unchanged. # Return - - `newDict::Dict` - new dictionary with the replaced keys +- `Dict`: A new dictionary with replaced keys. Values are preserved from the + original dictionary. -# Example +# Notes +- The function creates a new dictionary rather than modifying the input in + place. +- Keys not found in `replacementMap` are copied to the result with their + original keys unchanged. + +# Examples ```jldoctest -julia> using Revise julia> using GeneralUtils julia> d = Dict(:a => 1, :b => 2, :c => 3) julia> replacement_map = Dict(:a => :x, :b => :y) -julia> new_dict = GeneralUtils.replaceDictKeys(d, replacement_map) +julia> replaceDictKeys(d, replacement_map) Dict{Any, Any} with 3 entries: :y => 2 :c => 3 :x => 1 ``` - -# Signature """ function replaceDictKeys(d::Dict, replacementMap::Dict)::Dict newDict = Dict() @@ -294,36 +308,43 @@ end -""" Execute a function with timer. +""" Executes a function with a timeout mechanism. If the function does not +complete within the specified time, it is interrupted and a timeout message +is returned. # Arguments - - `f::Function` - a function to run - - `timeoutwindow::Integer`` - timeout in seconds +- `f::Function` + The function to execute. +- `timeoutwindow::Integer` + The timeout duration in seconds. -# Keyword Argument - - `fargs` - arguments for the function - - `timeoutmsg::String` - time out message +# Keyword Arguments +- `fargs` + Arguments to pass to the function `f`. If `nothing`, the function is called + without arguments. +- `timeoutmsg::String` + The message to return if the function times out. Defaults to `"task timed out"`. # Return - - task result otherwise timeout message +- The result of the function if it completes within the timeout, otherwise the + `timeoutmsg` string. -# Example - ```jldoctest +# Notes +- Uses Julia's `@task`, `schedule`, and `Timer` to implement non-blocking + execution with interruption via `Base.throwto`. +- Errors with `InterruptException` if the function exceeds the timeout. + +# Examples +```jldoctest julia> function testfunc(x) - sleep(x) - return "task done" - end + sleep(x) + return "task done" + end julia> result = timeout(testfunc, 10; fargs=20) "task timed out" julia> result = timeout(testfunc, 20; fargs=10) "task done" ``` - -# Signature """ function timeout(f::Function, timeoutwindow::Integer; fargs=nothing, timeoutmsg="task timed out") tsk = @task f(fargs) @@ -340,23 +361,26 @@ end -""" Convert a dataframe into CSV. +""" Converts a DataFrame to a CSV string representation using the CSV.jl package. # Arguments - - `df::DataFrame` - A connection object to Postgres database - -# Return - - `result::String` +- `df::DataFrame` + The DataFrame to convert to CSV format. -# Example +# Return +- `String`: The DataFrame contents as a CSV-formatted string. + +# Notes +- Uses `CSV.write` with an `IOBuffer` to capture the output as a string. +- The returned string contains the full CSV representation including headers. + +# Examples ```jldoctest julia> using DataFrames, GeneralUtils julia> df = DataFrame(A=1:3, B=5:7, fixed=1) -julia> result = GeneralUtils.dataframeToCSV(df) +julia> dataframeToCSV(df) +"1,5,1\n2,6,1\n3,7,1\n" ``` - -# Signature """ function dataframeToCSV(df::DataFrame) # Create an IOBuffer to capture the output @@ -426,8 +450,6 @@ end 3 => [Dict("a"=>7), Dict("a"=>8), Dict("a"=>9)] 4 => [Dict("a"=>10)] ``` - -# Signature """ function disintegrate_vectorDict(data::Vector, partsize::Integer ) @@ -473,8 +495,6 @@ end julia> getDataFrameValue(df[1, :], :name) "Alice" ``` - -# Signature """ getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key) @@ -543,8 +563,6 @@ end julia> dfToString(df) "1) name: Alice, age: 25\n2) name: Bob, age: 30" ``` - -# Signature """ function dfToString(df::DataFrame) dfstr = "" @@ -583,8 +601,6 @@ end "{\"name\":\"Alice\",\"age\":25}" "{\"name\":\"Bob\",\"age\":30}" ``` - -# Signature """ function dataframe_to_json_list(df::DataFrame)::Vector{String} json_list = [] @@ -618,8 +634,6 @@ end julia> dict_to_string(od) "1) name: Alice, 2) age: 25" ``` - -# Signature """ function dictToString(od::T) where {T<:AbstractDict} items = [] @@ -733,27 +747,39 @@ end -""" - remove_french_accents(text::String) -> String +""" Remove French accents from the given text. -Remove French accents from the given text. +The function replaces accented French characters with their non-accented +counterparts using a dictionary mapping. Supported accented characters +include: à, â, ä, á, é, è, ê, ë, î, ï, í, ñ, ô, ö, ò, ó, ù, û, ü, ÿ, ç, +and their uppercase variants. The apostrophe character `’` is removed +completely. # Arguments -- `text::String` The input string containing French accents. +- `text::AbstractString` + The input string containing French accented characters. -# Returns -- `String` The input string with all French accents removed. +# Return +- `AbstractString`: A new string with all French accents replaced by their + non-accented equivalents. + +# Notes +- The function creates a character list and replaces each accented character + according to an internal dictionary mapping. +- Does **not** mutate the input; it allocates a new string. # Examples - ```jldoctest - julia> remove_french_accents("Café") - "Cafe" +```jldoctest +julia> using GeneralUtils +julia> remove_french_accents("Café") +"Cafe" - julia> remove_french_accents("L'été est beau.") - "L'ete est beau." - ``` +julia> remove_french_accents("L'été est beau.") +"L'ete est beau." -# Signature +julia> remove_french_accents("Noël, naïve, François") +"Noel, naive, Francois" +``` """ function remove_french_accents(text::AbstractString)::AbstractString textcharlist = [i for i in text]