knockout-rails 0.0.1

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 (59) hide show
  1. data/.gitignore +8 -0
  2. data/Gemfile +12 -0
  3. data/Gemfile.lock +134 -0
  4. data/HISTORY.md +12 -0
  5. data/README.md +106 -0
  6. data/Rakefile +37 -0
  7. data/knockout-rails.gemspec +27 -0
  8. data/lib/assets/javascripts/knockout/bindings.js.coffee +1 -0
  9. data/lib/assets/javascripts/knockout/model.js.coffee +112 -0
  10. data/lib/assets/javascripts/knockout/observables.js.coffee +1 -0
  11. data/lib/knockout-rails.rb +5 -0
  12. data/lib/knockout-rails/engine.rb +6 -0
  13. data/lib/knockout-rails/version.rb +3 -0
  14. data/lib/tasks/knockout-rails_tasks.rake +4 -0
  15. data/spec/dummy/Rakefile +7 -0
  16. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  17. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  18. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  19. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  20. data/spec/dummy/app/mailers/.gitkeep +0 -0
  21. data/spec/dummy/app/models/.gitkeep +0 -0
  22. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  23. data/spec/dummy/config.ru +4 -0
  24. data/spec/dummy/config/application.rb +53 -0
  25. data/spec/dummy/config/boot.rb +10 -0
  26. data/spec/dummy/config/database.yml +25 -0
  27. data/spec/dummy/config/environment.rb +5 -0
  28. data/spec/dummy/config/environments/development.rb +30 -0
  29. data/spec/dummy/config/environments/production.rb +60 -0
  30. data/spec/dummy/config/environments/test.rb +39 -0
  31. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  32. data/spec/dummy/config/initializers/inflections.rb +10 -0
  33. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  34. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  35. data/spec/dummy/config/initializers/session_store.rb +8 -0
  36. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  37. data/spec/dummy/config/locales/en.yml +5 -0
  38. data/spec/dummy/config/routes.rb +58 -0
  39. data/spec/dummy/lib/assets/.gitkeep +0 -0
  40. data/spec/dummy/public/404.html +26 -0
  41. data/spec/dummy/public/422.html +26 -0
  42. data/spec/dummy/public/500.html +26 -0
  43. data/spec/dummy/public/favicon.ico +0 -0
  44. data/spec/dummy/script/rails +6 -0
  45. data/spec/javascripts/knockout/bindings_spec.js.coffee +2 -0
  46. data/spec/javascripts/knockout/model_spec.js.coffee +85 -0
  47. data/spec/javascripts/knockout/observables_spec.js.coffee +3 -0
  48. data/spec/javascripts/spec.css +3 -0
  49. data/spec/javascripts/spec.js.coffee +3 -0
  50. data/spec/javascripts/support/mock-ajax.js +207 -0
  51. data/spec/knockout_spec.rb +14 -0
  52. data/spec/spec_helper.rb +10 -0
  53. data/spec/support/global.rb +7 -0
  54. data/spec/support/matchers.rb +36 -0
  55. data/vendor/assets/javascripts/knockout.js +7 -0
  56. data/vendor/assets/javascripts/knockout/knockout.js +3153 -0
  57. data/vendor/assets/javascripts/knockout/knockout.mapping.js +676 -0
  58. data/vendor/assets/javascripts/knockout/sugar-1.1.1.js +5828 -0
  59. metadata +206 -0
File without changes
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
24
+ </div>
25
+ </body>
26
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,2 @@
1
+ describe "bindings", ->
2
+ it "coming soon"
@@ -0,0 +1,85 @@
1
+ class Page extends ko.Model
2
+ @configure 'page'
3
+
4
+
5
+ describe "Model", ->
6
+
7
+ beforeEach ->
8
+ @page = new Page
9
+ id: 123
10
+ name: 'Home'
11
+ content: 'Hello'
12
+
13
+
14
+ it "should create observable attributes", ->
15
+ expect(@page.name()).toBe 'Home'
16
+ expect(@page.content()).toBe 'Hello'
17
+
18
+ it "should set an id", -> expect(@page.id()).toBe 123
19
+
20
+ it "should determine if record is persisted or not", ->
21
+ @page.id(111)
22
+ expect(@page.persisted()).toBeTruthy()
23
+ @page.id(null)
24
+ expect(@page.persisted()).toBeFalsy()
25
+
26
+ describe "Ajax", ->
27
+ beforeEach ->
28
+ jasmine.Ajax.useMock()
29
+
30
+ it "should return jQuery deferred when saving", ->
31
+ expect( @page.save().done ).toBeTruthy()
32
+
33
+ it "should include CSRF token", ->
34
+ @page.save()
35
+ csrf = mostRecentAjaxRequest().requestHeaders['X-CSRF-Token']
36
+ expect(csrf).toBeTruthy()
37
+
38
+ it "should be PUT", ->
39
+ @page.save()
40
+ @page.id 123
41
+ method = mostRecentAjaxRequest().method
42
+ expect(method).toBe "PUT"
43
+
44
+ it "should be POST", ->
45
+ @page.id null
46
+ @page.save()
47
+ method = mostRecentAjaxRequest().method
48
+ expect(method).toBe "POST"
49
+
50
+ it "should include the JSON data", ->
51
+ @page.save()
52
+ sent = mostRecentAjaxRequest().params
53
+ expect(sent).toBe JSON.stringify
54
+ page:
55
+ id: 123
56
+ name: 'Home'
57
+ content: 'Hello'
58
+
59
+ describe "errors", ->
60
+ it "should have errors for fields", ->
61
+ e = @page.errors
62
+ e.name('a')
63
+ e.content('b')
64
+ e = @page.errors
65
+ expect(e.name()).toBe 'a'
66
+ expect(e.content()).toBe 'b'
67
+
68
+ describe "on 200 response", ->
69
+ it "should clear all errors", ->
70
+ @page.errors.name('something is incorrect for whatever reason')
71
+ @page.save() # Probably we should not allow to save in the first place
72
+ mostRecentAjaxRequest().response
73
+ status: 200
74
+ responseText: "{}"
75
+ expect( @page.errors.name() ).toBeFalsy()
76
+
77
+
78
+ describe "on 422 resposne (unprocessible entity = validation error)", ->
79
+ it "should set errors for returned fields", ->
80
+ @page.save()
81
+ mostRecentAjaxRequest().response
82
+ status: 422
83
+ responseText: '{"name": ["got ya", "really"]}'
84
+ expect( @page.errors.name() ).toBe "got ya, really"
85
+
@@ -0,0 +1,3 @@
1
+ describe "observables", ->
2
+
3
+ it "coming soon"
@@ -0,0 +1,3 @@
1
+ /*
2
+ * add css using =require application
3
+ */
@@ -0,0 +1,3 @@
1
+ #=require knockout
2
+ #=require_tree ./support
3
+ #=require_tree ./
@@ -0,0 +1,207 @@
1
+ /*
2
+ Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine
3
+ BDD framework for JavaScript.
4
+
5
+ Supports both Prototype.js and jQuery.
6
+
7
+ http://github.com/pivotal/jasmine-ajax
8
+
9
+ Jasmine Home page: http://pivotal.github.com/jasmine
10
+
11
+ Copyright (c) 2008-2010 Pivotal Labs
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining
14
+ a copy of this software and associated documentation files (the
15
+ "Software"), to deal in the Software without restriction, including
16
+ without limitation the rights to use, copy, modify, merge, publish,
17
+ distribute, sublicense, and/or sell copies of the Software, and to
18
+ permit persons to whom the Software is furnished to do so, subject to
19
+ the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be
22
+ included in all copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+
32
+ */
33
+
34
+ // Jasmine-Ajax interface
35
+ var ajaxRequests = [];
36
+
37
+ function mostRecentAjaxRequest() {
38
+ if (ajaxRequests.length > 0) {
39
+ return ajaxRequests[ajaxRequests.length - 1];
40
+ } else {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ function clearAjaxRequests() {
46
+ ajaxRequests = [];
47
+ }
48
+
49
+ // Fake XHR for mocking Ajax Requests & Responses
50
+ function FakeXMLHttpRequest() {
51
+ var extend = Object.extend || $.extend;
52
+ extend(this, {
53
+ requestHeaders: {},
54
+
55
+ open: function() {
56
+ this.method = arguments[0];
57
+ this.url = arguments[1];
58
+ this.readyState = 1;
59
+ },
60
+
61
+ setRequestHeader: function(header, value) {
62
+ this.requestHeaders[header] = value;
63
+ },
64
+
65
+ abort: function() {
66
+ this.readyState = 0;
67
+ },
68
+
69
+ readyState: 0,
70
+
71
+ onreadystatechange: function(isTimeout) {
72
+ },
73
+
74
+ status: null,
75
+
76
+ send: function(data) {
77
+ this.params = data;
78
+ this.readyState = 2;
79
+ },
80
+
81
+ getResponseHeader: function(name) {
82
+ return this.responseHeaders[name];
83
+ },
84
+
85
+ getAllResponseHeaders: function() {
86
+ var responseHeaders = [];
87
+ for (var i in this.responseHeaders) {
88
+ if (this.responseHeaders.hasOwnProperty(i)) {
89
+ responseHeaders.push(i + ': ' + this.responseHeaders[i]);
90
+ }
91
+ }
92
+ return responseHeaders.join('\r\n');
93
+ },
94
+
95
+ responseText: null,
96
+
97
+ response: function(response) {
98
+ this.status = response.status;
99
+ this.responseText = response.responseText || "";
100
+ this.readyState = 4;
101
+ this.responseHeaders = response.responseHeaders ||
102
+ {"Content-type": response.contentType || "application/json" };
103
+ // uncomment for jquery 1.3.x support
104
+ // jasmine.Clock.tick(20);
105
+
106
+ this.onreadystatechange();
107
+ },
108
+ responseTimeout: function() {
109
+ this.readyState = 4;
110
+ jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000);
111
+ this.onreadystatechange('timeout');
112
+ }
113
+ });
114
+
115
+ return this;
116
+ }
117
+
118
+
119
+ jasmine.Ajax = {
120
+
121
+ isInstalled: function() {
122
+ return jasmine.Ajax.installed == true;
123
+ },
124
+
125
+ assertInstalled: function() {
126
+ if (!jasmine.Ajax.isInstalled()) {
127
+ throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()")
128
+ }
129
+ },
130
+
131
+ useMock: function() {
132
+ if (!jasmine.Ajax.isInstalled()) {
133
+ var spec = jasmine.getEnv().currentSpec;
134
+ spec.after(jasmine.Ajax.uninstallMock);
135
+
136
+ jasmine.Ajax.installMock();
137
+ }
138
+ },
139
+
140
+ installMock: function() {
141
+ if (typeof jQuery != 'undefined') {
142
+ jasmine.Ajax.installJquery();
143
+ } else if (typeof Prototype != 'undefined') {
144
+ jasmine.Ajax.installPrototype();
145
+ } else {
146
+ throw new Error("jasmine.Ajax currently only supports jQuery and Prototype");
147
+ }
148
+ jasmine.Ajax.installed = true;
149
+ },
150
+
151
+ installJquery: function() {
152
+ jasmine.Ajax.mode = 'jQuery';
153
+ jasmine.Ajax.real = jQuery.ajaxSettings.xhr;
154
+ jQuery.ajaxSettings.xhr = jasmine.Ajax.jQueryMock;
155
+
156
+ },
157
+
158
+ installPrototype: function() {
159
+ jasmine.Ajax.mode = 'Prototype';
160
+ jasmine.Ajax.real = Ajax.getTransport;
161
+
162
+ Ajax.getTransport = jasmine.Ajax.prototypeMock;
163
+ },
164
+
165
+ uninstallMock: function() {
166
+ jasmine.Ajax.assertInstalled();
167
+ if (jasmine.Ajax.mode == 'jQuery') {
168
+ jQuery.ajaxSettings.xhr = jasmine.Ajax.real;
169
+ } else if (jasmine.Ajax.mode == 'Prototype') {
170
+ Ajax.getTransport = jasmine.Ajax.real;
171
+ }
172
+ jasmine.Ajax.reset();
173
+ },
174
+
175
+ reset: function() {
176
+ jasmine.Ajax.installed = false;
177
+ jasmine.Ajax.mode = null;
178
+ jasmine.Ajax.real = null;
179
+ },
180
+
181
+ jQueryMock: function() {
182
+ var newXhr = new FakeXMLHttpRequest();
183
+ ajaxRequests.push(newXhr);
184
+ return newXhr;
185
+ },
186
+
187
+ prototypeMock: function() {
188
+ return new FakeXMLHttpRequest();
189
+ },
190
+
191
+ installed: false,
192
+ mode: null
193
+ }
194
+
195
+
196
+ // Jasmine-Ajax Glue code for Prototype.js
197
+ if (typeof Prototype != 'undefined' && Ajax && Ajax.Request) {
198
+ Ajax.Request.prototype.originalRequest = Ajax.Request.prototype.request;
199
+ Ajax.Request.prototype.request = function(url) {
200
+ this.originalRequest(url);
201
+ ajaxRequests.push(this);
202
+ };
203
+
204
+ Ajax.Request.prototype.response = function(responseOptions) {
205
+ return this.transport.response(responseOptions);
206
+ };
207
+ }
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe KnockoutRails do
4
+ subject { assets }
5
+
6
+ it { should serve 'knockout' }
7
+ it { should serve 'knockout/knockout' }
8
+ it { should serve 'knockout/knockout.mapping' }
9
+ it { should serve 'knockout/sugar-1.1.1' }
10
+
11
+ it { should serve 'knockout/model' }
12
+ it { should serve 'knockout/observables' }
13
+ it { should serve 'knockout/bindings' }
14
+ end
@@ -0,0 +1,10 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+
7
+ Rails.backtrace_cleaner.remove_silencers!
8
+
9
+ # Load support files
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -0,0 +1,7 @@
1
+ def assets
2
+ Rails.application.assets
3
+ end
4
+
5
+ def asset_for(name)
6
+ assets[name]
7
+ end