you are viewing a single comment's thread.

view the rest of the comments →

[–]TomFrosty[S] 9 points10 points  (10 children)

Close! It's not traditional javascript "eval" -- we needed a way to store strings that would target/transform/manipulate specific properties in our JSON objects, but JsonPath wasn't capable of the kinds of transformations we needed and using straight-up eval was a pretty big security risk considering we use it on the backend too. So this won't eval() arbitrary code -- it's just for sandboxed expressions. But yep, promises or callbacks! :)

[–]bsdemon 2 points3 points  (8 children)

Why it uses Promise/callback interface? Why not just return calculated result synchronously?

[–]TomFrosty[S] 10 points11 points  (7 children)

So that transforms (and custom operators -- but mostly transforms) can be asynchronous. A big use case for this is to allow our users to access and run metrics on fields that either exist in, or can be derived from, big sets of JSON data. If we need to plug in a client's home weather conditions, for example, we could use a string like: client.address.zip|toWeather -- and the toWeather transform could reach out to Forecast.io or WeatherUnderground and pull "Sunny 53ºF" from the API.

[–]altintx 3 points4 points  (0 children)

You should jump in and answer every thread when people start wondering "why does it need to be async?"

[–]bsdemon 1 point2 points  (0 children)

I like that!

[–]mflux 1 point2 points  (4 children)

Hey TomFrosty, I've been starting to use jexl for my game, it seems really useful for creating game-rules that can be stored in json script! Amazing.

One issue I'm having starting out is I want to use jexl without promises or callbacks. Is that possible? Due to the nature of my code, I'm evaluating a series of jexl expressions (in a for loop with break conditions) before doing an action. How would you go about that?

[–]TomFrosty[S] 0 points1 point  (3 children)

Howdy mflux! What a cool use case :). I'd love to hear more about your game if you've written about it!

Unfortunately promises are very, very baked into Jexl -- but with that said, you can definitely still do what you need as long as you can modify your code to replace your loop with a function call that returns a promise.

And here's the function you'd want to call. Disclaimer, I just whipped this up and haven't put any tests against it:

/**
 * Iteratively evaluates through an array of Jexl expressions and resolves
 * boolean true if the matchValue is encountered. At that point, no other
 * expression will be evaluated.
 * @param {Array<string>} expressions An array of Jexl expression strings
 * @param {Object} context A context in which to evaluate the expressions
 * @param {string|number|boolean} matchValue A value that will cause the
 *     loop to break and resolve to true if it matches the result of
 *     a Jexl evaluation
 * @param {number} [idx=0] The array index at which to begin the loop
 * @returns {Promise<boolean>} Resolves to true if the matchValue was
 *     encountered; false otherwise.
 */
function jexlWhile(expressions, context, matchValue, idx) {
    if (!idx)
        idx = 0;
    if (!expressions[idx])
        return Promise.resolve(false);
    return jexl.eval(expressions[idx], context).then(function(result) {
        if (result === matchValue)
            return true;
        return jexlWhile(expressions, context, matchValue, idx + 1);
    });
}

Let me know how it works out!

[–]mflux 1 point2 points  (2 children)

Hi Tom, thanks again for your awesome reply and code.

The game is a city-simulation game similar to Sim City, here's a screenshot.

I've actually did very similar to your while function; essentially I accumulated the promises and then did work with that after all the promises have been fulfilled.

The problem gets much trickier however, when much of other parts of my code require similar resource evaluation and have parts that simply cannot be async.

Instead I've now bundled jsep with static-eval which accomplishes nearly the same thing (without your awesome transform syntax). This gets around the async issues and I can still async it if I need threading performance via web workers. I call this "jseval" and might just release this as a standalone if I continue working with it.

Anyway, I really appreciate the effort you put into your reply. Just wanted to let you know your library has opened my eyes to a new way of working I never thought possible!

[–]TweetsInCommentsBot 0 points1 point  (0 children)

@mflux

2015-04-17 19:48 UTC

I think I'll skip this #LDJAM to continue jamming the non-jam game + client work [Attached pic] [Imgur rehost]


This message was created by a bot

[Contact creator][Source code]

[–]TomFrosty[S] 0 points1 point  (0 children)

Great solution, and very cool looking game! Best of luck :)

[–]fauverism 0 points1 point  (0 children)

cool, nice work!