rails-backbone-generator 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.gitignore +19 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +213 -0
  5. data/Rakefile +2 -0
  6. data/lib/generators/backbone/collection_generator.rb +70 -0
  7. data/lib/generators/backbone/model_generator.rb +56 -0
  8. data/lib/generators/backbone/namespace_generator.rb +62 -0
  9. data/lib/generators/backbone/setup_generator/templates/Guardfile +44 -0
  10. data/lib/generators/backbone/setup_generator/templates/app/assets/javascripts/application.js +14 -0
  11. data/lib/generators/backbone/setup_generator/templates/app/assets/javascripts/shared/core_extentions/collections_extentions.coffee +30 -0
  12. data/lib/generators/backbone/setup_generator/templates/app/assets/javascripts/shared/helpers/.gitkeep +0 -0
  13. data/lib/generators/backbone/setup_generator/templates/app/assets/javascripts/shared/utils/.gitkeep +0 -0
  14. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/fixtures/.gitkeep +0 -0
  15. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/helpers/association_helpers.coffee +3 -0
  16. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/helpers/common_helpers.coffee +13 -0
  17. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/helpers/fake_host.coffee +14 -0
  18. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/helpers/headless_webkit_helper.coffee +9 -0
  19. data/lib/generators/backbone/setup_generator/templates/spec/javascripts/support/jasmine.yml +81 -0
  20. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/backbone-0.9.2.js +1431 -0
  21. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/backbone-bind-to-1.0.0.coffee +47 -0
  22. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/backbone-handlebars-1.0.0.js +121 -0
  23. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/backbone-query-0.2.3.coffee +314 -0
  24. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/backbone-relational-0.6.0.js +1687 -0
  25. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/handlebars-1.0.rc.1.js +1920 -0
  26. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/backbone/underscore-1.3.3.js +1059 -0
  27. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/browser_compatibility/json2.js +487 -0
  28. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/browser_compatibility/localstorage-polyfill.js +92 -0
  29. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/jquery/jquery-1.8.0.js +9227 -0
  30. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/jquery/jquery-ui.min.js +17 -0
  31. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/jquery/jquery.easing-1.3.js +205 -0
  32. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/jquery/jquery_ujs.js +368 -0
  33. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/testing/backbone-factory.js +53 -0
  34. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/testing/jasmine-jquery-1.3.1.js +288 -0
  35. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/testing/jasmine-sinon.js +43 -0
  36. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/testing/mock-ajax.js +207 -0
  37. data/lib/generators/backbone/setup_generator/templates/vendor/assets/javascripts/testing/sinon-1.4.2.js +4081 -0
  38. data/lib/generators/backbone/setup_generator.rb +90 -0
  39. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/collections/%collection_name%.coffee.tt +4 -0
  40. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/collections/.gitkeep +0 -0
  41. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/models/%model_name%.coffee.tt +15 -0
  42. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/models/.gitkeep +0 -0
  43. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/routes/.gitkeep +0 -0
  44. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/templates/.gitkeep +0 -0
  45. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%/views/.gitkeep +0 -0
  46. data/lib/generators/backbone/templates/app/assets/javascripts/%namespace%.coffee.tt +15 -0
  47. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/collections/%collection_name%_spec.coffee.tt +8 -0
  48. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/collections/.gitkeep +0 -0
  49. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/factories/%model_name%_factory.coffee.tt +43 -0
  50. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/factories/.gitkeep +0 -0
  51. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/models/%model_name%_spec.coffee.tt +12 -0
  52. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/models/.gitkeep +0 -0
  53. data/lib/generators/backbone/templates/spec/javascripts/%namespace%/views/.gitkeep +0 -0
  54. data/lib/generators/backbone_generator.rb +3 -0
  55. data/lib/rails_backbone_generator/version.rb +3 -0
  56. data/lib/rails_backbone_generator.rb +4 -0
  57. data/rails_backbone_generator.gemspec +20 -0
  58. metadata +61 -4
@@ -0,0 +1,47 @@
1
+ ###
2
+ Backbone BindTo 1.0.0
3
+
4
+ Author: Radoslav Stankov
5
+ Project site: https://github.com/RStankov/backbone-bind-to
6
+ Licensed under the MIT License.
7
+ ###
8
+
9
+ root = @
10
+ BackboneView = root.Backbone.View
11
+
12
+ class BindToView extends BackboneView
13
+ constructor: ->
14
+ super
15
+
16
+ @bindTo @model, eventName, methodName for eventName, methodName of @bindToModel if @model
17
+ @bindTo @collection, eventName, methodName for eventName, methodName of @bindToCollection if @collection
18
+
19
+ bindTo: (object, eventName, methodName) ->
20
+ unless object in [@model, @collection]
21
+ @_binded = []
22
+ @_binded.push object unless _.include @_binded, object
23
+
24
+ throw new Error "Method #{methodName} does not exists" unless @[methodName]
25
+ throw new Error "#{methodName} is not a function" unless typeof @[methodName] is 'function'
26
+
27
+ object.on eventName, @[methodName], @
28
+
29
+ remove: ->
30
+ @model.off null, null, @ if @model
31
+ @collection.off null, null, @ if @collection
32
+
33
+ _.invoke @_binded, 'off', null, null, @
34
+ delete @_binded
35
+
36
+ super
37
+
38
+ Backbone.BindTo =
39
+ VERSION: '1.0.0'
40
+
41
+ noConflict: ->
42
+ root.Backbone.View = BackboneView
43
+ BindToView
44
+
45
+ View: BindToView
46
+
47
+ root.Backbone.View = Backbone.BindTo.View
@@ -0,0 +1,121 @@
1
+ /*
2
+ Backbone Handlebars
3
+
4
+ Author: Radoslav Stankov
5
+ Project site: https://github.com/RStankov/backbone-handlebars
6
+ Licensed under the MIT License.
7
+ */
8
+
9
+
10
+ (function() {
11
+ var BH, _compile, _remove;
12
+
13
+ BH = {
14
+ VERSION: '1.0.0',
15
+ postponed: {},
16
+ rendered: {},
17
+ postponeRender: function(name, options, parentView) {
18
+ var cid, view, viewClass, _base, _ref;
19
+ viewClass = _.inject((name || '').split('.'), (function(memo, fragment) {
20
+ return memo[fragment] || false;
21
+ }), window);
22
+ if (!viewClass) {
23
+ throw "Invalid view name - " + name;
24
+ }
25
+ view = new viewClass(options.hash);
26
+ if (options.fn !== null) {
27
+ view.template = options.fn;
28
+ }
29
+ cid = (parentView || options.data.view).cid;
30
+ if ((_ref = (_base = this.postponed)[cid]) === null) {
31
+ _base[cid] = [];
32
+ }
33
+ this.postponed[cid].push(view);
34
+ return '<div id="_' + view.cid + '"></div>';
35
+ },
36
+ renderPostponed: function(parentView) {
37
+ var cid;
38
+ cid = parentView.cid;
39
+ this.rendered[cid] = _.map(this.postponed[parentView.cid], function(view) {
40
+ view.render();
41
+ parentView.$("#_" + view.cid).replaceWith(view.el);
42
+ return view;
43
+ });
44
+ return delete this.postponed[cid];
45
+ },
46
+ clearRendered: function(parentView) {
47
+ var cid;
48
+ cid = parentView.cid;
49
+ if (this.rendered[cid]) {
50
+ _.invoke(this.rendered[cid], 'remove');
51
+ return delete this.rendered[cid];
52
+ }
53
+ }
54
+ };
55
+
56
+ Handlebars.registerHelper('view', function(name, options) {
57
+ return new Handlebars.SafeString(BH.postponeRender(name, options, this._parentView));
58
+ });
59
+
60
+ Handlebars.registerHelper('views', function(name, models, options) {
61
+ var callback, markers,
62
+ _this = this;
63
+ callback = function(model) {
64
+ options.hash.model = model;
65
+ return BH.postponeRender(name, options, _this._parentView);
66
+ };
67
+ markers = 'map' in models ? models.map(callback) : _.map(callback);
68
+ return new Handlebars.SafeString(markers.join(''));
69
+ });
70
+
71
+ _compile = Handlebars.compile;
72
+
73
+ Handlebars.compile = function(template, options) {
74
+ if (options === null) {
75
+ options = {};
76
+ }
77
+ options.data = true;
78
+ return _compile.call(this, template, options);
79
+ };
80
+
81
+ Backbone.View.prototype.renderTemplate = function(context) {
82
+ if (context === null) {
83
+ context = {};
84
+ }
85
+ BH.clearRendered(this);
86
+ context = _.clone(context);
87
+ context._parentView = this;
88
+ this.$el.html(this.template(context, {
89
+ data: {
90
+ view: this
91
+ }
92
+ }));
93
+ BH.renderPostponed(this);
94
+ return this;
95
+ };
96
+
97
+ Backbone.View.prototype.renderedSubViews = function() {
98
+ return BH.rendered[this.cid];
99
+ };
100
+
101
+ _remove = Backbone.View.prototype.remove;
102
+
103
+ Backbone.View.prototype.remove = function() {
104
+ BH.clearRendered(this);
105
+ return _remove.apply(this, arguments);
106
+ };
107
+
108
+ Backbone.View.prototype.render = function() {
109
+ if (this.template) {
110
+ this.renderTemplate(typeof this.templateData === 'function' ? this.templateData() : this.templateData);
111
+ }
112
+ return this;
113
+ };
114
+
115
+ Backbone.View.prototype.templateData = function() {
116
+ return {};
117
+ };
118
+
119
+ Backbone.Handlebars = BH;
120
+
121
+ }).call(this);
@@ -0,0 +1,314 @@
1
+ ###
2
+ Backbone Query - A lightweight query API for Backbone Collections
3
+ (c)2012 - Dave Tonge
4
+ May be freely distributed according to MIT license.
5
+ ###
6
+ ((define) -> define 'backbone-query', (require, exports) ->
7
+ _ = require('underscore')
8
+ Backbone = require('backbone')
9
+
10
+ ### UTILS ###
11
+
12
+ # Custom Filter / Reject methods faster than underscore methods as use for loops
13
+ # http://jsperf.com/filter-vs-for-loop2
14
+ filter = (array, test) -> (val for val in array when test val)
15
+ reject = (array, test) -> (val for val in array when not test val)
16
+ detect = (array, test) ->
17
+ for val in array
18
+ return true if test val
19
+ false
20
+
21
+ # Utility Function to turn a list of values into an object
22
+ makeObj = (args...)->
23
+ o = {}
24
+ current = o
25
+ while args.length
26
+ key = args.shift()
27
+ val = (if args.length is 1 then args.shift() else {})
28
+ current = current[key] = val
29
+ o
30
+
31
+ # Get the type as a string
32
+ getType = (item) ->
33
+ return "$regex" if _.isRegExp(item)
34
+ return "$date" if _.isDate(item)
35
+ return "object" if _.isObject(item) and not _.isArray(item)
36
+ return "array" if _.isArray(item)
37
+ return "string" if _.isString(item)
38
+ return "number" if _.isNumber(item)
39
+ return "boolean" if _.isBoolean(item)
40
+ return "function" if _.isFunction(item)
41
+ false
42
+
43
+ ###
44
+ Function to parse raw queries
45
+ @param {mixed} raw query
46
+ @return {array} parsed query
47
+
48
+ Allows queries of the following forms:
49
+ query
50
+ name: "test"
51
+ id: $gte: 10
52
+
53
+ query [
54
+ {name:"test"}
55
+ {id:$gte:10}
56
+ ]
57
+ ###
58
+ parseSubQuery = (rawQuery) ->
59
+
60
+ if _.isArray(rawQuery)
61
+ queryArray = rawQuery
62
+ else
63
+ queryArray = (makeObj(key, val) for own key, val of rawQuery)
64
+
65
+ (for query in queryArray
66
+ for own key, queryParam of query
67
+ o = {key}
68
+ paramType = getType(queryParam)
69
+ switch paramType
70
+ # Test for Regexs and Dates as they can be supplied without an operator
71
+ when "$regex", "$date"
72
+ o.type = paramType
73
+ o.value = queryParam
74
+
75
+ # If the query paramater is an object then extract the key and value
76
+ when "object"
77
+ if key in ["$and", "$or", "$nor", "$not"]
78
+ o.value = parseSubQuery queryParam
79
+ o.type = key
80
+ o.key = null
81
+ else
82
+ for type, value of queryParam
83
+ # Before adding the query, its value is checked to make sure it is the right type
84
+ if testQueryValue type, value
85
+ o.type = type
86
+ switch type
87
+ when "$elemMatch", "$relationMatch"
88
+ o.value = parseQuery value
89
+ when "$computed"
90
+ q = makeObj(key,value)
91
+ o.value = parseSubQuery q
92
+ else
93
+ o.value = value
94
+
95
+ # If the query_param is not an object or a regexp then revert to the default operator: $equal
96
+ else
97
+ o.type = "$equal"
98
+ o.value = queryParam
99
+
100
+ # For "$equal" queries with arrays or objects we need to perform a deep equal
101
+ if (o.type is "$equal") and (paramType in ["object","array"])
102
+ o.type = "$oEqual"
103
+ o)
104
+
105
+
106
+
107
+ # Tests query value, to ensure that it is of the correct type
108
+ testQueryValue = (type, value) ->
109
+ switch type
110
+ when "$in","$nin","$all", "$any" then _(value).isArray()
111
+ when "$size" then _(value).isNumber()
112
+ when "$regex" then _(value).isRegExp()
113
+ when "$like", "$likeI" then _(value).isString()
114
+ when "$between" then _(value).isArray() and (value.length is 2)
115
+ when "$cb" then _(value).isFunction()
116
+ else true
117
+
118
+ # Test each attribute that is being tested to ensure that is of the correct type
119
+ testModelAttribute = (type, value) ->
120
+ switch type
121
+ when "$like", "$likeI", "$regex" then _(value).isString()
122
+ when "$contains", "$all", "$any", "$elemMatch" then _(value).isArray()
123
+ when "$size" then _(value).isArray() or _(value).isString()
124
+ when "$in", "$nin" then value?
125
+ when "$relationMatch" then value? and value.models
126
+ else true
127
+
128
+ # Perform the actual query logic for each query and each model/attribute
129
+ performQuery = (type, value, attr, model, key) ->
130
+ switch type
131
+ when "$equal"
132
+ # If the attribute is an array then search for the query value in the array the same as Mongo
133
+ if _(attr).isArray() then value in attr else attr is value
134
+ when "$oEqual" then _(attr).isEqual value
135
+ when "$contains" then value in attr
136
+ when "$ne" then attr isnt value
137
+ when "$lt" then attr < value
138
+ when "$gt" then attr > value
139
+ when "$lte" then attr <= value
140
+ when "$gte" then attr >= value
141
+ when "$between" then value[0] < attr < value[1]
142
+ when "$in" then attr in value
143
+ when "$nin" then attr not in value
144
+ when "$all" then _(value).all (item) -> item in attr
145
+ when "$any" then _(attr).any (item) -> item in value
146
+ when "$size" then attr.length is value
147
+ when "$exists", "$has" then attr? is value
148
+ when "$like" then attr.indexOf(value) isnt -1
149
+ when "$likeI" then attr.toLowerCase().indexOf(value.toLowerCase()) isnt -1
150
+ when "$regex" then value.test attr
151
+ when "$cb" then value.call model, attr
152
+ when "$elemMatch" then (runQuery(attr,value,"elemMatch")).length > 0
153
+ when "$relationMatch" then (runQuery(attr.models,value,"relationMatch")).length > 0
154
+ when "$computed" then iterator [model], value, false, detect, "computed"
155
+ when "$and", "$or", "$nor", "$not"
156
+ (processQuery[type]([model], value)).length is 1
157
+ else false
158
+
159
+
160
+ # The main iterator that actually applies the query
161
+ iterator = (models, query, andOr, filterFunction, itemType = false) ->
162
+ # The collections filter or reject method is used to iterate through each model in the collection
163
+ filterFunction models, (model) ->
164
+ # For each model in the collection, iterate through the supplied queries
165
+ for q in query
166
+ # Retrieve the attribute value from the model
167
+ attr = switch itemType
168
+ when "elemMatch" then model[q.key]
169
+ when "computed" then model[q.key]()
170
+ else model.get(q.key)
171
+ # Check if the attribute value is the right type (some operators need a string, or an array)
172
+ test = testModelAttribute(q.type, attr)
173
+ # If the attribute test is true, perform the query
174
+ if test then test = performQuery q.type, q.value, attr, model, q.key
175
+ # If the query is an "or" query than as soon as a match is found we return "true"
176
+ # Whereas if the query is an "and" query then we return "false" as soon as a match isn't found.
177
+ return andOr if andOr is test
178
+
179
+ # For an "or" query, if all the queries are false, then we return false
180
+ # For an "and" query, if all the queries are true, then we return true
181
+ not andOr
182
+
183
+
184
+
185
+ # An object with or, and, nor and not methods
186
+ processQuery =
187
+ $and: (models, query, itemType) -> iterator models, query, false, filter, itemType
188
+ $or: (models, query, itemType) -> iterator models, query, true, filter, itemType
189
+ $nor: (models, query, itemType) -> iterator models, query, true, reject, itemType
190
+ $not: (models, query, itemType) -> iterator models, query, false, reject, itemType
191
+
192
+ parseQuery = (query) ->
193
+ queryKeys = _(query).keys()
194
+ compoundKeys = ["$and", "$not", "$or", "$nor"]
195
+ compoundQuery = _.intersection compoundKeys, queryKeys
196
+
197
+ # If no compound methods are found then use the "and" iterator
198
+ if compoundQuery.length is 0
199
+ return [{type:"$and", parsedQuery:parseSubQuery(query)}]
200
+ else
201
+ # Detect if there is an implicit $and compundQuery operator
202
+ if compoundQuery.length isnt queryKeys.length
203
+ # Add the and compund query operator (with a sanity check that it doesn't exist)
204
+ if "$and" not in compoundQuery
205
+ query.$and = {}
206
+ compoundQuery.unshift "$and"
207
+ for own key, val of query when key not in compoundKeys
208
+ query.$and[key] = val
209
+ delete query[key]
210
+ return (for type in compoundQuery
211
+ {type, parsedQuery:parseSubQuery(query[type])})
212
+
213
+
214
+ runQuery = (items, query, itemType) ->
215
+ query = parseQuery(query) unless itemType
216
+ reduceIterator = (memo, queryItem) ->
217
+ processQuery[queryItem.type] memo, queryItem.parsedQuery, itemType
218
+ _.reduce query, reduceIterator, items
219
+
220
+
221
+ # This method attempts to retrieve the result from the cache.
222
+ # If no match is found in the cache, then the query is run and
223
+ # the results are saved in the cache
224
+ getCache = (collection, query, options) ->
225
+ # Convert the query to a string to use as a key in the cache
226
+ queryString = JSON.stringify query
227
+ # Create cache if doesn't exist
228
+ cache = collection._queryCache ?= {}
229
+ # Retrieve cached results
230
+ models = cache[queryString]
231
+ # If no results are retrieved then use the get_models method and cache the result
232
+ unless models
233
+ models = getSortedModels collection, query, options
234
+ cache[queryString] = models
235
+ # Return the results
236
+ models
237
+
238
+
239
+ # Gets the results and optionally sorts them
240
+ getSortedModels = (collection, query, options) ->
241
+ models = runQuery(collection.models, query)
242
+ if options.sortBy then models = sortModels models, options
243
+ models
244
+
245
+ # Sorts models either be a model attribute or with a callback
246
+ sortModels = (models, options) ->
247
+ # If the sortBy param is a string then we sort according to the model attribute with that string as a key
248
+ if _(options.sortBy).isString()
249
+ models = _(models).sortBy (model) -> model.get(options.sortBy)
250
+ # If a function is supplied then it is passed directly to the sortBy iterator
251
+ else if _(options.sortBy).isFunction()
252
+ models = _(models).sortBy(options.sortBy)
253
+
254
+ # If there is an order property of "desc" then the results can be reversed
255
+ # (sortBy provides result in ascending order by default)
256
+ if options.order is "desc" then models = models.reverse()
257
+ # The sorted models are returned
258
+ models
259
+
260
+ # Slices the results set according to the supplied options
261
+ pageModels = (models, options) ->
262
+ # Expects object in the form: {limit: num, offset: num, page: num, pager:callback}
263
+ if options.offset then start = options.offset
264
+ else if options.page then start = (options.page - 1) * options.limit
265
+ else start = 0
266
+
267
+ end = start + options.limit
268
+
269
+ # The results are sliced according to the calculated start and end params
270
+ sliced_models = models[start...end]
271
+
272
+ if options.pager and _.isFunction(options.pager)
273
+ total_pages = Math.ceil (models.length / options.limit)
274
+ options.pager total_pages, sliced_models
275
+
276
+ sliced_models
277
+
278
+
279
+ Backbone.QueryCollection = Backbone.Collection.extend
280
+
281
+ # The main query method
282
+ query: (query, options = {}) ->
283
+
284
+ # Retrieve matching models using the supplied query
285
+ if options.cache
286
+ models = getCache @, query, options
287
+ else
288
+ models = getSortedModels @, query, options
289
+
290
+ # If a limit param is specified than slice the results
291
+ if options.limit then models = pageModels models, options
292
+
293
+ # Return the results
294
+ models
295
+
296
+ findOne: (query) -> @query(query)[0]
297
+
298
+ # Where method wraps query and returns a new collection
299
+ whereBy: (params, options = {})->
300
+ new @constructor @query params, options
301
+
302
+ # Helper method to reset the query cache
303
+ # Defined as a separate method to make it easy to bind to collection's change/add/remove events
304
+ resetQueryCache: -> @_queryCache = {}
305
+
306
+ # On the server the new Query Collection is added to exports
307
+ exports.QueryCollection = Backbone.QueryCollection
308
+ ).call this, if typeof define == 'function' and define.amd then define else (id, factory) ->
309
+ unless typeof exports is 'undefined'
310
+ factory ((id) -> require id), exports
311
+ else
312
+ # Load Underscore and backbone. No need to export QueryCollection in an module-less environment
313
+ factory ((id) -> this[if id == 'underscore' then '_' else 'Backbone']), {}
314
+ return