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
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eyeballs::ModelGenerator do
4
+
5
+ before(:all) do
6
+ create_test_root
7
+ FileUtils.cd(test_root)
8
+ Eyeballs::ModelGenerator.start(["Paul"])
9
+ end
10
+ let(:model_file) { file('app', 'models', 'paul.js') }
11
+
12
+ it "should create my model" do
13
+ model_file.should exist
14
+ end
15
+
16
+ it "should create my file" do
17
+ model_file.read.should include("o_O('Paul', function(paul){")
18
+ end
19
+
20
+ after(:all) do
21
+ remove_test_root
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eyeballs::AppGenerator do
4
+ describe "generate a simple app" do
5
+ before(:all) do
6
+ create_test_root
7
+ FileUtils.mkdir(test_root + '/public')
8
+ FileUtils.cd(test_root)
9
+ Eyeballs::AppGenerator.start('test')
10
+ end
11
+ let(:app_dir) { file('public', 'javascripts', 'app') }
12
+
13
+ it "should create the test root" do
14
+ File.exists?(test_root).should be_true
15
+ end
16
+
17
+ it "should create the test app in the public javascripts directory" do
18
+ app_dir.should exist
19
+ end
20
+
21
+ after(:all) do
22
+ remove_test_root
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eyeballs::ModelGenerator do
4
+ before(:all) do
5
+ create_test_root
6
+ FileUtils.cd(test_root)
7
+ Eyeballs::ScaffoldGenerator.start(["Review", "title:string", "content:text"])
8
+ end
9
+ let(:model_file) { file('app', 'models', 'review.js') }
10
+ let(:controller_file) { file('app', 'controllers', 'reviews_controller.js') }
11
+ let(:html_file) { file('reviews.html') }
12
+ let(:edit_view_file) { file('app', 'views', 'reviews', 'edit.html.mustache') }
13
+ let(:partial_view_file) { file('app', 'views', 'reviews', '_review.html.mustache') }
14
+
15
+ it "should create my files" do
16
+ model_file.should exist
17
+ controller_file.should exist
18
+ html_file.should exist
19
+ edit_view_file.should exist
20
+ partial_view_file.should exist
21
+ end
22
+
23
+ it "should fill out the model file" do
24
+ model_file.read.should include("o_O('Review', function(review){")
25
+ end
26
+
27
+ it "should fill out the controller file" do
28
+ controller_file.read.should include("o_O('ReviewsController', {")
29
+ controller_file.read.should include("Review.all(function(reviews){")
30
+ controller_file.read.should include("for(var id in reviews)")
31
+ end
32
+
33
+ it "should fill out the html file" do
34
+ html_file.read.should include("Reviews")
35
+ html_file.read.should include(%Q[<input type="text" name="title" value="" data-attribute="title">])
36
+ html_file.read.should include(%Q[<textarea name="content" data-attribute="content"></textarea>])
37
+ end
38
+
39
+ after(:all) do
40
+ remove_test_root
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require 'eyeballs'
2
+ require 'fileutils'
3
+ require 'ruby-debug'
4
+ Debugger.settings[:autoeval] = true
5
+
6
+ def create_test_root
7
+ FileUtils.mkdir_p(test_root)
8
+ end
9
+
10
+ def remove_test_root
11
+ FileUtils.rm_r(test_root)
12
+ end
13
+
14
+ def run_command(cmd)
15
+ system("cd #{test_root}; ../../bin/#{cmd}")
16
+ end
17
+
18
+ def file(*parts)
19
+ FileChecker.new([test_root] + parts)
20
+ end
21
+
22
+ def test_root
23
+ File.join(File.dirname(File.expand_path(__FILE__)), 'test_root')
24
+ end
25
+
26
+ class FileChecker
27
+ def initialize(parts)
28
+ @file = File.join(parts)
29
+ end
30
+
31
+ def exist?
32
+ File.exists?(@file)
33
+ end
34
+
35
+ def read
36
+ File.read(@file)
37
+ end
38
+
39
+ def to_s
40
+ @file
41
+ end
42
+ end
@@ -0,0 +1,107 @@
1
+ // We're relaxing, baby!
2
+ o_O.couchdb = {
3
+ all: function(model, callback){
4
+
5
+ var database = o_O.model.adapter.settings.database;
6
+
7
+ var ddoc_id = ['_design', model.table_name].join('/')
8
+ var view_name = model.table_name + '/all'
9
+ var get_all_documents = function(result){
10
+ var documents = result.rows;
11
+ var all_documents = [];
12
+ for(var i = 0; i < documents.length; i++)
13
+ {
14
+ var document = documents[i];
15
+ document.value.id = document.id
16
+ all_documents.push(document.value);
17
+ }
18
+ if(typeof callback === 'function')
19
+ {
20
+ callback(all_documents);
21
+ }
22
+ }
23
+ $.couch.db(database).view(view_name, {
24
+ success:get_all_documents,
25
+ error: function(){
26
+ // create the doc
27
+ var design_doc = {
28
+ "_id": ddoc_id,
29
+ "language": "javascript",
30
+ "views": {
31
+ "all": {
32
+ "map": "function(doc) {\n if(doc.model_name === \
33
+ '" + model.model_name + "')\n emit(null, doc);\n}"
34
+ }
35
+ }
36
+ }
37
+ $.couch.db(database).saveDoc(design_doc, {success:function(){
38
+ $.couch.db(database).view(view_name, {
39
+ success: get_all_documents,
40
+ error: function(){
41
+ if(typeof console === 'object')
42
+ {
43
+ console.log("Design Doc couldn't be written");
44
+ }
45
+ }
46
+ })
47
+ }})
48
+ }
49
+ });
50
+ },
51
+ destroy: function(object, callback){
52
+ var database = o_O.model.adapter.settings.database;
53
+ this.find(object, object.id, function(found){
54
+ var url = '/' + o_O.model.adapter.settings.database + '/' + object.id;
55
+ $.ajax({
56
+ type: 'DELETE',
57
+ url: '/' + database + '/' + object.id + '?rev=' + found._rev,
58
+ success: function(data){
59
+ var response = JSON.parse(data);
60
+ if(typeof callback === 'function')
61
+ {
62
+ callback(response);
63
+ }
64
+ }
65
+ });
66
+ });
67
+ },
68
+ save: function(object, callback)
69
+ {
70
+ var database = o_O.model.adapter.settings.database;
71
+ var object_to_save = {}
72
+
73
+ // we only want the attributes, not all extra model data
74
+ for(var i = 0; i < object.attributes.length; i++)
75
+ {
76
+ object_to_save[object.attributes[i]] = object[object.attributes[i]];
77
+ }
78
+ object_to_save._id = object.id;
79
+ object_to_save.model_name = object.model_name;
80
+ $.couch.db(database).saveDoc(object_to_save, {
81
+ success:function(response){
82
+ object_to_save._rev = response.rev;
83
+ object_to_save._id = response.id;
84
+ object_to_save.id = response.id;
85
+ if(typeof callback === 'function')
86
+ {
87
+ callback(object_to_save);
88
+ }
89
+ }
90
+ });
91
+ },
92
+ table: function(object)
93
+ {
94
+
95
+ },
96
+ find: function(model, id, callback)
97
+ {
98
+ var database = o_O.model.adapter.settings.database;
99
+ $.couch.db(database).openDoc(id, {success: function(document){
100
+ document.id = id;
101
+ if(typeof callback === 'function')
102
+ {
103
+ callback(document);
104
+ }
105
+ }});
106
+ }
107
+ }
@@ -0,0 +1,37 @@
1
+ o_O.dom = {
2
+ save: function(object, callback){
3
+ if(typeof callback === 'function')
4
+ {
5
+ callback(object);
6
+ }
7
+ return object;
8
+ },
9
+ all: function(model, callback){
10
+ var output = [];
11
+ $('[data-model=' + model.model_name + ']').each(function(){
12
+ output.push(model.initialize(o_O.find_attributes($(this), function(field) { return field.text();})))
13
+ })
14
+ if(typeof callback === 'function')
15
+ {
16
+ callback(output);
17
+ }
18
+ },
19
+ destroy: function(object, callback){
20
+ $('[data-model=' + object.model_name +'][data-id= ' + object.id + ']').remove()
21
+ if(typeof callback === 'function')
22
+ {
23
+ callback(object);
24
+ }
25
+ },
26
+ find: function(model, id, callback){
27
+ var template = $('[data-model=' + model.model_name + '][data-id=' + id + ']');
28
+ var new_object;
29
+ if(typeof callback === 'function')
30
+ {
31
+ new_object = model.initialize(o_O.find_attributes(template, function(field){return field.text();}));
32
+ new_object.id = id;
33
+ callback(new_object);
34
+ }
35
+ return new_object;
36
+ }
37
+ }
data/src/jquery.o_O.js ADDED
@@ -0,0 +1,120 @@
1
+ o_O.controller = {
2
+ initialize: function(controller_name, controller){
3
+ var action_event = function(object){
4
+ if(object.attr('data-event'))
5
+ {
6
+ return object.attr('data-event');
7
+ }
8
+ return (object.is('form')) ? 'submit' : 'click';
9
+ }
10
+
11
+ var controller_name = controller_name.replace('Controller', '').toLowerCase();
12
+ var controller = controller;
13
+
14
+ $(function(){
15
+ for(var action in controller)
16
+ {
17
+ var selector = '[data-controller=' + controller_name + '][data-action=' + action + ']';
18
+ $(selector).livequery(function(){
19
+ var element = $(this);
20
+ $(this).bind(action_event(element), controller[element.attr('data-action')]);
21
+ if(!($(this).attr('data-default')))
22
+ {
23
+ $(this).bind(action_event(element), function(){ return false; });
24
+ }
25
+ })
26
+ }
27
+ $('[data-bind]').livequery(function(){
28
+ var binders = $(this).attr('data-bind').match(/[\+]?(\s+)?[^ :]?[: ]?[^ \/]+[ \/]+[^ ;]+[ ;]?/g)
29
+ if(binders != null && binders.length > 0)
30
+ {
31
+ for(i = 0; i < binders.length; i++)
32
+ {
33
+ var rule = binders[i];
34
+ var parts = rule.match(/([\+])?(\s+)?(([^ :]+)([: ]+))?([^ \/]+)[ \/]+([^ ;]+)[ ;]?/)
35
+ var default_bit = parts[1];
36
+ var this_action_event = parts[4];
37
+ if(this_action_event === undefined)
38
+ {
39
+ this_action_event = ($(this).is('form')) ? 'submit' : 'click';
40
+ }
41
+ var this_controller_name = parts[6];
42
+ var this_action = parts[7];
43
+ if(this_controller_name == controller_name)
44
+ {
45
+ $(this).bind(this_action_event,controller[this_action]);
46
+ if(default_bit != '+')
47
+ {
48
+ $(this).bind(this_action_event, function(){ return false; });
49
+ }
50
+ }
51
+ }
52
+ }
53
+ });
54
+ });
55
+ return controller;
56
+ }
57
+ }
58
+
59
+ o_O.find_attributes = function(template, callback){
60
+ var object = {};
61
+ for(i = 0; i<template.find('[data-attribute]').length; i++)
62
+ {
63
+ field = $(template.find('[data-attribute]')[i]);
64
+ object[field.attr('data-attribute')] = callback(field);
65
+ }
66
+ return object;
67
+ }
68
+
69
+ o_O.params = function(form){
70
+ return o_O.find_attributes(form, function(field){
71
+ if(field.is('[type=radio]'))
72
+ {
73
+ return $('[data-attribute=' + field.attr('data-attribute') + ']:checked').val()
74
+ }
75
+ else
76
+ {
77
+ return field.val();
78
+ }
79
+ });
80
+ }
81
+
82
+ o_O.render = function(template, data, options){
83
+ o_O.get_template(template, data, function(data, template){
84
+ var rendered = Mustache.to_html(template, data);
85
+ if(typeof options === 'object')
86
+ {
87
+ if(options.append)
88
+ {
89
+ $(options.append).append(rendered);
90
+ }
91
+ if(options.prepend)
92
+ {
93
+ $(options.prepend).prepend(rendered);
94
+ }
95
+ }
96
+ });
97
+ }
98
+
99
+ o_O.get_template = function(template, data, callback){
100
+ if(o_O.templates[template])
101
+ {
102
+ callback(data, o_O.templates[template]);
103
+ }
104
+ else
105
+ {
106
+ var url;
107
+ if(o_O.config.template_path)
108
+ {
109
+ url = o_O.config.template_path + '/';
110
+ }
111
+ else
112
+ {
113
+ url = 'app/views/'
114
+ }
115
+ $.get(url + template + '.html.mustache', function(response){
116
+ o_O.templates[template] = response;
117
+ callback(data, response);
118
+ });
119
+ }
120
+ }
@@ -0,0 +1,68 @@
1
+ // REST & Rails, woop!
2
+ o_O.rails = {
3
+ all: function(model, callback){
4
+ $.get('/' + model.table_name, function(response){
5
+ var documents = JSON.parse(response);
6
+ if(typeof callback === 'function')
7
+ {
8
+ callback(documents);
9
+ }
10
+ })
11
+ },
12
+ destroy: function(object, callback){
13
+ object.destroyed = true;
14
+ $.ajax({
15
+ type: 'DELETE',
16
+ url: '/' + object.table_name + '/' + object.id,
17
+ success: function(){
18
+ if(typeof callback === 'function')
19
+ {
20
+ callback(object);
21
+ }
22
+ }
23
+ })
24
+ },
25
+ save: function(object, callback)
26
+ {
27
+ var object_to_save = {}
28
+ for(var i = 0; i < object.attributes.length; i++)
29
+ {
30
+ object_to_save[object.attributes[i]] = object[object.attributes[i]];
31
+ }
32
+ var respond = function(response){
33
+ var saved_object = JSON.parse(response);
34
+ for(var attribute in saved_object)
35
+ {
36
+ object_to_save[attribute] = saved_object[attribute];
37
+ }
38
+ object_to_save.new_record = false;
39
+ if(typeof callback === 'function')
40
+ {
41
+ callback(object_to_save);
42
+ }
43
+ }
44
+ if(object.new_record)
45
+ {
46
+ $.post('/' + object.table_name, object_to_save, respond);
47
+ }
48
+ else
49
+ {
50
+ $.ajax({
51
+ type: 'PUT',
52
+ url: '/' + object.table_name + '/' + object.id,
53
+ success: respond
54
+ })
55
+ }
56
+ },
57
+ find: function(model, id, callback)
58
+ {
59
+ $.get('/' + model.table_name + '/' + id, function(response){
60
+ var retrieved_object = JSON.parse(response);
61
+ if(typeof callback === 'function')
62
+ {
63
+ retrieved_object.new_record = false;
64
+ callback(retrieved_object);
65
+ }
66
+ })
67
+ }
68
+ }