rails-backbone 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
- # Backbone-Rails [![Build Status](https://secure.travis-ci.org/codebrew/backbone-rails.png)](https://secure.travis-ci.org/codebrew/backbone-rails)
1
+ # Backbone-Rails [![Build Status](https://secure.travis-ci.org/codebrew/backbone-rails.png)](http://travis-ci.org/codebrew/backbone-rails)
2
2
 
3
- Easily setup and use backbone.js (0.5.0) with rails 3.1
3
+ Easily setup and use backbone.js (0.5.3) with rails 3.1
4
+
5
+ Follow [@TheRyanFitz on Twitter](http://twitter.com/#!/TheRyanFitz). Tweet any questions or suggestions you have about the project.
4
6
 
5
7
  ## Rails 3.1 setup
6
8
  This gem requires the use of rails 3.1, coffeescript and the new rails asset pipeline provided by sprockets.
7
9
 
8
- This gem vendors the latest version of underscore.js and backbones.js for Rails 3.1 and greater. The files will be added to the asset pipeline and available for you to use.
10
+ This gem vendors the latest version of underscore.js and backbone.js for Rails 3.1 and greater. The files will be added to the asset pipeline and available for you to use.
9
11
 
10
12
  ### Installation
11
13
 
@@ -30,7 +32,7 @@ Running `rails g backbone:install` will create the following directory structure
30
32
  It will also create a toplevel app_name.coffee file to setup namespacing and setup initial requires.
31
33
 
32
34
  ## Generators
33
- backbone-rails provides 3 simple generators to help get you started using bacbone.js with rails 3.1.
35
+ backbone-rails provides 3 simple generators to help get you started using backbone.js with rails 3.1.
34
36
  The generators will only create client side code (javascript).
35
37
 
36
38
  ### Model Generator
@@ -85,5 +87,15 @@ Edit your posts index view `app/views/posts/index.html.erb` with the following c
85
87
  });
86
88
  </script>
87
89
 
90
+ If you prefer haml, this is equivalent to inserting the following code into `app/views/posts/index.html.haml`:
91
+
92
+ :javascript
93
+ $(function() {
94
+ // Blog is the app name
95
+ window.router = new Blog.Routers.PostsRouter({posts: #{@posts.to_json.html_safe}});
96
+ Backbone.history.start();
97
+ });
98
+
99
+
88
100
  Now start your server `rails s` and browse to [localhost:3000/posts](http://localhost:3000/posts)
89
101
  You should now have a fully functioning single page crud app for Post models.
@@ -5,7 +5,7 @@ class <%= model_namespace %> extends Backbone.Model
5
5
  <% attributes.each do |attribute| -%>
6
6
  <%= attribute.name %>: null
7
7
  <% end -%>
8
-
8
+
9
9
  class <%= collection_namespace %>Collection extends Backbone.Collection
10
10
  model: <%= model_namespace %>
11
- url: '<%= route_url %>'
11
+ url: '<%= route_url %>'
@@ -47,9 +47,9 @@ module Backbone
47
47
  end
48
48
 
49
49
  def uncapitalize(str)
50
- str[0, 1].downcase + str[1..-1]
50
+ str[0, 1].downcase << str[1..-1]
51
51
  end
52
52
 
53
53
  end
54
54
  end
55
- end
55
+ end
@@ -1,14 +1,14 @@
1
1
  class <%= router_namespace %>Router extends Backbone.Router
2
2
  initialize: (options) ->
3
-
3
+
4
4
  routes:
5
5
  <% actions.each do |action| -%>
6
6
  "/<%= action %>": "<%= action %>"
7
7
  <% end -%>
8
-
8
+
9
9
  <% actions.each do |action| -%>
10
10
  <%= action %>: ->
11
11
  @view = new <%= "#{view_namespace}.#{action.camelize}View()" %>
12
12
  $("#<%= plural_name %>").html(@view.render().el)
13
-
14
- <% end -%>
13
+
14
+ <% end -%>
@@ -2,7 +2,7 @@
2
2
 
3
3
  class <%= view_namespace %>.<%= @action.camelize %>View extends Backbone.View
4
4
  template: JST["<%= jst @action %>"]
5
-
5
+
6
6
  render: ->
7
7
  $(@el).html(@template())
8
- return this
8
+ return this
@@ -5,7 +5,7 @@ class <%= model_namespace %> extends Backbone.Model
5
5
  <% attributes.each do |attribute| -%>
6
6
  <%= attribute.name %>: null
7
7
  <% end -%>
8
-
8
+
9
9
  class <%= collection_namespace %>Collection extends Backbone.Collection
10
10
  model: <%= model_namespace %>
11
- url: '<%= route_url %>'
11
+ url: '<%= route_url %>'
@@ -20,13 +20,12 @@ class <%= router_namespace %>Router extends Backbone.Router
20
20
 
21
21
  show: (id) ->
22
22
  <%= singular_name %> = @<%= plural_name %>.get(id)
23
-
23
+
24
24
  @view = new <%= "#{view_namespace}.ShowView(model: #{singular_name})" %>
25
25
  $("#<%= plural_name %>").html(@view.render().el)
26
-
26
+
27
27
  edit: (id) ->
28
28
  <%= singular_name %> = @<%= plural_name %>.get(id)
29
29
 
30
30
  @view = new <%= "#{view_namespace}.EditView(model: #{singular_name})" %>
31
31
  $("#<%= plural_name %>").html(@view.render().el)
32
-
@@ -2,23 +2,23 @@
2
2
 
3
3
  class <%= view_namespace %>.EditView extends Backbone.View
4
4
  template : JST["<%= jst 'edit' %>"]
5
-
5
+
6
6
  events :
7
7
  "submit #edit-<%= singular_name %>" : "update"
8
-
8
+
9
9
  update : (e) ->
10
10
  e.preventDefault()
11
11
  e.stopPropagation()
12
-
12
+
13
13
  @model.save(null,
14
14
  success : (<%= singular_name %>) =>
15
15
  @model = <%= singular_name %>
16
16
  window.location.hash = "/#{@model.id}"
17
17
  )
18
-
18
+
19
19
  render : ->
20
- $(this.el).html(this.template(@model.toJSON() ))
21
-
20
+ $(@el).html(@template(@model.toJSON() ))
21
+
22
22
  this.$("form").backboneLink(@model)
23
-
24
- return this
23
+
24
+ return this
@@ -2,21 +2,19 @@
2
2
 
3
3
  class <%= view_namespace %>.IndexView extends Backbone.View
4
4
  template: JST["<%= jst 'index' %>"]
5
-
5
+
6
6
  initialize: () ->
7
- _.bindAll(this, 'addOne', 'addAll', 'render')
8
-
9
7
  @options.<%= plural_model_name %>.bind('reset', @addAll)
10
-
11
- addAll: () ->
8
+
9
+ addAll: () =>
12
10
  @options.<%= plural_model_name %>.each(@addOne)
13
-
14
- addOne: (<%= singular_model_name %>) ->
11
+
12
+ addOne: (<%= singular_model_name %>) =>
15
13
  view = new <%= view_namespace %>.<%= singular_name.camelize %>View({model : <%= singular_model_name %>})
16
14
  @$("tbody").append(view.render().el)
17
-
18
- render: ->
15
+
16
+ render: =>
19
17
  $(@el).html(@template(<%= plural_model_name %>: @options.<%= plural_model_name %>.toJSON() ))
20
18
  @addAll()
21
-
22
- return this
19
+
20
+ return this
@@ -2,18 +2,18 @@
2
2
 
3
3
  class <%= view_namespace %>.<%= singular_name.camelize %>View extends Backbone.View
4
4
  template: JST["<%= jst singular_name %>"]
5
-
5
+
6
6
  events:
7
7
  "click .destroy" : "destroy"
8
-
8
+
9
9
  tagName: "tr"
10
-
10
+
11
11
  destroy: () ->
12
12
  @model.destroy()
13
13
  this.remove()
14
-
14
+
15
15
  return false
16
-
16
+
17
17
  render: ->
18
- $(this.el).html(@template(@model.toJSON() ))
19
- return this
18
+ $(@el).html(@template(@model.toJSON() ))
19
+ return this
@@ -1,11 +1,11 @@
1
1
  <%= view_namespace %> ||= {}
2
2
 
3
- class <%= view_namespace %>.NewView extends Backbone.View
3
+ class <%= view_namespace %>.NewView extends Backbone.View
4
4
  template: JST["<%= jst 'new' %>"]
5
-
5
+
6
6
  events:
7
7
  "submit #new-<%= singular_name %>": "save"
8
-
8
+
9
9
  constructor: (options) ->
10
10
  super(options)
11
11
  @model = new @collection.model()
@@ -13,25 +13,25 @@ class <%= view_namespace %>.NewView extends Backbone.View
13
13
  @model.bind("change:errors", () =>
14
14
  this.render()
15
15
  )
16
-
16
+
17
17
  save: (e) ->
18
18
  e.preventDefault()
19
19
  e.stopPropagation()
20
-
20
+
21
21
  @model.unset("errors")
22
-
23
- @collection.create(@model.toJSON(),
22
+
23
+ @collection.create(@model.toJSON(),
24
24
  success: (<%= singular_name %>) =>
25
25
  @model = <%= singular_name %>
26
26
  window.location.hash = "/#{@model.id}"
27
-
27
+
28
28
  error: (<%= singular_name %>, jqXHR) =>
29
29
  @model.set({errors: $.parseJSON(jqXHR.responseText)})
30
30
  )
31
-
31
+
32
32
  render: ->
33
- $(this.el).html(@template(@model.toJSON() ))
34
-
33
+ $(@el).html(@template(@model.toJSON() ))
34
+
35
35
  this.$("form").backboneLink(@model)
36
-
37
- return this
36
+
37
+ return this
@@ -2,7 +2,7 @@
2
2
 
3
3
  class <%= view_namespace %>.ShowView extends Backbone.View
4
4
  template: JST["<%= jst 'show' %>"]
5
-
5
+
6
6
  render: ->
7
- $(this.el).html(@template(@model.toJSON() ))
8
- return this
7
+ $(@el).html(@template(@model.toJSON() ))
8
+ return this
@@ -25,6 +25,8 @@
25
25
  beforeSend: function( xhr ) {
26
26
  var token = $('meta[name="csrf-token"]').attr('content');
27
27
  if (token) xhr.setRequestHeader('X-CSRF-Token', token);
28
+
29
+ model.trigger('sync:start');
28
30
  }
29
31
  }, options);
30
32
 
@@ -51,6 +53,13 @@
51
53
  if (params.type !== 'GET') {
52
54
  params.processData = false;
53
55
  }
56
+
57
+ // Trigger the sync end event
58
+ var complete = options.complete;
59
+ options.complete = function(jqXHR, textStatus) {
60
+ model.trigger('sync:end');
61
+ if (complete) complete(jqXHR, textStatus);
62
+ };
54
63
 
55
64
  // Make the request.
56
65
  return $.ajax(params);
@@ -1,4 +1,4 @@
1
- // Underscore.js 1.1.7
1
+ // Underscore.js 1.2.2
2
2
  // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
3
3
  // Underscore is freely distributable under the MIT license.
4
4
  // Portions of Underscore are inspired or borrowed from Prototype,
@@ -48,19 +48,26 @@
48
48
  // Create a safe reference to the Underscore object for use below.
49
49
  var _ = function(obj) { return new wrapper(obj); };
50
50
 
51
- // Export the Underscore object for **CommonJS**, with backwards-compatibility
52
- // for the old `require()` API. If we're not in CommonJS, add `_` to the
53
- // global object.
54
- if (typeof module !== 'undefined' && module.exports) {
55
- module.exports = _;
56
- _._ = _;
51
+ // Export the Underscore object for **Node.js** and **"CommonJS"**, with
52
+ // backwards-compatibility for the old `require()` API. If we're not in
53
+ // CommonJS, add `_` to the global object.
54
+ if (typeof exports !== 'undefined') {
55
+ if (typeof module !== 'undefined' && module.exports) {
56
+ exports = module.exports = _;
57
+ }
58
+ exports._ = _;
59
+ } else if (typeof define === 'function' && define.amd) {
60
+ // Register as a named module with AMD.
61
+ define('underscore', function() {
62
+ return _;
63
+ });
57
64
  } else {
58
65
  // Exported as a string, for Closure Compiler "advanced" mode.
59
66
  root['_'] = _;
60
67
  }
61
68
 
62
69
  // Current version.
63
- _.VERSION = '1.1.7';
70
+ _.VERSION = '1.2.2';
64
71
 
65
72
  // Collection Functions
66
73
  // --------------------
@@ -187,7 +194,7 @@
187
194
  if (obj == null) return result;
188
195
  if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
189
196
  each(obj, function(value, index, list) {
190
- if (result |= iterator.call(context, value, index, list)) return breaker;
197
+ if (result || (result = iterator.call(context, value, index, list))) return breaker;
191
198
  });
192
199
  return !!result;
193
200
  };
@@ -198,8 +205,8 @@
198
205
  var found = false;
199
206
  if (obj == null) return found;
200
207
  if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
201
- any(obj, function(value) {
202
- if (found = value === target) return true;
208
+ found = any(obj, function(value) {
209
+ return value === target;
203
210
  });
204
211
  return found;
205
212
  };
@@ -220,6 +227,7 @@
220
227
  // Return the maximum element or (element-based computation).
221
228
  _.max = function(obj, iterator, context) {
222
229
  if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
230
+ if (!iterator && _.isEmpty(obj)) return -Infinity;
223
231
  var result = {computed : -Infinity};
224
232
  each(obj, function(value, index, list) {
225
233
  var computed = iterator ? iterator.call(context, value, index, list) : value;
@@ -231,6 +239,7 @@
231
239
  // Return the minimum element (or element-based computation).
232
240
  _.min = function(obj, iterator, context) {
233
241
  if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
242
+ if (!iterator && _.isEmpty(obj)) return Infinity;
234
243
  var result = {computed : Infinity};
235
244
  each(obj, function(value, index, list) {
236
245
  var computed = iterator ? iterator.call(context, value, index, list) : value;
@@ -239,6 +248,21 @@
239
248
  return result.value;
240
249
  };
241
250
 
251
+ // Shuffle an array.
252
+ _.shuffle = function(obj) {
253
+ var shuffled = [], rand;
254
+ each(obj, function(value, index, list) {
255
+ if (index == 0) {
256
+ shuffled[0] = value;
257
+ } else {
258
+ rand = Math.floor(Math.random() * (index + 1));
259
+ shuffled[index] = shuffled[rand];
260
+ shuffled[rand] = value;
261
+ }
262
+ });
263
+ return shuffled;
264
+ };
265
+
242
266
  // Sort the object's values by a criterion produced by an iterator.
243
267
  _.sortBy = function(obj, iterator, context) {
244
268
  return _.pluck(_.map(obj, function(value, index, list) {
@@ -252,9 +276,11 @@
252
276
  }), 'value');
253
277
  };
254
278
 
255
- // Groups the object's values by a criterion produced by an iterator
256
- _.groupBy = function(obj, iterator) {
279
+ // Groups the object's values by a criterion. Pass either a string attribute
280
+ // to group by, or a function that returns the criterion.
281
+ _.groupBy = function(obj, val) {
257
282
  var result = {};
283
+ var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
258
284
  each(obj, function(value, index) {
259
285
  var key = iterator(value, index);
260
286
  (result[key] || (result[key] = [])).push(value);
@@ -298,6 +324,24 @@
298
324
  return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
299
325
  };
300
326
 
327
+ // Returns everything but the last entry of the array. Especcialy useful on
328
+ // the arguments object. Passing **n** will return all the values in
329
+ // the array, excluding the last N. The **guard** check allows it to work with
330
+ // `_.map`.
331
+ _.initial = function(array, n, guard) {
332
+ return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
333
+ };
334
+
335
+ // Get the last element of an array. Passing **n** will return the last N
336
+ // values in the array. The **guard** check allows it to work with `_.map`.
337
+ _.last = function(array, n, guard) {
338
+ if ((n != null) && !guard) {
339
+ return slice.call(array, Math.max(array.length - n, 0));
340
+ } else {
341
+ return array[array.length - 1];
342
+ }
343
+ };
344
+
301
345
  // Returns everything but the first entry of the array. Aliased as `tail`.
302
346
  // Especially useful on the arguments object. Passing an **index** will return
303
347
  // the rest of the values in the array from that index onward. The **guard**
@@ -306,20 +350,15 @@
306
350
  return slice.call(array, (index == null) || guard ? 1 : index);
307
351
  };
308
352
 
309
- // Get the last element of an array.
310
- _.last = function(array) {
311
- return array[array.length - 1];
312
- };
313
-
314
353
  // Trim out all falsy values from an array.
315
354
  _.compact = function(array) {
316
355
  return _.filter(array, function(value){ return !!value; });
317
356
  };
318
357
 
319
358
  // Return a completely flattened version of an array.
320
- _.flatten = function(array) {
359
+ _.flatten = function(array, shallow) {
321
360
  return _.reduce(array, function(memo, value) {
322
- if (_.isArray(value)) return memo.concat(_.flatten(value));
361
+ if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
323
362
  memo[memo.length] = value;
324
363
  return memo;
325
364
  }, []);
@@ -349,7 +388,7 @@
349
388
  // Produce an array that contains the union: each distinct element from all of
350
389
  // the passed-in arrays.
351
390
  _.union = function() {
352
- return _.uniq(_.flatten(arguments));
391
+ return _.uniq(_.flatten(arguments, true));
353
392
  };
354
393
 
355
394
  // Produce an array that contains every item shared between all the
@@ -397,7 +436,6 @@
397
436
  return -1;
398
437
  };
399
438
 
400
-
401
439
  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
402
440
  _.lastIndexOf = function(array, item) {
403
441
  if (array == null) return -1;
@@ -432,15 +470,25 @@
432
470
  // Function (ahem) Functions
433
471
  // ------------------
434
472
 
473
+ // Reusable constructor function for prototype setting.
474
+ var ctor = function(){};
475
+
435
476
  // Create a function bound to a given object (assigning `this`, and arguments,
436
477
  // optionally). Binding with arguments is also known as `curry`.
437
478
  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
438
479
  // We check for `func.bind` first, to fail fast when `func` is undefined.
439
- _.bind = function(func, obj) {
480
+ _.bind = function bind(func, context) {
481
+ var bound, args;
440
482
  if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
441
- var args = slice.call(arguments, 2);
442
- return function() {
443
- return func.apply(obj, args.concat(slice.call(arguments)));
483
+ if (!_.isFunction(func)) throw new TypeError;
484
+ args = slice.call(arguments, 2);
485
+ return bound = function() {
486
+ if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
487
+ ctor.prototype = func.prototype;
488
+ var self = new ctor;
489
+ var result = func.apply(self, args.concat(slice.call(arguments)));
490
+ if (Object(result) === result) return result;
491
+ return self;
444
492
  };
445
493
  };
446
494
 
@@ -476,31 +524,43 @@
476
524
  return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
477
525
  };
478
526
 
479
- // Internal function used to implement `_.throttle` and `_.debounce`.
480
- var limit = function(func, wait, debounce) {
481
- var timeout;
527
+ // Returns a function, that, when invoked, will only be triggered at most once
528
+ // during a given window of time.
529
+ _.throttle = function(func, wait) {
530
+ var context, args, timeout, throttling, more;
531
+ var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
482
532
  return function() {
483
- var context = this, args = arguments;
484
- var throttler = function() {
533
+ context = this; args = arguments;
534
+ var later = function() {
485
535
  timeout = null;
486
- func.apply(context, args);
536
+ if (more) func.apply(context, args);
537
+ whenDone();
487
538
  };
488
- if (debounce) clearTimeout(timeout);
489
- if (debounce || !timeout) timeout = setTimeout(throttler, wait);
539
+ if (!timeout) timeout = setTimeout(later, wait);
540
+ if (throttling) {
541
+ more = true;
542
+ } else {
543
+ func.apply(context, args);
544
+ }
545
+ whenDone();
546
+ throttling = true;
490
547
  };
491
548
  };
492
549
 
493
- // Returns a function, that, when invoked, will only be triggered at most once
494
- // during a given window of time.
495
- _.throttle = function(func, wait) {
496
- return limit(func, wait, false);
497
- };
498
-
499
550
  // Returns a function, that, as long as it continues to be invoked, will not
500
551
  // be triggered. The function will be called after it stops being called for
501
552
  // N milliseconds.
502
553
  _.debounce = function(func, wait) {
503
- return limit(func, wait, true);
554
+ var timeout;
555
+ return function() {
556
+ var context = this, args = arguments;
557
+ var later = function() {
558
+ timeout = null;
559
+ func.apply(context, args);
560
+ };
561
+ clearTimeout(timeout);
562
+ timeout = setTimeout(later, wait);
563
+ };
504
564
  };
505
565
 
506
566
  // Returns a function that will be executed at most one time, no matter how
@@ -539,12 +599,12 @@
539
599
 
540
600
  // Returns a function that will only be executed after being called N times.
541
601
  _.after = function(times, func) {
602
+ if (times <= 0) return func();
542
603
  return function() {
543
604
  if (--times < 1) { return func.apply(this, arguments); }
544
605
  };
545
606
  };
546
607
 
547
-
548
608
  // Object Functions
549
609
  // ----------------
550
610
 
@@ -594,6 +654,7 @@
594
654
 
595
655
  // Create a (shallow-cloned) duplicate of an object.
596
656
  _.clone = function(obj) {
657
+ if (!_.isObject(obj)) return obj;
597
658
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
598
659
  };
599
660
 
@@ -605,47 +666,103 @@
605
666
  return obj;
606
667
  };
607
668
 
608
- // Perform a deep comparison to check if two objects are equal.
609
- _.isEqual = function(a, b) {
610
- // Check object identity.
611
- if (a === b) return true;
612
- // Different types?
613
- var atype = typeof(a), btype = typeof(b);
614
- if (atype != btype) return false;
615
- // Basic equality test (watch out for coercions).
616
- if (a == b) return true;
617
- // One is falsy and the other truthy.
618
- if ((!a && b) || (a && !b)) return false;
669
+ // Internal recursive comparison function.
670
+ function eq(a, b, stack) {
671
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
672
+ // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
673
+ if (a === b) return a !== 0 || 1 / a == 1 / b;
674
+ // A strict comparison is necessary because `null == undefined`.
675
+ if (a == null || b == null) return a === b;
619
676
  // Unwrap any wrapped objects.
620
677
  if (a._chain) a = a._wrapped;
621
678
  if (b._chain) b = b._wrapped;
622
- // One of them implements an isEqual()?
623
- if (a.isEqual) return a.isEqual(b);
624
- if (b.isEqual) return b.isEqual(a);
625
- // Check dates' integer values.
626
- if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
627
- // Both are NaN?
628
- if (_.isNaN(a) && _.isNaN(b)) return false;
629
- // Compare regular expressions.
630
- if (_.isRegExp(a) && _.isRegExp(b))
631
- return a.source === b.source &&
632
- a.global === b.global &&
633
- a.ignoreCase === b.ignoreCase &&
634
- a.multiline === b.multiline;
635
- // If a is not an object by this point, we can't handle it.
636
- if (atype !== 'object') return false;
637
- // Check for different array lengths before comparing contents.
638
- if (a.length && (a.length !== b.length)) return false;
639
- // Nothing else worked, deep compare the contents.
640
- var aKeys = _.keys(a), bKeys = _.keys(b);
641
- // Different object sizes?
642
- if (aKeys.length != bKeys.length) return false;
643
- // Recursive comparison of contents.
644
- for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
645
- return true;
679
+ // Invoke a custom `isEqual` method if one is provided.
680
+ if (_.isFunction(a.isEqual)) return a.isEqual(b);
681
+ if (_.isFunction(b.isEqual)) return b.isEqual(a);
682
+ // Compare `[[Class]]` names.
683
+ var className = toString.call(a);
684
+ if (className != toString.call(b)) return false;
685
+ switch (className) {
686
+ // Strings, numbers, dates, and booleans are compared by value.
687
+ case '[object String]':
688
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
689
+ // equivalent to `new String("5")`.
690
+ return String(a) == String(b);
691
+ case '[object Number]':
692
+ a = +a;
693
+ b = +b;
694
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
695
+ // other numeric values.
696
+ return a != a ? b != b : (a == 0 ? 1 / a == 1 / b : a == b);
697
+ case '[object Date]':
698
+ case '[object Boolean]':
699
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
700
+ // millisecond representations. Note that invalid dates with millisecond representations
701
+ // of `NaN` are not equivalent.
702
+ return +a == +b;
703
+ // RegExps are compared by their source patterns and flags.
704
+ case '[object RegExp]':
705
+ return a.source == b.source &&
706
+ a.global == b.global &&
707
+ a.multiline == b.multiline &&
708
+ a.ignoreCase == b.ignoreCase;
709
+ }
710
+ if (typeof a != 'object' || typeof b != 'object') return false;
711
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
712
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
713
+ var length = stack.length;
714
+ while (length--) {
715
+ // Linear search. Performance is inversely proportional to the number of
716
+ // unique nested structures.
717
+ if (stack[length] == a) return true;
718
+ }
719
+ // Add the first object to the stack of traversed objects.
720
+ stack.push(a);
721
+ var size = 0, result = true;
722
+ // Recursively compare objects and arrays.
723
+ if (className == '[object Array]') {
724
+ // Compare array lengths to determine if a deep comparison is necessary.
725
+ size = a.length;
726
+ result = size == b.length;
727
+ if (result) {
728
+ // Deep compare the contents, ignoring non-numeric properties.
729
+ while (size--) {
730
+ // Ensure commutative equality for sparse arrays.
731
+ if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
732
+ }
733
+ }
734
+ } else {
735
+ // Objects with different constructors are not equivalent.
736
+ if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) return false;
737
+ // Deep compare objects.
738
+ for (var key in a) {
739
+ if (hasOwnProperty.call(a, key)) {
740
+ // Count the expected number of properties.
741
+ size++;
742
+ // Deep compare each member.
743
+ if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
744
+ }
745
+ }
746
+ // Ensure that both objects contain the same number of properties.
747
+ if (result) {
748
+ for (key in b) {
749
+ if (hasOwnProperty.call(b, key) && !(size--)) break;
750
+ }
751
+ result = !size;
752
+ }
753
+ }
754
+ // Remove the first object from the stack of traversed objects.
755
+ stack.pop();
756
+ return result;
757
+ }
758
+
759
+ // Perform a deep comparison to check if two objects are equal.
760
+ _.isEqual = function(a, b) {
761
+ return eq(a, b, []);
646
762
  };
647
763
 
648
- // Is a given array or object empty?
764
+ // Is a given array, string, or object empty?
765
+ // An "empty" object has no enumerable own-properties.
649
766
  _.isEmpty = function(obj) {
650
767
  if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
651
768
  for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
@@ -660,7 +777,7 @@
660
777
  // Is a given value an array?
661
778
  // Delegates to ECMA5's native Array.isArray
662
779
  _.isArray = nativeIsArray || function(obj) {
663
- return toString.call(obj) === '[object Array]';
780
+ return toString.call(obj) == '[object Array]';
664
781
  };
665
782
 
666
783
  // Is a given variable an object?
@@ -669,44 +786,50 @@
669
786
  };
670
787
 
671
788
  // Is a given variable an arguments object?
672
- _.isArguments = function(obj) {
673
- return !!(obj && hasOwnProperty.call(obj, 'callee'));
674
- };
789
+ if (toString.call(arguments) == '[object Arguments]') {
790
+ _.isArguments = function(obj) {
791
+ return toString.call(obj) == '[object Arguments]';
792
+ };
793
+ } else {
794
+ _.isArguments = function(obj) {
795
+ return !!(obj && hasOwnProperty.call(obj, 'callee'));
796
+ };
797
+ }
675
798
 
676
799
  // Is a given value a function?
677
800
  _.isFunction = function(obj) {
678
- return !!(obj && obj.constructor && obj.call && obj.apply);
801
+ return toString.call(obj) == '[object Function]';
679
802
  };
680
803
 
681
804
  // Is a given value a string?
682
805
  _.isString = function(obj) {
683
- return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
806
+ return toString.call(obj) == '[object String]';
684
807
  };
685
808
 
686
809
  // Is a given value a number?
687
810
  _.isNumber = function(obj) {
688
- return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
811
+ return toString.call(obj) == '[object Number]';
689
812
  };
690
813
 
691
- // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
692
- // that does not equal itself.
814
+ // Is the given value `NaN`?
693
815
  _.isNaN = function(obj) {
816
+ // `NaN` is the only value for which `===` is not reflexive.
694
817
  return obj !== obj;
695
818
  };
696
819
 
697
820
  // Is a given value a boolean?
698
821
  _.isBoolean = function(obj) {
699
- return obj === true || obj === false;
822
+ return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
700
823
  };
701
824
 
702
825
  // Is a given value a date?
703
826
  _.isDate = function(obj) {
704
- return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
827
+ return toString.call(obj) == '[object Date]';
705
828
  };
706
829
 
707
830
  // Is the given value a regular expression?
708
831
  _.isRegExp = function(obj) {
709
- return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
832
+ return toString.call(obj) == '[object RegExp]';
710
833
  };
711
834
 
712
835
  // Is a given value equal to null?
@@ -739,6 +862,11 @@
739
862
  for (var i = 0; i < n; i++) iterator.call(context, i);
740
863
  };
741
864
 
865
+ // Escape a string for HTML interpolation.
866
+ _.escape = function(string) {
867
+ return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
868
+ };
869
+
742
870
  // Add your own custom functions to the Underscore object, ensuring that
743
871
  // they're correctly added to the OOP wrapper as well.
744
872
  _.mixin = function(obj) {
@@ -759,7 +887,8 @@
759
887
  // following template settings to use alternative delimiters.
760
888
  _.templateSettings = {
761
889
  evaluate : /<%([\s\S]+?)%>/g,
762
- interpolate : /<%=([\s\S]+?)%>/g
890
+ interpolate : /<%=([\s\S]+?)%>/g,
891
+ escape : /<%-([\s\S]+?)%>/g
763
892
  };
764
893
 
765
894
  // JavaScript micro-templating, similar to John Resig's implementation.
@@ -771,19 +900,22 @@
771
900
  'with(obj||{}){__p.push(\'' +
772
901
  str.replace(/\\/g, '\\\\')
773
902
  .replace(/'/g, "\\'")
903
+ .replace(c.escape, function(match, code) {
904
+ return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
905
+ })
774
906
  .replace(c.interpolate, function(match, code) {
775
907
  return "'," + code.replace(/\\'/g, "'") + ",'";
776
908
  })
777
909
  .replace(c.evaluate || null, function(match, code) {
778
910
  return "');" + code.replace(/\\'/g, "'")
779
- .replace(/[\r\n\t]/g, ' ') + "__p.push('";
911
+ .replace(/[\r\n\t]/g, ' ') + ";__p.push('";
780
912
  })
781
913
  .replace(/\r/g, '\\r')
782
914
  .replace(/\n/g, '\\n')
783
915
  .replace(/\t/g, '\\t')
784
916
  + "');}return __p.join('');";
785
- var func = new Function('obj', tmpl);
786
- return data ? func(data) : func;
917
+ var func = new Function('obj', '_', tmpl);
918
+ return data ? func(data, _) : function(data) { return func(data, _) };
787
919
  };
788
920
 
789
921
  // The OOP Wrapper
@@ -842,4 +974,4 @@
842
974
  return this._wrapped;
843
975
  };
844
976
 
845
- })();
977
+ }).call(this);
metadata CHANGED
@@ -1,62 +1,58 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rails-backbone
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.5
4
5
  prerelease:
5
- version: 0.5.4
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Ryan Fitzgerald
9
9
  - Code Brew Studios
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
-
14
- date: 2011-09-04 00:00:00 -04:00
15
- default_executable:
16
- dependencies:
17
- - !ruby/object:Gem::Dependency
13
+ date: 2011-11-27 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
18
16
  name: rails
19
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &70162401622700 !ruby/object:Gem::Requirement
20
18
  none: false
21
- requirements:
19
+ requirements:
22
20
  - - ~>
23
- - !ruby/object:Gem::Version
21
+ - !ruby/object:Gem::Version
24
22
  version: 3.1.0
25
23
  type: :runtime
26
24
  prerelease: false
27
- version_requirements: *id001
28
- - !ruby/object:Gem::Dependency
25
+ version_requirements: *70162401622700
26
+ - !ruby/object:Gem::Dependency
29
27
  name: coffee-script
30
- requirement: &id002 !ruby/object:Gem::Requirement
28
+ requirement: &70162401622140 !ruby/object:Gem::Requirement
31
29
  none: false
32
- requirements:
30
+ requirements:
33
31
  - - ~>
34
- - !ruby/object:Gem::Version
32
+ - !ruby/object:Gem::Version
35
33
  version: 2.2.0
36
34
  type: :runtime
37
35
  prerelease: false
38
- version_requirements: *id002
39
- - !ruby/object:Gem::Dependency
36
+ version_requirements: *70162401622140
37
+ - !ruby/object:Gem::Dependency
40
38
  name: ejs
41
- requirement: &id003 !ruby/object:Gem::Requirement
39
+ requirement: &70162401501620 !ruby/object:Gem::Requirement
42
40
  none: false
43
- requirements:
41
+ requirements:
44
42
  - - ~>
45
- - !ruby/object:Gem::Version
43
+ - !ruby/object:Gem::Version
46
44
  version: 1.0.0
47
45
  type: :runtime
48
46
  prerelease: false
49
- version_requirements: *id003
50
- description: Quickly setup backbone.js for use with rails 3.1. Generators are provided to quickly get started.
51
- email:
47
+ version_requirements: *70162401501620
48
+ description: Quickly setup backbone.js for use with rails 3.1. Generators are provided
49
+ to quickly get started.
50
+ email:
52
51
  - ryan@codebrewstudios.com
53
52
  executables: []
54
-
55
53
  extensions: []
56
-
57
54
  extra_rdoc_files: []
58
-
59
- files:
55
+ files:
60
56
  - lib/backbone-rails.rb
61
57
  - lib/generators/backbone/install/install_generator.rb
62
58
  - lib/generators/backbone/install/templates/app.coffee
@@ -89,36 +85,34 @@ files:
89
85
  - MIT-LICENSE
90
86
  - Rakefile
91
87
  - README.md
92
- has_rdoc: true
93
88
  homepage: http://github.com/codebrew/backbone-rails
94
89
  licenses: []
95
-
96
90
  post_install_message:
97
91
  rdoc_options: []
98
-
99
- require_paths:
92
+ require_paths:
100
93
  - lib
101
- required_ruby_version: !ruby/object:Gem::Requirement
94
+ required_ruby_version: !ruby/object:Gem::Requirement
102
95
  none: false
103
- requirements:
104
- - - ">="
105
- - !ruby/object:Gem::Version
106
- hash: -3422163520620027386
107
- segments:
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ segments:
108
101
  - 0
109
- version: "0"
110
- required_rubygems_version: !ruby/object:Gem::Requirement
102
+ hash: 1776603317908361039
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
104
  none: false
112
- requirements:
113
- - - ">="
114
- - !ruby/object:Gem::Version
115
- version: "0"
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ segments:
110
+ - 0
111
+ hash: 1776603317908361039
116
112
  requirements: []
117
-
118
113
  rubyforge_project:
119
- rubygems_version: 1.6.2
114
+ rubygems_version: 1.8.11
120
115
  signing_key:
121
116
  specification_version: 3
122
117
  summary: Use backbone.js with rails 3.1
123
118
  test_files: []
124
-