halorgium-actionpack 3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +5179 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/lib/abstract_controller.rb +16 -0
  5. data/lib/abstract_controller/base.rb +158 -0
  6. data/lib/abstract_controller/callbacks.rb +113 -0
  7. data/lib/abstract_controller/exceptions.rb +12 -0
  8. data/lib/abstract_controller/helpers.rb +151 -0
  9. data/lib/abstract_controller/layouts.rb +250 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +61 -0
  12. data/lib/abstract_controller/rendering_controller.rb +188 -0
  13. data/lib/action_controller.rb +72 -0
  14. data/lib/action_controller/base.rb +168 -0
  15. data/lib/action_controller/caching.rb +80 -0
  16. data/lib/action_controller/caching/actions.rb +163 -0
  17. data/lib/action_controller/caching/fragments.rb +116 -0
  18. data/lib/action_controller/caching/pages.rb +154 -0
  19. data/lib/action_controller/caching/sweeping.rb +97 -0
  20. data/lib/action_controller/deprecated.rb +4 -0
  21. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  22. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  23. data/lib/action_controller/dispatch/dispatcher.rb +57 -0
  24. data/lib/action_controller/metal.rb +129 -0
  25. data/lib/action_controller/metal/benchmarking.rb +73 -0
  26. data/lib/action_controller/metal/compatibility.rb +145 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +105 -0
  30. data/lib/action_controller/metal/exceptions.rb +55 -0
  31. data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
  32. data/lib/action_controller/metal/flash.rb +162 -0
  33. data/lib/action_controller/metal/head.rb +27 -0
  34. data/lib/action_controller/metal/helpers.rb +115 -0
  35. data/lib/action_controller/metal/hide_actions.rb +47 -0
  36. data/lib/action_controller/metal/http_authentication.rb +312 -0
  37. data/lib/action_controller/metal/layouts.rb +171 -0
  38. data/lib/action_controller/metal/mime_responds.rb +317 -0
  39. data/lib/action_controller/metal/rack_convenience.rb +27 -0
  40. data/lib/action_controller/metal/redirector.rb +22 -0
  41. data/lib/action_controller/metal/render_options.rb +103 -0
  42. data/lib/action_controller/metal/rendering_controller.rb +57 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
  44. data/lib/action_controller/metal/rescuable.rb +13 -0
  45. data/lib/action_controller/metal/responder.rb +200 -0
  46. data/lib/action_controller/metal/session.rb +15 -0
  47. data/lib/action_controller/metal/session_management.rb +45 -0
  48. data/lib/action_controller/metal/streaming.rb +188 -0
  49. data/lib/action_controller/metal/testing.rb +39 -0
  50. data/lib/action_controller/metal/url_for.rb +41 -0
  51. data/lib/action_controller/metal/verification.rb +130 -0
  52. data/lib/action_controller/middleware.rb +38 -0
  53. data/lib/action_controller/notifications.rb +10 -0
  54. data/lib/action_controller/polymorphic_routes.rb +183 -0
  55. data/lib/action_controller/record_identifier.rb +91 -0
  56. data/lib/action_controller/testing/process.rb +111 -0
  57. data/lib/action_controller/testing/test_case.rb +345 -0
  58. data/lib/action_controller/translation.rb +13 -0
  59. data/lib/action_controller/url_rewriter.rb +204 -0
  60. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  61. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  62. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  65. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  66. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  67. data/lib/action_dispatch.rb +70 -0
  68. data/lib/action_dispatch/http/headers.rb +33 -0
  69. data/lib/action_dispatch/http/mime_type.rb +231 -0
  70. data/lib/action_dispatch/http/mime_types.rb +23 -0
  71. data/lib/action_dispatch/http/request.rb +539 -0
  72. data/lib/action_dispatch/http/response.rb +290 -0
  73. data/lib/action_dispatch/http/status_codes.rb +42 -0
  74. data/lib/action_dispatch/http/utils.rb +20 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  76. data/lib/action_dispatch/middleware/params_parser.rb +79 -0
  77. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  78. data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
  79. data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
  80. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  81. data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
  82. data/lib/action_dispatch/middleware/stack.rb +116 -0
  83. data/lib/action_dispatch/middleware/static.rb +44 -0
  84. data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
  90. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
  91. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
  92. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
  93. data/lib/action_dispatch/routing.rb +381 -0
  94. data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
  95. data/lib/action_dispatch/routing/mapper.rb +327 -0
  96. data/lib/action_dispatch/routing/route.rb +49 -0
  97. data/lib/action_dispatch/routing/route_set.rb +497 -0
  98. data/lib/action_dispatch/testing/assertions.rb +8 -0
  99. data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
  100. data/lib/action_dispatch/testing/assertions/model.rb +19 -0
  101. data/lib/action_dispatch/testing/assertions/response.rb +145 -0
  102. data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
  103. data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
  104. data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
  105. data/lib/action_dispatch/testing/integration.rb +504 -0
  106. data/lib/action_dispatch/testing/performance_test.rb +15 -0
  107. data/lib/action_dispatch/testing/test_request.rb +83 -0
  108. data/lib/action_dispatch/testing/test_response.rb +131 -0
  109. data/lib/action_pack.rb +24 -0
  110. data/lib/action_pack/version.rb +9 -0
  111. data/lib/action_view.rb +58 -0
  112. data/lib/action_view/base.rb +308 -0
  113. data/lib/action_view/context.rb +44 -0
  114. data/lib/action_view/erb/util.rb +48 -0
  115. data/lib/action_view/helpers.rb +62 -0
  116. data/lib/action_view/helpers/active_model_helper.rb +306 -0
  117. data/lib/action_view/helpers/ajax_helper.rb +68 -0
  118. data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
  119. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  120. data/lib/action_view/helpers/cache_helper.rb +39 -0
  121. data/lib/action_view/helpers/capture_helper.rb +168 -0
  122. data/lib/action_view/helpers/date_helper.rb +988 -0
  123. data/lib/action_view/helpers/debug_helper.rb +38 -0
  124. data/lib/action_view/helpers/form_helper.rb +1102 -0
  125. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  126. data/lib/action_view/helpers/form_tag_helper.rb +495 -0
  127. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  128. data/lib/action_view/helpers/number_helper.rb +311 -0
  129. data/lib/action_view/helpers/prototype_helper.rb +1309 -0
  130. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  131. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  132. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  133. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  134. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  135. data/lib/action_view/helpers/tag_helper.rb +151 -0
  136. data/lib/action_view/helpers/text_helper.rb +594 -0
  137. data/lib/action_view/helpers/translation_helper.rb +39 -0
  138. data/lib/action_view/helpers/url_helper.rb +639 -0
  139. data/lib/action_view/locale/en.yml +117 -0
  140. data/lib/action_view/paths.rb +80 -0
  141. data/lib/action_view/render/partials.rb +342 -0
  142. data/lib/action_view/render/rendering.rb +134 -0
  143. data/lib/action_view/safe_buffer.rb +28 -0
  144. data/lib/action_view/template/error.rb +101 -0
  145. data/lib/action_view/template/handler.rb +36 -0
  146. data/lib/action_view/template/handlers.rb +52 -0
  147. data/lib/action_view/template/handlers/builder.rb +17 -0
  148. data/lib/action_view/template/handlers/erb.rb +53 -0
  149. data/lib/action_view/template/handlers/rjs.rb +18 -0
  150. data/lib/action_view/template/resolver.rb +165 -0
  151. data/lib/action_view/template/template.rb +131 -0
  152. data/lib/action_view/template/text.rb +38 -0
  153. data/lib/action_view/test_case.rb +163 -0
  154. metadata +236 -0
@@ -0,0 +1,117 @@
1
+ "en":
2
+ number:
3
+ # Used in number_with_delimiter()
4
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
5
+ format:
6
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
7
+ separator: "."
8
+ # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
9
+ delimiter: ","
10
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
11
+ precision: 3
12
+
13
+ # Used in number_to_currency()
14
+ currency:
15
+ format:
16
+ # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
17
+ format: "%u%n"
18
+ unit: "$"
19
+ # These three are to override number.format and are optional
20
+ separator: "."
21
+ delimiter: ","
22
+ precision: 2
23
+
24
+ # Used in number_to_percentage()
25
+ percentage:
26
+ format:
27
+ # These three are to override number.format and are optional
28
+ # separator:
29
+ delimiter: ""
30
+ # precision:
31
+
32
+ # Used in number_to_precision()
33
+ precision:
34
+ format:
35
+ # These three are to override number.format and are optional
36
+ # separator:
37
+ delimiter: ""
38
+ # precision:
39
+
40
+ # Used in number_to_human_size()
41
+ human:
42
+ format:
43
+ # These three are to override number.format and are optional
44
+ # separator:
45
+ delimiter: ""
46
+ precision: 1
47
+ storage_units:
48
+ # Storage units output formatting.
49
+ # %u is the storage unit, %n is the number (default: 2 MB)
50
+ format: "%n %u"
51
+ units:
52
+ byte:
53
+ one: "Byte"
54
+ other: "Bytes"
55
+ kb: "KB"
56
+ mb: "MB"
57
+ gb: "GB"
58
+ tb: "TB"
59
+
60
+ # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
61
+ datetime:
62
+ distance_in_words:
63
+ half_a_minute: "half a minute"
64
+ less_than_x_seconds:
65
+ one: "less than 1 second"
66
+ other: "less than {{count}} seconds"
67
+ x_seconds:
68
+ one: "1 second"
69
+ other: "{{count}} seconds"
70
+ less_than_x_minutes:
71
+ one: "less than a minute"
72
+ other: "less than {{count}} minutes"
73
+ x_minutes:
74
+ one: "1 minute"
75
+ other: "{{count}} minutes"
76
+ about_x_hours:
77
+ one: "about 1 hour"
78
+ other: "about {{count}} hours"
79
+ x_days:
80
+ one: "1 day"
81
+ other: "{{count}} days"
82
+ about_x_months:
83
+ one: "about 1 month"
84
+ other: "about {{count}} months"
85
+ x_months:
86
+ one: "1 month"
87
+ other: "{{count}} months"
88
+ about_x_years:
89
+ one: "about 1 year"
90
+ other: "about {{count}} years"
91
+ over_x_years:
92
+ one: "over 1 year"
93
+ other: "over {{count}} years"
94
+ almost_x_years:
95
+ one: "almost 1 year"
96
+ other: "almost {{count}} years"
97
+ prompts:
98
+ year: "Year"
99
+ month: "Month"
100
+ day: "Day"
101
+ hour: "Hour"
102
+ minute: "Minute"
103
+ second: "Seconds"
104
+
105
+ activemodel:
106
+ errors:
107
+ template:
108
+ header:
109
+ one: "1 error prohibited this {{model}} from being saved"
110
+ other: "{{count}} errors prohibited this {{model}} from being saved"
111
+ # The variable :count is also available
112
+ body: "There were problems with the following fields:"
113
+
114
+ support:
115
+ select:
116
+ # default value for :prompt => true in FormOptionsHelper
117
+ prompt: "Please select"
@@ -0,0 +1,80 @@
1
+ module ActionView #:nodoc:
2
+ class PathSet < Array #:nodoc:
3
+ def self.type_cast(obj, cache = nil)
4
+ # TODO: Clean this up
5
+ if obj.is_a?(String)
6
+ if cache.nil?
7
+ cache = !defined?(Rails) || Rails.application.config.cache_classes
8
+ end
9
+ FileSystemResolverWithFallback.new(obj, :cache => cache)
10
+ else
11
+ obj
12
+ end
13
+ end
14
+
15
+ def initialize(*args)
16
+ super(*args).map! { |obj| self.class.type_cast(obj) }
17
+ end
18
+
19
+ def <<(obj)
20
+ super(self.class.type_cast(obj))
21
+ end
22
+
23
+ def concat(array)
24
+ super(array.map! { |obj| self.class.type_cast(obj) })
25
+ end
26
+
27
+ def insert(index, obj)
28
+ super(index, self.class.type_cast(obj))
29
+ end
30
+
31
+ def push(*objs)
32
+ super(*objs.map { |obj| self.class.type_cast(obj) })
33
+ end
34
+
35
+ def unshift(*objs)
36
+ super(*objs.map { |obj| self.class.type_cast(obj) })
37
+ end
38
+
39
+ def find(path, details = {}, prefix = nil, partial = false)
40
+ template_path = path
41
+
42
+ each do |load_path|
43
+ if template = load_path.find(template_path, details, prefix, partial)
44
+ return template
45
+ end
46
+ end
47
+
48
+ raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}")
49
+ end
50
+
51
+ def exists?(path, extension = nil, prefix = nil, partial = false)
52
+ template_path = path.sub(/^\//, '')
53
+
54
+ each do |load_path|
55
+ return true if template = load_path.find(template_path, extension, prefix, partial)
56
+ end
57
+ false
58
+ end
59
+
60
+ def find_template(original_template_path, format = nil, html_fallback = true)
61
+ return original_template_path if original_template_path.respond_to?(:render)
62
+ template_path = original_template_path.sub(/^\//, '')
63
+
64
+ each do |load_path|
65
+ if template = load_path.find(template_path, format)
66
+ return template
67
+ # Try to find html version if the format is javascript
68
+ elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
69
+ return template
70
+ elsif format == :js && html_fallback && template = load_path["#{template_path}.html"]
71
+ return template
72
+ end
73
+ end
74
+
75
+ return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
76
+
77
+ raise MissingTemplate.new(self, original_template_path, format)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,342 @@
1
+ module ActionView
2
+ # There's also a convenience method for rendering sub templates within the current controller that depends on a
3
+ # single object (we call this kind of sub templates for partials). It relies on the fact that partials should
4
+ # follow the naming convention of being prefixed with an underscore -- as to separate them from regular
5
+ # templates that could be rendered on their own.
6
+ #
7
+ # In a template for Advertiser#account:
8
+ #
9
+ # <%= render :partial => "account" %>
10
+ #
11
+ # This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable
12
+ # +account+ to the template for display.
13
+ #
14
+ # In another template for Advertiser#buy, we could have:
15
+ #
16
+ # <%= render :partial => "account", :locals => { :account => @buyer } %>
17
+ #
18
+ # <% for ad in @advertisements %>
19
+ # <%= render :partial => "ad", :locals => { :ad => ad } %>
20
+ # <% end %>
21
+ #
22
+ # This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then
23
+ # render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
24
+ #
25
+ # == Rendering a collection of partials
26
+ #
27
+ # The example of partial use describes a familiar pattern where a template needs to iterate over an array and
28
+ # render a sub template for each of the elements. This pattern has been implemented as a single method that
29
+ # accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
30
+ # example in "Using partials" can be rewritten with a single line:
31
+ #
32
+ # <%= render :partial => "ad", :collection => @advertisements %>
33
+ #
34
+ # This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An
35
+ # iteration counter will automatically be made available to the template with a name of the form
36
+ # +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
37
+ #
38
+ # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also
39
+ # just keep domain objects, like Active Records, in there.
40
+ #
41
+ # == Rendering shared partials
42
+ #
43
+ # Two controllers can share a set of partials and render them like this:
44
+ #
45
+ # <%= render :partial => "advertisement/ad", :locals => { :ad => @advertisement } %>
46
+ #
47
+ # This will render the partial "advertisement/_ad.erb" regardless of which controller this is being called from.
48
+ #
49
+ # == Rendering objects with the RecordIdentifier
50
+ #
51
+ # Instead of explicitly naming the location of a partial, you can also let the RecordIdentifier do the work if
52
+ # you're following its conventions for RecordIdentifier#partial_path. Examples:
53
+ #
54
+ # # @account is an Account instance, so it uses the RecordIdentifier to replace
55
+ # # <%= render :partial => "accounts/account", :locals => { :account => @buyer } %>
56
+ # <%= render :partial => @account %>
57
+ #
58
+ # # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
59
+ # # <%= render :partial => "posts/post", :collection => @posts %>
60
+ # <%= render :partial => @posts %>
61
+ #
62
+ # == Rendering the default case
63
+ #
64
+ # If you're not going to be using any of the options like collections or layouts, you can also use the short-hand
65
+ # defaults of render to render partials. Examples:
66
+ #
67
+ # # Instead of <%= render :partial => "account" %>
68
+ # <%= render "account" %>
69
+ #
70
+ # # Instead of <%= render :partial => "account", :locals => { :account => @buyer } %>
71
+ # <%= render "account", :account => @buyer %>
72
+ #
73
+ # # @account is an Account instance, so it uses the RecordIdentifier to replace
74
+ # # <%= render :partial => "accounts/account", :locals => { :account => @account } %>
75
+ # <%= render(@account) %>
76
+ #
77
+ # # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
78
+ # # <%= render :partial => "posts/post", :collection => @posts %>
79
+ # <%= render(@posts) %>
80
+ #
81
+ # == Rendering partials with layouts
82
+ #
83
+ # Partials can have their own layouts applied to them. These layouts are different than the ones that are
84
+ # specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
85
+ # of users:
86
+ #
87
+ # <%# app/views/users/index.html.erb &>
88
+ # Here's the administrator:
89
+ # <%= render :partial => "user", :layout => "administrator", :locals => { :user => administrator } %>
90
+ #
91
+ # Here's the editor:
92
+ # <%= render :partial => "user", :layout => "editor", :locals => { :user => editor } %>
93
+ #
94
+ # <%# app/views/users/_user.html.erb &>
95
+ # Name: <%= user.name %>
96
+ #
97
+ # <%# app/views/users/_administrator.html.erb &>
98
+ # <div id="administrator">
99
+ # Budget: $<%= user.budget %>
100
+ # <%= yield %>
101
+ # </div>
102
+ #
103
+ # <%# app/views/users/_editor.html.erb &>
104
+ # <div id="editor">
105
+ # Deadline: <%= user.deadline %>
106
+ # <%= yield %>
107
+ # </div>
108
+ #
109
+ # ...this will return:
110
+ #
111
+ # Here's the administrator:
112
+ # <div id="administrator">
113
+ # Budget: $<%= user.budget %>
114
+ # Name: <%= user.name %>
115
+ # </div>
116
+ #
117
+ # Here's the editor:
118
+ # <div id="editor">
119
+ # Deadline: <%= user.deadline %>
120
+ # Name: <%= user.name %>
121
+ # </div>
122
+ #
123
+ # You can also apply a layout to a block within any template:
124
+ #
125
+ # <%# app/views/users/_chief.html.erb &>
126
+ # <% render(:layout => "administrator", :locals => { :user => chief }) do %>
127
+ # Title: <%= chief.title %>
128
+ # <% end %>
129
+ #
130
+ # ...this will return:
131
+ #
132
+ # <div id="administrator">
133
+ # Budget: $<%= user.budget %>
134
+ # Title: <%= chief.name %>
135
+ # </div>
136
+ #
137
+ # As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
138
+ #
139
+ # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
140
+ # an array to layout and treat it as an enumerable.
141
+ #
142
+ # <%# app/views/users/_user.html.erb &>
143
+ # <div class="user">
144
+ # Budget: $<%= user.budget %>
145
+ # <%= yield user %>
146
+ # </div>
147
+ #
148
+ # <%# app/views/users/index.html.erb &>
149
+ # <% render :layout => @users do |user| %>
150
+ # Title: <%= user.title %>
151
+ # <% end %>
152
+ #
153
+ # This will render the layout for each user and yield to the block, passing the user, each time.
154
+ #
155
+ # You can also yield multiple times in one layout and use block arguments to differentiate the sections.
156
+ #
157
+ # <%# app/views/users/_user.html.erb &>
158
+ # <div class="user">
159
+ # <%= yield user, :header %>
160
+ # Budget: $<%= user.budget %>
161
+ # <%= yield user, :footer %>
162
+ # </div>
163
+ #
164
+ # <%# app/views/users/index.html.erb &>
165
+ # <% render :layout => @users do |user, section| %>
166
+ # <%- case section when :header -%>
167
+ # Title: <%= user.title %>
168
+ # <%- when :footer -%>
169
+ # Deadline: <%= user.deadline %>
170
+ # <%- end -%>
171
+ # <% end %>
172
+ module Partials
173
+ extend ActiveSupport::Concern
174
+
175
+ class PartialRenderer
176
+ PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
177
+ TEMPLATES = Hash.new {|h,k| h[k] = {} }
178
+
179
+ attr_reader :template
180
+
181
+ def initialize(view_context, options, block)
182
+ @view = view_context
183
+ @partial_names = PARTIAL_NAMES[@view.controller.class]
184
+
185
+ key = Thread.current[:format_locale_key]
186
+ @templates = TEMPLATES[key] if key
187
+
188
+ setup(options, block)
189
+ end
190
+
191
+ def setup(options, block)
192
+ partial = options[:partial]
193
+
194
+ @options = options
195
+ @locals = options[:locals] || {}
196
+ @block = block
197
+
198
+ if String === partial
199
+ @object = options[:object]
200
+ @path = partial
201
+ else
202
+ @object = partial
203
+ @path = partial_path(partial)
204
+ end
205
+ end
206
+
207
+ def render
208
+ if @collection = collection
209
+ render_collection
210
+ else
211
+ @template = template = find_template
212
+ render_template(template, @object || @locals[template.variable_name])
213
+ end
214
+ end
215
+
216
+ def render_collection
217
+ @template = template = find_template
218
+
219
+ return nil if @collection.blank?
220
+
221
+ if @options.key?(:spacer_template)
222
+ spacer = find_template(@options[:spacer_template]).render(@view, @locals)
223
+ end
224
+
225
+ result = template ? collection_with_template(template) : collection_without_template
226
+ result.join(spacer).html_safe!
227
+ end
228
+
229
+ def collection_with_template(template)
230
+ options = @options
231
+
232
+ segments, locals, as = [], @locals, options[:as] || template.variable_name
233
+
234
+ counter_name = template.counter_name
235
+ locals[counter_name] = -1
236
+
237
+ @collection.each do |object|
238
+ locals[counter_name] += 1
239
+ locals[as] = object
240
+
241
+ segments << template.render(@view, locals)
242
+ end
243
+
244
+ @template = template
245
+ segments
246
+ end
247
+
248
+ def collection_without_template
249
+ options = @options
250
+
251
+ segments, locals, as = [], @locals, options[:as]
252
+ index, template = -1, nil
253
+
254
+ @collection.each do |object|
255
+ template = find_template(partial_path(object))
256
+ locals[template.counter_name] = (index += 1)
257
+ locals[template.variable_name] = object
258
+
259
+ segments << template.render(@view, locals)
260
+ end
261
+
262
+ @template = template
263
+ segments
264
+ end
265
+
266
+ def render_template(template, object = @object)
267
+ options, locals, view = @options, @locals, @view
268
+ locals[options[:as] || template.variable_name] = object
269
+
270
+ content = template.render(view, locals) do |*name|
271
+ @view._layout_for(*name, &@block)
272
+ end
273
+
274
+ if @block || !options[:layout]
275
+ content
276
+ else
277
+ find_template(options[:layout]).render(@view, @locals) { content }
278
+ end
279
+ end
280
+
281
+ private
282
+ def collection
283
+ if @object.respond_to?(:to_ary)
284
+ @object
285
+ elsif @options.key?(:collection)
286
+ @options[:collection] || []
287
+ end
288
+ end
289
+
290
+ def find_template(path = @path)
291
+ unless @templates
292
+ path && _find_template(path)
293
+ else
294
+ path && @templates[path] ||= _find_template(path)
295
+ end
296
+ end
297
+
298
+ def _find_template(path)
299
+ if controller = @view.controller
300
+ prefix = controller.controller_path unless path.include?(?/)
301
+ end
302
+
303
+ @view.find(path, {:formats => @view.formats}, prefix, true)
304
+ end
305
+
306
+ def partial_path(object = @object)
307
+ @partial_names[object.class] ||= begin
308
+ return nil unless object.respond_to?(:to_model)
309
+
310
+ object.to_model.class.model_name.partial_path.dup.tap do |partial|
311
+ path = @view.controller_path
312
+ partial.insert(0, "#{File.dirname(path)}/") if path.include?(?/)
313
+ end
314
+ end
315
+ end
316
+ end
317
+
318
+ def render_partial(options)
319
+ _evaluate_assigns_and_ivars
320
+
321
+ details = options[:_details]
322
+
323
+ # Is this needed
324
+ self.formats = details[:formats] if details
325
+ renderer = PartialRenderer.new(self, options, nil)
326
+ text = renderer.render
327
+ options[:_template] = renderer.template
328
+ text
329
+ end
330
+
331
+ def _render_partial(options, &block) #:nodoc:
332
+ if @renderer
333
+ @renderer.setup(options, block)
334
+ else
335
+ @renderer = PartialRenderer.new(self, options, block)
336
+ end
337
+
338
+ @renderer.render
339
+ end
340
+
341
+ end
342
+ end