middleman-core 4.0.0.alpha.6 → 4.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/features/asset_hash.feature +8 -1
- data/features/asset_host.feature +2 -13
- data/features/builder.feature +0 -2
- data/features/cli_init.feature +32 -0
- data/features/collections.feature +50 -0
- data/features/directory_index.feature +4 -5
- data/features/front-matter-neighbor.feature +20 -0
- data/features/helpers_link_to.feature +18 -0
- data/features/image_srcset_paths.feature +7 -0
- data/features/markdown_kramdown_in_haml.feature +2 -1
- data/features/minify_javascript.feature +1 -1
- data/features/multiple-sources.feature +8 -0
- data/fixtures/asset-hash-app/source/slim.html.slim +8 -0
- data/fixtures/asset-hash-app/source/subdir/index.html.erb +10 -1
- data/fixtures/asset-host-app/source/asset_host.html.erb +23 -1
- data/fixtures/collections-app/source/blog2/2011-01-01-new-article.html.markdown +2 -0
- data/fixtures/frontmatter-settings-neighbor-app/config.rb +19 -14
- data/fixtures/image-srcset-paths-app/image-srcset-paths.html.erb +1 -0
- data/fixtures/image-srcset-paths-app/images/blank.gif +0 -0
- data/fixtures/indexable-app/source/evil spaces.html +1 -1
- data/fixtures/large-build-app/config.rb +2 -0
- data/fixtures/large-build-app/source/spaces in file.html.erb +1 -1
- data/fixtures/more-traversal-app/source/layout.erb +1 -1
- data/fixtures/multiple-sources-with-duplicate-file-names-app/config.rb +2 -0
- data/fixtures/multiple-sources-with-duplicate-file-names-app/source/index.html.erb +1 -0
- data/fixtures/multiple-sources-with-duplicate-file-names-app/source2/index.html.erb +1 -0
- data/fixtures/traversal-app/source/.htaccess +0 -0
- data/fixtures/traversal-app/source/layout.erb +1 -1
- data/lib/middleman/rack.rb +1 -0
- data/lib/middleman-core/application.rb +15 -15
- data/lib/middleman-core/builder.rb +11 -7
- data/lib/middleman-core/cli/server.rb +86 -0
- data/lib/middleman-core/config_context.rb +1 -1
- data/lib/middleman-core/contracts.rb +0 -32
- data/lib/middleman-core/core_extensions/collections.rb +19 -17
- data/lib/middleman-core/core_extensions/data.rb +15 -17
- data/lib/middleman-core/core_extensions/default_helpers.rb +22 -1
- data/lib/middleman-core/core_extensions/file_watcher.rb +9 -7
- data/lib/middleman-core/core_extensions/front_matter.rb +2 -2
- data/lib/middleman-core/core_extensions/i18n.rb +11 -9
- data/lib/middleman-core/core_extensions/routing.rb +3 -4
- data/lib/middleman-core/extension.rb +179 -0
- data/lib/middleman-core/extension_manager.rb +8 -7
- data/lib/middleman-core/extensions/asset_hash.rb +14 -9
- data/lib/middleman-core/extensions/asset_host.rb +3 -1
- data/lib/middleman-core/extensions/gzip.rb +3 -2
- data/lib/middleman-core/extensions/lorem.rb +2 -2
- data/lib/middleman-core/extensions/relative_assets.rb +11 -5
- data/lib/middleman-core/file_renderer.rb +2 -2
- data/lib/middleman-core/logger.rb +1 -1
- data/lib/middleman-core/middleware/inline_url_rewriter.rb +9 -4
- data/lib/middleman-core/preview_server.rb +13 -9
- data/lib/middleman-core/rack.rb +2 -1
- data/lib/middleman-core/renderers/haml.rb +6 -0
- data/lib/middleman-core/renderers/kramdown.rb +1 -1
- data/lib/middleman-core/renderers/redcarpet.rb +1 -0
- data/lib/middleman-core/renderers/sass.rb +1 -1
- data/lib/middleman-core/renderers/slim.rb +1 -0
- data/lib/middleman-core/sitemap/extensions/ignores.rb +7 -4
- data/lib/middleman-core/sitemap/extensions/on_disk.rb +1 -1
- data/lib/middleman-core/sitemap/extensions/proxies.rb +13 -10
- data/lib/middleman-core/sitemap/extensions/redirects.rb +8 -7
- data/lib/middleman-core/sitemap/extensions/request_endpoints.rb +7 -6
- data/lib/middleman-core/sitemap/extensions/traversal.rb +3 -1
- data/lib/middleman-core/sitemap/resource.rb +14 -15
- data/lib/middleman-core/sitemap/store.rb +6 -5
- data/lib/middleman-core/sources/source_watcher.rb +29 -16
- data/lib/middleman-core/sources.rb +19 -21
- data/lib/middleman-core/step_definitions/builder_steps.rb +1 -1
- data/lib/middleman-core/step_definitions/server_steps.rb +3 -3
- data/lib/middleman-core/template_context.rb +8 -7
- data/lib/middleman-core/template_renderer.rb +2 -2
- data/lib/middleman-core/util.rb +57 -21
- data/lib/middleman-core/version.rb +1 -1
- data/lib/middleman-core.rb +2 -1
- data/middleman-core.gemspec +4 -1
- data/spec/middleman-core/core_extensions/data_spec.rb +41 -0
- data/spec/middleman-core/util_spec.rb +96 -0
- metadata +38 -8
- data/lib/middleman-core/util/hash_with_indifferent_access.rb +0 -103
- data/spec/middleman-core/binary_spec.rb +0 -15
- data/spec/middleman-core/path_match_spec.rb +0 -37
@@ -7,12 +7,15 @@ module Middleman
|
|
7
7
|
# Manages the list of proxy configurations and manipulates the sitemap
|
8
8
|
# to include new resources based on those configurations
|
9
9
|
class Proxies < Extension
|
10
|
+
# Expose `create_proxy` as `app.proxy`
|
11
|
+
expose_to_application proxy: :create_proxy
|
12
|
+
|
13
|
+
# Expose `create_proxy` to config as `proxy`
|
14
|
+
expose_to_config proxy: :create_proxy
|
15
|
+
|
10
16
|
def initialize(app, config={}, &block)
|
11
17
|
super
|
12
18
|
|
13
|
-
@app.add_to_config_context(:proxy, &method(:create_proxy))
|
14
|
-
@app.define_singleton_method(:proxy, &method(:create_proxy))
|
15
|
-
|
16
19
|
@proxy_configs = Set.new
|
17
20
|
@post_config = false
|
18
21
|
end
|
@@ -71,10 +74,10 @@ module Middleman
|
|
71
74
|
ProxyResource.new(app.sitemap, path, target).tap do |p|
|
72
75
|
md = metadata.dup
|
73
76
|
p.add_metadata(
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
locals: md.delete(:locals) || {},
|
78
|
+
page: md.delete(:data) || {},
|
79
|
+
options: md
|
80
|
+
)
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
@@ -96,7 +99,7 @@ module Middleman
|
|
96
99
|
# The resource for the page this page is proxied to. Throws an exception
|
97
100
|
# if there is no resource.
|
98
101
|
# @return [Sitemap::Resource]
|
99
|
-
Contract
|
102
|
+
Contract IsA['Middleman::Sitemap::Resource']
|
100
103
|
def target_resource
|
101
104
|
resource = @store.find_resource_by_path(@target)
|
102
105
|
|
@@ -111,12 +114,12 @@ module Middleman
|
|
111
114
|
resource
|
112
115
|
end
|
113
116
|
|
114
|
-
Contract
|
117
|
+
Contract IsA['Middleman::SourceFile']
|
115
118
|
def source_file
|
116
119
|
target_resource.source_file
|
117
120
|
end
|
118
121
|
|
119
|
-
Contract
|
122
|
+
Contract Maybe[String]
|
120
123
|
def content_type
|
121
124
|
mime_type = super
|
122
125
|
return mime_type if mime_type
|
@@ -7,18 +7,19 @@ module Middleman
|
|
7
7
|
# Manages the list of proxy configurations and manipulates the sitemap
|
8
8
|
# to include new resources based on those configurations
|
9
9
|
class Redirects < Extension
|
10
|
+
# Expose `create_redirect` to config as `redirect`
|
11
|
+
expose_to_config redirect: :create_redirect
|
12
|
+
|
10
13
|
def initialize(app, config={}, &block)
|
11
14
|
super
|
12
15
|
|
13
|
-
@app.add_to_config_context(:redirect, &method(:create_redirect))
|
14
|
-
|
15
16
|
@redirects = {}
|
16
17
|
end
|
17
18
|
|
18
19
|
# Setup a redirect from a path to a target
|
19
20
|
# @param [String] path
|
20
21
|
# @param [Hash] opts The :to value gives a target path
|
21
|
-
Contract String, ({ to: Or[String, IsA['Middleman::Sitemap::Resource']] }), Proc => Any
|
22
|
+
Contract String, ({ to: Or[String, IsA['Middleman::Sitemap::Resource']] }), Maybe[Proc] => Any
|
22
23
|
def create_redirect(path, opts={}, &block)
|
23
24
|
opts[:template] = block if block_given?
|
24
25
|
|
@@ -44,7 +45,7 @@ module Middleman
|
|
44
45
|
end
|
45
46
|
|
46
47
|
class RedirectResource < ::Middleman::Sitemap::Resource
|
47
|
-
Contract
|
48
|
+
Contract Maybe[Proc]
|
48
49
|
attr_accessor :output
|
49
50
|
|
50
51
|
def initialize(store, path, target)
|
@@ -53,7 +54,7 @@ module Middleman
|
|
53
54
|
super(store, path)
|
54
55
|
end
|
55
56
|
|
56
|
-
Contract
|
57
|
+
Contract Bool
|
57
58
|
def template?
|
58
59
|
true
|
59
60
|
end
|
@@ -63,7 +64,7 @@ module Middleman
|
|
63
64
|
url = ::Middleman::Util.url_for(@store.app, @request_path,
|
64
65
|
relative: false,
|
65
66
|
find_resource: true
|
66
|
-
|
67
|
+
)
|
67
68
|
|
68
69
|
if output
|
69
70
|
output.call(path, url)
|
@@ -82,7 +83,7 @@ module Middleman
|
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
Contract
|
86
|
+
Contract Bool
|
86
87
|
def ignored?
|
87
88
|
false
|
88
89
|
end
|
@@ -4,13 +4,14 @@ module Middleman
|
|
4
4
|
module Sitemap
|
5
5
|
module Extensions
|
6
6
|
class RequestEndpoints < Extension
|
7
|
+
# Expose `create_endpoint` to config as `endpoint`
|
8
|
+
expose_to_config endpoint: :create_endpoint
|
9
|
+
|
7
10
|
# Manages the list of proxy configurations and manipulates the sitemap
|
8
11
|
# to include new resources based on those configurations
|
9
12
|
def initialize(app, config={}, &block)
|
10
13
|
super
|
11
14
|
|
12
|
-
@app.add_to_config_context(:endpoint, &method(:create_endpoint))
|
13
|
-
|
14
15
|
@endpoints = {}
|
15
16
|
end
|
16
17
|
|
@@ -52,7 +53,7 @@ module Middleman
|
|
52
53
|
end
|
53
54
|
|
54
55
|
class EndpointResource < ::Middleman::Sitemap::Resource
|
55
|
-
Contract
|
56
|
+
Contract Maybe[Proc]
|
56
57
|
attr_accessor :output
|
57
58
|
|
58
59
|
def initialize(store, path, request_path)
|
@@ -60,10 +61,10 @@ module Middleman
|
|
60
61
|
@request_path = ::Middleman::Util.normalize_path(request_path)
|
61
62
|
end
|
62
63
|
|
63
|
-
Contract
|
64
|
+
Contract String
|
64
65
|
attr_reader :request_path
|
65
66
|
|
66
|
-
Contract
|
67
|
+
Contract Bool
|
67
68
|
def template?
|
68
69
|
true
|
69
70
|
end
|
@@ -73,7 +74,7 @@ module Middleman
|
|
73
74
|
return output.call if output
|
74
75
|
end
|
75
76
|
|
76
|
-
Contract
|
77
|
+
Contract Bool
|
77
78
|
def ignored?
|
78
79
|
false
|
79
80
|
end
|
@@ -9,7 +9,9 @@ module Middleman
|
|
9
9
|
tail = parts.pop
|
10
10
|
is_index = (tail == @app.config[:index_file])
|
11
11
|
|
12
|
-
|
12
|
+
if parts.empty?
|
13
|
+
return is_index ? nil : @store.find_resource_by_path(@app.config[:index_file])
|
14
|
+
end
|
13
15
|
|
14
16
|
test_expr = parts.join('\\/')
|
15
17
|
# eponymous reverse-lookup
|
@@ -23,7 +23,7 @@ module Middleman
|
|
23
23
|
|
24
24
|
# The on-disk source file for this resource, if there is one
|
25
25
|
# @return [String]
|
26
|
-
Contract
|
26
|
+
Contract Maybe[IsA['Middleman::SourceFile']]
|
27
27
|
attr_reader :source_file
|
28
28
|
|
29
29
|
# The path to use when requesting this resource. Normally it's
|
@@ -35,7 +35,7 @@ module Middleman
|
|
35
35
|
|
36
36
|
# The metadata for this resource
|
37
37
|
# @return [Hash]
|
38
|
-
Contract
|
38
|
+
Contract METADATA_HASH
|
39
39
|
attr_reader :metadata
|
40
40
|
|
41
41
|
# Initialize resource with parent store and URL
|
@@ -46,7 +46,7 @@ module Middleman
|
|
46
46
|
def initialize(store, path, source_file=nil)
|
47
47
|
@store = store
|
48
48
|
@app = @store.app
|
49
|
-
@path = path
|
49
|
+
@path = path
|
50
50
|
|
51
51
|
if source_file && source_file.is_a?(String)
|
52
52
|
source_file = Pathname(source_file)
|
@@ -69,7 +69,7 @@ module Middleman
|
|
69
69
|
|
70
70
|
# Whether this resource has a template file
|
71
71
|
# @return [Boolean]
|
72
|
-
Contract
|
72
|
+
Contract Bool
|
73
73
|
def template?
|
74
74
|
return false if source_file.nil?
|
75
75
|
!::Tilt[source_file[:full_path].to_s].nil?
|
@@ -87,31 +87,30 @@ module Middleman
|
|
87
87
|
end
|
88
88
|
|
89
89
|
# Data about this resource, populated from frontmatter or extensions.
|
90
|
-
# @return [
|
91
|
-
Contract
|
90
|
+
# @return [IndifferentHash]
|
91
|
+
Contract IsA['Middleman::Util::IndifferentHash']
|
92
92
|
def data
|
93
|
-
# TODO: Should this really be a HashWithIndifferentAccess?
|
94
93
|
::Middleman::Util.recursively_enhance(metadata[:page])
|
95
94
|
end
|
96
95
|
|
97
96
|
# Options about how this resource is rendered, such as its :layout,
|
98
97
|
# :renderer_options, and whether or not to use :directory_indexes.
|
99
98
|
# @return [Hash]
|
100
|
-
Contract
|
99
|
+
Contract Hash
|
101
100
|
def options
|
102
101
|
metadata[:options]
|
103
102
|
end
|
104
103
|
|
105
104
|
# Local variable mappings that are used when rendering the template for this resource.
|
106
105
|
# @return [Hash]
|
107
|
-
Contract
|
106
|
+
Contract Hash
|
108
107
|
def locals
|
109
108
|
metadata[:locals]
|
110
109
|
end
|
111
110
|
|
112
111
|
# Extension of the path (i.e. '.js')
|
113
112
|
# @return [String]
|
114
|
-
Contract
|
113
|
+
Contract String
|
115
114
|
def ext
|
116
115
|
File.extname(path)
|
117
116
|
end
|
@@ -141,7 +140,7 @@ module Middleman
|
|
141
140
|
# A path without the directory index - so foo/index.html becomes
|
142
141
|
# just foo. Best for linking.
|
143
142
|
# @return [String]
|
144
|
-
Contract
|
143
|
+
Contract String
|
145
144
|
def url
|
146
145
|
url_path = destination_path
|
147
146
|
if @app.config[:strip_index_file]
|
@@ -154,7 +153,7 @@ module Middleman
|
|
154
153
|
# Whether the source file is binary.
|
155
154
|
#
|
156
155
|
# @return [Boolean]
|
157
|
-
Contract
|
156
|
+
Contract Bool
|
158
157
|
def binary?
|
159
158
|
!source_file.nil? && ::Middleman::Util.binary?(source_file[:full_path].to_s)
|
160
159
|
end
|
@@ -162,14 +161,14 @@ module Middleman
|
|
162
161
|
# Ignore a resource directly, without going through the whole
|
163
162
|
# ignore filter stuff.
|
164
163
|
# @return [void]
|
165
|
-
Contract
|
164
|
+
Contract Any
|
166
165
|
def ignore!
|
167
166
|
@ignored = true
|
168
167
|
end
|
169
168
|
|
170
169
|
# Whether the Resource is ignored
|
171
170
|
# @return [Boolean]
|
172
|
-
Contract
|
171
|
+
Contract Bool
|
173
172
|
def ignored?
|
174
173
|
return true if @ignored
|
175
174
|
# Ignore based on the source path (without template extensions)
|
@@ -184,7 +183,7 @@ module Middleman
|
|
184
183
|
|
185
184
|
# The preferred MIME content type for this resource based on extension or metadata
|
186
185
|
# @return [String] MIME type for this resource
|
187
|
-
Contract
|
186
|
+
Contract Maybe[String]
|
188
187
|
def content_type
|
189
188
|
options[:content_type] || ::Rack::Mime.mime_type(ext, nil)
|
190
189
|
end
|
@@ -74,12 +74,13 @@ module Middleman
|
|
74
74
|
# @param [Symbol] name Name of the manipulator for debugging
|
75
75
|
# @param [#manipulate_resource_list] manipulator Resource list manipulator
|
76
76
|
# @param [Numeric] priority Sets the order of this resource list manipulator relative to the rest. By default this is 50, and manipulators run in the order they are registered, but if a priority is provided then this will run ahead of or behind other manipulators.
|
77
|
+
# @param [Symbol] custom_name The method name to execute.
|
77
78
|
# @return [void]
|
78
|
-
Contract Symbol, RespondTo['manipulate_resource_list'], Maybe[Num] => Any
|
79
|
-
def register_resource_list_manipulator(name, manipulator, priority=50)
|
79
|
+
Contract Symbol, RespondTo['manipulate_resource_list'], Maybe[Num], Maybe[Symbol] => Any
|
80
|
+
def register_resource_list_manipulator(name, manipulator, priority=50, custom_name=nil)
|
80
81
|
# The third argument used to be a boolean - handle those who still pass one
|
81
82
|
priority = 50 unless priority.is_a? Numeric
|
82
|
-
@resource_list_manipulators << [name, manipulator, priority]
|
83
|
+
@resource_list_manipulators << [name, manipulator, priority, custom_name]
|
83
84
|
# The index trick is used so that the sort is stable - manipulators with the same priority
|
84
85
|
# will always be ordered in the same order as they were registered.
|
85
86
|
n = 0
|
@@ -177,8 +178,8 @@ module Middleman
|
|
177
178
|
|
178
179
|
@app.logger.debug '== Rebuilding resource list'
|
179
180
|
|
180
|
-
@resources = @resource_list_manipulators.reduce([]) do |result, (_, manipulator, _)|
|
181
|
-
newres = manipulator.manipulate_resource_list
|
181
|
+
@resources = @resource_list_manipulators.reduce([]) do |result, (_, manipulator, _, custom_name)|
|
182
|
+
newres = manipulator.send(custom_name || :manipulate_resource_list, result)
|
182
183
|
|
183
184
|
# Reset lookup cache
|
184
185
|
reset_lookup_cache!
|
@@ -17,15 +17,15 @@ module Middleman
|
|
17
17
|
def_delegator :app, :logger
|
18
18
|
|
19
19
|
# The type this watcher is representing
|
20
|
-
Contract
|
20
|
+
Contract Symbol
|
21
21
|
attr_reader :type
|
22
22
|
|
23
23
|
# The directory that is being watched
|
24
|
-
Contract
|
24
|
+
Contract Pathname
|
25
25
|
attr_reader :directory
|
26
26
|
|
27
27
|
# Options for configuring the watcher
|
28
|
-
Contract
|
28
|
+
Contract Hash
|
29
29
|
attr_reader :options
|
30
30
|
|
31
31
|
# Construct a new SourceWatcher
|
@@ -47,6 +47,7 @@ module Middleman
|
|
47
47
|
|
48
48
|
@validator = options.fetch(:validator, proc { true })
|
49
49
|
@ignored = options.fetch(:ignored, proc { false })
|
50
|
+
@only = Array(options.fetch(:only, []))
|
50
51
|
|
51
52
|
@disable_watcher = app.build? || @parent.options.fetch(:disable_watcher, false)
|
52
53
|
@force_polling = @parent.options.fetch(:force_polling, false)
|
@@ -79,7 +80,7 @@ module Middleman
|
|
79
80
|
# Stop watching.
|
80
81
|
#
|
81
82
|
# @return [void]
|
82
|
-
Contract
|
83
|
+
Contract Any
|
83
84
|
def unwatch
|
84
85
|
stop_listener!
|
85
86
|
end
|
@@ -87,7 +88,7 @@ module Middleman
|
|
87
88
|
# All the known files in this watcher.
|
88
89
|
#
|
89
90
|
# @return [Array<Middleman::SourceFile>]
|
90
|
-
Contract
|
91
|
+
Contract ArrayOf[IsA['Middleman::SourceFile']]
|
91
92
|
def files
|
92
93
|
@files.values
|
93
94
|
end
|
@@ -123,21 +124,27 @@ module Middleman
|
|
123
124
|
# Start the `listen` gem Listener.
|
124
125
|
#
|
125
126
|
# @return [void]
|
126
|
-
Contract
|
127
|
+
Contract Any
|
127
128
|
def listen!
|
128
129
|
return if @disable_watcher || @listener || @waiting_for_existence
|
129
130
|
|
130
|
-
config = {
|
131
|
+
config = {
|
132
|
+
force_polling: @force_polling,
|
133
|
+
wait_for_delay: 0.5
|
134
|
+
}
|
135
|
+
|
131
136
|
config[:latency] = @latency if @latency
|
132
137
|
|
133
138
|
@listener = ::Listen.to(@directory.to_s, config, &method(:on_listener_change))
|
134
139
|
@listener.start
|
140
|
+
|
141
|
+
@listener.only(@only) unless @only.empty?
|
135
142
|
end
|
136
143
|
|
137
144
|
# Stop the listener.
|
138
145
|
#
|
139
146
|
# @return [void]
|
140
|
-
Contract
|
147
|
+
Contract Any
|
141
148
|
def stop_listener!
|
142
149
|
return unless @listener
|
143
150
|
|
@@ -148,7 +155,7 @@ module Middleman
|
|
148
155
|
# Manually trigger update events.
|
149
156
|
#
|
150
157
|
# @return [void]
|
151
|
-
Contract
|
158
|
+
Contract Any
|
152
159
|
def poll_once!
|
153
160
|
removed = @files.keys
|
154
161
|
|
@@ -247,10 +254,9 @@ module Middleman
|
|
247
254
|
@extensionless_files.delete(strip_extensions(f[:full_path]))
|
248
255
|
end
|
249
256
|
|
257
|
+
Contract Pathname => Pathname
|
250
258
|
def strip_extensions(p)
|
251
|
-
while ::Tilt[p.to_s] || p.extname
|
252
|
-
p = p.sub_ext('')
|
253
|
-
end
|
259
|
+
p = p.sub_ext('') while ::Tilt[p.to_s] || p.extname == '.html'
|
254
260
|
Pathname(p.to_s + '.*')
|
255
261
|
end
|
256
262
|
|
@@ -260,9 +266,13 @@ module Middleman
|
|
260
266
|
# @return [Boolean]
|
261
267
|
Contract IsA['Middleman::SourceFile'] => Bool
|
262
268
|
def valid?(file)
|
263
|
-
@validator.call(file) &&
|
264
|
-
|
269
|
+
return false unless @validator.call(file) && !globally_ignored?(file)
|
270
|
+
|
271
|
+
if @only.empty?
|
265
272
|
!@ignored.call(file)
|
273
|
+
else
|
274
|
+
@only.any? { |reg| reg.match(file[:relative_path].to_s) }
|
275
|
+
end
|
266
276
|
end
|
267
277
|
|
268
278
|
# Convert a path to a file resprentation.
|
@@ -273,8 +283,11 @@ module Middleman
|
|
273
283
|
def path_to_source_file(path)
|
274
284
|
types = Set.new([@type])
|
275
285
|
|
276
|
-
|
277
|
-
|
286
|
+
relative_path = path.relative_path_from(@directory)
|
287
|
+
destination_dir = @options.fetch(:destination_dir, false)
|
288
|
+
relative_path = File.join(destination_dir, relative_path) if destination_dir
|
289
|
+
|
290
|
+
::Middleman::SourceFile.new(Pathname(relative_path), path, @directory, types)
|
278
291
|
end
|
279
292
|
|
280
293
|
# Notify callbacks for a file given an array of callbacks
|
@@ -14,15 +14,17 @@ module Middleman
|
|
14
14
|
extend Forwardable
|
15
15
|
include Contracts
|
16
16
|
|
17
|
+
Matcher = Or[Regexp, RespondTo[:call]]
|
18
|
+
|
17
19
|
# A reference to the current app.
|
18
|
-
Contract
|
20
|
+
Contract IsA['Middleman::Application']
|
19
21
|
attr_reader :app
|
20
22
|
|
21
23
|
# Duck-typed definition of a valid source watcher
|
22
24
|
HANDLER = RespondTo[:on_change]
|
23
25
|
|
24
26
|
# Config
|
25
|
-
Contract
|
27
|
+
Contract Hash
|
26
28
|
attr_reader :options
|
27
29
|
|
28
30
|
# Reference to the global logger.
|
@@ -125,7 +127,7 @@ module Middleman
|
|
125
127
|
end
|
126
128
|
|
127
129
|
# A list of registered watchers
|
128
|
-
Contract
|
130
|
+
Contract ArrayOf[HANDLER]
|
129
131
|
def watchers
|
130
132
|
@sorted_watchers
|
131
133
|
end
|
@@ -155,7 +157,7 @@ module Middleman
|
|
155
157
|
# Get all files for this collection of watchers.
|
156
158
|
#
|
157
159
|
# @return [Array<Middleman::SourceFile>]
|
158
|
-
Contract
|
160
|
+
Contract ArrayOf[SourceFile]
|
159
161
|
def files
|
160
162
|
watchers.flat_map(&:files).uniq { |f| f[:relative_path] }
|
161
163
|
end
|
@@ -204,7 +206,7 @@ module Middleman
|
|
204
206
|
# Manually poll all watchers for new content.
|
205
207
|
#
|
206
208
|
# @return [void]
|
207
|
-
Contract
|
209
|
+
Contract Any
|
208
210
|
def find_new_files!
|
209
211
|
return unless @update_count != @last_update_count
|
210
212
|
|
@@ -215,7 +217,7 @@ module Middleman
|
|
215
217
|
# Start up all listeners.
|
216
218
|
#
|
217
219
|
# @return [void]
|
218
|
-
Contract
|
220
|
+
Contract Any
|
219
221
|
def start!
|
220
222
|
watchers.each(&:listen!)
|
221
223
|
@running = true
|
@@ -224,7 +226,7 @@ module Middleman
|
|
224
226
|
# Stop the watchers.
|
225
227
|
#
|
226
228
|
# @return [void]
|
227
|
-
Contract
|
229
|
+
Contract Any
|
228
230
|
def stop!
|
229
231
|
watchers.each(&:stop_listener!)
|
230
232
|
@running = false
|
@@ -246,28 +248,24 @@ module Middleman
|
|
246
248
|
# Backwards compatible change handler.
|
247
249
|
#
|
248
250
|
# @param [nil,Regexp] matcher A Regexp to match the change path against
|
249
|
-
|
251
|
+
Contract Maybe[Matcher] => Any
|
250
252
|
def changed(matcher=nil, &block)
|
251
253
|
on_change :source do |updated, _removed|
|
252
|
-
updated
|
253
|
-
matcher.nil? ? true : matches?(matcher, f)
|
254
|
-
|
255
|
-
block.call(f[:relative_path])
|
256
|
-
end
|
254
|
+
updated
|
255
|
+
.select { |f| matcher.nil? ? true : matches?(matcher, f) }
|
256
|
+
.each { |f| block.call(f[:relative_path]) }
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
260
|
# Backwards compatible delete handler.
|
261
261
|
#
|
262
262
|
# @param [nil,Regexp] matcher A Regexp to match the change path against
|
263
|
-
|
263
|
+
Contract Maybe[Matcher] => Any
|
264
264
|
def deleted(matcher=nil, &block)
|
265
265
|
on_change :source do |_updated, removed|
|
266
|
-
removed
|
267
|
-
matcher.nil? ? true : matches?(matcher, f)
|
268
|
-
|
269
|
-
block.call(f[:relative_path])
|
270
|
-
end
|
266
|
+
removed
|
267
|
+
.select { |f| matcher.nil? ? true : matches?(matcher, f) }
|
268
|
+
.each { |f| block.call(f[:relative_path]) }
|
271
269
|
end
|
272
270
|
end
|
273
271
|
|
@@ -287,7 +285,7 @@ module Middleman
|
|
287
285
|
# @param [Regexp, #call] validator The match validator.
|
288
286
|
# @param [Middleman::SourceFile] file The file to check.
|
289
287
|
# @return [Boolean]
|
290
|
-
Contract
|
288
|
+
Contract Matcher, SourceFile => Bool
|
291
289
|
def matches?(validator, file)
|
292
290
|
path = file[:relative_path]
|
293
291
|
if validator.is_a? Regexp
|
@@ -300,7 +298,7 @@ module Middleman
|
|
300
298
|
# Increment the internal counter for changes.
|
301
299
|
#
|
302
300
|
# @return [void]
|
303
|
-
Contract
|
301
|
+
Contract Any
|
304
302
|
def bump_count
|
305
303
|
@update_count += 1
|
306
304
|
end
|
@@ -69,7 +69,7 @@ end
|
|
69
69
|
|
70
70
|
# Provide this Aruba overload in case we're matching something with quotes in it
|
71
71
|
Then /^the file "([^"]*)" should contain '([^']*)'$/ do |file, partial_content|
|
72
|
-
check_file_content(file, partial_content, true)
|
72
|
+
check_file_content(file, Regexp.new(Regexp.escape(partial_content)), true)
|
73
73
|
end
|
74
74
|
|
75
75
|
And /the file "(.*)" should be gzipped/ do |file|
|
@@ -70,7 +70,7 @@ end
|
|
70
70
|
|
71
71
|
When /^I go to "([^\"]*)"$/ do |url|
|
72
72
|
in_current_dir do
|
73
|
-
@last_response = @browser.get(URI.
|
73
|
+
@last_response = @browser.get(URI.encode(url))
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -78,8 +78,8 @@ Then /^going to "([^\"]*)" should not raise an exception$/ do |url|
|
|
78
78
|
in_current_dir do
|
79
79
|
last_response = nil
|
80
80
|
expect {
|
81
|
-
last_response = @browser.get(URI.
|
82
|
-
}.to_not
|
81
|
+
last_response = @browser.get(URI.encode(url))
|
82
|
+
}.to_not raise_exception
|
83
83
|
@last_response = last_response
|
84
84
|
end
|
85
85
|
end
|
@@ -100,7 +100,7 @@ module Middleman
|
|
100
100
|
def render(_, name, options={}, &block)
|
101
101
|
name = name.to_s
|
102
102
|
|
103
|
-
partial_file = locate_partial(name)
|
103
|
+
partial_file = locate_partial(name, false) || locate_partial(name, true)
|
104
104
|
|
105
105
|
return '' unless partial_file
|
106
106
|
raise ::Middleman::TemplateRenderer::TemplateNotFound, "Could not locate partial: #{name}" unless partial_file
|
@@ -123,8 +123,8 @@ module Middleman
|
|
123
123
|
# @api private
|
124
124
|
# @param [String] partial_path
|
125
125
|
# @return [String]
|
126
|
-
Contract String => Maybe[IsA['Middleman::SourceFile']]
|
127
|
-
def locate_partial(partial_path)
|
126
|
+
Contract String, Maybe[Bool] => Maybe[IsA['Middleman::SourceFile']]
|
127
|
+
def locate_partial(partial_path, try_static=true)
|
128
128
|
return unless resource = sitemap.find_resource_by_destination_path(current_path)
|
129
129
|
|
130
130
|
# Look for partials relative to the current path
|
@@ -140,9 +140,9 @@ module Middleman
|
|
140
140
|
[
|
141
141
|
[relative_dir.to_s, { preferred_engine: resource.source_file[:relative_path].extname[1..-1].to_sym }],
|
142
142
|
[non_root],
|
143
|
-
[non_root, { try_static:
|
144
|
-
[relative_dir_no_underscore.to_s, { try_static:
|
145
|
-
[non_root_no_underscore, { try_static:
|
143
|
+
[non_root, { try_static: try_static }],
|
144
|
+
[relative_dir_no_underscore.to_s, { try_static: try_static }],
|
145
|
+
[non_root_no_underscore, { try_static: try_static }]
|
146
146
|
].each do |args|
|
147
147
|
partial_file = ::Middleman::TemplateRenderer.resolve_template(@app, *args)
|
148
148
|
break if partial_file
|
@@ -161,11 +161,12 @@ module Middleman
|
|
161
161
|
# @param [Hash] opts Template options.
|
162
162
|
# @param [Proc] block A block will be evaluated to return internal contents.
|
163
163
|
# @return [String] The resulting content string.
|
164
|
-
Contract IsA['Middleman::SourceFile'], Hash, Hash, Proc => String
|
164
|
+
Contract IsA['Middleman::SourceFile'], Hash, Hash, Maybe[Proc] => String
|
165
165
|
def render_file(file, locs, opts, &block)
|
166
166
|
_render_with_all_renderers(file[:relative_path].to_s, locs, self, opts, &block)
|
167
167
|
end
|
168
168
|
|
169
|
+
Contract String, Hash, Any, Hash, Maybe[Proc] => String
|
169
170
|
def _render_with_all_renderers(path, locs, context, opts, &block)
|
170
171
|
# Keep rendering template until we've used up all extensions. This
|
171
172
|
# handles cases like `style.css.sass.erb`
|
@@ -58,8 +58,8 @@ module Middleman
|
|
58
58
|
# Sandboxed class for template eval
|
59
59
|
context = @app.template_context_class.new(@app, locals, options)
|
60
60
|
|
61
|
-
#
|
62
|
-
|
61
|
+
# Add extension helpers to context.
|
62
|
+
@app.extensions.add_exposed_to_context(context)
|
63
63
|
|
64
64
|
content = _render_with_all_renderers(path, locs, context, opts, &block)
|
65
65
|
|