Last active
August 29, 2015 14:12
-
-
Save trevnorris/efac1089d728934d44e2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function reblaze(vals, fn) { | |
if (typeof fn !== 'function') | |
throw new TypeError('fn should be a function'); | |
// V8 will automatically throw if vals is not an object. | |
var keys = Object.keys(vals); | |
var regexp; | |
var fn_name = fn.name; | |
var fn_str = fn.toString(); | |
var fn_len = fn_str.length; | |
var fn_args = fn_str.substring(fn_str.indexOf('(') + 1, fn_str.indexOf(')')); | |
var fn_body = fn_str.substring(fn_str.indexOf('{') + 1, fn_len - 1).trim(); | |
// TODO: This could be replaced by a replaced function that doesn't need | |
// to for loop around the keys and instead performs each individually. | |
// Also the strings would need to be concatinated every time and instead | |
// turned into a single string. | |
// XXX: Thought, could I use mutable strings to not need to rewrite each | |
// of these every time? | |
for (var i = 0; i < keys.length; i++) { | |
// Infer if the key is being used as an object key. | |
regexp = new RegExp('(\\w)(\s|\S)*\\\[\\(\\(\\(' + | |
keys[i] + | |
'\\)\\)\\)\\\]', 'g'); | |
fn_body = fn_body.replace(regexp, '$1.' + vals[keys[i]]); | |
// Need to do this since String#replace() in V8 doesn't support the optional | |
// third argument, flags, for global replacement. | |
regexp = new RegExp('\\(\\(\\(' + keys[i] + '\\)\\)\\)', 'g'); | |
fn_body = fn_body.replace(regexp, vals[keys[i]]); | |
} | |
return (new Function('return function ' + fn_name + | |
'(' + fn_args + ') {' + fn_body + '}'))(); | |
} | |
// Test mixed replacement types. | |
function replace4(foo) { | |
return foo[(((BAR)))] + (((BAZ))); | |
} | |
var fn = reblaze({ BAR: 'bar', BAZ: 3 }, replace4); | |
assert_eq(fn.toString(), 'function replace4(foo) {return foo.bar + 3;}'); | |
assert_eq(fn({ bar: 7 }), 10); | |
// Test multi property names replacement. | |
function replace3(foo) { | |
return foo[(((BAR)))] + foo[(((BAR)))]; | |
} | |
var fn = reblaze({ BAR: 'bar' }, replace3); | |
assert_eq(fn.toString(), 'function replace3(foo) {return foo.bar + foo.bar;}'); | |
assert_eq(fn({ bar: 13 }), 26); | |
// Test property names are correctly replaced. | |
function replace2(foo) { | |
return foo[(((BAR)))]; | |
} | |
var fn = reblaze({ BAR: 'bar' }, replace2); | |
assert_eq(fn.toString(), 'function replace2(foo) {return foo.bar;}'); | |
assert_eq(fn({ bar: 42 }), 42); | |
// Test arguments are properly inserted. | |
function replace1(foo, bar) { | |
return foo + bar + (((BAZ))); | |
} | |
var fn = reblaze({ BAZ: 1 }, replace1); | |
assert_eq(fn.toString(), 'function replace1(foo, bar) {return foo + bar + 1;}'); | |
assert_eq(fn(2, 3), 6); | |
// Test basic replacement. | |
function replace0() { | |
return (((A))) + (((B))) + (((C))) + (((A))); | |
} | |
var fn = reblaze({ A: 5, B: 7, C: 11 }, replace0); | |
assert_eq(fn.toString(), 'function replace0() {return 5 + 7 + 11 + 5;}'); | |
assert_eq(fn(), 28); | |
function log() { | |
return console.log.apply(this, arguments); | |
} | |
function assert_eq(val0, val1) { | |
if (val0 !== val1) | |
throw new Error('Assertion Failed: \n' + val0 + '\n' + val1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment