From 2d0c74054a3897f5d3f5b61ca201d9257c5236e5 Mon Sep 17 00:00:00 2001 From: Thomas Reynolds Date: Sun, 20 Nov 2011 13:48:28 -0800 Subject: [PATCH] begin work to let each path maintain it's own state. Paves the way for a dynamic rebuild command --- lib/middleman/base.rb | 62 ++-- lib/middleman/builder.rb | 8 +- lib/middleman/cache.rb | 2 +- lib/middleman/core_extensions/front_matter.rb | 1 + lib/middleman/core_extensions/routing.rb | 27 +- lib/middleman/core_extensions/sitemap.rb | 337 +++++++++++------- lib/middleman/renderers/liquid.rb | 2 + 7 files changed, 264 insertions(+), 175 deletions(-) diff --git a/lib/middleman/base.rb b/lib/middleman/base.rb index 3134e5c0..e3a4bd5a 100644 --- a/lib/middleman/base.rb +++ b/lib/middleman/base.rb @@ -64,19 +64,6 @@ class Middleman::Base end def asset_stamp; false; end - - def before_processing(name=:unnamed, idx=-1, &block) - @before_processes ||= [] - @before_processes.insert(idx, [name, block]) - end - - def execute_before_processing!(inst, resolved_template) - @before_processes ||= [] - - @before_processes.all? do |name, block| - inst.instance_exec(resolved_template, &block) - end - end end def set(key, value=nil, &block) @@ -202,11 +189,16 @@ class Middleman::Base @request_path = full_path(env["PATH_INFO"].gsub("%20", " ")) run_hook :before - - return not_found if sitemap.ignored_path?(@request_path) - if sitemap.path_is_proxy?(@request_path) - @request_path = "/" + sitemap.path_target(@request_path) + return not_found unless sitemap.exists?(@request_path) + + sitemap_page = sitemap.page(@request_path) + + return not_found if sitemap_page.ignored? + + if sitemap.proxied?(@request_path) + @request_path = "/" + sitemap_page.proxied_to + sitemap_page = sitemap.page(sitemap_page.proxied_to) end found_template = resolve_template(@request_path) @@ -216,33 +208,32 @@ class Middleman::Base path, engine = found_template # Static File - return send_file(path) if engine.nil? - - return unless self.class.execute_before_processing!(self, found_template) - - context = sitemap.get_context(full_path(@original_path.gsub("%20", " "))) || {} - - @options = context.has_key?(:options) ? context[:options] : {} - @locals = context.has_key?(:locals) ? context[:locals] : {} + return send_file(sitemap_page.source_file) unless sitemap_page.template? + + context = sitemap.page(full_path(@original_path.gsub("%20", " "))).template + @options = context.options.dup + @locals = context.locals.dup provides_metadata.each do |callback, matcher| next if !matcher.nil? && !path.match(matcher) instance_exec(path, &callback) end + context.blocks.each do |block| + instance_eval(&block) if block + end + local_layout = if options.has_key?(:layout) options[:layout] - elsif %w(.js .css .txt).include?(File.extname(@request_path)) + elsif %w(.js .css .txt).include?(sitemap_page.ext) false else layout end - - if context.has_key?(:block) && context[:block] - instance_eval(&context[:block]) - end - output = if local_layout + output = internal_render(path, locals, options) + + if local_layout engine_options = respond_to?(engine.to_sym) ? send(engine.to_sym) : {} layout_engine = if options.has_key?(:layout_engine) @@ -262,12 +253,8 @@ class Middleman::Base throw "Could not locate layout: #{local_layout}" unless layout_path - internal_render(layout_path, locals, options) do - internal_render(path, locals, options) - end - else - internal_render(path, locals) - end + output = internal_render(layout_path, locals, options) { output } + end content_type mime_type(File.extname(@request_path)) res.status = 200 @@ -422,7 +409,6 @@ public self.class.map(map, &block) end -private def internal_render(path, locals = {}, options = {}, &block) path = path.to_s diff --git a/lib/middleman/builder.rb b/lib/middleman/builder.rb index 3cb70526..ddfd3c38 100644 --- a/lib/middleman/builder.rb +++ b/lib/middleman/builder.rb @@ -146,11 +146,11 @@ module Middleman file_destination = File.join(given_destination, file_source.gsub(source, '.')) file_destination.gsub!('/./', '/') - if @app.sitemap.generic_path?(file_source) + if @app.sitemap.generic?(file_source) # no-op - elsif @app.sitemap.proxied_path?(file_source) - file_source = @app.sitemap.path_target(file_source) - elsif @app.sitemap.ignored_path?(file_source) + elsif @app.sitemap.proxied?(file_source) + file_source = @app.sitemap.page(file_source).proxied_to + elsif @app.sitemap.ignored?(file_source) next end diff --git a/lib/middleman/cache.rb b/lib/middleman/cache.rb index dd6f3922..23dd010e 100644 --- a/lib/middleman/cache.rb +++ b/lib/middleman/cache.rb @@ -17,7 +17,7 @@ module Middleman end def remove(*key) - @cache.delete(key) + @cache.delete(key) if @cache.has_key?(key) end end end \ No newline at end of file diff --git a/lib/middleman/core_extensions/front_matter.rb b/lib/middleman/core_extensions/front_matter.rb index bdda4c7b..ea397077 100644 --- a/lib/middleman/core_extensions/front_matter.rb +++ b/lib/middleman/core_extensions/front_matter.rb @@ -38,6 +38,7 @@ module Middleman::CoreExtensions::FrontMatter end @options.merge!(data) + { :options => data } end super diff --git a/lib/middleman/core_extensions/routing.rb b/lib/middleman/core_extensions/routing.rb index 070c22f0..f2601951 100644 --- a/lib/middleman/core_extensions/routing.rb +++ b/lib/middleman/core_extensions/routing.rb @@ -24,30 +24,33 @@ module Middleman::CoreExtensions::Routing # The page method allows the layout to be set on a specific path # page "/about.html", :layout => false # page "/", :layout => :homepage_layout - def page(url, options={}, &block) - options[:layout] = layout if options[:layout].nil? + def page(url, opts={}, &block) + opts[:layout] = layout if opts[:layout].nil? url = full_path(url) - if options.has_key?(:proxy) - reroute(url, options[:proxy]) + if opts.has_key?(:proxy) + reroute(url, opts[:proxy]) - if options.has_key?(:ignore) && options[:ignore] - ignore(options[:proxy]) - options.delete(:ignore) + if opts.has_key?(:ignore) && opts[:ignore] + ignore(opts[:proxy]) + opts.delete(:ignore) end - options.delete(:proxy) + opts.delete(:proxy) else - if options.has_key?(:ignore) && options[:ignore] + if opts.has_key?(:ignore) && opts[:ignore] ignore(url) - options.delete(:ignore) + opts.delete(:ignore) end end a_block = block_given? ? block : nil - if a_block || !options.empty? - sitemap.set_context(url, options, a_block) + if a_block || !opts.empty? + sitemap.page(url) do + template.options = opts + template.blocks = [a_block] + end end end end diff --git a/lib/middleman/core_extensions/sitemap.rb b/lib/middleman/core_extensions/sitemap.rb index f779bf2c..1dab36b9 100644 --- a/lib/middleman/core_extensions/sitemap.rb +++ b/lib/middleman/core_extensions/sitemap.rb @@ -27,11 +27,11 @@ module Middleman::CoreExtensions::Sitemap # Keep a path from building def ignore(path) - sitemap.ignore_path(path) + sitemap.ignore(path) end def reroute(url, target) - sitemap.set_path(url, target) + sitemap.proxy(url, target) end def provides_metadata(matcher=nil, &block) @@ -41,156 +41,254 @@ module Middleman::CoreExtensions::Sitemap end end + class SitemapTemplate + attr_accessor :page, :options, :locals, :blocks#, :dependencies + + def initialize(page) + @page = page + @options = {} + @locals = {} + @blocks = [] + end + # + # def path + # @page.path + # end + # + # def store + # @page.store + # end + # + # def app + # store.app + # end + # + # def ext + # @page.ext + # end + # + # def metadata + # cache.fetch(:metadata, path) do + # metadata = {} + # provides_metadata.each do |callback, matcher| + # next if !matcher.nil? && !path.match(matcher) + # metadata.merge(instance_exec(path, &callback)) + # end + # metadata + # end + # end + # + # def render(opts={}, locs={}) + # opts = options.merge(metadata[:options]).merge(opts) + # locs = locals.merge(metadata[:locals]).merge(locs) + # + # blocks.each do |block| + # instance_eval(&block) + # end + # + # content = app.internal_render(path, locals, options) + # + # if layout_path + # content = app.internal_render(layout_path, locals, options) { content } + # end + # + # content + # end + # + # protected + # def self.cache + # @_cache ||= ::Middleman::Cache.new + # end + # + # def cache + # self.class.cache + # end + # + # def options_for_ext(ext) + # cache.fetch(:options_for_ext, ext) do + # options = {} + # + # extension_class = Tilt[ext] + # Tilt.mappings.each do |ext, engines| + # next unless engines.include? extension_class + # engine_options = respond_to?(ext.to_sym) ? send(ext.to_sym) : {} + # options.merge!(engine_options) + # end + # + # options + # end + # end + # + # def layout_path + # return false if %w(.js .css .txt).include?(ext) + # local_layout = options.has_key?(:layout) ? options[:layout] : app.layout + # return false unless local_layout + # + # engine_options = app.respond_to?(engine.to_sym) ? app.send(engine.to_sym) : {} + # + # layout_engine = if options.has_key?(:layout_engine) + # options[:layout_engine] + # elsif engine_options.has_key?(:layout_engine) + # engine_options[:layout_engine] + # else + # engine + # end + # + # layout_path, *etc = app.resolve_template(local_layout, :preferred_engine => layout_engine) + # + # if !layout_path + # local_layout = File.join("layouts", local_layout.to_s) + # layout_path, *etc = app.resolve_template(local_layout, :preferred_engine => layout_engine) + # end + # + # throw "Could not locate layout: #{local_layout}" unless layout_path + # layout_path + end + + class SitemapPage + attr_accessor :path, :source_file, :proxied_to, :status + + def initialize(store, path) + @store = store + @path = path + @status = :generic + @source_file = nil + @proxied_to = nil + end + + def template? + return false if source_file.nil? + !Tilt[source_file].nil? + end + + def template + @_template ||= SitemapTemplate.new(self) + end + + def ext + File.extname(path) + end + + def mime_type + @store.app.mime_type ext + end + + def proxy? + @status == :proxy + end + + def proxy_to(target) + @status = :proxy + @proxied_to = target + end + + def generic? + @status == :generic + end + + def make_generic + @status = :generic + end + + def ignored? + @status == :ignored + end + + def ignore + @status = :ignored + end + + def touch + end + + protected + def app + @store.app + end + end + class SitemapStore + attr_accessor :app + def initialize(app) @app = app + @cache = ::Middleman::Cache.new @source = File.expand_path(@app.views, @app.root) - @map = {} - @context_map = {} - @source_map = {} - @ignored_paths = false - @generic_paths = false - @proxied_paths = false - - # build_static_map + @pages = {} end # Check to see if we know about a specific path - def path_exists?(path) - path = path.sub(/^\//, "") - @map.has_key?(path) + def exists?(path) + @pages.has_key?(path.sub(/^\//, "")) end - def path_is_proxy?(path) - path = path.sub(/^\//, "") - return false if !path_exists?(path) - @map[path].is_a?(String) - end - - def path_target(path) - path = path.sub(/^\//, "") - @map[path] - end - - def path_context(path) - path = path.sub(/^\//, "") - @context_map[path] - end - - def set_path(path, target=true) - path = path.sub(/^\//, "") - target = target.sub(/^\//, "") if target.is_a?(String) - - @map[path] = target - - @ignored_paths = false if target === false - @generic_paths = false if target === true - @proxied_paths = false if target.is_a?(String) - end - - def set_context(path, options={}, block=nil) - path = path.sub(/^\//, "") - @context_map[path] = { - :options => options, - :block => block - } - end - - def get_context(path) - path = path.sub(/^\//, "") - @context_map[path] - end - - def ignore_path(path) - set_path(path, false) - @ignored_paths = false - end - - def each(&block) - @map.each do |k, v| - yield(k, v) + def set_context(path, opts={}, blk=nil) + page(path) do + template.options = opts + template.blocks = [blk] end end + def ignore(path) + page(path) { ignore } + @cache.remove(:ignored_paths) + end + + def proxy(path, target) + page(path) { proxy_to(target.sub(%r{^/}, "")) } + @cache.remove(:proxied_paths) + end + + def page(path, &block) + path = path.sub(/^\//, "").gsub("%20", " ") + @pages[path] = SitemapPage.new(self, path) unless @pages.has_key?(path) + @pages[path].instance_exec(&block) if block_given? + @pages[path] + end + def all_paths - @map.keys + @pages.keys end - def all_values - @map.values - end - - def ignored_path?(path) - path = path.sub(/^\//, "") - ignored_paths.include?(path) + def ignored?(path) + ignored_paths.include?(path.sub(/^\//, "")) end def ignored_paths - @ignored_paths ||= begin - ignored = [] - each do |k, v| - ignored << k if v === false - end - ignored + @cache.fetch :ignored_paths do + @pages.values.select(&:ignored?).map(&:path) end end - def generic_path?(path) - path = path.sub(/^\//, "") - generic_paths.include?(path) + def generic?(path) + generic_paths.include?(path.sub(/^\//, "")) end def generic_paths - @generic_paths ||= begin - generic = [] - each do |k, v| - generic << k if v === true - end - generic + @cache.fetch :generic_paths do + @pages.values.select(&:generic?).map(&:path) end end - def proxied_path?(path) - path = path.sub(/^\//, "") - proxied_paths.include?(path) + def proxied?(path) + proxied_paths.include?(path.sub(/^\//, "")) end def proxied_paths - @proxied_paths ||= begin - proxied = [] - each do |k, v| - proxied << k if v.is_a?(String) - end - proxied + @cache.fetch :proxied_paths do + @pages.values.select(&:proxy?).map(&:path) end end - def touch_file(file) - add_file(file) - end - def remove_file(file) path = file_to_path(file) - remove_path(path) if path - end - - def remove_path(path) + return false unless path + path = path.sub(/^\//, "") - @map.delete(path) if path_exists?(path) + @pages.delete(path) if @pages.has_key?(path) @context_map.delete(path) if @context_map.has_key?(path) end - def source_map - @source_map - end - - protected - def build_static_map - Find.find(@source) do |file| - add_file(file) - end - end - def file_to_path(file) file = File.expand_path(file, @app.root) @@ -200,11 +298,10 @@ module Middleman::CoreExtensions::Sitemap path = file.sub(prefix, "") path = @app.extensionless_path(path) - @source_map[path] = file path end - def add_file(file) + def touch_file(file) return false if file == @source || file.match(/^\./) || file.match(/\/\./) || @@ -213,15 +310,15 @@ module Middleman::CoreExtensions::Sitemap path = file_to_path(file) - add_path(path) if path && !path_exists?(path) - end - - def add_path(path) + return false unless path + return false if path.match(%r{^layout}) || path.match(%r{^layouts/}) # @app.logger.debug :sitemap_update, Time.now, path if @app.logging? - set_path(path) + + # Add generic path + page(path).source_file = File.expand_path(file, @app.root) true end diff --git a/lib/middleman/renderers/liquid.rb b/lib/middleman/renderers/liquid.rb index cfdfff0b..c282763d 100644 --- a/lib/middleman/renderers/liquid.rb +++ b/lib/middleman/renderers/liquid.rb @@ -11,7 +11,9 @@ module Middleman::Renderers::Liquid provides_metadata %r{\.liquid$} do |path| @locals.merge!(:data => data.to_h) + { :locals => { :data => data.to_h } } end + end rescue LoadError end