1
0
Fork 0
mirror of https://github.com/middleman/middleman.git synced 2022-11-09 12:20:27 -05:00

Avoid all the Maybe nonsense (#2224)

Rename dep classes

Split into files

Sass was still returning nil

Let's make dependencies immutable

Avoid IsA

Fix contract
This commit is contained in:
Thomas Reynolds 2018-11-20 14:08:03 -08:00 committed by GitHub
parent 0b03aa358a
commit 067dd350c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 373 additions and 299 deletions

3
.gitignore vendored
View file

@ -23,4 +23,5 @@ Makefile
.idea
*.sublime-workspace
/bin
/vendor/bundle/
/vendor/bundle/
deps.yml

View file

@ -2,7 +2,9 @@ require 'pathname'
require 'fileutils'
require 'tempfile'
require 'parallel'
require 'middleman-core/dependencies'
require 'middleman-core/dependencies/graph'
require 'middleman-core/dependencies/edge'
require 'middleman-core/dependencies/vertices/file_vertex'
require 'middleman-core/callback_manager'
require 'middleman-core/contracts'
@ -81,8 +83,7 @@ module Middleman
prerender_css.tap do |resources|
if @track_dependencies
resources.each do |r|
dependency = r[1]
@graph.add_dependency(dependency) unless dependency.nil?
@graph.add_edge(r[1]) unless r[1].nil?
end
end
end
@ -94,8 +95,7 @@ module Middleman
output_files.tap do |resources|
if @track_dependencies
resources.each do |r|
dependency = r[1]
@graph.add_dependency(dependency) unless dependency.nil?
@graph.add_edge(r[1]) unless r[1].nil?
end
end
end
@ -120,7 +120,7 @@ module Middleman
# Pre-request CSS to give Compass a chance to build sprites
# @return [Array<Resource>] List of css resources that were output.
Contract ArrayOf[[Pathname, Maybe[::Middleman::Dependencies::DependencyLink]]]
Contract ArrayOf[[Pathname, Maybe[::Middleman::Dependencies::Edge]]]
def prerender_css
logger.debug '== Prerendering CSS'
@ -143,7 +143,7 @@ module Middleman
# Find all the files we need to output and do so.
# @return [Array<Resource>] List of resources that were output.
Contract ArrayOf[[Pathname, Maybe[::Middleman::Dependencies::DependencyLink]]]
Contract ArrayOf[[Pathname, Maybe[::Middleman::Dependencies::Edge]]]
def output_files
logger.debug '== Building files'
@ -155,7 +155,7 @@ module Middleman
output_resources(resources.to_a)
end
Contract OldResourceList => ArrayOf[Or[Bool, [Pathname, Maybe[::Middleman::Dependencies::DependencyLink]]]]
Contract OldResourceList => ArrayOf[Or[Bool, [Pathname, Maybe[::Middleman::Dependencies::Edge]]]]
def output_resources(resources)
res_count = resources.count
@ -278,7 +278,7 @@ module Middleman
# Try to output a resource and capture errors.
# @param [Middleman::Sitemap::Resource] resource The resource.
# @return [void]
Contract IsA['Middleman::Sitemap::Resource'] => Or[Bool, [Pathname, Maybe[::Middleman::Dependencies::DependencyLink]]]
Contract IsA['Middleman::Sitemap::Resource'] => Or[Bool, [Pathname, Maybe[::Middleman::Dependencies::Edge]]]
def output_resource(resource)
::Middleman::Util.instrument 'builder.output.resource', path: File.basename(resource.destination_path) do
begin
@ -305,17 +305,17 @@ module Middleman
end
end
deps = nil
vertices = nil
if resource.binary?
export_file!(output_file, resource.file_descriptor[:full_path], true)
else
content = resource.render({}, {})
unless resource.dependencies.empty?
deps = ::Middleman::Dependencies::DependencyLink.new(
::Middleman::Dependencies::FileDependency.from_resource(resource),
resource.dependencies
unless resource.vertices.empty?
vertices = ::Middleman::Dependencies::Edge.new(
::Middleman::Dependencies::FileVertex.from_resource(resource),
resource.vertices
)
end
@ -326,7 +326,7 @@ module Middleman
return false
end
[output_file, deps]
[output_file, vertices]
end
end

View file

@ -19,6 +19,29 @@ if ENV['CONTRACTS'] != 'false'
end
VectorOf = Contracts::CollectionOf::Factory.new(::Hamster::Vector)
class ImmutableHashOf < Contracts::CallableClass
INVALID_KEY_VALUE_PAIR = 'You should provide only one key-value pair to HashOf contract'.freeze
def initialize(key, value)
@key = key
@value = value
end
def valid?(hash)
return false unless hash.is_a?(::Hamster::Hash)
keys_match = hash.keys.map { |k| Contract.valid?(k, @key) }.all?
vals_match = hash.values.map { |v| Contract.valid?(v, @value) }.all?
[keys_match, vals_match].all?
end
def to_s
"ImmutableHash<#{@key}, #{@value}>"
end
end
ImmutableSetOf = Contracts::CollectionOf::Factory.new(::Hamster::Set)
ImmutableSortedSetOf = Contracts::CollectionOf::Factory.new(::Hamster::SortedSet)
OldResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
@ -110,6 +133,9 @@ else
class VectorOf < Callable
end
class ImmutableHashOf < Callable
end
class ImmutableSetOf < Callable
end
end

View file

@ -1,261 +1,47 @@
require 'middleman-core/contracts'
require 'set'
require 'pathname'
require 'digest/sha1'
require 'yaml'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/graph'
require 'middleman-core/dependencies/vertices'
module Middleman
module Dependencies
class BaseDependency
include Contracts
DEPENDENCY_KEY = Or[String, Symbol]
DEPENDENCY_ATTRS = HashOf[Symbol, String]
SERIALIZED_DEPENDENCY = {
key: Any, # Weird inheritance bug
type: Symbol,
attributes: DEPENDENCY_ATTRS
}.freeze
Contract DEPENDENCY_KEY
attr_reader :key
Contract DEPENDENCY_ATTRS
attr_reader :attributes
Contract DEPENDENCY_KEY, DEPENDENCY_ATTRS => Any
def initialize(key, attributes)
@key = key
@attributes = attributes
end
Contract BaseDependency => Bool
def ==(other)
key == other.key
end
Contract Bool
def valid?
raise NotImplementedError
end
Contract IsA['Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(_resource)
raise NotImplementedError
end
Contract Maybe[DEPENDENCY_ATTRS] => SERIALIZED_DEPENDENCY
def serialize(attributes = {})
{
key: @key,
type: type_id,
attributes: @attributes.merge(attributes)
}
end
protected
Contract Symbol
def type_id
self.class.const_get :TYPE_ID
end
Contract Pathname, String => String
def relative_path(root, file)
Pathname(File.expand_path(file)).relative_path_from(root).to_s
end
Contract Pathname, String => String
def full_path(root, file)
File.expand_path(file, root)
end
end
class FileDependency < BaseDependency
include Contracts
TYPE_ID = :file
Contract IsA['::Middleman::Application'], String, BaseDependency::DEPENDENCY_ATTRS => FileDependency
def self.deserialize(app, key, attributes)
FileDependency.new(app.root_path, key, attributes)
end
Contract IsA['Middleman::Sitemap::Resource'] => FileDependency
def self.from_resource(resource)
from_source_file(resource.app, resource.file_descriptor)
end
Contract IsA['::Middleman::Application'], IsA['::Middleman::SourceFile'] => FileDependency
def self.from_source_file(app, source_file)
FileDependency.new(app.root_path, source_file[:full_path].to_s)
end
Contract Or[String, Pathname], String, Maybe[DEPENDENCY_ATTRS] => Any
def initialize(root, key, attributes = {})
@root = Pathname(root)
@full_path = full_path(@root, key)
super(relative_path(@root, key), attributes)
end
Contract Bool
def valid?
@is_valid = (previous_hash.nil? || hash_file == previous_hash) if @is_valid.nil?
@is_valid
end
Contract IsA['Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(resource)
resource.file_descriptor[:full_path].to_s == @full_path
end
Contract BaseDependency::SERIALIZED_DEPENDENCY
def serialize
super({
hash: valid? && !previous_hash.nil? ? previous_hash : hash_file
})
end
private
Contract Maybe[String]
def previous_hash
@attributes[:hash]
end
Contract String
def hash_file
::Digest::SHA1.file(@full_path).hexdigest
end
end
DEPENDENCY_CLASSES_BY_TYPE = {
FileDependency::TYPE_ID => FileDependency
}.freeze
class DependencyLink
include Contracts
Contract BaseDependency
attr_reader :dependency
Contract Maybe[SetOf[BaseDependency]]
attr_accessor :depends_on
Contract BaseDependency, Maybe[SetOf[BaseDependency]] => Any
def initialize(dependency, depends_on = nil)
@dependency = dependency
@depends_on = nil
@depends_on = Set.new(depends_on) unless depends_on.nil?
end
Contract String
def to_s
"#<#{self.class} file=#{@dependency} depends_on=#{@depends_on}>"
end
end
class Graph
include Contracts
Contract HashOf[BaseDependency::DEPENDENCY_KEY, BaseDependency]
attr_reader :dependencies
Contract HashOf[BaseDependency, SetOf[BaseDependency]]
attr_accessor :dependency_map
def initialize(dependencies = {})
@dependencies = dependencies
@dependency_map = {}
end
Contract BaseDependency => BaseDependency
def known_dependency_or_new(dep)
@dependencies[dep.key] ||= dep
end
Contract DependencyLink => Any
def add_dependency(link)
deduped_depender = known_dependency_or_new link.dependency
@dependency_map[deduped_depender] ||= Set.new
@dependency_map[deduped_depender] << deduped_depender
return if link.depends_on.nil?
link.depends_on.each do |depended_on|
deduped_depended_on = known_dependency_or_new depended_on
@dependency_map[deduped_depended_on] ||= Set.new
@dependency_map[deduped_depended_on] << deduped_depended_on
@dependency_map[deduped_depended_on] << deduped_depender
end
end
Contract String => Bool
def exists?(file_path)
@dependency_map.key?(file_path)
end
Contract SetOf[BaseDependency]
def invalidated
@_invalidated_cache ||= begin
invalidated_dependencies = @dependency_map.keys.select do |dependency|
# Either "Missing from known dependencies"
# Or invalided by the class
!@dependencies.key?(dependency.key) || !dependency.valid?
end
invalidated_dependencies.reduce(Set.new) do |sum, dependency|
sum | invalidated_with_parents(dependency)
end
end
end
Contract BaseDependency => SetOf[BaseDependency]
def invalidated_with_parents(dependency)
# TODO, recurse more?
(Set.new + (@dependency_map[dependency])) << dependency
end
Contract IsA['::Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(resource)
invalidated.any? { |d| d.invalidates_resource?(resource) }
end
end
include Contracts
DEFAULT_FILE_PATH = 'deps.yml'.freeze
RUBY_FILES = ['**/*.rb', 'Gemfile.lock'].freeze
module_function
Contract IsA['::Middleman::Application'], Graph => String
def serialize(app, graph)
ruby_files = Dir['**/*.rb', 'Gemfile.lock'].reduce([]) do |sum, file|
ruby_files = Dir.glob(RUBY_FILES).reduce([]) do |sum, file|
sum << {
file: Pathname(File.expand_path(file)).relative_path_from(app.root_path).to_s,
hash: ::Digest::SHA1.file(file).hexdigest
}
end
dependency_links = graph.dependency_map.reduce([]) do |sum, (dependency, depended_on_by)|
edges = graph.dependency_map.reduce([]) do |sum, (vertex, depended_on_by)|
sum << {
key: dependency.key,
depended_on_by: depended_on_by.delete(dependency).to_a.map(&:key).sort
key: vertex.key,
depended_on_by: depended_on_by.delete(vertex).to_a.map(&:key).sort
}
end
dependencies = graph.dependency_map.reduce([]) do |sum, (dependency, _depended_on_by)|
sum << dependency.serialize
vertices = graph.dependency_map.reduce([]) do |sum, (vertex, _depended_on_by)|
sum << vertex.serialize
end
::YAML.dump(
ruby_files: ruby_files.sort_by { |d| d[:file] },
dependency_links: dependency_links.sort_by { |d| d[:file] },
dependencies: dependencies.sort_by { |d| d[:key] }
edges: edges.sort_by { |d| d[:file] },
vertices: vertices.sort_by { |d| d[:key] }
)
end
DEFAULT_FILE_PATH = 'deps.yml'.freeze
Contract IsA['::Middleman::Application'], Graph, Maybe[String] => Any
def serialize_and_save(app, graph, file_path = DEFAULT_FILE_PATH)
File.open(file_path, 'w') do |file|
@ -302,19 +88,19 @@ module Middleman
raise InvalidatedRubyFiles, invalidated
end
dependencies = data[:dependencies].each_with_object({}) do |row, sum|
dep_class = DEPENDENCY_CLASSES_BY_TYPE[row[:type]]
dep = dep_class.deserialize(app, row[:key], row[:attributes])
sum[dep.key] = dep
vertices = data[:vertices].each_with_object({}) do |row, sum|
vertex_class = VERTICES_BY_TYPE[row[:type]]
vertex = vertex_class.deserialize(app, row[:key], row[:attributes])
sum[vertex.key] = vertex
end
graph = Graph.new(dependencies)
graph = Graph.new(vertices)
dependency_links = data[:dependency_links]
graph.dependency_map = dependency_links.each_with_object({}) do |row, sum|
dependency = graph.dependencies[row[:key]]
depended_on_by = row[:depended_on_by].map { |k| graph.dependencies[k] }
sum[dependency] = Set.new(depended_on_by) << dependency
edges = data[:edges]
graph.dependency_map = edges.each_with_object({}) do |row, sum|
vertex = graph.vertices[row[:key]]
depended_on_by = row[:depended_on_by].map { |k| graph.vertices[k] }
sum[vertex] = ::Hamster::Set.new(depended_on_by) << vertex
end
graph

View file

@ -0,0 +1,27 @@
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
module Middleman
module Dependencies
class Edge
include Contracts
Contract Vertex
attr_reader :vertex
Contract ImmutableSetOf[Vertex]
attr_accessor :depends_on
Contract Vertex, ImmutableSetOf[Vertex] => Any
def initialize(vertex, depends_on)
@vertex = vertex
@depends_on = depends_on
end
Contract String
def to_s
"#<#{self.class} vertex=#{@vertex} edges=#{@edges}>"
end
end
end
end

View file

@ -0,0 +1,78 @@
require 'set'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
require 'middleman-core/dependencies/edge'
module Middleman
module Dependencies
class Graph
include Contracts
Contract HashOf[Vertex::VERTEX_KEY, Vertex]
attr_reader :vertices
Contract ImmutableHashOf[Vertex, ImmutableSetOf[Vertex]]
attr_accessor :dependency_map
def initialize(vertices = {})
@vertices = vertices
@dependency_map = ::Hamster::Hash.empty
end
Contract Vertex => Vertex
def known_vertex_or_new(v)
@vertices[v.key] ||= v
end
Contract Edge => Any
def add_edge(edge)
deduped_vertex = known_vertex_or_new edge.vertex
@dependency_map.put(deduped_vertex) do |v|
(v || ::Hamster::Set.empty) << deduped_vertex
end
return if edge.depends_on.nil?
edge.depends_on.each do |depended_on|
deduped_depended_on = known_vertex_or_new depended_on
@dependency_map.put(deduped_depended_on) do |v|
(v || ::Hamster::Set.empty) << deduped_depended_on << deduped_vertex
end
end
end
Contract String => Bool
def exists?(file_path)
@dependency_map.key?(file_path)
end
Contract ImmutableSetOf[Vertex]
def invalidated
@_invalidated_cache ||= begin
invalidated_vertices = @dependency_map.keys.select do |vertex|
# Either "Missing from known vertices"
# Or invalided by the class
!@vertices.key?(vertex.key) || !vertex.valid?
end
invalidated_vertices.reduce(::Hamster::Set.empty) do |sum, vertex|
sum | invalidated_with_parents(vertex)
end
end
end
Contract Vertex => ImmutableSetOf[Vertex]
def invalidated_with_parents(vertex)
# TODO, recurse more?
@dependency_map[vertex] << vertex
end
Contract IsA['::Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(resource)
invalidated.any? { |d| d.invalidates_resource?(resource) }
end
end
end
end

View file

@ -0,0 +1,9 @@
require 'middleman-core/dependencies/vertices/file_vertex'
module Middleman
module Dependencies
VERTICES_BY_TYPE = {
FileVertex::TYPE_ID => FileVertex
}.freeze
end
end

View file

@ -0,0 +1,66 @@
require 'pathname'
require 'digest/sha1'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
module Middleman
module Dependencies
class FileVertex < Vertex
include Contracts
TYPE_ID = :file
Contract IsA['::Middleman::Application'], String, Vertex::VERTEX_ATTRS => FileVertex
def self.deserialize(app, key, attributes)
FileVertex.new(app.root_path, key, attributes)
end
Contract IsA['Middleman::Sitemap::Resource'] => FileVertex
def self.from_resource(resource)
from_source_file(resource.app, resource.file_descriptor)
end
Contract IsA['::Middleman::Application'], IsA['::Middleman::SourceFile'] => FileVertex
def self.from_source_file(app, source_file)
FileVertex.new(app.root_path, source_file[:full_path].to_s)
end
Contract Or[String, Pathname], String, Maybe[VERTEX_ATTRS] => Any
def initialize(root, key, attributes = {})
@root = Pathname(root)
@full_path = full_path(@root, key)
super(relative_path(@root, key), attributes)
end
Contract Bool
def valid?
@is_valid = (previous_hash.nil? || hash_file == previous_hash) if @is_valid.nil?
@is_valid
end
Contract IsA['Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(resource)
resource.file_descriptor[:full_path].to_s == @full_path
end
Contract Vertex::SERIALIZED_VERTEX
def serialize
super({
hash: valid? && !previous_hash.nil? ? previous_hash : hash_file
})
end
private
Contract Maybe[String]
def previous_hash
@attributes[:hash]
end
Contract String
def hash_file
::Digest::SHA1.file(@full_path).hexdigest
end
end
end
end

View file

@ -0,0 +1,71 @@
require 'pathname'
require 'middleman-core/contracts'
module Middleman
module Dependencies
class Vertex
include Contracts
VERTEX_KEY = Or[String, Symbol]
VERTEX_ATTRS = HashOf[Symbol, String]
SERIALIZED_VERTEX = {
key: Any, # Weird inheritance bug
type: Symbol,
attributes: VERTEX_ATTRS
}.freeze
Contract VERTEX_KEY
attr_reader :key
Contract VERTEX_ATTRS
attr_reader :attributes
Contract VERTEX_KEY, VERTEX_ATTRS => Any
def initialize(key, attributes)
@key = key
@attributes = attributes
end
Contract Vertex => Bool
def ==(other)
key == other.key
end
Contract Bool
def valid?
raise NotImplementedError
end
Contract IsA['Middleman::Sitemap::Resource'] => Bool
def invalidates_resource?(_resource)
raise NotImplementedError
end
Contract Maybe[VERTEX_ATTRS] => SERIALIZED_VERTEX
def serialize(attributes = {})
{
key: @key,
type: type_id,
attributes: @attributes.merge(attributes)
}
end
protected
Contract Symbol
def type_id
self.class.const_get :TYPE_ID
end
Contract Pathname, String => String
def relative_path(root, file)
Pathname(File.expand_path(file)).relative_path_from(root).to_s
end
Contract Pathname, String => String
def full_path(root, file)
File.expand_path(file, root)
end
end
end
end

View file

@ -1,8 +1,9 @@
require 'tilt'
require 'set'
require 'hamster'
require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/module/delegation'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
::Tilt.default_mapping.lazy_map.delete('html')
::Tilt.default_mapping.lazy_map.delete('csv')
@ -16,15 +17,15 @@ module Middleman
@_cache ||= ::Tilt::Cache.new
end
Contract Maybe[SetOf[IsA['::Middleman::Dependencies::BaseDependency']]]
attr_reader :dependencies
Contract ImmutableSetOf[::Middleman::Dependencies::Vertex]
attr_reader :vertices
def_delegator :"self.class", :cache
def initialize(app, path)
@app = app
@path = path.to_s
@dependencies = nil
@vertices = ::Hamster::Set.empty
end
# Render an on-disk file. Used for everything, including layouts.
@ -71,12 +72,12 @@ module Middleman
# ::Tilt.new(path, 1, options) { body }
# end
@dependencies = nil
@vertices = ::Hamster::Set.empty
# Render using Tilt
content = ::Middleman::Util.instrument 'render.tilt', path: path do
template.render(context, locs, &block).tap do
@dependencies = template.dependencies if template.respond_to?(:dependencies)
@vertices = template.vertices if template.respond_to?(:vertices)
end
end

View file

@ -1,4 +1,6 @@
require 'hamster'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
module Middleman
class Filter
@ -31,7 +33,7 @@ module Middleman
@after_filter = @options.fetch(:after_filter, nil)
end
Contract String => String
Contract String => [String, ImmutableSetOf[::Middleman::Dependencies::Vertex]]
def execute_filter(_body)
raise NotImplementedError
end
@ -45,10 +47,10 @@ module Middleman
@callable = callable
end
Contract String => [String, Maybe[SetOf[String]]]
Contract String => [String, ImmutableSetOf[::Middleman::Dependencies::Vertex]]
def execute_filter(body)
result = @callable.call(body)
result.is_a?(Array) ? result : [result, nil]
result.is_a?(Array) ? result : [result, ::Hamster::Set.empty]
end
end
end

View file

@ -1,6 +1,9 @@
require 'hamster'
require 'middleman-core/util'
require 'middleman-core/filter'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
require 'middleman-core/dependencies/vertices/file_vertex'
module Middleman
class InlineURLRewriter < Filter
@ -28,13 +31,13 @@ module Middleman
@app.sitemap.by_destination_path(full_asset_path) || @app.sitemap.by_path(full_asset_path)
end
Contract String => [String, Maybe[SetOf[String]]]
Contract String => [String, ImmutableSetOf[::Middleman::Dependencies::Vertex]]
def execute_filter(body)
path = "/#{@resource.destination_path}"
dirpath = ::Pathname.new(File.dirname(path))
::Middleman::Util.instrument 'inline_url_filter', path: path do
deps = Set.new
vertices = ::Hamster::Set.empty
new_content = ::Middleman::Util.rewrite_paths(body, path, @options.fetch(:url_extensions), @app) do |asset_path|
uri = ::Middleman::Util.parse_uri(asset_path)
@ -55,7 +58,7 @@ module Middleman
if result
if @options.fetch(:create_dependencies, false)
deps << ::Middleman::Dependencies::FileDependency.from_resource(
vertices <<= ::Middleman::Dependencies::FileVertex.from_resource(
target_resource(asset_path, dirpath)
)
end
@ -66,7 +69,7 @@ module Middleman
asset_path
end
[new_content, deps]
[new_content, vertices]
end
end
end

View file

@ -1,6 +1,7 @@
require 'set'
require 'hamster'
require 'sass'
require 'middleman-core/dependencies'
require 'middleman-core/dependencies/vertices/file_vertex'
begin
require 'sassc'
@ -76,12 +77,10 @@ module Middleman
end
end
def dependencies
files = @engine.dependencies.map do |d|
::Middleman::Dependencies::FileDependency.new(@context.app.root_path, d.filename)
def vertices
@engine.dependencies.reduce(::Hamster::Set.empty) do |sum, d|
sum << ::Middleman::Dependencies::FileVertex.new(@context.app.root_path, d.filename)
end
files.empty? ? nil : Set.new(files)
end
# Change Sass path, for url functions, to the build folder if we're building

View file

@ -1,10 +1,12 @@
require 'rack/mime'
require 'set'
require 'hamster'
require 'middleman-core/sitemap/extensions/traversal'
require 'middleman-core/file_renderer'
require 'middleman-core/template_renderer'
require 'middleman-core/contracts'
require 'set'
require 'middleman-core/inline_url_filter'
require 'middleman-core/dependencies/vertices/vertex'
module Middleman
# Sitemap namespace
@ -39,8 +41,8 @@ module Middleman
Contract Num
attr_reader :priority
Contract Maybe[SetOf[IsA['::Middleman::Dependencies::BaseDependency']]]
attr_reader :dependencies
Contract ImmutableSetOf[::Middleman::Dependencies::Vertex]
attr_reader :vertices
# Initialize resource with parent store and URL
# @param [Middleman::Sitemap::Store] store
@ -54,7 +56,7 @@ module Middleman
@ignored = false
@filters = ::Hamster::SortedSet.empty
@priority = priority
@dependencies = Set.new
@vertices = ::Hamster::Set.empty
source = Pathname(source) if source&.is_a?(String)
@ -175,7 +177,7 @@ module Middleman
# @return [String]
Contract Hash, Hash, Maybe[Proc] => String
def render(options_hash = ::Middleman::EMPTY_HASH, locs = ::Middleman::EMPTY_HASH, &_block)
@dependencies = Set.new
@vertices = ::Hamster::Set.empty
body = render_without_filters(options_hash, locs)
@ -186,7 +188,7 @@ module Middleman
output
elsif filter.is_a?(Filter)
result = filter.execute_filter(output)
@dependencies |= result[1] unless result[1].nil?
@vertices |= result[1]
result[0]
else
output
@ -219,7 +221,7 @@ module Middleman
renderer = ::Middleman::TemplateRenderer.new(@app, file_descriptor[:full_path].to_s)
renderer.render(locs, opts).to_str.tap do
@dependencies |= renderer.dependencies unless renderer.dependencies.nil?
@vertices |= renderer.vertices
end
end

View file

@ -1,7 +1,10 @@
require 'pathname'
require 'hamster'
require 'middleman-core/file_renderer'
require 'middleman-core/template_renderer'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
require 'middleman-core/dependencies/vertices/file_vertex'
module Middleman
# The TemplateContext Class
@ -22,8 +25,8 @@ module Middleman
# Required for Padrino's rendering
attr_accessor :current_engine
Contract Maybe[SetOf[IsA['::Middleman::Dependencies::BaseDependency']]]
attr_reader :dependencies
Contract ImmutableSetOf[::Middleman::Dependencies::Vertex]
attr_reader :vertices
# Shorthand references to global values on the app instance.
def_delegators :@app, :config, :logger, :sitemap, :server?, :build?, :environment?, :environment, :data, :extensions, :root, :development?, :production?
@ -38,7 +41,7 @@ module Middleman
@locs = locs
@opts = options_hash
@dependencies = Set.new
@vertices = ::Hamster::Set.empty
end
# Return the current buffer to the caller and clear the value internally.
@ -91,7 +94,7 @@ module Middleman
restore_buffer(buf_was)
end
@dependencies << ::Middleman::Dependencies::FileDependency.from_source_file(@app, layout_file)
@vertices <<= ::Middleman::Dependencies::FileVertex.from_source_file(@app, layout_file)
# Render the layout, with the contents of the block inside.
concat_safe_content render_file(layout_file, @locs, @opts) { content }
@ -118,7 +121,7 @@ module Middleman
source_path = sitemap.file_to_path(partial_file)
r = sitemap.by_path(source_path)
@dependencies << ::Middleman::Dependencies::FileDependency.from_source_file(@app, partial_file)
@vertices <<= ::Middleman::Dependencies::FileVertex.from_source_file(@app, partial_file)
result = if (r && !r.template?) || (Tilt[partial_file[:full_path]].nil? && partial_file[:full_path].exist?)
partial_file.read
@ -218,7 +221,7 @@ module Middleman
content_renderer = ::Middleman::FileRenderer.new(@app, path)
content = content_renderer.render(locs, opts, context, &block)
@dependencies |= content_renderer.dependencies unless content_renderer.dependencies.nil?
@vertices |= content_renderer.vertices
path = File.basename(path, File.extname(path))
rescue LocalJumpError

View file

@ -1,10 +1,11 @@
require 'tilt'
require 'set'
require 'hamster'
require 'active_support/core_ext/string/output_safety'
require 'middleman-core/contracts'
require 'middleman-core/template_context'
require 'middleman-core/file_renderer'
require 'middleman-core/dependencies'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
require 'middleman-core/dependencies/vertices/file_vertex'
module Middleman
class TemplateRenderer
@ -100,13 +101,13 @@ module Middleman
# Custom error class for handling
class TemplateNotFound < RuntimeError; end
Contract Maybe[SetOf[IsA['::Middleman::Dependencies::BaseDependency']]]
attr_reader :dependencies
Contract ImmutableSetOf[::Middleman::Dependencies::Vertex]
attr_reader :vertices
def initialize(app, path)
@app = app
@path = path
@dependencies = nil
@vertices = ::Hamster::Set.empty
end
# Render a template, with layout, given a path
@ -174,8 +175,8 @@ module Middleman
::Middleman::Util.instrument 'builder.output.resource.render-layout', path: File.basename(layout_file[:relative_path].to_s) do
layout_renderer.render(locals, options, context) { content }.tap do
@dependencies << ::Middleman::Dependencies::FileDependency.from_source_file(@app, layout_file)
@dependencies |= layout_renderer.dependencies unless layout_renderer.dependencies.nil?
@vertices <<= ::Middleman::Dependencies::FileVertex.from_source_file(@app, layout_file)
@vertices |= layout_renderer.vertices
end
end
else
@ -183,8 +184,7 @@ module Middleman
end
end
@dependencies |= context.dependencies unless context.dependencies.nil?
@dependencies = @dependencies.empty? ? nil : @dependencies
@vertices |= context.vertices
# Return result
content
@ -201,7 +201,7 @@ module Middleman
# handles cases like `style.css.sass.erb`
content = nil
@dependencies = Set.new
@vertices = ::Hamster::Set.empty
while ::Middleman::Util.tilt_class(path)
begin
@ -209,7 +209,7 @@ module Middleman
content_renderer = ::Middleman::FileRenderer.new(@app, path)
content = content_renderer.render(locs, opts, context, &block)
@dependencies |= content_renderer.dependencies unless content_renderer.dependencies.nil?
@vertices |= content_renderer.vertices
path = path.sub(/\.[^.]*\z/, '')
rescue LocalJumpError