Skip to content

Instantly share code, notes, and snippets.

@eloytoro
Created June 9, 2018 23:51
Show Gist options
  • Save eloytoro/a2ee53070abf3c94a13ab779d46655a2 to your computer and use it in GitHub Desktop.
Save eloytoro/a2ee53070abf3c94a13ab779d46655a2 to your computer and use it in GitHub Desktop.
const builder = require('../');
const { expect } = require('chai');
describe('ice cream', () => {
it('builds an ice cream cone', () => {
const serving = builder
.steps({
scoop: ({ scoops }, flavor) => ({ scoops: scoops.concat(flavor) }),
})
.endings({
topping: (cone, topping) => ({ ...cone, topping })
})
.unwrap({ scoops: [] })
const basic = serving
.scoop('chocolate')
const holygrail = basic
.scoop('coconut')
.scoop('banana')
const perfection = holygrail
.topping('cherry');
const ruined = holygrail
.topping('sprinkles');
const enthusiast = basic
.scoop('chocolate')
.scoop('chocolate')
.topping('chocolate chip');
const disgrace = basic
.scoop('rum & raisins')
.topping('peanuts');
expect(perfection).to.eql({
scoops: ['chocolate', 'coconut', 'banana'],
topping: 'cherry'
});
expect(ruined).to.eql({
scoops: ['chocolate', 'coconut', 'banana'],
topping: 'sprinkles'
});
expect(enthusiast).to.eql({
scoops: ['chocolate', 'chocolate', 'chocolate'],
topping: 'chocolate chip'
});
expect(disgrace).to.eql({
scoops: ['chocolate', 'rum & raisins'],
topping: 'peanuts'
});
})
})
@eloytoro
Copy link
Author

const map = (source, mapper) =>
  Object.keys(source).reduce(
    (target, key) => ({ ...target, [key]: mapper(source[key], key) }),
    {}
  );

const update = (source, key, value) => Object.assign(
  {},
  source,
  { [key]: Object.assign({}, source[key], value) }
);

const echelon = (steps, endings, traverse) => Object.assign(
  map(steps, method => (...params) =>
    echelon(steps, endings, () => method(traverse(), ...params))
  ),
  map(endings, unwrap => (...params) =>
    unwrap(traverse(), ...params)
  )
);

const unwrap = (steps, endings, initialValue) => {
  return echelon(steps, endings, () => initialValue);
};

const builder = unwrap({
  steps(builder, steps) {
    return update(builder, 'steps', steps);
  },
  endings(builder, endings) {
    return update(builder, 'endings', endings);
  }
}, {
  unwrap(builder, initialValue) {
    return unwrap(builder.steps, builder.endings, initialValue);
  }
}, { steps: {}, endings: {} });

module.exports = builder;

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