diff --git a/Project.toml b/Project.toml index 77d2f10..0a4926d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,17 +1,7 @@ name = "CualerID" uuid = "a4892dd5-cee5-4429-912e-1922c40e7f9b" -version = "0.0.1" authors = ["Thomas A. Christensen II <25492070+MillironX@users.noreply.github.com> and contributors"] - -[deps] -ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" -FilePathsBase = "48062228-2e41-5def-b9a4-89aafe57970f" -UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" +version = "0.0.1" [compat] -ArgParse = "1.2.0" -FilePathsBase = "0.9.24" -UUIDs = "1.11.0" julia = "1.12" - -[apps.cualer-id] diff --git a/README.md b/README.md index 8bacf03..8d16d10 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ # CualerID [![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/invenia/BlueStyle) -[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) diff --git a/src/Base30.jl b/src/Base30.jl deleted file mode 100644 index 345fcb7..0000000 --- a/src/Base30.jl +++ /dev/null @@ -1,106 +0,0 @@ -""" - BASE30_ALPHABET::Vector{UInt8} - -An alphabet designed for unambiguous representation of values in either upper- -or lower-case. The alphabet was formed by taking the numbers 0-9 and the Latin -alphabet and removing characters that are considered easy to confuse. Excluded -characters are - -- ``I`` => easily confused for lowercase ``L`` or the digit ``1`` -- ``L`` => easily confused for uppercase ``I`` or the digit ``1`` -- ``O`` => easily confused for the digit ``0`` -- ``Q`` => easily confused with uppercase ``O`` or lowercase ``g`` -- ``V`` => easily confused with ``U`` - -This array contains the ASCII index of the characters included in the base30 -alphabet starting with 0 at position `BASE30_ALPHABET[1]`. Use `String()` to -convert an array of these indices to a base30 string. -""" -const BASE30_ALPHABET = UInt8.([ - 48:57..., #0-9 - 65:72..., #A-H - 74:75..., #J-K - 77:78..., #M-N - 80, #P - 83:85..., #S-U - 87:90..., #W-Z -]) - -""" - rebase(v::Integer, base::Integer) - -Rebase `v` into the base system of `base`. `v` can be any integer type, and can -be represented in base 10 (decimal) or base 16 (hexadecimal) based on Julia's -treatment of that integer type. Returns a `Vector{UInt8}` containing the -**indices** of each digit in the rebased number. Since Julia is 1-indexed, this -means that `rebase(0, base)[1]` actually returns a value of `UInt8[1]`, since -the first index of a numeral system's alphabet is assumed to be its ``0`` value. - -# Examples - -```jldoctest -julia> rebase(0, 10) -1-element Vector{UInt8}: - 0x01 - -julia> # Two plus two is ten... IN BASE FOUR! I'M FINE! - -julia> rebase(2 + 2, 4) -2-element Vector{UInt8}: - 0x02 - 0x01 - -julia> base_4_alphabet = ['0', '1', '2', '3']; - -julia> String([base_4_alphabet[i] for i in rebase(2 + 2, 4)]) -"10" -``` - -!!! warning - - This method is not tested on negative integers and may produce incorrect - output when passed negative numbers -""" -function rebase(v::Integer, base::Integer) - remainder = UInt8((v % base) + 1) - quotient = div(v, base) - - if quotient == 0 - return [remainder] - else - return [rebase(quotient, base)..., remainder] - end #if - -end #function - -""" - base30encode(v::Integer) - base30encode(v::UUID) - -Creates a base30 representation of `v`. If `v` is a `UUID`, then the `UInt128` -value of the `UUID` is passed directly into the method. - -# Examples - -```jldoctest; filter = r"[0-9A-Z]{26}" -julia> base30encode(30) -"10" - -julia> using UUIDs - -julia> base30encode(UUIDs.uuid1()) -"7ZK00JECBDF2H7GNBXN59C6S9S" -``` - -!!! warning - - Just like [`rebase`](@ref), this method is not tested on negative integers - and may produce incorrect output when passed negative numbers -""" -function base30encode(v::Integer) - return String([BASE30_ALPHABET[i] for i in rebase(v, 30)]) -end #function - -function base30encode(v::UUID) - return base30encode(v.value) -end #function diff --git a/src/CualerID.jl b/src/CualerID.jl index 08879b2..95ceb36 100644 --- a/src/CualerID.jl +++ b/src/CualerID.jl @@ -1,174 +1,5 @@ module CualerID -using ArgParse: ArgParse, ArgParseSettings, parse_args, parse_item, @add_arg_table! -using FilePathsBase: AbstractPath, Path, exists, isfile -using UUIDs: UUID +# Write your package code here. -include("Base30.jl") -include("ResultCodeOption.jl") - -export ResultCode -export ResultCodeOption -export base30encode -export has_duplicate -export has_fixed -export has_not_fixable -export has_valid -export rebase - -function _create_arg_table() - s = ArgParseSettings(autofix_names = true) - - #! format: off - @add_arg_table! s begin - "create" - help = "Create CualerID sample ids or barcode labels" - action = :command - "fix" - help = "Compare a set of possibly invalid IDs against a correct set of IDs to identify errors in the IDs" - action = :command - "convert" - help = "Convert CualID sample ids to CualerID sample ids or vice-versa" - action = :command - end #add_arg_table - - @add_arg_table! s["create"] begin - "ids" - help = "Generate sample ids" - action = :command - "labels" - help = "Generate a pdf of barcodes (NOT YET IMPLEMENTED)" - action = :command - end #add_arg_table - - @add_arg_table! s["create"]["ids"] begin - "--length", "-l" - help = "The length of the printed sample ids" - arg_type = UInt64 - default = UInt64(5) - "--fail-threshold", "-f" - help = "NOT IMPLEMENTED: The rate at which similar ids will fail the process" - arg_type = Float64 - range_tester = x -> x >= 0 && x <= 1.0 - default = 0.99 - "number_of_ids" - help = "The number of sample ids to print" - arg_type = UInt64 - range_tester = x -> x >= 1 - required = true - end #add_arg_table - - @add_arg_table! s["fix"] begin - "--correct-ids" - help = "Path to the list of correct ids" - arg_type = AbstractPath - range_tester = x -> exists(x) && isfile(x) - required = true - "--show", "-s" - help = """ - Which types of fixes should be printed to output. Can be a - combination of D for duplicate, F for fixed, N for not fixable, - and V for valid. - """ - arg_type = ResultCodeOption - default = ResultCodeOption("DFN") - "--all", "-a" - help = "Show all ids regardless of fixed status" - action = :store_true - "ids_to_be_corrected" - help = "File containing CualerIDs that need correction" - arg_type = AbstractPath - range_tester = x -> exists(x) && isfile(x) - required = true - end #add_arg_table - - @add_arg_table! s["convert"] begin - "--length", "-l" - help = "The length of the printed sample ids" - arg_type = UInt64 - default = UInt64(5) - "--fail-threshold", "-f" - help = "NOT IMPLEMENTED: The rate at which similar ids will fail the process" - arg_type = Float64 - range_tester = x -> x >= 0 && x <= 1.0 - default = 0.99 - "--to-cual-id" - help = "Convert from CualerID to CualID" - action = :store_true - "ids_to_be_converted" - help = "TSV file containing CualIDs or CualerIDs to be converted" - arg_type = AbstractPath - range_tester = x -> exists(x) && isfile(x) - required = true - end #@add_arg_table! - - #! format: on - - return s - -end #function - -const ARG_PARSE_TABLE = _create_arg_table() - -function _create(parsed_args::Dict{Symbol,Any}) - if parsed_args[:_COMMAND_] == :ids - _create_ids(parsed_args[:ids]) - elseif parsed_args[:_COMMAND_] == :labels - _create_labels(parsed_args[:labels]) - end #if - - return 0 -end #function - -function _create_ids(parsed_args::Dict{Symbol,Any}) - println("COMMAND:\tcreate ids") - for (key, val) in parsed_args - println("\t$key:\t$val") - end #function - - return 0 -end #function - -function _create_labels(parsed_args::Dict{Symbol,Any}) - println("COMMAND:\tcreate labels") - for (key, val) in parsed_args - println("\t$key:\t$val") - end #function - - return 0 -end #function - -function _fix(parsed_args::Dict{Symbol,Any}) - println("COMMAND:\tfix") - for (key, val) in parsed_args - println("\t$key:\t$val") - end #function - - return 0 -end #function - -function _convert(parsed_args::Dict{Symbol,Any}) - println("COMMAND:\tconvert") - for (key, val) in parsed_args - println("\t$key:\t$val") - end #function - - return 0 -end #function - - -function (@main)() - parsed_args = parse_args(ARG_PARSE_TABLE; as_symbols = true) - - if parsed_args[:_COMMAND_] == :create - _create(parsed_args[:create]) - elseif parsed_args[:_COMMAND_] == :fix - _fix(parsed_args[:fix]) - elseif parsed_args[:_COMMAND_] == :convert - _convert(parsed_args[:convert]) - end #if - - return 0 -end #function - -end #module +end diff --git a/src/ResultCodeOption.jl b/src/ResultCodeOption.jl deleted file mode 100644 index b435609..0000000 --- a/src/ResultCodeOption.jl +++ /dev/null @@ -1,120 +0,0 @@ -""" - ResultCode::UInt8 - -Encodes a result of attempting to correct a CualerID - -The valid codes are - -- **D**: duplicate -- **F**: fixed -- **N**: not fixable -- **V**: valid (no need for correction) -""" -@enum ResultCode::UInt8 begin - D = UInt8(1) - F = UInt8(2) - N = UInt8(4) - V = UInt8(8) -end #enum - -""" - ResultCodeOption - -Encodes potential corrected id codes. - -The valid codes are - -- **D**: duplicate -- **F**: fixed -- **N**: not fixable -- **V**: valid (no need for correction) - -The codes are implemented exactly as from cual-id and in that order - -# Constructors - - ResultCodeOption(str::AbstractString) - -Create a `ResultCodeOption` based on a the character codes contained within -`str`. `str` is case insensitive, may contain an arbitrary number of valid codes -(as specified above), and may contain duplicates. A `ResultCodeOption` cannot be -constructed from a combination of strings and bitmasks/integers. - -# Extended help - -The struct stores values as a bitmask - -| Bit (Int) | Bit (UInt) | Description | -| ---------:| ----------:| --------------- | -| 1 | 0x01 | D - duplicate | -| 2 | 0x02 | F - fixed | -| 4 | 0x04 | N - not fixable | -| 8 | 0x08 | V - valid | - -""" -struct ResultCodeOption - val::UInt8 -end #struct - -ResultCodeOption(str::AbstractString) = Base.parse(ResultCodeOption, str) - -function Base.parse(::Type{ResultCodeOption}, str::AbstractString) - upper_str = uppercase(str) - - # Throw if there are any invalid codes - occursin(r"[^DFNV]", upper_str) && - throw(DomainError("Valid `ResultCodeOption` must contain D, F, N, or V only")) - - # Throw if there are no valid codes - occursin(r"[DFNV]", upper_str) || throw( - DomainError("Valid `ResultCodeOption` must contain at least one of D, F, N, or V"), - ) - - result_code = sum( - c -> occursin(string(Symbol(c)), upper_str) ? UInt8(c) : UInt8(0), - instances(ResultCode), - ) - - return ResultCodeOption(result_code) - -end #function - -function Base.show(io::IO, r::ResultCodeOption) - print_code = "" - - print(io, summary(r), " (") - foreach( - c -> r.val & UInt8(c) != 0 && print(io, string(Symbol(c))), - instances(ResultCode), - ) - print(io, ")") -end #function - -""" - has_duplicate(r::ResultCodeOption) - -Determines if `r` contains a duplicate result ([`ResultCode`](@ref) D) -""" -has_duplicate(r::ResultCodeOption) = r.val & UInt8(D) != 0 - -""" - has_fixed(r::ResultCodeOption) - -Determines if `r` contains a fixed result ([`ResultCode`](@ref) F) -""" -has_fixed(r::ResultCodeOption) = r.val & UInt8(F) != 0 - -""" - has_not_fixable(r::ResultCodeOption) - -Determines if `r` contains a not fixable result ([`ResultCode`](@ref) N) -""" -has_not_fixable(r::ResultCodeOption) = r.val & UInt8(N) != 0 - -""" - has_valid(r::ResultCodeOption) - -Determines if `r` contains a valid (not corrected) result -([`ResultCode`](@ref) V) -""" -has_valid(r::ResultCodeOption) = r.val & UInt8(V) != 0 diff --git a/test/Aqua.jl b/test/Aqua.jl deleted file mode 100644 index 73d1555..0000000 --- a/test/Aqua.jl +++ /dev/null @@ -1,5 +0,0 @@ -using Aqua - -@testset "Aqua" begin - Aqua.test_all(CualerID) -end #@testset diff --git a/test/Base30.jl b/test/Base30.jl deleted file mode 100644 index 6de61d3..0000000 --- a/test/Base30.jl +++ /dev/null @@ -1,21 +0,0 @@ -using CualerID: base30encode, rebase - -@testset "rebase" begin - @test rebase(0, 10) == UInt8[1] - @test rebase(0, 2) == UInt8[1] - @test rebase(0, 32) == UInt8[1] - - @test rebase(10, 10) == UInt8[2, 1] - @test rebase(2, 2) == UInt8[2, 1] - @test rebase(32, 32) == UInt8[2, 1] - - @test rebase(11, 10) == UInt8[2, 2] - @test rebase(3, 2) == UInt8[2, 2] - @test rebase(33, 32) == UInt8[2, 2] -end #@testset - -@testset "base30encode" begin - @test base30encode(0) == "0" - @test base30encode(1) == "1" - @test base30encode(30) == "10" -end diff --git a/test/Doctests.jl b/test/Doctests.jl deleted file mode 100644 index 414b707..0000000 --- a/test/Doctests.jl +++ /dev/null @@ -1,6 +0,0 @@ -using Documenter - -@testset "doctests" begin - DocMeta.setdocmeta!(CualerID, :DocTestSetup, :(using CualerID); recursive = true) - doctest(CualerID) -end diff --git a/test/Project.toml b/test/Project.toml index abb5d2c..0c36332 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,10 +1,2 @@ [deps] -Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[compat] -Aqua = "0.8" -Documenter = "1.16" -UUIDs = "1.11.0" diff --git a/test/ResultCodeOption.jl b/test/ResultCodeOption.jl deleted file mode 100644 index 1cb00ba..0000000 --- a/test/ResultCodeOption.jl +++ /dev/null @@ -1,8 +0,0 @@ -@testset "ResultCode" begin - @test_throws DomainError ResultCodeOption("A") - @test_throws DomainError ResultCodeOption("") - @test has_duplicate(ResultCodeOption("D")) - @test has_fixed(ResultCodeOption("F")) - @test has_not_fixable(ResultCodeOption("N")) - @test has_valid(ResultCodeOption("V")) -end #@testset diff --git a/test/runtests.jl b/test/runtests.jl index a9a4b00..43f586c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,6 @@ using CualerID using Test -include("Doctests.jl") -include("Aqua.jl") -include("Base30.jl") -include("ResultCodeOption.jl") +@testset "CualerID.jl" begin + # Write your tests here. +end