<commit_before>var stringWidth = require('string-width')
var stripAnsi = require('strip-ansi')
var wrap = require('wrap-ansi')
var align = {
  right: alignRight,
  center: alignCenter
}
var top = 0
var right = 1
var bottom = 2
var left = 3

function UI (opts) {
  this.width = opts.width
  this.wrap = opts.wrap
  this.rows = []
}

UI.prototype.span = function () {
  var cols = this.div.apply(this, arguments)
  cols.span = true
}

UI.prototype.div = function () {
  if (arguments.length === 0) this.div('')
  if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
    return this._applyLayoutDSL(arguments[0])
  }

  var cols = []

  for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
    if (typeof arg === 'string') cols.push(this._colFromString(arg))
    else cols.push(arg)
  }

  this.rows.push(cols)
  return cols
}

UI.prototype._shouldApplyLayoutDSL = function () {
  return arguments.length === 1 && typeof arguments[0] === 'string' &&
    /[\t\n]/.test(arguments[0])
}

UI.prototype._applyLayoutDSL = function (str) {
  var _this = this
  var rows = str.split('\n')
  var leftColumnWidth = 0

  // simple heuristic for layout, make sure the
  // second column lines up along the left-hand.
  // don't allow the first column to take up more
  // than 50% of the screen.
  rows.forEach(function (row) {
    var columns = row.split('\t')
    if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
      leftColumnWidth = Math.min(
        Math.floor(_this.width * 0.5),
        stringWidth(columns[0])
      )
    }
  })

  // generate a table:
  //  replacing ' ' with padding calculations.
  //  using the algorithmically generated width.
  rows.forEach(function (row) {
    var columns = row.split('\t')
    _this.div.apply(_this, columns.map(function (r, i) {
      return {
        text: r.trim(),
        padding: _this._measurePadding(r),
        width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
      }
    }))
  })

  return this.rows[this.rows.length - 1]
}

UI.prototype._colFromString = function (str) {
  return {
    text: str,
    padding: this._measurePadding(str)
  }
}

UI.prototype._measurePadding = function (str) {
  // measure padding without ansi escape codes
  var noAnsi = stripAnsi(str)
  return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
}

UI.prototype.toString = function () {
  var _this = this
  var lines = []

  _this.rows.forEach(function (row, i) {
    _this.rowToString(row, lines)
  })

  // don't display any lines with the
  // hidden flag set.
  lines = lines.filter(function (line) {
    return !line.hidden
  })

  return lines.map(function (line) {
    return line.text
  }).join('\n')
}

UI.prototype.rowToString = function (row, lines) {
  var _this = this
  var padding
  var rrows = this._rasterize(row)
  var str = ''
  var ts
  var width
  var wrapWidth

  rrows.forEach(function (rrow, r) {
    str = ''
    rrow.forEach(function (col, c) {
      ts = '' // temporary string used during alignment/padding.
      width = row[c].width // the width with padding.
      wrapWidth = _this._negatePadding(row[c]) // the width without padding.

      ts += col

      for (var i = 0; i < wrapWidth - stringWidth(col); i++) {
        ts += ' '
      }

      // align the string within its column.
      if (row[c].align && row[c].align !== 'left' && _this.wrap) {
        ts = align[row[c].align](ts, wrapWidth)
        if (stringWidth(ts) < wrapWidth) ts += new Array(width - stringWidth(ts)).join(' ')
      }

      // apply border and padding to string.
      padding = row[c].padding || [0, 0, 0, 0]
      if (padding[left]) str += new Array(padding[left] + 1).join(' ')
      str += addBorder(row[c], ts, '| ')
      str += ts
      str += addBorder(row[c], ts, ' |')
      if (padding[right]) str += new Array(padding[right] + 1).join(' ')

      // if prior row is span, try to render the
      // current row on the prior line.
      if (r === 0 && lines.length > 0) {
        str = _this._renderInline(str, lines[lines.length - 1])
      }
    })

    // remove trailing whitespace.
    lines.push({
      text: str.replace(/ +$/, ''),
      span: row.span
    })
  })

  return lines
}

function addBorder (row, ts, style) {
  if (row.border) {
    if (/[.']-+[.']/.test(ts)) return ''
    else if (ts.trim().length) return style
    else return '  '
  }
  return ''
}

// if the full 'source' can render in
// the target line, do so.
UI.prototype._renderInline = function (source, previousLine) {
  var leadingWhitespace = source.match(/^ */)[0].length
  var target = previousLine.text
  var targetTextWidth = stringWidth(target.trimRight())

  if (!previousLine.span) return source

  // if we're not applying wrapping logic,
  // just always append to the span.
  if (!this.wrap) {
    previousLine.hidden = true
    return target + source
  }

  if (leadingWhitespace < targetTextWidth) return source

  previousLine.hidden = true

  return target.trimRight() + new Array(leadingWhitespace - targetTextWidth + 1).join(' ') + source.trimLeft()
}

UI.prototype._rasterize = function (row) {
  var _this = this
  var i
  var rrow
  var rrows = []
  var widths = this._columnWidths(row)
  var wrapped

  // word wrap all columns, and create
  // a data-structure that is easy to rasterize.
  row.forEach(function (col, c) {
    // leave room for left and right padding.
    col.width = widths[c]
    if (_this.wrap) wrapped = wrap(col.text, _this._negatePadding(col), {hard: true}).split('\n')
    else wrapped = col.text.split('\n')

    if (col.border) {
      wrapped.unshift('.' + new Array(_this._negatePadding(col) + 3).join('-') + '.')
      wrapped.push("'" + new Array(_this._negatePadding(col) + 3).join('-') + "'")
    }

    // add top and bottom padding.
    if (col.padding) {
      for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
      for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
    }

    wrapped.forEach(function (str, r) {
      if (!rrows[r]) rrows.push([])

      rrow = rrows[r]

      for (var i = 0; i < c; i++) {
        if (rrow[i] === undefined) rrow.push('')
      }
      rrow.push(str)
    })
  })

  return rrows
}

UI.prototype._negatePadding = function (col) {
  var wrapWidth = col.width
  if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
  if (col.border) wrapWidth -= 4
  return wrapWidth
}

UI.prototype._columnWidths = function (row) {
  var _this = this
  var widths = []
  var unset = row.length
  var unsetWidth
  var remainingWidth = this.width

  // column widths can be set in config.
  row.forEach(function (col, i) {
    if (col.width) {
      unset--
      widths[i] = col.width
      remainingWidth -= col.width
    } else {
      widths[i] = undefined
    }
  })

  // any unset widths should be calculated.
  if (unset) unsetWidth = Math.floor(remainingWidth / unset)
  widths.forEach(function (w, i) {
    if (!_this.wrap) widths[i] = row[i].width || stringWidth(row[i].text)
    else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
  })

  return widths
}

// calculates the minimum width of
// a column, based on padding preferences.
function _minWidth (col) {
  var padding = col.padding || []
  var minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
  if (col.border) minWidth += 4
  return minWidth
}

function alignRight (str, width) {
  str = str.trim()
  var padding = ''
  var strWidth = stringWidth(str)

  if (strWidth < width) {
    padding = new Array(width - strWidth + 1).join(' ')
  }

  return padding + str
}

function alignCenter (str, width) {
  str = str.trim()
  var padding = ''
  var strWidth = stringWidth(str.trim())

  if (strWidth < width) {
    padding = new Array(parseInt((width - strWidth) / 2, 10) + 1).join(' ')
  }

  return padding + str
}

module.exports = function (opts) {
  opts = opts || {}

  return new UI({
    width: (opts || {}).width || 80,
    wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
  })
}
<commit_msg>variable is actually a column not a row<commit_after>var stringWidth = require('string-width')
var stripAnsi = require('strip-ansi')
var wrap = require('wrap-ansi')
var align = {
  right: alignRight,
  center: alignCenter
}
var top = 0
var right = 1
var bottom = 2
var left = 3

function UI (opts) {
  this.width = opts.width
  this.wrap = opts.wrap
  this.rows = []
}

UI.prototype.span = function () {
  var cols = this.div.apply(this, arguments)
  cols.span = true
}

UI.prototype.div = function () {
  if (arguments.length === 0) this.div('')
  if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
    return this._applyLayoutDSL(arguments[0])
  }

  var cols = []

  for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
    if (typeof arg === 'string') cols.push(this._colFromString(arg))
    else cols.push(arg)
  }

  this.rows.push(cols)
  return cols
}

UI.prototype._shouldApplyLayoutDSL = function () {
  return arguments.length === 1 && typeof arguments[0] === 'string' &&
    /[\t\n]/.test(arguments[0])
}

UI.prototype._applyLayoutDSL = function (str) {
  var _this = this
  var rows = str.split('\n')
  var leftColumnWidth = 0

  // simple heuristic for layout, make sure the
  // second column lines up along the left-hand.
  // don't allow the first column to take up more
  // than 50% of the screen.
  rows.forEach(function (row) {
    var columns = row.split('\t')
    if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
      leftColumnWidth = Math.min(
        Math.floor(_this.width * 0.5),
        stringWidth(columns[0])
      )
    }
  })

  // generate a table:
  //  replacing ' ' with padding calculations.
  //  using the algorithmically generated width.
  rows.forEach(function (row) {
    var columns = row.split('\t')
    _this.div.apply(_this, columns.map(function (r, i) {
      return {
        text: r.trim(),
        padding: _this._measurePadding(r),
        width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
      }
    }))
  })

  return this.rows[this.rows.length - 1]
}

UI.prototype._colFromString = function (str) {
  return {
    text: str,
    padding: this._measurePadding(str)
  }
}

UI.prototype._measurePadding = function (str) {
  // measure padding without ansi escape codes
  var noAnsi = stripAnsi(str)
  return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
}

UI.prototype.toString = function () {
  var _this = this
  var lines = []

  _this.rows.forEach(function (row, i) {
    _this.rowToString(row, lines)
  })

  // don't display any lines with the
  // hidden flag set.
  lines = lines.filter(function (line) {
    return !line.hidden
  })

  return lines.map(function (line) {
    return line.text
  }).join('\n')
}

UI.prototype.rowToString = function (row, lines) {
  var _this = this
  var padding
  var rrows = this._rasterize(row)
  var str = ''
  var ts
  var width
  var wrapWidth

  rrows.forEach(function (rrow, r) {
    str = ''
    rrow.forEach(function (col, c) {
      ts = '' // temporary string used during alignment/padding.
      width = row[c].width // the width with padding.
      wrapWidth = _this._negatePadding(row[c]) // the width without padding.

      ts += col

      for (var i = 0; i < wrapWidth - stringWidth(col); i++) {
        ts += ' '
      }

      // align the string within its column.
      if (row[c].align && row[c].align !== 'left' && _this.wrap) {
        ts = align[row[c].align](ts, wrapWidth)
        if (stringWidth(ts) < wrapWidth) ts += new Array(width - stringWidth(ts)).join(' ')
      }

      // apply border and padding to string.
      padding = row[c].padding || [0, 0, 0, 0]
      if (padding[left]) str += new Array(padding[left] + 1).join(' ')
      str += addBorder(row[c], ts, '| ')
      str += ts
      str += addBorder(row[c], ts, ' |')
      if (padding[right]) str += new Array(padding[right] + 1).join(' ')

      // if prior row is span, try to render the
      // current row on the prior line.
      if (r === 0 && lines.length > 0) {
        str = _this._renderInline(str, lines[lines.length - 1])
      }
    })

    // remove trailing whitespace.
    lines.push({
      text: str.replace(/ +$/, ''),
      span: row.span
    })
  })

  return lines
}

function addBorder (col, ts, style) {
  if (col.border) {
    if (/[.']-+[.']/.test(ts)) return ''
    else if (ts.trim().length) return style
    else return '  '
  }
  return ''
}

// if the full 'source' can render in
// the target line, do so.
UI.prototype._renderInline = function (source, previousLine) {
  var leadingWhitespace = source.match(/^ */)[0].length
  var target = previousLine.text
  var targetTextWidth = stringWidth(target.trimRight())

  if (!previousLine.span) return source

  // if we're not applying wrapping logic,
  // just always append to the span.
  if (!this.wrap) {
    previousLine.hidden = true
    return target + source
  }

  if (leadingWhitespace < targetTextWidth) return source

  previousLine.hidden = true

  return target.trimRight() + new Array(leadingWhitespace - targetTextWidth + 1).join(' ') + source.trimLeft()
}

UI.prototype._rasterize = function (row) {
  var _this = this
  var i
  var rrow
  var rrows = []
  var widths = this._columnWidths(row)
  var wrapped

  // word wrap all columns, and create
  // a data-structure that is easy to rasterize.
  row.forEach(function (col, c) {
    // leave room for left and right padding.
    col.width = widths[c]
    if (_this.wrap) wrapped = wrap(col.text, _this._negatePadding(col), {hard: true}).split('\n')
    else wrapped = col.text.split('\n')

    if (col.border) {
      wrapped.unshift('.' + new Array(_this._negatePadding(col) + 3).join('-') + '.')
      wrapped.push("'" + new Array(_this._negatePadding(col) + 3).join('-') + "'")
    }

    // add top and bottom padding.
    if (col.padding) {
      for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
      for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
    }

    wrapped.forEach(function (str, r) {
      if (!rrows[r]) rrows.push([])

      rrow = rrows[r]

      for (var i = 0; i < c; i++) {
        if (rrow[i] === undefined) rrow.push('')
      }
      rrow.push(str)
    })
  })

  return rrows
}

UI.prototype._negatePadding = function (col) {
  var wrapWidth = col.width
  if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
  if (col.border) wrapWidth -= 4
  return wrapWidth
}

UI.prototype._columnWidths = function (row) {
  var _this = this
  var widths = []
  var unset = row.length
  var unsetWidth
  var remainingWidth = this.width

  // column widths can be set in config.
  row.forEach(function (col, i) {
    if (col.width) {
      unset--
      widths[i] = col.width
      remainingWidth -= col.width
    } else {
      widths[i] = undefined
    }
  })

  // any unset widths should be calculated.
  if (unset) unsetWidth = Math.floor(remainingWidth / unset)
  widths.forEach(function (w, i) {
    if (!_this.wrap) widths[i] = row[i].width || stringWidth(row[i].text)
    else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
  })

  return widths
}

// calculates the minimum width of
// a column, based on padding preferences.
function _minWidth (col) {
  var padding = col.padding || []
  var minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
  if (col.border) minWidth += 4
  return minWidth
}

function alignRight (str, width) {
  str = str.trim()
  var padding = ''
  var strWidth = stringWidth(str)

  if (strWidth < width) {
    padding = new Array(width - strWidth + 1).join(' ')
  }

  return padding + str
}

function alignCenter (str, width) {
  str = str.trim()
  var padding = ''
  var strWidth = stringWidth(str.trim())

  if (strWidth < width) {
    padding = new Array(parseInt((width - strWidth) / 2, 10) + 1).join(' ')
  }

  return padding + str
}

module.exports = function (opts) {
  opts = opts || {}

  return new UI({
    width: (opts || {}).width || 80,
    wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
  })
}
<|endoftext|>


<commit_before>/**
 * Created by Scott on 2/25/2015.
 */
define(['testharness', '../lib/request', '../lib/SQLish'],
    function(harness, request, SQLish) {
        return {
            run: function () {
                "use strict";

                var db, table, query;

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    harness.assert_true(SQLish.getDB('Library') !== undefined);
                }, "CREATE DATABASE Library  => happens in each test, checking here");

                harness.test(function () {
                    db = SQLish.dropDB('Library');
                    harness.assert_true(db && SQLish.getDB('Library') === undefined);
                }, "DROP DATABASE Library  => happens in each test, checking here");

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    table = db.createTable('Books')('title');
                    harness.assert_true(table.hasOwnProperty('title'));
                    db = SQLish.dropDB('Library');
                }, "CREATE TABLE Books (title)");

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    db.createTable('Books')('title');
                    db.insertInto('Books')('title').values('Book of Foo');
                    query = db.select('title').from('Books')();
                    harness.assert_true(query[0].title === 'Book of Foo');
                    db = SQLish.dropDB('Library');
                }, "INSERT INTO Books (title) VALUES ('Book of Foo')");

                // setup for next test
                db = SQLish.createDB('Library');
                table = db.createTable('Books')('title');

                harness.test(function () {
                    var insertValues = db.insertInto('Books')('title').values('Alphabet Soup')('Aliens')('Baseball')('Bats')('Cats')('Soup for the Soul'),
                        testPassed = false,
                        titlesArray;

                    titlesArray = db.select('title').from('Books')();
                    testPassed = titlesArray.every(function (rowObj) {
                        var title = rowObj.title,
                            a = ['Alphabet Soup', 'Aliens', 'Baseball', 'Bats', 'Cats', 'Soup for the Soul'];

                        return title && a.indexOf(title) >= 0;
                    });
                    harness.assert_true(testPassed);
                    // do not tear down Library
                }, "INSERT INTO Books (title) VALUES ('Alphabet Soup'),('Aliens'),('Baseball'),('Bats'),('Cats'),('Soup for the Soul')");

                // next test uses prerequisites from previous test...
                harness.test(function () {
                    query = db.select('title').from('Books').where('title', '===', 'Aliens');
                    harness.assert_true(query[0] && query[0].title === 'Aliens');
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title = 'Aliens'");

                // keep going...
                harness.test(function () {
                    var where,
                        returnSet,
                        passedTest = false;

                    query = db.select('title').from('Books');
                    where = query.where;
                    returnSet = where('title', 'like', 'soup');
                    passedTest = returnSet.length === 0;
                    if (passedTest) {
                        returnSet = where('title', 'like', '.*soup');
                        passedTest = returnSet.length === 1 && returnSet[0].title === 'Alphabet Soup';
                    }
                    if (passedTest) {
                        returnSet = where('title', 'like', 'ba.*');
                        passedTest = returnSet.length === 2 && returnSet[0].title === 'Baseball' && returnSet[1].title === 'Bats';
                    }
                    if (passedTest) {
                        returnSet = where('title', 'like', '.*ou.*ou.*');
                        passedTest = returnSet.length === 1 && returnSet[0].title === 'Soup for the Soul';
                    }
                    harness.assert_true(passedTest);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title LIKE %ou%ou%  => plus 3 more 'LIKE' tests");

                harness.test(function () {
                    var where = query.where,
                        returnSet,
                        passedTest = false;

                    returnSet = where('title', 'not like', '.*b.*');
                    passedTest = returnSet.length === 3 && returnSet[0].title === 'Aliens' && returnSet[1].title === 'Cats' && returnSet[2].title === 'Soup for the Soul';
                    harness.assert_true(passedTest);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title NOT LIKE %b%");

                harness.test(function () {
                    query = db.select('*').from('Books')();
                    harness.assert_true(query.length === 6);
                    db = SQLish.dropDB('Library');
                }, "SELECT * FROM Books");

                // setup for next test
                db = SQLish.createDB('Library');
                table = db.createTable('Books')('title', 'author');

                harness.test(function () {
                    var testPassed = false,
                        returnSet;

                    db.insertInto('Books')('title', 'author').values('Baseball', 'Hank Aaron')('Alphabet Soup', 'Abe Jones')('Aliens', 'Corey Dorey')
                                                                    ('Baseball', 'Hank Aaron')('Bats', 'Creepy Guy')('Cats', 'Kaitlyn Rose')
                                                                    ('Soup for the Soul', 'Flora Ivy');
                    returnSet = db.select('title').from('Books').where('author', 'like', '.*o.*s.*');
                    testPassed = returnSet.length === 2 && returnSet[0].title === 'Alphabet Soup' && returnSet[1].title === 'Cats';
                    harness.assert_true(testPassed);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE author LIKE %o%s%  => condition based on field not in SELECT");

                harness.test(function () {
                    db.update('Books').set('title', 'Green Eggs & Ham')('author', 'Dr. Seuss').where('title', '===', 'Bats');
                    query = db.select('title', 'author').from('Books')();
                    harness.assert_true(query && query.length && query.length === 7 && query[4].title === 'Green Eggs & Ham' && query[4].author === 'Dr. Seuss');
                    //db = SQLish.dropDB('Library');
                }, "UPDATE Books SET title = 'Green Eggs & Ham', author = 'Dr. Seuss' WHERE title = 'Bats'");
            }
        };
    }
);
<commit_msg>SQLishTest - new tests for AND OR in where statements<commit_after>/**
 * Created by Scott on 2/25/2015.
 */
define(['testharness', '../lib/request', '../lib/SQLish'],
    function(harness, request, SQLish) {
        return {
            run: function () {
                "use strict";

                var db, table, query;

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    harness.assert_true(SQLish.getDB('Library') !== undefined);
                }, "CREATE DATABASE Library  => happens in each test, checking here");

                harness.test(function () {
                    db = SQLish.dropDB('Library');
                    harness.assert_true(db && SQLish.getDB('Library') === undefined);
                }, "DROP DATABASE Library  => happens in each test, checking here");

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    table = db.createTable('Books')('title');
                    harness.assert_true(table.hasOwnProperty('title'));
                    db = SQLish.dropDB('Library');
                }, "CREATE TABLE Books (title)");

                harness.test(function () {
                    db = SQLish.createDB('Library');
                    db.createTable('Books')('title');
                    db.insertInto('Books')('title').values('Book of Foo');
                    query = db.select('title').from('Books').go();
                    harness.assert_true(query[0].title === 'Book of Foo');
                    db = SQLish.dropDB('Library');
                }, "INSERT INTO Books (title) VALUES ('Book of Foo')");

                // setup for next test
                db = SQLish.createDB('Library');
                table = db.createTable('Books')('title');

                harness.test(function () {
                    var insertValues = db.insertInto('Books')('title').values('Alphabet Soup')('Aliens')('Baseball')('Bats')('Cats')('Soup for the Soul'),
                        testPassed = false,
                        titlesArray;

                    titlesArray = db.select('title').from('Books').go();
                    testPassed = titlesArray.every(function (rowObj) {
                        var title = rowObj.title,
                            a = ['Alphabet Soup', 'Aliens', 'Baseball', 'Bats', 'Cats', 'Soup for the Soul'];

                        return title && a.indexOf(title) >= 0;
                    });
                    harness.assert_true(testPassed);
                    // do not tear down Library
                }, "INSERT INTO Books (title) VALUES ('Alphabet Soup'),('Aliens'),('Baseball'),('Bats'),('Cats'),('Soup for the Soul')");

                // next test uses prerequisites from previous test...
                harness.test(function () {
                    query = db.select('title').from('Books').where('title', '===', 'Aliens').go();
                    harness.assert_true(query[0] && query[0].title === 'Aliens');
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title = 'Aliens'");

                // keep going...
                harness.test(function () {
                    var where,
                        returnSet,
                        passedTest = false;

                    query = db.select('title').from('Books');
                    where = query.where;
                    returnSet = where('title', 'like', 'soup').go();
                    passedTest = returnSet.length === 0;
                    if (passedTest) {
                        returnSet = where('title', 'like', '.*soup').go();
                        passedTest = returnSet.length === 1 && returnSet[0].title === 'Alphabet Soup';
                    }
                    if (passedTest) {
                        returnSet = where('title', 'like', 'ba.*').go();
                        passedTest = returnSet.length === 2 && returnSet[0].title === 'Baseball' && returnSet[1].title === 'Bats';
                    }
                    if (passedTest) {
                        returnSet = where('title', 'like', '.*ou.*ou.*').go();
                        passedTest = returnSet.length === 1 && returnSet[0].title === 'Soup for the Soul';
                    }
                    harness.assert_true(passedTest);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title LIKE %ou%ou%  => plus 3 more 'LIKE' tests");

                harness.test(function () {
                    var where = query.where,
                        returnSet,
                        passedTest = false;

                    returnSet = where('title', 'not like', '.*b.*').go();
                    passedTest = returnSet.length === 3 && returnSet[0].title === 'Aliens' && returnSet[1].title === 'Cats' && returnSet[2].title === 'Soup for the Soul';
                    harness.assert_true(passedTest);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE title NOT LIKE %b%");

                harness.test(function () {
                    query = db.select('*').from('Books').go();
                    harness.assert_true(query.length === 6);
                    db = SQLish.dropDB('Library');
                }, "SELECT * FROM Books");

                // setup for next test
                db = SQLish.createDB('Library');
                table = db.createTable('Books')('title', 'author');

                harness.test(function () {
                    var testPassed = false,
                        returnSet;

                    db.insertInto('Books')('title', 'author').values('Baseball', 'Hank Aaron')('Alphabet Soup', 'Abe Jones')('Aliens', 'Corey Dorey')
                                                                    ('Coffee Break', 'Bob Aaron')('Bats', 'Creepy Guy')('Cats', 'Kaitlyn Rose')
                                                                    ('Soup for the Soul', 'Flora Ivy');
                    returnSet = db.select('title').from('Books').where('author', 'like', '.*o.*s.*').go();
                    testPassed = returnSet.length === 2 && returnSet[0].title === 'Alphabet Soup' && returnSet[1].title === 'Cats';
                    harness.assert_true(testPassed);
                    // do not tear down Library
                }, "SELECT title FROM Books WHERE author LIKE %o%s%  => condition based on field not in SELECT");

                harness.test(function () {
                    db.update('Books').set('title', 'Green Eggs & Ham')('author', 'Dr. Seuss').where('title', '===', 'Bats').go();
                    query = db.select('title', 'author').from('Books').go();
                    harness.assert_true(query.length === 7 && query[4].title === 'Green Eggs & Ham' && query[4].author === 'Dr. Seuss');
                    //db = SQLish.dropDB('Library');
                }, "UPDATE Books SET title = 'Green Eggs & Ham', author = 'Dr. Seuss' WHERE title = 'Bats'");

                harness.test(function() {
                    query = db.select('title').from('Books').where('title', 'like', '.*break').and('author', 'like', '.*Aaron').go();
                    harness.assert_true(query[0].title === 'Coffee Break');
                }, "SELECT title FROM Books WHERE title like %break AND author like %Aaron");

                harness.test(function() {
                    query = db.select('title').from('Books').where('title', '===', 'Aliens').or('author', '===', 'Kaitlyn Rose').go();
                    harness.assert_true(query.length === 2 && query[0].title === 'Aliens' && query[1].title === 'Cats');
                }, "SELECT title FROM Books WHERE title = 'Aliens' OR author = 'Kaitlyn Rose'");
            }
        };
    }
);
<|endoftext|>


<commit_before>var Q = require("q");
var util = require("util");

module.exports = Theatre;

function Theatre() {
  this._instances = new WeakMap();
  this._overrides = new WeakMap();
}

/**
 * Resolves the dependencies for a class and then instantiates the class.
 *
 * @param {Function|Array.<Function>} classy Class or array of classes to instantiate
 * @returns {Promise.<Object>|Promise.<Array.<Object>>} Instance or array of instances
 */
Theatre.prototype.resolve = function (classy) {
  if (util.isArray(classy))
    return this._resolveAll(classy);

  if (this._overrides.has(classy))
    classy = this._overrides.get(classy);

  var cyclePath = this._detectCycle(classy);
  if (cyclePath !== false)
    return Q.reject(this._createCycleDetectedError(cyclePath));

  var singleton = false;
  var dependencies = [];

  if (typeof classy.__theatre !== "undefined") {
    if (typeof classy.__theatre.single !== "undefined")
      singleton = classy.__theatre.single;

    if (typeof classy.__theatre.inject !== "undefined")
      dependencies = classy.__theatre.inject;
  }

  // If this class is a singleton and we already have an instance, return the instance
  if (singleton && this._instances.has(classy))
    return this._instances.get(classy);

  // After the dependencies are resolved, instantiate the class
  var instancePromise = this._resolveAll(dependencies)
    .then(function (resolved) {
      var tmpClass = function () {};
      tmpClass.prototype = classy.prototype;
      var instance = new tmpClass();
      var maybePromise = classy.apply(instance, resolved);
      instance.constructor = classy;

      return Q(maybePromise)
        .thenResolve(instance);
    });

  if (singleton)
    this._instances.set(classy, instancePromise);

  return instancePromise;
};

/**
 * Resolves an array of promises.
 *
 * @param {Array} classes Array of classes to resolve.
 * @returns {Promise.<Array.<Object>>} Array of instances.
 * @private
 */
Theatre.prototype._resolveAll = function (classes) {
  classes = classes.map(function (classy) {
    return this.resolve(classy);
  }, this);

  return Q.all(classes);
};

/**
 * Adds an override for a class.
 *
 * @param {Function} oldClass Class to be overridden.
 * @param {Function} newClass New class to override the old one with.
 */
Theatre.prototype.addOverride = function (oldClass, newClass) {
  this._overrides.set(oldClass, newClass);
};

/**
 * Removes an override for a class.
 *
 * @param {Function} oldClass Overridden class to be returned to normal.
 */
Theatre.prototype.removeOverride = function (oldClass) {
  this._overrides.delete(oldClass);
};

/**
 * Removes all overrides.
 */
Theatre.prototype.removeAllOverrides = function () {
  // Weakmap#clear() was removed, so we just create a new WeakMap
  this._overrides = new WeakMap();
};

/**
 * Detects cycles in the dependencies of classes.
 *
 * @param {Function} classy Class to check the dependency list for.
 * @param {Array} [ancestors] Ancestors of the class.
 * @returns {boolean|Array.<Function>} The path if a cycle was found, otherwise false.
 * @private
 */
Theatre.prototype._detectCycle = function (classy, ancestors) {
  if (typeof ancestors === "undefined") {
    ancestors = [];
  } else if (ancestors.indexOf(classy) != -1) {
    var path = ancestors.slice(ancestors.indexOf(classy));
    path.push(classy);
    return path;
  }

  if (classy.__theatre && classy.__theatre.inject) {
    var dependencies = classy.__theatre.inject;

    ancestors = ancestors.slice(0);
    ancestors.push(classy);

    for (var i = 0, result; i < dependencies.length; i++) {
      result = this._detectCycle(dependencies[i], ancestors);
      if (result !== false)
        return result;
    }
  }

  return false;
};

Theatre.prototype._createCycleDetectedError = function (path) {
  path = path.map(function (classy) {
    return classy.name || "Anonymous";
  }).join(" -> ");

  return new Error("Cycle detected in class dependencies: " + path);
};<commit_msg>Update comments<commit_after>var Q = require("q");
var util = require("util");

module.exports = Theatre;

function Theatre() {
  this._instances = new WeakMap();
  this._overrides = new WeakMap();
}

/**
 * Resolves the dependencies for a class and then instantiates the class.
 *
 * @param {Function|Array.<Function>} classy Class or array of classes to instantiate
 * @returns {Promise.<Object>|Promise.<Array.<Object>>} Instance or array of instances
 */
Theatre.prototype.resolve = function (classy) {
  if (util.isArray(classy))
    return this._resolveAll(classy);

  if (this._overrides.has(classy))
    classy = this._overrides.get(classy);

  var cyclePath = this._detectCycle(classy);
  if (cyclePath !== false)
    return Q.reject(this._createCycleDetectedError(cyclePath));

  var singleton = false;
  var dependencies = [];

  if (typeof classy.__theatre !== "undefined") {
    if (typeof classy.__theatre.single !== "undefined")
      singleton = classy.__theatre.single;

    if (typeof classy.__theatre.inject !== "undefined")
      dependencies = classy.__theatre.inject;
  }

  // If this class is a singleton and we already have a promise for an instance, return the promise
  if (singleton && this._instances.has(classy))
    return this._instances.get(classy);

  // After the dependencies are resolved, instantiate the class
  var instancePromise = this._resolveAll(dependencies)
    .then(function (resolved) {
      var tmpClass = function () {};
      tmpClass.prototype = classy.prototype;
      var instance = new tmpClass();
      var maybePromise = classy.apply(instance, resolved);
      instance.constructor = classy;

      return Q(maybePromise)
        .thenResolve(instance);
    });

  if (singleton)
    this._instances.set(classy, instancePromise);

  return instancePromise;
};

/**
 * Resolves an array of promises.
 *
 * @param {Array} classes Array of classes to resolve.
 * @returns {Promise.<Array.<Object>>} Array of instances.
 * @private
 */
Theatre.prototype._resolveAll = function (classes) {
  classes = classes.map(function (classy) {
    return this.resolve(classy);
  }, this);

  return Q.all(classes);
};

/**
 * Adds an override for a class.
 *
 * @param {Function} oldClass Class to be overridden.
 * @param {Function} newClass New class to override the old one with.
 */
Theatre.prototype.addOverride = function (oldClass, newClass) {
  this._overrides.set(oldClass, newClass);
};

/**
 * Removes an override for a class.
 *
 * @param {Function} oldClass Overridden class to be returned to normal.
 */
Theatre.prototype.removeOverride = function (oldClass) {
  this._overrides.delete(oldClass);
};

/**
 * Removes all overrides.
 */
Theatre.prototype.removeAllOverrides = function () {
  // Weakmap#clear() was removed, so we just create a new WeakMap
  this._overrides = new WeakMap();
};

/**
 * Detects cycles in the dependencies of classes.
 *
 * @param {Function} classy Class to check the dependency list for.
 * @param {Array} [ancestors] Ancestors of the class.
 * @returns {boolean|Array.<Function>} The path if a cycle was found, otherwise false.
 * @private
 */
Theatre.prototype._detectCycle = function (classy, ancestors) {
  if (typeof ancestors === "undefined") {
    ancestors = [];
  } else if (ancestors.indexOf(classy) != -1) {
    var path = ancestors.slice(ancestors.indexOf(classy));
    path.push(classy);
    return path;
  }

  if (classy.__theatre && classy.__theatre.inject) {
    var dependencies = classy.__theatre.inject;

    ancestors = ancestors.slice(0);
    ancestors.push(classy);

    for (var i = 0, result; i < dependencies.length; i++) {
      result = this._detectCycle(dependencies[i], ancestors);
      if (result !== false)
        return result;
    }
  }

  return false;
};

Theatre.prototype._createCycleDetectedError = function (path) {
  path = path.map(function (classy) {
    return classy.name || "Anonymous";
  }).join(" -> ");

  return new Error("Cycle detected in class dependencies: " + path);
};<|endoftext|>


<commit_before>/**
 * Dependencies
 */
var _ = require('lodash'),
  util = require('util'),
  Err = require('../../../errors/fatal'),
  onRoute = require('./onRoute'),
  STRINGFILE = require('sails-stringfile');

/**
 * Expose hook definition
 */

module.exports = function(sails) {

  return {

    defaults: {},
    configure: function() {

      // Legacy (< v0.10) support for configured handlers
      if (typeof sails.config[500] === 'function') {
        sails.after('lifted', function() {
          STRINGFILE.logDeprecationNotice('sails.config[500]',
            STRINGFILE.get('links.docs.migrationGuide.responses'),
            sails.log.debug);
          sails.log.debug('sails.config[500] (i.e. `config/500.js`) has been superceded in Sails v0.10.');
          sails.log.debug('Please define a "response" instead. (i.e. api/responses/serverError.js)');
          sails.log.debug('Your old handler is being ignored. (the format has been upgraded in v0.10)');
          sails.log.debug('If you\'d like to use the default handler, just remove this configuration option.');
        });
      }
      if (typeof sails.config[404] === 'function') {
        sails.after('lifted', function() {
          STRINGFILE.logDeprecationNotice('sails.config[404]',
            STRINGFILE.get('links.docs.migrationGuide.responses'),
            sails.log.debug);
          sails.log.debug('Please define a "response" instead. (i.e. api/responses/notFound.js)');
          sails.log.debug('Your old handler is being ignored. (the format has been upgraded in v0.10)');
          sails.log.debug('If you\'d like to use the default handler, just remove this configuration option.');
        });
      }
    },

    /**
     * When this hook is loaded...
     */

    initialize: function(cb) {

      // Register route syntax that allows explicit routes
      // to be bound directly to custom responses by name.
      // (e.g. {response: 'foo'})
      sails.on('route:typeUnknown', onRoute(sails));

      cb();
    },

    /**
     * Fetch relevant modules, exposing them on `sails` subglobal if necessary,
     */
    loadModules: function(cb) {
      var hook = this;

      sails.log.verbose('Loading runtime custom response definitions...');
      sails.modules.loadResponses(function loadedRuntimeErrorModules(err, responseDefs) {
        if (err) return cb(err);

        // Check that the user reserved response methods/properties
        var reservedResKeys = [
          'view',
          'status', 'set', 'get', 'cookie', 'clearCookie', 'redirect',
          'location', 'charset', 'send', 'json', 'jsonp', 'type', 'format',
          'attachment', 'sendfile', 'download', 'links', 'locals', 'render'
        ];

        _.each(Object.keys(responseDefs), function(userResponseKey) {
          if (_.contains(reservedResKeys, userResponseKey)) {
            return Err.invalidCustomResponse(userResponseKey);
          }
        });

        // Ensure that required custom responses exist.
        _.defaults(responseDefs, {
          ok: require('./defaults/ok'),
          created: require('./defaults/created'),
          negotiate: require('./defaults/negotiate'),
          notFound: require('./defaults/notFound'),
          serverError: require('./defaults/serverError'),
          forbidden: require('./defaults/forbidden'),
          badRequest: require('./defaults/badRequest')

          // Example usage:
          // foo: cannotFindResponseWarning('foo', 400)
        });

        // Register blueprint actions as middleware
        hook.middleware = responseDefs;

        return cb();
      });

      /**
       *
       * @param  {String} responseName
       * @return {Function}
       */
      function cannotFindResponseWarning(responseName, statusCode) {
        return function _mockCustomResponse(err) {
          var req = this.req;
          var res = this.res;

          // Log a warning:
          var warningMsg = '`res.%s()` was called, but no response module was found for `%s`.';
          warningMsg = util.format(warningMsg, responseName, responseName);
          // sails.log.warn(warningMsg);
          var helpMsg = 'You can probably solve this by creating `%s.js` in:';
          helpMsg = util.format(helpMsg, responseName);
          // sails.log.warn(helpMsg);
          // sails.log.warn(sails.config.paths.responses);

          // Send a default response:
          // var wrappedErr = { status: statusCode };
          // if (_.isObject(err)) {
          //   _.extend(wrappedErr, err);
          // }
          // else {
          //   wrappedErr.error = err;
          // }

          if (process.env.NODE_ENV === 'production') {
            return res.status(statusCode || 500).send(err);
          }
          return res.status(statusCode || 500).send(err);
        };
      }
    },

    /**
     * Shadow route bindings
     * @type {Object}
     */
    routes: {
      before: {

        /**
         * Add custom response methods to `res`.
         *
         * @param {Request} req
         * @param {Response} res
         * @param  {Function} next [description]
         * @api private
         */
        'all /*': function addResponseMethods(req, res, next) {

          // Attach res.jsonx to `res` object
          _mixin_jsonx(req,res);

          // Attach custom responses to `res` object
          // Provide access to `req` and `res` in each of their `this` contexts.
          _.each(sails.middleware.responses, function eachMethod(responseFn, name) {
            res[name] = _.bind(responseFn, {
              req: req,
              res: res
            });
          });

          // Proceed!
          next();
        }
      }
    }

  };
};

/**
 * [_mixin_jsonx description]
 * @param  {[type]} req [description]
 * @param  {[type]} res [description]
 * @return {[type]}     [description]
 */
function _mixin_jsonx(req, res) {

  /**
   * res.jsonx(data)
   *
   * Serve JSON (and allow JSONP if enabled in `req.options`)
   *
   * @param  {Object} data
   */
  res.jsonx = res.jsonx || function jsonx (data){

    // Send conventional status message if no data was provided
    // (see http://expressjs.com/api.html#res.send)
    if (_.isUndefined(data)) {
      return res.status(res.statusCode).send();
    }
    else if (typeof data !== 'object') {
      // (note that this guard includes arrays)
      return res.send(data);
    }

    // When responding with an Error instance, if it's going to get sringified
    // without its `.stack`, then manually add the `.stack` and `.message` back in.
    if (data instanceof Error) {
      var jsonSerializedErr;
      try {
        jsonSerializedErr = JSON.parse(JSON.stringify(data));
        if (!jsonSerializedErr.stack || !jsonSerializedErr.message) {
          data = {message: data.message, stack: data.stack};
        }
      }
      catch (e){
        data = {message: data.message, stack: data.stack};
      }
    }

    if ( req.options.jsonp && !req.isSocket ) {
      return res.jsonp(data);
    }
    else return res.json(data);
  };
}

// Note for later
// We could differentiate between 500 (generic error message)
// and 504 (gateway did not receive response from upstream server) which could describe an IO problem
// This is worth having a think about, since there are 2 fundamentally different kinds of "server errors":
// (a) An infrastructural issue, or 504  (e.g. MySQL database randomly crashed or Twitter is down)
// (b) Unexpected bug in app code, or 500 (e.g. `req.session.user.id`, but `req.session.user` doesn't exist)
<commit_msg>Make inline comments around serialization of Error instances in 'res.jsonx()' clearer for future reference.<commit_after>/**
 * Dependencies
 */
var _ = require('lodash'),
  util = require('util'),
  Err = require('../../../errors/fatal'),
  onRoute = require('./onRoute'),
  STRINGFILE = require('sails-stringfile');

/**
 * Expose hook definition
 */

module.exports = function(sails) {

  return {

    defaults: {},
    configure: function() {

      // Legacy (< v0.10) support for configured handlers
      if (typeof sails.config[500] === 'function') {
        sails.after('lifted', function() {
          STRINGFILE.logDeprecationNotice('sails.config[500]',
            STRINGFILE.get('links.docs.migrationGuide.responses'),
            sails.log.debug);
          sails.log.debug('sails.config[500] (i.e. `config/500.js`) has been superceded in Sails v0.10.');
          sails.log.debug('Please define a "response" instead. (i.e. api/responses/serverError.js)');
          sails.log.debug('Your old handler is being ignored. (the format has been upgraded in v0.10)');
          sails.log.debug('If you\'d like to use the default handler, just remove this configuration option.');
        });
      }
      if (typeof sails.config[404] === 'function') {
        sails.after('lifted', function() {
          STRINGFILE.logDeprecationNotice('sails.config[404]',
            STRINGFILE.get('links.docs.migrationGuide.responses'),
            sails.log.debug);
          sails.log.debug('Please define a "response" instead. (i.e. api/responses/notFound.js)');
          sails.log.debug('Your old handler is being ignored. (the format has been upgraded in v0.10)');
          sails.log.debug('If you\'d like to use the default handler, just remove this configuration option.');
        });
      }
    },

    /**
     * When this hook is loaded...
     */

    initialize: function(cb) {

      // Register route syntax that allows explicit routes
      // to be bound directly to custom responses by name.
      // (e.g. {response: 'foo'})
      sails.on('route:typeUnknown', onRoute(sails));

      cb();
    },

    /**
     * Fetch relevant modules, exposing them on `sails` subglobal if necessary,
     */
    loadModules: function(cb) {
      var hook = this;

      sails.log.verbose('Loading runtime custom response definitions...');
      sails.modules.loadResponses(function loadedRuntimeErrorModules(err, responseDefs) {
        if (err) return cb(err);

        // Check that the user reserved response methods/properties
        var reservedResKeys = [
          'view',
          'status', 'set', 'get', 'cookie', 'clearCookie', 'redirect',
          'location', 'charset', 'send', 'json', 'jsonp', 'type', 'format',
          'attachment', 'sendfile', 'download', 'links', 'locals', 'render'
        ];

        _.each(Object.keys(responseDefs), function(userResponseKey) {
          if (_.contains(reservedResKeys, userResponseKey)) {
            return Err.invalidCustomResponse(userResponseKey);
          }
        });

        // Ensure that required custom responses exist.
        _.defaults(responseDefs, {
          ok: require('./defaults/ok'),
          created: require('./defaults/created'),
          negotiate: require('./defaults/negotiate'),
          notFound: require('./defaults/notFound'),
          serverError: require('./defaults/serverError'),
          forbidden: require('./defaults/forbidden'),
          badRequest: require('./defaults/badRequest')

          // Example usage:
          // foo: cannotFindResponseWarning('foo', 400)
        });

        // Register blueprint actions as middleware
        hook.middleware = responseDefs;

        return cb();
      });

      /**
       *
       * @param  {String} responseName
       * @return {Function}
       */
      function cannotFindResponseWarning(responseName, statusCode) {
        return function _mockCustomResponse(err) {
          var req = this.req;
          var res = this.res;

          // Log a warning:
          var warningMsg = '`res.%s()` was called, but no response module was found for `%s`.';
          warningMsg = util.format(warningMsg, responseName, responseName);
          // sails.log.warn(warningMsg);
          var helpMsg = 'You can probably solve this by creating `%s.js` in:';
          helpMsg = util.format(helpMsg, responseName);
          // sails.log.warn(helpMsg);
          // sails.log.warn(sails.config.paths.responses);

          // Send a default response:
          // var wrappedErr = { status: statusCode };
          // if (_.isObject(err)) {
          //   _.extend(wrappedErr, err);
          // }
          // else {
          //   wrappedErr.error = err;
          // }

          if (process.env.NODE_ENV === 'production') {
            return res.status(statusCode || 500).send(err);
          }
          return res.status(statusCode || 500).send(err);
        };
      }
    },

    /**
     * Shadow route bindings
     * @type {Object}
     */
    routes: {
      before: {

        /**
         * Add custom response methods to `res`.
         *
         * @param {Request} req
         * @param {Response} res
         * @param  {Function} next [description]
         * @api private
         */
        'all /*': function addResponseMethods(req, res, next) {

          // Attach res.jsonx to `res` object
          _mixin_jsonx(req,res);

          // Attach custom responses to `res` object
          // Provide access to `req` and `res` in each of their `this` contexts.
          _.each(sails.middleware.responses, function eachMethod(responseFn, name) {
            res[name] = _.bind(responseFn, {
              req: req,
              res: res
            });
          });

          // Proceed!
          next();
        }
      }
    }

  };
};

/**
 * [_mixin_jsonx description]
 * @param  {[type]} req [description]
 * @param  {[type]} res [description]
 * @return {[type]}     [description]
 */
function _mixin_jsonx(req, res) {

  /**
   * res.jsonx(data)
   *
   * Serve JSON (and allow JSONP if enabled in `req.options`)
   *
   * @param  {Object} data
   */
  res.jsonx = res.jsonx || function jsonx (data){

    // Send conventional status message if no data was provided
    // (see http://expressjs.com/api.html#res.send)
    if (_.isUndefined(data)) {
      return res.status(res.statusCode).send();
    }
    else if (typeof data !== 'object') {
      // (note that this guard includes arrays)
      return res.send(data);
    }

    // When responding with an Error instance, if it's going to get sringified into
    // a dictionary with no `.stack` or `.message` properties, add them in.
    if (data instanceof Error) {
      var jsonSerializedErr;
      try {
        jsonSerializedErr = JSON.parse(JSON.stringify(data));
        if (!jsonSerializedErr.stack || !jsonSerializedErr.message) {
          data = {message: data.message, stack: data.stack};
        }
      }
      catch (e){
        data = {message: data.message, stack: data.stack};
      }
    }

    if ( req.options.jsonp && !req.isSocket ) {
      return res.jsonp(data);
    }
    else return res.json(data);
  };
}

// Note for later
// We could differentiate between 500 (generic error message)
// and 504 (gateway did not receive response from upstream server) which could describe an IO problem
// This is worth having a think about, since there are 2 fundamentally different kinds of "server errors":
// (a) An infrastructural issue, or 504  (e.g. MySQL database randomly crashed or Twitter is down)
// (b) Unexpected bug in app code, or 500 (e.g. `req.session.user.id`, but `req.session.user` doesn't exist)
<|endoftext|>


<commit_before>var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var prefix = require('gulp-autoprefixer');
var changed = require('gulp-changed');
var browserSync = require('browser-sync');

var TARGET_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

function styles() {
  return gulp.src('./src/assets/stylesheets/main.scss')
    .pipe(sourcemaps.init())
    .pipe(changed('styles', {extension: '.scss'}))
    .pipe(sass({
      precision: 10,
      errLogToConsole: true
    }))
    .pipe(prefix({browsers: TARGET_BROWSERS}))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./dist/assets/stylesheets'))
    .pipe(browserSync.reload({stream:true}));
}

gulp.task(styles);<commit_msg>Better reload<commit_after>var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var prefix = require('gulp-autoprefixer');
var changed = require('gulp-changed');
var browserSync = require('browser-sync');
var reload = browserSync.reload;

var TARGET_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

function styles() {
  return gulp.src('./src/assets/stylesheets/main.scss')
    .pipe(sourcemaps.init())
    .pipe(changed('styles', {extension: '.scss'}))
    .pipe(sass({
      precision: 10,
      errLogToConsole: true
    }))
    .pipe(prefix({browsers: TARGET_BROWSERS}))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./dist/assets/stylesheets'))
    .pipe(reload({stream:true}));
}

gulp.task(styles);<|endoftext|>


<commit_before>/**
 * FF's first picture implementation is static and does not react to viewport changes, this tiny script fixes this.
 */
(function(window) {
	/*jshint eqnull:true */
	var ua = navigator.userAgent;

	if ( window.HTMLPictureElement && ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 < 41) ) {
		addEventListener("resize", (function() {
			var timer;

			var dummySrc = document.createElement("source");

			var fixRespimg = function(img) {
				var source, sizes;
				var picture = img.parentNode;

				if (picture.nodeName.toUpperCase() === "PICTURE") {
					source = dummySrc.cloneNode();

					picture.insertBefore(source, picture.firstElementChild);
					setTimeout(function() {
						picture.removeChild(source);
					});
				} else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) {
					img._pfLastSize = img.offsetWidth;
					sizes = img.sizes;
					img.sizes += ",100vw";
					setTimeout(function() {
						img.sizes = sizes;
					});
				}
			};

			var findPictureImgs = function() {
				var i;
				var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]");
				for (i = 0; i < imgs.length; i++) {
					fixRespimg(imgs[i]);
				}
			};
			var onResize = function() {
				clearTimeout(timer);
				timer = setTimeout(findPictureImgs, 99);
			};
			var mq = window.matchMedia && matchMedia("(orientation: landscape)");

			dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";

			onResize();

			if (mq && mq.addListener) {
				mq.addListener(onResize);
			}

			return onResize;
		})());
	}
})(window);
<commit_msg>initialize gecko static picture fix on dom ready<commit_after>/**
 * FF's first picture implementation is static and does not react to viewport changes, this tiny script fixes this.
 */
(function(window) {
	/*jshint eqnull:true */
	var ua = navigator.userAgent;

	if ( window.HTMLPictureElement && ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 < 41) ) {
		addEventListener("resize", (function() {
			var timer;

			var dummySrc = document.createElement("source");

			var fixRespimg = function(img) {
				var source, sizes;
				var picture = img.parentNode;

				if (picture.nodeName.toUpperCase() === "PICTURE") {
					source = dummySrc.cloneNode();

					picture.insertBefore(source, picture.firstElementChild);
					setTimeout(function() {
						picture.removeChild(source);
					});
				} else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) {
					img._pfLastSize = img.offsetWidth;
					sizes = img.sizes;
					img.sizes += ",100vw";
					setTimeout(function() {
						img.sizes = sizes;
					});
				}
			};

			var findPictureImgs = function() {
				var i;
				var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]");
				for (i = 0; i < imgs.length; i++) {
					fixRespimg(imgs[i]);
				}
			};
			var onResize = function() {
				clearTimeout(timer);
				timer = setTimeout(findPictureImgs, 99);
			};
			var mq = window.matchMedia && matchMedia("(orientation: landscape)");
			var init = function(){
				onResize();

				if (mq && mq.addListener) {
					mq.addListener(onResize);
				}
			};

			dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";

			if (/^[c|i]|d$/.test(document.readyState || "")) {
				init();
			} else {
				document.addEventListener("DOMContentLoaded", init);
			}

			return onResize;
		})());
	}
})(window);
<|endoftext|>


<commit_before>// See license.txt, BSD
// Copyright 2011 Google, Inc. author: johnjbarton@google.com

define(['../lib/domplate/lib/domplate'], function findAnythingFactory(DOMPLATE) {

  var anyThingBar = {
    initialize: function() {
      this.buildDomplate();
      this.renderDomplate();
      this.addListeners();
    },
    buildDomplate: function() {
      with (DOMPLATE.tags) {
        this.template = DOMPLATE.domplate({
          tag: DIV({'id': 'findAnythingToolbar','class':'purpleToolbar'},
             FOR('preButton', '$preButtons',
               TAG("$buttonTag", {button: "$button"})
             ),
             DIV({'id': 'findAnything', 'class':'omniboxLikeLeft omniboxLike omniboxLikeRight'},
               IMG({'id': 'findAnythingIcon', 'class':'findAnythingIcon omniboxLikeLeft', 'src':'../ui/icons/o2_http_query.png'} ),
               DIV({'id':'findAnythingBackground'},
                 INPUT({'id':'findAnythingCompletion', 'value':'.js'}),
                 DIV({'id':'findAnythingNotify'}, '.js    26 js, 3 css, 1 html, 205 logs'),
                 INPUT({'id':'findAnythingInput', 'value':'.js'})
               )
             )
           ),
        });
      }
    },
    renderDomplate: function() {
      var html = this.template.tag.render({
        preButtons: [],
      });

      var body = document.getElementsByTagName('body')[0];
      body.innerHTML = html;
      this.resize();
    },

    addListeners: function () {
      var body = document.getElementsByTagName('body')[0];
      window.addEventListener('resize', this.resize.bind(this), true);
    },

    resize: function () {
      var toolbar = document.getElementById('findAnythingToolbar');
      var availableWidth = toolbar.offsetWidth;
      // remove the width of childern TODO
      availableWidth -= 24*4;
      this.setWidth('findAnythingBackground', availableWidth);
      this.setWidth('findAnythingCompletion', availableWidth);
      this.setWidth('findAnythingInput', availableWidth);
      //this.setWidth('findAnythingNotify', availableWidth);
    },
    setWidth: function(id, availableWidth) {
      var elt =  document.getElementById(id);
      elt.style.width = availableWidth +"px";
    }
  };

  return anyThingBar;
});<commit_msg>begin to implement event listeners<commit_after>// See license.txt, BSD
// Copyright 2011 Google, Inc. author: johnjbarton@google.com

define(['../lib/domplate/lib/domplate'], function findAnythingFactory(DOMPLATE) {

  var anyThingBar = {
    initialize: function() {
      this.buildDomplate();
      this.renderDomplate();
      this.addListeners();
    },
    buildDomplate: function() {
      with (DOMPLATE.tags) {
        this.template = DOMPLATE.domplate({
          tag: DIV({'id': 'findAnythingToolbar','class':'purpleToolbar'},
             FOR('preButton', '$preButtons',
               TAG("$buttonTag", {button: "$button"})
             ),
             DIV({'id': 'findAnything', 'class':'omniboxLikeLeft omniboxLike omniboxLikeRight'},
               IMG({'id': 'findAnythingIcon', 'class':'findAnythingIcon omniboxLikeLeft', 'src':'../ui/icons/o2_http_query.png'} ),
               DIV({'id':'findAnythingBackground'},
                 INPUT({'id':'findAnythingCompletion', 'value':'.js'}),
                 DIV({'id':'findAnythingNotify'}, 'Resource and event counts here'),
                 INPUT({'id':'findAnythingInput', 'value':'.js'})
               )
             )
           ),
        });
      }
    },
    renderDomplate: function() {
      var html = this.template.tag.render({
        preButtons: [],
      });

      var body = document.getElementsByTagName('body')[0];
      body.innerHTML = html;
      this.resize();
    },

    addListeners: function () {
      window.addEventListener('resize', this.resize, true);

    },

    resize: function () {
      var toolbar = document.getElementById('findAnythingToolbar');
      var availableWidth = toolbar.offsetWidth;
      // remove the width of childern TODO
      availableWidth -= 24*4;
      this.setWidth('findAnythingBackground', availableWidth);
      this.setWidth('findAnythingCompletion', availableWidth);
      this.setWidth('findAnythingInput', availableWidth);
      //this.setWidth('findAnythingNotify', availableWidth);
    },
    setWidth: function(id, availableWidth) {
      var elt =  document.getElementById(id);
      elt.style.width = availableWidth +"px";
    }
  };

  function listen(eventSelectorPairs, handlers) {
    Object.keys(eventSelectorPairs).forEach(function on(prop) {
      var selector = eventSelectorPairs[prop];
      var elt = document.querySelector(selector);
      var handler = handlers[prop];
      if (!handler.isBound) {
        handlers[prop] = handler.bind(handlers);
        handlers[prop].isBound = handler;
        handler = handlers[prop];
      }
      elt.addEventListener(prop, handler, false);
    });
  }

  listen({'resize': 'body'}, anyThingBar);

  return anyThingBar;
});<|endoftext|>


<commit_before>/**
 * Created by wil on 14/01/2014.
 */

/**
 * ++
 * @TODO: Mapping() public methods should be defined in the prototype for improved performance
 *
 * ++
 * @TODO: Add YUIDocs
 *
 * ++
 * @TODO: as([...]) - for duck typing...
 */

;(function(root) {

    "use strict";

    var deps = [];

    function factory() {

        var INVALID_MAPPING_TYPE = '[#001] The mapping must be a function',
            INVALID_KEY_TYPE = '[#002] The key must be a String',
            NO_RESOLVER = '[#003] No resolver found',
            MAPPING_EXISTS = '[#004] A mapping already exists',
            NO_MAPPING = '[#005] No mapping found',
            MAPPING_HAS_DEPENDANTS = '[#006] The mapping has dependants',
            INVALID_RESOLVE_TARGET = '[#007] The resolve target must be an Object or Function',

            slice = Array.prototype.slice;

        function is(value, type) {

            return Object.prototype.toString
                .call(value)
                .split(' ')[1]
                .toLowerCase()
                .indexOf(type.toLowerCase()) !== -1;
        }

        function validateType(value, type, errorMsg) {
            if (!is(value, type)) {
                throw new TypeError(errorMsg);
            }
        }

        // Mapping
        // --------------------
        function Mapping(injector) {

            var isSingleton = false,
                resolver = null,
                deps = {
                    args: [],
                    props: null
                },

                target = null;

            function validate(target) {

                validateType(target, 'function', INVALID_MAPPING_TYPE);

                if (resolver !== null) {
                    throw new Error(MAPPING_EXISTS);
                }
            }

            function getProps(instance) {

                if (deps.props === null) {

                    deps.props = [];

                    for (var prop in instance) {
                        if (prop.indexOf('i_') === 0) {
                            deps.props.push(prop);
                        }
                    }
                }

                return deps.props;
            }

            function instantiate(Constructor) {

                var instance = new Constructor(slice.call(arguments, 1));

                getProps(instance).forEach(function(prop) {
                    if (instance[prop] == null) {
                        instance[prop] = injector.getMappingFor(prop.replace('i_', ''));
                    }
                });

                if (instance['postConstruct'] != null) {
                    instance.postConstruct();
                }

                return instance;
            }

            this.toFactory = function(value) {

                var facade = null;

                function makeFactory() {

                    var Constructor = value.apply(value, deps.args.map(function(key) {
                        return injector.getMappingFor(key);
                    }));

                    function Factory(args) {
                        return Constructor.apply(this, args);
                    }

                    Factory.prototype = Constructor.prototype;

                    return Factory;
                }

                function makeFacade(Constructor) {

                    var instance = instantiate(Constructor);

                    return {

                        make: function() {

                            return instantiate.apply(this, [Constructor].concat(slice.call(arguments, 0)));
                        },

                        name: instance.constructor.name,

                        type: instance.constructor
                    };
                }

                validate(value);

                target = value;

                resolver = function() {

                    return facade || (facade = makeFacade(makeFactory()));
                };

                return this;
            };

            this.toType = function(value) {

                var singleton = null;

                validate(value);

                function Builder() {

                    return value.apply(this, deps.args.map(function(key) {
                        return injector.getMappingFor(key);
                    }));
                }

                Builder.prototype = value.prototype;

                target = value;

                resolver = function() {

                    if (isSingleton && singleton === null) {
                        singleton = instantiate(Builder);
                    }

                    return singleton || instantiate(Builder);
                };

                return this;
            };

            this.toValue = function(value) {

                deps.props = [];

                target = value;

                resolver = function() {

                    return value;
                };

                return this;
            };

            this.using = function() {

                if (arguments.length > 0 && arguments[0]) {
                    deps.args = is(arguments[0], 'Array') ? arguments[0] : slice.call(arguments, 0);
                }

                return this;
            };

            this.asSingleton = function() {

                isSingleton = true;

                return this;
            };

            this.resolve = function() {

                validateType(resolver, 'function', NO_RESOLVER);

                return resolver();
            };

            this.injector = function() {

                return injector;
            };

            this.dependsOn = function(key) {

                if (deps.props === null) {
                    resolver();
                }

                return deps.args.indexOf(key) > -1 || deps.props.indexOf('i_' + key) > -1;
            };

            this.destroy = function() {

                var rtn = target;

                deps.args.length = 0;
                deps.props.length = 0;

                resolver = null;
                target = null;

                return rtn;
            };
        }

        // Injector
        // --------------------
        function Injector() {

            var self = this,
                mappings = {};

            function validateKey(key) {

                validateType(key, 'string', INVALID_KEY_TYPE);

                if (self.hasMappingFor(key)) {
                    throw new Error(MAPPING_EXISTS);
                }
            }

            this.map = function(key) {

                validateKey(key);

                return (mappings[key] = new Mapping(self));
            };

            this.unMap = function(key) {

                var value = null;

                if (self.hasMappingFor(key)) {

                    Object.keys(mappings).forEach(function(name) {
                        if (mappings[name].dependsOn(key)) {
                            throw new Error(MAPPING_HAS_DEPENDANTS);
                        }
                    });

                    value = mappings[key].destroy();

                    delete mappings[key];
                }

                return value;
            };

            this.hasMappingFor = function(key) {

                return mappings.hasOwnProperty(key);
            };

            this.getMappingFor = function(key) {

                validateType(key, 'string', INVALID_KEY_TYPE);

                if (!self.hasMappingFor(key)) {
                    throw new Error(NO_MAPPING);
                }

                return mappings[key].resolve();
            };

            this.resolveFactory = function(target) {

                validateType(target, 'Function', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toFactory(target)
                    .using(slice.call(arguments, 1))
                    .resolve();
            };

            this.resolveType = function(target) {

                validateType(target, 'Function', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toType(target)
                    .using(slice.call(arguments, 1))
                    .resolve();
            };

            this.resolveValue = function(target) {

                validateType(target, 'Object', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toValue(target)
                    .resolve();
            };
        }

        return Injector;
    }

    // UMD style export.
	// ----------------------------------------
    /* istanbul ignore next */
	if (typeof define === 'function' && define.amd) {

		define(deps, factory);

	} else if (typeof module !== 'undefined' && module.exports) {

		module.exports = factory.apply(factory, deps.map(function(dep) {
            return require(dep);
        }));

	} else {

        root['Injector'] = factory.apply(factory, deps.map(function(dep) {
            return root[dep];
        }));
	}

})(this);
<commit_msg>Updated TODO list<commit_after>/**
 * Created by wil on 14/01/2014.
 */

/**
 * ++
 * @TODO: Mapping() public methods should be defined in the prototype for improved performance
 *  - NOTE: Using prototype should making testing easier
 *
 * ++
 * @TODO: Update README
 *
 * ++
 * @TODO: Add YUIDocs
 *  - Injector
 *  - Mapping
 *
 * ++
 * @TODO: Tidy up tests
 *  - Each Mapping function should be a separate describe
 *  - describe Injector ...
 *  - describe Mapping ...
 *
 * ++
 * @TODO: Mapping.as([...]) - for duck typing...
 */

;(function(root) {

    "use strict";

    var deps = [];

    function factory() {

        var INVALID_MAPPING_TYPE = '[#001] The mapping must be a function',
            INVALID_KEY_TYPE = '[#002] The key must be a String',
            NO_RESOLVER = '[#003] No resolver found',
            MAPPING_EXISTS = '[#004] A mapping already exists',
            NO_MAPPING = '[#005] No mapping found',
            MAPPING_HAS_DEPENDANTS = '[#006] The mapping has dependants',
            INVALID_RESOLVE_TARGET = '[#007] The resolve target must be an Object or Function',

            slice = Array.prototype.slice;

        function is(value, type) {

            return Object.prototype.toString
                .call(value)
                .split(' ')[1]
                .toLowerCase()
                .indexOf(type.toLowerCase()) !== -1;
        }

        function validateType(value, type, errorMsg) {
            if (!is(value, type)) {
                throw new TypeError(errorMsg);
            }
        }

        // Mapping
        // --------------------
        function Mapping(injector) {

            var isSingleton = false,
                resolver = null,
                deps = {
                    args: [],
                    props: null
                },

                target = null;

            function validate(target) {

                validateType(target, 'function', INVALID_MAPPING_TYPE);

                if (resolver !== null) {
                    throw new Error(MAPPING_EXISTS);
                }
            }

            function getProps(instance) {

                if (deps.props === null) {

                    deps.props = [];

                    for (var prop in instance) {
                        if (prop.indexOf('i_') === 0) {
                            deps.props.push(prop);
                        }
                    }
                }

                return deps.props;
            }

            function instantiate(Constructor) {

                var instance = new Constructor(slice.call(arguments, 1));

                getProps(instance).forEach(function(prop) {
                    if (instance[prop] == null) {
                        instance[prop] = injector.getMappingFor(prop.replace('i_', ''));
                    }
                });

                if (instance['postConstruct'] != null) {
                    instance.postConstruct();
                }

                return instance;
            }

            this.toFactory = function(value) {

                var facade = null;

                function makeFactory() {

                    var Constructor = value.apply(value, deps.args.map(function(key) {
                        return injector.getMappingFor(key);
                    }));

                    function Factory(args) {
                        return Constructor.apply(this, args);
                    }

                    Factory.prototype = Constructor.prototype;

                    return Factory;
                }

                function makeFacade(Constructor) {

                    var instance = instantiate(Constructor);

                    return {

                        make: function() {

                            return instantiate.apply(this, [Constructor].concat(slice.call(arguments, 0)));
                        },

                        name: instance.constructor.name,

                        type: instance.constructor
                    };
                }

                validate(value);

                target = value;

                resolver = function() {

                    return facade || (facade = makeFacade(makeFactory()));
                };

                return this;
            };

            this.toType = function(value) {

                var singleton = null;

                validate(value);

                function Builder() {

                    return value.apply(this, deps.args.map(function(key) {
                        return injector.getMappingFor(key);
                    }));
                }

                Builder.prototype = value.prototype;

                target = value;

                resolver = function() {

                    if (isSingleton && singleton === null) {
                        singleton = instantiate(Builder);
                    }

                    return singleton || instantiate(Builder);
                };

                return this;
            };

            this.toValue = function(value) {

                deps.props = [];

                target = value;

                resolver = function() {

                    return value;
                };

                return this;
            };

            this.using = function() {

                if (arguments.length > 0 && arguments[0]) {
                    deps.args = is(arguments[0], 'Array') ? arguments[0] : slice.call(arguments, 0);
                }

                return this;
            };

            this.asSingleton = function() {

                isSingleton = true;

                return this;
            };

            this.resolve = function() {

                validateType(resolver, 'function', NO_RESOLVER);

                return resolver();
            };

            this.injector = function() {

                return injector;
            };

            this.dependsOn = function(key) {

                if (deps.props === null) {
                    resolver();
                }

                return deps.args.indexOf(key) > -1 || deps.props.indexOf('i_' + key) > -1;
            };

            this.destroy = function() {

                var rtn = target;

                deps.args.length = 0;
                deps.props.length = 0;

                resolver = null;
                target = null;

                return rtn;
            };
        }

        // Injector
        // --------------------
        function Injector() {

            var self = this,
                mappings = {};

            function validateKey(key) {

                validateType(key, 'string', INVALID_KEY_TYPE);

                if (self.hasMappingFor(key)) {
                    throw new Error(MAPPING_EXISTS);
                }
            }

            this.map = function(key) {

                validateKey(key);

                return (mappings[key] = new Mapping(self));
            };

            this.unMap = function(key) {

                var value = null;

                if (self.hasMappingFor(key)) {

                    Object.keys(mappings).forEach(function(name) {
                        if (mappings[name].dependsOn(key)) {
                            throw new Error(MAPPING_HAS_DEPENDANTS);
                        }
                    });

                    value = mappings[key].destroy();

                    delete mappings[key];
                }

                return value;
            };

            this.hasMappingFor = function(key) {

                return mappings.hasOwnProperty(key);
            };

            this.getMappingFor = function(key) {

                validateType(key, 'string', INVALID_KEY_TYPE);

                if (!self.hasMappingFor(key)) {
                    throw new Error(NO_MAPPING);
                }

                return mappings[key].resolve();
            };

            this.resolveFactory = function(target) {

                validateType(target, 'Function', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toFactory(target)
                    .using(slice.call(arguments, 1))
                    .resolve();
            };

            this.resolveType = function(target) {

                validateType(target, 'Function', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toType(target)
                    .using(slice.call(arguments, 1))
                    .resolve();
            };

            this.resolveValue = function(target) {

                validateType(target, 'Object', INVALID_RESOLVE_TARGET);

                return new Mapping(self)
                    .toValue(target)
                    .resolve();
            };
        }

        return Injector;
    }

    // UMD style export.
	// ----------------------------------------
    /* istanbul ignore next */
	if (typeof define === 'function' && define.amd) {

		define(deps, factory);

	} else if (typeof module !== 'undefined' && module.exports) {

		module.exports = factory.apply(factory, deps.map(function(dep) {
            return require(dep);
        }));

	} else {

        root['Injector'] = factory.apply(factory, deps.map(function(dep) {
            return root[dep];
        }));
	}

})(this);
<|endoftext|>