merb 0.3.4 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/README +206 -197
  2. data/Rakefile +12 -21
  3. data/bin/merb +1 -1
  4. data/examples/skeleton/Rakefile +6 -20
  5. data/examples/skeleton/dist/app/mailers/layout/application.erb +1 -0
  6. data/examples/skeleton/dist/conf/database.yml +23 -0
  7. data/examples/skeleton/dist/conf/environments/development.rb +1 -0
  8. data/examples/skeleton/dist/conf/environments/production.rb +1 -0
  9. data/examples/skeleton/dist/conf/environments/test.rb +1 -0
  10. data/examples/skeleton/dist/conf/merb.yml +32 -28
  11. data/examples/skeleton/dist/conf/merb_init.rb +16 -13
  12. data/examples/skeleton/dist/conf/router.rb +9 -9
  13. data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +2 -2
  14. data/lib/merb.rb +23 -18
  15. data/lib/merb/caching/fragment_cache.rb +3 -7
  16. data/lib/merb/caching/store/memcache.rb +20 -0
  17. data/lib/merb/core_ext/merb_array.rb +0 -0
  18. data/lib/merb/core_ext/merb_class.rb +44 -4
  19. data/lib/merb/core_ext/merb_enumerable.rb +43 -1
  20. data/lib/merb/core_ext/merb_hash.rb +200 -122
  21. data/lib/merb/core_ext/merb_kernel.rb +2 -0
  22. data/lib/merb/core_ext/merb_module.rb +41 -0
  23. data/lib/merb/core_ext/merb_numeric.rb +57 -5
  24. data/lib/merb/core_ext/merb_object.rb +172 -6
  25. data/lib/merb/generators/merb_app/merb_app.rb +15 -9
  26. data/lib/merb/merb_abstract_controller.rb +193 -0
  27. data/lib/merb/merb_constants.rb +26 -1
  28. data/lib/merb/merb_controller.rb +143 -234
  29. data/lib/merb/merb_dispatcher.rb +28 -20
  30. data/lib/merb/merb_drb_server.rb +2 -3
  31. data/lib/merb/merb_exceptions.rb +194 -49
  32. data/lib/merb/merb_handler.rb +34 -26
  33. data/lib/merb/merb_mail_controller.rb +200 -0
  34. data/lib/merb/merb_mailer.rb +33 -13
  35. data/lib/merb/merb_part_controller.rb +42 -0
  36. data/lib/merb/merb_plugins.rb +293 -0
  37. data/lib/merb/merb_request.rb +6 -4
  38. data/lib/merb/merb_router.rb +99 -65
  39. data/lib/merb/merb_server.rb +65 -21
  40. data/lib/merb/merb_upload_handler.rb +2 -1
  41. data/lib/merb/merb_view_context.rb +36 -15
  42. data/lib/merb/mixins/basic_authentication_mixin.rb +5 -5
  43. data/lib/merb/mixins/controller_mixin.rb +67 -28
  44. data/lib/merb/mixins/erubis_capture_mixin.rb +1 -8
  45. data/lib/merb/mixins/form_control_mixin.rb +280 -42
  46. data/lib/merb/mixins/render_mixin.rb +127 -45
  47. data/lib/merb/mixins/responder_mixin.rb +5 -7
  48. data/lib/merb/mixins/view_context_mixin.rb +260 -94
  49. data/lib/merb/session.rb +23 -0
  50. data/lib/merb/session/merb_ar_session.rb +28 -16
  51. data/lib/merb/session/merb_mem_cache_session.rb +108 -0
  52. data/lib/merb/session/merb_memory_session.rb +65 -20
  53. data/lib/merb/template/erubis.rb +22 -13
  54. data/lib/merb/template/haml.rb +5 -16
  55. data/lib/merb/template/markaby.rb +5 -3
  56. data/lib/merb/template/xml_builder.rb +17 -5
  57. data/lib/merb/test/merb_fake_request.rb +63 -0
  58. data/lib/merb/test/merb_multipart.rb +58 -0
  59. data/lib/tasks/db.rake +2 -0
  60. data/lib/tasks/merb.rake +20 -8
  61. metadata +24 -25
  62. data/examples/skeleton.tar +0 -0
@@ -1,57 +1,103 @@
1
1
  module Merb
2
2
 
3
3
  module RenderMixin
4
-
4
+
5
+ def self.included(base)
6
+ base.class_eval {
7
+ class_inheritable_accessor :_template_root,
8
+ :_layout
9
+
10
+ @@template_extensions = { }
11
+ self._layout = :application
12
+ self._template_root = File.expand_path(MERB_VIEW_ROOT)
13
+ # This method is called by templating-engines to register themselves with
14
+ # a list of extensions that will be looked up on #render of an action.
15
+ def self.register_engine(engine, *extensions)
16
+ [extensions].flatten.uniq.each do |ext|
17
+ @@template_extensions[ext] = engine
18
+ end
19
+ end
20
+
21
+ }
22
+ end
23
+
5
24
  # universal render method. Template handlers are registered
6
25
  # by template extension. So you can use the same render method
7
26
  # for any kind of template that implements an adapter module.
8
- # out of the box Merb support Erubis, Markaby and Builder templates
27
+ # out of the box Merb support Erubis, Haml, Markaby and Builder templates
9
28
  #
10
29
  # Erubis template ext: .herb .jerb .erb
11
30
  # Markaby template ext: .mab
12
31
  # Builder template ext: .rxml .builder .xerb
32
+ # Haml template ext: .haml
13
33
  #
14
34
  # Examples:
15
35
  #
16
- # render
17
- # looks for views/controllername/actionname.* and renders
36
+ # render
37
+ #
38
+ # Looks for views/controllername/actionname.* and renders
18
39
  # the template with the proper engine based on its file extension.
19
40
  #
20
- # render :layout => :none
21
- # renders the current template with no layout. XMl Builder templates
41
+ # render :layout => :none
42
+ #
43
+ # Renders the current template with no layout. XMl Builder templates
22
44
  # are exempt from layout by default.
23
45
  #
24
- # render :action => 'foo'
25
- # renders views/controllername/foo.*
46
+ # render :action => 'foo'
47
+ #
48
+ # Renders views/controllername/foo.*
49
+ #
50
+ # render :nothing => 200
26
51
  #
27
- # render :nothing => 200
28
- # renders nothing with a status of 200
52
+ # Renders nothing with a status of 200
29
53
  #
30
- # render :template => 'shared/message'
31
- # renders views/shared/message
54
+ # render :template => 'shared/message'
32
55
  #
33
- # render :js => "$('some-div').toggle();"
34
- # if the right hand side of :js => is a string then the proper
56
+ # Renders views/shared/message
57
+ #
58
+ # render :js => "$('some-div').toggle();"
59
+ #
60
+ # If the right hand side of :js => is a string then the proper
35
61
  # javascript headers will be set and the string will be returned
36
62
  # verbatim as js.
37
63
  #
38
- # render :js => :spinner
39
- # when the rhs of :js => is a Symbol, it will be used as the
64
+ # render :js => :spinner
65
+ #
66
+ # When the rhs of :js => is a Symbol, it will be used as the
40
67
  # action/template name so: views/controllername/spinner.jerb
41
68
  # will be rendered as javascript
42
69
  #
43
- # render :js => true
44
- # this will just look for the current controller/action tenmplate
70
+ # render :js => true
71
+ #
72
+ # This will just look for the current controller/action template
45
73
  # with the .jerb extension and render it as javascript
46
74
  #
47
- # render :xml => @posts.to_xml
48
- # render :xml => "<foo><bar>Hi!</bar></foo>"
49
- # this will set the appropriate xml headers and render the rhs
75
+ # XML can be rendered with the same options as Javascript.
76
+ #
77
+ # render :xml => @posts.to_xml
78
+ # render :xml => "<foo><bar>Hi!</bar></foo>"
79
+ #
80
+ # This will set the appropriate xml headers and render the rhs
50
81
  # of :xml => as a string. SO you can pass any xml string to this
51
82
  # to be rendered.
52
83
  #
84
+ # render :xml => :hello
85
+ #
86
+ # Renders the hello.xrb template for the current controller.
87
+ #
88
+ # render :xml => true
89
+ # render :xml => true, :action => "buffalo"
90
+ #
91
+ # Renders the buffalo.xerb template for the current controller.
92
+ #
53
93
  def render(opts={}, &blk)
54
- action = opts[:action] || params[:action]
94
+
95
+ action = if kind_of?(Merb::ControllerExceptions::Base)
96
+ self.class.name.snake_case.split('::').last
97
+ else
98
+ opts[:action] || params[:action]
99
+ end
100
+
55
101
  opts[:layout] ||= _layout
56
102
 
57
103
  case
@@ -70,23 +116,32 @@ module Merb
70
116
  when js = opts[:js]
71
117
  headers['Content-Type'] = "text/javascript"
72
118
  opts[:layout] = :none
73
- if String === js
119
+ case js
120
+ when String
74
121
  return js
75
- elsif Symbol === js
122
+ when Symbol
76
123
  template = find_template(:action => js, :ext => 'jerb')
77
- else
124
+ else
78
125
  template = find_template(:action => action, :ext => 'jerb')
79
126
  end
80
127
  when xml = opts[:xml]
81
128
  headers['Content-Type'] = 'application/xml'
82
129
  headers['Encoding'] = 'UTF-8'
83
- return xml
130
+ # TODO This is the same as the js logic above. Can it be refactored?
131
+ case xml
132
+ when String
133
+ return xml
134
+ when Symbol
135
+ template = find_template(:action => xml, :ext => 'rxml,xerb,builder')
136
+ else
137
+ template = find_template(:action => action, :ext => 'rxml,xerb,builder')
138
+ end
84
139
  when template = opts[:template]
85
140
  template = find_template(:template => template)
86
141
  else
87
142
  template = find_template(:action => action)
88
143
  end
89
-
144
+
90
145
  engine = engine_for(template)
91
146
  options = {
92
147
  :file => template,
@@ -101,16 +156,7 @@ module Merb
101
156
  end
102
157
  end
103
158
 
104
- # this returns a ViewContext object populated with all
105
- # the instance variables in your controller. This is used
106
- # as the view context object for the Erubis templates.
107
- def cached_view_context
108
- @_view_context_cache ||= ViewContext.new(self)
109
- end
110
-
111
- def clean_view_context
112
- ViewContext.new(self)
113
- end
159
+
114
160
 
115
161
  # does a render with no layout. Also sets the
116
162
  # content type header to text/javascript. Use
@@ -124,10 +170,14 @@ module Merb
124
170
  # to 200. does send one ' ' space char, this is for
125
171
  # safari and flash uploaders to work.
126
172
  def render_nothing(status=200)
127
- @status = status
173
+ @_status = status
128
174
  return " "
129
175
  end
130
176
 
177
+ def set_status(status)
178
+ @_status = status
179
+ end
180
+
131
181
  def render_no_layout(opts={})
132
182
  render opts.update({:layout => :none})
133
183
  end
@@ -144,14 +194,32 @@ module Merb
144
194
  def partial(template, locals={})
145
195
  render :partial => template, :locals => locals
146
196
  end
197
+
198
+ # +catch_content+ catches the thrown content from another template
199
+ # So when you throw_content(:foo) {...} you can catch_content :foo
200
+ # in another view or the layout.
201
+ def catch_content(name)
202
+ cached_view_context.instance_variable_get("@_#{name}_content")
203
+ end
147
204
 
148
205
  private
149
206
 
207
+ # this returns a ViewContext object populated with all
208
+ # the instance variables in your controller. This is used
209
+ # as the view context object for the Erubis templates.
210
+ def cached_view_context
211
+ @_view_context_cache ||= ViewContext.new(self)
212
+ end
213
+
214
+ def clean_view_context
215
+ ViewContext.new(self)
216
+ end
217
+
150
218
  def wrap_layout(content, opts={})
151
219
  if opts[:layout] != :application
152
220
  layout_choice = find_template(:layout => opts[:layout])
153
221
  else
154
- if name = find_template(:layout => self.class.name.snake_case)
222
+ if name = find_template(:layout => self.class.name.snake_case.split('::').join('/'))
155
223
  layout_choice = name
156
224
  else
157
225
  layout_choice = find_template(:layout => :application)
@@ -172,14 +240,17 @@ module Merb
172
240
  def find_template(opts={})
173
241
  if template = opts[:template]
174
242
  path = _template_root / template
243
+ elsif opts[:action] and kind_of?(Merb::ControllerExceptions::Base)
244
+ path = _template_root / 'exceptions' / opts[:action]
175
245
  elsif action = opts[:action]
176
- path = _template_root / self.class.name.snake_case / action
246
+ segment = self.class.name.snake_case.split('::').join('/')
247
+ path = _template_root / segment / action
177
248
  elsif _layout = opts[:layout]
178
- path = _layout_root / _layout
249
+ path = _template_root / 'layout' / _layout
179
250
  else
180
251
  raise "called find_template without an :action or :layout"
181
- end
182
- extensions = [_template_extensions.keys].flatten.uniq
252
+ end
253
+ extensions = [@@template_extensions.keys].flatten.uniq
183
254
  glob = "#{path}.{#{opts[:ext] || extensions.join(',')}}"
184
255
  Dir[glob].first
185
256
  end
@@ -190,12 +261,23 @@ module Merb
190
261
  template = t.pop
191
262
  path = _template_root / t.join('/') / "_#{template}"
192
263
  else
193
- path = _template_root / self.class.name.snake_case / "_#{template}"
264
+ segment = self.class.name.snake_case.split('::').join('/')
265
+ path = _template_root / segment / "_#{template}"
194
266
  end
195
- extensions = [_template_extensions.keys].flatten.uniq
267
+ extensions = [@@template_extensions.keys].flatten.uniq
196
268
  glob = "#{path}.{#{opts[:ext] || extensions.join(',')}}"
197
269
  Dir[glob].first
198
270
  end
199
271
 
272
+ # lookup the template_extensions for the extname of the filename
273
+ # you pass. Answers with the engine that matches the extension, Template::Erubis
274
+ # is used if none matches.
275
+ def engine_for(file)
276
+ extension = File.extname(file)[1..-1]
277
+ @@template_extensions[extension]
278
+ rescue
279
+ ::Merb::Template::Erubis
280
+ end
281
+
200
282
  end
201
283
  end
@@ -12,10 +12,10 @@ module Merb
12
12
  module ResponderMixin
13
13
 
14
14
  def respond_to(&block)
15
- responder = Rest::Responder.new(@env['HTTP_ACCEPT'], params)
15
+ responder = Rest::Responder.new(request.env['HTTP_ACCEPT'], params)
16
16
  block.call(responder)
17
17
  responder.respond(headers)
18
- @status = responder.status if responder.status
18
+ @_status = responder.status if responder.status
19
19
  responder.body
20
20
  end
21
21
 
@@ -57,9 +57,7 @@ module Merb
57
57
  headers['Content-Type'] = mime_type.super_range
58
58
  @body = @stack[mime_type.to_sym].call
59
59
  else
60
- headers['Content-Type'] = nil
61
- @status = 406
62
- @body = nil
60
+ raise ControllerExceptions::NotAcceptable
63
61
  end
64
62
  end
65
63
 
@@ -84,7 +82,7 @@ module Merb
84
82
  private
85
83
 
86
84
  def negotiate_content
87
- if @params['format']
85
+ if @params[:format]
88
86
  negotiate_by_format
89
87
  elsif (@stack.keys & @accepts.map(&:to_sym)).size > 0
90
88
  negotiate_by_accept_header
@@ -92,7 +90,7 @@ module Merb
92
90
  end
93
91
 
94
92
  def negotiate_by_format
95
- format = @params['format'].to_sym
93
+ format = @params[:format].to_sym
96
94
  if @stack[format]
97
95
  if @accepts.map(&:to_sym).include?(format)
98
96
  @accepts.detect{|a| a.to_sym == format }
@@ -1,39 +1,96 @@
1
1
  module Merb
2
+ # The ViewContextMixin module provides a number of helper methods to views for
3
+ # linking to assets and other pages, dealing with JavaScript, and caching.
2
4
  module ViewContextMixin
3
-
5
+ # :section: Accessing Assets
6
+ # Merb provides views with convenience methods for links images and other assets.
7
+
8
+ # Creates a link for the URL given in +url+ with the text in +name+; HTML options are given in the +opts+
9
+ # hash.
10
+ #
11
+ # ==== Options
12
+ # The +opts+ hash is used to set HTML attributes on the tag.
13
+ #
14
+ # ==== Examples
15
+ # link_to("The Merb home page", "http://www.merbivore.com/")
16
+ # # => <a href="http://www.merbivore.com/">The Merb home page</a>
17
+ #
18
+ # link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'})
19
+ # # => <a href="http://www.ruby-lang.org" class="special" target="blank">The Ruby home page</a>
20
+ #
21
+ # link_to p.title, "/blog/show/#{p.id}"
22
+ # # => <a href="blog/show/13">The Entry Title</a>
23
+ #
4
24
  def link_to(name, url='', opts={})
5
25
  %{<a href="#{url}" #{opts.map{|k,v| "#{k}=\"#{v}\""}.join(' ')}>#{name}</a>}
6
26
  end
7
27
 
8
- # escape text for javascript.
28
+ # Creates an image tag with the +src+ attribute set to the +img+ argument. The path
29
+ # prefix defaults to <tt>/images/</tt>. The path prefix can be overriden by setting a +:path+
30
+ # parameter in the +opts+ hash. The rest of the +opts+ hash sets HTML attributes.
31
+ #
32
+ # ==== Options
33
+ # path:: Sets the path prefix for the image (defaults to +/images/+)
34
+ #
35
+ # All other options in +opts+ set HTML attributes on the tag.
36
+ #
37
+ # ==== Examples
38
+ # image_tag('foo.gif')
39
+ # # => <img src='/images/foo.gif' />
40
+ #
41
+ # image_tag('foo.gif', :class => 'bar')
42
+ # # => <img src='/images/foo.gif' class='bar' />
43
+ #
44
+ # image_tag('foo.gif', :path => '/files/')
45
+ # # => <img src='/files/foo.gif' />
46
+ #
47
+ def image_tag(img, opts={})
48
+ opts[:path] ||= '/images/'
49
+ %{<img src="#{opts.delete(:path) + img}" #{opts.map{|k,v| "#{k}=\"#{v}\""}.join(' ')} />}
50
+ end
51
+
52
+ # :section: JavaScript related functions
53
+ #
54
+
55
+ # Escapes text for use in JavaScript, replacing unsafe strings with their
56
+ # escaped equivalent.
57
+ #
58
+ # ==== Examples
59
+ # escape_js("'Lorem ipsum!' -- Some guy")
60
+ # # => "\\'Lorem ipsum!\\' -- Some guy"
61
+ #
62
+ # escape_js("Please keep text\nlines as skinny\nas possible.")
63
+ # # => "Please keep text\\nlines as skinny\\nas possible."
9
64
  def escape_js(javascript)
10
65
  (javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
11
66
  end
12
67
 
13
- # creates an <a> tag with with an onclick containing
14
- # a js function
15
- # link_to_function('click me', "alert('hi!')")
68
+ # Creates a link tag with the text in +name+ and the <tt>onClick</tt> handler set to a JavaScript
69
+ # string in +function+.
70
+ #
71
+ # ==== Examples
72
+ # link_to_function('Click me', "alert('hi!')")
73
+ # # => <a href="#" onclick="alert('hi!'); return false;">Click me</a>
74
+ #
75
+ # link_to_function('Add to cart', "item_total += 1; alert('Item added!');")
76
+ # # => <a href="#" onclick="item_total += 1; alert('Item added!'); return false;">Add to cart</a>
77
+ #
16
78
  def link_to_function(name, function)
17
79
  %{<a href="#" onclick="#{function}; return false;">#{name}</a>}
18
80
  end
19
81
 
20
- # creates an <img> tag
21
- # defaults to a src path prefix of /images/
22
- #
23
- # image_tag('foo.gif') => <img src='/images/foo.gif' />
24
- # image_tag('foo.gif', :class => 'bar') => <img src='/images/foo.gif' class='bar' />
82
+ # The js method simply calls +to_json+ on an object in +data+; if the object
83
+ # does not implement a +to_json+ method, then it calls +to_json+ on
84
+ # +data.inspect+.
25
85
  #
26
- # you can override the default path by sending a :path parameter in the opts
86
+ # ==== Examples
87
+ # js({'user' => 'Lewis', 'page' => 'home'})
88
+ # # => "{\"user\":\"Lewis\",\"page\":\"home\"}"
27
89
  #
28
- # image_tag('foo.gif', :path => '/files/') => <img src='/files/foo.gif' />
90
+ # my_array = [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
91
+ # js(my_array)
92
+ # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
29
93
  #
30
- def image_tag(img, opts={})
31
- opts[:path] ||= '/images/'
32
- %{<img src="#{opts.delete(:path) + img}" #{opts.map{|k,v| "#{k}=\"#{v}\""}.join(' ')} />}
33
- end
34
-
35
- # calls .to_json on data.
36
- # so it can be faster than escape_js
37
94
  def js(data)
38
95
  if data.respond_to? :to_json
39
96
  data.to_json
@@ -41,117 +98,226 @@ module Merb
41
98
  data.inspect.to_json
42
99
  end
43
100
  end
44
-
45
-
46
- # Helper method to cache a fragment.
47
- # <h1>Article list</h1>
101
+
102
+ # :section: External JavaScript and Stylesheets
48
103
  #
49
- # <% cache(:article_list) do %>
50
- # <ul>
51
- # <% @articles.each do |a| %>
52
- # <li><%= a.title %></li>
53
- # <% end %>
54
- # </ul>
55
- # <% end %>
56
-
57
- def cache(name, &block)
58
- return block.call unless caching_enabled?
59
- buffer = eval("_buf", block.binding)
60
- if fragment = ::Merb::Caching::Fragment.get(name)
61
- buffer.concat(fragment)
62
- else
63
- pos = buffer.length
64
- block.call
65
- ::Merb::Caching::Fragment.put(name, buffer[pos..-1])
66
- end
67
- end
68
-
69
- # Requiring javascripts and stylesheets:
70
- # you can use require_js(:prototype) or require_css(:shinystyles)
71
- # from any view or layout and the scripts will only be included once
72
- # in the head of the final page. In the head of your layout you will
73
- # need to add these two tags:
74
- #
75
- # <%= include_required_js %>
76
- # <%= include_required_css %>
77
- #
78
- # --app/views/layouts/application.rhtml
79
- #
80
- # <html>
81
- # <head>
82
- # <%= include_required_js %>
83
- # <%= include_required_css %>
84
- # </head>
85
- # <body>
86
- # <%= catch_content :layout %>
87
- # </body>
88
- # </html>
89
- #
90
- # --app/views/whatever/index.rhtml
104
+ # You can use require_js(:prototype) or require_css(:shinystyles)
105
+ # from any view or layout, and the scripts will only be included once
106
+ # in the head of the final page. To get this effect, the head of your layout you will
107
+ # need to include a call to include_required_js and include_required_css.
108
+ #
109
+ # ==== Examples
110
+ # # File: app/views/layouts/application.herb
91
111
  #
92
- # <%= partial(:part1) %>
93
- # <%= partial(:part2) %>
112
+ # <html>
113
+ # <head>
114
+ # <%= include_required_js %>
115
+ # <%= include_required_css %>
116
+ # </head>
117
+ # <body>
118
+ # <%= catch_content :layout %>
119
+ # </body>
120
+ # </html>
94
121
  #
95
- # --app/views/whatever/_part1.rhtml
122
+ # # File: app/views/whatever/_part1.herb
96
123
  #
97
- # <% require_js 'this' -%>
98
- # <% require_css 'that', 'another_one' -%>
124
+ # <% require_js 'this' -%>
125
+ # <% require_css 'that', 'another_one' -%>
99
126
  #
100
- # --app/views/whatever/_part2.rhtml
127
+ # # File: app/views/whatever/_part2.herb
101
128
  #
102
- # <% require_js 'this', 'something_else' -%>
103
- # <% require_css 'that' -%>
104
-
129
+ # <% require_js 'this', 'something_else' -%>
130
+ # <% require_css 'that' -%>
131
+ #
132
+ # # File: app/views/whatever/index.herb
133
+ #
134
+ # <%= partial(:part1) %>
135
+ # <%= partial(:part2) %>
136
+ #
137
+ # # Will generate the following in the final page...
138
+ # <html>
139
+ # <head>
140
+ # <script src="/javascripts/this.js" type="text/javascript"></script>
141
+ # <script src="/javascripts/something_else.js" type="text/javascript"></script>
142
+ # <link href="/stylesheets/that.css" media="all" rel="Stylesheet" type="text/css"/>
143
+ # <link href="/stylesheets/another_one.css" media="all" rel="Stylesheet" type="text/css"/>
144
+ # </head>
145
+ # .
146
+ # .
147
+ # .
148
+ # </html>
149
+ #
150
+ # See each method's documentation for more information.
105
151
 
106
- # require_js(:myjs) can be used to require any javascript
107
- # file anywhere in your templates. It will only include the
108
- # javascript tag once in the header
152
+ # The require_js method can be used to require any JavaScript
153
+ # file anywhere in your templates. Regardless of how many times
154
+ # a single script is included with require_js, Merb will only include
155
+ # it once in the header.
156
+ #
157
+ # ==== Examples
158
+ # <% require_js 'jquery' %>
159
+ # # A subsequent call to include_required_js will render...
160
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
161
+ #
162
+ # <% require_js 'jquery', 'effects' %>
163
+ # # A subsequent call to include_required_js will render...
164
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
165
+ # # <script src="/javascripts/effects.js" type="text/javascript"></script>
166
+ #
109
167
  def require_js(*js)
110
168
  @required_js ||= []
111
169
  @required_js |= js
112
170
  end
113
171
 
114
- # require_css(:mystyles) can be used to require any javascript
115
- # file anywhere in your templates. It will only include the
116
- # javascript tag once in the header
172
+ # The require_ccs method can be used to require any CSS
173
+ # file anywhere in your templates. Regardless of how many times
174
+ # a single stylesheet is included with require_css, Merb will only include
175
+ # it once in the header.
176
+ #
177
+ # ==== Examples
178
+ # <% require_css('style') %>
179
+ # # A subsequent call to include_required_css will render...
180
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
181
+ #
182
+ # <% require_css('style', 'ie-specific') %>
183
+ # # A subsequent call to include_required_css will render...
184
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
185
+ # # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
186
+ #
117
187
  def require_css(*css)
118
188
  @required_css ||= []
119
189
  @required_css |= css
120
190
  end
121
191
 
122
- # this goes in the head of your layout if you will be using
123
- # require_js
192
+ # A method used in the layout of an application to create +<script>+ tags to include JavaScripts required in
193
+ # in templates and subtemplates using require_js.
194
+ #
195
+ # ==== Examples
196
+ # # my_action.herb has a call to require_js 'jquery'
197
+ # # File: layout/application.herb
198
+ # include_required_js
199
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
200
+ #
201
+ # # my_action.herb has a call to require_js 'jquery', 'effects', 'validation'
202
+ # # File: layout/application.herb
203
+ # include_required_js
204
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
205
+ # # <script src="/javascripts/effects.js" type="text/javascript"></script>
206
+ # # <script src="/javascripts/validation.js" type="text/javascript"></script>
207
+ #
124
208
  def include_required_js
125
209
  js_include_tag(*@required_js)
126
210
  end
127
211
 
128
- # this goes in the head of your layout if you will be using
129
- # require_css
212
+ # A method used in the layout of an application to create +<link>+ tags for CSS stylesheets required in
213
+ # in templates and subtemplates using require_css.
214
+ #
215
+ # ==== Examples
216
+ # # my_action.herb has a call to require_css 'style'
217
+ # # File: layout/application.herb
218
+ # include_required_css
219
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
220
+ #
221
+ # # my_action.herb has a call to require_js 'style', 'ie-specific'
222
+ # # File: layout/application.herb
223
+ # include_required_css
224
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
225
+ # # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
226
+ #
130
227
  def include_required_css
131
- css_link_tag(*@required_js)
228
+ css_link_tag(*@required_css)
132
229
  end
133
230
 
134
- # js_include_tag(:foo, :bar, :baz) will create a javascript
135
- # include tag for each script in the arguments. It will append
231
+ # The js_include_tag method will create a JavaScript
232
+ # +<include>+ tag for each script named in the arguments, appending
136
233
  # '.js' if it is left out of the call.
234
+ #
235
+ # ==== Examples
236
+ # js_include_tag 'jquery'
237
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
238
+ #
239
+ # js_include_tag 'moofx.js', 'upload'
240
+ # # => <script src="/javascripts/moofx.js" type="text/javascript"></script>
241
+ # # <script src="/javascripts/upload.js" type="text/javascript"></script>
242
+ #
243
+ # js_include_tag :effects
244
+ # # => <script src="/javascripts/effects.js" type="text/javascript"></script>
245
+ #
246
+ # js_include_tag :jquery, :validation
247
+ # # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
248
+ # # <script src="/javascripts/validation.js" type="text/javascript"></script>
249
+ #
137
250
  def js_include_tag(*scripts)
138
251
  return nil if scripts.empty?
139
- scripts.inject('') do |memo,script|
252
+ include_tag = ""
253
+ scripts.each do |script|
140
254
  script = script.to_s
141
- memo << %Q|<script src="/javascripts/#{script=~/\.js$/ ? script : script+'.js' }" type="text/javascript">//</script>\n|
255
+ include_tag << %Q|<script src="/javascripts/#{script=~/\.js$/ ? script : script+'.js' }" type="text/javascript">//</script>\n|
142
256
  end
257
+ include_tag
143
258
  end
144
259
 
145
- # css_include_tag(:foo, :bar, :baz) will create a stylesheet
146
- # link tag for each stylesheet in the arguments. It will append
260
+ # The css_include_tag method will create a CSS stylesheet
261
+ # +<link>+ tag for each stylesheet named in the arguments, appending
147
262
  # '.css' if it is left out of the call.
263
+ #
264
+ # ==== Examples
265
+ # css_include_tag 'style'
266
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
267
+ #
268
+ # css_include_tag 'style.css', 'layout'
269
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
270
+ # # <link href="/stylesheets/layout.css" media="all" rel="Stylesheet" type="text/css"/>
271
+ #
272
+ # css_include_tag :menu
273
+ # # => <link href="/stylesheets/menu.css" media="all" rel="Stylesheet" type="text/css"/>
274
+ #
275
+ # css_include_tag :style, :screen
276
+ # # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
277
+ # # <link href="/stylesheets/screen.css" media="all" rel="Stylesheet" type="text/css"/>
278
+ #
148
279
  def css_include_tag(*scripts)
149
280
  return nil if scripts.empty?
150
- scripts.inject('') do |memo,script|
281
+ include_tag = ""
282
+ scripts.each do |script|
151
283
  script = script.to_s
152
- memo << %Q|<link href="/stylesheets/#{script=~/\.css$/ ? script : script+'.css' }" media="all" rel="Stylesheet" type="text/css"/>\n|
284
+ include_tag << %Q|<link href="/stylesheets/#{script=~/\.css$/ ? script : script+'.css' }" media="all" rel="Stylesheet" type="text/css"/>\n|
153
285
  end
286
+ include_tag
154
287
  end
155
288
 
289
+ # :section: Caching
290
+ # ViewContextMixin provides views with fragment caching facilities.
291
+
292
+ # The cache method is a simple helper method
293
+ # for caching template fragments. The value of the supplied
294
+ # block is stored in the cache and identified by the string
295
+ # in the +name+ argument.
296
+ #
297
+ # ==== Example
298
+ # <h1>Article list</h1>
299
+ #
300
+ # <% cache(:article_list) do %>
301
+ # <ul>
302
+ # <% @articles.each do |a| %>
303
+ # <li><%= a.title %></li>
304
+ # <% end %>
305
+ # </ul>
306
+ # <% end %>
307
+ #
308
+ # See the documentation for Merb::Caching::Fragment for more
309
+ # information.
310
+ #
311
+ def cache(name, &block)
312
+ return block.call unless caching_enabled?
313
+ buffer = eval("_buf", block.binding)
314
+ if fragment = ::Merb::Caching::Fragment.get(name)
315
+ buffer.concat(fragment)
316
+ else
317
+ pos = buffer.length
318
+ block.call
319
+ ::Merb::Caching::Fragment.put(name, buffer[pos..-1])
320
+ end
321
+ end
156
322
  end
157
- end
323
+ end