middleman-apps 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +2 -1
- data/Gemfile +4 -0
- data/{LICENSE.txt → LICENSE} +0 -0
- data/README.md +166 -40
- data/features/e_asset_hash.feature +17 -0
- data/features/{directory_indexes.feature → e_directory_indexes.feature} +14 -16
- data/features/e_relative_assets.feature +17 -0
- data/features/f_code_reloading.feature +134 -0
- data/features/f_metadata.feature +25 -0
- data/features/{not_found_rack.feature → f_not_found.feature} +12 -22
- data/features/f_options.feature +39 -0
- data/features/step_definitions/capybara_steps.rb +18 -0
- data/features/step_definitions/mechanize_steps.rb +19 -0
- data/features/step_definitions/rack_app_steps.rb +4 -2
- data/features/support/aruba.rb +22 -0
- data/features/support/env.rb +0 -14
- data/features/support/helpers.rb +11 -0
- data/features/support/mechanize.rb +32 -0
- data/features/support/poltegeist.rb +35 -0
- data/features/v_activating.feature +74 -0
- data/features/v_building.feature +31 -0
- data/features/v_inheriting_from.feature +38 -0
- data/fixtures/asset_hash/apps/ignored_app.rb +10 -0
- data/fixtures/asset_hash/apps/test_app.rb +11 -0
- data/fixtures/asset_hash/config.rb +2 -0
- data/fixtures/asset_hash/source/error.html.erb +2 -0
- data/fixtures/{complex-app → asset_hash}/source/index.html.erb +0 -0
- data/fixtures/asset_hash/source/layouts/layout.erb +12 -0
- data/fixtures/asset_hash/source/layouts/page.erb +6 -0
- data/fixtures/asset_hash/source/stylesheets/style.css.scss.erb +5 -0
- data/fixtures/dir_index/apps/ignored_app.rb +10 -0
- data/fixtures/dir_index/apps/test_app.rb +10 -0
- data/fixtures/dir_index/config.rb +2 -0
- data/fixtures/{simple-app → dir_index}/source/index.html.erb +0 -0
- data/fixtures/mount_path/apps/test_app.rb +10 -0
- data/fixtures/mount_path/config.rb +1 -0
- data/fixtures/{complex-app/build/index.html → mount_path/source/index.html.erb} +0 -0
- data/fixtures/real_world/apps/awesome_api.rb +40 -0
- data/fixtures/{complex-app → real_world}/apps/child_app.rb +15 -2
- data/fixtures/{complex-app/apps/test_app.rb → real_world/apps/ignored_app.rb} +2 -2
- data/fixtures/real_world/apps/no_namespace.rb +8 -0
- data/fixtures/real_world/apps/test_app.rb +16 -0
- data/fixtures/real_world/config.rb +13 -0
- data/fixtures/real_world/source/apps.html.erb +14 -0
- data/fixtures/real_world/source/custom.html.erb +1 -0
- data/fixtures/{simple-app/build/index.html → real_world/source/index.html.erb} +0 -0
- data/fixtures/real_world/source/layouts/_partial.erb +1 -0
- data/fixtures/real_world/source/layouts/layout.erb +11 -0
- data/fixtures/real_world/source/layouts/page.erb +6 -0
- data/fixtures/real_world/source/layouts/test.html.markdown.erb +3 -0
- data/fixtures/relative_assets/apps/ignored_app.rb +10 -0
- data/fixtures/relative_assets/apps/test_app.rb +11 -0
- data/fixtures/relative_assets/config.rb +2 -0
- data/fixtures/relative_assets/source/error.html.erb +2 -0
- data/fixtures/relative_assets/source/index.html.erb +2 -0
- data/fixtures/relative_assets/source/layouts/layout.erb +12 -0
- data/fixtures/relative_assets/source/layouts/page.erb +6 -0
- data/fixtures/relative_assets/source/stylesheets/style.css.scss.erb +5 -0
- data/fixtures/simple/apps/ignored_app.rb +10 -0
- data/fixtures/simple/apps/test_app.rb +10 -0
- data/fixtures/simple/config.rb +1 -0
- data/fixtures/simple/source/index.html.erb +2 -0
- data/lib/middleman/apps.rb +26 -7
- data/lib/middleman/apps/base.rb +71 -15
- data/lib/middleman/apps/extension.rb +34 -158
- data/lib/middleman/apps/version.rb +2 -1
- data/lib/middleman/sitemap/app_collection.rb +225 -0
- data/lib/middleman/sitemap/app_resource.rb +61 -0
- metadata +77 -31
- data/features/activation.feature +0 -53
- data/features/build.feature +0 -20
- data/features/child_app.feature +0 -18
- data/features/complex_app.feature +0 -66
- data/features/not_found_server.feature +0 -8
- data/features/verbose.feature +0 -23
- data/fixtures/complex-app/apps/awesome_api.rb +0 -11
- data/fixtures/complex-app/build/error.html +0 -1
- data/fixtures/complex-app/config.rb +0 -1
- data/fixtures/simple-app/apps/test_app.rb +0 -8
- data/fixtures/simple-app/build/error.html +0 -1
- data/fixtures/simple-app/config.rb +0 -1
data/lib/middleman/apps/base.rb
CHANGED
@@ -1,35 +1,91 @@
|
|
1
1
|
require 'sinatra'
|
2
|
+
require 'middleman/apps'
|
2
3
|
|
3
4
|
module Middleman
|
4
5
|
module Apps
|
5
6
|
# Base application class for creating child applications.
|
6
7
|
#
|
7
|
-
# Inheriting from this class
|
8
|
-
#
|
8
|
+
# Inheriting from this class provides better integration with the static
|
9
|
+
# middleman app.
|
9
10
|
#
|
10
11
|
class Base < ::Sinatra::Base
|
11
|
-
#
|
12
|
+
# @!attribute [r] static
|
13
|
+
# Serve static assets from #public_folder, if found
|
14
|
+
set :static, true
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
#
|
16
|
+
set :environment, (ENV['RACK_ENV'] || 'development').to_sym
|
17
|
+
|
18
|
+
# @!attribute [r] mm_app
|
19
|
+
# Middleman Application instance for references to config, sitemap, etc.
|
20
|
+
#
|
21
|
+
# Lazily evaluated since this is a bit costly.
|
22
|
+
#
|
23
|
+
set :mm_app, Middleman::Apps.middleman_app
|
24
|
+
|
25
|
+
# @!attribute [r] views
|
26
|
+
# Path to the directory containing our layout files.
|
27
|
+
set :views, File.join(settings.mm_app.root, 'source', 'layouts')
|
28
|
+
|
29
|
+
configure :production do
|
30
|
+
# @!attribute [r] public_folder
|
31
|
+
# Path to the directory containing our layout files.
|
32
|
+
set :public_folder, File.join(settings.mm_app.root, 'build')
|
33
|
+
end
|
34
|
+
|
35
|
+
configure :development do
|
36
|
+
set :show_exceptions, true
|
37
|
+
set :public_folder, File.join(settings.mm_app.root, 'source')
|
38
|
+
end
|
17
39
|
|
18
40
|
not_found do
|
19
|
-
|
41
|
+
status 404
|
42
|
+
Middleman::Apps.not_found(settings.mm_app)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.app_resource
|
46
|
+
Middleman::Apps.find_app_resource_for(self, settings.mm_app)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.metadata
|
50
|
+
res = app_resource
|
51
|
+
data = res ? res.locals : {}
|
52
|
+
keys = %i[routes html_description]
|
53
|
+
data = keys.map { |key| [key, res.send(key)] }.to_h.merge(data) if res
|
54
|
+
Hashie::Mash.new(data)
|
55
|
+
rescue NameError
|
56
|
+
data
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.set_metadata(key, val, overwrite: false)
|
60
|
+
return if !overwrite && settings.respond_to?("app_#{key}")
|
61
|
+
set "app_#{key}", val
|
62
|
+
app_resource && app_resource.update_locals(key, val)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.add_routes_to_metadata(*verbs)
|
66
|
+
verbs = %i[get post put patch delete] if verbs.empty?
|
67
|
+
app_routes = verbs.map do |verb|
|
68
|
+
(routes[verb.to_s.upcase] || []).map do |route|
|
69
|
+
"##{verb.to_s.upcase} #{route[0]}"
|
70
|
+
end
|
71
|
+
end.flatten
|
72
|
+
set_metadata :routes, app_routes, overwrite: true
|
20
73
|
end
|
21
74
|
|
22
75
|
protected
|
23
76
|
|
24
|
-
def
|
25
|
-
|
77
|
+
def metadata
|
78
|
+
self.class.metadata
|
26
79
|
end
|
27
80
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
81
|
+
# Render a MM layout with the given name.
|
82
|
+
#
|
83
|
+
def middleman_layout(name, opts = {})
|
84
|
+
locs = opts.delete(:locals) || {}
|
85
|
+
opts[:layout] ||= name
|
86
|
+
|
87
|
+
res = self.class.app_resource
|
88
|
+
res.render(opts, res.locals.merge(locs))
|
33
89
|
end
|
34
90
|
end
|
35
91
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'middleman-core'
|
2
3
|
require 'middleman-core/load_paths'
|
3
4
|
|
@@ -11,6 +12,10 @@ module Middleman
|
|
11
12
|
# Usage examples can be seen in README for this extension.
|
12
13
|
#
|
13
14
|
class Extension < ::Middleman::Extension
|
15
|
+
extend Forwardable
|
16
|
+
attr_reader :collection
|
17
|
+
def_delegators :@collection, :apps_list
|
18
|
+
expose_to_template :apps_list
|
14
19
|
|
15
20
|
# @!group Options for Extension
|
16
21
|
|
@@ -22,6 +27,9 @@ module Middleman
|
|
22
27
|
option :namespace, nil, 'Namespace for the child apps'
|
23
28
|
option :map, {}, 'Mappings for differently named child apps'
|
24
29
|
option :verbose, false, 'Displays list of child apps that were ignored'
|
30
|
+
option :mount_path, '/', 'Root mount path for child apps'
|
31
|
+
option :app_dir, ENV['MM_APPS_DIR'] || 'apps',
|
32
|
+
'The directory child apps are stored in'
|
25
33
|
|
26
34
|
# @!endgroup
|
27
35
|
|
@@ -29,61 +37,11 @@ module Middleman
|
|
29
37
|
super
|
30
38
|
# useful for converting file names to ruby classes
|
31
39
|
require 'active_support/core_ext/string/inflections'
|
32
|
-
|
33
|
-
|
34
|
-
# Mount all child apps on a specific Rack app (or current app)
|
35
|
-
#
|
36
|
-
# @param [Rack::App] rack_app app on which to mount child apps
|
37
|
-
# Default: app from MM configuration
|
38
|
-
#
|
39
|
-
# @return [Rack::App] rack_app with child apps mounted on top
|
40
|
-
#
|
41
|
-
def mount_child_apps(rack_app = nil)
|
42
|
-
rack_app ||= app
|
43
|
-
child_apps.each do |url, klass|
|
44
|
-
rack_app.map(url) { run klass }
|
45
|
-
end
|
46
|
-
rack_app
|
47
|
-
end
|
48
|
-
|
49
|
-
# Get a hash of all child applications URLs paths matched to corresponding
|
50
|
-
# Ruby classes.
|
51
|
-
#
|
52
|
-
# Warning is raised (if `verbose` option is `true`) when a child app was
|
53
|
-
# found, but could not be mapped due to the specified config.
|
54
|
-
#
|
55
|
-
# @return [Hash] - child application URL vs Ruby class
|
56
|
-
#
|
57
|
-
def child_apps
|
58
|
-
apps_list.map do |mapp|
|
59
|
-
require mapp
|
60
|
-
klass = get_application_class_for(mapp)
|
61
|
-
warn "Ignored child app: #{mapp}" unless klass
|
62
|
-
[get_application_url_for(mapp), klass] if klass
|
63
|
-
end.compact.to_h
|
64
|
-
end
|
65
|
-
|
66
|
-
# Get a Rack::App that can serve the MM app's build directory.
|
67
|
-
#
|
68
|
-
# Directory paths, and 404 error page are deduced from extensions' options.
|
69
|
-
#
|
70
|
-
# @return [Rack::App] Rack::TryStatic app for MM app's build directory.
|
71
|
-
#
|
72
|
-
def middleman_static_app
|
73
|
-
not_found = options.not_found
|
74
|
-
return create_static_app(root) unless not_found
|
75
|
-
|
76
|
-
not_found_path = File.join(build_dir, find_resource(not_found))
|
77
|
-
create_static_app build_dir, not_found_path
|
78
|
-
end
|
40
|
+
require 'middleman/sitemap/app_resource'
|
41
|
+
require 'middleman/sitemap/app_collection'
|
79
42
|
|
80
|
-
|
81
|
-
|
82
|
-
def apps_list
|
83
|
-
pattern = File.join(app.root, 'apps', '*.rb')
|
84
|
-
Dir[pattern].map do |file|
|
85
|
-
File.realpath(file) if File.file?(file)
|
86
|
-
end.compact
|
43
|
+
# get a reference to all the apps
|
44
|
+
@collection = Sitemap::AppCollection.new(app, self, options)
|
87
45
|
end
|
88
46
|
|
89
47
|
# Run `after_configuration` hook passed on by MM
|
@@ -99,8 +57,27 @@ module Middleman
|
|
99
57
|
#
|
100
58
|
def after_configuration
|
101
59
|
create_config_ru
|
60
|
+
return if app.build?
|
61
|
+
|
62
|
+
app.sitemap.register_resource_list_manipulator(:child_apps, @collection)
|
102
63
|
return unless app.server?
|
103
|
-
|
64
|
+
|
65
|
+
watch_child_apps
|
66
|
+
@collection.mount_child_apps(app)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Set a watcher to reload MM when files change in the directory for the
|
70
|
+
# child apps.
|
71
|
+
#
|
72
|
+
# @return [nil]
|
73
|
+
#
|
74
|
+
def watch_child_apps
|
75
|
+
# Make sure it exists, or `listen` will explode.
|
76
|
+
app_path = File.expand_path(options.app_dir, app.root)
|
77
|
+
::FileUtils.mkdir_p(app_path)
|
78
|
+
watcher = app.files.watch :reload, path: app_path, only: /\.rb$/
|
79
|
+
list = @collection
|
80
|
+
watcher.on_change { list.mount_child_apps(app) }
|
104
81
|
end
|
105
82
|
|
106
83
|
# Create a `config.ru` file, if one does not exist, yet.
|
@@ -117,115 +94,14 @@ module Middleman
|
|
117
94
|
path = File.join(app.root, 'config.ru')
|
118
95
|
return if File.exist?(path)
|
119
96
|
|
120
|
-
content = <<-CONTENT.gsub(/^ {
|
121
|
-
ENV['RACK_ENV']
|
97
|
+
content = <<-CONTENT.gsub(/^ {8}/, '')
|
98
|
+
ENV['RACK_ENV'] ||= 'production'
|
122
99
|
require 'middleman/apps'
|
123
100
|
run Middleman::Apps.rack_app
|
124
101
|
CONTENT
|
125
102
|
|
126
103
|
File.open(path, 'wb') { |file| file.puts content }
|
127
104
|
end
|
128
|
-
|
129
|
-
# Create a Rack::TryStatic application for the given directory root.
|
130
|
-
#
|
131
|
-
# @param [String] root - path to directory root
|
132
|
-
# @param [String] path - path to not found error page
|
133
|
-
# If not provided, default 404 response from Rack
|
134
|
-
# is served.
|
135
|
-
#
|
136
|
-
# @return [Rack::App] static app for the `root` directory
|
137
|
-
#
|
138
|
-
# @api private
|
139
|
-
#
|
140
|
-
def create_static_app(root, path = nil)
|
141
|
-
unless File.exist?(path)
|
142
|
-
warn("Could not find: #{path}")
|
143
|
-
path = nil
|
144
|
-
end
|
145
|
-
|
146
|
-
# require 'rack/contrib'
|
147
|
-
require 'middleman/apps/rack_contrib'
|
148
|
-
::Rack::Builder.new do
|
149
|
-
use ::Rack::TryStatic, urls: ['/'], root: root,
|
150
|
-
try: ['.html', 'index.html', '/index.html']
|
151
|
-
run ::Rack::NotFound.new(path)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# Find a resource given its path, destination path, or page_id.
|
156
|
-
#
|
157
|
-
# @param [String] name - identifier for this resource
|
158
|
-
# @return [String] relative path to resource
|
159
|
-
#
|
160
|
-
# @api private
|
161
|
-
#
|
162
|
-
def find_resource(name)
|
163
|
-
sitemap = app.sitemap
|
164
|
-
resource = sitemap.find_resource_by_path(name)
|
165
|
-
resource ||= sitemap.find_resource_by_destination_path(name)
|
166
|
-
resource ||= sitemap.find_resource_by_page_id(name)
|
167
|
-
resource ? resource.destination_path : name
|
168
|
-
end
|
169
|
-
|
170
|
-
private
|
171
|
-
|
172
|
-
# Warn user about message if `verbose` option is on.
|
173
|
-
#
|
174
|
-
# @param [String] message - message to display
|
175
|
-
#
|
176
|
-
# @private
|
177
|
-
# @api private
|
178
|
-
#
|
179
|
-
def warn(message)
|
180
|
-
logger.warn(message) if logger && options.verbose
|
181
|
-
end
|
182
|
-
|
183
|
-
# Get path to MM's build dir.
|
184
|
-
#
|
185
|
-
# @return [String] path to build dir
|
186
|
-
#
|
187
|
-
def build_dir
|
188
|
-
File.expand_path(app.config.build_dir.to_s)
|
189
|
-
end
|
190
|
-
|
191
|
-
# Convert options data to a hash for easy searches.
|
192
|
-
#
|
193
|
-
# @api private
|
194
|
-
# @return [Hash] options data
|
195
|
-
#
|
196
|
-
def mappings
|
197
|
-
options.map.map { |key, val| [key.to_s, val] }.to_h
|
198
|
-
end
|
199
|
-
|
200
|
-
# Get URL at which given child app should be mounted.
|
201
|
-
#
|
202
|
-
# @api private
|
203
|
-
# @param [String] file - path to child app
|
204
|
-
# @return [String] url component for the child app
|
205
|
-
#
|
206
|
-
def get_application_url_for(file)
|
207
|
-
name = File.basename(file, '.rb')
|
208
|
-
url = mappings[name]
|
209
|
-
url = url[:url] if url.is_a?(Hash)
|
210
|
-
'/' + (url ? url.to_s.gsub(%r{^\/}, '') : name.titleize.parameterize)
|
211
|
-
end
|
212
|
-
|
213
|
-
# Get Application Class for the child app.
|
214
|
-
#
|
215
|
-
# @api private
|
216
|
-
# @param [String] file - path to child app
|
217
|
-
# @return [Class, nil] Class for the child app, if exists.
|
218
|
-
#
|
219
|
-
def get_application_class_for(file)
|
220
|
-
name = File.basename(file, '.rb')
|
221
|
-
namespace = options.namespace
|
222
|
-
|
223
|
-
klass = mappings[name][:class] if mappings[name].is_a?(Hash)
|
224
|
-
klass ||= namespace ? "#{namespace}/#{name}" : name
|
225
|
-
klass.to_s.classify.constantize
|
226
|
-
rescue NameError
|
227
|
-
return nil
|
228
|
-
end
|
229
105
|
end
|
230
106
|
end
|
231
107
|
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module Middleman
|
2
|
+
module Sitemap
|
3
|
+
# Resource manipulator class that handles list of all our child app
|
4
|
+
# resources.
|
5
|
+
#
|
6
|
+
# To evaluate anything in the context of an instance of this class, use:
|
7
|
+
#
|
8
|
+
# Middleman::Apps.with_app_list do
|
9
|
+
# apps_list # => this will be returned by the block
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
class AppCollection
|
13
|
+
def initialize(app, _extension, options = {})
|
14
|
+
@app = app
|
15
|
+
@options = options
|
16
|
+
@sitemap = app.sitemap
|
17
|
+
@app_dir = app.root_path.join(options.app_dir)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add our child apps to the list of resources managed by MM.
|
21
|
+
#
|
22
|
+
# @param [Array<Middleman::Sitemap::Resource>] resources - resource list
|
23
|
+
# @return [Array<Middleman::Sitemap::Resource>] updated resource list
|
24
|
+
#
|
25
|
+
def manipulate_resource_list(resources)
|
26
|
+
resources + apps_list
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get a list of all child app resources found in child apps directory.
|
30
|
+
#
|
31
|
+
# All child apps will be reloaded everytime this method is called.
|
32
|
+
#
|
33
|
+
# @return [Array<Middleman::Sitemap::AppResource>] array of child apps
|
34
|
+
#
|
35
|
+
def apps_list
|
36
|
+
Dir[@app_dir.join('*.rb').to_s].map do |file|
|
37
|
+
path = Pathname.new(file)
|
38
|
+
resource = create_app(path) if path.file?
|
39
|
+
warn "Ignored child app: #{path}" unless resource
|
40
|
+
resource
|
41
|
+
end.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create or reload child app resource for each found child app.
|
45
|
+
#
|
46
|
+
# @param [String] path to the child app source file
|
47
|
+
# @return [Middleman::Sitemap::AppResource] app resource
|
48
|
+
#
|
49
|
+
def create_app(path)
|
50
|
+
reload_resource_at path
|
51
|
+
url = get_application_url_for(path)
|
52
|
+
klass = get_application_class_for(path)
|
53
|
+
return unless klass
|
54
|
+
|
55
|
+
source = get_source_file(path, @app_dir, :app)
|
56
|
+
title = (klass || url).to_s.titleize
|
57
|
+
AppResource.new(@sitemap, url.gsub(%r{^\/}, ''), source).tap do |p|
|
58
|
+
p.add_metadata locals: { url: url, klass: klass, title: title }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Mount all child apps on a specific Rack app (or current app)
|
63
|
+
#
|
64
|
+
# Warning is raised (if `verbose` option is `true`) when a child app was
|
65
|
+
# found, but could not be mapped due to the specified config.
|
66
|
+
#
|
67
|
+
# @param [Rack::App] rack_app app on which to mount child apps
|
68
|
+
# Default: app from MM configuration
|
69
|
+
#
|
70
|
+
# @return [Rack::App] rack_app with child apps mounted on top
|
71
|
+
#
|
72
|
+
def mount_child_apps(rack_app = nil)
|
73
|
+
rack_app ||= @app
|
74
|
+
apps_list.each do |res|
|
75
|
+
rack_app.map(res.url) { run res.klass } if res.klass
|
76
|
+
end
|
77
|
+
rack_app
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get a Rack::App that can serve the MM app's build directory.
|
81
|
+
#
|
82
|
+
# Directory paths, and 404 error page are deduced from extensions'
|
83
|
+
# options.
|
84
|
+
#
|
85
|
+
# @return [Rack::App] Rack::TryStatic app for MM app's build directory.
|
86
|
+
#
|
87
|
+
def middleman_static_app
|
88
|
+
not_found = @options.not_found
|
89
|
+
return create_static_app(build_dir) unless not_found
|
90
|
+
|
91
|
+
not_found_path = File.join(build_dir, find_resource(not_found))
|
92
|
+
create_static_app build_dir, not_found_path
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
# Create a Rack::TryStatic application for the given directory root.
|
98
|
+
#
|
99
|
+
# @param [String] root - path to directory root
|
100
|
+
# @param [String] path - path to not found error page
|
101
|
+
# If not provided, default 404 response from Rack
|
102
|
+
# is served.
|
103
|
+
#
|
104
|
+
# @return [Rack::App] static app for the `root` directory
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
#
|
108
|
+
def create_static_app(root, path = nil)
|
109
|
+
unless File.exist?(path)
|
110
|
+
warn("Could not find: #{path}")
|
111
|
+
path = nil
|
112
|
+
end
|
113
|
+
|
114
|
+
# require 'rack/contrib'
|
115
|
+
require 'middleman/apps/rack_contrib'
|
116
|
+
::Rack::Builder.new do
|
117
|
+
use ::Rack::TryStatic, urls: ['/'], root: root,
|
118
|
+
try: ['.html', 'index.html', '/index.html']
|
119
|
+
run ::Rack::NotFound.new(path)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Find a resource given its path, destination path, or page_id.
|
124
|
+
#
|
125
|
+
# @param [String] name - identifier for this resource
|
126
|
+
# @return [String] relative path to resource
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
#
|
130
|
+
def find_resource(name)
|
131
|
+
sitemap = @app.sitemap
|
132
|
+
resource = sitemap.find_resource_by_path(name)
|
133
|
+
resource ||= sitemap.find_resource_by_destination_path(name)
|
134
|
+
resource ||= sitemap.find_resource_by_page_id(name)
|
135
|
+
resource ? resource.destination_path : name
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
# Warn user about message if `verbose` option is on.
|
141
|
+
#
|
142
|
+
# @param [String] message - message to display
|
143
|
+
#
|
144
|
+
# @private
|
145
|
+
# @api private
|
146
|
+
#
|
147
|
+
def warn(message)
|
148
|
+
@app.logger.warn(message) if @app.logger && @options.verbose
|
149
|
+
end
|
150
|
+
|
151
|
+
# Get path to MM's build dir.
|
152
|
+
#
|
153
|
+
# @return [String] path to build dir
|
154
|
+
#
|
155
|
+
def build_dir
|
156
|
+
@app.root_path.join(@app.config.build_dir.to_s)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Convert options data to a hash for easy searches.
|
160
|
+
#
|
161
|
+
# @api private
|
162
|
+
# @return [Hash] options data
|
163
|
+
#
|
164
|
+
def mappings
|
165
|
+
@options.map.map { |key, val| [key.to_s, val] }.to_h
|
166
|
+
end
|
167
|
+
|
168
|
+
# Get URL at which given child app should be mounted.
|
169
|
+
#
|
170
|
+
# @api private
|
171
|
+
# @param [String] path - path to child app
|
172
|
+
# @return [String] url component for the child app
|
173
|
+
#
|
174
|
+
def get_application_url_for(path)
|
175
|
+
name = path.basename('.rb').to_s
|
176
|
+
url = mappings[name]
|
177
|
+
url = url[:url] if url.is_a?(Hash)
|
178
|
+
url ||= name.to_s.titleize.parameterize
|
179
|
+
"#{@options.mount_path}/#{url}".gsub(%r{\/+}, '/')
|
180
|
+
end
|
181
|
+
|
182
|
+
# Get Application Class for the child app.
|
183
|
+
#
|
184
|
+
# @api private
|
185
|
+
# @param [String] path - path to child app
|
186
|
+
# @return [Class, nil] Class for the child app, if exists.
|
187
|
+
#
|
188
|
+
def get_application_class_for(path)
|
189
|
+
name = path.basename('.rb').to_s
|
190
|
+
namespace = @options.namespace
|
191
|
+
|
192
|
+
klass = mappings[name][:class] if mappings[name].is_a?(Hash)
|
193
|
+
klass ||= namespace ? "#{namespace}/#{name}" : name
|
194
|
+
klass.to_s.classify.safe_constantize
|
195
|
+
end
|
196
|
+
|
197
|
+
# Get SourceFile instance from the given path.
|
198
|
+
#
|
199
|
+
# @api private
|
200
|
+
# @param [String] path - path to the source file
|
201
|
+
# @return [Middleman::SourceFile]
|
202
|
+
def get_source_file(path, dir, name)
|
203
|
+
::Middleman::SourceFile.new(path.relative_path_from(dir),
|
204
|
+
path, path.dirname.to_s, Set.new([name]), 0)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Reload resource at a given file path
|
208
|
+
#
|
209
|
+
# @api private
|
210
|
+
# @param [String] path - path to the source file
|
211
|
+
# @return [nil]
|
212
|
+
#
|
213
|
+
def reload_resource_at(path)
|
214
|
+
if $LOADED_FEATURES.include?(path.to_s)
|
215
|
+
klass = get_application_class_for(path)
|
216
|
+
container = klass.to_s.deconstantize.safe_constantize || Object
|
217
|
+
container.send(:remove_const, klass.to_s.demodulize) if klass
|
218
|
+
$LOADED_FEATURES.delete(path.to_s)
|
219
|
+
end
|
220
|
+
|
221
|
+
require path
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|