[Ovirt-devel] [PATCH server 7/8] Install render_component plugin.

Joey Boggs jboggs at redhat.com
Mon Jul 20 16:42:35 UTC 2009


Jason Guiditta wrote:
> This is no longer in core rails (and we should
> look at removing it's use altogether asap).
>
> Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com>
> ---
>  src/vendor/plugins/render_component/README         |   37 +++++
>  src/vendor/plugins/render_component/Rakefile       |   22 +++
>  src/vendor/plugins/render_component/init.rb        |    2 +
>  .../plugins/render_component/lib/components.rb     |  141 ++++++++++++++++++++
>  .../plugins/render_component/test/abstract_unit.rb |    8 +
>  .../render_component/test/components_test.rb       |  136 +++++++++++++++++++
>  6 files changed, 346 insertions(+), 0 deletions(-)
>  create mode 100644 src/vendor/plugins/render_component/README
>  create mode 100644 src/vendor/plugins/render_component/Rakefile
>  create mode 100644 src/vendor/plugins/render_component/init.rb
>  create mode 100644 src/vendor/plugins/render_component/lib/components.rb
>  create mode 100644 src/vendor/plugins/render_component/test/abstract_unit.rb
>  create mode 100644 src/vendor/plugins/render_component/test/components_test.rb
>
> diff --git a/src/vendor/plugins/render_component/README b/src/vendor/plugins/render_component/README
> new file mode 100644
> index 0000000..a6a318a
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/README
> @@ -0,0 +1,37 @@
> +Components allow you to call other actions for their rendered response while executing another action. You can either delegate
> +the entire response rendering or you can mix a partial response in with your other content.
> +
> +  class WeblogController < ActionController::Base
> +    # Performs a method and then lets hello_world output its render
> +    def delegate_action
> +      do_other_stuff_before_hello_world
> +      render_component :controller => "greeter",  :action => "hello_world", :params => { :person => "david" }
> +    end
> +  end
> +
> +  class GreeterController < ActionController::Base
> +    def hello_world
> +      render :text => "#{params[:person]} says, Hello World!"
> +    end
> +  end
> +
> +The same can be done in a view to do a partial rendering:
> +
> +  Let's see a greeting:
> +  <%= render_component :controller => "greeter", :action => "hello_world" %>
> +
> +It is also possible to specify the controller as a class constant, bypassing the inflector
> +code to compute the controller class at runtime:
> +
> +<%= render_component :controller => GreeterController, :action => "hello_world" %>
> +
> +== When to use components
> +
> +Components should be used with care. They're significantly slower than simply splitting reusable parts into partials and
> +conceptually more complicated. Don't use components as a way of separating concerns inside a single application. Instead,
> +reserve components to those rare cases where you truly have reusable view and controller elements that can be employed
> +across many applications at once.
> +
> +So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters.
> +
> +Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
> \ No newline at end of file
> diff --git a/src/vendor/plugins/render_component/Rakefile b/src/vendor/plugins/render_component/Rakefile
> new file mode 100644
> index 0000000..d99407b
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/Rakefile
> @@ -0,0 +1,22 @@
> +require 'rake'
> +require 'rake/testtask'
> +require 'rake/rdoctask'
> +
> +desc 'Default: run unit tests.'
> +task :default => :test
> +
> +desc 'Test the components plugin.'
> +Rake::TestTask.new(:test) do |t|
> +  t.libs << 'lib'
> +  t.pattern = 'test/**/*_test.rb'
> +  t.verbose = true
> +end
> +
> +desc 'Generate documentation for the components plugin.'
> +Rake::RDocTask.new(:rdoc) do |rdoc|
> +  rdoc.rdoc_dir = 'rdoc'
> +  rdoc.title = 'Components'
> +  rdoc.options << '--line-numbers' << '--inline-source'
> +  rdoc.rdoc_files.include('README')
> +  rdoc.rdoc_files.include('lib/**/*.rb')
> +end
> \ No newline at end of file
> diff --git a/src/vendor/plugins/render_component/init.rb b/src/vendor/plugins/render_component/init.rb
> new file mode 100644
> index 0000000..b428c52
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/init.rb
> @@ -0,0 +1,2 @@
> +require 'components'
> +ActionController::Base.send :include, Components
> diff --git a/src/vendor/plugins/render_component/lib/components.rb b/src/vendor/plugins/render_component/lib/components.rb
> new file mode 100644
> index 0000000..9263cde
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/lib/components.rb
> @@ -0,0 +1,141 @@
> +module Components
> +  def self.included(base) #:nodoc:
> +    base.class_eval do
> +      include InstanceMethods
> +      extend ClassMethods
> +      helper HelperMethods
> +
> +      # If this controller was instantiated to process a component request,
> +      # +parent_controller+ points to the instantiator of this controller.
> +      attr_accessor :parent_controller
> +
> +      alias_method_chain :process_cleanup, :render_component
> +      alias_method_chain :session=, :render_component
> +      alias_method_chain :flash, :render_component
> +      alias_method_chain :perform_action, :render_component
> +      alias_method_chain :send_response, :render_component
> +
> +      alias_method :component_request?, :parent_controller
> +    end
> +  end
> +
> +  module ClassMethods
> +    # Track parent controller to identify component requests
> +    def process_with_components(request, response, parent_controller = nil) #:nodoc:
> +      controller = new
> +      controller.parent_controller = parent_controller
> +      controller.process(request, response)
> +    end
> +  end
> +
> +  module HelperMethods
> +    def render_component(options)
> +      @controller.__send__(:render_component_as_string, options)
> +    end
> +  end
> +
> +  module InstanceMethods
> +    def perform_action_with_render_component
> +      perform_action_without_render_component
> +      remove_instance_variable(:@_flash) if defined? @_flash
> +    end
> +
> +    # Extracts the action_name from the request parameters and performs that action.
> +    def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc:
> +      flash.discard if component_request?
> +      process_without_components(request, response, method, *arguments)
> +    end
> +
> +    def send_response_with_render_component
> +      response.prepare! unless component_request?
> +      response
> +    end
> +
> +    protected
> +      # Renders the component specified as the response for the current method
> +      def render_component(options) #:doc:
> +        component_logging(options) do
> +          render_for_text(component_response(options, true).body, response.status)
> +        end
> +      end
> +
> +      # Returns the component response as a string
> +      def render_component_as_string(options) #:doc:
> +        component_logging(options) do
> +          response = component_response(options, false)
> +
> +          if redirected = response.redirected_to
> +            render_component_as_string(redirected)
> +          else
> +            response.body
> +          end
> +        end
> +      end
> +
> +      def flash_with_render_component(refresh = false) #:nodoc:
> +        if !defined?(@_flash) || refresh
> +          @_flash =
> +            if defined?(@parent_controller)
> +              @parent_controller.flash
> +            else
> +              flash_without_render_component
> +            end
> +        end
> +        @_flash
> +      end
> +
> +    private
> +      def component_response(options, reuse_response)
> +        klass    = component_class(options)
> +        request  = request_for_component(klass.controller_path, options)
> +        new_response = reuse_response ? response : response.dup
> +
> +        klass.process_with_components(request, new_response, self)
> +      end
> +
> +      # determine the controller class for the component request
> +      def component_class(options)
> +        if controller = options[:controller]
> +          controller.is_a?(Class) ? controller : "#{controller.camelize}Controller".constantize
> +        else
> +          self.class
> +        end
> +      end
> +
> +      # Create a new request object based on the current request.
> +      # The new request inherits the session from the current request,
> +      # bypassing any session options set for the component controller's class
> +      def request_for_component(controller_path, options)
> +        new_request         = request.dup
> +        new_request.session = request.session
> +
> +        new_request.instance_variable_set(
> +          :@parameters,
> +          (options[:params] || {}).with_indifferent_access.update(
> +            "controller" => controller_path, "action" => options[:action], "id" => options[:id]
> +          )
> +        )
> +
> +        new_request
> +      end
> +
> +      def component_logging(options)
> +        if logger
> +          logger.info "Start rendering component (#{options.inspect}): "
> +          result = yield
> +          logger.info "\n\nEnd of component rendering"
> +          result
> +        else
> +          yield
> +        end
> +      end
> +
> +      def session_with_render_component=(options = {})
> +        session_without_render_component=(options) unless component_request?
> +      end
> +
> +      def process_cleanup_with_render_component
> +        process_cleanup_without_render_component unless component_request?
> +      end
> +  end
> +end
> diff --git a/src/vendor/plugins/render_component/test/abstract_unit.rb b/src/vendor/plugins/render_component/test/abstract_unit.rb
> new file mode 100644
> index 0000000..f022971
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/test/abstract_unit.rb
> @@ -0,0 +1,8 @@
> +require 'rubygems'
> +require 'test/unit'
> +require 'action_controller'
> +require 'action_controller/test_process'
> +ActionController::Routing::Routes.reload rescue nil
> +
> +$: << File.dirname(__FILE__) + "/../lib"
> +require File.dirname(__FILE__) + "/../init"
> diff --git a/src/vendor/plugins/render_component/test/components_test.rb b/src/vendor/plugins/render_component/test/components_test.rb
> new file mode 100644
> index 0000000..53fcd7f
> --- /dev/null
> +++ b/src/vendor/plugins/render_component/test/components_test.rb
> @@ -0,0 +1,136 @@
> +require File.dirname(__FILE__) + '/abstract_unit'
> +
> +class CallerController < ActionController::Base
> +  def calling_from_controller
> +    render_component(:controller => "callee", :action => "being_called")
> +  end
> +
> +  def calling_from_controller_with_params
> +    render_component(:controller => "callee", :action => "being_called", :params => { "name" => "David" })
> +  end
> +
> +  def calling_from_controller_with_different_status_code
> +    render_component(:controller => "callee", :action => "blowing_up")
> +  end
> +
> +  def calling_from_template
> +    render :inline => "Ring, ring: <%= render_component(:controller => 'callee', :action => 'being_called') %>"
> +  end
> +
> +  def internal_caller
> +    render :inline => "Are you there? <%= render_component(:action => 'internal_callee') %>"
> +  end
> +
> +  def internal_callee
> +    render :text => "Yes, ma'am"
> +  end
> +
> +  def set_flash
> +    render_component(:controller => "callee", :action => "set_flash")
> +  end
> +
> +  def use_flash
> +    render_component(:controller => "callee", :action => "use_flash")
> +  end
> +
> +  def calling_redirected
> +    render_component(:controller => "callee", :action => "redirected")
> +  end
> +
> +  def calling_redirected_as_string
> +    render :inline => "<%= render_component(:controller => 'callee', :action => 'redirected') %>"
> +  end
> +
> +  def rescue_action(e) raise end
> +end
> +
> +class CalleeController < ActionController::Base
> +  def being_called
> +    render :text => "#{params[:name] || "Lady"} of the House, speaking"
> +  end
> +
> +  def blowing_up
> +    render :text => "It's game over, man, just game over, man!", :status => 500
> +  end
> +
> +  def set_flash
> +    flash[:notice] = 'My stoney baby'
> +    render :text => 'flash is set'
> +  end
> +
> +  def use_flash
> +    render :text => flash[:notice] || 'no flash'
> +  end
> +
> +  def redirected
> +    redirect_to :controller => "callee", :action => "being_called"
> +  end
> +
> +  def rescue_action(e) raise end
> +end
> +
> +class ComponentsTest < ActionController::TestCase
> +  tests CallerController
> +
> +  def test_calling_from_controller
> +    get :calling_from_controller
> +    assert_equal "Lady of the House, speaking", @response.body
> +  end
> +
> +  def test_calling_from_controller_with_params
> +    get :calling_from_controller_with_params
> +    assert_equal "David of the House, speaking", @response.body
> +  end
> +
> +  def test_calling_from_controller_with_different_status_code
> +    get :calling_from_controller_with_different_status_code
> +    assert_equal 500, @response.response_code
> +  end
> +
> +  def test_calling_from_template
> +    get :calling_from_template
> +    assert_equal "Ring, ring: Lady of the House, speaking", @response.body
> +  end
> +
> +  def test_etag_is_set_for_parent_template_when_calling_from_template
> +    get :calling_from_template
> +    expected_etag = etag_for("Ring, ring: Lady of the House, speaking")
> +    assert_equal expected_etag, @response.headers['ETag']
> +  end
> +
> +  def test_internal_calling
> +    get :internal_caller
> +    assert_equal "Are you there? Yes, ma'am", @response.body
> +  end
> +
> +  def test_flash
> +    get :set_flash
> +    assert_equal 'My stoney baby', flash[:notice]
> +    get :use_flash
> +    assert_equal 'My stoney baby', @response.body
> +    get :use_flash
> +    assert_equal 'no flash', @response.body
> +  end
> +
> +  def test_component_redirect_redirects
> +    get :calling_redirected
> +
> +    assert_redirected_to :controller=>"callee", :action => "being_called"
> +  end
> +
> +  def test_component_multiple_redirect_redirects
> +    test_component_redirect_redirects
> +    test_internal_calling
> +  end
> +
> +  def test_component_as_string_redirect_renders_redirected_action
> +    get :calling_redirected_as_string
> +
> +    assert_equal "Lady of the House, speaking", @response.body
> +  end
> +
> +  protected
> +    def etag_for(text)
> +      %("#{Digest::MD5.hexdigest(text)}")
> +    end
> +end
>   
ACK, Flexchart works and no log error output




More information about the ovirt-devel mailing list