render_component_vho 3.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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 vhochstein
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,37 @@
1
+ Components allow you to call other actions for their rendered response while executing another action. You can either delegate
2
+ the entire response rendering or you can mix a partial response in with your other content.
3
+
4
+ class WeblogController < ActionController::Base
5
+ # Performs a method and then lets hello_world output its render
6
+ def delegate_action
7
+ do_other_stuff_before_hello_world
8
+ render_component :controller => "greeter", :action => "hello_world", :params => { :person => "david" }
9
+ end
10
+ end
11
+
12
+ class GreeterController < ActionController::Base
13
+ def hello_world
14
+ render :text => "#{params[:person]} says, Hello World!"
15
+ end
16
+ end
17
+
18
+ The same can be done in a view to do a partial rendering:
19
+
20
+ Let's see a greeting:
21
+ <%= render_component :controller => "greeter", :action => "hello_world" %>
22
+
23
+ It is also possible to specify the controller as a class constant, bypassing the inflector
24
+ code to compute the controller class at runtime:
25
+
26
+ <%= render_component :controller => GreeterController, :action => "hello_world" %>
27
+
28
+ == When to use components
29
+
30
+ Components should be used with care. They're significantly slower than simply splitting reusable parts into partials and
31
+ conceptually more complicated. Don't use components as a way of separating concerns inside a single application. Instead,
32
+ reserve components to those rare cases where you truly have reusable view and controller elements that can be employed
33
+ across many applications at once.
34
+
35
+ So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters.
36
+
37
+ Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ require './lib/render_component/version.rb'
14
+
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "render_component_vho"
18
+ gem.version = RenderComponent::Version::STRING
19
+ gem.homepage = "http://github.com/vhochstein/render_component"
20
+ gem.license = "MIT"
21
+ gem.summary = %Q{render actions in other controllers for their rendered response}
22
+ gem.description = %Q{Components allow you to call other actions for their rendered response while executing another action}
23
+ gem.email = "david@loudthinking.com"
24
+ gem.authors = ["David Heinemeier Hansson"]
25
+ gem.add_runtime_dependency 'railties', '~>3.0.0'
26
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
27
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
28
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
29
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
30
+ end
31
+ Jeweler::RubygemsDotOrgTasks.new
32
+
33
+
34
+ require 'rake/testtask'
35
+ desc 'Test the components plugin.'
36
+ Rake::TestTask.new(:test) do |t|
37
+ t.libs << 'lib'
38
+ t.pattern = 'test/**/*_test.rb'
39
+ t.verbose = true
40
+ end
41
+
42
+ require 'rcov/rcovtask'
43
+ Rcov::RcovTask.new do |test|
44
+ test.libs << 'test'
45
+ test.pattern = 'test/**/test_*.rb'
46
+ test.verbose = true
47
+ end
48
+
49
+ task :default => :test
50
+
51
+ require 'rake/rdoctask'
52
+
53
+ desc 'Generate documentation for the components plugin.'
54
+ Rake::RDocTask.new(:rdoc) do |rdoc|
55
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "render_component #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ RENDER_COMPONENT_PLUGIN = true
2
+ require 'render_component'
@@ -0,0 +1,4 @@
1
+ require 'render_component/components'
2
+ require 'action_controller'
3
+ require 'action_dispatch/middleware/flash'
4
+ ActionController::Base.send :include, RenderComponent::Components
@@ -0,0 +1,153 @@
1
+ module RenderComponent
2
+ module Components
3
+ def self.included(base) #:nodoc:
4
+ base.class_eval do
5
+ include InstanceMethods
6
+ extend ClassMethods
7
+ helper HelperMethods
8
+
9
+ # If this controller was instantiated to process a component request,
10
+ # +parent_controller+ points to the instantiator of this controller.
11
+ attr_accessor :parent_controller
12
+
13
+ alias_method_chain :session, :render_component
14
+ alias_method_chain :flash, :render_component
15
+ alias_method :component_request?, :parent_controller
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ # Track parent controller to identify component requests
21
+ def process_with_components(request, action, parent_controller = nil) #:nodoc:
22
+ controller = new
23
+ controller.parent_controller = parent_controller
24
+ controller.dispatch(action, request)
25
+ end
26
+ end
27
+
28
+ module HelperMethods
29
+ def render_component(options)
30
+ controller.send(:render_component_into_view, options)
31
+ end
32
+ end
33
+
34
+ module InstanceMethods
35
+
36
+ protected
37
+ # Renders the component specified as the response for the current method
38
+ def render_component(options) #:doc:
39
+ component_logging(options) do
40
+ response = component_response(options, true)[2]
41
+ if response.redirect_url
42
+ redirect_to response.redirect_url
43
+ else
44
+ render :text => response.body, :status => response.status
45
+ end
46
+ end
47
+ end
48
+
49
+ # Returns the component response as a string
50
+ def render_component_into_view(options) #:doc:
51
+ component_logging(options) do
52
+ response = component_response(options, false)[2]
53
+ if redirected = response.redirect_url
54
+ if redirected =~ %r{://}
55
+ location = URI.parse(redirected)
56
+ redirected = location.query ? "#{location.path}?#{location.query}" : location.path
57
+ end
58
+ render_component_into_view(Rails.application.routes.recognize_path(redirected, { :method => nil }))
59
+ else
60
+ response.body.html_safe
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ def flash_with_render_component(refresh = false) #:nodoc:
67
+ if @component_flash.nil? || refresh
68
+ @component_flash =
69
+ if defined?(@parent_controller)
70
+ @parent_controller.flash
71
+ else
72
+ session['flash'] ||= ActionDispatch::Flash::FlashHash.new
73
+ end
74
+ end
75
+ @component_flash
76
+ end
77
+
78
+ def session_with_render_component
79
+ #if defined?(@parent_controller)
80
+ if component_request?
81
+ @parent_controller.session
82
+ else
83
+ @_request.session
84
+ end
85
+ end
86
+
87
+ private
88
+ def component_response(options, reuse_response)
89
+ klass = component_class(options)
90
+ component_request = request_for_component(klass.controller_path, options)
91
+ # needed ???
92
+ #if reuse_response
93
+ #component_request.env["action_controller.instance"].instance_variable_set :@_response, request.env["action_controller.instance"].instance_variable_get(:@_response)
94
+ #end
95
+ klass.process_with_components(component_request, options[:action], self)
96
+ end
97
+
98
+ # determine the controller class for the component request
99
+ def component_class(options)
100
+ if controller = options[:controller]
101
+ controller.is_a?(Class) ? controller : "#{controller.to_s.camelize}Controller".constantize
102
+ else
103
+ self.class
104
+ end
105
+ end
106
+
107
+ # Create a new request object based on the current request.
108
+ # NOT IMPLEMENTED FOR RAILS 3 SO FAR: The new request inherits the session from the current request,
109
+ # bypassing any session options set for the component controller's class
110
+ def request_for_component(controller_path, options)
111
+ if options.is_a? Hash
112
+ old_style_params = options.delete(:params)
113
+ options.merge!(old_style_params) unless old_style_params.nil?
114
+
115
+ request_params = options.symbolize_keys
116
+ request_env = {}
117
+
118
+ request.env.select {|key, value| key == key.upcase || key == 'rack.input'}.each {|item| request_env[item[0]] = item[1]}
119
+
120
+ request_env['REQUEST_URI'] = url_for(options)
121
+ request_env["PATH_INFO"] = url_for(options.merge(:only_path => true))
122
+ request_env["action_dispatch.request.symbolized_path_parameters"] = request_params
123
+ request_env["action_dispatch.request.parameters"] = request_params.with_indifferent_access
124
+ request_env["action_dispatch.request.path_parameters"] = Hash[request_params.select{|key, value| [:controller, :action].include?(key)}].with_indifferent_access
125
+ request_env["warden"] = request.env["warden"] if (request.env.has_key?("warden"))
126
+ component_request = ActionDispatch::Request.new(request_env)
127
+
128
+ # its an internal request request forgery protection has to be disabled
129
+ # because otherwise forgery detection might raise an error
130
+ component_request.instance_eval do
131
+ def forgery_whitelisted?
132
+ true
133
+ end
134
+ end
135
+ component_request
136
+ else
137
+ request
138
+ end
139
+ end
140
+
141
+ def component_logging(options)
142
+ if logger
143
+ logger.info "Start rendering component (#{options.inspect}): "
144
+ result = yield
145
+ logger.info "\n\nEnd of component rendering"
146
+ result
147
+ else
148
+ yield
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,9 @@
1
+ module RenderComponent
2
+ module Version
3
+ MAJOR = 3
4
+ MINOR = 0
5
+ PATCH = 2
6
+
7
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ ENV["RAILS_ENV"] = "test"
3
+ require File.expand_path('../../../../../config/environment', __FILE__)
4
+ require 'rails/test_help'
5
+
6
+ $: << File.dirname(__FILE__) + "/../lib"
7
+ require File.dirname(__FILE__) + "/../init"
@@ -0,0 +1,156 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ class CallersController < ActionController::Base
4
+ def calling_from_controller
5
+ render_component(:controller => "callees", :action => "being_called")
6
+ end
7
+
8
+ def calling_from_controller_with_params
9
+ render_component(:controller => "callees", :action => "being_called", :params => { "name" => "David" })
10
+ end
11
+
12
+ def calling_from_controller_with_session
13
+ session['name'] = 'Bernd'
14
+ render_component(:controller => "callees", :action => "being_called")
15
+ end
16
+
17
+ def calling_from_controller_with_different_status_code
18
+ render_component(:controller => "callees", :action => "blowing_up")
19
+ end
20
+
21
+ def calling_from_template
22
+ render :inline => "Ring, ring: <%= render_component(:controller => 'callees', :action => 'being_called') %>"
23
+ end
24
+
25
+ def internal_caller
26
+ render :inline => "Are you there? <%= render_component(:action => 'internal_callee') %>"
27
+ end
28
+
29
+ def internal_callee
30
+ render :text => "Yes, ma'am"
31
+ end
32
+
33
+ def set_flash
34
+ render_component(:controller => "callees", :action => "set_flash")
35
+ end
36
+
37
+ def use_flash
38
+ render_component(:controller => "callees", :action => "use_flash")
39
+ end
40
+
41
+ def calling_redirected
42
+ render_component(:controller => "callees", :action => "redirected")
43
+ end
44
+
45
+ def calling_redirected_as_string
46
+ render :inline => "<%= render_component(:controller => 'callees', :action => 'redirected') %>"
47
+ end
48
+
49
+ def rescue_action(e) raise end
50
+ end
51
+
52
+ class CalleesController < ActionController::Base
53
+ def being_called
54
+ render :text => "#{params[:name] || session[:name] || "Lady"} of the House, speaking"
55
+ end
56
+
57
+ def blowing_up
58
+ render :text => "It's game over, man, just game over, man!", :status => 500
59
+ end
60
+
61
+ def set_flash
62
+ flash[:notice] = 'My stoney baby'
63
+ render :text => 'flash is set'
64
+ end
65
+
66
+ def use_flash
67
+ render :text => flash[:notice] || 'no flash'
68
+ end
69
+
70
+ def redirected
71
+ redirect_to :controller => "callees", :action => "being_called"
72
+ end
73
+
74
+ def rescue_action(e) raise end
75
+ end
76
+
77
+ class ComponentsTest < ActionController::IntegrationTest #ActionController::TestCase
78
+
79
+ def setup
80
+ @routes.draw do
81
+ match 'callers/:action', :to => 'callers'
82
+ match 'callees/:action', :to => 'callees'
83
+ end
84
+ end
85
+
86
+ def test_calling_from_controller
87
+ get '/callers/calling_from_controller'
88
+ assert_equal "Lady of the House, speaking", @response.body
89
+ end
90
+
91
+ def test_calling_from_controller_with_params
92
+ get '/callers/calling_from_controller_with_params'
93
+ assert_equal "David of the House, speaking", @response.body
94
+ end
95
+
96
+ def test_calling_from_controller_with_different_status_code
97
+ get '/callers/calling_from_controller_with_different_status_code'
98
+ assert_equal 500, @response.response_code
99
+ end
100
+
101
+ def test_calling_from_template
102
+ get '/callers/calling_from_template'
103
+ assert_equal "Ring, ring: Lady of the House, speaking", @response.body
104
+ end
105
+
106
+ def test_etag_is_set_for_parent_template_when_calling_from_template
107
+ get '/callers/calling_from_template'
108
+ expected_etag = etag_for("Ring, ring: Lady of the House, speaking")
109
+ assert_equal expected_etag, @response.headers['ETag']
110
+ end
111
+
112
+ def test_internal_calling
113
+ get '/callers/internal_caller'
114
+ assert_equal "Are you there? Yes, ma'am", @response.body
115
+ end
116
+
117
+ def test_flash
118
+ get '/callers/set_flash'
119
+ assert_equal 'My stoney baby', flash[:notice]
120
+ get '/callers/use_flash'
121
+ assert_equal 'My stoney baby', @response.body
122
+ get '/callers/use_flash'
123
+ assert_equal 'no flash', @response.body
124
+ end
125
+
126
+ def test_component_redirect_redirects
127
+ get '/callers/calling_redirected'
128
+ assert_redirected_to :controller=>"callees", :action => "being_called"
129
+ end
130
+
131
+
132
+ def test_component_multiple_redirect_redirects
133
+ test_component_redirect_redirects
134
+ test_internal_calling
135
+ end
136
+
137
+
138
+ def test_component_as_string_redirect_renders_redirected_action
139
+ get '/callers/calling_redirected_as_string'
140
+
141
+ assert_equal "Lady of the House, speaking", @response.body
142
+ end
143
+
144
+ def test_calling_from_controller_with_session
145
+ get '/callers/calling_from_controller_with_session'
146
+ assert_equal "Bernd of the House, speaking", @response.body
147
+ end
148
+
149
+
150
+
151
+
152
+ protected
153
+ def etag_for(text)
154
+ %("#{Digest::MD5.hexdigest(text)}")
155
+ end
156
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: render_component_vho
3
+ version: !ruby/object:Gem::Version
4
+ hash: 3
5
+ prerelease: false
6
+ segments:
7
+ - 3
8
+ - 0
9
+ - 2
10
+ version: 3.0.2
11
+ platform: ruby
12
+ authors:
13
+ - David Heinemeier Hansson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-26 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ name: shoulda
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ requirement: *id001
34
+ type: :development
35
+ - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ name: bundler
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ requirement: *id002
50
+ type: :development
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ name: jeweler
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 7
60
+ segments:
61
+ - 1
62
+ - 5
63
+ - 2
64
+ version: 1.5.2
65
+ requirement: *id003
66
+ type: :development
67
+ - !ruby/object:Gem::Dependency
68
+ prerelease: false
69
+ name: rcov
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirement: *id004
80
+ type: :development
81
+ - !ruby/object:Gem::Dependency
82
+ prerelease: false
83
+ name: railties
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 7
90
+ segments:
91
+ - 3
92
+ - 0
93
+ - 0
94
+ version: 3.0.0
95
+ requirement: *id005
96
+ type: :runtime
97
+ description: Components allow you to call other actions for their rendered response while executing another action
98
+ email: david@loudthinking.com
99
+ executables: []
100
+
101
+ extensions: []
102
+
103
+ extra_rdoc_files:
104
+ - LICENSE.txt
105
+ - README
106
+ files:
107
+ - .document
108
+ - LICENSE.txt
109
+ - README
110
+ - Rakefile
111
+ - init.rb
112
+ - lib/render_component.rb
113
+ - lib/render_component/components.rb
114
+ - lib/render_component/version.rb
115
+ - test/abstract_unit.rb
116
+ - test/components_test.rb
117
+ has_rdoc: true
118
+ homepage: http://github.com/vhochstein/render_component
119
+ licenses:
120
+ - MIT
121
+ post_install_message:
122
+ rdoc_options: []
123
+
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirements: []
145
+
146
+ rubyforge_project:
147
+ rubygems_version: 1.3.7
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: render actions in other controllers for their rendered response
151
+ test_files:
152
+ - test/abstract_unit.rb
153
+ - test/components_test.rb