cream-and-sugar
Version:
A deliciously functional syntax for JavaScript with native support for JSX
147 lines (132 loc) • 9.37 kB
HTML
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cream & Sugar: Modules</title>
<link rel="icon" type="image/x-icon" href="https://jgnewman.github.io/cream-and-sugar/assets/images/favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Bitter:400,700|Open+Sans:300,400,800" rel="stylesheet">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css" />
<link rel="stylesheet" href="../../assets/css/app.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/highlight.min.js"></script>
</head>
<body class="docs">
<div class="branding"></div>
<div class="content">
<div class="left-border">
<h1>Modules</h1>
<h2 class="subhead">Inspired by ES2015</h2>
</div>
<p>Cream & Sugar takes inspiration from module syntax introduced in ES2015 and also supports C&S' new <a href="/reference/data-types/">data types</a>.</p>
<p>At a high level, any C&S file can import other modules and export functions of its own. The compiled code uses <code>require</code> syntax so that it can work with as many types of transpiled/compiled code in as many environments as possible. With that in mind, you are not limited to importing only C&S modules. C&S simply sits on top of JavaScript so you are free to import as many JavaScript modules as you like.</p>
<pre><code>import '/path/to/filename'
</code></pre><p>To import a module that does not actually export any particular values, simply <code>import</code> a filename. This will cause the module to be executed if it hasn't been already.</p>
<pre><code>import x from '/path/to/filename'
</code></pre><p>To assign a module's exported value to a variable, drop a variable name into the expression. This example will create a value called <code>x</code> that references whatever it is that your module exported.</p>
<pre><code>import {x, y} from '/path/to/filename'
</code></pre><p>To destructure values from a module that exports an object, place your variable names between curly braces. This will find values in the export associated with keys named <code>x</code> and <code>y</code>, and turn those into variables
in the module importing them.</p>
<pre><code>import {
keyname1: x,
keyname2: y
} from '/path/to/filename'
</code></pre><p>Use full object syntax in order to import keys under different variable names. This will assign the value at <code>keyname1</code> to the variable name <code>x</code> and the value at <code>keyname2</code>, to the variable name <code>y</code>.</p>
<p>When you export, you can export any type of value you want. As such, you can use destructuring of any object type in your imports. More options are shown here.</p>
<pre><code># Import the first 2 items of an exported tuple.
import {{ x, y }} from '/path/to/filename'
# Import the first two items from an exported array.
import [ x, y ] from '/path/to/filename'
# Assign the first item in an array to `hd`
# and all the rest of them to `tl`.
import [ hd | tl ] from '/path/to/filename'
</code></pre><p>When it comes to exports, ES2015 and C&S begin to differ. Whereas JavaScript allows using the <code>export</code> keyword multiple times per module, exporting items in C&S is akin to assigning a value to <code>module.exports</code> every time you invoke the <code>export</code> function. As such, you'll want to make sure you only call it once.</p>
<p>Since you can only call <code>export</code> once per module, it's likely that you will want to export an object.</p>
<p>Exports are also a good place to lock down the allowed arities that may be used with your functions. For example, if you have defined a function called <code>funA</code> and you export it as <code>aritize funA, 2</code>, then when a user imports your function, they will only be allowed to call it with 2 arguments. If they try to call it with any other number of arguments, they'll get an error. Following is a great example of where that would be useful.</p>
<pre><code>map list, fun => map list, fun, []
map [], fun, acc => acc
map [h|t], fun, acc =>
map t, fun, acc << (fun h, acc.length)
export aritize map, 2
</code></pre><p>In this example, we created a function called <code>map</code> that essentially mimics JavaScript's <code>Array.map</code> method. It assumes the user will call it with two arguments (an array and a function) and, when that happens, it will recur with a third argument – an array that accumulates all of the values as iterations occur.</p>
<p>In this case, we don't want users of our module to be able to pass in 3 arguments to this function as they could pretty easily mess things up. So when we export it, we call the <code>aritize</code> function and lock it down to an arity of 2. This way, if a user tries to call it with a third argument, they'll get an error. However, this does not inhibit the function's own ability to recurse with 3 arguments.</p>
<pre><code>import { Component } from 'react'
App = React.createClass {
render: fn =>
<div>"Hello"</div>
}
export App
</code></pre><p>Of course, you don't always want to lock down everything you export in this way. Leaving arity open can be important when working with certain libraries, for example React.js. If you export a react class, you'll need to leave the arity open so that you don't end up with a console error:</p>
<p>Remember that you can export any type of data from a C&S module including atoms and tuples.</p>
</div>
<section id="docs-app"></section>
<script>
// Section for random JavaScript hacks just to get this out quickly.
window.addEventListener('load', function () {
// Fix indentation in code blocks the best we can since panini's
// markdown compiler injects whitespace into pre tags.
Array.prototype.slice.call(document.querySelectorAll('pre code')).forEach(function (code) {
var lines = code.innerHTML.trim().split('\n');
var out = [lines[0]];
var sliceAmount;
lines.slice(1).forEach(function (line, index) {
if (index === 0) {
var whitespace = line.match(/^\s+/);
whitespace = whitespace ? whitespace[0] : '';
if (/([=-](\>)?|\{|match|\>|div|try|chain|default\s+[^\n])$/.test(lines[0])) {
whitespace = whitespace.slice(2);
}
sliceAmount = whitespace;
}
out.push(line.replace(sliceAmount, ''));
});
code.innerHTML = out.join('\n');
code.className = 'visible lang-coffeescript';
hljs.highlightBlock(code);
});
// Attach id's to h4 tags so that we can link to specific bifs.
Array.prototype.slice.call(document.querySelectorAll('h4')).forEach(function (h4) {
var html = h4.innerHTML.split(/\s+/g);
html[0] = '<span class="bif" id="' + html[0] + '">' + html[0] + '</span>';
h4.innerHTML = html.join(' ');
h4.className = 'visible';
});
// Fix relative link issues with the github site living in a subdirectory
Array.prototype.slice.call(document.querySelectorAll('.content a')).forEach(function (a) {
if (/^\/cream-and-sugar\//.test(location.pathname)) {
a.setAttribute('href', '/cream-and-sugar' + a.getAttribute('href'))
}
});
// Some script conflict is preventing us from linking to a certain
// spot on the page so here we just wait until the next run loop
// and if we have a hash in the location object, scroll to it.
(function () {
var hash = location.hash;
if (hash) {
var item = document.querySelector(hash);
setTimeout(function () {
item && window.scroll(0, item.offsetParent.offsetTop);
},0);
}
}());
// Fixes a responsiveness issue where on large screens sometimes
// the offgray sidebar isn't tall enough. Make sure its always
// tall enough whenever the screen resizes.
(function () {
var branding = document.querySelector('.branding');
var content = document.querySelector('.content');
function resizerizer() {
var brandingHeight = branding.offsetHeight;
content.style.height = '';
if (content.offsetHeight < brandingHeight) {
content.style.height = brandingHeight + 'px';
}
}
window.addEventListener('resize', resizerizer);
resizerizer();
}());
});
</script>
<script src="../../assets/js/app.js"></script>
</body>
</html>