Skip to content

Instantly share code, notes, and snippets.

@ebidel
Last active May 23, 2018 13:02
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ebidel/5e56a516e93ae0d9286c to your computer and use it in GitHub Desktop.
Save ebidel/5e56a516e93ae0d9286c to your computer and use it in GitHub Desktop.
"ES6 meta programming" using tagged template strings
// ES6 meta programming ???
// The more complex form of ES6 template strings are called
// "tagged" template strings. In short, they allow you to
// pass the final evaluated string to a function for further
// processing. This allows for some interesting things. For example:
//
// get`https://api.github.com/repos/${org}/${repo}/issues?sort=${sort}`;
//
// _could_ make a network request and return a Promise with the result
// (instead of a string).
//
// Why would you want to do this? Well, you wouldn't! Users won't expect
// such side effects and returning a value other than a string is...bananas.
//
// That said, this type of ES6 magic is a fun POC :)
// Run this in Babel: https://goo.gl/NfgPq1
function get(strs, ...values) {
// Reconstruct the final URL. If no substitutions were given,
// the original string is used.
let url = values.reduce((prev, curr, i) => prev + curr + strs.raw[i + 1], strs.raw[0]);
return fetch(url).then(response => response.json()).then(results => {
results.forEach(r => {
console.log(r.url, r.title);
});
return results;
});
}
let org = 'Polymer';
let repo = 'polymer';
let sort = 'updated';
// Example 1
get`https://api.github.com/repos/${org}/${repo}/issues?sort=${sort}`;
// Example 2
// Note: we dropped the Promise on the floor in Example 1.
// get`https://www.chromestatus.com/features.json`.then(results => {
// results.forEach(r => console.log(r.name));
// });
@ebidel
Copy link
Author

ebidel commented Aug 6, 2015

Demo it in Babel: https://goo.gl/NfgPq1

@rauschma
Copy link

rauschma commented Aug 6, 2015

There are two things you can improve:

  • Your code ignores text after the last ${}.
  • You should be using raw text in the reduce() callback.

How about the following (note: strs.length === values.length+1)?

function get(strs, ...values) {
  // Reconstruct the final URL.
  let url = values.reduce((prev, curr, i) => prev + curr + strs.raw[i+1], strs.raw[0]);

  return ···
  ···
}

@ebidel
Copy link
Author

ebidel commented Aug 6, 2015

Thanks for that. I updated the snippet. Good call on #1.

@rauschma
Copy link

rauschma commented Aug 6, 2015

You don’t need the if statement (lines 24–26) anymore: reduce() uses strs.raw[0] whenever values.length === 0.

@ebidel
Copy link
Author

ebidel commented Aug 6, 2015

Right right. Removed.

@0x-r4bbit
Copy link

Is that syntax possible with every function then?

@ebidel
Copy link
Author

ebidel commented Aug 6, 2015

Maybe with Proxies? This was interesting to me because you can define a custom function to be called on your template string, but it's still used as a string. In this example, it's not doing any processing on the string and hijacking the return val to be something else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment