Skip to content

Commit

Permalink
feat(edge): add support for cache
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 22, 2017
1 parent a84148e commit 3e46c85
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 63 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"klaw": "^1.3.1",
"lodash": "^4.17.4",
"node-exceptions": "^2.0.0",
"require-uncached": "^1.0.3",
"upcast": "^1.0.4"
}
}
20 changes: 19 additions & 1 deletion src/Edge/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class Edge {
this._tags = {}
this._globals = require('../Globals')
this._loader = new Loader()
this._options = {
cache: false
}
this._boot()
}

Expand Down Expand Up @@ -54,7 +57,9 @@ class Edge {
* @private
*/
_getTemplate () {
return new Template(this._tags, this._globals, this._loader)
return new Template(this._tags, {
cache: this._options.cache
}, this._globals, this._loader)
}

/**
Expand Down Expand Up @@ -100,6 +105,19 @@ class Edge {
tag.run(Context)
}

/**
* Configure edge by passing object of options.
*
* @method configure
*
* @param {Object} options
*
* @return {void}
*/
configure (options) {
this._options = _.merge(this._options, options)
}

/**
* Register a new global.
*
Expand Down
6 changes: 4 additions & 2 deletions src/Loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

const fs = require('fs')
const path = require('path')
const requireUncached = require('require-uncached')
const CE = require('../Exceptions')

/**
Expand Down Expand Up @@ -147,7 +148,7 @@ class Loader {
*
* @return {String}
*/
loadPresenter (presenter) {
loadPresenter (presenter, clearCache = false) {
/**
* Presenters path has not been registered and trying
* to load a presenter.
Expand All @@ -157,7 +158,8 @@ class Loader {
}

try {
return require(path.join(this.presentersPath, presenter))
const presenterPath = path.join(this.presentersPath, presenter)
return clearCache ? requireUncached(presenterPath) : require(presenterPath)
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
throw CE.RuntimeException.missingPresenter(presenter, this.presentersPath)
Expand Down
60 changes: 49 additions & 11 deletions src/Template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ const cache = require('../Cache')
* @constructor
*/
class Template {
constructor (tags, globals = {}, loader = null) {
constructor (tags, options, globals = {}, loader = null) {
this._tags = tags
this._globals = globals
this._loader = loader
this._viewName = 'raw string'
this._runTimeViews = []
this._options = options

this._locals = {}
this._presenter = null
Expand Down Expand Up @@ -111,7 +112,7 @@ class Template {
* @private
*/
_makeContext (data) {
const Presenter = this._presenter ? this._loader.loadPresenter(this._presenter) : BasePresenter
const Presenter = this._presenter ? this._loader.loadPresenter(this._presenter, !this._options.cache) : BasePresenter
const presenter = new Presenter(data, this._locals)
/**
* We should always make the context with the original view
Expand All @@ -126,6 +127,8 @@ class Template {
* @method _addRunTimeView
*
* @param {String} view
*
* @private
*/
_addRunTimeView (view) {
this._runTimeViews.push(view)
Expand All @@ -138,11 +141,52 @@ class Template {
* @method _removeRunTimeView
*
* @return {void}
*
* @private
*/
_removeRunTimeView () {
this._runTimeViews.pop()
}

/**
* Return the view from cache if cachining is
* turned on.
*
* @method _getFromCache
*
* @param {String} view
*
* @return {String|Null}
*
* @private
*/
_getFromCache (view) {
if (!this._options.cache) {
return null
}
return cache.get(view)
}

/**
* Save view to cache when caching is turned on
*
* @method _saveToCache
*
* @param {String} view
* @param {String} output
*
* @return {void}
*
* @private
*/
_saveToCache (view, output) {
if (!this._options.cache) {
return
}
cache.add(view, output)
debug('adding view %s to cache', view)
}

/**
* Compile a view by loading it from the disk and
* cache the view when caching is set to true.
Expand All @@ -155,7 +199,7 @@ class Template {
* @return {String}
*/
_compileView (view, asFunction = true) {
const preCompiledView = cache.get(view)
const preCompiledView = this._getFromCache(view)

/**
* Return the precompiled view from the cache if
Expand All @@ -170,13 +214,7 @@ class Template {

try {
const compiledView = compiler.compile(view)

/**
* Adding view to cache
*/
cache.add(view, compiledView)
debug('adding view %s to cache', view)

this._saveToCache(view, compiledView)
return compiledView
} catch (error) {
throw this._prepareStack(view, error)
Expand Down Expand Up @@ -378,7 +416,7 @@ class Template {
return result
}, {})

const template = new Template(this._tags, this._globals, this._loader)
const template = new Template(this._tags, this._options, this._globals, this._loader)
template.presenter(presenter)
template._makeContext(data)
return template
Expand Down
34 changes: 17 additions & 17 deletions test/unit/tags/component.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component without any slots', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert')
<h2> Hello dude </h2>
Expand All @@ -45,7 +45,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component with props', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert', username = 'virk')
<h2> Hello dude </h2>
Expand All @@ -65,7 +65,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component with dynamic props', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert', username = username)
<h2> Hello dude </h2>
Expand All @@ -85,7 +85,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component with object as props', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert', { username })
<h2> Hello dude </h2>
Expand All @@ -105,7 +105,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component with dynamic slots', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert', { username })
@slot('header')
Expand All @@ -131,7 +131,7 @@ test.group('Tags | Component ', (group) => {
})

test('parse a simple component with one or more dynamic slots', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert', { username })
@slot('header')
Expand Down Expand Up @@ -169,7 +169,7 @@ test.group('Tags | Component ', (group) => {
@endslot
@endcomponent
`
const output = new Template(this.tags, {}, loader).renderString(statement)
const output = new Template(this.tags, {}, {}, loader).renderString(statement)

assert.equal(output.trim(), dedent`
<div class="header">
Expand All @@ -186,7 +186,7 @@ test.group('Tags | Component ', (group) => {
@component('components.user', username = 'virk')
@endcomponent
`
const output = new Template(this.tags, {}, loader).renderString(statement, {
const output = new Template(this.tags, {}, {}, loader).renderString(statement, {
username: 'nikk'
})
assert.equal(output.trim(), '<h2> Hello virk </h2>')
Expand All @@ -197,7 +197,7 @@ test.group('Tags | Component ', (group) => {
@component('components.user', username = username)
@endcomponent
`
const output = new Template(this.tags, {}, loader).renderString(statement, {
const output = new Template(this.tags, {}, {}, loader).renderString(statement, {
username: 'nikk'
})
assert.equal(output.trim(), '<h2> Hello nikk </h2>')
Expand All @@ -215,7 +215,7 @@ test.group('Tags | Component ', (group) => {
@endslot
@endcomponent
`
const output = () => new Template(this.tags, {}, loader).compileString(statement)
const output = () => new Template(this.tags, {}, {}, loader).compileString(statement)
assert.throw(output, 'lineno:6 charno:0 E_INVALID_EXPRESSION: Invalid name <body> passed to slot. Only strings are allowed')
})

Expand All @@ -228,13 +228,13 @@ test.group('Tags | Component ', (group) => {
@endslot
@endcomponent
`
const output = new Template(this.tags, {}, loader).renderString(statement)
const output = new Template(this.tags, {}, {}, loader).renderString(statement)
const $ = cheerio.load(output)
assert.equal($('.body').html().trim(), '<h2> Hello joe </h2>')
})

test('pass multiple props to a component', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.user', username = 'virk', age = 22)
@endcomponent
Expand All @@ -246,7 +246,7 @@ test.group('Tags | Component ', (group) => {
})

test('component slots should have access to parent template scope', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert')
<h2>{{ username }}</h2>
Expand All @@ -260,7 +260,7 @@ test.group('Tags | Component ', (group) => {
})

test('include inside the components', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.alert')
@slot('body')
Expand All @@ -276,7 +276,7 @@ test.group('Tags | Component ', (group) => {
})

test('include component inside component', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.modal')
@slot('header')
Expand All @@ -295,7 +295,7 @@ test.group('Tags | Component ', (group) => {
})

test('deeply nested tags inside slots', (assert) => {
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@component('components.modal')
@slot('body')
Expand Down Expand Up @@ -326,7 +326,7 @@ test.group('Tags | Component ', (group) => {

test('pass presenter to component', (assert) => {
loader.presentersPath = path.join(__dirname, '../../../test-helpers/presenters')
const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const statement = dedent`
@!component('components.user', presenter = 'User', username = 'virk')
`
Expand Down
12 changes: 6 additions & 6 deletions test/unit/tags/include.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test.group('Tags | Include ', (group) => {
const statement = dedent`
@include('includes.users.edge')
`
const output = new Template(this.tags, {}, loader).compileString(statement)
const output = new Template(this.tags, {}, {}, loader).compileString(statement)
assert.equal(output, dedent`
return (function templateFn () {
let out = new String()
Expand All @@ -29,7 +29,7 @@ test.group('Tags | Include ', (group) => {
const statement = dedent`
@include(user.profile)
`
const output = new Template(this.tags, {}, loader).compileString(statement)
const output = new Template(this.tags, {}, {}, loader).compileString(statement)
assert.equal(output, dedent`
return (function templateFn () {
let out = new String()
Expand All @@ -43,7 +43,7 @@ test.group('Tags | Include ', (group) => {
const statement = dedent`
@include(usersPartial)
`
const output = new Template(this.tags, {}, loader).renderString(statement, {
const output = new Template(this.tags, {}, {}, loader).renderString(statement, {
usersPartial: 'includes.users'
})
assert.equal(output.trim(), '<h2> Hello </h2>')
Expand All @@ -55,7 +55,7 @@ test.group('Tags | Include ', (group) => {
@include(usersPartial)
@endif
`
const output = new Template(this.tags, {}, loader).renderString(statement, {
const output = new Template(this.tags, {}, {}, loader).renderString(statement, {
usersPartial: 'includes.users',
username: 'virk'
})
Expand All @@ -68,7 +68,7 @@ test.group('Tags | Include ', (group) => {
@include(usersPartial)
@endif
`
const output = new Template(this.tags, {}, loader).renderString(statement, {
const output = new Template(this.tags, {}, {}, loader).renderString(statement, {
usersPartial: 'includes.users'
})
assert.equal(output.trim(), '')
Expand All @@ -77,7 +77,7 @@ test.group('Tags | Include ', (group) => {
test('work fine with nested includes', (assert) => {
const statement = `@include('includes.user-profile')`

const template = new Template(this.tags, {}, loader)
const template = new Template(this.tags, {}, {}, loader)
const output = template.renderString(statement, { username: 'Foo' })
assert.equal(output.trim(), dedent`<h1> User Profile </h1>
<h2> Foo </h2>
Expand Down
Loading

0 comments on commit 3e46c85

Please sign in to comment.