racket-mvc 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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
|
#
|
@@ -29,15 +29,17 @@ module Racket
|
|
29
29
|
@owner = owner
|
30
30
|
end
|
31
31
|
|
32
|
-
# Fetches settings from the current object. If the setting cannot be found in the
|
33
|
-
# object, the
|
34
|
-
# inheritance chain has been queried, the
|
32
|
+
# Fetches settings from the current object. If the setting cannot be found in the current
|
33
|
+
# object, the objects class/superclass will be queried. If all controller classes in the
|
34
|
+
# inheritance chain has been queried, the application settings will be used as a final
|
35
35
|
# fallback.
|
36
36
|
def fetch(key, default = nil)
|
37
37
|
return @custom[key] if @custom.key?(key)
|
38
|
-
parent = @owner.superclass
|
39
|
-
return
|
40
|
-
|
38
|
+
parent = @owner.is_a?(Class) ? @owner.superclass : @owner.class
|
39
|
+
return @owner.context.application_settings.fetch(key, default) if
|
40
|
+
@owner == ::Racket::Controller
|
41
|
+
return parent.context.application_settings.fetch(key, default) if
|
42
|
+
parent == ::Racket::Controller
|
41
43
|
parent.settings.fetch(key, default)
|
42
44
|
end
|
43
45
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Racket - The noisy Rack MVC framework
|
2
|
+
# Copyright (C) 2015-2016 Lars Olsson <lasso@lassoweb.se>
|
3
|
+
#
|
4
|
+
# This file is part of Racket.
|
5
|
+
#
|
6
|
+
# Racket is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Racket is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with Racket. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require 'logger'
|
20
|
+
require 'racket/registry'
|
21
|
+
|
22
|
+
module Racket
|
23
|
+
module Settings
|
24
|
+
# Module used for storing default values.
|
25
|
+
module Defaults
|
26
|
+
# Returns a Racke::Registry object containing application defaults.
|
27
|
+
#
|
28
|
+
# @return [Racket::Registry]
|
29
|
+
def self.application_defaults
|
30
|
+
Racket::Registry.with_map(
|
31
|
+
default_action: -> { :index },
|
32
|
+
default_content_type: -> { 'text/html' },
|
33
|
+
default_controller_helpers: -> { [:routing, :view] },
|
34
|
+
default_layout: nil_block,
|
35
|
+
default_view: nil_block,
|
36
|
+
logger: -> { Logger.new($stdout) },
|
37
|
+
middleware: array_block,
|
38
|
+
mode: -> { :live },
|
39
|
+
plugins: array_block,
|
40
|
+
session_handler: session_handler,
|
41
|
+
root_dir: -> { Dir.pwd },
|
42
|
+
template_settings: template_settings,
|
43
|
+
warmup_urls: -> { Set.new }
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.array_block
|
48
|
+
-> { [] }
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.nil_block
|
52
|
+
-> { nil }
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.session_handler
|
56
|
+
lambda do
|
57
|
+
[
|
58
|
+
Rack::Session::Cookie,
|
59
|
+
{
|
60
|
+
key: 'racket.session',
|
61
|
+
old_secret: SecureRandom.hex(16),
|
62
|
+
secret: SecureRandom.hex(16)
|
63
|
+
}
|
64
|
+
]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.template_settings
|
69
|
+
lambda do
|
70
|
+
{
|
71
|
+
common: {},
|
72
|
+
layout: {},
|
73
|
+
view: {}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private_class_method :array_block, :nil_block, :session_handler, :template_settings
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/racket/utils.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
|
#
|
@@ -26,21 +26,25 @@ require_relative 'utils/views.rb'
|
|
26
26
|
module Racket
|
27
27
|
# Collects utilities needed by different objects in Racket.
|
28
28
|
module Utils
|
29
|
-
|
29
|
+
# Collects functionality from all utility modules into a handy class.
|
30
|
+
class ToolBelt
|
31
|
+
include Application
|
32
|
+
include Exceptions
|
33
|
+
include FileSystem
|
34
|
+
include Helpers
|
35
|
+
include Views
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
# Returns a service proc that can be used by the registry.
|
38
|
+
#
|
39
|
+
# @param [Hash] options
|
40
|
+
# @return [Proc]
|
41
|
+
def self.service(options = {})
|
42
|
+
-> { new(options[:root_dir]) }
|
43
|
+
end
|
38
44
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
__embrace(Routing)
|
44
|
-
__embrace(Views)
|
45
|
+
def initialize(root_dir)
|
46
|
+
@root_dir = Pathname.new(root_dir).cleanpath.expand_path
|
47
|
+
end
|
48
|
+
end
|
45
49
|
end
|
46
50
|
end
|
@@ -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
|
#
|
@@ -16,116 +16,6 @@
|
|
16
16
|
# You should have received a copy of the GNU Affero General Public License
|
17
17
|
# along with Racket. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# Utility functions for filesystem.
|
23
|
-
module Application
|
24
|
-
# Class used for building a proper Rack application.
|
25
|
-
class ApplicationBuilder
|
26
|
-
def initialize(application)
|
27
|
-
@application = application
|
28
|
-
@builder = Rack::Builder.new
|
29
|
-
@settings = @application.settings
|
30
|
-
@middleware = @settings.middleware
|
31
|
-
end
|
32
|
-
|
33
|
-
# Builds a Rack application representing Racket.
|
34
|
-
#
|
35
|
-
# @return [Proc]
|
36
|
-
def build
|
37
|
-
init_plugins
|
38
|
-
add_warmup_hook
|
39
|
-
add_middleware
|
40
|
-
@builder.run(application_proc)
|
41
|
-
@builder
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
# Add middleware to the builder.
|
47
|
-
def add_middleware
|
48
|
-
expand_middleware_list
|
49
|
-
@middleware.each do |ware|
|
50
|
-
klass, opts = ware
|
51
|
-
@application.inform_dev("Loading middleware #{klass} with settings #{opts.inspect}.")
|
52
|
-
@builder.use(*ware)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Add a list of urls to visit on startup
|
57
|
-
def add_warmup_hook
|
58
|
-
warmup_urls = Racket::Application.settings.warmup_urls
|
59
|
-
return if warmup_urls.empty?
|
60
|
-
@builder.warmup do |app|
|
61
|
-
client = Rack::MockRequest.new(app)
|
62
|
-
visit_warmup_urls(client, warmup_urls)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Returns a lambda that represenents that application flow.
|
67
|
-
def application_proc
|
68
|
-
application = @application
|
69
|
-
lambda do |env|
|
70
|
-
static_result = application.serve_static_file(env)
|
71
|
-
return static_result if static_result && static_result.first < 400
|
72
|
-
application.router.route(env)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Expands middleware list based on application settings.
|
77
|
-
def expand_middleware_list
|
78
|
-
session_handler = @settings.session_handler
|
79
|
-
default_content_type = @settings.default_content_type
|
80
|
-
@middleware.unshift(session_handler) if session_handler
|
81
|
-
@middleware.unshift([Rack::ContentType, default_content_type]) if default_content_type
|
82
|
-
@middleware.unshift([Rack::ShowExceptions]) if @application.dev_mode?
|
83
|
-
end
|
84
|
-
|
85
|
-
# Initializes plugins.
|
86
|
-
def init_plugins
|
87
|
-
@settings.plugins.each do |plugin_info|
|
88
|
-
plugin_instance = self.class.get_plugin_instance(*plugin_info)
|
89
|
-
run_plugin_hooks(plugin_instance)
|
90
|
-
# TODO: Store plugin instance somewhere in application settings
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Runs plugin hooks.
|
95
|
-
def run_plugin_hooks(plugin_obj)
|
96
|
-
@middleware.concat(plugin_obj.middleware)
|
97
|
-
@settings.default_controller_helpers.concat(plugin_obj.default_controller_helpers)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Visits a list of warmup URLs.
|
101
|
-
def visit_warmup_urls(client, urls)
|
102
|
-
urls.each do |url|
|
103
|
-
@application.inform_dev("Visiting warmup url #{url}.")
|
104
|
-
client.get(url)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Returns an instance of a specific plugin.
|
109
|
-
#
|
110
|
-
# @param [Symbol] plugin
|
111
|
-
# @param [Hash|nil] settings
|
112
|
-
# @return [Object] An instance of the requested plugin class
|
113
|
-
def self.get_plugin_instance(plugin, settings)
|
114
|
-
Utils.safe_require("racket/plugins/#{plugin}.rb")
|
115
|
-
# TODO: Allow custom plugins dir as well
|
116
|
-
klass =
|
117
|
-
Racket::Plugins.const_get(plugin.to_s.split('_').collect(&:capitalize).join.to_sym)
|
118
|
-
klass.new(settings)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Builds and returns a Rack::Builder using the provided Racket::Application
|
123
|
-
#
|
124
|
-
# @param [Racket::Application] application
|
125
|
-
# @return [Rack::Builder]
|
126
|
-
def self.build_application(application)
|
127
|
-
ApplicationBuilder.new(application).build
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
19
|
+
require_relative 'application/handler_stack.rb'
|
20
|
+
require_relative 'application/logger.rb'
|
21
|
+
require_relative 'application/registry_builder.rb'
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# Racket - The noisy Rack MVC framework
|
2
|
+
# Copyright (C) 2015-2016 Lars Olsson <lasso@lassoweb.se>
|
3
|
+
#
|
4
|
+
# This file is part of Racket.
|
5
|
+
#
|
6
|
+
# Racket is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Racket is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with Racket. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require 'ostruct'
|
20
|
+
|
21
|
+
module Racket
|
22
|
+
module Utils
|
23
|
+
module Application
|
24
|
+
# Class used for building a proper Rack application.
|
25
|
+
class HandlerStack
|
26
|
+
attr_reader :stack
|
27
|
+
|
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
|
+
lambda do |reg|
|
34
|
+
settings = reg.application_settings
|
35
|
+
|
36
|
+
options = {
|
37
|
+
default_content_type: settings.default_content_type,
|
38
|
+
default_controller_helpers: settings.default_controller_helpers,
|
39
|
+
dev_mode: settings.mode == :dev,
|
40
|
+
logger: reg.application_logger,
|
41
|
+
middleware: settings.middleware,
|
42
|
+
plugins: settings.plugins,
|
43
|
+
router: reg.router,
|
44
|
+
session_handler: settings.session_handler,
|
45
|
+
static_server: reg.static_server,
|
46
|
+
utils: reg.utils,
|
47
|
+
warmup_urls: settings.warmup_urls
|
48
|
+
}
|
49
|
+
|
50
|
+
new(options).stack
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(options)
|
55
|
+
@stack = Rack::Builder.new
|
56
|
+
@options = OpenStruct.new(options)
|
57
|
+
build
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Builds a Rack application representing Racket.
|
63
|
+
#
|
64
|
+
# @return [Proc]
|
65
|
+
def build
|
66
|
+
init_plugins
|
67
|
+
add_warmup_hook
|
68
|
+
add_middleware(@options.middleware)
|
69
|
+
@stack.run(application_proc)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Add middleware to the builder.
|
73
|
+
def add_middleware(middleware)
|
74
|
+
expand_middleware_list(middleware)
|
75
|
+
middleware.each do |ware|
|
76
|
+
klass, opts = ware
|
77
|
+
@options.logger.inform_dev("Loading middleware #{klass} with settings #{opts.inspect}.")
|
78
|
+
@stack.use(*ware)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add a list of urls to visit on startup
|
83
|
+
def add_warmup_hook
|
84
|
+
warmup_urls = @options.warmup_urls
|
85
|
+
return if warmup_urls.empty?
|
86
|
+
@stack.warmup do |app|
|
87
|
+
client = Rack::MockRequest.new(app)
|
88
|
+
visit_warmup_urls(client, warmup_urls)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns a lambda that represenents that application flow.
|
93
|
+
def application_proc
|
94
|
+
if (static_server = @options.static_server)
|
95
|
+
application_proc_with_static_server(static_server)
|
96
|
+
else
|
97
|
+
application_proc_without_static_server
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def application_proc_with_static_server(static_server)
|
102
|
+
router = @options.router
|
103
|
+
lambda do |env|
|
104
|
+
static_result = static_server.call(env)
|
105
|
+
return static_result if static_result && static_result.first < 400
|
106
|
+
router.route(env)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def application_proc_without_static_server
|
111
|
+
router = @options.router
|
112
|
+
->(env) { router.route(env) }
|
113
|
+
end
|
114
|
+
|
115
|
+
# Expands middleware list based on application settings.
|
116
|
+
def expand_middleware_list(middleware)
|
117
|
+
session_handler = @options.session_handler
|
118
|
+
default_content_type = @options.default_content_type
|
119
|
+
middleware.unshift(session_handler) if session_handler
|
120
|
+
middleware.unshift([Rack::ContentType, default_content_type]) if
|
121
|
+
default_content_type
|
122
|
+
middleware.unshift([Rack::ShowExceptions]) if @options.dev_mode
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns an instance of a specific plugin.
|
126
|
+
#
|
127
|
+
# @param [Symbol] plugin
|
128
|
+
# @param [Hash|nil] settings
|
129
|
+
# @return [Object] An instance of the requested plugin class
|
130
|
+
def get_plugin_instance(plugin, settings)
|
131
|
+
@options.utils.safe_require("racket/plugins/#{plugin}.rb")
|
132
|
+
# TODO: Allow custom plugins dir as well
|
133
|
+
klass =
|
134
|
+
Racket::Plugins.const_get(plugin.to_s.split('_').collect(&:capitalize).join.to_sym)
|
135
|
+
klass.new(settings)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Initializes plugins.
|
139
|
+
def init_plugins
|
140
|
+
@options.plugins.each do |plugin_info|
|
141
|
+
plugin_instance = get_plugin_instance(*plugin_info)
|
142
|
+
run_plugin_hooks(plugin_instance)
|
143
|
+
# TODO: Store plugin instance somewhere in application settings
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Runs plugin hooks.
|
148
|
+
def run_plugin_hooks(plugin_obj)
|
149
|
+
@options.middleware.concat(plugin_obj.middleware)
|
150
|
+
@options.default_controller_helpers.concat(plugin_obj.default_controller_helpers)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Visits a list of warmup URLs.
|
154
|
+
def visit_warmup_urls(client, urls)
|
155
|
+
urls.each do |url|
|
156
|
+
@options.logger.inform_dev("Visiting warmup url #{url}.")
|
157
|
+
client.get(url)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|