Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #13 from Postmedia/simplify

removed client rendering and kitkat
  • Loading branch information...
commit 96da1bed9eef3e57828d6a969b03719c09dea615 2 parents 9fc310c + e7703ae
Edward de Groot authored
View
10 History.md
@@ -1,3 +1,11 @@
+0.4.0 / 2012-02-02
+==================
+
+ * Removed client side rendering (for now)
+ * Switched out kitkat for vows
+ * Supports alternate view engines
+ * No error if helpers aren't defined (missing folder)
+
0.3.3 / 2011-11-23
==================
@@ -13,7 +21,7 @@
* added support for json directory of available timbits
* Timbit fetch method will store pantry result in array if context contains existing entry
- * Timbit fetch method will store the requested uri in context[name_uri] (or array if context contains existing entry)
+ * Timbit fetch method will store the requested uri in context\[name_uri\] (or array if context contains existing entry)
* added initial support for express sessions
* routing now works for both get and post methods
View
44 README.md
@@ -99,49 +99,7 @@ The examples and params used to power the help pages are also used to power the
There is also a master test page located at /timbits/test which will execute tests
Although not overly sophisticated, it will ensure your definitions, examples, and views are valid and compile properly. It is also useful for remote monitoring of production systems.
-Additional functional testing can and should be implemented via a testing library, such as our very own [kitkat](https://github.com/Postmedia/kitkat)
-
-### Client Side Rendering
-
-Although Timbits was originally developed with the intent of serving out widgets via ESI (or other mechanisms of server to server requests) we now have built in support for client side rendering. Simply pass a remote=true parameter and the timbit will render JavaScript which provides the data context, requests the view, and renders on the client.
-
-Ensure that the following javascript libraries have been loaded in the browser first:
-- jQuery (http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js)
-- CoffeeScript (http://jashkenas.github.com/coffee-script/extras/coffee-script.js)
-- CoffeeKup (https://github.com/mauricemach/coffeekup)
-
-Below is an example of rendering the plain timbit on the client. If you are rendering multiple timbits on a single page, the id (in this case esi_0) must be unique for each timbit request.
-
- <div id="esi_0"></div>
- <script>
- $.getScript("/plain/?who=World&esi_id=esi_0&remote=true");
- </script>
-
-In this case, the result of the '/plain/?who=World&esi_id=esi_0&remote=true' getScript call will be similar to the following:
-
- context_esi_0 = {"who":"World","esi_id":"esi_0","remote":"true","name":"plain","view":"plain/default","maxAge":60};
- var views = views || {};
- if (views['plain/default'] || false) {
- render = CoffeeKup.render(views['plain/default'], context_esi_0);
- $('#esi_0').html(render);
- }
- else {
- $.ajax({
- url: "http://localhost:5678/plain/default.coffee?json=true&callback=?",
- dataType: "jsonp",
- cache: true,
- jsonpCallback: "plain_default",
- success: function(data, textStatus, jqXHR){
- views['plain/default'] = data; //save view for reuse
- render = CoffeeKup.render(views['plain/default'], context_esi_0);
- $('#esi_0').html(render);
- }
- });
- }
-
-When run, this script will check if the current view requested has been stored. If the view has been stored, coffeekup will render the view along with the context. If the view has not been stored, it will send an ajax request for the view. On ajax callback, the view will be stored and then rendered along with the context.
-
-Alternatively to the above method, the parse-esi.js script (from the connect-esi project) will search for esi/csi tags on a page and then automatically append the required &esi_id=esi_id&remote=true parameters. For a more detailed example of this method of remote rendering, please see public/tests in the 'timbits-example' project. The 'timbits-example' project makes use of PMScriptManager which simplifies the process of rendering remotely by using javascript packages which contain all required libraries to display a particular timbit.
+Additional functional testing can and should be implemented via a testing library, such as vows [vows](http://vowsjs.org/)
### Sharing of views
View
28 bin/template/kitkat.config.js
@@ -1,28 +0,0 @@
-var config = {}
-
-/* ========CONFIGURATION SECTION=============*/
-config.safetyOff = true;
-config.noCompile = true;
-config.prodSrcDir = "timbits";
-/* ==========================================*/
-
-
-module.exports = config;
-
-
-
-/*
-// Acceptable options exist within this comment block. copy and modify any of these settings into the config section above
-// between the two comment lines, this keepts the samples below and serves as documentation on possible options.
-
-config.safetyOff = true;
-config.noCompile = true;
-
-//paths are specified reletive to the root of your project. path.join() is used to append these to that path.
-config.prodSrcDir = "examples/timbits";
-config.specFileDir = "spec";
-config.prodDeployDir = "lib";
-
-*/
-
-
View
21 bin/template/spec/base.spec.coffee
@@ -1,21 +0,0 @@
-timbits = require 'timbits'
-assert = require 'assert'
-path = require 'path'
-
-homeFolder = "#{process.cwd()}"
-
-#start serving timbits
-
-server = timbits.serve( {home: homeFolder, port: 8785 })
-
-module.exports =
-
-## Test Case #1 - check we have a valid server running
- "test that the express server object returned is functioning, note by default the root redirects to the help page so we get a http status code of 302": (beforeExit)->
- assert.response server,
- url: "/"
- method: "GET"
- ,
- status: 302
- , (res) ->
- assert.ok res, "Expected a response, perhaps something is wrong our status was: #{res.status}"
View
43 bin/template/test/timbits-test.coffee
@@ -0,0 +1,43 @@
+timbits = require 'timbits'
+vows = require 'vows'
+assert = require 'assert'
+path = require 'path'
+request = require 'request'
+
+homeFolder = process.cwd()
+port = 8785
+
+server = timbits.serve( {home: homeFolder, port: port })
+
+assertStatus = (code) ->
+ return (err, res) ->
+ assert.isNull err
+ assert.equal res.statusCode, code
+
+respondsWith = (status) ->
+ context = {
+ topic: ->
+ req = @context.name.split(' ')
+ method = req[0].toLowerCase()
+ path = req[1]
+ uri = "http://localhost:#{port}#{path}"
+ console.log uri
+
+ request[method] uri, @callback
+ return
+ }
+
+ context["should respond with a #{status}"] = assertStatus(status)
+ return context
+
+vows
+ .describe('timbits')
+ .addBatch
+
+ #test main help page
+ 'GET /timbits/help': respondsWith 200
+
+ #test json directory
+ 'GET /timbits/json': respondsWith 200
+
+ .export module
View
6 bin/timbits
@@ -75,15 +75,15 @@ newProject = (argv) ->
log.error "New project requires two parameters (eg. './timbits new project')"
else
log.notice "Creating project '#{argv[1]}'"
- directories = ["#{argv[1]}", "#{argv[1]}/timbits", "#{argv[1]}/helpers", "#{argv[1]}/views", "#{argv[1]}/spec"]
- files = ["server.js", "History.md", "README.md", "LICENSE", "kitkat.config.js"]
+ directories = ["#{argv[1]}", "#{argv[1]}/timbits", "#{argv[1]}/helpers", "#{argv[1]}/views", "#{argv[1]}/test"]
+ files = ["server.js", "History.md", "README.md", "LICENSE"]
mkdir directories[0], ->
mkdir directories[1], ->
mkdir directories[2], ->
mkdir directories[3], ->
mkdir directories[4], ->
- cp "#{lib}/spec/base.spec.coffee", "#{argv[1]}/spec/#{argv[1]}.spec.coffee", ->
+ cp "#{lib}/test/timbits-test.coffee", "#{argv[1]}/test/#{argv[1]}-test.coffee", ->
pending = files.length
for file in files
cp "#{lib}/#{file}", argv[1], ->
View
27 kitkat.config.js
@@ -1,27 +0,0 @@
-var config = {}
-
-/* ========CONFIGURATION SECTION=============*/
-
-
-/* ==========================================*/
-
-
-module.exports = config;
-
-
-
-/*
-// Acceptable options exist within this comment block. copy and modify any of these settings into the config section above
-// between the two comment lines, this keepts the samples below and serves as documentation on possible options.
-
-config.safetyOff = true;
-config.noCompile = true;
-
-//paths are specified reletive to the root of your project. path.join() is used to append these to that path.
-config.prodSrcDir = "examples/timbits";
-config.specFileDir = "spec";
-config.prodDeployDir = "lib";
-
-*/
-
-
View
21 package.json
@@ -1,7 +1,7 @@
{
"name": "timbits",
"description": "Widget framework based on Express and CoffeeScript",
- "version": "0.3.3",
+ "version": "0.4.0",
"homepage": "https://github.com/Postmedia/timbits",
"author": "Edward de Groot <edegroot@postmedia.com> (http://mred9.wordpress.com)",
"contributors": [
@@ -10,22 +10,23 @@
{ "name": "Kevin Gamble", "email": "kgamble@postmedia.com" }
],
"dependencies": {
- "coffee-script": ">= 1.1.1",
- "coffeekup": ">= 0.3.0",
+ "coffee-script": ">= 1.2.0",
+ "coffeekup": ">= 0.3.1",
"coloured-log": ">= 0.9.7",
"connect-assets": "= 2.0.0-rc1",
- "connect-esi": ">= 0.1.6",
- "connect-less": ">= 0.2.2",
- "express": ">= 2.4.6",
- "jsonp-filter": ">= 0.0.1",
+ "connect-esi": ">= 0.1.7",
+ "connect-less": ">= 0.2.3",
+ "express": ">= 2.5.6",
+ "jsonp-filter": ">= 0.0.2",
"pantry": ">= 0.2.0",
- "request": ">= 2.1.1",
+ "request": ">= 2.9.1",
"optimist": ">= 0.2.6"
},
"devDependencies": {
- "kitkat": ">= 0.3.0"
+ "vows": ">= 0.6.1",
+ "request": ">= 2.9.100"
},
- "bugs": { "web": "https://github.com/Postmedia/timbits/issues"},
+ "bugs": { "url": "https://github.com/Postmedia/timbits/issues"},
"licenses": [
{ "type": "MIT", "url": "https://github.com/Postmedia/timbits/blob/master/LICENSE"}
],
View
108 spec/timbits.spec.coffee
@@ -1,108 +0,0 @@
-timbits = require 'timbits'
-assert = require 'assert'
-path = require 'path'
-
-homeFolder = path.join("#{process.cwd()}", "examples")
-
-#start serving timbits
-
-server = {}
-
-module.exports =
-
- "setup": ->
- server = timbits.serve( {home: homeFolder, port: 8785 })
-
- "teardown": ->
- server.close()
-
-## Test Case #1 - check we have a valid server running
- "test that the express server object returned is functioning, note by default the root redirects so hhtp status code should be 302": (beforeExit)->
- assert.response server,
- url: "/"
- method: "GET"
- ,
- status: 200
- headers: "Content-Type": "text/html; charset=utf-8;"
- , (res) ->
- "Test Case #1 - check we have a valid server running\n"
-
-
-## Test Case #2 - Plain timbit request
- "test the plain timbit request, this is the simpliest request we could try": (beforeExit) ->
- assert.response server,
- url: "/plain/"
- method: "GET"
- ,
- status: 200
- body: /Hello Anonymous/
- , (res) ->
- "Test Case #2 - Plain timbit request\n"
-
-
-## Test Case #3 - Plain timbit with querystring
- "test the plain timbit request with the addition of a querystring": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/plain/?who=cthulhu"
- ,
- body: /cthulhu/
- , (res) ->
- "Test Case #3 - Plain timbit with querystring\n"
-
-
-## Test Case #4 - Cherry timbit which uses the eat callback to override or extend the render method
- "test the cherry timbit, specifically we are vetting that the eat callback is working allowing us to customize the context rendered": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/cherry/"
- ,
- body: /The current server date\/time is/
- status: 200
- , (res) ->
- "Test Case #4 - Cherry timbit which uses the eat callback to override or extend the render method\n"
-
-
-## Test Case #5 - Chocolate timbit which utilizes custom views
- "test the chocolate timbit which allows us to use alternate views if they exist, this is a test of the 'alternate' view which does exist": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/chocolate/alternate?q=coffeescript"
- ,
- body: /coffeescript/
- status: 200
- , (res) ->
- "Test Case #5 - Chocolate timbit which utilizes custom views\n"
-
-
-## Test Case #6 - Chocolate timbit requesting a view that can not be found (500 Error)
- "test the choclate timbit using an alternate view that does not exist": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/chocolate/badrequest?q=coffeescript"
- ,
- body: /Error/
- status: 500
- , (res) ->
- "Test Case #6 - Chocolate timbit requesting a view that can not be found (500 Error)\n"
-
-## Test Case #7 - Dutchie timbit which uses the fetch callback to re-route these calls through the chocolate timbit with views
- "test the dutchie timbit which implements the fetch callback to re-route calls here to the chocolate timbit with views": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/dutchie/alternate?q=nodejs"
- ,
- body: /Alternate dutchie Timbit View/
- status: 200
- , (res) ->
- "Test Case #7 - Dutchie timbit which uses the fetch callback to re-route these calls through the chocolate timbit with views\n"
-
-## Test Case #8 - Dutchie timbit which has an invalid path that should generate a 404
- "test the dutchie timbit with an invalid path in the request": (beforeExit) ->
- calls = 0
- assert.response server,
- url: "/dutchie/another/nodejs/alternate"
- ,
- status: 404
- , (res) ->
- "Test Case #8 - Dutchie timbit which has an invalid path that should generate a 404\n"
View
58 src/timbits.coffee
@@ -13,7 +13,7 @@ request = require 'request'
jsonp = require 'jsonp-filter'
less = require 'connect-less'
-config = { appName: "Timbits", engine: "coffee", port: 5678, home: process.cwd(), maxAge: 60 }
+config = { appName: "Timbits", engine: "coffee", port: 5678, home: process.cwd(), maxAge: 60, secret: "secret" }
server = {}
log = new Log()
@@ -37,14 +37,13 @@ log = new Log()
@server.configure =>
@server.use express.bodyParser()
@server.use express.cookieParser()
- @server.use express.session({ secret: "secret" })
+ @server.use express.session({ secret: config.secret })
@server.use jsonp.setupJSONP()
@server.use connectESI.setupESI()
- @server.use express.static("#{config.home}/public")
+ @server.use express.static(path.join(config.home, "public"))
@server.use express.static(path.join(path.dirname(__filename),"../resources"))
- @server.use assets({src:"#{config.home}/public"}) # serve static files or compile coffee and serve js
- @server.use assets({src:"#{config.home}/views"})
- @server.use less({src:"#{config.home}/public"})
+ @server.use assets({src: path.join(config.home, "public")}) # serve static files or compile coffee and serve js
+ @server.use less({src: path.join(config.home, "public")})
@server.configure 'development', =>
@server.use express.errorHandler({ dumpExceptions: true, showStack: true })
@@ -79,16 +78,16 @@ log = new Log()
res.end master
# automagically load helpers found in the ./helpers folder
- helper_path = "#{config.home}/helpers"
+ helper_path = path.join(config.home, "helpers")
helpers = {}
fs.readdir helper_path, (err, files) =>
- throw err if err
- for file in files
- if file.match(/\.(coffee|js)$/)?
- helper_name = file.substring(0, file.lastIndexOf("."))
- log.info "Loading dynamic helpers: #{helper_name}"
- helpers[helper_name] = require("#{helper_path}/#{file}")
- @server.helpers helpers
+ if not err?
+ for file in files
+ if file.match(/\.(coffee|js)$/)?
+ helper_name = file.substring(0, file.lastIndexOf("."))
+ log.info "Loading dynamic helpers: #{helper_name}"
+ helpers[helper_name] = require(path.join(helper_path, file))
+ @server.helpers helpers
# automagically load timbits found in the ./timbits folder
timbit_path = "#{config.home}/timbits"
@@ -96,7 +95,7 @@ log = new Log()
throw err if err
for file in files
if file.match(/\.(coffee|js)$/)?
- @add file.substring(0, file.lastIndexOf(".")), require("#{timbit_path}/#{file}")
+ @add file.substring(0, file.lastIndexOf(".")), require( path.join(timbit_path, file))
# starts the server
try
@@ -198,32 +197,7 @@ class @Timbit
res.setHeader "Cache-Control", "max-age=#{context.maxAge}"
res.setHeader "Edge-Control", "max-age=#{context.maxAge}"
- if context.remote is 'true'
- output = """
- context_#{context.esi_id} = #{JSON.stringify(context)};
- var views = views || {};
- if (views['#{context.view}'] || false) {
- render = CoffeeKup.render(views['#{context.view}'], context_#{context.esi_id});
- #{if context.esi_id? then "$('##{context.esi_id}').html(render)" else "$('body').append(render)"};
- }
- else {
- $.ajax({
- url: "http://#{req.headers.host}/#{context.view}.coffee?json=true&callback=?",
- dataType: "jsonp",
- cache: true,
- jsonpCallback: "#{context.view.replace(/\//,'_')}",
- success: function(data, textStatus, jqXHR){
- views['#{context.view}'] = data; //save view for reuse
- render = CoffeeKup.render(views['#{context.view}'], context_#{context.esi_id});
- #{if context.esi_id? then "$('##{context.esi_id}').html(render)" else "$('body').append(render)"};
- }
- });
- }
- """
- res.setHeader "Content-Type", "text/javascript"
- res.write output
- res.end()
- else if /^\w+\/json$/.test(context.view)
+ if /^\w+\/json$/.test(context.view)
res.json context
else
res.render context.view, context
@@ -253,7 +227,7 @@ class @Timbit
# this method returns a list of views available to this timbit
listviews: (callback) ->
view = []
- fs.readdir "#{config.home}/views/#{@viewBase}", (err,list) ->
+ fs.readdir path.join(config.home, 'views', @viewBase), (err,list) ->
if err || list is undefined
view.push 'default' # We will attempt the default view anyway and hope the timbit knows what it is doing.
else
View
72 test/timbits-test.coffee
@@ -0,0 +1,72 @@
+timbits = require '../src/timbits'
+vows = require 'vows'
+assert = require 'assert'
+path = require 'path'
+request = require 'request'
+
+homeFolder = path.join("#{process.cwd()}", "examples")
+port = 8785
+
+server = timbits.serve( {home: homeFolder, port: port })
+
+assertStatus = (code) ->
+ return (err, res) ->
+ assert.isNull err
+ assert.equal res.statusCode, code
+
+respondsWith = (status) ->
+ context = {
+ topic: ->
+ req = @context.name.split(' ')
+ method = req[0].toLowerCase()
+ path = req[1]
+ uri = "http://localhost:#{port}#{path}"
+ console.log uri
+
+ request[method] uri, @callback
+ return
+ }
+
+ context["should respond with a #{status}"] = assertStatus(status)
+ return context
+
+vows
+ .describe('timbits')
+ .addBatch
+ 'inspect loaded timbits':
+ topic: timbits.box
+
+ 'should contain four timbits': (box) ->
+ assert.equal Object.keys(box).length, 4
+
+ #test main help page
+ 'GET /timbits/help': respondsWith 200
+
+ #test json directory
+ 'GET /timbits/json': respondsWith 200
+
+ #test individual help pages
+ 'GET /plain/help': respondsWith 200
+ 'GET /cherry/help': respondsWith 200
+ 'GET /chocolate/help': respondsWith 200
+ 'GET /dutchie/help': respondsWith 200
+
+ #execute automated test pages
+ 'GET /plain/test': respondsWith 200
+ 'GET /cherry/test': respondsWith 200
+ 'GET /chocolate/test': respondsWith 200
+ 'GET /dutchie/test': respondsWith 200
+
+ #retrieve json view
+ 'GET /plain/json': respondsWith 200
+
+ #retrieve an non-existant timbit
+ 'GET /fake': respondsWith 404
+
+ #use an non-existant view
+ 'GET /plain/fake': respondsWith 500
+
+ #enforcement of required parameters
+ 'GET /chocolate': respondsWith 500
+
+ .export module
Please sign in to comment.
Something went wrong with that request. Please try again.