diff --git a/+globalmacrodata/gmd.m b/+globalmacrodata/gmd.m index b133ba0..7e5fc20 100644 --- a/+globalmacrodata/gmd.m +++ b/+globalmacrodata/gmd.m @@ -434,13 +434,7 @@ end function out = loadSourceData(srcName, anything, countryArg) - csColPrefix = ''; - name = strtrim(srcName); - if numel(name) == 7 && startsWith(name, 'CS') - parts = strsplit(name, '_'); - csColPrefix = parts{1}; - name = normalizeSourceName(name); - end + [name, csColPrefix] = normalizeSourceName(srcName); srcTokens = tokens(name); if numel(srcTokens) > 1 fail(498, 'Warning: Please specify exactly one source.'); diff --git a/+globalmacrodata/private/normalizeSourceName.m b/+globalmacrodata/private/normalizeSourceName.m index de87abd..32eb278 100644 --- a/+globalmacrodata/private/normalizeSourceName.m +++ b/+globalmacrodata/private/normalizeSourceName.m @@ -1,9 +1,14 @@ -function s = normalizeSourceName(source) -%NORMALIZESOURCENAME Convert a 7-char CS alias (e.g. "CS1_ARG") to "ARG_1". -% Ports the Python _normalize_source_name helper. +function [s, csPrefix] = normalizeSourceName(source) +%NORMALIZESOURCENAME Convert a CS alias to its file name. +% "CS1_ARG" -> "ARG_1", "CS10_ITA" -> "ITA_10". Also returns the column +% prefix inside the file ("CS1", "CS10"), or '' when the name is not a CS +% alias. Ports the Python _normalize_source_name helper. s = strtrim(char(source)); - if numel(s) == 7 && startsWith(s, 'CS') - s = sprintf('%s_%s', s(end-2:end), s(3)); + csPrefix = ''; + tok = regexp(s, '^CS(\d+)_([A-Za-z]{3})$', 'tokens', 'once', 'ignorecase'); + if ~isempty(tok) + csPrefix = ['CS', tok{1}]; + s = sprintf('%s_%s', upper(tok{2}), tok{1}); end end diff --git a/tests/fixtures/clean/combined/ITA_10.dta b/tests/fixtures/clean/combined/ITA_10.dta new file mode 100644 index 0000000..d1a71c9 Binary files /dev/null and b/tests/fixtures/clean/combined/ITA_10.dta differ diff --git a/tests/tGmdOffline.m b/tests/tGmdOffline.m index 68fa983..599b529 100644 --- a/tests/tGmdOffline.m +++ b/tests/tGmdOffline.m @@ -121,6 +121,44 @@ function sourceCsAliasResolves(tc) tc.verifyTrue(ismember('CS1_M3_GDP', df.Properties.VariableNames)); end + function sourceCsAliasTwoDigitSlot(tc) + % CS10_ITA normalizes to source ITA_10 with data columns prefixed CS10_. + df = globalmacrodata.gmd('sources','CS10_ITA','variables','CPI'); + tc.verifyEqual(df.Properties.VariableNames, {'ISO3','year','CS10_CPI'}); + tc.verifyEqual(height(df), 10); + end + + function sourceCsAliasIgnoresCase(tc) + df = globalmacrodata.gmd('sources','cs10_ita'); + tc.verifyTrue(ismember('CS10_rGDP', df.Properties.VariableNames)); + end + + function sourceCsAliasTrimsWhitespace(tc) + df = globalmacrodata.gmd('sources',' CS10_ITA ','variables','CPI'); + tc.verifyEqual(df.Properties.VariableNames, {'ISO3','year','CS10_CPI'}); + end + + function sourceCsNearMissNotTranslated(tc) + % CS1_ARGX is not a CS alias, so it must not resolve to ARG_1. + tc.verifyError(@() globalmacrodata.gmd('sources','CS1_ARGX'), 'GMD:e498'); + end + + function sourceFileNameLoads(tc) + df = globalmacrodata.gmd('sources','ITA_10'); + tc.verifyTrue(ismember('CS10_CPI', df.Properties.VariableNames)); + end + + function sourceCsAliasUnknownVariableListsCodes(tc) + % The error lists the codes with the CS10_ prefix stripped. + try + globalmacrodata.gmd('sources','CS10_ITA','variables','M3'); + tc.verifyFail('Expected error GMD:e498.'); + catch ME + tc.verifyEqual(ME.identifier, 'GMD:e498'); + tc.verifySubstring(ME.message, 'It has data on CPI nGDP rGDP.'); + end + end + function invalidSourceRaises(tc) tc.verifyError(@() globalmacrodata.gmd('sources','NOPE'), 'GMD:e498'); end