merb 0.3.4 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README +206 -197
- data/Rakefile +12 -21
- data/bin/merb +1 -1
- data/examples/skeleton/Rakefile +6 -20
- data/examples/skeleton/dist/app/mailers/layout/application.erb +1 -0
- data/examples/skeleton/dist/conf/database.yml +23 -0
- data/examples/skeleton/dist/conf/environments/development.rb +1 -0
- data/examples/skeleton/dist/conf/environments/production.rb +1 -0
- data/examples/skeleton/dist/conf/environments/test.rb +1 -0
- data/examples/skeleton/dist/conf/merb.yml +32 -28
- data/examples/skeleton/dist/conf/merb_init.rb +16 -13
- data/examples/skeleton/dist/conf/router.rb +9 -9
- data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +2 -2
- data/lib/merb.rb +23 -18
- data/lib/merb/caching/fragment_cache.rb +3 -7
- data/lib/merb/caching/store/memcache.rb +20 -0
- data/lib/merb/core_ext/merb_array.rb +0 -0
- data/lib/merb/core_ext/merb_class.rb +44 -4
- data/lib/merb/core_ext/merb_enumerable.rb +43 -1
- data/lib/merb/core_ext/merb_hash.rb +200 -122
- data/lib/merb/core_ext/merb_kernel.rb +2 -0
- data/lib/merb/core_ext/merb_module.rb +41 -0
- data/lib/merb/core_ext/merb_numeric.rb +57 -5
- data/lib/merb/core_ext/merb_object.rb +172 -6
- data/lib/merb/generators/merb_app/merb_app.rb +15 -9
- data/lib/merb/merb_abstract_controller.rb +193 -0
- data/lib/merb/merb_constants.rb +26 -1
- data/lib/merb/merb_controller.rb +143 -234
- data/lib/merb/merb_dispatcher.rb +28 -20
- data/lib/merb/merb_drb_server.rb +2 -3
- data/lib/merb/merb_exceptions.rb +194 -49
- data/lib/merb/merb_handler.rb +34 -26
- data/lib/merb/merb_mail_controller.rb +200 -0
- data/lib/merb/merb_mailer.rb +33 -13
- data/lib/merb/merb_part_controller.rb +42 -0
- data/lib/merb/merb_plugins.rb +293 -0
- data/lib/merb/merb_request.rb +6 -4
- data/lib/merb/merb_router.rb +99 -65
- data/lib/merb/merb_server.rb +65 -21
- data/lib/merb/merb_upload_handler.rb +2 -1
- data/lib/merb/merb_view_context.rb +36 -15
- data/lib/merb/mixins/basic_authentication_mixin.rb +5 -5
- data/lib/merb/mixins/controller_mixin.rb +67 -28
- data/lib/merb/mixins/erubis_capture_mixin.rb +1 -8
- data/lib/merb/mixins/form_control_mixin.rb +280 -42
- data/lib/merb/mixins/render_mixin.rb +127 -45
- data/lib/merb/mixins/responder_mixin.rb +5 -7
- data/lib/merb/mixins/view_context_mixin.rb +260 -94
- data/lib/merb/session.rb +23 -0
- data/lib/merb/session/merb_ar_session.rb +28 -16
- data/lib/merb/session/merb_mem_cache_session.rb +108 -0
- data/lib/merb/session/merb_memory_session.rb +65 -20
- data/lib/merb/template/erubis.rb +22 -13
- data/lib/merb/template/haml.rb +5 -16
- data/lib/merb/template/markaby.rb +5 -3
- data/lib/merb/template/xml_builder.rb +17 -5
- data/lib/merb/test/merb_fake_request.rb +63 -0
- data/lib/merb/test/merb_multipart.rb +58 -0
- data/lib/tasks/db.rake +2 -0
- data/lib/tasks/merb.rake +20 -8
- metadata +24 -25
- 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
|
-
#
|
17
|
-
#
|
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
|
-
#
|
21
|
-
#
|
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
|
-
#
|
25
|
-
#
|
46
|
+
# render :action => 'foo'
|
47
|
+
#
|
48
|
+
# Renders views/controllername/foo.*
|
49
|
+
#
|
50
|
+
# render :nothing => 200
|
26
51
|
#
|
27
|
-
#
|
28
|
-
# renders nothing with a status of 200
|
52
|
+
# Renders nothing with a status of 200
|
29
53
|
#
|
30
|
-
#
|
31
|
-
# renders views/shared/message
|
54
|
+
# render :template => 'shared/message'
|
32
55
|
#
|
33
|
-
#
|
34
|
-
#
|
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
|
-
#
|
39
|
-
#
|
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
|
-
#
|
44
|
-
#
|
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
|
-
#
|
48
|
-
#
|
49
|
-
#
|
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
|
-
|
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
|
-
|
119
|
+
case js
|
120
|
+
when String
|
74
121
|
return js
|
75
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
246
|
+
segment = self.class.name.snake_case.split('::').join('/')
|
247
|
+
path = _template_root / segment / action
|
177
248
|
elsif _layout = opts[:layout]
|
178
|
-
path =
|
249
|
+
path = _template_root / 'layout' / _layout
|
179
250
|
else
|
180
251
|
raise "called find_template without an :action or :layout"
|
181
|
-
end
|
182
|
-
extensions = [
|
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
|
-
|
264
|
+
segment = self.class.name.snake_case.split('::').join('/')
|
265
|
+
path = _template_root / segment / "_#{template}"
|
194
266
|
end
|
195
|
-
extensions = [
|
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(
|
15
|
+
responder = Rest::Responder.new(request.env['HTTP_ACCEPT'], params)
|
16
16
|
block.call(responder)
|
17
17
|
responder.respond(headers)
|
18
|
-
@
|
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
|
-
|
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[
|
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[
|
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
|
-
#
|
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
|
-
#
|
14
|
-
#
|
15
|
-
#
|
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
|
-
#
|
21
|
-
#
|
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
|
-
#
|
86
|
+
# ==== Examples
|
87
|
+
# js({'user' => 'Lewis', 'page' => 'home'})
|
88
|
+
# # => "{\"user\":\"Lewis\",\"page\":\"home\"}"
|
27
89
|
#
|
28
|
-
#
|
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
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
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
|
-
#
|
93
|
-
#
|
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
|
-
#
|
122
|
+
# # File: app/views/whatever/_part1.herb
|
96
123
|
#
|
97
|
-
#
|
98
|
-
#
|
124
|
+
# <% require_js 'this' -%>
|
125
|
+
# <% require_css 'that', 'another_one' -%>
|
99
126
|
#
|
100
|
-
#
|
127
|
+
# # File: app/views/whatever/_part2.herb
|
101
128
|
#
|
102
|
-
#
|
103
|
-
#
|
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
|
107
|
-
# file anywhere in your templates.
|
108
|
-
#
|
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
|
-
#
|
115
|
-
# file anywhere in your templates.
|
116
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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(*@
|
228
|
+
css_link_tag(*@required_css)
|
132
229
|
end
|
133
230
|
|
134
|
-
# js_include_tag
|
135
|
-
# include tag for each script in the arguments
|
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
|
-
|
252
|
+
include_tag = ""
|
253
|
+
scripts.each do |script|
|
140
254
|
script = script.to_s
|
141
|
-
|
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
|
146
|
-
# link tag for each stylesheet in the arguments
|
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
|
-
|
281
|
+
include_tag = ""
|
282
|
+
scripts.each do |script|
|
151
283
|
script = script.to_s
|
152
|
-
|
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
|