diff --git a/format.md b/format.md index 76e12b8a..e5ed1526 100644 --- a/format.md +++ b/format.md @@ -24,6 +24,20 @@ TODOC: coupled formula using ${some-formula:some-index-formula} notation +## Filter + +We can use builtin filter at substitution time, using the `${formula/filter}` syntax. + +Valid filters: +* uppercase +* lowercase +* regexp: escape for regexp pattern +* shellarg: escape for a shell argument + + + + + # References ## Top level diff --git a/lib/spellcast.js b/lib/spellcast.js index 01686114..37f3d61d 100644 --- a/lib/spellcast.js +++ b/lib/spellcast.js @@ -1006,10 +1006,14 @@ spellcast.Book.prototype.castTransmute = function castTransmute( transmute , cas spellcast.Book.prototype.variableSubstitution = function variableSubstitution( input ) { - var output , self = this ; + var i , filters , output , self = this ; - output = input.replace( /\$\{([0-9a-zA-Z_-]+)(:([0-9a-zA-Z_-]+))?\}/g , function() { - var index , thirdParty , substitute = self.formula[ arguments[ 1 ] ] ; + output = input.replace( /\$\{([0-9a-zA-Z_-]+)(:([0-9a-zA-Z_-]+))?([\\\/0-9a-zA-Z_-]*)?\}/g , function() { + //output = input.replace( /\$\{([0-9a-zA-Z_-]+)(:([0-9a-zA-Z_-]+))?\}/g , function() { + + //console.log( 'arguments:' , arguments ) ; + + var index , value , thirdParty , substitute = self.formula[ arguments[ 1 ] ] ; if ( substitute === undefined ) { return '' ; } @@ -1036,7 +1040,26 @@ spellcast.Book.prototype.variableSubstitution = function variableSubstitution( i index = substitute.index ; } - return substitute[ index ] ; + value = substitute[ index ] ; + + // Filters + if ( arguments[ 4 ] ) + { + filters = arguments[ 4 ].split( '/' ) ; + filters.shift() ; + + for ( i = 0 ; i < filters.length ; i ++ ) + { + //console.log( "filter #" + i + ":" , filters[ i ] ) ; + + if ( spellcast.filter[ filters[ i ] ] ) + { + value = spellcast.filter[ filters[ i ] ]( value ) ; + } + } + } + + return value ; } ) ; return output ; @@ -1044,6 +1067,19 @@ spellcast.Book.prototype.variableSubstitution = function variableSubstitution( i +spellcast.filter = { + 'uppercase': function uppercase( str ) { return str.toUpperCase() ; } , + 'lowercase': function lowercase( str ) { return str.toLowerCase() ; } , + 'regexp': function escapeRegExp( str ) { + return str.replace( /([.*+?^${}()|\[\]\/\\])/g , "\\$1" ) ; + } , + 'shellarg' : function escapeShellArg( str ) { + return '\'' + str.replace( /\'/g , "'\\''" ) + '\'' ; + } +} ; + + + spellcast.Book.prototype.argsVariableSubstitution = function argsVariableSubstitution( inArgs ) { var key , args = {} ; @@ -1059,15 +1095,6 @@ spellcast.Book.prototype.argsVariableSubstitution = function argsVariableSubstit -spellcast.filter = {} ; - -spellcast.filter['regexp-escape'] = function regexpEscape( str ) -{ - return str.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' ) ; -} ; - - - /* Makefile builder */ diff --git a/test/spellbook b/test/spellbook index 25c4b497..61799d3a 100644 --- a/test/spellbook +++ b/test/spellbook @@ -2,8 +2,10 @@ formula alert:bob blah:blih + allcaps:FUUU list:one,two,three list-fr:un,deux,trois + version:0.1.2 @@ -20,6 +22,12 @@ formula scroll echo ${alert} ${blah}${blah} ${list} +.kawarimi-filter + scroll + echo ${version/regexp/shellarg} + echo ${alert/uppercase} + echo ${allcaps/lowercase} + .foreach foreach list scroll diff --git a/test/spellcast-test.js b/test/spellcast-test.js index c7aa4bbd..e25a086a 100644 --- a/test/spellcast-test.js +++ b/test/spellcast-test.js @@ -78,7 +78,7 @@ function getFizzledLog( spell ) -describe( "Formula" , function() { +describe( "Formula & variable substitution" , function() { it( "should be parsed into list of string, with an additionnal property 'index' equals to 0" , function() { var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ; @@ -86,52 +86,67 @@ describe( "Formula" , function() { expect( book.formula.alert ).to.be.eql( [ 'bob' ] ) ; expect( book.formula.list ).to.be.eql( [ 'one' , 'two' , 'three' ] ) ; } ) ; -} ) ; - - - -describe( "'scroll' block" , function() { - it( "should echoing echo" , function( done ) { + it( "should substitute variable (aka formula) accordingly in 'scroll' block" , function( done ) { cleanup( function() { var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ; - book.cast( 'echo' , function( error ) + book.cast( 'kawarimi' , function( error ) { expect( error ).not.ok() ; - expect( getCastedLog( 'echo' ) ).to.be( 'echo\n' ) ; + expect( getCastedLog( 'kawarimi' ) ).to.be( 'bob blihblih one\n' ) ; done() ; } ) ; } ) ; } ) ; - it( "should echoing delayed-echo after one second" , function( done ) { + it( "should substitute variable (aka formula) using filters" , function( done ) { cleanup( function() { var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ; - book.cast( 'delayed-echo' , function( error ) + book.cast( 'kawarimi-filter' , function( error ) { expect( error ).not.ok() ; - expect( getCastedLog( 'delayed-echo' ) ).to.be( 'delayed-echo\n' ) ; + expect( getCastedLog( 'kawarimi-filter' ) ).to.be( '0\\.1\\.2\nBOB\nfuuu\n' ) ; done() ; } ) ; } ) ; } ) ; +} ) ; + + + +describe( "'scroll' block" , function() { - it( "should substitute variable (aka formula) accordingly in 'scroll' block" , function( done ) { + it( "should echoing echo" , function( done ) { cleanup( function() { var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ; - book.cast( 'kawarimi' , function( error ) + book.cast( 'echo' , function( error ) { expect( error ).not.ok() ; - expect( getCastedLog( 'kawarimi' ) ).to.be( 'bob blihblih one\n' ) ; + expect( getCastedLog( 'echo' ) ).to.be( 'echo\n' ) ; + done() ; + } ) ; + } ) ; + } ) ; + + it( "should echoing delayed-echo after one second" , function( done ) { + + cleanup( function() { + + var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ; + + book.cast( 'delayed-echo' , function( error ) + { + expect( error ).not.ok() ; + expect( getCastedLog( 'delayed-echo' ) ).to.be( 'delayed-echo\n' ) ; done() ; } ) ; } ) ;