merb 0.3.7 → 0.4.0

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 (173) hide show
  1. data/README +25 -26
  2. data/Rakefile +48 -36
  3. data/app_generators/merb/USAGE +5 -0
  4. data/app_generators/merb/merb_generator.rb +107 -0
  5. data/app_generators/merb/templates/Rakefile +99 -0
  6. data/{examples/skeleton/dist → app_generators/merb/templates}/app/controllers/application.rb +1 -1
  7. data/app_generators/merb/templates/app/controllers/exceptions.rb +13 -0
  8. data/{examples/skeleton/dist → app_generators/merb/templates}/app/helpers/global_helper.rb +0 -0
  9. data/{examples/skeleton/dist/app/mailers → app_generators/merb/templates/app/mailers/views}/layout/application.erb +0 -0
  10. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +207 -0
  11. data/app_generators/merb/templates/app/views/exceptions/not_acceptable.html.erb +38 -0
  12. data/app_generators/merb/templates/app/views/exceptions/not_found.html.erb +40 -0
  13. data/app_generators/merb/templates/app/views/layout/application.html.erb +11 -0
  14. data/app_generators/merb/templates/config/boot.rb +11 -0
  15. data/app_generators/merb/templates/config/dependencies.rb +41 -0
  16. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/development.rb +0 -0
  17. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/production.rb +0 -0
  18. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/test.rb +0 -0
  19. data/app_generators/merb/templates/config/merb.yml +64 -0
  20. data/app_generators/merb/templates/config/merb_init.rb +16 -0
  21. data/app_generators/merb/templates/config/plugins.yml +1 -0
  22. data/app_generators/merb/templates/config/router.rb +32 -0
  23. data/{lib/merb/core_ext/merb_array.rb → app_generators/merb/templates/config/upload.conf} +0 -0
  24. data/app_generators/merb/templates/public/images/merb.jpg +0 -0
  25. data/app_generators/merb/templates/public/merb.fcgi +6 -0
  26. data/app_generators/merb/templates/public/stylesheets/master.css +119 -0
  27. data/app_generators/merb/templates/script/destroy +28 -0
  28. data/app_generators/merb/templates/script/generate +28 -0
  29. data/{examples/skeleton → app_generators/merb/templates}/script/stop_merb +0 -0
  30. data/app_generators/merb/templates/script/win_script.cmd +1 -0
  31. data/app_generators/merb/templates/spec/spec.opts +6 -0
  32. data/app_generators/merb/templates/spec/spec_helper.rb +10 -0
  33. data/app_generators/merb/templates/test/test_helper.rb +13 -0
  34. data/app_generators/merb_plugin/USAGE +5 -0
  35. data/app_generators/merb_plugin/merb_plugin_generator.rb +64 -0
  36. data/app_generators/merb_plugin/templates/LICENSE +20 -0
  37. data/app_generators/merb_plugin/templates/README +4 -0
  38. data/app_generators/merb_plugin/templates/Rakefile +35 -0
  39. data/app_generators/merb_plugin/templates/TODO +5 -0
  40. data/app_generators/merb_plugin/templates/merbtasks.rb +6 -0
  41. data/app_generators/merb_plugin/templates/sampleplugin.rb +10 -0
  42. data/app_generators/merb_plugin/templates/sampleplugin_spec.rb +7 -0
  43. data/app_generators/merb_plugin/templates/spec_helper.rb +2 -0
  44. data/bin/merb +1 -1
  45. data/lib/autotest/discover.rb +3 -0
  46. data/lib/autotest/merb_rspec.rb +79 -0
  47. data/lib/merb.rb +72 -93
  48. data/lib/merb/{merb_abstract_controller.rb → abstract_controller.rb} +28 -5
  49. data/lib/merb/caching/action_cache.rb +65 -29
  50. data/lib/merb/caching/fragment_cache.rb +9 -4
  51. data/lib/merb/caching/store/file_cache.rb +22 -14
  52. data/lib/merb/caching/store/memory_cache.rb +26 -8
  53. data/lib/merb/{merb_constants.rb → constants.rb} +9 -7
  54. data/lib/merb/controller.rb +178 -0
  55. data/lib/merb/core_ext.rb +13 -11
  56. data/lib/merb/core_ext/array.rb +0 -0
  57. data/lib/merb/core_ext/{merb_class.rb → class.rb} +0 -0
  58. data/lib/merb/core_ext/{merb_enumerable.rb → enumerable.rb} +0 -0
  59. data/lib/merb/core_ext/get_args.rb +52 -0
  60. data/lib/merb/core_ext/{merb_hash.rb → hash.rb} +40 -11
  61. data/lib/merb/core_ext/{merb_inflections.rb → inflections.rb} +0 -0
  62. data/lib/merb/core_ext/{merb_inflector.rb → inflector.rb} +1 -1
  63. data/lib/merb/core_ext/{merb_kernel.rb → kernel.rb} +56 -3
  64. data/lib/merb/core_ext/mash.rb +88 -0
  65. data/lib/merb/core_ext/{merb_module.rb → module.rb} +0 -0
  66. data/lib/merb/core_ext/{merb_numeric.rb → numeric.rb} +0 -0
  67. data/lib/merb/core_ext/{merb_object.rb → object.rb} +10 -47
  68. data/lib/merb/core_ext/string.rb +56 -0
  69. data/lib/merb/core_ext/{merb_symbol.rb → symbol.rb} +0 -0
  70. data/lib/merb/dispatcher.rb +109 -0
  71. data/lib/merb/{merb_drb_server.rb → drb_server.rb} +0 -0
  72. data/lib/merb/erubis_ext.rb +10 -0
  73. data/lib/merb/exceptions.rb +173 -0
  74. data/lib/merb/generators/merb_app/merb_app.rb +5 -25
  75. data/lib/merb/generators/merb_generator_helpers.rb +317 -0
  76. data/lib/merb/generators/merb_plugin.rb +19 -0
  77. data/lib/merb/logger.rb +65 -0
  78. data/lib/merb/{merb_mail_controller.rb → mail_controller.rb} +102 -49
  79. data/lib/merb/{merb_mailer.rb → mailer.rb} +31 -27
  80. data/lib/merb/mixins/{basic_authentication_mixin.rb → basic_authentication.rb} +3 -3
  81. data/lib/merb/mixins/{controller_mixin.rb → controller.rb} +131 -112
  82. data/lib/merb/mixins/{erubis_capture_mixin.rb → erubis_capture.rb} +12 -21
  83. data/lib/merb/mixins/{form_control_mixin.rb → form_control.rb} +6 -12
  84. data/lib/merb/mixins/render.rb +401 -0
  85. data/lib/merb/mixins/responder.rb +378 -0
  86. data/lib/merb/mixins/{view_context_mixin.rb → view_context.rb} +65 -10
  87. data/lib/merb/mixins/web_controller.rb +29 -0
  88. data/lib/merb/{merb_handler.rb → mongrel_handler.rb} +59 -38
  89. data/lib/merb/part_controller.rb +19 -0
  90. data/lib/merb/plugins.rb +16 -0
  91. data/lib/merb/rack_adapter.rb +37 -0
  92. data/lib/merb/request.rb +421 -0
  93. data/lib/merb/router.rb +576 -0
  94. data/lib/merb/{merb_server.rb → server.rb} +275 -71
  95. data/lib/merb/session.rb +10 -10
  96. data/lib/merb/session/cookie_store.rb +125 -0
  97. data/lib/merb/session/{merb_mem_cache_session.rb → mem_cache_session.rb} +22 -9
  98. data/lib/merb/session/{merb_memory_session.rb → memory_session.rb} +15 -11
  99. data/lib/merb/template.rb +35 -8
  100. data/lib/merb/template/erubis.rb +16 -10
  101. data/lib/merb/template/haml.rb +33 -20
  102. data/lib/merb/template/markaby.rb +16 -14
  103. data/lib/merb/template/xml_builder.rb +8 -4
  104. data/lib/merb/test/{merb_fake_request.rb → fake_request.rb} +11 -5
  105. data/lib/merb/test/helper.rb +31 -0
  106. data/lib/merb/test/hpricot.rb +136 -0
  107. data/lib/merb/test/{merb_multipart.rb → multipart.rb} +1 -1
  108. data/lib/merb/test/rspec.rb +93 -0
  109. data/lib/merb/{merb_upload_handler.rb → upload_handler.rb} +5 -6
  110. data/lib/merb/{merb_upload_progress.rb → upload_progress.rb} +1 -1
  111. data/lib/merb/{merb_view_context.rb → view_context.rb} +27 -42
  112. data/lib/{merb_tasks.rb → tasks.rb} +0 -0
  113. data/lib/tasks/merb.rake +21 -11
  114. data/merb_default_generators/model/USAGE +0 -0
  115. data/merb_default_generators/model/model_generator.rb +16 -0
  116. data/merb_default_generators/model/templates/new_model_template.erb +5 -0
  117. data/merb_default_generators/resource_controller/USAGE +0 -0
  118. data/merb_default_generators/resource_controller/resource_controller_generator.rb +26 -0
  119. data/merb_default_generators/resource_controller/templates/controller.rb +30 -0
  120. data/merb_default_generators/resource_controller/templates/edit.html.erb +1 -0
  121. data/merb_default_generators/resource_controller/templates/helper.rb +5 -0
  122. data/merb_default_generators/resource_controller/templates/index.html.erb +1 -0
  123. data/merb_default_generators/resource_controller/templates/new.html.erb +1 -0
  124. data/merb_default_generators/resource_controller/templates/show.html.erb +1 -0
  125. data/merb_generators/controller/USAGE +5 -0
  126. data/merb_generators/controller/controller_generator.rb +16 -0
  127. data/merb_generators/controller/templates/controller.rb +8 -0
  128. data/merb_generators/controller/templates/helper.rb +5 -0
  129. data/merb_generators/controller/templates/index.html.erb +3 -0
  130. data/merb_generators/resource/USAGE +0 -0
  131. data/merb_generators/resource/resource_generator.rb +60 -0
  132. data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +67 -0
  133. data/rspec_generators/merb_controller_test/templates/controller_spec.rb +8 -0
  134. data/rspec_generators/merb_controller_test/templates/edit_spec.rb +12 -0
  135. data/rspec_generators/merb_controller_test/templates/helper_spec.rb +5 -0
  136. data/rspec_generators/merb_controller_test/templates/index_spec.rb +12 -0
  137. data/rspec_generators/merb_controller_test/templates/new_spec.rb +12 -0
  138. data/rspec_generators/merb_controller_test/templates/show_spec.rb +5 -0
  139. data/rspec_generators/merb_model_test/merb_model_test_generator.rb +26 -0
  140. data/rspec_generators/merb_model_test/templates/model_spec_template.erb +7 -0
  141. data/script/destroy +14 -0
  142. data/script/generate +14 -0
  143. data/test_unit_generators/merb_controller_test/merb_controller_test_generator.rb +53 -0
  144. data/test_unit_generators/merb_controller_test/templates/functional_test.rb +17 -0
  145. data/test_unit_generators/merb_controller_test/templates/helper_test.rb +9 -0
  146. data/test_unit_generators/merb_model_test/merb_model_test_generator.rb +29 -0
  147. data/test_unit_generators/merb_model_test/templates/model_test_unit_template.erb +9 -0
  148. metadata +172 -94
  149. data/examples/README_EXAMPLES +0 -10
  150. data/examples/skeleton/Rakefile +0 -68
  151. data/examples/skeleton/dist/app/views/layout/application.herb +0 -12
  152. data/examples/skeleton/dist/conf/database.yml +0 -23
  153. data/examples/skeleton/dist/conf/merb.yml +0 -57
  154. data/examples/skeleton/dist/conf/merb_init.rb +0 -24
  155. data/examples/skeleton/dist/conf/router.rb +0 -22
  156. data/examples/skeleton/dist/conf/upload.conf +0 -5
  157. data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +0 -14
  158. data/examples/skeleton/script/new_migration +0 -21
  159. data/lib/merb/core_ext/merb_string.rb +0 -18
  160. data/lib/merb/merb_controller.rb +0 -206
  161. data/lib/merb/merb_dispatcher.rb +0 -87
  162. data/lib/merb/merb_exceptions.rb +0 -319
  163. data/lib/merb/merb_part_controller.rb +0 -42
  164. data/lib/merb/merb_plugins.rb +0 -293
  165. data/lib/merb/merb_request.rb +0 -165
  166. data/lib/merb/merb_router.rb +0 -309
  167. data/lib/merb/merb_yaml_store.rb +0 -31
  168. data/lib/merb/mixins/render_mixin.rb +0 -283
  169. data/lib/merb/mixins/responder_mixin.rb +0 -159
  170. data/lib/merb/session/merb_ar_session.rb +0 -131
  171. data/lib/merb/vendor/paginator/README.txt +0 -84
  172. data/lib/merb/vendor/paginator/paginator.rb +0 -124
  173. data/lib/tasks/db.rake +0 -55
@@ -1,6 +1,14 @@
1
1
  module Merb
2
+
3
+
2
4
 
3
5
  module ErubisCaptureMixin
6
+
7
+ # Provides direct acccess to the buffer for this view context
8
+ def _buffer( the_binding )
9
+ @_buffer ||= eval( "_buf", the_binding )
10
+ end
11
+
4
12
  # Capture allows you to extract a part of the template into an
5
13
  # instance variable. You can use this instance variable anywhere
6
14
  # in your templates and even in your layout.
@@ -13,7 +21,7 @@ module Merb
13
21
  def capture(*args, &block)
14
22
  # execute the block
15
23
  begin
16
- buffer = eval("_buf", block.binding)
24
+ buffer = _buffer( block.binding )
17
25
  rescue
18
26
  buffer = nil
19
27
  end
@@ -24,23 +32,6 @@ module Merb
24
32
  capture_erb_with_buffer(buffer, *args, &block)
25
33
  end
26
34
  end
27
-
28
- # Calling throw_content stores the block of markup for later use.
29
- # Subsequently, you can make calls to it by name with <tt>catch_content</tt>
30
- # in another template or in the layout.
31
- #
32
- # Example:
33
- #
34
- # <% throw_content :header do %>
35
- # alert('hello world')
36
- # <% end %>
37
- #
38
- # You can use catch_content :header anywhere in your templates.
39
- #
40
- # <%= catch_content :header %>
41
- def throw_content(name, content = nil, &block)
42
- eval "@_#{name}_content = (@_#{name}_content || '') + capture(&block)"
43
- end
44
35
 
45
36
  private
46
37
  def capture_block(*args, &block)
@@ -48,7 +39,7 @@ module Merb
48
39
  end
49
40
 
50
41
  def capture_erb(*args, &block)
51
- buffer = eval("_buf", block.binding)
42
+ buffer = _buffer
52
43
  capture_erb_with_buffer(buffer, *args, &block)
53
44
  end
54
45
 
@@ -66,11 +57,11 @@ module Merb
66
57
  end
67
58
 
68
59
  def erb_content_for(name, &block)
69
- eval "@_#{name}_content = (@_#{name}_content|| '') + capture_erb(&block)"
60
+ controller.thrown_content[name] << capture_erb( &block )
70
61
  end
71
62
 
72
63
  def block_content_for(name, &block)
73
- eval "@_#{name}_content = (@_#{name}_content|| '') + capture_block(&block)"
64
+ controller.thrown_content[name] << capture_block( &block )
74
65
  end
75
66
  end
76
67
 
@@ -156,7 +156,6 @@ module Merb
156
156
  # </optgroup>
157
157
  # </select>
158
158
  #
159
-
160
159
 
161
160
  def control_for( obj, meth, type, opts = {} )
162
161
  instance = obj
@@ -217,11 +216,11 @@ module Merb
217
216
  def textarea(o)
218
217
  tag = ''
219
218
  tag << label_for_object( o )
220
- tag << %{<textarea #{options_as_attributes( o.html ) }>#{o.value}</textarea>}
219
+ tag << %{<textarea #{o.html.to_xml_attributes }>#{o.value}</textarea>}
221
220
  end
222
221
 
223
222
  def date(o)
224
- o.value ||= Date.today
223
+ o.value = Date.today unless (o.value.is_a? Time or o.value.is_a? Date or o.value.is_a? DateTime)
225
224
  selects = []
226
225
  selects << label_for_object( o )
227
226
  selects << date_day(o.temp(:value => o.value.day))
@@ -231,7 +230,7 @@ module Merb
231
230
  end
232
231
 
233
232
  def time(o)
234
- o.value ||= Time.now
233
+ o.value = Time.now unless (o.value.is_a? Time or o.value.is_a? DateTime)
235
234
  selects = []
236
235
  selects << label_for_object( o )
237
236
  selects << date_day(o.temp(:value => o.value.day))
@@ -257,14 +256,14 @@ module Merb
257
256
  end
258
257
  out = ""
259
258
  out << label_for_object( o )
260
- out << %{<select #{options_as_attributes( o.html )}>}
259
+ out << %{<select #{o.html.to_xml_attributes }>}
261
260
  out << %{#{options_for_select( o.obj, o.meth, options )}}
262
261
  out << %{</select>}
263
262
  end
264
263
 
265
264
  # Creates an input tag with the given +option+ hash as xml/html attributes
266
265
  def input_tag( options )
267
- %{<input #{options_as_attributes( options ) }/>}
266
+ %{<input #{options.to_xml_attributes }/>}
268
267
  end
269
268
 
270
269
  # Creates an select tag that is not nesiscarily bound to an objects value
@@ -286,12 +285,7 @@ module Merb
286
285
  # Creates a label from the openstruct created in control_for
287
286
  def label_for_object( o )
288
287
  o.label.nil? ? "" : %{<label for="#{o.html[:id]}">#{o.label}</label>}
289
- end
290
-
291
- # Converts a hash to use as attributes in an xml/html tag
292
- def options_as_attributes( options )
293
- options ? options.map{ |k,v| "#{k}=\"#{v}\""}.join( ' ' ) : nil
294
- end
288
+ end
295
289
 
296
290
  # The gateway to creating options for a select box
297
291
  def options_for_select( obj, value_method, options )
@@ -0,0 +1,401 @@
1
+ module Merb
2
+
3
+ module RenderMixin
4
+ @@cached_templates = {}
5
+ include Merb::ControllerExceptions
6
+
7
+ def self.included(base)
8
+ base.class_eval {
9
+ class_inheritable_accessor :_template_root,
10
+ :_layout
11
+
12
+ self._layout = :application
13
+ self._template_root = File.expand_path(MERB_VIEW_ROOT)
14
+
15
+ attr_accessor :template
16
+ }
17
+ end
18
+
19
+ # Universal render method. Template handlers are registered
20
+ # by template extension. So you can use the same render method
21
+ # for any kind of template that implements an adapter module.
22
+ #
23
+ # Out of the box Merb supports Erubis. In addition, Haml, Markaby
24
+ # and Builder templates are built in, but you must activate them in
25
+ # merb_init.rb by listing the name of the template engine you
26
+ # want to use:
27
+ #
28
+ # Merb::Template::Haml
29
+ #
30
+ # In addition, you can identify the type of output with an
31
+ # extension in the middle of the filename. Erubis is capable of
32
+ # rendering any kind of text output, not just HTML.
33
+ # This is the recommended usage.
34
+ #
35
+ # index.html.erb update.js.erb feed.xml.erb
36
+ #
37
+ # Examples:
38
+ #
39
+ # render
40
+ #
41
+ # Looks for views/controllername/actionname.* and renders
42
+ # the template with the proper engine based on its file extension.
43
+ #
44
+ # render :layout => :none
45
+ #
46
+ # Renders the current template with no layout. XMl Builder templates
47
+ # are exempt from layout by default.
48
+ #
49
+ # render :action => 'foo'
50
+ #
51
+ # Renders views/controllername/foo.*
52
+ #
53
+ # render :nothing => 200
54
+ #
55
+ # Renders nothing with a status of 200
56
+ #
57
+ # render :template => 'shared/message'
58
+ #
59
+ # Renders views/shared/message
60
+ #
61
+ # render :js => "$('some-div').toggle();"
62
+ #
63
+ # If the right hand side of :js => is a string then the proper
64
+ # javascript headers will be set and the string will be returned
65
+ # verbatim as js.
66
+ #
67
+ # render :js => :spinner
68
+ #
69
+ # When the rhs of :js => is a Symbol, it will be used as the
70
+ # action/template name so: views/controllername/spinner.js.erb
71
+ # will be rendered as javascript
72
+ #
73
+ # render :js => true
74
+ #
75
+ # This will just look for the current controller/action template
76
+ # with the .js.erb extension and render it as javascript
77
+ #
78
+ # XML can be rendered with the same options as Javascript, but it
79
+ # also accepts the :template option. This allows you to use any
80
+ # template engine to render XML.
81
+ #
82
+ # render :xml => @posts.to_xml
83
+ # render :xml => "<foo><bar>Hi!</bar></foo>"
84
+ #
85
+ # This will set the appropriate xml headers and render the rhs
86
+ # of :xml => as a string. SO you can pass any xml string to this
87
+ # to be rendered.
88
+ #
89
+ # render :xml => :hello
90
+ #
91
+ # Renders the hello.xrb template for the current controller.
92
+ #
93
+ # render :xml => true
94
+ # render :xml => true, :action => "buffalo"
95
+ #
96
+ # Renders the buffalo.xml.builder or buffalo.xerb template for the current controller.
97
+ #
98
+ # render :xml=>true, :template => 'foo/bar'
99
+ #
100
+ # Renders the the foo/bar template. This is not limited to
101
+ # the default rxml, xerb, or builder templates, but could
102
+ # just as easy be HAML.
103
+ #
104
+ # Render also supports passing in an object
105
+ # ===Example
106
+ #
107
+ # class People < Application
108
+ # provides :xml
109
+ #
110
+ # def index
111
+ # @people = User.all
112
+ # render @people
113
+ # end
114
+ # end
115
+ #
116
+ # This will first check to see if a index.xml.* template extists, if not
117
+ # it will call @people.to_xml (as defined in the add_mime_type method) on the passed
118
+ # in object if such a method exists for the current content_type
119
+ #
120
+ # When using multiple calls to render in one action, the context of the render is cached for performance reasons
121
+ # That is, all instance variables are loaded into the view_context object only on the first call and then this is re-used.
122
+ # What this means is that in the case where you may want to render then set some more instance variables and then call render again
123
+ # you will want to use a clean context object. To do this
124
+ #
125
+ # render :clean_context => true
126
+ #
127
+ # This will ensure that all instance variable are up to date in your views.
128
+ #
129
+ def render(*args,&blk)
130
+ opts = Hash === args.last ? args.pop : {}
131
+
132
+ action = opts[:action] || params[:action]
133
+ opts[:layout] ||= _layout
134
+
135
+ choose_template_format(Merb.available_mime_types, opts)
136
+
137
+ # Handles the case where render is called with an object
138
+ if obj = args.first
139
+ # Check for a template
140
+ unless find_template({:action => action}.merge(opts))
141
+ fmt = content_type
142
+ if transform_method = Merb.mime_transform_method(fmt)
143
+ set_response_headers fmt
144
+ return obj.send(transform_method)
145
+ end
146
+ end
147
+ end
148
+
149
+ case
150
+ when status = opts[:nothing]
151
+ return render_nothing(status)
152
+
153
+ when partial = opts[:partial]
154
+ opts[:format] ||= :html
155
+ template = find_partial(partial, opts)
156
+ opts[:layout] = :none
157
+
158
+ # Add an instance variable that can be used to create the locals in the
159
+ # partial
160
+ if opts[:locals]
161
+ @_merb_partial_locals = opts[:locals]
162
+ end
163
+ opts[:clean_context] = true
164
+
165
+ when opts[:inline]
166
+ text = opts.delete(:inline)
167
+ return render_inline(text, opts)
168
+ else
169
+ set_response_headers @_template_format
170
+
171
+ case @_format_value
172
+ when String
173
+ return @_format_value
174
+ when Symbol
175
+ if !Merb.available_mime_types.keys.include?(@_format_value) # render :js => "Some js value"
176
+ template = find_template(:action => @_format_value)
177
+ else
178
+ if opts[@_format_value] == @_format_value # An edge case that lives in the specs
179
+ # says that a render :js => :js should be catered for
180
+ template = find_template(:action => @_format_value)
181
+ else
182
+ # when called from within an action as plain render within a respond_to block
183
+ template = find_template(opts.merge( :action => action ))
184
+ end
185
+ end
186
+ else
187
+ if template = opts[:template]
188
+ # render :template => "this_template"
189
+ template = find_template( :template => template)
190
+ else
191
+ # a plain action render
192
+ # def index; render; end
193
+ template = find_template(:action => action)
194
+ end
195
+ end
196
+ end
197
+
198
+ unless template
199
+ raise TemplateNotFound, "No template matched at #{unmatched}"
200
+ end
201
+ self.template ||= File.basename(template)
202
+
203
+ engine = Template.engine_for(template)
204
+ options = {
205
+ :file => template,
206
+ :view_context => (opts[:clean_context] ? clean_view_context(engine) : cached_view_context(engine)),
207
+ :opts => opts
208
+ }
209
+ content = engine.transform(options)
210
+ if engine.exempt_from_layout? || opts[:layout] == :none || [:js].include?(@_template_format)
211
+ content
212
+ else
213
+ wrap_layout(content, opts)
214
+ end
215
+ end
216
+
217
+ def set_response_headers(tmpl_fmt)
218
+ if self.respond_to?(:headers)
219
+ # Set the headers
220
+ headers['Content-Type'] = Merb.available_mime_types[tmpl_fmt].first
221
+
222
+ # set any additinal headers that may be associated with the current mime type
223
+ Merb.response_headers[tmpl_fmt].each do |key,value|
224
+ headers[key.to_s] = value
225
+ end if Merb.response_headers[tmpl_fmt]
226
+
227
+ end
228
+ end
229
+
230
+ def render_inline(text, opts)
231
+ # Does not yet support format selection in the wrap_layout
232
+ # Needs to get the template format need a spec for this
233
+ # should be
234
+ choose_template_format(Merb.available_mime_types, opts)
235
+
236
+ engine = Template.engine_for_extension(opts[:extension] || 'erb')
237
+ options = {
238
+ :text => text,
239
+ :view_context => (opts[:clean_context] ? clean_view_context(engine) : cached_view_context(engine)),
240
+ :opts => opts
241
+ }
242
+ content = engine.transform(options)
243
+ if engine.exempt_from_layout? || opts[:layout] == :none
244
+ content
245
+ else
246
+ wrap_layout(content, opts)
247
+ end
248
+ end
249
+
250
+ # does a render with no layout. Also sets the
251
+ # content type header to text/javascript. Use
252
+ # this when you want to render a template with
253
+ # .jerb extension.
254
+ def render_js(template=nil)
255
+ render :js => true, :action => (template || params[:action])
256
+ end
257
+
258
+ # renders nothing but sets the status, defaults
259
+ # to 200. does send one ' ' space char, this is for
260
+ # safari and flash uploaders to work.
261
+ def render_nothing(status=200)
262
+ @_status = status
263
+ return " "
264
+ end
265
+
266
+ def set_status(status)
267
+ @_status = status
268
+ end
269
+
270
+ def render_no_layout(opts={})
271
+ render opts.update({:layout => :none})
272
+ end
273
+
274
+ # This is merb's partial render method. You name your
275
+ # partials _partialname.format.* , and then call it like
276
+ # partial(:partialname). If there is no '/' character
277
+ # in the argument passed in it will look for the partial
278
+ # in the view directory that corresponds to the current
279
+ # controller name. If you pass a string with a path in it
280
+ # you can render partials in other view directories. So
281
+ # if you create a views/shared directory then you can call
282
+ # partials that live there like partial('shared/foo')
283
+ def partial(template, locals={})
284
+ options = {:partial => template, :locals => locals}
285
+ options.merge!(:format => @_template_format) if @_template_format
286
+ render options
287
+ end
288
+
289
+ # +catch_content+ catches the thrown content from another template
290
+ # So when you throw_content(:foo) {...} you can catch_content :foo
291
+ # in another view or the layout.
292
+ def catch_content(name)
293
+ thrown_content[name]
294
+ end
295
+
296
+ private
297
+
298
+ # this returns a ViewContext object populated with all
299
+ # the instance variables in your controller. This is used
300
+ # as the view context object for the Erubis templates.
301
+ def cached_view_context(engine=nil)
302
+ @_view_context_cache ||= clean_view_context(engine)
303
+ end
304
+
305
+ def clean_view_context(engine=nil)
306
+ if engine.nil?
307
+ ::Merb::ViewContext.new(self)
308
+ else
309
+ engine.view_context_klass.new(self)
310
+ end
311
+ end
312
+
313
+ def wrap_layout(content, opts={})
314
+ @_template_format ||= choose_template_format(Merb.available_mime_types, opts)
315
+
316
+ if opts[:layout] != :application
317
+ layout_choice = find_template(:layout => opts[:layout])
318
+ else
319
+ if name = find_template(:layout => self.class.name.snake_case.split('::').join('/'))
320
+ layout_choice = name
321
+ else
322
+ previous_glob = unmatched
323
+ layout_choice = find_template(:layout => :application)
324
+ end
325
+ end
326
+ unless layout_choice
327
+ raise LayoutNotFound, "No layout matched #{unmatched}#{" or #{previous_glob}" if previous_glob}"
328
+ end
329
+
330
+ thrown_content[:layout] = content
331
+ engine = Template.engine_for(layout_choice)
332
+ options = {
333
+ :file => layout_choice,
334
+ :view_context => cached_view_context,
335
+ :opts => opts
336
+ }
337
+ engine.transform(options)
338
+ end
339
+
340
+ # OPTIMIZE : combine find_template and find_partial ?
341
+ def find_template(opts={})
342
+ if template = opts[:template]
343
+ path = _template_root / template
344
+ elsif action = opts[:action]
345
+ segment = self.class.name.snake_case.split('::').join('/')
346
+ path = _template_root / segment / action
347
+ elsif _layout = opts[:layout]
348
+ path = _template_root / 'layout' / _layout
349
+ else
350
+ raise "called find_template without an :action or :layout"
351
+ end
352
+ glob_template(path, opts)
353
+ end
354
+
355
+ def find_partial(template, opts={})
356
+ if template =~ /\//
357
+ t = template.split('/')
358
+ template = t.pop
359
+ path = _template_root / t.join('/') / "_#{template}"
360
+ else
361
+ segment = self.class.name.snake_case.split('::').join('/')
362
+ path = _template_root / segment / "_#{template}"
363
+ end
364
+ glob_template(path, opts)
365
+ end
366
+
367
+ # This method will return a matching template at the specified path, first using the
368
+ # template_name.format.engine convention and if that fails, it falls back to the old
369
+ # style extensions (herb, jerb etc)
370
+ def glob_template(path, opts = {})
371
+ extensions = Template::EXTENSIONS.keys
372
+ glob = "#{path}.#{@_template_format}.{#{opts[:ext] || extensions.join(",")}}"
373
+ Dir[glob].first || (@_merb_unmatched = glob; nil)
374
+ end
375
+
376
+ # Chooses the format of the template based on the params hash or the explicit
377
+ # request of the developer.
378
+ def choose_template_format(types, opts)
379
+ opts[:format] ||= content_type
380
+ @_template_format = [(opts.keys & types.keys)].flatten.first # Check for render :js => etc
381
+ @_template_format ||= opts[:format] || :html
382
+ @_format_value = opts[@_template_format] || opts[:format] # get the value of the option if something
383
+ # like :js was used
384
+
385
+ # need to change things to symbols so as not to stuff up part controllers
386
+ if @_template_format.to_s == @_format_value.to_s
387
+ @_template_format = @_template_format.to_sym
388
+ @_format_value = @_format_value.to_sym
389
+ end
390
+
391
+ @_template_format
392
+ end
393
+
394
+ # For the benefit of error handlers, returns the most recent glob
395
+ # pattern which didn't find a file in the filesystem
396
+ def unmatched
397
+ @_merb_unmatched
398
+ end
399
+
400
+ end
401
+ end