tml-application

TML basic app config support

npm install tml-application
4 downloads in the last week
16 downloads in the last month

tml-application(3) -- basic app config support

SYNOPSIS

tml-application basic app config support.

OPTIONS

SYNTAX

ENVIRONMENT

RETURN VALUES

STANDARDS

SECURITY CONSIDERATIONS

BUGS

HISTORY

AUTHOR

SEE ALSO

IMPLEMENTATION


Application

    @purpose Application configuration;
    @author Erin Phillips;
    @version 0.0.2-2;
    @history 2013-04-30 EMP [0.0.2-1] adding-tml-build;
    @history 2013-04-30 EMP [0.0.2-2] fix-description;

resources

    CON = console
    TMLR = tml-runtime
    IO = tml-io
    CORE = tml-core

locals

    log = CON::log
    parseJson = TMLR::parseJson
    getEnv = TMLR::getEnv

notes

    @need N.1 provide a config object, whose contents are release specific;
    @need N.2 load the .regex files from PROTALIS_ETC/regex if any;
    @need N.3 load any .json files from PROTALIS_ETC/json if any;

messages

    ERR-ENV.000 {*} Release not found in env.json [{1}];
    ERR-ENV.001 {*} Environment var not set [{1}];
    ERR-FIL.000 {*} File op failed [{1} {2}];

code

-- STATICS --;

pattern patSetMap :name :typ

    <<<
    ###private method add:Name k$ v:typ -> this
        @:name+Map.(k)=v;
    >>>

var tmlHome

    = getEnv('TML_HOME',process.cwd())

var envJson

    = require('etc/env.json')

-- TYPES --;

private type Locale(@v%)

method get k$ ->$

    =@v.(k);

method getOr k$ def$ ->$

    =coalesce @v.(k) def;;

method getMaybe k$ -> opt $

    =@v.(k);

type Config(@release$)

    enforce exists envJson @release ERR-ENV.000(@release)
    @env=envJson[@release]

    @tmlHomeDir = new IO::Dir(tmlHome)

    @tmpDir=@tmlHomeDir.makeSub('tmp')

    @etcDir=@tmlHomeDir.makeSub('etc')        
        @purpose TML_HOME/etc contains the applications configuration
            information, with regex, data, and json subdirectories;

    @regexDir=@etcDir.makeSub('regex')
    @jsonDir=@etcDir.makeSub('json')
    @dataDir=@etcDir.makeSub('data')

    @regexMap={}
    @jsonMap={}
    @dataMap={}

    @localeMap={}
    @currentLocale=null

    ;

render patSetMap regex %;

render patSetMap json %;

render patSetMap data $;

render patSetMap locale %Locale;

method getData k$ -> $

    =@dataMap.(k);

method getDataOr k$ def$ -> $

    =coalesce @dataMap.(k) def;;

method getDataMaybe k$ -> opt $

    =@dataMap.(k);

method getEnv k$ -> $

    =@env.(k);

method getEnvOr k$ def$ -> $

    =coalesce @env.(k) def;;

method getEnvMaybe k$ -> opt $

    =@env.(k);

method getEnvNumeric k$ ->

    = as-numeric @env.(k);

method getEnvOrNumeric k$ def# ->

    =as-numeric coalesce @env.(k) def;;

method getEnvMaybeNumeric k$ -> opt

    =as-numeric @env.(k);

method getParam g$ k$ -> $

    =@jsonMap.(g).(k);

method getParamNumeric g$ k$ ->

    =as-numeric @jsonMap.(g).(k);

method getParamList g$ k$ -> *

    =@jsonMap.(g).(k);

method getParamHash g$ k$ -> %

    =@jsonMap.(g).(k);

method getParamOr g$ k$ def$ -> $

    =coalesce @jsonMap.(g).(k) def;;

method getParamOrNumeric g$ k$ def# ->

    =as-numeric coalesce @jsonMap.(g).(k) def;;

method getParamMaybe g$ k$ -> opt $

    =@jsonMap.(g).(k);

method getRegex k$ -> %CORE::Regex

    =@regexMap.(k);

method getText k$ -> $

    =coalesce @currentLocale.getMaybe(k) @localeMap.en.getOr(k,con '?' k);;

method getTextOr k$ def$ -> $

    =coalesce @currentLocale.getMaybe(k) @localeMap.en.getOr(k,def);;

method getTextMaybe k$ -> opt $

    =coalesce @currentLocale.getMaybe(k) @localeMap.en.getMaybe(k);;

method setLocale k$ -> this

    @currentLocale=coalesce @localeMap.(k) @localeMap.en;
    enforce @currentLocale (con 'Locale not set `' k '`')
    ;

method setParam g$ k$ v$-> this

    (coalesce= @jsonMap.(g) {}).(k)=val;

method loadConfigFiles cb& -> this

    vars sfxRegex=new IO::FileSuffix('regex')
         sfxJson=new IO::FileSuffix('json')
         sfxDat=new IO::FileSuffix('dat');

    async

        func
            @regexDir.foreachFile(sfxRegex,
                func $ cb2&
                    vars fp=new IO::FilePath(a);
                    fp.read(
                        func e? text$
                          enforce nullval e ERR-FIL.000('read',fp.asString())
                          @@addRegex(fp.getFileBase(),new CORE::Regex(text))
                          cb2()
                    ;)
                ;,
                next);

        func
            @jsonDir.foreachFile(sfxJson,
                func $ cb2&
                  vars locale
                       fp=new IO::FilePath(a);
                  locale = (scan fp.getFileBase() /^locale[-](.*?)$/)
                  if locale
                    locale=locale[1];
                  fp.read(
                    func e? text$
                      vars jsonVals=parseJson(text);
                      enforce nullval e ERR-FIL.000('read',fp.asString())
                      if locale
                        @@addLocale(locale,new Locale(jsonVals))
                      else
                        @@addJson(fp.getFileBase(),jsonVals)
                      ;
                      cb2()
                    ;)
                ;,
                next);

        func
            @dataDir.foreachFile(sfxDat,
                func $ cb2&
                  vars name
                       fp=new IO::FilePath(a);
                  fp.read(
                    func e? text$
                      enforce nullval e ERR-FIL.000('read',fp.asString())
                      @@addData(fp.getFileBase(),text)
                      cb2()
                    ;)
                ;,
                next);

    finally
        cb()
    ;


    ;

-- TESTS --;

test CONFIG

    vars c1 = new Config('TEST')
         c2 = new Config('TEST')
         c3 = new Config('TEST')
         c4 = new Config('TEST')
         c5 = new Config('TEST')
         ;

test-async : should return ?term for a missing message

    c1.loadConfigFiles(
        func 
            enforce 
                eq$
                c1.setLocale('en').getText('xxunknown')
                '?xxunknown'
                'invalid get failed'
            done()
        ;);

test-async : should return an english message

    c2.loadConfigFiles(
        func 
            enforce 
                eq$
                c2.setLocale('en').getText('hello')
                'hello'
                'get hello failed'
            done()
        ;);

test-async : should return an spanish message

    c3.loadConfigFiles(
        func 
            enforce 
                eq$
                c3.setLocale('es').getText('hello')
                'hola'
                'spanish get hello failed'
            done()
        ;);

test-async : should return data file contents

    c4.loadConfigFiles(
        func 
            enforce 
                eq$
                c4.getData('hello')
                "WORLD\n"
                'getData for `data/hello` failed'
            done()
        ;);

test-async : should return param list

    c5.loadConfigFiles(
        func 
            vars list=c5.getParamList('words','shortList');
            enforce 
                eq
                item-count list
                5
                'getParamList for `shortList` failed'
            done()
        ;);

    ;
npm loves you