merb 0.3.4 → 0.3.7
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.
- 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
|