eyeballs 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/CHANGELOG +15 -0
  2. data/README.md +293 -0
  3. data/Rakefile +45 -0
  4. data/bin/eyeballs +9 -0
  5. data/config.ru +2 -0
  6. data/dist/jquery-1.4.2.min.js +154 -0
  7. data/dist/jquery.livequery.js +226 -0
  8. data/dist/mustache.js +324 -0
  9. data/eyeballs.gemspec +86 -0
  10. data/eyeballs.js.gemspec +83 -0
  11. data/lib/eyeballs.rb +11 -0
  12. data/lib/eyeballs/app_detector.rb +29 -0
  13. data/lib/eyeballs/app_generator.rb +30 -0
  14. data/lib/eyeballs/cli.rb +14 -0
  15. data/lib/eyeballs/controller_generator.rb +26 -0
  16. data/lib/eyeballs/model_generator.rb +26 -0
  17. data/lib/eyeballs/scaffold_generator.rb +66 -0
  18. data/spec/app_generator_spec.rb +51 -0
  19. data/spec/controller_generator_spec.rb +22 -0
  20. data/spec/model_generator_spec.rb +23 -0
  21. data/spec/rack_app_detector_spec.rb +25 -0
  22. data/spec/scaffold_generator_spec.rb +42 -0
  23. data/spec/spec_helper.rb +42 -0
  24. data/src/jquery.o_O.couchdb.js +107 -0
  25. data/src/jquery.o_O.dom.js +37 -0
  26. data/src/jquery.o_O.js +120 -0
  27. data/src/jquery.o_O.rails.js +68 -0
  28. data/src/o_O.js +286 -0
  29. data/src/o_O.localstorage.js +60 -0
  30. data/templates/app_root/index.html +26 -0
  31. data/templates/controller.js +3 -0
  32. data/templates/model.js +3 -0
  33. data/templates/scaffold_controller.js +75 -0
  34. data/templates/scaffold_edit.html.mustache +13 -0
  35. data/templates/scaffold_index.html +47 -0
  36. data/templates/scaffold_partial.html.mustache +12 -0
  37. data/test/unit/qunit.css +119 -0
  38. data/test/unit/qunit.js +1069 -0
  39. data/test/unit/test_controller.html +137 -0
  40. data/test/unit/test_dom.html +81 -0
  41. data/test/unit/test_dom_with_callbacks.html +121 -0
  42. data/test/unit/test_form.html +42 -0
  43. data/test/unit/test_localstorage.html +79 -0
  44. data/test/unit/test_model.html +136 -0
  45. data/test/unit/test_model_with_callbacks.html +118 -0
  46. data/test/unit/test_rails.html +97 -0
  47. metadata +117 -0
data/src/o_O.js ADDED
@@ -0,0 +1,286 @@
1
+ var o_O = function(){
2
+
3
+ var bind_to;
4
+ var object_to_bind_to = arguments[2];
5
+ bind_to = (object_to_bind_to) ? object_to_bind_to : window;
6
+
7
+ if(typeof arguments[1] === 'object')
8
+ {
9
+ var controller_name = arguments[0];
10
+ bind_to[controller_name] = o_O.controller.initialize(controller_name, arguments[1]);
11
+ return bind_to[controller_name];
12
+ }
13
+
14
+ if(typeof arguments[1] === 'function')
15
+ {
16
+
17
+ var model_name = arguments[0];
18
+ var model_initializer = arguments[1];
19
+ bind_to[model_name] = o_O.model.initialize(model_name, model_initializer);
20
+
21
+ if(typeof o_O.models !== 'object')
22
+ {
23
+ o_O.models = {};
24
+ }
25
+ o_O.models[model_name] = bind_to[model_name];
26
+
27
+ return bind_to[model_name];
28
+ }
29
+ }
30
+
31
+ o_O.model = {
32
+ adapter: false,
33
+ initialize: function(model_name, callback){
34
+ var callback = callback;
35
+ var class_methods, instance_methods, initializer_methods;
36
+ var validates_presence_of, validates_length_of;
37
+ var table_name = model_name.toLowerCase() + 's';
38
+
39
+ class_methods = {
40
+ validations: {presence: [], lengthliness: [], custom: []},
41
+ methods: {},
42
+ validates_presence_of: function(field){
43
+ this.validations.presence.push({field: field});
44
+ },
45
+ validates_length_of: function(field, options){
46
+ options.field = field;
47
+ this.validations.lengthliness.push(options);
48
+ },
49
+ validates: function(validation){
50
+ this.validations.custom.push(validation)
51
+ }
52
+ }
53
+
54
+ var run_callback = function(callback, method, args){
55
+ try{
56
+ if(typeof callback === 'function' && method === 'success')
57
+ {
58
+ callback(args);
59
+ }
60
+ if(typeof callback === 'object' && typeof callback[method] === 'function')
61
+ {
62
+ callback[method](args);
63
+ }
64
+ }
65
+ catch(e)
66
+ {
67
+ if(typeof console === 'object')
68
+ {
69
+ console.log(e);
70
+ }
71
+ else
72
+ {
73
+ alert(e);
74
+ }
75
+ }
76
+ }
77
+
78
+ var config = callback(class_methods);
79
+ instance_methods = {
80
+ adapter: o_O.model.adapter,
81
+ destroy: function(callback){
82
+ run_callback(callback, 'loading', this)
83
+ if(this.adapter)
84
+ {
85
+ this.adapter.destroy(this, function(returned_object){
86
+ run_callback(callback, 'success', returned_object);
87
+ });
88
+ }
89
+ else
90
+ {
91
+ run_callback(callback, 'success', this)
92
+ }
93
+ return this;
94
+ },
95
+ model_name: model_name,
96
+ save: function(callback){
97
+ if(this.valid())
98
+ {
99
+ run_callback(callback, 'loading', this);
100
+ if(this.adapter)
101
+ {
102
+ var model = this;
103
+ this.adapter.save(this, function(returned_object){
104
+ var initialized_object = o_O.models[model.model_name].initialize(returned_object);
105
+ initialized_object.new_record = false;
106
+ run_callback(callback, 'success', initialized_object);
107
+ });
108
+ }
109
+ else
110
+ {
111
+ run_callback(callback, 'success', this);
112
+ }
113
+ return this;
114
+ }
115
+ else
116
+ {
117
+ run_callback(callback, 'invalid', this);
118
+ }
119
+ },
120
+ table_name: table_name,
121
+ to_json: function(){
122
+ var serialized_object = {};
123
+ for(var i = 0; i < this.attributes.length; i++);
124
+ {
125
+ var index = i - 1;
126
+ var attribute_name = this.attributes[index];
127
+ serialized_object[this.attributes[index]] = this[this.attributes[index]];
128
+ }
129
+ serialized_object._model_name = this.model_name;
130
+ return JSON.stringify(serialized_object);
131
+ },
132
+ update_attributes: function(attributes, callback){
133
+ for(var attribute in attributes)
134
+ {
135
+ this[attribute] = attributes[attribute];
136
+ }
137
+ this.save(callback);
138
+ },
139
+ valid: function(){
140
+ this.errors = [];
141
+
142
+ o_O.validations.run(this);
143
+
144
+ if(this.errors.length == 0)
145
+ {
146
+ return true;
147
+ }
148
+ else
149
+ {
150
+ return false;
151
+ }
152
+ },
153
+ errors: [],
154
+ validations: class_methods.validations
155
+ }
156
+ for(method in class_methods.methods)
157
+ {
158
+ instance_methods[method] = class_methods.methods[method]
159
+ }
160
+
161
+ initializer_methods = {
162
+ adapter: o_O.model.adapter,
163
+ all: function(callback){
164
+ if(this.adapter)
165
+ {
166
+ return this.adapter.all(this, callback);
167
+ }
168
+ },
169
+ initialize: function(attributes){
170
+ if(!attributes) { var attributes = {}; };
171
+ var initialized_attributes = [];
172
+ for( var attribute in attributes )
173
+ {
174
+ initialized_attributes.push(attribute);
175
+ }
176
+ attributes['attributes'] = initialized_attributes;
177
+ for ( var method in instance_methods ) {
178
+ attributes[method] = instance_methods[method];
179
+ }
180
+ if(!attributes['id'])
181
+ {
182
+ attributes['id'] = o_O.uuid();
183
+ }
184
+ if(!attributes['new_record'])
185
+ {
186
+ attributes['new_record'] = true;
187
+ }
188
+ return attributes;
189
+ },
190
+ find: function(id, callback){
191
+ if(this.adapter)
192
+ {
193
+ var model = this;
194
+ return this.adapter.find(this, id, function(returned_object){
195
+ if(typeof callback === 'function')
196
+ {
197
+ found_object = model.initialize(returned_object);
198
+ if(!found_object['new_record'])
199
+ {
200
+ found_object['new_record'] = false;
201
+ }
202
+ callback(found_object);
203
+ }
204
+ });
205
+ }
206
+ },
207
+ model_name: model_name,
208
+ table_name: table_name
209
+ }
210
+
211
+ return initializer_methods;
212
+ }
213
+ }
214
+
215
+ o_O.validations = {
216
+ run: function(object){
217
+ this.run_custom_validations(object);
218
+ this.run_length_validations(object);
219
+ this.run_presence_validations(object);
220
+ },
221
+ run_custom_validations: function(object){
222
+ for(var i = 0; i < object.validations.custom.length; i++)
223
+ {
224
+ object.validations.custom[i](object);
225
+ }
226
+ },
227
+ run_length_validations: function(object){
228
+ for(var i = 0; i < object.validations.lengthliness.length; i++)
229
+ {
230
+ var field = object.validations.lengthliness[i].field;
231
+ var max = object.validations.lengthliness[i].max
232
+ var min = object.validations.lengthliness[i].min
233
+ if(object[field])
234
+ {
235
+ if(max && object[field].length > max)
236
+ {
237
+ var message = field + ' should be less than ' + max + ' characters';
238
+ object.errors.push({field: field, type: 'length', message: message});
239
+ }
240
+ if(min && object[field].length < min)
241
+ {
242
+ var message = field + ' should be greater than ' + min + ' characters';
243
+ object.errors.push({field: field, type: 'length', message: message});
244
+ }
245
+ }
246
+ }
247
+ },
248
+ run_presence_validations: function(object){
249
+ for(var i = 0; i < object.validations.presence.length; i++)
250
+ {
251
+ var field = object.validations.presence[i].field;
252
+ if(object[field] == '' || object[field] == null)
253
+ {
254
+ var message = field + ' should be present';
255
+ object.errors.push({field: field, type: 'presence', message: message})
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ o_O.config = {}
262
+ o_O.templates = {}
263
+
264
+ o_O._uuid_default_prefix = '';
265
+
266
+ o_O._uuidlet = function () {
267
+ return(((1+Math.random())*0x10000)|0).toString(16).substring(1);
268
+ };
269
+
270
+ o_O.uuid = function (p) {
271
+ if (typeof(p) == 'object' && typeof(p.prefix) == 'string') {
272
+ o_O._uuid_default_prefix = p.prefix;
273
+ } else {
274
+ p = p || o_O._uuid_default_prefix || '';
275
+ return(p+o_O._uuidlet()+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+o_O._uuidlet()+o_O._uuidlet());
276
+ };
277
+ };
278
+
279
+ o_O.alert_errors = function(object){
280
+ var error_message = '';
281
+ for(i = 0; i < object.errors.length; i++)
282
+ {
283
+ error_message = error_message + object.errors[i].message + "\n";
284
+ }
285
+ alert(error_message);
286
+ }
@@ -0,0 +1,60 @@
1
+ if(typeof localStorage === 'object')
2
+ {
3
+ // We're storing locally, baby!
4
+ o_O.localstorage = {
5
+ all: function(model, callback){
6
+ var all_objects = []
7
+ for(var record in this.table(model))
8
+ {
9
+ all_objects.push(this.table(model)[record]);
10
+ }
11
+ if(typeof callback === 'function')
12
+ {
13
+ callback(all_objects);
14
+ }
15
+ return all_objects;
16
+ },
17
+ destroy: function(object, callback){
18
+ var table = this.table(object)
19
+ delete table[object.id]
20
+ localStorage.setItem(object.table_name, JSON.stringify(table))
21
+ if(typeof callback === 'function')
22
+ {
23
+ callback(object)
24
+ }
25
+ },
26
+ save: function(object, callback)
27
+ {
28
+ var all = this.table(object)
29
+ all[object.id] = object;
30
+ localStorage.setItem(object.table_name, JSON.stringify(all))
31
+ if(typeof callback === 'function')
32
+ {
33
+ callback(object);
34
+ }
35
+ },
36
+ table: function(object)
37
+ {
38
+ var all;
39
+ var stored_all = localStorage.getItem(object.table_name);
40
+ if(stored_all == null)
41
+ {
42
+ return {};
43
+ }
44
+ else
45
+ {
46
+ return JSON.parse(stored_all);
47
+ }
48
+ },
49
+ find: function(model, id, callback)
50
+ {
51
+ var object = this.table(model)[id]
52
+ object.id = id;
53
+ if(typeof callback === 'function')
54
+ {
55
+ callback(object);
56
+ }
57
+ return object;
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
+ "http://www.w3.org/TR/html4/loose.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
6
+ <title>Welcome to eyeballs.js</title>
7
+ </head>
8
+
9
+ <body>
10
+ <h2>Welcome to eyeballs.js</h2>
11
+
12
+ <p>A world of javascript goodness awaits!</p>
13
+
14
+ <p>As you add models and controllers, don't forget to include them!</p>
15
+
16
+ <script src="vendor/jquery/jquery-1.4.2.min.js"></script>
17
+ <script src="vendor/jquery/jquery.livequery.js"></script>
18
+ <script src="vendor/jquery/mustache.js"></script>
19
+ <script src="vendor/eyeballs/o_O.js"></script>
20
+ <script src="vendor/eyeballs/jquery.o_O.js"></script>
21
+ <script src="vendor/eyeballs/o_O.localstorage.js"></script>
22
+ <script type="text/javascript" charset="utf-8">
23
+ o_O.model.adapter = o_O.localstorage;
24
+ </script>
25
+ </body>
26
+ </html>
@@ -0,0 +1,3 @@
1
+ o_O('<%= name.capitalize -%>Controller', {
2
+
3
+ })
@@ -0,0 +1,3 @@
1
+ o_O('<%= name.capitalize %>', function(<%= name.downcase %>){
2
+
3
+ })
@@ -0,0 +1,75 @@
1
+ o_O('<%= name.capitalize.pluralize -%>Controller', {
2
+ index: function(){
3
+ <%= name.capitalize %>.all(function(<%= name.downcase.pluralize %>){
4
+ for(var id in <%= name.downcase.pluralize %>)
5
+ {
6
+ var <%= name.downcase %> = <%= name.downcase.pluralize %>[id];
7
+ o_O.render('<%= name.downcase.pluralize %>/_<%= name.downcase %>', <%= name.downcase %>, {append: 'div#<%= name.pluralize %>'})
8
+ }
9
+ });
10
+ },
11
+ new: function(){
12
+ o_O.render('<%= name.downcase.pluralize %>/new', {}, {before: 'div#<%= name.pluralize %>'})
13
+ },
14
+ create: function(){
15
+ var <%= name.downcase %> = <%= name.capitalize %>.initialize(o_O.params($(this)));
16
+ var form = $(this);
17
+ <%= name.downcase %>.save({
18
+ invalid: function(<%= name.downcase %>){
19
+ o_O.alert_errors(<%= name.downcase %>);
20
+ },
21
+ success: function(<%= name.downcase %>){
22
+ o_O.render('<%= name.downcase.pluralize %>/_<%= name.downcase %>', <%= name.downcase %>, {prepend: 'div#<%= name.downcase.pluralize %>'});
23
+ form.find('input[type=text], textarea').val('');
24
+ }
25
+ })
26
+ },
27
+ edit: function(){
28
+ <%= name.downcase %>_div = $(this).parents('div.<%= name.downcase %>');
29
+ review = <%= name.capitalize %>.find(<%= name.downcase %>_div.attr('data-id'), function(<%= name.downcase %>){
30
+ o_O.get_template('<%= name.downcase.pluralize %>/edit', <%= name.downcase %>, function(data, template){
31
+ edit_<%= name.downcase %> = Mustache.to_html(template, data);
32
+ <%= name.downcase %>_div.hide().after(edit_<%= name.downcase %>);
33
+ });
34
+ });
35
+ },
36
+ cancel_edit: function(){
37
+ edit_<%= name.downcase %>_div = $(this).parents('div.edit-<%= name.downcase %>');
38
+ <%= name.downcase %>_div = edit_<%= name.downcase %>_div.prev('div.<%= name.downcase %>:first');
39
+ edit_<%= name.downcase %>_div.remove();
40
+ <%= name.downcase %>_div.show();
41
+ },
42
+ update: function(){
43
+ edit_<%= name.downcase %>_div = $(this).parents('div.edit-<%= name.downcase %>');
44
+ review_div = edit_<%= name.downcase %>_div.prev('div.<%= name.downcase %>:first');
45
+ var form = $(this)
46
+ <%= name.capitalize %>.find(form.attr('data-id'), function(<%= name.capitalize %>){
47
+ if(<%= name.capitalize %>.valid())
48
+ {
49
+ <%= name.capitalize %>.update_attributes(o_O.params(form), function(updated_<%= name.downcase %>){
50
+ o_O.get_template('<%= name.downcase.pluralize %>/_<%= name.downcase %>', updated_<%= name.downcase %>, function(data, template){
51
+ var template = Mustache.to_html(template, data);
52
+ edit_<%= name.downcase %>_div.replaceWith(template);
53
+ <%= name.downcase %>_div.remove();
54
+ });
55
+ });
56
+ }
57
+ else
58
+ {
59
+ o_O.alert_errors(<%= name.downcase %>);
60
+ }
61
+ });
62
+ },
63
+ destroy: function(){
64
+ if(confirm('Are You sure?'))
65
+ {
66
+ $(this).parents('div.<%= name.downcase %>:first').slideToggle(function(){
67
+ var div = $(this);
68
+ <%= name.capitalize %>.find($(this).attr('data-id'), function(<%= name.downcase %>){
69
+ <%= name.downcase %>.destroy();
70
+ div.remove();
71
+ });
72
+ });
73
+ }
74
+ },
75
+ });