middleman/middleman-core/lib/middleman-core/application.rb

368 lines
12 KiB
Ruby
Raw Normal View History

2013-05-19 22:23:49 +02:00
# i18n Built-in
require 'i18n'
2013-05-19 22:23:49 +02:00
# Don't fail on invalid locale, that's not what our current
# users expect.
2014-02-19 03:30:29 +01:00
::I18n.enforce_available_locales = false
# Use ActiveSupport JSON
require 'active_support/json'
require 'active_support/core_ext/integer/inflections'
# Our custom logger
require 'middleman-core/logger'
2014-07-10 21:35:47 +02:00
require 'middleman-core/contracts'
2014-01-01 03:21:30 +01:00
require 'middleman-core/sitemap/store'
require 'middleman-core/configuration'
2015-05-03 04:24:18 +02:00
require 'middleman-core/callback_manager'
require 'middleman-core/extension_manager'
require 'middleman-core/core_extensions'
2014-01-01 03:21:30 +01:00
require 'middleman-core/config_context'
require 'middleman-core/file_renderer'
require 'middleman-core/template_renderer'
2014-01-01 03:21:30 +01:00
2011-11-24 06:59:53 +01:00
# Core Middleman Class
module Middleman
2015-04-24 19:26:42 +02:00
MiddlewareDescriptor = Struct.new(:class, :options, :block)
MapDescriptor = Struct.new(:path, :block)
class Application
extend Forwardable
2014-07-10 21:35:47 +02:00
include Contracts
class << self
# Global configuration for the whole Middleman project.
# @return [ConfigurationManager]
def config
@config ||= ::Middleman::Configuration::ConfigurationManager.new
end
# Root project directory (overwritten in middleman build/server)
# @return [String]
def root
ENV['MM_ROOT'] || Dir.pwd
end
# Pathname-addressed root
def root_path
Pathname(root)
end
end
# Which host preview should start on.
# @return [Fixnum]
config.define_setting :host, '0.0.0.0', 'The preview server host'
# Which port preview should start on.
# @return [Fixnum]
config.define_setting :port, 4567, 'The preview server port'
# Name of the source directory
# @return [String]
2014-12-24 20:38:54 +01:00
config.define_setting :source, 'source', 'Name of the source directory'
2014-06-07 00:32:00 +02:00
# Middleman mode. Defaults to :server, set to :build by the build process
# @return [String]
config.define_setting :mode, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :server), 'Middleman mode. Defaults to :server'
# Middleman environment. Defaults to :development
# @return [String]
2014-06-07 00:32:00 +02:00
config.define_setting :environment, :development, 'Middleman environment. Defaults to :development'
# Which file should be used for directory indexes
# @return [String]
config.define_setting :index_file, 'index.html', 'Which file should be used for directory indexes'
2011-11-18 04:56:55 +01:00
# Whether to strip the index file name off links to directory indexes
# @return [Boolean]
2012-10-14 04:54:55 +02:00
config.define_setting :strip_index_file, true, 'Whether to strip the index file name off links to directory indexes'
# Whether to include a trailing slash when stripping the index file
# @return [Boolean]
2012-10-14 04:54:55 +02:00
config.define_setting :trailing_slash, true, 'Whether to include a trailing slash when stripping the index file'
2012-05-24 23:29:29 +02:00
# Location of javascripts within source.
# @return [String]
config.define_setting :js_dir, 'javascripts', 'Location of javascripts within source'
# Location of stylesheets within source. Used by Compass.
# @return [String]
config.define_setting :css_dir, 'stylesheets', 'Location of stylesheets within source'
# Location of images within source. Used by HTML helpers and Compass.
# @return [String]
config.define_setting :images_dir, 'images', 'Location of images within source'
2011-11-18 04:56:55 +01:00
# Location of fonts within source. Used by Compass.
# @return [String]
config.define_setting :fonts_dir, 'fonts', 'Location of fonts within source'
# Location of layouts within source. Used by renderers.
# @return [String]
config.define_setting :layouts_dir, 'layouts', 'Location of layouts within source'
# Where to build output files
# @return [String]
config.define_setting :build_dir, 'build', 'Where to build output files'
# Default prefix for building paths. Used by HTML helpers and Compass.
# @return [String]
config.define_setting :http_prefix, '/', 'Default prefix for building paths'
2011-11-24 06:59:53 +01:00
# Default layout name
# @return [String, Symbold]
2012-10-14 04:54:55 +02:00
config.define_setting :layout, :_auto_layout, 'Default layout name'
# Default string encoding for templates and output.
# @return [String]
config.define_setting :encoding, 'utf-8', 'Default string encoding for templates and output'
2013-11-20 03:10:26 +01:00
# Should Padrino include CRSF tag
# @return [Boolean]
config.define_setting :protect_from_csrf, false, 'Should Padrino include CRSF tag'
# Set to automatically convert some characters into a directory
config.define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
# Setup callbacks which can exclude paths from the sitemap
config.define_setting :ignored_sitemap_matchers, {
# Files starting with an underscore, but not a double-underscore
2014-08-18 23:53:15 +02:00
partials: proc { |file|
ignored = false
file[:relative_path].ascend do |f|
if f.basename.to_s.match %r{^_[^_]}
ignored = true
break
end
end
ignored
},
2014-07-16 03:01:45 +02:00
layout: proc { |file, _sitemap_app|
file[:relative_path].to_s.start_with?('layout.') ||
2014-11-19 18:04:56 +01:00
file[:relative_path].to_s.start_with?('layouts/')
}
}, 'Callbacks that can exclude paths from the sitemap'
2014-07-16 03:01:45 +02:00
config.define_setting :watcher_disable, false, 'If the Listen watcher should not run'
config.define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode'
config.define_setting :watcher_latency, nil, 'The Listen watcher latency'
2014-01-01 03:21:30 +01:00
attr_reader :config_context
attr_reader :sitemap
attr_reader :cache
attr_reader :template_context_class
attr_reader :config
2014-01-02 06:19:05 +01:00
attr_reader :generic_template_context
attr_reader :extensions
2014-07-16 03:01:45 +02:00
attr_reader :sources
2014-07-10 21:35:47 +02:00
2015-04-24 19:26:42 +02:00
Contract SetOf[MiddlewareDescriptor]
attr_reader :middleware
2014-07-10 21:35:47 +02:00
2015-04-24 19:26:42 +02:00
Contract SetOf[MapDescriptor]
attr_reader :mappings
# Reference to Logger singleton
def_delegator :"::Middleman::Logger", :singleton, :logger
def_delegator :"::Middleman::Util", :instrument
def_delegators :"self.class", :root, :root_path
def_delegators :@generic_template_context, :link_to, :image_tag, :asset_path
def_delegators :@extensions, :activate
# Initialize the Middleman project
def initialize(&block)
# Search the root of the project for required files
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
2015-05-03 04:24:18 +02:00
@callbacks = ::Middleman::CallbackManager.new
@callbacks.install_methods!(self, [
:initialized,
:after_configuration,
:before_configuration,
:before,
:ready,
:before_build,
:after_build,
:before_shutdown,
:before_render,
:after_render
])
2014-07-10 21:35:47 +02:00
@middleware = Set.new
@mappings = Set.new
2014-01-02 06:19:05 +01:00
@template_context_class = Class.new(Middleman::TemplateContext)
@generic_template_context = @template_context_class.new(self)
@config_context = ConfigContext.new(self, @template_context_class)
::Middleman::FileRenderer.cache.clear
::Middleman::TemplateRenderer.cache.clear
# Setup the default values from calls to set before initialization
@config = ::Middleman::Configuration::ConfigurationManager.new
@config.load_settings(self.class.config.all_settings)
2014-07-16 03:01:45 +02:00
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
@extensions = ::Middleman::ExtensionManager.new(self)
2014-07-16 03:01:45 +02:00
# Evaluate a passed block if given
config_context.instance_exec(&block) if block_given?
@extensions.auto_activate(:before_sitemap)
2014-01-01 03:21:30 +01:00
# Initialize the Sitemap
@sitemap = ::Middleman::Sitemap::Store.new(self)
if Object.const_defined?(:Encoding)
Encoding.default_internal = config[:encoding]
Encoding.default_external = config[:encoding]
end
::Middleman::Extension.clear_after_extension_callbacks
@extensions.auto_activate(:before_configuration)
2015-05-03 04:24:18 +02:00
execute_callbacks :initialized
2015-05-03 04:24:18 +02:00
execute_callbacks :before_configuration
2014-07-16 03:01:45 +02:00
evaluate_configuration
# This is for making the tests work - since the tests
# don't completely reload middleman, I18n.load_path can get
# polluted with paths from other test app directories that don't
# exist anymore.
if ENV['TEST']
::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
::I18n.reload!
end
# Clean up missing Tilt exts
Tilt.mappings.each do |key, _|
begin
Tilt[".#{key}"]
rescue LoadError, NameError
Tilt.mappings.delete(key)
end
end
2015-01-04 21:23:35 +01:00
2014-12-24 20:38:54 +01:00
@extensions.activate_all
2015-05-03 04:24:18 +02:00
execute_callbacks :after_configuration
config_context.execute_callbacks(:after_configuration)
2015-05-03 04:24:18 +02:00
execute_callbacks :ready
@config_context.execute_callbacks(:ready)
end
2014-07-16 03:01:45 +02:00
def evaluate_configuration
# Check for and evaluate local configuration in `config.rb`
2014-08-15 05:34:31 +02:00
config_rb = File.join(root, 'config.rb')
if File.exist? config_rb
logger.debug '== Reading: Local config: config.rb'
config_context.instance_eval File.read(config_rb), config_rb, 1
else
# Check for and evaluate local configuration in `middleman.rb`
middleman_rb = File.join(root, 'middleman.rb')
if File.exist? middleman_rb
logger.debug '== Reading: Local middleman: middleman.rb'
config_context.instance_eval File.read(middleman_rb), middleman_rb, 1
end
end
env_config = File.join(root, 'environments', "#{config[:environment]}.rb")
if File.exist? env_config
logger.debug "== Reading: #{config[:environment]} config"
config_context.instance_eval File.read(env_config), env_config, 1
end
2014-09-11 18:40:10 +02:00
# Run any `configure` blocks for the current environment.
config_context.execute_callbacks([:configure, config[:environment]])
2014-09-11 18:40:10 +02:00
# Run any `configure` blocks for the current mode.
config_context.execute_callbacks([:configure, config[:mode]])
end
2014-06-07 00:32:00 +02:00
# Whether we're in server mode
# @return [Boolean] If we're in dev mode
2014-06-07 00:32:00 +02:00
def server?
config[:mode] == :server
end
# Whether we're in build mode
2014-06-07 00:32:00 +02:00
# @return [Boolean] If we're in dev mode
def build?
2014-06-07 00:32:00 +02:00
config[:mode] == :build
end
# Whether we're in a specific environment
# @return [Boolean]
def environment?(key)
config[:environment] == key
end
2011-11-18 04:56:55 +01:00
2014-12-23 23:54:21 +01:00
# Backwards compatible helper. What the current environment is.
# @return [Symbol]
def environment
config[:environment]
end
# Backwards compatible helper. Whether we're in dev mode.
# @return [Boolean]
def development?
environment?(:development)
end
# Backwards compatible helper. Whether we're in production mode.
# @return [Boolean]
def production?
environment?(:production)
end
# Backwards compatible helper. The full path to the default source dir.
def source_dir
Pathname(File.join(root, config[:source]))
end
# Use Rack middleware
#
# @param [Class] middleware Middleware module
# @return [void]
2015-04-24 19:26:42 +02:00
# Contract Any, Args[Any], Maybe[Proc] => Any
def use(middleware, *args, &block)
2014-07-10 21:35:47 +02:00
@middleware << MiddlewareDescriptor.new(middleware, args, block)
end
# Add Rack App mapped to specific path
#
# @param [String] map Path to map
# @return [void]
2014-07-10 21:35:47 +02:00
Contract String, Proc => Any
def map(map, &block)
2014-07-10 21:35:47 +02:00
@mappings << MapDescriptor.new(map, block)
end
2014-07-16 03:01:45 +02:00
def shutdown!
2015-05-03 04:24:18 +02:00
execute_callbacks :before_shutdown
2014-07-16 03:01:45 +02:00
end
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
# where Ruby will call to_s/inspect while printing exception
# messages, which can take a long time (minutes at full CPU)
# if the object is huge or has cyclic references, like this.
def to_s
"#<Middleman::Application:0x#{object_id}>"
end
2014-04-29 19:50:21 +02:00
alias_method :inspect, :to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s
2011-11-18 04:56:55 +01:00
end
end