paloma 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +148 -0
  4. data/License +22 -0
  5. data/README.md +240 -0
  6. data/Rakefile +16 -0
  7. data/app/views/paloma/_callback_hook.html.erb +33 -0
  8. data/lib/paloma.rb +14 -0
  9. data/lib/paloma/action_controller_extension.rb +52 -0
  10. data/lib/paloma/action_controller_filters.rb +53 -0
  11. data/lib/paloma/paloma_generator.rb +94 -0
  12. data/lib/paloma/templates/_callbacks.js +2 -0
  13. data/lib/paloma/templates/_local.js +20 -0
  14. data/lib/paloma/templates/action.js +5 -0
  15. data/lib/paloma/templates/index.js +1 -0
  16. data/lib/paloma/templates/paloma.js +22 -0
  17. data/paloma.gemspec +23 -0
  18. data/spec/callback_spec.rb +65 -0
  19. data/spec/sample_app/app/assets/javascripts/application.js +4 -0
  20. data/spec/sample_app/app/assets/javascripts/paloma/articles/callbacks.js +1 -0
  21. data/spec/sample_app/app/assets/javascripts/paloma/articles/create.js +3 -0
  22. data/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js +3 -0
  23. data/spec/sample_app/app/assets/javascripts/paloma/articles/index.js +3 -0
  24. data/spec/sample_app/app/assets/javascripts/paloma/articles/new.js +3 -0
  25. data/spec/sample_app/app/assets/javascripts/paloma/articles/show.js +3 -0
  26. data/spec/sample_app/app/assets/javascripts/paloma/articles/update.js +3 -0
  27. data/spec/sample_app/app/assets/javascripts/paloma/index.js +2 -0
  28. data/spec/sample_app/app/assets/javascripts/paloma/paloma.js +1 -0
  29. data/spec/sample_app/app/views/articles/index.html.erb +5 -0
  30. data/spec/sample_app/app/views/articles/new.html.erb +9 -0
  31. data/spec/sample_app/app/views/articles/show.html.erb +2 -0
  32. data/spec/sample_app/app/views/layouts/application.html.erb +12 -0
  33. data/spec/sample_app/controllers.rb +54 -0
  34. data/spec/sample_app/init.rb +33 -0
  35. data/spec/sample_app/model.rb +28 -0
  36. data/spec/sample_app/paloma_test +0 -0
  37. data/spec/spec_helper.rb +21 -0
  38. metadata +215 -39
@@ -0,0 +1,33 @@
1
+ <% callback_details_id = "#{Time.now.to_i}#{(rand * 1000).ceil}" %>
2
+
3
+ <div class="callback-details" id="callback-details-<%= callback_details_id %>">
4
+ <script type="text/javascript">
5
+ var id = "callback-details-<%= callback_details_id %>",
6
+ callbacks = [];
7
+
8
+ // Remove any callback details if any
9
+ $('.callback-details[id!=" + id + "]').remove();
10
+
11
+
12
+ // Convert callbacks to javascript variable
13
+ <% callbacks.each do |callback| %>
14
+ callbacks.push({
15
+ name: '<%= callback[:name] %>',
16
+ params: eval($('<div/>').html("(<%= callback[:params].to_json %>)").text())
17
+ });
18
+ <% end %>
19
+
20
+
21
+ // Run Callbacks
22
+ for (var i = 0, len = callbacks.length; i < len; i++){
23
+ var callback = callbacks[i],
24
+ callbackFunction = Paloma.callbacks[callback.name];
25
+
26
+ console.log("Paloma: Fetching [" + callback.name + "]");
27
+ if (callback != undefined){
28
+ console.log("Paloma: Calling [" + callback.name + "]");
29
+ callbackFunction(callback.params);
30
+ }
31
+ }
32
+ </script>
33
+ </div>
data/lib/paloma.rb CHANGED
@@ -0,0 +1,14 @@
1
+ module Paloma
2
+ def self.root
3
+ @paloma_root ||= File.dirname(__FILE__) + '/../'
4
+ end
5
+ end
6
+
7
+ require 'action_controller/railtie'
8
+ require 'rails/generators'
9
+
10
+ # TODO: Rails version checking
11
+
12
+ require 'paloma/paloma_generator'
13
+ require 'paloma/action_controller_filters'
14
+ require 'paloma/action_controller_extension'
@@ -0,0 +1,52 @@
1
+ module Paloma
2
+
3
+ # TODO explain!
4
+ module ::ActionController::Redirecting
5
+ alias_method :original_redirect_to, :redirect_to
6
+ end
7
+
8
+
9
+
10
+ module ActionControllerExtension
11
+ def redirect_js_hook options = {}, response_status = {}
12
+ add_to_callbacks @__callback__, @__js_params__
13
+ original_redirect_to options, response_status
14
+ end
15
+ alias_method :redirect_to, :redirect_js_hook
16
+
17
+
18
+ #
19
+ # js_callback false
20
+ # js_callback :new, :params => {}
21
+ # js_callback :controller => '', :action => '', :params => {}
22
+ # js_callback :params => {}
23
+ #
24
+ def js_callback options = {}, extras = {}
25
+ default_callback = "#{controller_name}/#{action_name}"
26
+ params = {}
27
+
28
+ if options.is_a? Hash
29
+ params = options[:params]
30
+ callback = options[:controller].present? && options[:action].present? ?
31
+ "#{options[:controller]}/#{options[:action]}" :
32
+ default_callback
33
+
34
+ elsif options.is_a? Symbol
35
+ params = extras[:params]
36
+ callback = "#{controller_name}/#{options}"
37
+
38
+ elsif options.nil? || options.is_a?(TrueClass)
39
+ callback = default_callback
40
+
41
+ else # false
42
+ callback = nil
43
+ end
44
+
45
+ @__callback__ = callback
46
+ @__js_params__ = params
47
+ end
48
+ end
49
+
50
+
51
+ ::ActionController::Base.send :include, ActionControllerExtension
52
+ end
@@ -0,0 +1,53 @@
1
+ module Paloma
2
+ module ActionControllerFilters
3
+
4
+ def self.included base
5
+ base.module_eval do
6
+ prepend_view_path "#{Paloma.root}/app/views/"
7
+ before_filter :js_callback
8
+ after_filter :update_callback, :if => :html_response_from_render?
9
+ end
10
+ end
11
+
12
+
13
+ protected
14
+
15
+ def html_response_from_render?
16
+ [nil, 'text/html'].include?(response.content_type) && self.status != 302
17
+ end
18
+
19
+
20
+ def update_callback
21
+ add_to_callbacks @__callback__, @__js_params__
22
+
23
+ response_body[0] += view_context.render(
24
+ :partial => "paloma/callback_hook",
25
+ :locals => {:callbacks => session[:callbacks]})
26
+
27
+ response.body = response_body[0]
28
+ clear_callbacks
29
+ end
30
+
31
+
32
+ def add_to_callbacks name, params
33
+ return true if name.nil?
34
+ session[:callbacks] ||= []
35
+ session[:callbacks].push({:name => name, :params => params})
36
+ end
37
+
38
+
39
+ def get_callbacks
40
+ session[:callbacks]
41
+ end
42
+
43
+
44
+ def clear_callbacks
45
+ session[:callbacks] = []
46
+ end
47
+
48
+ end
49
+
50
+ ::ActionController::Base.send :include, ActionControllerFilters
51
+ end
52
+
53
+
@@ -0,0 +1,94 @@
1
+ module Paloma
2
+ #
3
+ # Setup:
4
+ # rails g paloma:setup
5
+ # - Generates the following:
6
+ # - 'paloma' folder under app/assets/javascripts/paloma
7
+ # - index.js and paloma.js under the 'paloma' folder
8
+ #
9
+ #
10
+ # Usage:
11
+ # rails g paloma:add <controller_name>
12
+ # - Generates the following:
13
+ # - a folder under app/assets/javascripts/paloma named as <controller_name>
14
+ # - callbacks.js inside the folder just made
15
+ # - Updates index.js under the 'paloma' folder
16
+ # - adds a line in order to require the callbacks to be made under the recently made folder
17
+ #
18
+ #
19
+ # rails g paloma:add <controller_name>/<action_name>
20
+ # - Generates the following:
21
+ # - <action_name>.js file inside the <controller_name> folder
22
+ #
23
+ #
24
+ # Generated Files:
25
+ # index.js
26
+ # - contains code for requiring all callbacks of all folders
27
+ # - always updated when new folders and callback.js files are created
28
+ #
29
+ # paloma.js
30
+ # - declaration of namespace used in all callbacks
31
+ #
32
+ # <controller_name>/callbacks.js
33
+ # - contains code for requiring all callbacks under the same folder <controller_name>
34
+ #
35
+ # <controller_name>/<action_name>.js
36
+ # - actual code to be executed when callback is called
37
+ #
38
+
39
+ PARENT = 'app/assets/javascripts/paloma/'
40
+ INDEX = PARENT + 'index.js'
41
+ PALOMA = PARENT + 'paloma.js'
42
+
43
+ class SetupGenerator < ::Rails::Generators::Base
44
+ source_root File.expand_path('../templates', __FILE__)
45
+
46
+ def setup_paloma
47
+ #index.js on callbacks folder
48
+ has_index = File.exists? INDEX
49
+ copy_file 'index.js', INDEX unless has_index
50
+
51
+ has_paloma = File.exists? PALOMA
52
+ copy_file 'paloma.js', PALOMA unless has_paloma
53
+ end
54
+
55
+ end
56
+
57
+
58
+ class AddGenerator < ::Rails::Generators::NamedBase
59
+ source_root File.expand_path('../templates', __FILE__)
60
+
61
+ def create_callback_file
62
+ file = file_path.split('/')
63
+ controller = file[0]
64
+ action = file[1]
65
+
66
+ callbacks = PARENT + "#{controller}/_callbacks.js"
67
+ templates = "#{Paloma.root}/lib/paloma/templates/"
68
+ local = PARENT + "#{controller}/_local.js"
69
+ action_file = PARENT + "#{controller}/#{action}.js"
70
+
71
+ #_callbacks.js per folder(controller)
72
+ has_callbacks = File.exists? callbacks
73
+ unless has_callbacks
74
+ content = File.read(templates + '_callbacks.js').gsub('controller', "#{controller}")
75
+ File.open(callbacks, 'w'){ |f| f.write(content) }
76
+ File.open(INDEX, 'a+'){|f| f << "\n//= require ./" + controller + '/_callbacks' }
77
+ end
78
+
79
+ #_local.js per folder(controller)
80
+ has_local =File.exists? local
81
+ unless has_local
82
+ content = File.read(templates + '_local.js').gsub('controller', "#{controller}")
83
+ File.open(local, 'w'){ |f| f.write(content) }
84
+ end
85
+
86
+ #<action>.js on folder(controller) - code for callback
87
+ has_action = File.exists? action_file
88
+ unless (action.nil? || has_action)
89
+ content = File.read(templates + 'action.js').gsub('controller/action', "#{controller}/#{action}")
90
+ File.open(action_file, 'w'){ |f| f.write(content) }
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,2 @@
1
+ //= require ./controller/_local
2
+ //= require_tree .
@@ -0,0 +1,20 @@
1
+ Paloma.controller = {
2
+
3
+ /*
4
+ Put here code which can be used by all callbacks
5
+ under the controller folder.
6
+
7
+ Example:
8
+
9
+ variableName: value;
10
+
11
+ functionName: function(params){
12
+ alert('Paloma');
13
+ };
14
+
15
+ To use the variable and function:
16
+ Paloma.controller.variableName
17
+ Paloma.controller.functionName(params);
18
+ */
19
+
20
+ };
@@ -0,0 +1,5 @@
1
+ Paloma.callbacks['controller/action'] = function(params){
2
+
3
+ // alert('Paloma');
4
+
5
+ };
@@ -0,0 +1 @@
1
+ //= require ./paloma
@@ -0,0 +1,22 @@
1
+ window.Paloma = {callbacks:{}};
2
+
3
+ Paloma.g = {
4
+
5
+ /*
6
+ Put here global code that can be used by all callbacks,
7
+ regardless which folder they're from.
8
+
9
+ Example:
10
+
11
+ variableName: value;
12
+
13
+ functionName: function(params){
14
+ alert('Paloma');
15
+ };
16
+
17
+ To use the variable and function:
18
+ Paloma.g.variableName
19
+ Paloma.g.functionName(params);
20
+ */
21
+
22
+ };
data/paloma.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'paloma'
3
+ s.version = '0.0.2'
4
+ s.date = '2012-12-17'
5
+ s.summary = "Javascript Callback Manager for Rails"
6
+ s.description = "Javascript Callback Manager for Rails"
7
+ s.authors = ["Karl Paragua", "Bia Esmero"]
8
+ s.email = 'kb.paragua@gmail.com'
9
+ s.files = `git ls-files`.split("\n")
10
+ s.homepage = 'https://github.com/kbparagua/paloma'
11
+
12
+ s.add_dependency 'jquery-rails'
13
+
14
+ s.add_development_dependency 'rails', ['>= 3.1.0']
15
+ s.add_development_dependency 'bundler', ['>= 1.0.0']
16
+ s.add_development_dependency 'rake', ['>= 0']
17
+ s.add_development_dependency 'sqlite3', ['>= 0']
18
+ s.add_development_dependency 'rspec', ['>= 0']
19
+ s.add_development_dependency 'rspec-rails', ['~> 2.0']
20
+ s.add_development_dependency 'capybara', ['>= 1.0']
21
+ s.add_development_dependency 'database_cleaner', ['>= 0']
22
+ s.add_development_dependency 'launchy', ['>= 0']
23
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Callbacks' do
4
+
5
+ it 'should execute articles/new callback', :js => true do
6
+ visit new_article_path
7
+ page.has_selector?('#from-articles-new-callback').should == true
8
+ end
9
+
10
+
11
+ it 'should execute callbacks for articles/create and articles/show', :js => true do
12
+ visit new_article_path
13
+
14
+ fill_in 'article[title]', :with => 'sexy paloma'
15
+ fill_in 'article[body]', :with => 'sexy paloma body'
16
+ click_button 'Save'
17
+
18
+ page.has_selector?('#from-articles-create-callback').should == true
19
+ page.has_selector?('#from-articles-show-callback').should == true
20
+ end
21
+
22
+
23
+ it 'should execute "new" callback instead of "create" after failed save', :js => true do
24
+ visit new_article_path
25
+
26
+ fill_in 'article[body]', :with => 'sexy paloma body'
27
+ click_button 'Save'
28
+
29
+ page.has_selector?('#from-articles-create-callback').should == false
30
+ page.has_selector?('#from-articles-new-callback').should == true
31
+ end
32
+
33
+
34
+ it 'should have an access on the passed parameters on js_callback', :js => true do
35
+ 1.upto(30) do |i|
36
+ Article.create :title => "Sexy Paloma #{i}", :body => "Sexy Body"
37
+ end
38
+
39
+ visit articles_path
40
+ page.has_selector?('#article-count-30').should == true
41
+ end
42
+
43
+
44
+ it 'should not execute articles/update callback', :js => true do
45
+ article = Article.create :title => "Sexy Paloma Baby!", :body => "OMG"
46
+
47
+ visit edit_article_path(article)
48
+ fill_in 'article[body]', :with => 'Updated Body'
49
+ click_button 'Save'
50
+
51
+ page.has_selector?('#from-articles-update-callback').should == false
52
+ page.has_selector?('#from-articles-show-callback').should == true
53
+ end
54
+
55
+
56
+ it 'should execute articles/edit callback after failed update', :js => true do
57
+ article = Article.create :title => 'Sexy Paloma Baby!', :body => 'Yeah'
58
+
59
+ visit edit_article_path(article)
60
+ fill_in 'article[title]', :with => ''
61
+ click_button 'Save'
62
+
63
+ page.has_selector?('#from-articles-edit-callback').should == true
64
+ end
65
+ end
@@ -0,0 +1,4 @@
1
+ //
2
+ //= require jquery.js
3
+ //= require jquery_ujs.js
4
+ //= require paloma
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/create'] = function(params){
2
+ $('body').append($("<div id='from-articles-create-callback'></div>"));
3
+ };
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/edit'] = function(params){
2
+ $('body').append($("<div id='from-articles-edit-callback'></div>"));
3
+ };
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/index'] = function(params){
2
+ $('body').append($("<div id='article-count-" + params['article_count'] + "'></div>"));
3
+ };
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/new'] = function(params){
2
+ $('body').append($("<div id='from-articles-new-callback'></div>"));
3
+ };
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/show'] = function(params){
2
+ $('body').append($("<div id='from-articles-show-callback'></div>"));
3
+ };
@@ -0,0 +1,3 @@
1
+ Paloma.callbacks['articles/update'] = function(params){
2
+ $('body').append($("<div id='from-articles-update-callback'></div>"));
3
+ };