roda 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +70 -0
- data/README.rdoc +261 -302
- data/Rakefile +1 -1
- data/doc/release_notes/1.2.0.txt +406 -0
- data/lib/roda.rb +206 -124
- data/lib/roda/plugins/all_verbs.rb +11 -10
- data/lib/roda/plugins/assets.rb +5 -5
- data/lib/roda/plugins/backtracking_array.rb +12 -5
- data/lib/roda/plugins/caching.rb +10 -8
- data/lib/roda/plugins/class_level_routing.rb +94 -0
- data/lib/roda/plugins/content_for.rb +6 -0
- data/lib/roda/plugins/default_headers.rb +4 -11
- data/lib/roda/plugins/delay_build.rb +42 -0
- data/lib/roda/plugins/delegate.rb +64 -0
- data/lib/roda/plugins/drop_body.rb +33 -0
- data/lib/roda/plugins/empty_root.rb +48 -0
- data/lib/roda/plugins/environments.rb +68 -0
- data/lib/roda/plugins/error_email.rb +1 -2
- data/lib/roda/plugins/error_handler.rb +1 -1
- data/lib/roda/plugins/halt.rb +7 -5
- data/lib/roda/plugins/head.rb +4 -2
- data/lib/roda/plugins/header_matchers.rb +17 -9
- data/lib/roda/plugins/hooks.rb +16 -32
- data/lib/roda/plugins/json.rb +4 -10
- data/lib/roda/plugins/mailer.rb +233 -0
- data/lib/roda/plugins/match_affix.rb +48 -0
- data/lib/roda/plugins/multi_route.rb +9 -11
- data/lib/roda/plugins/multi_run.rb +81 -0
- data/lib/roda/plugins/named_templates.rb +93 -0
- data/lib/roda/plugins/not_allowed.rb +43 -48
- data/lib/roda/plugins/path.rb +63 -2
- data/lib/roda/plugins/render.rb +79 -48
- data/lib/roda/plugins/render_each.rb +6 -0
- data/lib/roda/plugins/sinatra_helpers.rb +523 -0
- data/lib/roda/plugins/slash_path_empty.rb +25 -0
- data/lib/roda/plugins/static_path_info.rb +64 -0
- data/lib/roda/plugins/streaming.rb +1 -1
- data/lib/roda/plugins/view_subdirs.rb +12 -8
- data/lib/roda/version.rb +1 -1
- data/spec/integration_spec.rb +33 -0
- data/spec/plugin/backtracking_array_spec.rb +24 -18
- data/spec/plugin/class_level_routing_spec.rb +138 -0
- data/spec/plugin/delay_build_spec.rb +23 -0
- data/spec/plugin/delegate_spec.rb +20 -0
- data/spec/plugin/drop_body_spec.rb +20 -0
- data/spec/plugin/empty_root_spec.rb +14 -0
- data/spec/plugin/environments_spec.rb +31 -0
- data/spec/plugin/h_spec.rb +1 -3
- data/spec/plugin/header_matchers_spec.rb +14 -0
- data/spec/plugin/hooks_spec.rb +3 -5
- data/spec/plugin/mailer_spec.rb +191 -0
- data/spec/plugin/match_affix_spec.rb +22 -0
- data/spec/plugin/multi_run_spec.rb +31 -0
- data/spec/plugin/named_templates_spec.rb +65 -0
- data/spec/plugin/path_spec.rb +66 -2
- data/spec/plugin/render_spec.rb +46 -1
- data/spec/plugin/sinatra_helpers_spec.rb +534 -0
- data/spec/plugin/slash_path_empty_spec.rb +22 -0
- data/spec/plugin/static_path_info_spec.rb +50 -0
- data/spec/request_spec.rb +23 -0
- data/spec/response_spec.rb +12 -1
- metadata +48 -6
@@ -0,0 +1,48 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The match_affix plugin allows changing the default prefix and suffix used for
|
4
|
+
# match patterns. Roda's default behavior for a match pattern like <tt>"albums"</tt>
|
5
|
+
# is to use the pattern <tt>/\A\/(?:albums)(?=\/|\z)/</tt>. This prefixes the pattern
|
6
|
+
# with +/+ and suffixes it with <tt>(?=\/|\z)</tt>. With the match_affix plugin, you
|
7
|
+
# can change the prefix and suffix to use. So if you want to be explicit and require
|
8
|
+
# a leading +/+ in patterns, you can set the prefix to <tt>""</tt>. If you want to
|
9
|
+
# consume a trailing slash instead of leaving it, you can set the suffix to <tt>(\/|\z)</tt>.
|
10
|
+
#
|
11
|
+
# You set the prefix and suffix to use by passing arguments when loading the plugin:
|
12
|
+
#
|
13
|
+
# plugin :match_affix, ""
|
14
|
+
#
|
15
|
+
# will load the plugin and use an empty prefix.
|
16
|
+
#
|
17
|
+
# plugin :match_affix, "", /(\/|\z)/
|
18
|
+
#
|
19
|
+
# will use an empty prefix and change the suffix to consume a trailing slash.
|
20
|
+
#
|
21
|
+
# plugin :match_affix, nil, /(\/|\z)/
|
22
|
+
#
|
23
|
+
# will not modify the prefix and will change the suffix to consume a trailing slash.
|
24
|
+
module MatchAffix
|
25
|
+
PREFIX = "/".freeze
|
26
|
+
SUFFIX = "(?=\/|\z)".freeze
|
27
|
+
|
28
|
+
# Set the default prefix and suffix to use in match patterns, if a non-nil value
|
29
|
+
# is given.
|
30
|
+
def self.configure(app, prefix, suffix=nil)
|
31
|
+
app.opts[:match_prefix] = prefix if prefix
|
32
|
+
app.opts[:match_suffix] = suffix if suffix
|
33
|
+
end
|
34
|
+
|
35
|
+
module RequestClassMethods
|
36
|
+
private
|
37
|
+
|
38
|
+
# Use the match prefix and suffix provided when loading the plugin, or fallback
|
39
|
+
# to Roda's default prefix/suffix if one was not provided.
|
40
|
+
def consume_pattern(pattern)
|
41
|
+
/\A#{roda_class.opts[:match_prefix] || PREFIX}(?:#{pattern})#{roda_class.opts[:match_suffix] || SUFFIX}/
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
register_plugin(:match_affix, MatchAffix)
|
47
|
+
end
|
48
|
+
end
|
@@ -125,29 +125,27 @@ class Roda
|
|
125
125
|
module MultiRoute
|
126
126
|
# Initialize storage for the named routes.
|
127
127
|
def self.configure(app)
|
128
|
-
app.
|
129
|
-
|
130
|
-
app::RodaRequest.instance_variable_set(:@namespaced_route_regexps, {})
|
131
|
-
end
|
128
|
+
app.opts[:namespaced_routes] ||= {}
|
129
|
+
app::RodaRequest.instance_variable_set(:@namespaced_route_regexps, {})
|
132
130
|
end
|
133
131
|
|
134
132
|
module ClassMethods
|
135
133
|
# Copy the named routes into the subclass when inheriting.
|
136
134
|
def inherited(subclass)
|
137
135
|
super
|
138
|
-
nsr = subclass.
|
139
|
-
|
136
|
+
nsr = subclass.opts[:namespaced_routes]
|
137
|
+
opts[:namespaced_routes].each{|k, v| nsr[k] = v.dup}
|
140
138
|
subclass::RodaRequest.instance_variable_set(:@namespaced_route_regexps, {})
|
141
139
|
end
|
142
140
|
|
143
141
|
# The names for the currently stored named routes
|
144
142
|
def named_routes(namespace=nil)
|
145
|
-
|
143
|
+
opts[:namespaced_routes][namespace].keys
|
146
144
|
end
|
147
145
|
|
148
146
|
# Return the named route with the given name.
|
149
147
|
def named_route(name, namespace=nil)
|
150
|
-
|
148
|
+
opts[:namespaced_routes][namespace][name]
|
151
149
|
end
|
152
150
|
|
153
151
|
# If the given route has a name, treat it as a named route and
|
@@ -155,8 +153,8 @@ class Roda
|
|
155
153
|
# call super.
|
156
154
|
def route(name=nil, namespace=nil, &block)
|
157
155
|
if name
|
158
|
-
|
159
|
-
|
156
|
+
opts[:namespaced_routes][namespace] ||= {}
|
157
|
+
opts[:namespaced_routes][namespace][name] = block
|
160
158
|
self::RodaRequest.clear_named_route_regexp!(namespace)
|
161
159
|
else
|
162
160
|
super(&block)
|
@@ -199,7 +197,7 @@ class Roda
|
|
199
197
|
|
200
198
|
# Dispatch to the named route with the given name.
|
201
199
|
def route(name, namespace=nil)
|
202
|
-
scope.instance_exec(self, &
|
200
|
+
scope.instance_exec(self, &roda_class.named_route(name, namespace))
|
203
201
|
end
|
204
202
|
end
|
205
203
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The multi_run plugin provides the ability to easily dispatch to other
|
4
|
+
# rack applications based on the request path prefix.
|
5
|
+
# First, load the plugin:
|
6
|
+
#
|
7
|
+
# class App < Roda
|
8
|
+
# plugin :multi_run
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# Then, other rack applications can register with the multi_run plugin:
|
12
|
+
#
|
13
|
+
# App.run "ra", PlainRackApp
|
14
|
+
# App.run "ro", OtherRodaApp
|
15
|
+
# App.run "si", SinatraApp
|
16
|
+
#
|
17
|
+
# Inside your route block, you can call r.multi_run to dispatch to all
|
18
|
+
# three rack applications based on the prefix:
|
19
|
+
#
|
20
|
+
# App.route do |r|
|
21
|
+
# r.multi_run
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# This will dispatch routes starting with +/ra+ to +PlainRackApp+, routes
|
25
|
+
# starting with +/ro+ to +OtherRodaApp+, and routes starting with +/si+ to
|
26
|
+
# SinatraApp.
|
27
|
+
#
|
28
|
+
# The multi_run plugin is similar to the multi_route plugin, with the difference
|
29
|
+
# being the multi_route plugin keeps all routing subtrees in the same Roda app/class,
|
30
|
+
# while multi_run dispatches to other rack apps. If you want to isolate your routing
|
31
|
+
# subtrees, multi_run is a better approach, but it does not let you set instance
|
32
|
+
# variables in the main Roda app and have those instance variables usable in
|
33
|
+
# the routing subtrees.
|
34
|
+
module MultiRun
|
35
|
+
# Initialize the storage for the dispatched applications
|
36
|
+
def self.configure(app)
|
37
|
+
app.instance_eval do
|
38
|
+
@multi_run_apps ||= {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
# Hash storing rack applications to dispatch to, keyed by the prefix
|
44
|
+
# for the application.
|
45
|
+
attr_reader :multi_run_apps
|
46
|
+
|
47
|
+
# Add a rack application to dispatch to for the given prefix when
|
48
|
+
# r.multi_run is called.
|
49
|
+
def run(prefix, app)
|
50
|
+
@multi_run_apps[prefix.to_s] = app
|
51
|
+
self::RodaRequest.refresh_multi_run_regexp!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module RequestClassMethods
|
56
|
+
# Refresh the multi_run_regexp, using the stored route prefixes,
|
57
|
+
# preferring longer routes before shorter routes.
|
58
|
+
def refresh_multi_run_regexp!
|
59
|
+
@multi_run_regexp = /(#{Regexp.union(roda_class.multi_run_apps.keys.sort.reverse)})/
|
60
|
+
end
|
61
|
+
|
62
|
+
# Refresh the multi_run_regexp if it hasn't been loaded yet.
|
63
|
+
def multi_run_regexp
|
64
|
+
@multi_run_regexp || refresh_multi_run_regexp!
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module RequestMethods
|
69
|
+
# If one of the stored route prefixes match the current request,
|
70
|
+
# dispatch the request to the stored rack application.
|
71
|
+
def multi_run
|
72
|
+
on self.class.multi_run_regexp do |prefix|
|
73
|
+
run scope.class.multi_run_apps[prefix]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
register_plugin(:multi_run, MultiRun)
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The named_templates plugin allows you to specify templates by name,
|
4
|
+
# providing the template code to use for a given name:
|
5
|
+
#
|
6
|
+
# plugin :named_templates
|
7
|
+
#
|
8
|
+
# template :layout do
|
9
|
+
# "<html><body><%= yield %></body></html>"
|
10
|
+
# end
|
11
|
+
# template :index do
|
12
|
+
# "<p>Hello <%= @user %>!</p>"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# route do |r|
|
16
|
+
# @user = 'You'
|
17
|
+
# render(:index)
|
18
|
+
# end
|
19
|
+
# # => "<html><body><p>Hello You!</p></body></html>"
|
20
|
+
#
|
21
|
+
# You can provide options for the template, for example to change the
|
22
|
+
# engine that the template uses:
|
23
|
+
#
|
24
|
+
# template :index, :engine=>:str do
|
25
|
+
# "<p>Hello #{@user}!</p>"
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# The block you use is reevaluted on every call, allowing you to easily
|
29
|
+
# include additional setup logic:
|
30
|
+
#
|
31
|
+
# template :index do
|
32
|
+
# greeting = ['hello', 'hi', 'howdy'].sample
|
33
|
+
# @user.downcase!
|
34
|
+
# "<p>#{greating} <%= @user %>!</p>"
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# This plugin also works with the view_subdirs plugin, as long as you
|
38
|
+
# prefix the template name with the view subdirectory:
|
39
|
+
#
|
40
|
+
# template "main/index" do
|
41
|
+
# "<html><body><%= yield %></body></html>"
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# route do |r|
|
45
|
+
# set_view_subdir("main")
|
46
|
+
# @user = 'You'
|
47
|
+
# render(:index)
|
48
|
+
# end
|
49
|
+
module NamedTemplates
|
50
|
+
# Depend on the render plugin
|
51
|
+
def self.load_dependencies(app)
|
52
|
+
app.plugin :render
|
53
|
+
end
|
54
|
+
|
55
|
+
# Initialize the storage for named templates.
|
56
|
+
def self.configure(app)
|
57
|
+
app.opts[:named_templates] ||= {}
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
# Store a new template block and options for the given template name.
|
62
|
+
def template(name, options=nil, &block)
|
63
|
+
opts[:named_templates][name.to_s] = [options, block]
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module InstanceMethods
|
69
|
+
private
|
70
|
+
|
71
|
+
# If a template name is given and it matches a named template, call
|
72
|
+
# the named template block to get the inline template to use.
|
73
|
+
def find_template(options)
|
74
|
+
if options[:template] && (template_opts, block = opts[:named_templates][template_name(options)]; block)
|
75
|
+
if template_opts
|
76
|
+
options = template_opts.merge(options)
|
77
|
+
else
|
78
|
+
options = options.dup
|
79
|
+
end
|
80
|
+
|
81
|
+
options[:inline] = instance_exec(&block)
|
82
|
+
|
83
|
+
super(options)
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
register_plugin(:named_templates, NamedTemplates)
|
92
|
+
end
|
93
|
+
end
|
@@ -59,48 +59,15 @@ class Roda
|
|
59
59
|
#
|
60
60
|
# In all cases where it uses a 405 response, it also sets the +Allow+
|
61
61
|
# header in the response to contain the request methods supported.
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
62
|
+
#
|
63
|
+
# This plugin depends on the all_verbs plugin. It works by overriding
|
64
|
+
# the verb methods, so it wouldn't work if loaded after the all_verbs
|
65
|
+
# plugin.
|
65
66
|
module NotAllowed
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
app::RodaRequest.def_verb_method(self, :post)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
module RequestClassMethods
|
75
|
-
# Define a method named +verb+ in the given module which will
|
76
|
-
# return a 405 response if the method is called with any
|
77
|
-
# arguments and the arguments terminally match but the
|
78
|
-
# request method does not.
|
79
|
-
#
|
80
|
-
# If called without any arguments, check to see if the call
|
81
|
-
# is inside a terminal match, and in that case record the
|
82
|
-
# request method used.
|
83
|
-
def def_verb_method(mod, verb)
|
84
|
-
mod.class_eval(<<-END, __FILE__, __LINE__+1)
|
85
|
-
def #{verb}(*args, &block)
|
86
|
-
if args.empty?
|
87
|
-
@_is_verbs << "#{verb.to_s.upcase}" if defined?(@_is_verbs)
|
88
|
-
always(&block) if #{verb == :get ? :is_get : verb}?
|
89
|
-
else
|
90
|
-
args << ::Roda::RodaPlugins::Base::RequestMethods::TERM
|
91
|
-
if_match(args) do |*a|
|
92
|
-
if #{verb == :get ? :is_get : verb}?
|
93
|
-
block_result(yield(*a))
|
94
|
-
throw :halt, response.finish
|
95
|
-
end
|
96
|
-
response.status = 405
|
97
|
-
response['Allow'] = '#{verb.to_s.upcase}'
|
98
|
-
nil
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
END
|
103
|
-
end
|
67
|
+
# Depend on the all_verbs plugin, as this plugin overrides methods
|
68
|
+
# defined by it and calls super.
|
69
|
+
def self.load_dependencies(app)
|
70
|
+
app.plugin :all_verbs
|
104
71
|
end
|
105
72
|
|
106
73
|
module RequestMethods
|
@@ -110,20 +77,19 @@ class Roda
|
|
110
77
|
# since there was already a successful terminal match, the
|
111
78
|
# request method must not be allowed, so return a 405
|
112
79
|
# response in that case.
|
113
|
-
def is(*
|
114
|
-
super(*
|
80
|
+
def is(*args)
|
81
|
+
super(*args) do
|
115
82
|
begin
|
116
|
-
@_is_verbs = []
|
83
|
+
is_verbs = @_is_verbs = []
|
117
84
|
|
118
|
-
ret = if
|
85
|
+
ret = if args.empty?
|
119
86
|
yield
|
120
87
|
else
|
121
88
|
yield(*captures)
|
122
89
|
end
|
123
90
|
|
124
|
-
unless
|
125
|
-
|
126
|
-
response['Allow'] = @_is_verbs.join(', ')
|
91
|
+
unless is_verbs.empty?
|
92
|
+
method_not_allowed(is_verbs.join(', '))
|
127
93
|
end
|
128
94
|
|
129
95
|
ret
|
@@ -132,6 +98,35 @@ class Roda
|
|
132
98
|
end
|
133
99
|
end
|
134
100
|
end
|
101
|
+
|
102
|
+
# Setup methods for all verbs. If inside an is block and not given
|
103
|
+
# arguments, record the verb used. If given an argument, add an is
|
104
|
+
# check with the argu
|
105
|
+
%w'get post delete head options link patch put trace unlink'.each do |verb|
|
106
|
+
if ::Rack::Request.method_defined?("#{verb}?")
|
107
|
+
class_eval(<<-END, __FILE__, __LINE__+1)
|
108
|
+
def #{verb}(*args, &block)
|
109
|
+
if (empty = args.empty?) && @_is_verbs
|
110
|
+
@_is_verbs << "#{verb.to_s.upcase}"
|
111
|
+
end
|
112
|
+
super
|
113
|
+
unless empty
|
114
|
+
is(*args){method_not_allowed("#{verb.to_s.upcase}")}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
END
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Set the response status to 405 (Method Not Allowed), and set the Allow header
|
124
|
+
# to the given string of allowed request methods.
|
125
|
+
def method_not_allowed(verbs)
|
126
|
+
res = response
|
127
|
+
res.status = 405
|
128
|
+
res['Allow'] = verbs
|
129
|
+
end
|
135
130
|
end
|
136
131
|
end
|
137
132
|
|
data/lib/roda/plugins/path.rb
CHANGED
@@ -17,9 +17,31 @@ class Roda
|
|
17
17
|
# r.redirect bar_path(bar)
|
18
18
|
# end
|
19
19
|
# end
|
20
|
+
#
|
21
|
+
# The path method accepts the following options:
|
22
|
+
#
|
23
|
+
# :add_script_name :: Prefix the path generated with SCRIPT_NAME.
|
24
|
+
# :name :: Provide a different name for the method, instead of using <tt>*_path</tt>.
|
25
|
+
# :url :: Create a url method in addition to the path method, which will prefix the string generated
|
26
|
+
# with the appropriate scheme, host, and port. If true, creates a <tt>*_url</tt>
|
27
|
+
# method. If a Symbol or String, uses the value as the url method name.
|
28
|
+
# :url_only :: Do not create a path method, just a url method.
|
29
|
+
#
|
30
|
+
# Note that if :add_script_name, :url, or :url_only is used, this will also create a <tt>_*_path</tt>
|
31
|
+
# method. This is necessary in order to support path methods that accept blocks, as you can't pass
|
32
|
+
# a block to a block that is instance_execed.
|
20
33
|
module Path
|
34
|
+
DEFAULT_PORTS = {'http' => 80, 'https' => 443}.freeze
|
35
|
+
|
21
36
|
module ClassMethods
|
22
|
-
|
37
|
+
# Create a new instance method for the named path. See plugin module documentation for options.
|
38
|
+
def path(name, path=nil, opts={}, &block)
|
39
|
+
if path.is_a?(Hash)
|
40
|
+
raise RodaError, "cannot provide two option hashses to Roda.path" unless opts.empty?
|
41
|
+
opts = path
|
42
|
+
path = nil
|
43
|
+
end
|
44
|
+
|
23
45
|
raise RodaError, "cannot provide both path and block to Roda.path" if path && block
|
24
46
|
raise RodaError, "must provide either path or block to Roda.path" unless path || block
|
25
47
|
|
@@ -28,7 +50,46 @@ class Roda
|
|
28
50
|
block = lambda{path}
|
29
51
|
end
|
30
52
|
|
31
|
-
|
53
|
+
meth = opts[:name] || "#{name}_path"
|
54
|
+
url = opts[:url]
|
55
|
+
add_script_name = opts[:add_script_name]
|
56
|
+
|
57
|
+
if add_script_name || url || opts[:url_only]
|
58
|
+
_meth = "_#{meth}"
|
59
|
+
define_method(_meth, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
unless opts[:url_only]
|
63
|
+
if add_script_name
|
64
|
+
define_method(meth) do |*a, &blk|
|
65
|
+
request.script_name.to_s + send(_meth, *a, &blk)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
define_method(meth, &block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if url || opts[:url_only]
|
73
|
+
url_meth = if url.is_a?(String) || url.is_a?(Symbol)
|
74
|
+
url
|
75
|
+
else
|
76
|
+
"#{name}_url"
|
77
|
+
end
|
78
|
+
|
79
|
+
url_block = lambda do |*a, &blk|
|
80
|
+
r = request
|
81
|
+
scheme = r.scheme
|
82
|
+
port = r.port
|
83
|
+
uri = ["#{scheme}://#{r.host}#{":#{port}" unless DEFAULT_PORTS[scheme] == port}"]
|
84
|
+
uri << request.script_name.to_s if add_script_name
|
85
|
+
uri << send(_meth, *a, &blk)
|
86
|
+
File.join(uri)
|
87
|
+
end
|
88
|
+
|
89
|
+
define_method(url_meth, &url_block)
|
90
|
+
end
|
91
|
+
|
92
|
+
nil
|
32
93
|
end
|
33
94
|
end
|
34
95
|
end
|