paloma 0.0.1 → 0.0.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 (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
+ };