gin 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.rdoc +22 -1
- data/Manifest.txt +7 -0
- data/TODO.rdoc +45 -0
- data/bin/gin +105 -35
- data/lib/gin.rb +7 -1
- data/lib/gin/app.rb +328 -59
- data/lib/gin/asset_manifest.rb +178 -0
- data/lib/gin/asset_pipeline.rb +235 -0
- data/lib/gin/cache.rb +36 -0
- data/lib/gin/config.rb +3 -1
- data/lib/gin/constants.rb +6 -1
- data/lib/gin/controller.rb +180 -17
- data/lib/gin/core_ext/float.rb +10 -0
- data/lib/gin/core_ext/time.rb +41 -0
- data/lib/gin/filterable.rb +5 -5
- data/lib/gin/mountable.rb +100 -0
- data/lib/gin/request.rb +4 -12
- data/lib/gin/response.rb +4 -2
- data/lib/gin/router.rb +110 -37
- data/lib/gin/strict_hash.rb +33 -0
- data/lib/gin/test.rb +8 -4
- data/lib/gin/worker.rb +49 -0
- data/test/mock_app.rb +7 -7
- data/test/test_app.rb +266 -17
- data/test/test_cache.rb +73 -5
- data/test/test_config.rb +4 -4
- data/test/test_controller.rb +158 -32
- data/test/test_filterable.rb +16 -1
- data/test/test_gin.rb +7 -6
- data/test/test_request.rb +6 -1
- data/test/test_response.rb +1 -1
- data/test/test_router.rb +156 -34
- data/test/test_test.rb +51 -45
- metadata +42 -14
- checksums.yaml +0 -7
data/lib/gin/config.rb
CHANGED
@@ -41,6 +41,8 @@ class Gin::Config
|
|
41
41
|
|
42
42
|
attr_accessor :dir, :logger, :ttl, :environment
|
43
43
|
|
44
|
+
SYNTAX_ERROR = defined?(Psych) ? Psych::SyntaxError : ArgumentError
|
45
|
+
|
44
46
|
##
|
45
47
|
# Create a new config instance for the given environment name.
|
46
48
|
# The environment dictates which part of the config files gets exposed.
|
@@ -120,7 +122,7 @@ class Gin::Config
|
|
120
122
|
@data[name] = c
|
121
123
|
end
|
122
124
|
|
123
|
-
rescue
|
125
|
+
rescue SYNTAX_ERROR
|
124
126
|
@logger.write "[ERROR] Could not parse config `#{filepath}' as YAML"
|
125
127
|
return nil
|
126
128
|
end
|
data/lib/gin/constants.rb
CHANGED
@@ -7,6 +7,8 @@ module Gin::Constants
|
|
7
7
|
REMOTE_ADDR = 'REMOTE_ADDR'.freeze
|
8
8
|
REMOTE_USER = 'REMOTE_USER'.freeze
|
9
9
|
HTTP_VERSION = 'HTTP_VERSION'.freeze
|
10
|
+
SERVER_NAME = 'SERVER_NAME'.freeze
|
11
|
+
SERVER_PORT = 'SERVER_PORT'.freeze
|
10
12
|
REQ_METHOD = 'REQUEST_METHOD'.freeze
|
11
13
|
PATH_INFO = 'PATH_INFO'.freeze
|
12
14
|
QUERY_STRING = 'QUERY_STRING'.freeze
|
@@ -14,6 +16,7 @@ module Gin::Constants
|
|
14
16
|
IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
|
15
17
|
IF_MOD_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
|
16
18
|
IF_UNMOD_SINCE = 'HTTP_IF_UNMODIFIED_SINCE'.freeze
|
19
|
+
RACK_INPUT = 'rack.input'.freeze
|
17
20
|
|
18
21
|
ASYNC_CALLBACK = 'async.callback'.freeze
|
19
22
|
|
@@ -27,13 +30,15 @@ module Gin::Constants
|
|
27
30
|
CACHE_CTRL = 'Cache-Control'.freeze
|
28
31
|
EXPIRES = 'Expires'.freeze
|
29
32
|
PRAGMA = 'Pragma'.freeze
|
33
|
+
HOST_NAME = 'Host'.freeze
|
30
34
|
|
31
35
|
# Gin env constants
|
36
|
+
GIN_APP = 'gin.app'.freeze
|
32
37
|
GIN_STACK = 'gin.stack'.freeze
|
33
38
|
GIN_ROUTE = 'gin.http_route'.freeze
|
34
39
|
GIN_PATH_PARAMS = 'gin.path_query_hash'.freeze
|
40
|
+
GIN_TARGET = 'gin.target'.freeze
|
35
41
|
GIN_CTRL = 'gin.controller'.freeze
|
36
|
-
GIN_ACTION = 'gin.action'.freeze
|
37
42
|
GIN_STATIC = 'gin.static'.freeze
|
38
43
|
GIN_RELOADED = 'gin.reloaded'.freeze
|
39
44
|
GIN_ERRORS = 'gin.errors'.freeze
|
data/lib/gin/controller.rb
CHANGED
@@ -49,6 +49,7 @@
|
|
49
49
|
|
50
50
|
class Gin::Controller
|
51
51
|
extend GinClass
|
52
|
+
extend Gin::Mountable
|
52
53
|
include Gin::Constants
|
53
54
|
include Gin::Filterable
|
54
55
|
include Gin::Errorable
|
@@ -84,7 +85,7 @@ class Gin::Controller
|
|
84
85
|
# Array of action names for this controller.
|
85
86
|
|
86
87
|
def self.actions
|
87
|
-
instance_methods(false)
|
88
|
+
instance_methods(false).map{|a| a.to_sym }
|
88
89
|
end
|
89
90
|
|
90
91
|
|
@@ -93,6 +94,9 @@ class Gin::Controller
|
|
93
94
|
# Underscores the class name and removes mentions of 'controller'.
|
94
95
|
# MyApp::FooController.controller_name
|
95
96
|
# #=> "my_app/foo"
|
97
|
+
#
|
98
|
+
# Note that when route names get autogenerated, the namespacing is dropped.
|
99
|
+
# If two routes have the same name, the last one defined wins.
|
96
100
|
|
97
101
|
def self.controller_name new_name=nil
|
98
102
|
@ctrl_name = new_name if new_name
|
@@ -100,6 +104,32 @@ class Gin::Controller
|
|
100
104
|
end
|
101
105
|
|
102
106
|
|
107
|
+
DEFAULT_ACTION_MAP = {
|
108
|
+
:index => %w{GET /},
|
109
|
+
:show => %w{GET /:id},
|
110
|
+
:new => %w{GET /new},
|
111
|
+
:create => %w{POST /},
|
112
|
+
:edit => %w{GET /:id/edit},
|
113
|
+
:update => %w{PUT /:id},
|
114
|
+
:destroy => %w{DELETE /:id}
|
115
|
+
} # :nodoc:
|
116
|
+
|
117
|
+
|
118
|
+
def self.default_route_for action #:nodoc:
|
119
|
+
DEFAULT_ACTION_MAP[action] || ['GET', "/#{action}"]
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def self.route_name_for action #:nodoc:
|
124
|
+
"#{action}_#{controller_name.sub(%r{^.*/},'')}".to_sym
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def self.display_name action=nil #:nodoc:
|
129
|
+
[self, action].compact.join("#")
|
130
|
+
end
|
131
|
+
|
132
|
+
|
103
133
|
##
|
104
134
|
# Set or get the default content type for this Gin::Controller.
|
105
135
|
# Default value is "text/html". This attribute is inherited.
|
@@ -123,6 +153,18 @@ class Gin::Controller
|
|
123
153
|
end
|
124
154
|
|
125
155
|
|
156
|
+
##
|
157
|
+
# Call the Controller with an Rack env hash. Requires the hash to have
|
158
|
+
# the keys 'gin.target' with the action name as the second item of the array,
|
159
|
+
# and 'gin.app'.
|
160
|
+
|
161
|
+
def self.call env
|
162
|
+
inst = new(env[GIN_APP], env)
|
163
|
+
env[GIN_CTRL] = inst
|
164
|
+
inst.call_action(env[GIN_TARGET][1])
|
165
|
+
end
|
166
|
+
|
167
|
+
|
126
168
|
##
|
127
169
|
# Get or set a layout for a given controller.
|
128
170
|
# Value can be a symbol or filepath.
|
@@ -164,7 +206,11 @@ class Gin::Controller
|
|
164
206
|
end
|
165
207
|
|
166
208
|
|
167
|
-
|
209
|
+
##
|
210
|
+
# Calls the given or preset action and returns a Rack response Array.
|
211
|
+
|
212
|
+
def call_action action=nil
|
213
|
+
action ||= @action
|
168
214
|
invoke{ dispatch action }
|
169
215
|
invoke{ handle_status(@response.status) }
|
170
216
|
content_type self.class.content_type unless @response[CNT_TYPE]
|
@@ -301,8 +347,6 @@ class Gin::Controller
|
|
301
347
|
end
|
302
348
|
|
303
349
|
|
304
|
-
|
305
|
-
|
306
350
|
##
|
307
351
|
# Set multiple response headers with Hash.
|
308
352
|
|
@@ -404,7 +448,8 @@ class Gin::Controller
|
|
404
448
|
|
405
449
|
def path_to *args
|
406
450
|
return "#{args[0]}#{"?" << Gin.build_query(args[1]) if args[1]}" if String === args[0]
|
407
|
-
args.unshift(self.class) if Symbol === args[0] &&
|
451
|
+
args.unshift(self.class) if Symbol === args[0] &&
|
452
|
+
self.class.actions.include?(args[0])
|
408
453
|
@app.router.path_to(*args)
|
409
454
|
end
|
410
455
|
|
@@ -471,6 +516,95 @@ class Gin::Controller
|
|
471
516
|
end
|
472
517
|
|
473
518
|
|
519
|
+
##
|
520
|
+
# Halt execution of the current controller action and create a new request to
|
521
|
+
# another action and/or controller, or path.
|
522
|
+
#
|
523
|
+
# Raises Gin::RouterError if the controller and action don't have a route.
|
524
|
+
# Returns a 404 response if an unrecognized path is given.
|
525
|
+
#
|
526
|
+
# The rewrite method acts just as if a request had been sent from the client,
|
527
|
+
# and will re-run any of the in-app middleware. If the app is itself running
|
528
|
+
# as middleware, you may use rewrite to pass a request down to the next item
|
529
|
+
# in the stack by specifying a path not supported by the app.
|
530
|
+
#
|
531
|
+
# Supports the same arguments at the Gin::Controller#url_to method.
|
532
|
+
#
|
533
|
+
# rewrite MyController, :action
|
534
|
+
# #=> Calls app with route for MyController#action
|
535
|
+
#
|
536
|
+
# rewrite MyController, :show, :id => 123
|
537
|
+
# #=> Calls app with route for MyController#action with the given params
|
538
|
+
#
|
539
|
+
# rewrite :show_foo
|
540
|
+
# #=> Calls app with route for the current controller's :show_foo action,
|
541
|
+
# #=> or if missing the controller and action for the :show_foo named route.
|
542
|
+
#
|
543
|
+
# # Rewrite and execute the request with the given headers.
|
544
|
+
# rewrite :show_foo, 'HTTP_X_CUSTOM_HEADER' => 'foo'
|
545
|
+
# rewrite :show_foo, params, 'HTTP_X_CUSTOM_HEADER' => 'foo'
|
546
|
+
#
|
547
|
+
# # Rewrite to an arbitrary path.
|
548
|
+
# rewrite '/path/to/something/else', {}, 'REQUEST_METHOD' => 'POST'
|
549
|
+
#
|
550
|
+
# Note that params are not forwarded with the rewrite call. The app
|
551
|
+
# considers this to be a completely different request, which means all params
|
552
|
+
# required must be passed explicitely.
|
553
|
+
#
|
554
|
+
# Streamed and IO request content is also ignored unless it is explicitely
|
555
|
+
# assigned to the 'rack.input' (as a part of the headers argument).
|
556
|
+
|
557
|
+
def rewrite *args
|
558
|
+
args.unshift(self.class) if Symbol === args[0] &&
|
559
|
+
self.class.actions.include?(args[0])
|
560
|
+
halt(*@app.rewrite!(@env, *args))
|
561
|
+
end
|
562
|
+
|
563
|
+
|
564
|
+
##
|
565
|
+
# Unlike Gin::Controller#rewrite, the reroute method forwards the current
|
566
|
+
# request and params to the provided controller and/or action, or named route.
|
567
|
+
# Halts further execution in the current action.
|
568
|
+
# Raises RouterError if a given named route isn't found in the app's routes.
|
569
|
+
#
|
570
|
+
# reroute MyController, :action
|
571
|
+
# #=> Executes MyController#action
|
572
|
+
#
|
573
|
+
# reroute MyController, :show, :id => 123
|
574
|
+
# #=> Executes MyController#action with the given params merged to
|
575
|
+
# #=> the current params.
|
576
|
+
#
|
577
|
+
# reroute :show_foo
|
578
|
+
# #=> Executes the current controller's :show_foo action, or if missing
|
579
|
+
# #=> the controller and action for the :show_foo named route.
|
580
|
+
#
|
581
|
+
# # Reroute with the given headers.
|
582
|
+
# reroute :show_foo, {}, 'HTTP_X_CUSTOM_HEADER' => 'foo'
|
583
|
+
|
584
|
+
def reroute *args
|
585
|
+
args.unshift(self.class) if Symbol === args[0] &&
|
586
|
+
self.class.actions.include?(args[0])
|
587
|
+
nheaders = args.pop if Hash === args.last && Hash === args[-2] && args[-2] != args[-1]
|
588
|
+
nparams = args.pop if Hash === args.last
|
589
|
+
|
590
|
+
if Class === args[0]
|
591
|
+
ctrl_klass, naction = args[0..1]
|
592
|
+
else
|
593
|
+
route = @app.router.route_to(*args)
|
594
|
+
ctrl_klass, naction = route.target
|
595
|
+
end
|
596
|
+
|
597
|
+
nenv = @env.merge(nheaders || {})
|
598
|
+
nenv[GIN_PATH_PARAMS] = {}
|
599
|
+
ctrl = ctrl_klass.new(@app, nenv)
|
600
|
+
|
601
|
+
ctrl.params.merge!(params)
|
602
|
+
ctrl.params.merge!(nparams) if nparams
|
603
|
+
|
604
|
+
halt(*ctrl.call_action(naction))
|
605
|
+
end
|
606
|
+
|
607
|
+
|
474
608
|
##
|
475
609
|
# Assigns a file to the response body and halts the execution of the action.
|
476
610
|
# Produces a 404 response if no file is found.
|
@@ -510,9 +644,15 @@ class Gin::Controller
|
|
510
644
|
def last_modified time
|
511
645
|
return unless time
|
512
646
|
|
513
|
-
time =
|
514
|
-
|
515
|
-
|
647
|
+
time = if Integer === time
|
648
|
+
Time.at(time)
|
649
|
+
elsif time.respond_to?(:to_time)
|
650
|
+
time.to_time
|
651
|
+
elsif !time.is_a?(Time)
|
652
|
+
Time.parse time.to_s
|
653
|
+
else
|
654
|
+
time
|
655
|
+
end
|
516
656
|
|
517
657
|
@response[LAST_MOD] = time.httpdate
|
518
658
|
return if @env[IF_NONE_MATCH]
|
@@ -596,7 +736,7 @@ class Gin::Controller
|
|
596
736
|
|
597
737
|
def expire_cache_control
|
598
738
|
@response[PRAGMA] = 'no-cache'
|
599
|
-
expires EPOCH, :no_cache, :no_store, :must_revalidate, max_age
|
739
|
+
expires EPOCH, :no_cache, :no_store, :must_revalidate, :max_age => 0
|
600
740
|
end
|
601
741
|
|
602
742
|
|
@@ -604,9 +744,28 @@ class Gin::Controller
|
|
604
744
|
# Returns the url to an asset, including predefined asset cdn hosts if set.
|
605
745
|
|
606
746
|
def asset_url name
|
607
|
-
|
608
|
-
|
609
|
-
|
747
|
+
host = @app.asset_host_for(name)
|
748
|
+
return asset_path(name) if !host
|
749
|
+
File.join(host, name)
|
750
|
+
end
|
751
|
+
|
752
|
+
|
753
|
+
##
|
754
|
+
# Returns the HTTP path to the local asset.
|
755
|
+
|
756
|
+
def asset_path name
|
757
|
+
fdpath = @app.asset(name)
|
758
|
+
|
759
|
+
if fdpath && fdpath.start_with?(@app.assets_dir)
|
760
|
+
if fdpath.start_with?(@app.public_dir)
|
761
|
+
fdpath[@app.public_dir.length..-1]
|
762
|
+
else
|
763
|
+
fdpath[@app.assets_dir.length..-1]
|
764
|
+
end
|
765
|
+
else
|
766
|
+
path = File.join('', name)
|
767
|
+
[path, *@app.asset_version(name)].compact.join("?")
|
768
|
+
end
|
610
769
|
end
|
611
770
|
|
612
771
|
|
@@ -643,7 +802,7 @@ class Gin::Controller
|
|
643
802
|
# #=> "<root_dir>/other/foo"
|
644
803
|
|
645
804
|
def template_path template, is_layout=false
|
646
|
-
dir = if template[0] == ?/
|
805
|
+
dir = if template.to_s[0] == ?/
|
647
806
|
@app.root_dir
|
648
807
|
elsif is_layout
|
649
808
|
@app.layouts_dir
|
@@ -765,10 +924,11 @@ class Gin::Controller
|
|
765
924
|
|
766
925
|
def html_error_page err, code=nil
|
767
926
|
if @app.development?
|
768
|
-
|
927
|
+
backtrace = err.backtrace || ['No backtrace :(']
|
928
|
+
fulltrace = backtrace.join("\n")
|
769
929
|
fulltrace = "<pre>#{h(fulltrace)}</pre>"
|
770
930
|
|
771
|
-
apptrace = Gin.app_trace(
|
931
|
+
apptrace = Gin.app_trace(backtrace).join("\n")
|
772
932
|
apptrace = "<pre>#{h(apptrace)}</pre>" unless apptrace.empty?
|
773
933
|
|
774
934
|
DEV_ERROR_HTML %
|
@@ -807,9 +967,12 @@ class Gin::Controller
|
|
807
967
|
# Get action arguments from the params.
|
808
968
|
# Raises Gin::BadRequest if a required argument has no matching param.
|
809
969
|
|
810
|
-
def action_arguments action
|
970
|
+
def action_arguments action
|
971
|
+
raise Gin::NotFound,
|
972
|
+
"No action exists for: #{env[REQ_METHOD]} #{env[PATH_INFO]}" unless action
|
973
|
+
|
811
974
|
raise Gin::NotFound, "No action #{self.class}##{action}" unless
|
812
|
-
self.class.actions.include?
|
975
|
+
self.class.actions.include?(action.to_sym)
|
813
976
|
|
814
977
|
args = []
|
815
978
|
temp = []
|
@@ -0,0 +1,41 @@
|
|
1
|
+
unless Time.now.respond_to?(:httpdate)
|
2
|
+
|
3
|
+
class Time
|
4
|
+
def httpdate(date)
|
5
|
+
if /\A\s*
|
6
|
+
(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\x20
|
7
|
+
(\d{2})\x20
|
8
|
+
(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20
|
9
|
+
(\d{4})\x20
|
10
|
+
(\d{2}):(\d{2}):(\d{2})\x20
|
11
|
+
GMT
|
12
|
+
\s*\z/x =~ date
|
13
|
+
self.rfc2822(date)
|
14
|
+
elsif /\A\s*
|
15
|
+
(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\x20
|
16
|
+
(\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d)\x20
|
17
|
+
(\d\d):(\d\d):(\d\d)\x20
|
18
|
+
GMT
|
19
|
+
\s*\z/x =~ date
|
20
|
+
year = $3.to_i
|
21
|
+
if year < 50
|
22
|
+
year += 2000
|
23
|
+
else
|
24
|
+
year += 1900
|
25
|
+
end
|
26
|
+
self.utc(year, $2, $1.to_i, $4.to_i, $5.to_i, $6.to_i)
|
27
|
+
elsif /\A\s*
|
28
|
+
(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\x20
|
29
|
+
(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20
|
30
|
+
(\d\d|\x20\d)\x20
|
31
|
+
(\d\d):(\d\d):(\d\d)\x20
|
32
|
+
(\d{4})
|
33
|
+
\s*\z/x =~ date
|
34
|
+
self.utc($6.to_i, MonthValue[$1.upcase], $2.to_i,
|
35
|
+
$3.to_i, $4.to_i, $5.to_i)
|
36
|
+
else
|
37
|
+
raise ArgumentError.new("not RFC 2616 compliant date: #{date.inspect}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/gin/filterable.rb
CHANGED
@@ -74,14 +74,14 @@ module Gin::Filterable
|
|
74
74
|
|
75
75
|
elsif opts[:except]
|
76
76
|
except = Array(opts[:except])
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
except.include?(action)
|
77
|
+
except.each do |action|
|
78
|
+
filter_hsh[action] ||= filter_hsh[nil].dup
|
79
|
+
end
|
81
80
|
|
81
|
+
filter_hsh.keys.each do |action|
|
82
|
+
next if except.include?(action)
|
82
83
|
yield filter_hsh, action, names
|
83
84
|
end
|
84
|
-
yield filter_hsh, nil, names
|
85
85
|
|
86
86
|
else
|
87
87
|
filter_hsh.keys.each do |action|
|
@@ -0,0 +1,100 @@
|
|
1
|
+
##
|
2
|
+
# The Gin::Mountable module provides an interface to mount any type of object
|
3
|
+
# to a Gin::App route.
|
4
|
+
#
|
5
|
+
# The Gin::Mountable module is only necessary if features such automatic route
|
6
|
+
# naming and defaults are needed. Gin will otherwise happily mount any object
|
7
|
+
# that responds to the `call' method onto it's routing tree.
|
8
|
+
|
9
|
+
module Gin::Mountable
|
10
|
+
|
11
|
+
def verify_mount! #:nodoc:
|
12
|
+
controller_name.to_str
|
13
|
+
|
14
|
+
test_action = actions[0]
|
15
|
+
|
16
|
+
test_route = default_route_for(test_action)
|
17
|
+
test_route[0].to_str
|
18
|
+
test_route[1].to_str
|
19
|
+
|
20
|
+
route_name_for(test_action).to_proc
|
21
|
+
|
22
|
+
display_name.to_str
|
23
|
+
display_name(test_action).to_str
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
##
|
30
|
+
# The actions available on this Mountable object.
|
31
|
+
# Actions can be of any object type.
|
32
|
+
#
|
33
|
+
# Must return an Array of actions. Must be overloaded.
|
34
|
+
# UserController.actions
|
35
|
+
# #=> [:show, :delete, :list, :update]
|
36
|
+
|
37
|
+
def actions
|
38
|
+
raise NoMethodError,
|
39
|
+
"The `#{__method__}' method must be defined on #{self} and return an\
|
40
|
+
Array of available actions for the Router to map to."
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
##
|
45
|
+
# The String representing the controller.
|
46
|
+
#
|
47
|
+
# Must return a String. Must be overloaded.
|
48
|
+
# UserController.controller_name
|
49
|
+
# #=> 'user'
|
50
|
+
|
51
|
+
def controller_name
|
52
|
+
raise NoMethodError,
|
53
|
+
"The `#{__method__}' method must be defined on #{self} and return a\
|
54
|
+
String representing the controller name."
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
##
|
59
|
+
# Should return a 2 item Array with the HTTP verb and request path (local to
|
60
|
+
# the controller) to use for a given action.
|
61
|
+
#
|
62
|
+
# Must return a 2 item Array of Strings. Must be overloaded.
|
63
|
+
# UserController.default_route_for :show
|
64
|
+
# #=> ['GET', '/:id']
|
65
|
+
|
66
|
+
def default_route_for action
|
67
|
+
raise NoMethodError,
|
68
|
+
"The `#{__method__}' method must be defined on #{self} and return a\
|
69
|
+
2 item Array with the HTTP verb and local path: ['GET', '/users/:id']"
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
##
|
74
|
+
# Creates a route name used to identify a given route. Used by helper methods.
|
75
|
+
#
|
76
|
+
# Must return a Symbol, or nil. Must be overloaded.
|
77
|
+
# UserController.route_name_for :show
|
78
|
+
# #=> :show_user
|
79
|
+
|
80
|
+
def route_name_for action
|
81
|
+
raise NoMethodError,
|
82
|
+
"The `#{__method__}' method must be defined on #{self} and return a\
|
83
|
+
Symbol representing the route name: :show_user"
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
##
|
88
|
+
# Creates a display name for the Controller (and optional action).
|
89
|
+
# Used for logging and error messages.
|
90
|
+
#
|
91
|
+
# Must return a String. Must be overloaded.
|
92
|
+
# UserController.display_name :show
|
93
|
+
# #=> "UserController#show"
|
94
|
+
|
95
|
+
def display_name action=nil
|
96
|
+
raise NoMethodError,
|
97
|
+
"The `#{__method__}' method must be defined on #{self} and return a\
|
98
|
+
String for display purposes"
|
99
|
+
end
|
100
|
+
end
|