Implement generic which is a simple way to build a file from Rack

This commit is contained in:
Thomas Reynolds 2013-06-13 09:05:13 -07:00
parent f97c9ffab1
commit 913d2b7049
8 changed files with 251 additions and 2 deletions

View file

@ -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
===

View file

@ -6,3 +6,62 @@ Feature: Support Rack apps mounted using map
Then I should see "Hello World (Middleman)"
When I go to "/sinatra/"
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'

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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