public
Description: response for lets you decorate your actions respond_to blocks
Homepage: http://blog.ardes.com/response_for
Clone URL: git://github.com/ianwhite/response_for.git
Click here to lend your support to: response_for and make a donation at www.pledgie.com !
response_for / lib / ardes / response_for.rb
570f798d » ian 2007-10-23 response_for: initial release 1 module Ardes #:nodoc:
8ac908ad » ianwhite 2008-09-14 Added specs for stacking re... 2 # included into ActionController::Base
f0b98bf1 » ian 2007-10-18 Initial import of response_for 3 module ResponseFor
570f798d » ian 2007-10-23 response_for: initial release 4 def self.included(base)
5 base.class_eval do
6 extend ClassMethods
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 7 alias_method_chain :default_render, :response_for
c89bc63b » ianwhite 2008-10-09 now intercepting template_e... 8 alias_method_chain :template_exists?, :response_for
37c5ff4c » ianwhite 2008-10-19 Fixed bug where response_fo... 9 alias_method_chain :respond_to, :response_for
570f798d » ian 2007-10-23 response_for: initial release 10 end
11 end
f0b98bf1 » ian 2007-10-18 Initial import of response_for 12
570f798d » ian 2007-10-23 response_for: initial release 13 module ClassMethods
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 14 # response_for allows you to specify a default response for your actions that don't specify a
15 # respond_to block.
2b728b93 » ian 2007-10-23 response_for: tiny docfix 16 #
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 17 # Using response_for, you may keep the response logic out of the action, so that it can be overriden easily
18 # without having to rewrite the entire action. This is very useful when subclassing controllers.
19 #
20 # == Usage
21 #
22 # response_for :action1 [, :action2], [,:types => [:mime, :type, :list]] [ do |format| ... end] # or
570f798d » ian 2007-10-23 response_for: initial release 23 #
24 # === Example
25 #
26 # class FooController < ApplicationController
27 # def index
28 # @foos = Foo.find(:all)
29 # end
30 #
31 # def show
32 # @foo = Foo.find(params[:id])
33 # end
34 # end
35 #
36 # # this controller needs to respond_to fbml on index, and
37 # # js, html and xml (templates) on index and show
38 # class SpecialFooController < FooController
39 # response_for :index do |format|
40 # format.fbml { render :inline => turn_into_facebook(@foos) }
41 # end
42 #
43 # response_for :index, :show, :types => [:html, :xml, :js]
44 # end
45 #
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 46 # === when response_for kicks in
64911cf3 » ian 2007-11-27 response_for: * IMPORTANT: ... 47 #
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 48 # response_for only kicks in if the action (or any filters) have not already redirected or rendered.
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 49 #
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 50 # This means that if you foresee wanting to override your action's responses, you should write them without
51 # a respond_to block, but with a response_for block (the latter can be overridden by subsequent response_fors, the
52 # former cannot)
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 53 #
54 # === Other examples
570f798d » ian 2007-10-23 response_for: initial release 55 #
56 # response_for :index, :types => [:fbml] # index will respond to fbml and try to render, say, index.fbml.builder
57 #
58 # response_for :update do |format| # this example is for a resources_controller controller
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 59 # if !(resource.new_record? || resource.changed?) # => resource.saved?
c89bc63b » ianwhite 2008-10-09 now intercepting template_e... 60 # format.js { render(:update) {|page| page.replace dom_id(resource), :partial => resource }}
570f798d » ian 2007-10-23 response_for: initial release 61 # else
62 # format.js { render(:update) {|page| page.visual_effect :shake, dom_id(resource) }}
63 # end
64 # end
65 #
66 # === Notes
67 #
c89bc63b » ianwhite 2008-10-09 now intercepting template_e... 68 # * If the before_filters or action renders or redirects, then response_for will not be invoked.
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 69 # * you can stack up multiple response_for calls, the most recent has precedence
570f798d » ian 2007-10-23 response_for: initial release 70 # * the specifed block is executed within the controller instance, so you can use controller
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 71 # instance methods and instance variables (i.e. you can make it look just like a regular
c89bc63b » ianwhite 2008-10-09 now intercepting template_e... 72 # respond_to block).
73 # * you can add a response_for an action that has no action method defined. This is just like
74 # defining a template for an action that has no action method defined.
570f798d » ian 2007-10-23 response_for: initial release 75 # * you can combine the :types option with a block, the block has precedence if you specify the
76 # same mime type in both.
77 def response_for(*actions, &block)
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 78 (options = actions.extract_options!).assert_valid_keys(:types)
570f798d » ian 2007-10-23 response_for: initial release 79
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 80 types_block = if options[:types]
81 proc {|responder| Array(options[:types]).each {|type| responder.send type}}
82 end
570f798d » ian 2007-10-23 response_for: initial release 83
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 84 # store responses against action names
570f798d » ian 2007-10-23 response_for: initial release 85 actions.collect(&:to_s).each do |action|
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 86 action_responses[action] ||= []
87 action_responses[action].unshift types_block if types_block
88 action_responses[action].unshift block if block
570f798d » ian 2007-10-23 response_for: initial release 89 end
90 end
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 91
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 92 # remove any response for the specified actions. If no arguments are given,
93 # then all repsonses for all actions are removed
570f798d » ian 2007-10-23 response_for: initial release 94 def remove_response_for(*actions)
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 95 if actions.empty?
96 instance_variable_set('@action_responses', nil)
97 else
98 actions.each {|action| action_responses.delete(action.to_s)}
99 end
570f798d » ian 2007-10-23 response_for: initial release 100 end
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 101
102 # return action_responses Hash. On initialize, set and return hash whose values are copies of superclass action_responses, if any
570f798d » ian 2007-10-23 response_for: initial release 103 def action_responses
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 104 instance_variable_get('@action_responses') || instance_variable_set('@action_responses', copy_of_each_of_superclass_action_responses)
570f798d » ian 2007-10-23 response_for: initial release 105 end
106
06da19df » ianwhite 2008-10-09 Added note about placement ... 107 # takes any responses from the argument (a controller, or responses module) and adds them to this controller's responses
108 def include_responses_from(responses_container)
109 responses_container.action_responses.each do |action, responses|
110 action_responses[action] ||= []
d8ca73c5 » ianwhite 2008-10-09 Fixed bug where include_res... 111 action_responses[action].unshift(*responses)
06da19df » ianwhite 2008-10-09 Added note about placement ... 112 end
113 end
114
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 115 private
116 def copy_of_each_of_superclass_action_responses
117 (superclass.action_responses rescue {}).inject({}){|m,(k,v)| m.merge(k => v.dup)}
570f798d » ian 2007-10-23 response_for: initial release 118 end
119 end
c92657b8 » ian 2007-12-11 response_for only kicks in ... 120
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 121 protected
c89bc63b » ianwhite 2008-10-09 now intercepting template_e... 122 # does a response exist for the current action?
123 def response_exists?
124 self.class.action_responses.keys.include?(action_name.to_s)
125 end
126
127 # we extend template_exists? to return true if a template OR a response exists corresponding to the current action.
128 # This is so that a default render will be triggered when no action, but a repsonse does exist.
129 def template_exists_with_response_for?
130 response_exists? || template_exists_without_response_for?
131 end
132
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 133 # if there are responses for the current action, then respond_to them
8ac908ad » ianwhite 2008-09-14 Added specs for stacking re... 134 #
135 # we rescue the case where there were no responses, so that the default_render
136 # action will be performed
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 137 def respond_to_action_responses
37c5ff4c » ianwhite 2008-10-19 Fixed bug where response_fo... 138 if !@respond_to_performed && (responses = self.class.action_responses[action_name]) && responses.any?
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 139 respond_to do |responder|
8ac908ad » ianwhite 2008-09-14 Added specs for stacking re... 140 responses.each {|response| instance_exec(responder, &response) }
141 end rescue Responder::NoResponsesError
570f798d » ian 2007-10-23 response_for: initial release 142 end
143 end
144
9dc94651 » ianwhite 2008-09-13 Final notes and docfixes fo... 145 # this method is invoked if we've got to the end of an action without
146 # performing, which is when we respond_to any repsonses defined
3b1ae5e4 » ianwhite 2008-09-13 API change and rewrite. Va... 147 def default_render_with_response_for
148 respond_to_action_responses
149 default_render_without_response_for unless performed?
570f798d » ian 2007-10-23 response_for: initial release 150 end
8ac908ad » ianwhite 2008-09-14 Added specs for stacking re... 151
37c5ff4c » ianwhite 2008-10-19 Fixed bug where response_fo... 152 def respond_to_with_response_for(*args, &block)
153 @respond_to_performed = true
154 respond_to_without_response_for(*args, &block)
155 end
156
8ac908ad » ianwhite 2008-09-14 Added specs for stacking re... 157 # included into ActionController::MimeResponds::Responder
158 module Responder
159 class NoResponsesError < RuntimeError; end
160
161 def self.included(responder)
162 responder.class_eval do
163 # we make the responder raise an error if there are no responses
164 def respond_with_response_for
165 raise NoResponseError if @responses.empty?
166 respond_without_response_for
167 end
168 alias_method_chain :respond, :response_for
169 end
170 end
171 end
3d94fabc » ianwhite 2008-10-10 Adding stuff for 0.2.1 172
173 module VERSION #:nodoc:
174 MAJOR = 0
175 MINOR = 2
176 TINY = 1
177
178 STRING = [MAJOR, MINOR, TINY].join('.')
179 end
f0b98bf1 » ian 2007-10-18 Initial import of response_for 180 end
181 end