Skip to content

Commit

Permalink
Implemented text case converter
Browse files Browse the repository at this point in the history
  • Loading branch information
kapple19 committed Aug 6, 2024
1 parent 4cfbbf6 commit fcd040a
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/00_preliminary/01_general/01_auxiliary.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
export
export uniquesort!

const uniquesort! = unique! sort!

function isalphanumeric(char::AbstractChar)
'0' char '9' && return true
'a' char 'z' && return true
'A' char 'Z' && return true
return false
end

# TODO: Update when Unitful.jl is incorporated into package.
function (levels...)
10log10(
Expand Down
127 changes: 127 additions & 0 deletions src/00_preliminary/01_general/02_text_cases.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
export textcase
export titletext
export snaketext
export pascaltext
# public keeptokens

const textcaseseps = (
snake = '_',
space = ' ',
kebab = '-'
)

"""
Text conversions
"""
const keeptokens = [
"a"
"to"
"the"
"NSW"
] |> uniquesort!

function _textcase_casify_token(
newcase::AbstractString,
token::AbstractString;
keeptokens::AbstractVector{<:AbstractString} = keeptokens
)
token = lowercase(token)

idx = findall(token .== lowercase.(keeptokens))
length(idx) > 1 && error("Non-unique `keeptokens` specified.")
return if !isempty(idx)
keeptoken = keeptokens[idx |> only]
if newcase == "Pascal"
uppercase(keeptoken[1]) * (length(keeptoken) > 1 ? keeptoken[2:end] : "")
else
keeptoken
end
elseif isuppercase(newcase[1])
uppercase(token[1]) * (
length(token) > 1 ? token[2:end] : ""
)
else
token
end
end

function _textcase_verify_case(::Val{C}) where {C}
@assert C isa Symbol
return String(C)
end

function textcase(
v::V,
text::AbstractString;
keeptokens::AbstractVector{<:AbstractString} = keeptokens
) where {
V <: Union{
Val{:snake}, Val{:space}, Val{:kebab},
Val{:Snake}, Val{:Space}, Val{:Kebab},
Val{:Pascal}
}
}
tempsep = textcaseseps.snake

# Convert camel word separations to snake separations
camel_regexes = [
"[a-z][A-Z]"
"[0-9][A-Z]"
"[a-z][0-9]"
"[A-Z][0-9]"
] .|> Regex
for camel_regex = camel_regexes
text = replace(text,
[
text[idxs] => text[idxs[begin]] * tempsep * text[idxs[end]]
for idxs in findall(camel_regex, text, overlap = true)
]...
)
end

# Normalise existing separators
normaliser_regex = r"(_| |-)(_| |-)"
while contains(text, normaliser_regex)
text = replace(text, normaliser_regex => tempsep)
end
text = replace(text, "-" => tempsep)
text = replace(text, " " => tempsep)

# Remove non-alphanumeric symbols
is_alphanumeric_or_tempsep(char::AbstractChar) = (isalphanumeric(char) || char == tempsep)
text = filter(is_alphanumeric_or_tempsep, text)

# Tokenise
texts = split(text, tempsep)

newcase = _textcase_verify_case(v)
texts = _textcase_casify_token.(newcase, texts, keeptokens = keeptokens)

sep = if newcase == "Pascal"
""
else
textcaseseps[newcase |> lowercase |> Symbol]
end
return join(texts, sep)
end

function textcase(::Val{:camel}, text::AbstractString; keeptokens = keeptokens)
text = textcase(Val(:Pascal), text; keeptokens = keeptokens)
return lowercase(text[1]) * (length(text) > 1 ? text[2:end] : "")
end

function textcase(::Val{:pascal}, args...; kw...)
return textcase(Val(:Pascal), args...; kw...)
end

function textcase(::Val{:title}, args...; kw...)
return textcase(Val(:Space), args...; kw...)
end

titletext(text::AbstractString) = textcase(Val(:title), text)
snaketext(text::AbstractString) = textcase(Val(:snake), text)
pascaltext(text::AbstractString) = textcase(Val(:pascal), text)

prettytext(text::AbstractString) = titletext(text)
prettytext(text::Symbol) = text |> String |> prettytext
prettytext(::Val{T}) where {T} = T |> prettytext
12 changes: 5 additions & 7 deletions src/00_preliminary/02_modelling/01_model_naming.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ export ModelName

struct ModelName{m} end

ModelName(name::Symbol) = ModelName{name}()

# ModelName(m::AbstractString) = ModelName{m |> snakecase |> Symbol}()
# ModelName(m::Symbol) = ModelName(m |> String)
ModelName(m::AbstractString) = ModelName{m |> pascaltext |> Symbol}()
ModelName(m::Symbol) = ModelName(m |> String)

Symbol(::ModelName{M}) where {M} = M
String(model::ModelName) = model |> ModelName |> String
String(model::ModelName) = model |> Symbol |> String

# titletext(model::ModelName) = model |> String |> titletext
# snaketext(model::ModelName) = model |> String |> snaketext
titletext(model::ModelName) = model |> Symbol |> titletext
snaketext(model::ModelName) = model |> Symbol |> snaketext
6 changes: 5 additions & 1 deletion src/OceanSonar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export print_tree
using AbstractTrees: print_tree
import AbstractTrees: children

import Base: getproperty, show
import Base:
getproperty,
show,
String,
Symbol

using InteractiveUtils: subtypes

Expand Down
20 changes: 20 additions & 0 deletions test/00_preliminary/text_cases.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using OceanSonar
using Test

texts = (
Space = "Say 32 Big Goodbyes to 1 Cruel NSW 1st World",
space = "say 32 big goodbyes to 1 cruel NSW 1st world",
Snake = "Say_32_Big_Goodbyes_to_1_Cruel_NSW_1st_World",
snake = "say_32_big_goodbyes_to_1_cruel_NSW_1st_world",
Kebab = "Say-32-Big-Goodbyes-to-1-Cruel-NSW-1st-World",
kebab = "say-32-big-goodbyes-to-1-cruel-NSW-1st-world",
pascal = "Say32BigGoodbyesTo1CruelNSW1stWorld",
camel = "say32BigGoodbyesTo1CruelNSW1stWorld",
)

@testset "From $oldcase" for (oldcase, oldtext) in pairs(texts)
@testset "To $newcase" for (newcase, newtext) in pairs(texts)
context = textcase(newcase |> Symbol |> Val, oldtext)
@test context == newtext
end
end
6 changes: 6 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ using SafeTestsets
@safetestset "Docstrings" include("00_preliminary/01_code_quality/docstrings.jl")
end

name = "Preliminary Tests"
@time @testset "$name" begin
@info "Testing $name"
@safetestset "Text Cases" include("00_preliminary/text_cases.jl")
end

name = "Postliminary Tests"
@time @testset "$name" begin
@info "Testing $name"
Expand Down

0 comments on commit fcd040a

Please sign in to comment.