Standardize exposing methods inside extensions to the outside world
This commit is contained in:
parent
33cb9b3ba9
commit
82b84668b0
15 changed files with 172 additions and 62 deletions
|
@ -1,6 +1,9 @@
|
|||
master
|
||||
===
|
||||
|
||||
* rename `app.add_to_instance` to `Extension.expose_to_application` for adding extension-local methods to the shared app instance.
|
||||
* rename `app.add_to_config_context` to `Extension.expose_to_config` for adding extension-local methods to the sandboxed scope of `config.rb`
|
||||
* Add `Extension.expose_to_templates`, which auto binds copies of extension-local methods into a Template context.
|
||||
* Remove side-loading of CLI tasks from `tasks/`
|
||||
* Add the option of naming `config.rb` as `middleman.rb`.
|
||||
* Builder extracted from Thor. `after_build` hook now passes an instance of a Builder instead of the Thor CLI.
|
||||
|
|
|
@ -305,14 +305,6 @@ module Middleman
|
|||
config_context.execute_configure_callbacks(config[:mode])
|
||||
end
|
||||
|
||||
def add_to_instance(name, &func)
|
||||
define_singleton_method(name, &func)
|
||||
end
|
||||
|
||||
def add_to_config_context(name, &func)
|
||||
@config_context.define_singleton_method(name, &func)
|
||||
end
|
||||
|
||||
# Whether we're in server mode
|
||||
# @return [Boolean] If we're in dev mode
|
||||
def server?
|
||||
|
|
|
@ -18,6 +18,20 @@ module Middleman
|
|||
|
||||
attr_accessor :sitemap_collector, :data_collector, :leaves
|
||||
|
||||
# Expose `resources`, `data`, and `collection` to config.
|
||||
expose_to_config resources: :sitemap_collector,
|
||||
data: :data_collector,
|
||||
collection: :register_collector
|
||||
|
||||
# Exposes `collection` to templates
|
||||
expose_to_template collection: :collector_value
|
||||
|
||||
helpers do
|
||||
def pagination
|
||||
current_resource.data.pagination
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
|
@ -29,13 +43,8 @@ module Middleman
|
|||
@data_collector = LazyCollectorRoot.new(self)
|
||||
end
|
||||
|
||||
Contract Any
|
||||
def before_configuration
|
||||
@leaves.clear
|
||||
|
||||
app.add_to_config_context :resources, &method(:sitemap_collector)
|
||||
app.add_to_config_context :data, &method(:data_collector)
|
||||
app.add_to_config_context :collection, &method(:register_collector)
|
||||
end
|
||||
|
||||
Contract Symbol, LazyCollectorStep => Any
|
||||
|
@ -69,16 +78,6 @@ module Middleman
|
|||
# Inject descriptors
|
||||
resources + ctx.descriptors.map { |d| d.to_resource(app) }
|
||||
end
|
||||
|
||||
helpers do
|
||||
def collection(label)
|
||||
extensions[:collections].collector_value(label)
|
||||
end
|
||||
|
||||
def pagination
|
||||
current_resource.data.pagination
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,12 @@ module Middleman
|
|||
class Data < Extension
|
||||
attr_reader :data_store
|
||||
|
||||
# Make the internal `data_store` method available as `app.data`
|
||||
expose_to_application data: :data_store
|
||||
|
||||
# Exposes `data` to templates
|
||||
expose_to_template data: :data_store
|
||||
|
||||
# The regex which tells Middleman which files are for data
|
||||
DATA_FILE_MATCHER = /^(.*?)[\w-]+\.(yml|yaml|json)$/
|
||||
|
||||
|
@ -18,8 +24,6 @@ module Middleman
|
|||
@data_store = DataStore.new(app, DATA_FILE_MATCHER)
|
||||
app.config.define_setting :data_dir, 'data', 'The directory data files are stored in'
|
||||
|
||||
app.add_to_instance(:data, &method(:data_store))
|
||||
|
||||
start_watching(app.config[:data_dir])
|
||||
end
|
||||
|
||||
|
@ -42,12 +46,6 @@ module Middleman
|
|||
@watcher.update_path(app.config[:data_dir])
|
||||
end
|
||||
|
||||
helpers do
|
||||
def data
|
||||
extensions[:data].data_store
|
||||
end
|
||||
end
|
||||
|
||||
# The core logic behind the data extension.
|
||||
class DataStore
|
||||
include Contracts
|
||||
|
|
|
@ -9,6 +9,12 @@ module Middleman
|
|||
Contract IsA['Middleman::Sources']
|
||||
attr_reader :sources
|
||||
|
||||
# Make the internal `sources` method available as `app.files`
|
||||
expose_to_application files: :sources
|
||||
|
||||
# Make the internal `sources` method available in config as `files`
|
||||
expose_to_config files: :sources
|
||||
|
||||
# The default list of ignores.
|
||||
IGNORES = {
|
||||
emacs_files: /(^|\/)\.?#/,
|
||||
|
@ -34,10 +40,6 @@ module Middleman
|
|||
|
||||
# Watch current source.
|
||||
start_watching(app.config[:source])
|
||||
|
||||
# Expose API to app and config.
|
||||
app.add_to_instance(:files, &method(:sources))
|
||||
app.add_to_config_context(:files, &method(:sources))
|
||||
end
|
||||
|
||||
# Before we config, find initial files.
|
||||
|
|
|
@ -7,6 +7,9 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
option :mount_at_root, nil, 'Mount a specific language at the root of the site'
|
||||
option :data, 'locales', 'The directory holding your locale configurations'
|
||||
|
||||
# Exposes `langs` to templates
|
||||
expose_to_template :langs
|
||||
|
||||
def after_configuration
|
||||
# See https://github.com/svenfuchs/i18n/wiki/Fallbacks
|
||||
unless options[:no_fallbacks]
|
||||
|
@ -41,12 +44,6 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
::I18n.t(*args)
|
||||
end
|
||||
|
||||
# Access the list of languages supported by this Middleman application
|
||||
# @return [Array<Symbol>]
|
||||
def langs
|
||||
extensions[:i18n].langs
|
||||
end
|
||||
|
||||
def locate_partial(partial_name, try_static=false)
|
||||
locals_dir = extensions[:i18n].options[:templates_dir]
|
||||
|
||||
|
|
|
@ -6,16 +6,15 @@ module Middleman
|
|||
# so it can add metadata to any pages generated by other extensions
|
||||
self.resource_list_manipulator_priority = 80
|
||||
|
||||
# Expose the `page` method to config.
|
||||
expose_to_config :page
|
||||
|
||||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
@page_configs = Set.new
|
||||
end
|
||||
|
||||
def before_configuration
|
||||
app.add_to_config_context(:page, &method(:page))
|
||||
end
|
||||
|
||||
# @return Array<Middleman::Sitemap::Resource>
|
||||
Contract ResourceList => ResourceList
|
||||
def manipulate_resource_list(resources)
|
||||
|
|
|
@ -82,6 +82,24 @@ module Middleman
|
|||
# @return [Array<Module>] a list of all the helper modules this extension provides. Set these using {#helpers}.
|
||||
class_attribute :defined_helpers, instance_reader: false, instance_writer: false
|
||||
|
||||
# @!attribute exposed_to_application
|
||||
# @!scope class
|
||||
# @api private
|
||||
# @return [Hash<Symbol, Symbol>] a list of all the methods modules this extension exposes to app. Set these using {#expose_to_application}.
|
||||
class_attribute :exposed_to_application, instance_reader: false, instance_writer: false
|
||||
|
||||
# @!attribute exposed_to_config
|
||||
# @!scope class
|
||||
# @api private
|
||||
# @return [Hash<Symbol, Symbol>] a list of all the methods modules this extension exposes to config. Set these using {#expose_to_config}.
|
||||
class_attribute :exposed_to_config, instance_reader: false, instance_writer: false
|
||||
|
||||
# @!attribute exposed_to_template
|
||||
# @!scope class
|
||||
# @api private
|
||||
# @return [Hash<Symbol, Symbol>] a list of all the methods modules this extension exposes to templates. Set these using {#expose_to_template}.
|
||||
class_attribute :exposed_to_template, instance_reader: false, instance_writer: false
|
||||
|
||||
# @!attribute ext_name
|
||||
# @!scope class
|
||||
# @return [Symbol] the name this extension is registered under. This is the symbol used to activate the extension.
|
||||
|
@ -138,6 +156,68 @@ module Middleman
|
|||
self.defined_helpers += modules
|
||||
end
|
||||
|
||||
# Takes a method within this extension and exposes it globally
|
||||
# on the main `app` instance. Used for very low-level extensions
|
||||
# which many other extensions depend upon. Such as Data and
|
||||
# File watching.
|
||||
# @example with Hash:
|
||||
# expose_to_application global_name: :local_name
|
||||
# @example with Array:
|
||||
# expose_to_application :method1, :method2
|
||||
# @param [Array<Sumbol>, Hash<Symbol, Symbol>] symbols An optional list of symbols representing instance methods to exposed.
|
||||
# @return [void]
|
||||
def expose_to_application(*symbols)
|
||||
self.exposed_to_application ||= {}
|
||||
|
||||
if symbols.first && symbols.first.is_a?(Hash)
|
||||
self.exposed_to_application.merge!(symbols.first)
|
||||
elsif symbols.is_a? Array
|
||||
symbols.each do |sym|
|
||||
self.exposed_to_application[sym] = sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Takes a method within this extension and exposes it inside the scope
|
||||
# of the config.rb sandbox.
|
||||
# @example with Hash:
|
||||
# expose_to_config global_name: :local_name
|
||||
# @example with Array:
|
||||
# expose_to_config :method1, :method2
|
||||
# @param [Array<Sumbol>, Hash<Symbol, Symbol>] symbols An optional list of symbols representing instance methods to exposed.
|
||||
# @return [void]
|
||||
def expose_to_config(*symbols)
|
||||
self.exposed_to_config ||= {}
|
||||
|
||||
if symbols.first && symbols.first.is_a?(Hash)
|
||||
self.exposed_to_config.merge!(symbols.first)
|
||||
elsif symbols.is_a? Array
|
||||
symbols.each do |sym|
|
||||
self.exposed_to_config[sym] = sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Takes a method within this extension and exposes it inside the scope
|
||||
# of the templating engine. Like `helpers`, but scoped.
|
||||
# @example with Hash:
|
||||
# expose_to_template global_name: :local_name
|
||||
# @example with Array:
|
||||
# expose_to_template :method1, :method2
|
||||
# @param [Array<Sumbol>, Hash<Symbol, Symbol>] symbols An optional list of symbols representing instance methods to exposed.
|
||||
# @return [void]
|
||||
def expose_to_template(*symbols)
|
||||
self.exposed_to_template ||= {}
|
||||
|
||||
if symbols.first && symbols.first.is_a?(Hash)
|
||||
self.exposed_to_template.merge!(symbols.first)
|
||||
elsif symbols.is_a? Array
|
||||
symbols.each do |sym|
|
||||
self.exposed_to_template[sym] = sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Reset all {Extension.after_extension_activated} callbacks.
|
||||
# @api private
|
||||
# @return [void]
|
||||
|
@ -191,6 +271,7 @@ module Middleman
|
|||
@_helpers = []
|
||||
@app = app
|
||||
|
||||
expose_methods
|
||||
setup_options(options_hash, &block)
|
||||
|
||||
# Bind app hooks to local methods
|
||||
|
@ -227,8 +308,28 @@ module Middleman
|
|||
# @param [Array<Sitemap::Resource>] resources A list of all the resources known to the sitemap.
|
||||
# @return [Array<Sitemap::Resource>] The transformed list of resources.
|
||||
|
||||
def add_exposed_to_context(context)
|
||||
(self.class.exposed_to_template || {}).each do |k, v|
|
||||
context.define_singleton_method(k, &method(v))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expose_methods
|
||||
(self.class.exposed_to_application || {}).each do |k, v|
|
||||
app.define_singleton_method(k, &method(v))
|
||||
end
|
||||
|
||||
(self.class.exposed_to_config || {}).each do |k, v|
|
||||
app.config_context.define_singleton_method(k, &method(v))
|
||||
end
|
||||
|
||||
(self.class.defined_helpers || []).each do |m|
|
||||
app.template_context_class.send(:include, m)
|
||||
end
|
||||
end
|
||||
|
||||
# @yield An optional block that can be used to customize options before the extension is activated.
|
||||
# @yieldparam Middleman::Configuration::ConfigurationManager] options Extension options
|
||||
def setup_options(options_hash)
|
||||
|
|
|
@ -68,13 +68,15 @@ module Middleman
|
|||
end
|
||||
|
||||
instances.each do |ext|
|
||||
# Forward Extension helpers to TemplateContext
|
||||
Array(ext.class.defined_helpers).each do |m|
|
||||
@app.template_context_class.send(:include, m)
|
||||
end
|
||||
|
||||
::Middleman::Extension.activated_extension(ext)
|
||||
end
|
||||
end
|
||||
|
||||
def add_exposed_to_context(context)
|
||||
@activated.each do |(_, ext)|
|
||||
ext.add_exposed_to_context(context)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,13 @@ module Middleman
|
|||
# Add haml helpers to context
|
||||
::Middleman::TemplateContext.send :include, ::Haml::Helpers
|
||||
end
|
||||
|
||||
def add_exposed_to_context(context)
|
||||
super
|
||||
|
||||
context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,12 +3,15 @@ module Middleman
|
|||
module Extensions
|
||||
# Class to handle managing ignores
|
||||
class Ignores < Extension
|
||||
# Expose `create_ignore` as `app.ignore`
|
||||
expose_to_application ignore: :create_ignore
|
||||
|
||||
# Expose `create_ignore` to config as `ignore`
|
||||
expose_to_config ignore: :create_ignore
|
||||
|
||||
def initialize(app, config={}, &block)
|
||||
super
|
||||
|
||||
@app.add_to_config_context(:ignore, &method(:create_ignore))
|
||||
@app.define_singleton_method(:ignore, &method(:create_ignore))
|
||||
|
||||
# Array of callbacks which can ass ignored
|
||||
@ignored_callbacks = Set.new
|
||||
|
||||
|
|
|
@ -7,12 +7,15 @@ module Middleman
|
|||
# Manages the list of proxy configurations and manipulates the sitemap
|
||||
# to include new resources based on those configurations
|
||||
class Proxies < Extension
|
||||
# Expose `create_proxy` as `app.proxy`
|
||||
expose_to_application proxy: :create_proxy
|
||||
|
||||
# Expose `create_proxy` to config as `proxy`
|
||||
expose_to_config proxy: :create_proxy
|
||||
|
||||
def initialize(app, config={}, &block)
|
||||
super
|
||||
|
||||
@app.add_to_config_context(:proxy, &method(:create_proxy))
|
||||
@app.define_singleton_method(:proxy, &method(:create_proxy))
|
||||
|
||||
@proxy_configs = Set.new
|
||||
@post_config = false
|
||||
end
|
||||
|
|
|
@ -7,11 +7,13 @@ module Middleman
|
|||
# Manages the list of proxy configurations and manipulates the sitemap
|
||||
# to include new resources based on those configurations
|
||||
class Redirects < Extension
|
||||
|
||||
# Expose `create_redirect` to config as `redirect`
|
||||
expose_to_config redirect: :create_redirect
|
||||
|
||||
def initialize(app, config={}, &block)
|
||||
super
|
||||
|
||||
@app.add_to_config_context(:redirect, &method(:create_redirect))
|
||||
|
||||
@redirects = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -4,13 +4,15 @@ module Middleman
|
|||
module Sitemap
|
||||
module Extensions
|
||||
class RequestEndpoints < Extension
|
||||
|
||||
# Expose `create_endpoint` to config as `endpoint`
|
||||
expose_to_config endpoint: :create_endpoint
|
||||
|
||||
# Manages the list of proxy configurations and manipulates the sitemap
|
||||
# to include new resources based on those configurations
|
||||
def initialize(app, config={}, &block)
|
||||
super
|
||||
|
||||
@app.add_to_config_context(:endpoint, &method(:create_endpoint))
|
||||
|
||||
@endpoints = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ module Middleman
|
|||
# Sandboxed class for template eval
|
||||
context = @app.template_context_class.new(@app, locals, options)
|
||||
|
||||
# TODO: Only for HAML files
|
||||
context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
|
||||
# Add extension helpers to context.
|
||||
@app.extensions.add_exposed_to_context(context)
|
||||
|
||||
content = _render_with_all_renderers(path, locs, context, opts, &block)
|
||||
|
||||
|
|
Loading…
Reference in a new issue