From 913d2b704993da1c922fa9201f54006e7092cb29 Mon Sep 17 00:00:00 2001 From: Thomas Reynolds Date: Thu, 13 Jun 2013 09:05:13 -0700 Subject: [PATCH] Implement generic which is a simple way to build a file from Rack --- CHANGELOG.md | 1 + middleman-core/features/mount_rack.feature | 61 +++++- middleman-core/fixtures/sinatra-app/config.rb | 3 + .../lib/middleman-core/cli/build.rb | 2 +- middleman-core/lib/middleman-core/sitemap.rb | 2 + .../sitemap/extensions/request_endpoints.rb | 177 ++++++++++++++++++ .../lib/middleman-core/sitemap/resource.rb | 4 + .../lib/middleman-core/sitemap/store.rb | 3 + 8 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 middleman-core/lib/middleman-core/sitemap/extensions/request_endpoints.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d38d54f..19e3a243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ === * Blocks with different templating languages than their layout now work as expected. #860 +* The `endpoint` method allows the building of Rack-based files or arbitrary content. 3.1.0.rc.2 === diff --git a/middleman-core/features/mount_rack.feature b/middleman-core/features/mount_rack.feature index 8e88b164..b2dbe5a0 100644 --- a/middleman-core/features/mount_rack.feature +++ b/middleman-core/features/mount_rack.feature @@ -5,4 +5,63 @@ Feature: Support Rack apps mounted using map When I go to "/" Then I should see "Hello World (Middleman)" When I go to "/sinatra/" - Then I should see "Hello World (Sinatra)" \ No newline at end of file + Then I should see "Hello World (Sinatra)" + + Scenario: Built Mounted Rack App at /sinatra + Given a successfully built app at "sinatra-app" + When I cd to "build" + Then the following files should exist: + | index.html | + Then the following files should not exist: + | sinatra/index.html | + | sinatra/index2.html | + + Scenario: Static Ruby Endpoints + Given a fixture app "sinatra-app" + And a file named "config.rb" with: + """ + endpoint "hello.html" do + "world" + end + """ + And the Server is running at "sinatra-app" + When I go to "/hello.html" + Then I should see "world" + + Scenario: Built Mounted Rack App at /sinatra (including rack endpoints) + Given a fixture app "sinatra-app" + And a file named "config.rb" with: + """ + require "sinatra" + + class MySinatra < Sinatra::Base + get "/" do + "Hello World (Sinatra)" + end + get "/derp.html" do + "De doo" + end + end + + map "/sinatra" do + run MySinatra + end + + configure :build do + endpoint "sinatra/index2.html", :path => "/sinatra/" + end + + endpoint "dedoo.html", :path => "/sinatra/derp.html" + + endpoint "hello.html" do + "world" + end + """ + And a successfully built app at "sinatra-app" + When I cd to "build" + Then the following files should exist: + | index.html | + | sinatra/index2.html | + | dedoo.html | + And the file "sinatra/index2.html" should contain 'Hello World (Sinatra)' + And the file "dedoo.html" should contain 'De doo' \ No newline at end of file diff --git a/middleman-core/fixtures/sinatra-app/config.rb b/middleman-core/fixtures/sinatra-app/config.rb index b64a4361..0251a715 100644 --- a/middleman-core/fixtures/sinatra-app/config.rb +++ b/middleman-core/fixtures/sinatra-app/config.rb @@ -4,6 +4,9 @@ class MySinatra < Sinatra::Base get "/" do "Hello World (Sinatra)" end + get "/derp.html" do + "De doo" + end end map "/sinatra" do diff --git a/middleman-core/lib/middleman-core/cli/build.rb b/middleman-core/lib/middleman-core/cli/build.rb index a3261d2e..1bad224c 100644 --- a/middleman-core/lib/middleman-core/cli/build.rb +++ b/middleman-core/lib/middleman-core/cli/build.rb @@ -135,7 +135,7 @@ module Middleman::Cli FileUtils.cp(resource.source_file, output_file) else begin - response = self.class.shared_rack.get(URI.escape(resource.destination_path)) + response = self.class.shared_rack.get(URI.escape(resource.request_path)) if response.status == 200 create_file(output_file, binary_encode(response.body)) diff --git a/middleman-core/lib/middleman-core/sitemap.rb b/middleman-core/lib/middleman-core/sitemap.rb index 88d2bbb9..c41d6125 100644 --- a/middleman-core/lib/middleman-core/sitemap.rb +++ b/middleman-core/lib/middleman-core/sitemap.rb @@ -2,6 +2,7 @@ require "middleman-core/sitemap/store" require "middleman-core/sitemap/resource" require "middleman-core/sitemap/extensions/on_disk" +require "middleman-core/sitemap/extensions/request_endpoints" require "middleman-core/sitemap/extensions/proxies" require "middleman-core/sitemap/extensions/ignores" @@ -16,6 +17,7 @@ module Middleman # Once registered def registered(app) + app.register Middleman::Sitemap::Extensions::RequestEndpoints app.register Middleman::Sitemap::Extensions::Proxies app.register Middleman::Sitemap::Extensions::Ignores diff --git a/middleman-core/lib/middleman-core/sitemap/extensions/request_endpoints.rb b/middleman-core/lib/middleman-core/sitemap/extensions/request_endpoints.rb new file mode 100644 index 00000000..43d33503 --- /dev/null +++ b/middleman-core/lib/middleman-core/sitemap/extensions/request_endpoints.rb @@ -0,0 +1,177 @@ +module Middleman + + module Sitemap + + module Extensions + + module RequestEndpoints + + # Setup extension + class << self + + # Once registered + def registered(app) + # ::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods + + # Include methods + app.send :include, InstanceMethods + end + + alias :included :registered + end + + # module ResourceInstanceMethods + # # Whether this page is a proxy + # # @return [Boolean] + # def proxy? + # !!@proxied_to + # end + + # # Set this page to proxy to a target path + # # @param [String] target + # # @return [void] + # def proxy_to(target) + # target = ::Middleman::Util.normalize_path(target) + # raise "You can't proxy #{path} to itself!" if target == path + # @proxied_to = target + # end + + # # The path of the page this page is proxied to, or nil if it's not proxied. + # # @return [String] + # def proxied_to + # @proxied_to + # end + + # # The resource for the page this page is proxied to. Throws an exception + # # if there is no resource. + # # @return [Sitemap::Resource] + # def proxied_to_resource + # proxy_resource = store.find_resource_by_path(proxied_to) + + # unless proxy_resource + # raise "Path #{path} proxies to unknown file #{proxied_to}:#{store.resources.map(&:path)}" + # end + + # if proxy_resource.proxy? + # raise "You can't proxy #{path} to #{proxied_to} which is itself a proxy." + # end + + # proxy_resource + # end + + # def get_source_file + # if proxy? + # proxied_to_resource.source_file + # else + # super + # end + # end + + # def content_type + # mime_type = super + # return mime_type if mime_type + + # if proxy? + # proxied_to_resource.content_type + # else + # nil + # end + # end + # end + + module InstanceMethods + def endpoint_manager + @_endpoint_manager ||= EndpointManager.new(self) + end + + def endpoint(*args, &block) + endpoint_manager.create_endpoint(*args, &block) + end + end + + # Manages the list of proxy configurations and manipulates the sitemap + # to include new resources based on those configurations + class EndpointManager + def initialize(app) + @app = app + @endpoints = {} + end + + # Setup a proxy from a path to a target + # @param [String] path + # @param [Hash] The :path value gives a request path if it + # differs from the output path + # @return [void] + def create_endpoint(path, opts={}, &block) + endpoint = { + :request_path => path + } + + if block_given? + endpoint[:output] = block + else + endpoint[:request_path] = opts[:path] if opts.has_key?(:path) + end + + @endpoints[path] = endpoint + + @app.sitemap.rebuild_resource_list!(:added_endpoint) + end + + # Update the main sitemap resource list + # @return [void] + def manipulate_resource_list(resources) + resources + @endpoints.map do |path, config| + r = EndpointResource.new( + @app.sitemap, + path, + config[:request_path] + ) + r.output = config[:output] if config.has_key?(:output) + r + end + end + end + + class EndpointResource < ::Middleman::Sitemap::Resource + attr_accessor :output + + def initialize(store, path, source_file) + @request_path = ::Middleman::Util.normalize_path(source_file) + + super(store, path) + end + + def template? + true + end + + def render(*args, &block) + return self.output.call if self.output + end + + def request_path + @request_path + end + + def binary? + false + end + + def raw_data + {} + end + + def ignored? + false + end + + def metadata + @local_metadata.dup + end + + end + end + end + end +end diff --git a/middleman-core/lib/middleman-core/sitemap/resource.rb b/middleman-core/lib/middleman-core/sitemap/resource.rb index 63e29396..4cb181cb 100644 --- a/middleman-core/lib/middleman-core/sitemap/resource.rb +++ b/middleman-core/lib/middleman-core/sitemap/resource.rb @@ -105,6 +105,10 @@ module Middleman File.extname(path) end + def request_path + self.destination_path + end + # Render this resource # @return [String] def render(opts={}, locs={}, &block) diff --git a/middleman-core/lib/middleman-core/sitemap/store.rb b/middleman-core/lib/middleman-core/sitemap/store.rb index 37cd0e71..4ae2bc15 100644 --- a/middleman-core/lib/middleman-core/sitemap/store.rb +++ b/middleman-core/lib/middleman-core/sitemap/store.rb @@ -36,6 +36,9 @@ module Middleman # Register classes which can manipulate the main site map list register_resource_list_manipulator(:on_disk, Middleman::Sitemap::Extensions::OnDisk.new(self)) + # Request Endpoints + register_resource_list_manipulator(:request_endpoints, @app.endpoint_manager) + # Proxies register_resource_list_manipulator(:proxies, @app.proxy_manager) end