Skip to content

Commit

Permalink
Create render module which handles rendering a file with running it t…
Browse files Browse the repository at this point in the history
…hrough all plugins.

Move associated tests into new location.
  • Loading branch information
hswolff committed Mar 20, 2016
1 parent a4f4867 commit 7c342bc
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 160 deletions.
69 changes: 5 additions & 64 deletions lib/collection/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import each from 'lodash/each';
import log from '../log';
import filter from './filter';
import Plugin from '../plugin';
import {
renderAndWriteFileWithPlugins,
} from '../render';
import CollectionPage from './page';

export default class CollectionBase {
Expand Down Expand Up @@ -251,7 +254,7 @@ export default class CollectionBase {
return Promise.resolve();
}

return CollectionBase.renderAndWriteFile(
return renderAndWriteFileWithPlugins(
file,
this.template,
siteData,
Expand All @@ -268,7 +271,7 @@ export default class CollectionBase {
* @return {Promise} Promise object, resolved when file is written to disk.
*/
writePage(collectionPage, siteData) {
return CollectionBase.renderAndWriteFile(
return renderAndWriteFileWithPlugins(
collectionPage,
this.pagination.template,
siteData,
Expand Down Expand Up @@ -319,68 +322,6 @@ export default class CollectionBase {
return result;
}

/**
* Write a file to the file system. Calls all plugin events.
* @param {(File|CollectionPage)} file File or CollectionPage object.
* @param {string} template Which template template to use.
* @param {Object} siteData Site wide template data.
* @param {Plugin.Event} eventBefore Which event handler to process before
* rendering the file.
* @param {Plugin.Event} eventAfter Which event handler to process after
* rendering the file.
* @return {Promise}
*/
static async renderAndWriteFile(file, template, siteData,
eventBefore, eventAfter) {

if (eventBefore) {
await Plugin.processEventHandlers(eventBefore, file);
}

let renderedFile = file.render(template, siteData);

if (eventAfter) {
[file, renderedFile] = await Plugin.processEventHandlers(
eventAfter,
file,
renderedFile
);
}

return CollectionBase.writeToFileSystem(
file,
renderedFile
);
}

/**
* Wrapper for writing to the file system.
* @param {(File|CollectionPage)} file File or CollectionPage object.
* @param {string} content Content of file.
* @param {string} encoding What encoding to use when writing file.
* @return {Promise}
*/
static async writeToFileSystem(file, content, encoding = 'utf8') {
// log.info('Writing file to %s', file.destination);

[file, content] = await Plugin.processEventHandlers(
Plugin.Event.collection.beforeWrite,
file, content
);

let result = await fs.outputFileAsync(
file.destination,
content,
encoding
);

await Plugin.processEventHandlers(
Plugin.Event.collection.afterWrite,
file, content
);

return result;
}

/**
* Sorts files according to a sort config object.
Expand Down
71 changes: 71 additions & 0 deletions lib/render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import fs from 'fs-extra';
import Promise from 'bluebird';
import Plugin from './plugin';

/**
* Wrapper for writing to the file system.
* @param {(File|CollectionPage)} file File or CollectionPage object.
* @param {string} content Content of file.
* @param {string} encoding What encoding to use when writing file.
* @return {Promise}
*/
export async function writeToDiskWithPlugins(file, content, encoding = 'utf8') {
[file, content] = await Plugin.processEventHandlers(
Plugin.Event.collection.beforeWrite,
file, content
);

let result = await Promise.fromCallback(cb => {
fs.outputFile(file.destination, content, encoding, cb);
});

await Plugin.processEventHandlers(
Plugin.Event.collection.afterWrite,
file, content
);

return result;
}

/**
* Write a file to the file system. Calls all plugin events.
* @param {(File|CollectionPage)} file File or CollectionPage object.
* @param {string} template Which template template to use.
* @param {Object} siteData Site wide template data.
* @param {Plugin.Event} eventBefore Which event handler to process before
* rendering the file.
* @param {Plugin.Event} eventAfter Which event handler to process after
* rendering the file.
* @return {Promise}
*/
export async function renderFileWithPlugins(file, template, siteData,
eventBefore, eventAfter) {

if (eventBefore) {
await Plugin.processEventHandlers(eventBefore, file);
}

let renderedFile = file.render(template, siteData);

if (eventAfter) {
[file, renderedFile] = await Plugin.processEventHandlers(
eventAfter,
file,
renderedFile
);
}

return [file, renderedFile];
}

/**
* Combines renderFileWithPlugins and writeToDiskWithPlugins for conveinience.
* @return {Promise}
*/
export async function renderAndWriteFileWithPlugins(...args) {
let [file, renderedFile] = await renderFileWithPlugins.apply(undefined, args);
return writeToDiskWithPlugins(
file,
renderedFile
);
}
96 changes: 0 additions & 96 deletions test/unit/collection/base.spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import assert from 'power-assert';
import sinon from 'sinon';
import fs from 'fs-extra';
import isUndefined from 'lodash/isUndefined';
import isArray from 'lodash/isArray';
import isObject from 'lodash/isObject';

import fixture from '../../fixture';

import Plugin from '../../../lib/plugin/index.js';
const PluginAPI = Plugin.API;

import CollectionBase from '../../../lib/collection/base.js';

Expand Down Expand Up @@ -101,100 +99,6 @@ describe('collection/base CollectionBase', () => {
});
});

describe('renderAndWriteFile', () => {
it('calls all functions in expected order', async () => {
let renderContent = 'hello world';

let instance = new CollectionBase('name');
instance.files = fixture.collectionFiles().map(file => {
file.render = sinon.spy(() => {
return renderContent;
});
return file;
});

sandbox.stub(CollectionBase, 'writeToFileSystem').returns(sinon.spy());

let file = instance.files[0];
let beforeSpy = sinon.spy();
let afterSpy = sinon.spy((val, val2) => [val, val2]);
PluginAPI.event.file.beforeRender(beforeSpy);
PluginAPI.event.file.afterRender(afterSpy);

try {
await CollectionBase.renderAndWriteFile(
file,
file.template,
{},
Plugin.Event.file.beforeRender,
Plugin.Event.file.afterRender
);
} catch (e) {
console.log(e);
}

assert.equal(beforeSpy.callCount, 1);
assert.ok(beforeSpy.calledWith(file));

assert.equal(file.render.callCount, 1);
assert.ok(file.render.calledWith(instance.template, {}));

assert.equal(afterSpy.callCount, 1);
assert.ok(afterSpy.calledWith(file, renderContent));

assert.equal(CollectionBase.writeToFileSystem.callCount, 1);
assert.ok(
CollectionBase.writeToFileSystem.calledWith(
file,
renderContent
)
);

assert.ok(beforeSpy.calledBefore(file.render));
assert.ok(file.render.calledBefore(afterSpy));
assert.ok(afterSpy.calledBefore(CollectionBase.writeToFileSystem));
});
});

describe('writeToFileSystem', () => {
it('calls all functions in expected order', async () => {
sandbox.stub(fs, 'outputFileAsync').returns(sinon.spy());

let mockFile = {
destination: './path/to/write/file'
};
let content = 'this is the excellent content';

let beforeSpy = sinon.spy();
let afterSpy = sinon.spy((val) => val);
PluginAPI.event.collection.beforeWrite(beforeSpy);
PluginAPI.event.collection.afterWrite(afterSpy);

try {
await CollectionBase.writeToFileSystem(mockFile, content);
} catch (e) {
console.log(e);
}

assert.equal(beforeSpy.callCount, 1);
assert.ok(beforeSpy.calledWith(mockFile, content));

assert.equal(fs.outputFileAsync.callCount, 1);
assert.ok(fs.outputFileAsync.calledWith(
mockFile.destination,
content,
'utf8'
));

assert.equal(afterSpy.callCount, 1);
assert.ok(afterSpy.calledWith(mockFile, content));

assert.ok(beforeSpy.calledBefore(fs.outputFileAsync));
assert.ok(fs.outputFileAsync.calledBefore(afterSpy));
assert.ok(afterSpy.calledBefore(CollectionBase.writeToFileSystem));
});
});

describe('sortFiles', () => {
it('sorts files according to config', () => {
assert.ok(true);
Expand Down
113 changes: 113 additions & 0 deletions test/unit/render.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import assert from 'power-assert';
import fs from 'fs-extra';
import sinon from 'sinon';
import fixture from '../fixture';
import Plugin from '../../lib/plugin/index.js';
const PluginAPI = Plugin.API;
import CollectionBase from '../../lib/collection/base.js';
import {
writeToDiskWithPlugins,
renderAndWriteFileWithPlugins,
} from '../../lib/render.js';

describe('render Render', function() {
let sandbox;
beforeEach(() => {
sandbox = sinon.sandbox.create();

Plugin._reset();
});

afterEach(() => {
sandbox.restore();
});

describe('renderFileWithPlugins', () => {
it('calls all functions in expected order', async () => {
// Disallow actually writing to disk.
sandbox.stub(fs, 'outputFile', function(...args) {
// Call callback.
args[args.length - 1]();
});

let renderContent = 'hello world';

let instance = new CollectionBase('name');
instance.files = fixture.collectionFiles().map(file => {
file.render = sinon.spy(() => {
return renderContent;
});
return file;
});

let file = instance.files[0];
let beforeSpy = sinon.spy();
let afterSpy = sinon.spy((val, val2) => [val, val2]);
PluginAPI.event.file.beforeRender(beforeSpy);
PluginAPI.event.file.afterRender(afterSpy);

try {
await renderAndWriteFileWithPlugins(
file,
file.template,
{},
Plugin.Event.file.beforeRender,
Plugin.Event.file.afterRender
);
} catch (e) {
console.log(e);
}

assert.equal(beforeSpy.callCount, 1);
assert.ok(beforeSpy.calledWith(file));

assert.equal(file.render.callCount, 1);
assert.ok(file.render.calledWith(instance.template, {}));

assert.equal(afterSpy.callCount, 1);
assert.ok(afterSpy.calledWith(file, renderContent));
});
});

describe('writeToDiskWithPlugins', () => {
it('calls all functions in expected order', async () => {
sandbox.stub(fs, 'outputFile', function(...args) {
// Call callback.
args[args.length - 1]();
});

let mockFile = {
destination: './path/to/write/file'
};
let content = 'this is the excellent content';

let beforeSpy = sinon.spy();
let afterSpy = sinon.spy((val) => val);
PluginAPI.event.collection.beforeWrite(beforeSpy);
PluginAPI.event.collection.afterWrite(afterSpy);

try {
await writeToDiskWithPlugins(mockFile, content);
} catch (e) {
console.log(e);
}

assert.equal(beforeSpy.callCount, 1);
assert.ok(beforeSpy.calledWith(mockFile, content));

assert.equal(fs.outputFile.callCount, 1);
assert.ok(fs.outputFile.calledWith(
mockFile.destination,
content,
'utf8'
));

assert.equal(afterSpy.callCount, 1);
assert.ok(afterSpy.calledWith(mockFile, content));

assert.ok(beforeSpy.calledBefore(fs.outputFile));
assert.ok(fs.outputFile.calledBefore(afterSpy));
assert.ok(afterSpy.calledBefore(writeToDiskWithPlugins));
});
});
});

0 comments on commit 7c342bc

Please sign in to comment.