rails_bridge 0.0.5

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 (73) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +21 -0
  3. data/Gemfile.lock +154 -0
  4. data/LICENSE +13 -0
  5. data/README.rdoc +244 -0
  6. data/Rakefile +46 -0
  7. data/VERSION +1 -0
  8. data/app/controllers/rails_bridge/layout_bridge_controller.rb +43 -0
  9. data/app/views/content.html.erb +13 -0
  10. data/app/views/rails_bridge/layout_bridge/index.html.erb +6 -0
  11. data/config/routes.rb +11 -0
  12. data/lib/generators/content_bridge/USAGE +12 -0
  13. data/lib/generators/content_bridge/content_bridge_generator.rb +9 -0
  14. data/lib/generators/content_bridge/templates/content_bridge.rb +47 -0
  15. data/lib/rails_bridge.rb +16 -0
  16. data/lib/rails_bridge/content_bridge.rb +137 -0
  17. data/lib/rails_bridge/content_request.rb +100 -0
  18. data/lib/rails_bridge/engine.rb +34 -0
  19. data/rails_bridge.gemspec +186 -0
  20. data/script/console +2 -0
  21. data/spec/dummy/.rspec +1 -0
  22. data/spec/dummy/Rakefile +7 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  24. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  25. data/spec/dummy/app/rails_bridge/content_bridges/twitter_content_bridge.rb +26 -0
  26. data/spec/dummy/app/rails_bridge/layout_bridge/layouts/application/content.html.erb +1 -0
  27. data/spec/dummy/app/rails_bridge/layout_bridge/views/layouts/_partial.html.erb +1 -0
  28. data/spec/dummy/app/views/layouts/_partial.html.erb +1 -0
  29. data/spec/dummy/app/views/layouts/alternative.html.erb +0 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +17 -0
  31. data/spec/dummy/autotest/discover.rb +2 -0
  32. data/spec/dummy/config.ru +4 -0
  33. data/spec/dummy/config/application.rb +44 -0
  34. data/spec/dummy/config/boot.rb +10 -0
  35. data/spec/dummy/config/database.yml +22 -0
  36. data/spec/dummy/config/environment.rb +5 -0
  37. data/spec/dummy/config/environments/development.rb +26 -0
  38. data/spec/dummy/config/environments/production.rb +49 -0
  39. data/spec/dummy/config/environments/test.rb +35 -0
  40. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec/dummy/config/initializers/inflections.rb +10 -0
  42. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  43. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  44. data/spec/dummy/config/initializers/session_store.rb +8 -0
  45. data/spec/dummy/config/locales/en.yml +5 -0
  46. data/spec/dummy/config/routes.rb +2 -0
  47. data/spec/dummy/db/development.sqlite3 +0 -0
  48. data/spec/dummy/db/test.sqlite3 +0 -0
  49. data/spec/dummy/public/404.html +26 -0
  50. data/spec/dummy/public/422.html +26 -0
  51. data/spec/dummy/public/500.html +26 -0
  52. data/spec/dummy/public/favicon.ico +0 -0
  53. data/spec/dummy/public/javascripts/application.js +2 -0
  54. data/spec/dummy/public/javascripts/controls.js +965 -0
  55. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  56. data/spec/dummy/public/javascripts/effects.js +1123 -0
  57. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  58. data/spec/dummy/public/javascripts/rails.js +175 -0
  59. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  60. data/spec/dummy/script/rails +6 -0
  61. data/spec/dummy/spec/spec_helper.rb +33 -0
  62. data/spec/integration/content_bridge_spec.rb +82 -0
  63. data/spec/integration/engine_spec.rb +25 -0
  64. data/spec/requests/layout_bridge_controller_spec.rb +16 -0
  65. data/spec/spec_helper.rb +62 -0
  66. data/spec/support/content_bridge_helper.rb +26 -0
  67. data/spec/support/layout_bridge_helper.rb +2 -0
  68. data/spec/support/rails_bridge_helper.rb +12 -0
  69. data/spec/support/test_server_helper.rb +125 -0
  70. data/spec/unit/content_bridge_spec.rb +59 -0
  71. data/spec/unit/content_request_spec.rb +84 -0
  72. data/spec/unit/rails_bridge_spec.rb +11 -0
  73. metadata +380 -0
@@ -0,0 +1,175 @@
1
+ (function() {
2
+ // Technique from Juriy Zaytsev
3
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
+ function isEventSupported(eventName) {
5
+ var el = document.createElement('div');
6
+ eventName = 'on' + eventName;
7
+ var isSupported = (eventName in el);
8
+ if (!isSupported) {
9
+ el.setAttribute(eventName, 'return;');
10
+ isSupported = typeof el[eventName] == 'function';
11
+ }
12
+ el = null;
13
+ return isSupported;
14
+ }
15
+
16
+ function isForm(element) {
17
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
+ }
19
+
20
+ function isInput(element) {
21
+ if (Object.isElement(element)) {
22
+ var name = element.nodeName.toUpperCase()
23
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
+ }
25
+ else return false
26
+ }
27
+
28
+ var submitBubbles = isEventSupported('submit'),
29
+ changeBubbles = isEventSupported('change')
30
+
31
+ if (!submitBubbles || !changeBubbles) {
32
+ // augment the Event.Handler class to observe custom events when needed
33
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
+ function(init, element, eventName, selector, callback) {
35
+ init(element, eventName, selector, callback)
36
+ // is the handler being attached to an element that doesn't support this event?
37
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
+ // "submit" => "emulated:submit"
40
+ this.eventName = 'emulated:' + this.eventName
41
+ }
42
+ }
43
+ )
44
+ }
45
+
46
+ if (!submitBubbles) {
47
+ // discover forms on the page by observing focus events which always bubble
48
+ document.on('focusin', 'form', function(focusEvent, form) {
49
+ // special handler for the real "submit" event (one-time operation)
50
+ if (!form.retrieve('emulated:submit')) {
51
+ form.on('submit', function(submitEvent) {
52
+ var emulated = form.fire('emulated:submit', submitEvent, true)
53
+ // if custom event received preventDefault, cancel the real one too
54
+ if (emulated.returnValue === false) submitEvent.preventDefault()
55
+ })
56
+ form.store('emulated:submit', true)
57
+ }
58
+ })
59
+ }
60
+
61
+ if (!changeBubbles) {
62
+ // discover form inputs on the page
63
+ document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
+ // special handler for real "change" events
65
+ if (!input.retrieve('emulated:change')) {
66
+ input.on('change', function(changeEvent) {
67
+ input.fire('emulated:change', changeEvent, true)
68
+ })
69
+ input.store('emulated:change', true)
70
+ }
71
+ })
72
+ }
73
+
74
+ function handleRemote(element) {
75
+ var method, url, params;
76
+
77
+ var event = element.fire("ajax:before");
78
+ if (event.stopped) return false;
79
+
80
+ if (element.tagName.toLowerCase() === 'form') {
81
+ method = element.readAttribute('method') || 'post';
82
+ url = element.readAttribute('action');
83
+ params = element.serialize();
84
+ } else {
85
+ method = element.readAttribute('data-method') || 'get';
86
+ url = element.readAttribute('href');
87
+ params = {};
88
+ }
89
+
90
+ new Ajax.Request(url, {
91
+ method: method,
92
+ parameters: params,
93
+ evalScripts: true,
94
+
95
+ onComplete: function(request) { element.fire("ajax:complete", request); },
96
+ onSuccess: function(request) { element.fire("ajax:success", request); },
97
+ onFailure: function(request) { element.fire("ajax:failure", request); }
98
+ });
99
+
100
+ element.fire("ajax:after");
101
+ }
102
+
103
+ function handleMethod(element) {
104
+ var method = element.readAttribute('data-method'),
105
+ url = element.readAttribute('href'),
106
+ csrf_param = $$('meta[name=csrf-param]')[0],
107
+ csrf_token = $$('meta[name=csrf-token]')[0];
108
+
109
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
+ element.parentNode.insert(form);
111
+
112
+ if (method !== 'post') {
113
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
+ form.insert(field);
115
+ }
116
+
117
+ if (csrf_param) {
118
+ var param = csrf_param.readAttribute('content'),
119
+ token = csrf_token.readAttribute('content'),
120
+ field = new Element('input', { type: 'hidden', name: param, value: token });
121
+ form.insert(field);
122
+ }
123
+
124
+ form.submit();
125
+ }
126
+
127
+
128
+ document.on("click", "*[data-confirm]", function(event, element) {
129
+ var message = element.readAttribute('data-confirm');
130
+ if (!confirm(message)) event.stop();
131
+ });
132
+
133
+ document.on("click", "a[data-remote]", function(event, element) {
134
+ if (event.stopped) return;
135
+ handleRemote(element);
136
+ event.stop();
137
+ });
138
+
139
+ document.on("click", "a[data-method]", function(event, element) {
140
+ if (event.stopped) return;
141
+ handleMethod(element);
142
+ event.stop();
143
+ });
144
+
145
+ document.on("submit", function(event) {
146
+ var element = event.findElement(),
147
+ message = element.readAttribute('data-confirm');
148
+ if (message && !confirm(message)) {
149
+ event.stop();
150
+ return false;
151
+ }
152
+
153
+ var inputs = element.select("input[type=submit][data-disable-with]");
154
+ inputs.each(function(input) {
155
+ input.disabled = true;
156
+ input.writeAttribute('data-original-value', input.value);
157
+ input.value = input.readAttribute('data-disable-with');
158
+ });
159
+
160
+ var element = event.findElement("form[data-remote]");
161
+ if (element) {
162
+ handleRemote(element);
163
+ event.stop();
164
+ }
165
+ });
166
+
167
+ document.on("ajax:after", "form", function(event, element) {
168
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
+ inputs.each(function(input) {
170
+ input.value = input.readAttribute('data-original-value');
171
+ input.removeAttribute('data-original-value');
172
+ input.disabled = false;
173
+ });
174
+ });
175
+ })();
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,33 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require File.expand_path("../../config/environment", __FILE__)
4
+ require 'rspec/rails'
5
+
6
+ # Requires supporting ruby files with custom matchers and macros, etc,
7
+ # in spec/support/ and its subdirectories.
8
+ Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ # == Mock Framework
12
+ #
13
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
14
+ #
15
+ # config.mock_with :mocha
16
+ # config.mock_with :flexmock
17
+ # config.mock_with :rr
18
+ config.mock_with :rspec
19
+
20
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
21
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
22
+
23
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
24
+ # examples within a transaction, remove the following line or assign false
25
+ # instead of true.
26
+ config.use_transactional_fixtures = true
27
+
28
+
29
+ # Only run focus tests, if any, or all tests if none.
30
+ config.filter_run :focus => true
31
+ config.run_all_when_everything_filtered = true
32
+
33
+ end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe RailsBridge::ContentBridge do
4
+
5
+ include ContentBridgeSpecHelper
6
+
7
+ before(:each) do
8
+ ContentBridgeTest.request_timeout = 2000
9
+ TestServer.startup(TEST_SERVER_PORT)
10
+ end
11
+
12
+ after(:each) do
13
+ TestServer.shutdown
14
+ end
15
+
16
+ it "verify the TestServer is running" do
17
+ response = Typhoeus::Request.get("http://localhost:#{TEST_SERVER_PORT}/hi?return_data=verified")
18
+ response.body.should == 'verified'
19
+ end
20
+
21
+ it ":get_remote_content fetches by explicit URL" do
22
+ ContentBridgeTest.get_remote_content("http://localhost:#{TEST_SERVER_PORT}/")
23
+ end
24
+
25
+ it "fetches the server's content" do
26
+ ContentBridgeTest.get_chang.should == DEFAULT_RETURN_DATA
27
+ end
28
+
29
+ it "honors the bridge's request_timeout on a hung connection" do
30
+ cbt = ContentBridgeTest
31
+ wang = ContentBridgeTest.content_requests[:chang].dup
32
+ wang.params = wang.params.merge(:sleep=>2)
33
+ cbt.content_requests[:wang] = wang
34
+ cbt.request_timeout = 10
35
+ cbt.get_wang().should == wang.default_content
36
+ end
37
+
38
+ it "honors the request's request_timeout on a hung connection" do
39
+ cbt = ContentBridgeTest
40
+ cbt.request_timeout = 4000
41
+ cbt.get_chang(:params=>{:sleep=>20},:request_timeout=>10).should == cbt.content_requests[:chang].default_content
42
+ end
43
+
44
+ it "does not cache a request's content when the cache_timeout is 0 or nil" do
45
+ cbt = ContentBridgeTest
46
+ cbt.get_chang(:cache_timeout=>0).should == DEFAULT_RETURN_DATA
47
+ TestServer.shutdown
48
+ cbt.get_chang(:cache_timeout=>0,:request_timeout=>10).should == cbt.content_requests[:chang].default_content
49
+ TestServer.startup(TEST_SERVER_PORT)
50
+ cbt.get_chang(:cache_timeout=>0).should == DEFAULT_RETURN_DATA
51
+ TestServer.shutdown
52
+ cbt.get_chang(:cache_timeout=>0,:request_timeout=>10).should == cbt.content_requests[:chang].default_content
53
+ end
54
+
55
+ it "caches a request's content when the cache_timeout is > 0" do
56
+ unique = __LINE__
57
+ cbt = ContentBridgeTest
58
+ chang = cbt.content_requests[:chang]
59
+ cbt.get_chang(:cache_timeout=>60,:params=>chang.params.merge(:unique=>unique)).should == DEFAULT_RETURN_DATA
60
+ TestServer.shutdown
61
+ cbt.get_chang(:cache_timeout=>60,:params=>chang.params.merge(:unique=>unique)).should == DEFAULT_RETURN_DATA
62
+ end
63
+
64
+ it "the cache expires correctly" do
65
+ unique = __LINE__
66
+ cbt = ContentBridgeTest
67
+ chang = cbt.content_requests[:chang]
68
+ cbt.get_chang(:cache_timeout=>2,:params=>chang.params.merge(:unique=>unique)).should == DEFAULT_RETURN_DATA
69
+ TestServer.shutdown
70
+ cbt.get_chang(:cache_timeout=>2,:params=>chang.params.merge(:unique=>unique)).should == DEFAULT_RETURN_DATA
71
+ sleep 2
72
+ cbt.get_chang(:cache_timeout=>2,:params=>chang.params.merge(:unique=>unique)).should == cbt.content_requests[:chang].default_content
73
+ end
74
+
75
+ it "allows get_remote_content to be called directly with request options" do
76
+ ContentBridgeTest.get_remote_content(DEFAULT_REQUEST_VALUES).should == DEFAULT_RETURN_DATA
77
+ end
78
+
79
+ it "automatically loads class in the app/rails_bridge/content_bridges directory" do
80
+ defined?( TwitterContentBridge ).should == 'constant'
81
+ end
82
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe "initialize test" do
4
+ it "verify the Dummy app gets loaded" do
5
+ Rails.application.kind_of?( Dummy::Application ).should == true
6
+ end
7
+
8
+ it "verify the LayoutBridgeController class is loaded" do
9
+ defined?( RailsBridge::LayoutBridgeController ).should == "constant"
10
+ end
11
+
12
+ it "sets the ContentBridge logger to the Rails logger" do
13
+ Rails.logger.should_receive(:info)
14
+ RailsBridge::ContentBridge.logger.info "test"
15
+ end
16
+
17
+ it "sets the ContentBridge cache to Rails cache" do
18
+ Rails.cache.should_receive(:set)
19
+ RailsBridge::ContentBridge.cache.set( "key", "value" )
20
+ end
21
+
22
+ it "autoloads classes in the app/rails_bridge path" do
23
+ defined?( TwitterContentBridge ).should == "constant"
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe RailsBridge::LayoutBridgeController do
4
+
5
+ include LayoutBridgeSpecHelper
6
+
7
+ it "the index action returns the applications layouts" do
8
+ visit rails_bridge_layouts_path
9
+ puts page.source
10
+ end
11
+
12
+ it "the show action returns the specified layout" do
13
+ visit rails_bridge_layout_path(:id=>'application')
14
+ puts page.source
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ # Configure Rails Envinronment
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+ require 'tm_helper'
5
+
6
+ ENV["RAILS_ENV"] = "test"
7
+
8
+ LOG_TO_STDOUT = ENV["LOG_TO_STDOUT"]
9
+
10
+ def application_test?
11
+ ENV['TM_FILEPATH'] =~ /integration/ || \
12
+ ENV['TM_FILEPATH'] =~ /requests/
13
+ end
14
+
15
+ if TmHelper.running_in_textmate? && !application_test?
16
+ require File.join(File.dirname(__FILE__),'..','lib','rails_bridge')
17
+ else
18
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
19
+ require "rails/test_help"
20
+ require "rspec/rails"
21
+ require 'capybara/rspec'
22
+ Capybara.app = Dummy::Application
23
+
24
+ ActionMailer::Base.delivery_method = :test
25
+ ActionMailer::Base.perform_deliveries = true
26
+ ActionMailer::Base.default_url_options[:host] = "test.com"
27
+
28
+ Rails.backtrace_cleaner.remove_silencers!
29
+
30
+ # Configure capybara for integration testing
31
+ require "capybara/rails"
32
+ Capybara.default_driver = :rack_test
33
+ Capybara.default_selector = :css
34
+
35
+ # Run any available migration
36
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
37
+
38
+ end
39
+
40
+ # Load support files
41
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
42
+
43
+ TestServer.logger = RailsBridge::ContentBridge.logger
44
+
45
+ RSpec.configure do |config|
46
+ # == Mock Framework
47
+ #
48
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
49
+ #
50
+ # config.mock_with :mocha
51
+ # config.mock_with :flexmock
52
+ # config.mock_with :rr
53
+ config.mock_with :rspec
54
+
55
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
56
+ # examples within a transaction, remove the following line or assign false
57
+ # instead of true.
58
+ # config.use_transactional_fixtures = false
59
+ # config.filter_run :focus => true
60
+ config.run_all_when_everything_filtered = true
61
+
62
+ end
@@ -0,0 +1,26 @@
1
+ module ContentBridgeSpecHelper
2
+ DEFAULT_RETURN_DATA = "RETURN DATA"
3
+
4
+ TEST_SERVER_PORT=1234
5
+
6
+ DEFAULT_REQUEST_VALUES = {
7
+ :protocol => 'http',
8
+ :host => 'localhost',
9
+ :port => TEST_SERVER_PORT,
10
+ :path => '/path',
11
+ :params => {:return_data=>DEFAULT_RETURN_DATA},
12
+ :default_content => 'Request Default Content',
13
+ :cache_timeout => 0
14
+ }
15
+
16
+ class ContentBridgeTest < RailsBridge::ContentBridge
17
+ content_request :chang do |request|
18
+ request.protocol = DEFAULT_REQUEST_VALUES[:protocol]
19
+ request.host = DEFAULT_REQUEST_VALUES[:host]
20
+ request.port = DEFAULT_REQUEST_VALUES[:port]
21
+ request.path = DEFAULT_REQUEST_VALUES[:path]
22
+ request.params = DEFAULT_REQUEST_VALUES[:params]
23
+ request.default_content = DEFAULT_REQUEST_VALUES[:default_content]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,2 @@
1
+ module LayoutBridgeSpecHelper
2
+ end
@@ -0,0 +1,12 @@
1
+ log_filename = File.join(File.dirname(__FILE__),'..','..','log',"#{ENV["RAILS_ENV"]}.log")
2
+
3
+ if defined?(LOG_TO_STDOUT) && LOG_TO_STDOUT
4
+ logger = Logger.new(STDOUT)
5
+ else
6
+ logger = Logger.new(File.open(log_filename,'a'))
7
+ end
8
+
9
+ if defined? Rails
10
+ Rails.logger = logger
11
+ end
12
+ RailsBridge::ContentBridge.logger = logger