diff --git a/src/UAParser.jl b/src/UAParser.jl index f01a5b7..35d21d7 100644 --- a/src/UAParser.jl +++ b/src/UAParser.jl @@ -10,7 +10,7 @@ export parsedevice, parseuseragent, parseos, DeviceResult, OSResult, UAResult, D ## ############################################################################## -using YAML, DataFrames, Nulls +using YAML, DataFrames, Missings import DataFrames.DataFrame, DataFrames.names! ############################################################################## @@ -28,46 +28,46 @@ const REGEXES = YAML.load(open(joinpath(dirname(@__FILE__), "..", "regexes.yaml" ############################################################################## # helper function used by constructors -_check_null_string(s::AbstractString) = String(s) -_check_null_string(::Null) = null -_check_null_string(::Void) = null -_check_null_string(x) = ArgumentError("Invalid string or null passed: $x") +_check_missing_string(s::AbstractString) = String(s) +_check_missing_string(::Missing) = missing +_check_missing_string(::Void) = missing +_check_missing_string(x) = ArgumentError("Invalid string or missing passed: $x") struct UserAgentParser user_agent_re::Regex - family_replacement::Union{String, Null} - v1_replacement::Union{String, Null} - v2_replacement::Union{String, Null} + family_replacement::Union{String, Missing} + v1_replacement::Union{String, Missing} + v2_replacement::Union{String, Missing} function UserAgentParser(user_agent_re::Regex, family_replacement, v1_replacement, v2_replacement) - new(user_agent_re, _check_null_string(family_replacement), - _check_null_string(v1_replacement), _check_null_string(v2_replacement)) + new(user_agent_re, _check_missing_string(family_replacement), + _check_missing_string(v1_replacement), _check_missing_string(v2_replacement)) end end struct OSParser user_agent_re::Regex - os_replacement::Union{String, Null} - os_v1_replacement::Union{String, Null} - os_v2_replacement::Union{String, Null} + os_replacement::Union{String, Missing} + os_v1_replacement::Union{String, Missing} + os_v2_replacement::Union{String, Missing} function OSParser(user_agent_re::Regex, os_replacement, os_v1_replacement, os_v2_replacement) - new(user_agent_re, _check_null_string(os_replacement), _check_null_string(os_v1_replacement), - _check_null_string(os_v2_replacement)) + new(user_agent_re, _check_missing_string(os_replacement), _check_missing_string(os_v1_replacement), + _check_missing_string(os_v2_replacement)) end end struct DeviceParser user_agent_re::Regex - device_replacement::Union{String, Null} - brand_replacement::Union{String, Null} - model_replacement::Union{String, Null} + device_replacement::Union{String, Missing} + brand_replacement::Union{String, Missing} + model_replacement::Union{String, Missing} function DeviceParser(user_agent_re::Regex, device_replacement, brand_replacement, model_replacement) - new(user_agent_re, _check_null_string(device_replacement), - _check_null_string(brand_replacement), _check_null_string(model_replacement)) + new(user_agent_re, _check_missing_string(device_replacement), + _check_missing_string(brand_replacement), _check_missing_string(model_replacement)) end end @@ -79,36 +79,36 @@ end struct DeviceResult family::String - brand::Union{String, Null} - model::Union{String, Null} + brand::Union{String, Missing} + model::Union{String, Missing} function DeviceResult(family::AbstractString, brand, model) - new(string(family), _check_null_string(brand), _check_null_string(model)) + new(string(family), _check_missing_string(brand), _check_missing_string(model)) end end struct UAResult family::String - major::Union{String, Null} - minor::Union{String, Null} - patch::Union{String, Null} + major::Union{String, Missing} + minor::Union{String, Missing} + patch::Union{String, Missing} function UAResult(family::AbstractString, major, minor, patch) - new(string(family), _check_null_string(major), _check_null_string(minor), - _check_null_string(patch)) + new(string(family), _check_missing_string(major), _check_missing_string(minor), + _check_missing_string(patch)) end end struct OSResult family::String - major::Union{String, Null} - minor::Union{String, Null} - patch::Union{String, Null} - patch_minor::Union{String, Null} + major::Union{String, Missing} + minor::Union{String, Missing} + patch::Union{String, Missing} + patch_minor::Union{String, Missing} function OSResult(family::AbstractString, major, minor, patch, patch_minor) - new(string(family), _check_null_string(major), _check_null_string(minor), - _check_null_string(patch), _check_null_string(patch_minor)) + new(string(family), _check_missing_string(major), _check_missing_string(minor), + _check_missing_string(patch), _check_missing_string(patch_minor)) end end @@ -125,9 +125,9 @@ function loadua() #Loop over entire set of user_agent_parsers, add to USER_AGENT_PARSERS for _ua_parser in REGEXES["user_agent_parsers"] _user_agent_re = Regex(_ua_parser["regex"]) - _family_replacement = get(_ua_parser, "family_replacement", null) - _v1_replacement = get(_ua_parser, "v1_replacement", null) - _v2_replacement = get(_ua_parser, "v2_replacement", null) + _family_replacement = get(_ua_parser, "family_replacement", missing) + _v1_replacement = get(_ua_parser, "v1_replacement", missing) + _v2_replacement = get(_ua_parser, "v2_replacement", missing) #Add values to array push!(temp, UserAgentParser(_user_agent_re, @@ -148,9 +148,9 @@ function loados() #Loop over entire set of os_parsers, add to OS_PARSERS for _os_parser in REGEXES["os_parsers"] _user_agent_re = Regex(_os_parser["regex"]) - _os_replacement = get(_os_parser, "os_replacement", null) - _os_v1_replacement = get(_os_parser, "os_v1_replacement", null) - _os_v2_replacement = get(_os_parser, "os_v2_replacement", null) + _os_replacement = get(_os_parser, "os_replacement", missing) + _os_v1_replacement = get(_os_parser, "os_v1_replacement", missing) + _os_v2_replacement = get(_os_parser, "os_v2_replacement", missing) #Add values to array push!(temp, OSParser(_user_agent_re, @@ -172,9 +172,9 @@ function loaddevice() #Loop over entire set of device_parsers, add to DEVICE_PARSERS for _device_parser in REGEXES["device_parsers"] _user_agent_re = Regex(_device_parser["regex"]) - _device_replacement = get(_device_parser, "device_replacement", null) - _brand_replacement = get(_device_parser, "brand_replacement", null) - _model_replacement = get(_device_parser, "model_replacement", null) + _device_replacement = get(_device_parser, "device_replacement", missing) + _brand_replacement = get(_device_parser, "brand_replacement", missing) + _model_replacement = get(_device_parser, "model_replacement", missing) #Add values to array push!(temp, DeviceParser(_user_agent_re, _device_replacement, _brand_replacement, @@ -206,7 +206,7 @@ end function _multireplace(str::AbstractString, mtch::RegexMatch) _str = replace(str, r"\$(\d)", m -> _inner_replace(m, mtch.captures)) _str = replace(_str, r"^\s+|\s+$", "") - length(_str) == 0 ? null : _str + length(_str) == 0 ? missing : _str end @@ -218,36 +218,36 @@ function parsedevice(user_agent_string::AbstractString) _match = match(value.user_agent_re, user_agent_string) # family - if !isnull(value.device_replacement) + if !ismissing(value.device_replacement) device = _multireplace(value.device_replacement, _match) else device = _match.captures[1] end # brand - if !isnull(value.brand_replacement) + if !ismissing(value.brand_replacement) brand = _multireplace(value.brand_replacement, _match) elseif length(_match.captures) > 1 brand = match_vals[2] else - brand = null + brand = missing end # model - if !isnull(value.model_replacement) + if !ismissing(value.model_replacement) model = _multireplace(value.model_replacement, _match) elseif length(_match.captures) > 2 model = match_vals[3] else - model = null + model = missing end return DeviceResult(device, brand, model) end end - DeviceResult("Other",null,null) #Fail-safe for no match + DeviceResult("Other",missing,missing) #Fail-safe for no match end # parsedevice -parsedevice(::Null) = null +parsedevice(::Missing) = missing function parseuseragent(user_agent_string::AbstractString) @@ -257,7 +257,7 @@ function parseuseragent(user_agent_string::AbstractString) match_vals = match(value.user_agent_re, user_agent_string).captures #family - if !isnull(value.family_replacement) + if !ismissing(value.family_replacement) if ismatch(r"\$1", value.family_replacement) family = replace(value.family_replacement, "\$1", match_vals[1]) else @@ -268,28 +268,28 @@ function parseuseragent(user_agent_string::AbstractString) end #major - if !isnull(value.v1_replacement) + if !ismissing(value.v1_replacement) v1 = value.v1_replacement elseif length(match_vals) > 1 v1 = match_vals[2] else - v1 = null + v1 = missing end #minor - if !isnull(value.v2_replacement) + if !ismissing(value.v2_replacement) v2 = value.v2_replacement elseif length(match_vals) > 2 v2 = match_vals[3] else - v2 = null + v2 = missing end #patch if length(match_vals) > 3 v3 = match_vals[4] else - v3 = null + v3 = missing end return UAResult(family, v1, v2, v3) @@ -297,9 +297,9 @@ function parseuseragent(user_agent_string::AbstractString) end end -return UAResult("Other", null, null, null) #Fail-safe for no match +return UAResult("Other", missing, missing, missing) #Fail-safe for no match end #End parseuseragent -parseuseragent(::Null) = null +parseuseragent(::Missing) = missing function parseos(user_agent_string::AbstractString) @@ -308,42 +308,42 @@ function parseos(user_agent_string::AbstractString) match_vals = match(value.user_agent_re, user_agent_string).captures #os - if !isnull(value.os_replacement) + if !ismissing(value.os_replacement) os = value.os_replacement else os = match_vals[1] end #os_v1 - if !isnull(value.os_v1_replacement) + if !ismissing(value.os_v1_replacement) os_v1 = value.os_v1_replacement elseif length(match_vals) > 1 os_v1 = match_vals[2] else - os_v1 = null + os_v1 = missing end #os_v2 - if !isnull(value.os_v2_replacement) + if !ismissing(value.os_v2_replacement) os_v2 = value.os_v2_replacement elseif length(match_vals) > 2 os_v2 = match_vals[3] else - os_v2 = null + os_v2 = missing end #os_v3 if length(match_vals) > 3 os_v3 = match_vals[4] else - os_v3 = null + os_v3 = missing end #os_v4 if length(match_vals) > 4 os_v4 = match_vals[5] else - os_v4 = null + os_v4 = missing end return OSResult(os, os_v1, os_v2, os_v3, os_v4) @@ -351,9 +351,9 @@ function parseos(user_agent_string::AbstractString) end end -return OSResult("Other", null, null, null, null) #Fail-safe if no match +return OSResult("Other", missing, missing, missing, missing) #Fail-safe if no match end #End parseos -parseos(::Null) = null +parseos(::Missing) = missing ############################################################################## @@ -368,9 +368,9 @@ function DataFrame(x::AbstractVector{DeviceResult}) temp["device"] = String[element.family for element in x] - temp["brand"] = Union{String,Null}[element.brand for element in x] + temp["brand"] = Union{String,Missing}[element.brand for element in x] - temp["model"] = Union{String,Null}[element.model for element in x] + temp["model"] = Union{String,Missing}[element.model for element in x] temp end @@ -383,16 +383,16 @@ function DataFrame(x::AbstractVector{OSResult}) temp["os_family"] = String[element.family for element in x] #Major - temp["os_major"] = Union{String,Null}[element.major for element in x] + temp["os_major"] = Union{String,Missing}[element.major for element in x] #Minor - temp["os_minor"] = Union{String,Null}[element.minor for element in x] + temp["os_minor"] = Union{String,Missing}[element.minor for element in x] #Patch - temp["os_patch"] = Union{String,Null}[element.patch for element in x] + temp["os_patch"] = Union{String,Missing}[element.patch for element in x] #Patch_Minor - temp["os_patch_minor"] = Union{String,Null}[element.patch_minor for element in x] + temp["os_patch_minor"] = Union{String,Missing}[element.patch_minor for element in x] temp end @@ -406,13 +406,13 @@ function DataFrame(x::AbstractVector{UAResult}) temp["browser_family"] = String[element.family for element in x] #Major - temp["browser_major"] = Union{String,Null}[element.major for element in x] + temp["browser_major"] = Union{String,Missing}[element.major for element in x] #Minor - temp["browser_minor"] = Union{String,Null}[element.minor for element in x] + temp["browser_minor"] = Union{String,Missing}[element.minor for element in x] #Patch - temp["browser_patch"] = Union{String,Null}[element.patch for element in x] + temp["browser_patch"] = Union{String,Missing}[element.patch for element in x] temp end diff --git a/test/runtests.jl b/test/runtests.jl index fdddde8..a146dd5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using UAParser, YAML, Base.Test +using UAParser, YAML, Missings, Base.Test #These user-agents look to be older, may not still be out in wild @@ -8,7 +8,7 @@ macro testparseval(obj::Symbol, valname::String, outputname::Symbol) valsymb = Symbol(valname) esc(quote if $obj[$valname] == nothing - @test isnull($outputname.$valsymb) + @test ismissing($outputname.$valsymb) else @test $obj[$valname] == $outputname.$valsymb end