eyeballs 0.3.2

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 (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
+ });