middleman-core 4.1.0.rc.1 → 4.1.0.rc.2

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/features/asset_hash.feature +44 -6
  4. data/features/asset_host.feature +1 -0
  5. data/features/automatic_image_sizes.feature +18 -5
  6. data/fixtures/asset-hash-host-app/source/index.html.erb +1 -1
  7. data/fixtures/asset-host-app/config.rb +1 -0
  8. data/fixtures/asset-host-app/source/asset_host.html.erb +9 -0
  9. data/fixtures/automatic-image-size-app/source/markdown-sizes.html.markdown +1 -0
  10. data/lib/middleman-core/application.rb +68 -58
  11. data/lib/middleman-core/builder.rb +24 -18
  12. data/lib/middleman-core/callback_manager.rb +8 -1
  13. data/lib/middleman-core/contracts.rb +13 -102
  14. data/lib/middleman-core/core_extensions.rb +6 -0
  15. data/lib/middleman-core/core_extensions/collections/lazy_step.rb +1 -1
  16. data/lib/middleman-core/core_extensions/data.rb +3 -2
  17. data/lib/middleman-core/core_extensions/default_helpers.rb +5 -5
  18. data/lib/middleman-core/core_extensions/external_helpers.rb +6 -11
  19. data/lib/middleman-core/core_extensions/file_watcher.rb +1 -1
  20. data/lib/middleman-core/core_extensions/front_matter.rb +1 -0
  21. data/lib/middleman-core/core_extensions/i18n.rb +4 -4
  22. data/lib/middleman-core/core_extensions/inline_url_rewriter.rb +150 -0
  23. data/lib/middleman-core/core_extensions/routing.rb +22 -28
  24. data/lib/middleman-core/core_extensions/show_exceptions.rb +1 -7
  25. data/lib/middleman-core/extension.rb +19 -2
  26. data/lib/middleman-core/extension_manager.rb +2 -0
  27. data/lib/middleman-core/extensions.rb +12 -0
  28. data/lib/middleman-core/extensions/asset_hash.rb +21 -20
  29. data/lib/middleman-core/extensions/asset_host.rb +9 -10
  30. data/lib/middleman-core/extensions/automatic_image_sizes.rb +1 -1
  31. data/lib/middleman-core/extensions/cache_buster.rb +6 -12
  32. data/lib/middleman-core/extensions/gzip.rb +2 -2
  33. data/lib/middleman-core/extensions/lorem.rb +1 -1
  34. data/lib/middleman-core/extensions/minify_css.rb +2 -2
  35. data/lib/middleman-core/extensions/minify_javascript.rb +2 -2
  36. data/lib/middleman-core/extensions/relative_assets.rb +6 -12
  37. data/lib/middleman-core/preview_server.rb +11 -9
  38. data/lib/middleman-core/preview_server/server_hostname.rb +2 -2
  39. data/lib/middleman-core/rack.rb +1 -1
  40. data/lib/middleman-core/renderers/kramdown.rb +1 -1
  41. data/lib/middleman-core/renderers/less.rb +3 -4
  42. data/lib/middleman-core/renderers/markdown.rb +2 -8
  43. data/lib/middleman-core/renderers/redcarpet.rb +1 -1
  44. data/lib/middleman-core/renderers/sass.rb +8 -11
  45. data/lib/middleman-core/renderers/stylus.rb +1 -5
  46. data/lib/middleman-core/sitemap/extensions/ignores.rb +5 -4
  47. data/lib/middleman-core/sitemap/extensions/import.rb +12 -15
  48. data/lib/middleman-core/sitemap/extensions/move_file.rb +3 -3
  49. data/lib/middleman-core/sitemap/extensions/proxies.rb +4 -4
  50. data/lib/middleman-core/sitemap/extensions/redirects.rb +16 -28
  51. data/lib/middleman-core/sitemap/extensions/request_endpoints.rb +17 -35
  52. data/lib/middleman-core/sitemap/extensions/traversal.rb +5 -5
  53. data/lib/middleman-core/sitemap/resource.rb +16 -16
  54. data/lib/middleman-core/sitemap/store.rb +42 -31
  55. data/lib/middleman-core/sources.rb +9 -9
  56. data/lib/middleman-core/sources/source_watcher.rb +14 -10
  57. data/lib/middleman-core/step_definitions/server_steps.rb +12 -4
  58. data/lib/middleman-core/template_context.rb +1 -1
  59. data/lib/middleman-core/template_renderer.rb +74 -75
  60. data/lib/middleman-core/util.rb +19 -16
  61. data/lib/middleman-core/util/data.rb +86 -82
  62. data/lib/middleman-core/version.rb +1 -1
  63. data/middleman-core.gemspec +1 -0
  64. metadata +19 -39
  65. data/features/cli/preview_server-hook.feature +0 -17
  66. data/features/cli/preview_server.feature +0 -536
  67. data/features/cli_extension.feature +0 -14
  68. data/features/cli_init.feature +0 -89
  69. data/fixtures/asset-hash-host-app/config.rb +0 -4
  70. data/fixtures/preview-server-app/bin/dns_server.rb +0 -33
  71. data/fixtures/preview-server-app/config.rb +0 -0
  72. data/fixtures/preview-server-app/source/index.html.erb +0 -1
  73. data/fixtures/preview-server-app/source/layout.erb +0 -9
  74. data/fixtures/preview-server-app/source/layouts/custom.erb +0 -8
  75. data/fixtures/preview-server-app/source/real.html +0 -1
  76. data/fixtures/preview-server-app/source/real/index.html.erb +0 -5
  77. data/fixtures/preview-server-app/source/should_be_ignored.html +0 -1
  78. data/fixtures/preview-server-app/source/should_be_ignored2.html +0 -1
  79. data/fixtures/preview-server-app/source/should_be_ignored3.html +0 -1
  80. data/fixtures/preview-server-app/source/static.html +0 -1
  81. data/fixtures/preview-server-hook-app/config.rb +0 -19
  82. data/fixtures/preview-server-hook-app/source/index.html.erb +0 -9
  83. data/lib/middleman-core/middleware/inline_url_rewriter.rb +0 -109
@@ -48,8 +48,15 @@ module Middleman
48
48
 
49
49
  Contract Or[Symbol, ArrayOf[Symbol]], Maybe[ArrayOf[Any]], Maybe[RespondTo[:instance_exec]] => Any
50
50
  def execute(keys, args=[], scope=self)
51
- callbacks_for(keys).each { |b| scope.instance_exec(*args, &b) }
51
+ callbacks = callbacks_for(keys)
52
+ callbacks_count = callbacks.length + @subscribers.length
53
+
54
+ return if callbacks_count < 1
55
+
56
+ # ::Middleman::Util.instrument "callbacks.execute", keys: keys, length: callbacks_count do
57
+ callbacks.each { |b| scope.instance_exec(*args, &b) }
52
58
  @subscribers.each { |b| scope.instance_exec(keys, args, &b) }
59
+ # end
53
60
  end
54
61
 
55
62
  Contract Or[Symbol, ArrayOf[Symbol]] => ::Hamster::Vector
@@ -1,112 +1,23 @@
1
- if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
2
- require 'contracts'
3
- require 'hamster'
1
+ require 'contracts'
2
+ require 'hamster'
4
3
 
5
- module Contracts
6
- class IsA
7
- def self.[](val)
8
- @lookup ||= {}
9
- @lookup[val] ||= new(val)
10
- end
11
-
12
- def initialize(val)
13
- @val = val
14
- end
15
-
16
- def valid?(val)
17
- val.is_a? @val.constantize
18
- end
19
- end
20
-
21
- VectorOf = Contracts::CollectionOf::Factory.new(::Hamster::Vector)
22
- ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
23
- end
24
- else
25
- module Contracts
26
- def self.included(base)
27
- base.extend self
28
- end
29
-
30
- # rubocop:disable MethodName
31
- def Contract(*)
32
- end
33
-
34
- class Callable
35
- def self.[](*)
36
- end
37
- end
38
-
39
- class Bool
40
- end
41
-
42
- class Num
43
- end
44
-
45
- class Pos
46
- end
47
-
48
- class Neg
49
- end
50
-
51
- class Any
52
- end
53
-
54
- class None
55
- end
56
-
57
- class Or < Callable
58
- end
59
-
60
- class Xor < Callable
61
- end
62
-
63
- class And < Callable
64
- end
65
-
66
- class Not < Callable
67
- end
68
-
69
- class RespondTo < Callable
70
- end
71
-
72
- class Send < Callable
73
- end
74
-
75
- class Exactly < Callable
76
- end
77
-
78
- class ArrayOf < Callable
79
- end
80
-
81
- class ResourceList < Callable
82
- end
83
-
84
- class Args < Callable
85
- end
86
-
87
- class HashOf < Callable
88
- end
89
-
90
- class Bool
91
- end
92
-
93
- class Maybe < Callable
94
- end
95
-
96
- class IsA < Callable
97
- end
98
-
99
- class SetOf < Callable
4
+ module Contracts
5
+ class IsA
6
+ def self.[](val)
7
+ @lookup ||= {}
8
+ @lookup[val] ||= new(val)
100
9
  end
101
10
 
102
- class Frozen < Callable
11
+ def initialize(val)
12
+ @val = val
103
13
  end
104
14
 
105
- class VectorOf < Callable
15
+ def valid?(val)
16
+ val.is_a? @val.constantize
106
17
  end
107
18
  end
108
- end
109
19
 
110
- module Contracts
20
+ VectorOf = ::Contracts::CollectionOf::Factory.new(::Hamster::Vector)
21
+ ResourceList = ::Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
111
22
  PATH_MATCHER = Or[String, RespondTo[:match], RespondTo[:call], RespondTo[:to_s]]
112
23
  end
@@ -19,6 +19,12 @@ Middleman::Extensions.register :data, auto_activate: :before_sitemap do
19
19
  Middleman::CoreExtensions::Data
20
20
  end
21
21
 
22
+ # Rewrite embedded URLs via Rack
23
+ Middleman::Extensions.register :inline_url_rewriter, auto_activate: :before_sitemap do
24
+ require 'middleman-core/core_extensions/inline_url_rewriter'
25
+ Middleman::CoreExtensions::InlineURLRewriter
26
+ end
27
+
22
28
  # Catch and show exceptions at the Rack level
23
29
  Middleman::Extensions.register :show_exceptions, auto_activate: :before_configuration, modes: [:server] do
24
30
  require 'middleman-core/core_extensions/show_exceptions'
@@ -2,7 +2,7 @@ module Middleman
2
2
  module CoreExtensions
3
3
  module Collections
4
4
  class LazyCollectorStep < BasicObject
5
- DELEGATE = [:hash, :eql?]
5
+ DELEGATE = [:hash, :eql?].freeze
6
6
 
7
7
  def initialize(name, args, block, parent=nil)
8
8
  @name = name
@@ -8,6 +8,8 @@ module Middleman
8
8
  class Data < Extension
9
9
  attr_reader :data_store
10
10
 
11
+ define_setting :data_dir, 'data', 'The directory data files are stored in'
12
+
11
13
  # Make the internal `data_store` method available as `app.data`
12
14
  expose_to_application data: :data_store
13
15
 
@@ -21,7 +23,6 @@ module Middleman
21
23
  super
22
24
 
23
25
  @data_store = DataStore.new(app, DATA_FILE_MATCHER)
24
- app.config.define_setting :data_dir, 'data', 'The directory data files are stored in'
25
26
 
26
27
  start_watching(app.config[:data_dir])
27
28
  end
@@ -188,7 +189,7 @@ module Middleman
188
189
  (@local_data.keys + @local_sources.keys + @callback_sources.keys).include?(key.to_s)
189
190
  end
190
191
 
191
- alias_method :has_key?, :key?
192
+ alias has_key? key?
192
193
 
193
194
  # Convert all the data into a static hash
194
195
  #
@@ -9,7 +9,7 @@ class Padrino::Helpers::OutputHelpers::ErbHandler
9
9
  def capture_from_template(*args, &block)
10
10
  self.output_buffer = ''
11
11
  buf_was = output_buffer
12
- raw = block.call(*args)
12
+ raw = yield(*args)
13
13
  captured = template.instance_variable_get(:@_out_buf)
14
14
  self.output_buffer = buf_was
15
15
  engine_matches?(block) && !captured.empty? ? captured : raw
@@ -17,6 +17,8 @@ class Padrino::Helpers::OutputHelpers::ErbHandler
17
17
  end
18
18
 
19
19
  class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
20
+ define_setting :relative_links, false, 'Whether to generate relative links instead of absolute ones'
21
+
20
22
  def initialize(app, options_hash={}, &block)
21
23
  super
22
24
 
@@ -30,8 +32,6 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
30
32
  ::Middleman::TemplateContext.send :include, ::Padrino::Helpers::RenderHelpers
31
33
  ::Middleman::TemplateContext.send :include, ::Padrino::Helpers::NumberHelpers
32
34
  # ::Middleman::TemplateContext.send :include, ::Padrino::Helpers::TranslationHelpers
33
-
34
- app.config.define_setting :relative_links, false, 'Whether to generate relative links instead of absolute ones'
35
35
  end
36
36
 
37
37
  # The helpers
@@ -55,7 +55,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
55
55
  output.safe_concat ::Padrino::Helpers::TagHelpers::NEWLINE
56
56
  end
57
57
  else
58
- output.safe_concat "#{content}"
58
+ output.safe_concat content.to_s
59
59
  end
60
60
  output.safe_concat "</#{name}>"
61
61
 
@@ -66,7 +66,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
66
66
  result = if handler = auto_find_proper_handler(&block)
67
67
  handler.capture_from_template(*args, &block)
68
68
  else
69
- block.call(*args)
69
+ yield(*args)
70
70
  end
71
71
 
72
72
  ::ActiveSupport::SafeBuffer.new.safe_concat(result)
@@ -2,17 +2,12 @@ module Middleman
2
2
  module CoreExtensions
3
3
  # Load helpers in `helpers/`
4
4
  class ExternalHelpers < Extension
5
- def initialize(app, options_hash={}, &block)
6
- super
7
-
8
- # Setup a default helpers paths
9
- app.config.define_setting :helpers_dir, 'helpers', 'Directory to autoload helper modules from'
10
- app.config.define_setting :helpers_filename_glob, '**.rb', 'Glob pattern for matching helper ruby files'
11
- app.config.define_setting :helpers_filename_to_module_name_proc, proc { |filename|
12
- basename = File.basename(filename, File.extname(filename))
13
- basename.camelcase
14
- }, 'Proc implementing the conversion from helper filename to module name'
15
- end
5
+ define_setting :helpers_dir, 'helpers', 'Directory to autoload helper modules from'
6
+ define_setting :helpers_filename_glob, '**.rb', 'Glob pattern for matching helper ruby files'
7
+ define_setting :helpers_filename_to_module_name_proc, proc { |filename|
8
+ basename = File.basename(filename, File.extname(filename))
9
+ basename.camelcase
10
+ }, 'Proc implementing the conversion from helper filename to module name'
16
11
 
17
12
  def after_configuration
18
13
  helpers_path = File.join(app.root, app.config[:helpers_dir])
@@ -21,7 +21,7 @@ module Middleman
21
21
  tilde_files: /~$/,
22
22
  ds_store: /\.DS_Store$/,
23
23
  git: /(^|\/)\.git(ignore|modules|\/)/
24
- }
24
+ }.freeze
25
25
 
26
26
  # Setup the extension.
27
27
  def initialize(app, config={}, &block)
@@ -28,6 +28,7 @@ module Middleman::CoreExtensions
28
28
  Contract ResourceList => ResourceList
29
29
  def manipulate_resource_list(resources)
30
30
  resources.each do |resource|
31
+ next if resource.binary?
31
32
  next if resource.ignored?
32
33
  next if resource.file_descriptor.nil?
33
34
 
@@ -127,7 +127,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
127
127
  end
128
128
 
129
129
  # Backwards API compat
130
- alias_method :langs, :locales
130
+ alias langs locales
131
131
 
132
132
  Contract Symbol
133
133
  def locale
@@ -135,7 +135,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
135
135
  end
136
136
 
137
137
  # Backwards API compat
138
- alias_method :lang, :locale
138
+ alias lang locale
139
139
 
140
140
  # Update the main sitemap resource list
141
141
  # @return Array<Middleman::Sitemap::Resource>
@@ -190,7 +190,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
190
190
  end
191
191
  end
192
192
 
193
- Contract String, Symbol => String
193
+ Contract String, Symbol => Maybe[String]
194
194
  def localized_path(path, locale)
195
195
  lookup_path = path.dup
196
196
  lookup_path << app.config[:index_file] if lookup_path.end_with?('/')
@@ -274,7 +274,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
274
274
 
275
275
  File.dirname(path).split('/').each do |path_sub|
276
276
  next if path_sub == ''
277
- partially_localized_path = "#{partially_localized_path}/#{(::I18n.t("paths.#{path_sub}", default: path_sub).to_s)}"
277
+ partially_localized_path = "#{partially_localized_path}/#{::I18n.t("paths.#{path_sub}", default: path_sub)}"
278
278
  end
279
279
 
280
280
  path = "#{partially_localized_path}/#{File.basename(path)}"
@@ -0,0 +1,150 @@
1
+ require 'rack'
2
+ require 'rack/response'
3
+ require 'addressable/uri'
4
+ require 'middleman-core/util'
5
+ require 'middleman-core/contracts'
6
+
7
+ module Middleman
8
+ module CoreExtensions
9
+ class InlineURLRewriter < ::Middleman::Extension
10
+ include Contracts
11
+
12
+ expose_to_application rewrite_inline_urls: :add
13
+
14
+ IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
15
+ REWRITER_DESCRIPTOR = {
16
+ id: Symbol,
17
+ proc: Or[Proc, Method],
18
+ url_extensions: ArrayOf[String],
19
+ source_extensions: ArrayOf[String],
20
+ ignore: ArrayOf[IGNORE_DESCRIPTOR],
21
+ after: Maybe[Symbol]
22
+ }.freeze
23
+
24
+ def initialize(app, options_hash={}, &block)
25
+ super
26
+
27
+ @rewriters = {}
28
+ end
29
+
30
+ Contract REWRITER_DESCRIPTOR => Any
31
+ def add(options)
32
+ @rewriters[options] = options
33
+ end
34
+
35
+ def after_configuration
36
+ rewriters = @rewriters.values.sort do |a, b|
37
+ if b[:after] && b[:after] == a[:id]
38
+ 1
39
+ else
40
+ 0
41
+ end
42
+ end
43
+
44
+ app.use Rack, rewriters: rewriters, middleman_app: @app
45
+ end
46
+
47
+ class Rack
48
+ include Contracts
49
+
50
+ Contract RespondTo[:call], {
51
+ middleman_app: IsA['Middleman::Application'],
52
+ rewriters: ArrayOf[REWRITER_DESCRIPTOR]
53
+ } => Any
54
+ def initialize(app, options={})
55
+ @rack_app = app
56
+ @middleman_app = options.fetch(:middleman_app)
57
+ @rewriters = options.fetch(:rewriters)
58
+ end
59
+
60
+ def call(env)
61
+ status, headers, response = @rack_app.call(env)
62
+
63
+ # Allow configuration or upstream request to skip all rewriting
64
+ return [status, headers, response] if env['bypass_inline_url_rewriter'] == 'true'
65
+
66
+ all_source_exts = @rewriters
67
+ .reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] }
68
+ .flatten
69
+ .uniq
70
+ source_exts_regex_text = Regexp.union(all_source_exts).to_s
71
+
72
+ all_asset_exts = @rewriters
73
+ .reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] }
74
+ .flatten
75
+ .uniq
76
+
77
+ path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app)
78
+
79
+ return [status, headers, response] unless path =~ /(^\/$)|(#{source_exts_regex_text}$)/
80
+ return [status, headers, response] unless body = ::Middleman::Util.extract_response_text(response)
81
+
82
+ dirpath = ::Pathname.new(File.dirname(path))
83
+
84
+ rewritten = ::Middleman::Util.instrument 'inline_url_rewriter', path: path do
85
+ ::Middleman::Util.rewrite_paths(body, path, all_asset_exts) do |asset_path|
86
+ uri = ::Addressable::URI.parse(asset_path)
87
+
88
+ relative_path = uri.host.nil?
89
+
90
+ full_asset_path = if relative_path
91
+ dirpath.join(asset_path).to_s
92
+ else
93
+ asset_path
94
+ end
95
+
96
+ @rewriters.each do |rewriter|
97
+ uid = rewriter.fetch(:id)
98
+
99
+ # Allow upstream request to skip this specific rewriting
100
+ next if env["bypass_inline_url_rewriter_#{uid}"] == 'true'
101
+
102
+ exts = rewriter.fetch(:url_extensions)
103
+ next unless exts.include?(::File.extname(asset_path))
104
+
105
+ source_exts = rewriter.fetch(:source_extensions)
106
+ next unless source_exts.include?(::File.extname(path))
107
+
108
+ ignore = rewriter.fetch(:ignore)
109
+ next if ignore.any? { |r| should_ignore?(r, full_asset_path) }
110
+
111
+ rewrite_ignore = Array(rewriter.fetch(:rewrite_ignore, []))
112
+ next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) }
113
+
114
+ proc = rewriter.fetch(:proc)
115
+
116
+ result = proc.call(asset_path, dirpath, path)
117
+ asset_path = result if result
118
+ end
119
+
120
+ asset_path
121
+ end
122
+ end
123
+
124
+ ::Rack::Response.new(
125
+ rewritten,
126
+ status,
127
+ headers
128
+ ).finish
129
+ end
130
+
131
+ Contract IGNORE_DESCRIPTOR, String => Bool
132
+ def should_ignore?(validator, value)
133
+ if validator.is_a? Regexp
134
+ # Treat as Regexp
135
+ !value.match(validator).nil?
136
+ elsif validator.respond_to? :call
137
+ # Treat as proc
138
+ validator.call(value)
139
+ elsif validator.is_a? String
140
+ # Treat as glob
141
+ File.fnmatch(value, validator)
142
+ else
143
+ # If some unknown thing, don't ignore
144
+ false
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end