racket-mvc 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +7 -5
- data/lib/racket.rb +25 -7
- data/lib/racket/application.rb +70 -136
- data/lib/racket/controller.rb +95 -38
- data/lib/racket/current.rb +1 -1
- data/lib/racket/helpers/file.rb +7 -5
- data/lib/racket/helpers/routing.rb +5 -5
- data/lib/racket/helpers/sass.rb +11 -11
- data/lib/racket/helpers/view.rb +8 -5
- data/lib/racket/plugins/base.rb +1 -1
- data/lib/racket/plugins/sass.rb +1 -1
- data/lib/racket/request.rb +3 -3
- data/lib/racket/response.rb +1 -1
- data/lib/racket/router.rb +31 -12
- data/lib/racket/session.rb +3 -3
- data/lib/racket/settings/application.rb +27 -33
- data/lib/racket/settings/base.rb +19 -8
- data/lib/racket/settings/controller.rb +9 -7
- data/lib/racket/settings/defaults.rb +81 -0
- data/lib/racket/utils.rb +19 -15
- data/lib/racket/utils/application.rb +4 -114
- data/lib/racket/utils/application/handler_stack.rb +163 -0
- data/lib/racket/utils/application/logger.rb +72 -0
- data/lib/racket/utils/application/registry_builder.rb +88 -0
- data/lib/racket/utils/application/stateless_services.rb +73 -0
- data/lib/racket/utils/exceptions.rb +3 -3
- data/lib/racket/utils/file_system.rb +75 -47
- data/lib/racket/utils/helpers.rb +35 -13
- data/lib/racket/utils/routing.rb +62 -46
- data/lib/racket/utils/views.rb +19 -187
- data/lib/racket/utils/views/renderer.rb +75 -0
- data/lib/racket/utils/views/template_cache.rb +126 -0
- data/lib/racket/utils/views/template_locator.rb +83 -0
- data/lib/racket/utils/views/template_resolver.rb +112 -0
- data/lib/racket/version.rb +2 -2
- data/lib/racket/view_manager.rb +12 -4
- data/rake/utils.rb +5 -5
- data/spec/_custom.rb +69 -19
- data/spec/_default.rb +60 -44
- data/spec/_plugin.rb +12 -14
- data/spec/_template_cache.rb +176 -0
- data/spec/racket.rb +10 -13
- data/spec/test_custom_app/controllers/sub1/custom_sub_controller_1.rb +1 -1
- data/spec/test_custom_app/controllers/sub3/custom_sub_controller_3.rb +19 -1
- data/spec/test_custom_app/controllers/sub5/custom_sub_controller_5.rb +8 -0
- data/spec/test_custom_app/files/stuff.rb +3 -0
- data/spec/test_custom_app/files/triplet.erb +5 -0
- data/spec/test_custom_app/templates/sub5/text.erb +3 -0
- data/spec/test_default_app/controllers/default_root_controller.rb +3 -0
- data/spec/test_default_app/controllers/sub1/default_sub_controller_1.rb +1 -1
- metadata +52 -11
data/lib/racket/utils/helpers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Racket - The noisy Rack MVC framework
|
2
|
-
# Copyright (C) 2015 Lars Olsson <lasso@lassoweb.se>
|
2
|
+
# Copyright (C) 2015-2016 Lars Olsson <lasso@lassoweb.se>
|
3
3
|
#
|
4
4
|
# This file is part of Racket.
|
5
5
|
#
|
@@ -22,9 +22,25 @@ module Racket
|
|
22
22
|
module Helpers
|
23
23
|
# Cache for helpers, ensuring that helpers get loaded exactly once.
|
24
24
|
class HelperCache
|
25
|
-
|
25
|
+
# Returns a service proc that can be used by the registry.
|
26
|
+
#
|
27
|
+
# @param [Hash] _options (unused)
|
28
|
+
# @return [Proc]
|
29
|
+
def self.service(_options = {})
|
30
|
+
lambda do |reg|
|
31
|
+
new(
|
32
|
+
reg.application_settings.helper_dir,
|
33
|
+
reg.application_logger,
|
34
|
+
reg.utils
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(helper_dir, logger, utils)
|
26
40
|
@helper_dir = helper_dir
|
27
41
|
@helpers = {}
|
42
|
+
@logger = logger
|
43
|
+
@utils = utils
|
28
44
|
end
|
29
45
|
|
30
46
|
# Loads helper files and return the loadad modules as a hash. Any helper files that
|
@@ -51,20 +67,24 @@ module Racket
|
|
51
67
|
|
52
68
|
def load_helper_file(helper)
|
53
69
|
require_helper_file(helper)
|
54
|
-
|
70
|
+
load_helper_module(helper)
|
55
71
|
end
|
56
72
|
|
57
73
|
def require_helper_file(helper)
|
58
|
-
loaded =
|
59
|
-
|
74
|
+
loaded = @utils.safe_require("racket/helpers/#{helper}")
|
75
|
+
@utils.safe_require(@utils.build_path(@helper_dir, helper).to_s) if !loaded && @helper_dir
|
60
76
|
end
|
61
77
|
|
62
|
-
|
78
|
+
# Loads a helper module
|
79
|
+
#
|
80
|
+
# @param [Symbol] helper
|
81
|
+
# @return [Module]
|
82
|
+
def load_helper_module(helper)
|
63
83
|
helper_module = nil
|
64
|
-
|
84
|
+
@utils.run_block(NameError) do
|
65
85
|
helper_module =
|
66
86
|
Racket::Helpers.const_get(helper.to_s.split('_').collect(&:capitalize).join.to_sym)
|
67
|
-
|
87
|
+
@logger.inform_dev("Loaded helper module #{helper.inspect}.")
|
68
88
|
end
|
69
89
|
helper_module
|
70
90
|
end
|
@@ -73,23 +93,25 @@ module Racket
|
|
73
93
|
# Applies helpers to a controller class by including the modules in the class.
|
74
94
|
#
|
75
95
|
# @param [Class] klass
|
76
|
-
def
|
96
|
+
def apply_helpers(klass)
|
77
97
|
klass.helper unless klass.settings.fetch(:helpers) # Makes sure default helpers are loaded.
|
78
98
|
__apply_helpers(klass)
|
79
99
|
nil
|
80
100
|
end
|
81
101
|
|
82
|
-
|
102
|
+
# Applies helpers to a controller class by including the modules in the class.
|
103
|
+
#
|
104
|
+
# @param [Class] klass
|
105
|
+
# @return [Class]
|
106
|
+
def __apply_helpers(klass)
|
83
107
|
klass.settings.fetch(:helpers).reverse_each do |pair|
|
84
108
|
helper_key, helper = pair
|
85
|
-
|
109
|
+
klass.context.logger.inform_dev(
|
86
110
|
"Adding helper module #{helper_key.inspect} to #{klass}"
|
87
111
|
)
|
88
112
|
klass.send(:include, helper)
|
89
113
|
end
|
90
114
|
end
|
91
|
-
|
92
|
-
private_class_method :__apply_helpers
|
93
115
|
end
|
94
116
|
end
|
95
117
|
end
|
data/lib/racket/utils/routing.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Racket - The noisy Rack MVC framework
|
2
|
-
# Copyright (C) 2015 Lars Olsson <lasso@lassoweb.se>
|
2
|
+
# Copyright (C) 2015-2016 Lars Olsson <lasso@lassoweb.se>
|
3
3
|
#
|
4
4
|
# This file is part of Racket.
|
5
5
|
#
|
@@ -25,10 +25,19 @@ module Racket
|
|
25
25
|
|
26
26
|
# Class for caching actions
|
27
27
|
class ActionCache
|
28
|
+
# Returns a service proc that can be used by the registry.
|
29
|
+
#
|
30
|
+
# @param [Hash] _options (unused)
|
31
|
+
# @return [Proc]
|
32
|
+
def self.service(_options = {})
|
33
|
+
->(reg) { new(reg.application_logger) }
|
34
|
+
end
|
35
|
+
|
28
36
|
attr_reader :items
|
29
37
|
|
30
|
-
def initialize
|
38
|
+
def initialize(logger)
|
31
39
|
@items = {}
|
40
|
+
@logger = logger
|
32
41
|
end
|
33
42
|
|
34
43
|
# Returns whether +controller_class+ is in the cache and that it contains the action
|
@@ -50,7 +59,7 @@ module Racket
|
|
50
59
|
__add(controller_class)
|
51
60
|
actions = @items[controller_class].to_a
|
52
61
|
@items[controller_class] = actions
|
53
|
-
|
62
|
+
@logger.inform_dev(
|
54
63
|
"Registering actions #{actions} for #{controller_class}."
|
55
64
|
) && nil
|
56
65
|
end
|
@@ -69,55 +78,62 @@ module Racket
|
|
69
78
|
end
|
70
79
|
end
|
71
80
|
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
# Class responsible for dispatching requests to controllers.
|
82
|
+
class Dispatcher
|
83
|
+
# Extracts the target class, target params and target action from a list of valid routes.
|
84
|
+
#
|
85
|
+
# @param [HttpRouter::Response] response
|
86
|
+
# @return [Array]
|
87
|
+
def self.extract_target(response)
|
88
|
+
target_klass = response.route.dest
|
89
|
+
params = response.param_values.first.reject(&:empty?)
|
90
|
+
action =
|
91
|
+
if params.empty?
|
92
|
+
target_klass.settings.fetch(:default_action)
|
93
|
+
else
|
94
|
+
params.shift.to_sym
|
95
|
+
end
|
96
|
+
[target_klass, params, action]
|
97
|
+
end
|
82
98
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
99
|
+
# Constructor
|
100
|
+
#
|
101
|
+
# @param [Hash] env
|
102
|
+
# @param [Array] target_info
|
103
|
+
def initialize(env, target_info)
|
104
|
+
@env = env
|
105
|
+
@controller_class, @params, @action = target_info
|
106
|
+
end
|
88
107
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
controller_class, params, action = target_info
|
108
|
+
# Dispatches request to a controller. This is the default action whenever a matching
|
109
|
+
# route for a request is found.
|
110
|
+
#
|
111
|
+
# @return [Array] A racket response triplet
|
112
|
+
def dispatch
|
113
|
+
# Rewrite PATH_INFO to reflect that we split out the parameters
|
114
|
+
update_path_info(@params.length)
|
97
115
|
|
98
|
-
|
99
|
-
|
116
|
+
# Call controller
|
117
|
+
call_controller(Current.init(RouterParams.new(@action, @params, @env)))
|
118
|
+
end
|
100
119
|
|
101
|
-
|
102
|
-
call_controller(
|
103
|
-
controller_class,
|
104
|
-
Current.init(RouterParams.new(action, params, env))
|
105
|
-
)
|
106
|
-
end
|
120
|
+
private
|
107
121
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
# @param [Fixnum] num_params
|
112
|
-
# @return [nil]
|
113
|
-
def self.update_path_info(env, num_params)
|
114
|
-
env['PATH_INFO'] = env['PATH_INFO']
|
115
|
-
.split('/')[0...-num_params]
|
116
|
-
.join('/') unless num_params.zero?
|
117
|
-
nil
|
118
|
-
end
|
122
|
+
def call_controller(mod)
|
123
|
+
@controller_class.new.extend(mod).__run
|
124
|
+
end
|
119
125
|
|
120
|
-
|
126
|
+
# Updates the PATH_INFO environment variable.
|
127
|
+
#
|
128
|
+
# @param [Fixnum] num_params
|
129
|
+
# @return [nil]
|
130
|
+
def update_path_info(num_params)
|
131
|
+
@env['PATH_INFO'] = @env['PATH_INFO']
|
132
|
+
.split('/')[0...-num_params]
|
133
|
+
.join('/') unless num_params.zero?
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
end
|
121
137
|
end
|
122
138
|
end
|
123
139
|
end
|
data/lib/racket/utils/views.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Racket - The noisy Rack MVC framework
|
2
|
-
# Copyright (C) 2015 Lars Olsson <lasso@lassoweb.se>
|
2
|
+
# Copyright (C) 2015-2016 Lars Olsson <lasso@lassoweb.se>
|
3
3
|
#
|
4
4
|
# This file is part of Racket.
|
5
5
|
#
|
@@ -18,197 +18,29 @@
|
|
18
18
|
|
19
19
|
require 'tilt'
|
20
20
|
|
21
|
+
require_relative 'views/renderer.rb'
|
22
|
+
require_relative 'views/template_cache.rb'
|
23
|
+
require_relative 'views/template_locator.rb'
|
24
|
+
require_relative 'views/template_resolver.rb'
|
25
|
+
|
21
26
|
module Racket
|
22
27
|
module Utils
|
23
|
-
#
|
28
|
+
# Namespace for view utilities
|
24
29
|
module Views
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def ensure_in_cache(path, template_params)
|
38
|
-
return @cache[path] if @cache.key?(path)
|
39
|
-
@cache[path] = TemplateLocator.calculate_path(path, template_params)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# Class used for locating templates.
|
44
|
-
class TemplateLocator
|
45
|
-
def initialize(layout_base_dir, view_base_dir)
|
46
|
-
@layout_base_dir = layout_base_dir
|
47
|
-
@view_base_dir = view_base_dir
|
48
|
-
@layout_cache = TemplateCache.new
|
49
|
-
@view_cache = TemplateCache.new
|
50
|
-
end
|
51
|
-
|
52
|
-
# Returns the layout associated with the current request. On the first request to any action
|
53
|
-
# the result is cached, meaning that the layout only needs to be looked up once.
|
54
|
-
#
|
55
|
-
# @param [Racket::Controller] controller
|
56
|
-
# @return [String|nil]
|
57
|
-
def get_layout(controller)
|
58
|
-
get_template(TemplateParams.new(:layout, controller, @layout_base_dir, @layout_cache))
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns the view associated with the current request. On the first request to any action
|
62
|
-
# the result is cached, meaning that the view only needs to be looked up once.
|
63
|
-
#
|
64
|
-
# @param [Racket::Controller] controller
|
65
|
-
# @return [String|nil]
|
66
|
-
def get_view(controller)
|
67
|
-
get_template(TemplateParams.new(:view, controller, @view_base_dir, @view_cache))
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
# Tries to locate a template matching +path+ in the file system and returns the path if a
|
73
|
-
# matching file is found. If no matching file is found, +nil+ is returned. The result is
|
74
|
-
# cached, meaning that the filesystem lookup for a specific path will only happen once.
|
75
|
-
#
|
76
|
-
# @param [TemplateParams] template_params
|
77
|
-
# @return [String|nil]
|
78
|
-
def get_template(template_params)
|
79
|
-
klass = self.class
|
80
|
-
path = klass.get_template_path(template_params.controller)
|
81
|
-
template = template_params.cache.ensure_in_cache(path, template_params)
|
82
|
-
klass.resolve_template(path, template, template_params)
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.calculate_path(path, template_params)
|
86
|
-
type, controller, base_dir = template_params.to_a
|
87
|
-
default_template = controller.settings.fetch("default_#{type}".to_sym)
|
88
|
-
template =
|
89
|
-
TemplateLocator.lookup_template_with_default(
|
90
|
-
Utils.fs_path(base_dir, path), default_template
|
91
|
-
)
|
92
|
-
::Racket::Application.inform_dev(
|
93
|
-
"Using #{type} #{template.inspect} for #{controller.class}.#{controller.racket.action}."
|
94
|
-
)
|
95
|
-
template
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.resolve_template(path, template, template_params)
|
99
|
-
return template unless template.is_a?(Proc)
|
100
|
-
_, controller, base_dir = template_params.to_a
|
101
|
-
lookup_template(
|
102
|
-
Utils.fs_path(
|
103
|
-
Utils.fs_path(base_dir, path).dirname,
|
104
|
-
call_template_proc(template, controller)
|
105
|
-
)
|
106
|
-
)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Calls a template proc. Depending on how many parameters the template proc takes, different
|
110
|
-
# types of information will be passed to the proc.
|
111
|
-
# If the proc takes zero parameters, no information will be passed.
|
112
|
-
# If the proc takes one parameter, it will contain the current action.
|
113
|
-
# If the proc takes two parameters, they will contain the current action and the current
|
114
|
-
# params.
|
115
|
-
# If the proc takes three parameters, they will contain the current action, the current
|
116
|
-
# params and the current request.
|
117
|
-
#
|
118
|
-
# @param [Proc] proc
|
119
|
-
# @param [Racket::Controller] controller
|
120
|
-
# @return [String]
|
121
|
-
def self.call_template_proc(proc, controller)
|
122
|
-
racket = controller.racket
|
123
|
-
proc_args = [racket.action, racket.params, controller.request].slice(0...proc.arity)
|
124
|
-
proc.call(*proc_args).to_s
|
125
|
-
end
|
126
|
-
|
127
|
-
# Returns the "url path" that should be used when searching for templates.
|
128
|
-
#
|
129
|
-
# @param [Racket::Controller] controller
|
130
|
-
# @return [String]
|
131
|
-
def self.get_template_path(controller)
|
132
|
-
template_path =
|
133
|
-
[::Racket::Application.get_route(controller.class), controller.racket.action].join('/')
|
134
|
-
template_path = template_path[1..-1] if template_path.start_with?('//')
|
135
|
-
template_path
|
136
|
-
end
|
137
|
-
|
138
|
-
# Locates a file in the filesystem matching an URL path. If there exists a matching file,
|
139
|
-
# the path to it is returned. If there is no matching file, +nil+ is returned.
|
140
|
-
# @param [Pathname] path
|
141
|
-
# @return [Pathname|nil]
|
142
|
-
def self.lookup_template(path)
|
143
|
-
Utils.first_matching_path(*Utils.extract_dir_and_glob(path))
|
144
|
-
end
|
145
|
-
|
146
|
-
# Locates a file in the filesystem matching an URL path. If there exists a matching file,
|
147
|
-
# the path to it is returned. If there is no matching file and +default_template+ is a
|
148
|
-
# String or a Symbol, another lookup will be performed using +default_template+. If
|
149
|
-
# +default_template+ is a Proc or nil, +default_template+ will be used as is instead.
|
150
|
-
#
|
151
|
-
# @param [Pathname] path
|
152
|
-
# @param [String|Symbol|Proc|nil] default_template
|
153
|
-
# @return [String|Proc|nil]
|
154
|
-
def self.lookup_template_with_default(path, default_template)
|
155
|
-
template = lookup_template(path)
|
156
|
-
unless template
|
157
|
-
if default_template.is_a?(String) || default_template.is_a?(Symbol)
|
158
|
-
# Strings and symbols can be lookup up in the file system...
|
159
|
-
template = lookup_template(Utils.fs_path(path.dirname, default_template))
|
160
|
-
else
|
161
|
-
# ...but not nils/procs!
|
162
|
-
template = default_template
|
163
|
-
end
|
164
|
-
end
|
165
|
-
template
|
30
|
+
# Extracts what template settings to use based on context and incoming parameters.
|
31
|
+
#
|
32
|
+
# @param [Object] context
|
33
|
+
# @param [Hash] template_settings
|
34
|
+
# @return [Hash]
|
35
|
+
def self.extract_template_settings(context, template_settings)
|
36
|
+
if context.respond_to?(:view_settings) && !template_settings
|
37
|
+
context.view_settings
|
38
|
+
elsif template_settings
|
39
|
+
template_settings
|
40
|
+
else
|
41
|
+
{}
|
166
42
|
end
|
167
43
|
end
|
168
|
-
|
169
|
-
# Class responsible for rendering a controller/view/layout combination.
|
170
|
-
class ViewRenderer
|
171
|
-
# Renders a page using the provided controller/view and layout combination and returns an
|
172
|
-
# response array that can be sent to the client.
|
173
|
-
#
|
174
|
-
# @param [Racket::Controller] controller
|
175
|
-
# @param [String] view
|
176
|
-
# @param [String] layout
|
177
|
-
# @return [Array]
|
178
|
-
def self.render(controller, view, layout)
|
179
|
-
send_response(
|
180
|
-
controller.response,
|
181
|
-
view ? render_template(controller, view, layout) : controller.racket.action_result
|
182
|
-
)
|
183
|
-
end
|
184
|
-
|
185
|
-
# Renders a template/layout combo using Tilt and returns it as a string.
|
186
|
-
#
|
187
|
-
# @param [Racket::Controller] controller
|
188
|
-
# @param [String] view
|
189
|
-
# @param [String|nil] layout
|
190
|
-
# @return [String]
|
191
|
-
def self.render_template(controller, view, layout)
|
192
|
-
output = Tilt.new(view).render(controller)
|
193
|
-
output = Tilt.new(layout).render(controller) { output } if layout
|
194
|
-
output
|
195
|
-
end
|
196
|
-
|
197
|
-
# Sends response to client.
|
198
|
-
#
|
199
|
-
# @param [Racket::Response] response
|
200
|
-
# @param [String] output
|
201
|
-
# @return nil
|
202
|
-
def self.send_response(response, output)
|
203
|
-
response.write(output)
|
204
|
-
response.finish
|
205
|
-
end
|
206
|
-
|
207
|
-
private_class_method :render_template, :send_response
|
208
|
-
end
|
209
|
-
|
210
|
-
# Struct for holding template data.
|
211
|
-
TemplateParams = Struct.new(:type, :controller, :base_dir, :cache)
|
212
44
|
end
|
213
45
|
end
|
214
46
|
end
|