Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Move config settings into a separate object #620

Merged
merged 3 commits into from

2 participants

@bhollis
Owner

Right now all config settings are essentially attr_accessors on Middleman::Application, which has too many methods already. This can cause problems when users try to declare their own instance variables or locals (using page or just in helpers/config.rb). For example, just the other day I saw somebody's middleman project break because they set @source from a page block and it overwrote the location of Middleman's source folder causing things to blow up.

It'd be much nicer if configs were stored on a separate object just to keep them contained. We could also do neat things like have a "config view" that shows all the settings you've chosen (and what their defaults are).

@tdreyno
Owner

Great idea, thankfull we've already got the set abstraction.

bhollis added some commits
@bhollis bhollis Move configuration into a separate object, that can be reused for ext…
…ension configuration and makes settings, their defaults, and descriptions inspectable.
781fa1c
@bhollis bhollis Switch over to new config methods a50ca56
@bhollis
Owner

OK, that was harder than I thought it would be, especially to preserve backwards-compatibility.

Features of the new system:

  • Separate object, so no ivar pollution in the main class
  • Still accessible through methods on the main class via method_missing as a backwards-compat thing.
  • ConfigurationManager can be reused to do configs for things like blog.
  • Each config knows its default, a user-friendly description, and whether it's been set.
  • Writing out config[:whatever] instead of relying on auto-methods makes it way easier to understand what's coming from config.
  • I'll be able to inspect the collection of configs for a meta page.

I'm not 100% sure how I'll poke into extension options for the config meta page, but this gets me a lot of stuff.

@tdreyno
Owner

Excellent. I've been building #460 in anticipation of this.

@tdreyno
Owner

That is, the new extension class is instantiated and doesn't use global config.

@bhollis
Owner

Nice! My thought is that the new extension class can use its own private ConfigurationManager instance per extension and expose it through some property so we can walk through all the extensions and show how they're configured (and what settings are available).

@tdreyno
Owner

The code readability is greatly improved by this.

Here's a question... should we be using IndifferentAccess for this? I hate the level of complexity it adds to basic objects, but I hate answering bug requests where people's code uses config.js_compressor vs config["js_compressor"] vs config[:js_compressor].

@tdreyno
Owner

Or maybe only enable indifferent access once we get into a plugin, so we keep our code consistent.

@tdreyno
Owner

Merging this, so I can use it in my Rack stuff without having to worry about a horrible future merge.

@tdreyno tdreyno merged commit af81b58 into middleman:master

1 check passed

Details default The Travis build passed
@tdreyno
Owner

Derp, I didn't even dig into the code. You're already handling all the method_missing crap for "indifferent"

@bhollis
Owner

I really don't like IndifferentAccess - in this case, you get methods or symbols, and if you put something else in it tells you you're wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 14, 2012
  1. @bhollis

    Move configuration into a separate object, that can be reused for ext…

    bhollis authored
    …ension configuration and makes settings, their defaults, and descriptions inspectable.
  2. @bhollis
  3. @bhollis
This page is out of date. Refresh to see the latest.
Showing with 374 additions and 186 deletions.
  1. +35 −78 middleman-core/lib/middleman-core/application.rb
  2. +2 −2 middleman-core/lib/middleman-core/cli/build.rb
  3. +231 −0 middleman-core/lib/middleman-core/configuration.rb
  4. +5 −5 middleman-core/lib/middleman-core/core_extensions/data.rb
  5. +3 −9 middleman-core/lib/middleman-core/core_extensions/extensions.rb
  6. +7 −7 middleman-core/lib/middleman-core/core_extensions/external_helpers.rb
  7. +1 −1  middleman-core/lib/middleman-core/core_extensions/file_watcher.rb
  8. +1 −1  middleman-core/lib/middleman-core/core_extensions/front_matter.rb
  9. +2 −2 middleman-core/lib/middleman-core/core_extensions/rendering.rb
  10. +5 −5 middleman-core/lib/middleman-core/core_extensions/routing.rb
  11. +6 −2 middleman-core/lib/middleman-core/core_extensions/ruby_encoding.rb
  12. +5 −1 middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb
  13. +1 −1  middleman-core/lib/middleman-core/preview_server.rb
  14. +5 −5 middleman-core/lib/middleman-core/renderers/erb.rb
  15. +3 −3 middleman-core/lib/middleman-core/renderers/less.rb
  16. +9 −9 middleman-core/lib/middleman-core/renderers/markdown.rb
  17. +5 −5 middleman-core/lib/middleman-core/renderers/sass.rb
  18. +3 −3 middleman-core/lib/middleman-core/sitemap.rb
  19. +2 −2 middleman-core/lib/middleman-core/sitemap/extensions/on_disk.rb
  20. +3 −3 middleman-core/lib/middleman-core/sitemap/store.rb
  21. +3 −0  middleman-core/lib/middleman-core/step_definitions/builder_steps.rb
  22. +2 −1  middleman-core/lib/middleman-core/step_definitions/server_steps.rb
  23. +0 −6 middleman-core/lib/middleman-core/templates/extension/lib/lib.rb
  24. +1 −1  middleman-more/lib/middleman-more/core_extensions/assets.rb
  25. +19 −19 middleman-more/lib/middleman-more/core_extensions/compass.rb
  26. +4 −4 middleman-more/lib/middleman-more/core_extensions/default_helpers.rb
  27. +2 −2 middleman-more/lib/middleman-more/core_extensions/i18n.rb
  28. +6 −6 middleman-more/lib/middleman-more/extensions/asset_host.rb
  29. +2 −2 middleman-more/lib/middleman-more/extensions/minify_css.rb
  30. +1 −1  middleman-more/lib/middleman-more/extensions/minify_javascript.rb
View
113 middleman-core/lib/middleman-core/application.rb
@@ -12,10 +12,14 @@
require "middleman-core/sitemap"
require "middleman-core/core_extensions"
+require "middleman-core/configuration"
# Core Middleman Class
module Middleman
class Application
+ # Global configuration
+ include Configuration::Global
+
# Uses callbacks
include Hooks
@@ -25,115 +29,75 @@ class Application
# Ready (all loading and parsing of extensions complete) hook
define_hook :ready
- class << self
-
- # Mix-in helper methods. Accepts either a list of Modules
- # and/or a block to be evaluated
- # @return [void]
- def helpers(*extensions, &block)
- class_eval(&block) if block_given?
- include(*extensions) if extensions.any?
- end
-
- # Access class-wide defaults
- #
- # @private
- # @return [Hash] Hash of default values
- def defaults
- @defaults ||= {}
- end
-
- # Set class-wide defaults
- #
- # @param [Symbol] key Unique key name
- # @param value Default value
- # @return [void]
- def set(key, value=nil, &block)
- @defaults ||= {}
- @defaults[key] = value
-
- @inst.set(key, value, &block) if @inst
- end
- end
-
- delegate :helpers, :to => :"self.class"
-
- # Set attributes (global variables)
- #
- # @param [Symbol] key Name of the attribue
- # @param value Attribute value
+ # Mix-in helper methods. Accepts either a list of Modules
+ # and/or a block to be evaluated
# @return [void]
- def set(key, value=nil, &block)
- setter = "#{key}=".to_sym
- self.class.send(:attr_accessor, key) if !respond_to?(setter)
- value = block if block_given?
- send(setter, value)
+ def self.helpers(*extensions, &block)
+ class_eval(&block) if block_given?
+ include(*extensions) if extensions.any?
end
+ delegate :helpers, :to => :"self.class"
# Root project directory (overwritten in middleman build/server)
# @return [String]
- set :root, ENV["MM_ROOT"] || Dir.pwd
+ def self.root
+ ENV["MM_ROOT"] || Dir.pwd
+ end
+ delegate :root, :to => :"self.class"
# Pathname-addressed root
- def root_path
- @_root_path ||= Pathname.new(root)
+ def self.root_path
+ Pathname(root)
end
+ delegate :root_path, :to => :"self.class"
# Name of the source directory
# @return [String]
- set :source, "source"
+ config.define_setting :source, "source", 'Name of the source directory'
# Middleman environment. Defaults to :development, set to :build by the build process
# @return [String]
- set :environment, (ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :development
+ config.define_setting :environment, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :development), 'Middleman environment. Defaults to :development, set to :build by the build process'
# Which file should be used for directory indexes
# @return [String]
- set :index_file, "index.html"
+ config.define_setting :index_file, "index.html", 'Which file should be used for directory indexes'
# Whether to strip the index file name off links to directory indexes
# @return [Boolean]
- set :strip_index_file, true
+ 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]
- set :trailing_slash, true
+ config.define_setting :trailing_slash, true, 'Whether to include a trailing slash when stripping the index file'
# Location of javascripts within source.
# @return [String]
- set :js_dir, "javascripts"
+ config.define_setting :js_dir, "javascripts", 'Location of javascripts within source'
# Location of stylesheets within source. Used by Compass.
# @return [String]
- set :css_dir, "stylesheets"
+ config.define_setting :css_dir, "stylesheets", 'Location of stylesheets within source'
# Location of images within source. Used by HTML helpers and Compass.
# @return [String]
- set :images_dir, "images"
+ config.define_setting :images_dir, "images", 'Location of images within source'
# Location of fonts within source. Used by Compass.
# @return [String]
- set :fonts_dir, "fonts"
+ config.define_setting :fonts_dir, "fonts", 'Location of fonts within source'
# Where to build output files
# @return [String]
- set :build_dir, "build"
+ config.define_setting :build_dir, "build", 'Where to build output files'
# Default prefix for building paths. Used by HTML helpers and Compass.
# @return [String]
- set :http_prefix, "/"
-
- # Default string encoding for templates and output.
- # @return [String]
- set :encoding, "utf-8"
-
- # Whether to catch and display exceptions
- # @return [Boolean]
- set :show_exceptions, true
+ config.define_setting :http_prefix, "/", 'Default prefix for building paths'
# Default layout name
# @return [String, Symbold]
- set :layout, :_auto_layout
+ config.define_setting :layout, :_auto_layout, 'Default layout name'
# Activate custom features and extensions
include Middleman::CoreExtensions::Extensions
@@ -178,12 +142,12 @@ def initialize(&block)
cache.clear
# Setup the default values from calls to set before initialization
- self.class.superclass.defaults.each { |k,v| set(k,v) }
+ self.class.superclass.config.to_h.each { |k,v| self.class.config.define_setting(k,v) }
# Evaluate a passed block if given
instance_exec(&block) if block_given?
- set :source, ENV["MM_SOURCE"] if ENV["MM_SOURCE"]
+ config[:source] = ENV["MM_SOURCE"] if ENV["MM_SOURCE"]
super
end
@@ -199,24 +163,17 @@ def self.cache
# Whether we're in development mode
# @return [Boolean] If we're in dev mode
- def development?; environment == :development; end
+ def development?; config[:environment] == :development; end
# Whether we're in build mode
# @return [Boolean] If we're in build mode
- def build?; environment == :build; end
-
- # Backwards compatibilty with old Sinatra template interface
- #
- # @return [Middleman::Application]
- def settings
- self
- end
+ def build?; config[:environment] == :build; end
# The full path to the source directory
#
# @return [String]
def source_dir
- File.join(root, source)
+ File.join(root, config[:source])
end
delegate :logger, :instrument, :to => ::Middleman::Util
@@ -239,7 +196,7 @@ def full_path(path)
if !resource
# Try it with /index.html at the end
- indexed_path = File.join(path.sub(%r{/$}, ''), index_file)
+ indexed_path = File.join(path.sub(%r{/$}, ''), config[:index_file])
resource = sitemap.find_resource_by_destination_path(indexed_path)
end
View
4 middleman-core/lib/middleman-core/cli/build.rb
@@ -83,7 +83,7 @@ def exit_on_failure?
# @return [Middleman::Application]
def shared_instance(verbose=false, instrument=false)
@_shared_instance ||= ::Middleman::Application.server.inst do
- set :environment, :build
+ config[:environment] = :build
logger(verbose ? 0 : 1, instrument)
end
end
@@ -114,7 +114,7 @@ def source_root
# @param [Middleman::Sitemap::Resource] resource
# @return [String] The full path of the file that was written
def render_to_file(resource)
- build_dir = self.class.shared_instance.build_dir
+ build_dir = self.class.shared_instance.config[:build_dir]
output_file = File.join(build_dir, resource.destination_path)
begin
View
231 middleman-core/lib/middleman-core/configuration.rb
@@ -0,0 +1,231 @@
+module Middleman
+ module Configuration
+ # Access to a global configuration manager for the whole Middleman project,
+ # plus backwards compatibility mechanisms for older Middleman projects.
+ module Global
+ def self.included(app)
+ app.send :extend, ClassMethods
+ end
+
+ module ClassMethods
+ # Global configuration for the whole Middleman project.
+ # @return [ConfigurationManager]
+ def config
+ @_config ||= ConfigurationManager.new
+ end
+
+ # Set attributes (global variables)
+ #
+ # @deprecated Prefer accessing settings through "config".
+ #
+ # @param [Symbol] key Name of the attribue
+ # @param value Attribute value
+ # @return [void]
+ def set(key, default=nil, &block)
+ config.define_setting(key, default)
+ @inst.set(key, default, &block) if @inst
+ end
+
+ # Access global settings as methods, to preserve compatibility with
+ # old Middleman.
+ #
+ # @deprecated Prefer accessing settings through "config".
+ def method_missing(method, *args)
+ if config.defines_setting? method
+ config[method]
+ else
+ super
+ end
+ end
+
+ # Needed so that method_missing makes sense
+ def respond_to?(method, include_private = false)
+ super || config.defines_setting?(method)
+ end
+ end
+
+ def config
+ self.class.config
+ end
+
+ # Backwards compatibilty with old Sinatra template interface
+ #
+ # @deprecated Prefer accessing settings through "config".
+ #
+ # @return [ConfigurationManager]
+ alias :settings :config
+
+ # Set attributes (global variables)
+ #
+ # @deprecated Prefer accessing settings through "config".
+ #
+ # @param [Symbol] key Name of the attribue
+ # @param value Attribute value
+ # @return [void]
+ def set(key, value=nil, &block)
+ value = block if block_given?
+ config[key] = value
+ end
+
+ # Access global settings as methods, to preserve compatibility with
+ # old Middleman.
+ #
+ # @deprecated Prefer accessing settings through "config".
+ def method_missing(method, *args)
+ if config.defines_setting? method
+ config[method]
+ else
+ super
+ end
+ end
+
+ # Needed so that method_missing makes sense
+ def respond_to?(method, include_private = false)
+ super || config.defines_setting?(method)
+ end
+ end
+
+ # A class that manages a collection of documented settings.
+ # Can be used by extensions as well as the main Middleman
+ # application. Extensions should probably finalize their instance
+ # after defining all the settings they want to expose.
+ class ConfigurationManager
+ def initialize
+ # A hash from setting key to ConfigSetting instance.
+ @settings = {}
+ @finalized = false
+ end
+
+ # Get all settings, sorted by key, as ConfigSetting objects.
+ # @return [Array<ConfigSetting>]
+ def all_settings
+ @settings.values.sort_by(&:key)
+ end
+
+ # Get a full ConfigSetting object for the setting with the give key.
+ # @return [ConfigSetting]
+ def setting(key)
+ @settings[key]
+ end
+
+ # Get the value of a setting by key. Returns nil if there is no such setting.
+ # @return [Object]
+ def [](key)
+ setting = @settings[key]
+ setting ? setting.value : nil
+ end
+
+ # Set the value of a setting by key. Creates the setting if it doesn't exist.
+ # @param [Symbol] key
+ # @param [Object] val
+ def []=(key, val)
+ setting = @settings[key] || define_setting(key)
+ setting.value = val
+ end
+
+ # Allow configuration settings to be read and written via methods
+ def method_missing(method, *args)
+ if defines_setting?(method) && args.size == 0
+ self[method]
+ elsif method =~ /^(\w+)=$/ && args.size == 1
+ self[$1.to_sym] = args[0]
+ else
+ super
+ end
+ end
+
+ # Needed so that method_missing makes sense
+ def respond_to?(method, include_private = false)
+ super || defines_setting?(method) || (method =~ /^(\w+)=$/ && defines_setting?($1))
+ end
+
+ # Does this configuration manager know about the setting identified by key?
+ # @param [Symbol] key
+ # @return [Boolean]
+ def defines_setting?(key)
+ @settings.has_key?(key)
+ end
+
+ # Define a new setting, with optional default and user-friendly description.
+ # Once the configuration manager is finalized, no new settings may be defined.
+ #
+ # @param [Symbol] key
+ # @param [Object] default
+ # @param [String] description
+ # @return [ConfigSetting]
+ def define_setting(key, default=nil, description=nil)
+ raise "Setting #{key} doesn't exist" if @finalized
+ raise "Setting #{key} already defined" if @settings.has_key?(key)
+ raise "Setting key must be a Symbol" unless key.is_a? Symbol
+
+ @settings[key] = ConfigSetting.new(key, default, description)
+ end
+
+ # Switch the configuration manager is finalized, it switches to read-only
+ # mode and no new settings may be defined.
+ def finalize!
+ @finalized = true
+ end
+
+ # Deep duplicate of the configuration manager
+ def dup
+ copy = ConfigurationManager.new
+ @settings.each do |key, setting|
+ copy_setting = copy.define_setting setting.key, setting.default, setting.description
+ copy_setting.value = setting.value if setting.value_set?
+ end
+ copy
+ end
+
+ def to_h
+ hash = {}
+ @settings.each do |key, setting|
+ hash[key] = setting.value
+ end
+ hash
+ end
+
+ def to_s
+ to_h.inspect
+ end
+ end
+
+ # An individual configuration setting, with an optional default and description.
+ # Also models whether or not a value has been set.
+ class ConfigSetting
+ # The name of this setting
+ attr_accessor :key
+
+ # The default value for this setting
+ attr_accessor :default
+
+ # A human-friendly description of the setting
+ attr_accessor :description
+
+ def initialize(key, default, description)
+ @value_set = false
+ self.key = key
+ self.default = default
+ self.description = description
+ end
+
+ # The user-supplied value for this setting, overriding the default
+ def value=(value)
+ @value = value
+ @value_set = true
+ end
+
+ # The effective value of the setting, which may be the default
+ # if the user has not set a value themselves. Note that even if the
+ # user sets the value to nil it will override the default.
+ def value
+ value_set? ? @value : default
+ end
+
+ # Whether or not there has been a value set beyond the default
+ def value_set?
+ @value_set
+ end
+ end
+ end
+end
View
10 middleman-core/lib/middleman-core/core_extensions/data.rb
@@ -13,7 +13,7 @@ def registered(app)
require "yaml"
require "active_support/json"
- app.set :data_dir, "data"
+ app.config.define_setting :data_dir, "data", "The directory data files are stored in"
app.send :include, InstanceMethods
end
alias :included :registered
@@ -24,12 +24,12 @@ module InstanceMethods
# Setup data files before anything else so they are available when
# parsing config.rb
def initialize
- self.files.changed DataStore.matcher do |file|
- self.data.touch_file(file) if file.match(%r{^#{self.data_dir}\/})
+ files.changed DataStore.matcher do |file|
+ data.touch_file(file) if file.match(%r{^#{config[:data_dir]}\/})
end
- self.files.deleted DataStore.matcher do |file|
- self.data.remove_file(file) if file.match(%r{^#{self.data_dir}\/})
+ files.deleted DataStore.matcher do |file|
+ data.remove_file(file) if file.match(%r{^#{config[data_dir]}\/})
end
super
View
12 middleman-core/lib/middleman-core/core_extensions/extensions.rb
@@ -37,19 +37,13 @@ module Extensions
class << self
# @private
def registered(app)
- # Using for version parsing
- require "rubygems"
-
app.define_hook :after_configuration
app.define_hook :before_configuration
app.define_hook :build_config
app.define_hook :development_config
- if ENV["AUTOLOAD_SPROCKETS"]
- app.set :autoload_sprockets, (ENV["AUTOLOAD_SPROCKETS"] == "true")
- else
- app.set :autoload_sprockets, true
- end
+ app.config.define_setting :autoload_sprockets, true, 'Automatically load sprockets at startup?'
+ app.config[:autoload_sprockets] = (ENV["AUTOLOAD_SPROCKETS"] == "true") if ENV["AUTOLOAD_SPROCKETS"]
app.extend ClassMethods
app.send :include, InstanceMethods
@@ -137,7 +131,7 @@ def initialize
instance_eval File.read(local_config), local_config, 1
end
- if autoload_sprockets
+ if config[:autoload_sprockets]
begin
require "middleman-sprockets"
activate(:sprockets)
View
14 middleman-core/lib/middleman-core/core_extensions/external_helpers.rb
@@ -9,20 +9,20 @@ class << self
# once registered
def registered(app)
# Setup a default helpers paths
- app.set :helpers_dir, "helpers"
- app.set :helpers_filename_glob, "**{,/*/**}/*.rb"
- app.set :helpers_filename_to_module_name_proc, Proc.new { |filename|
+ app.config.define_setting :helpers_dir, "helpers", 'Directory to autoload helper modules from'
+ app.config.define_setting :helpers_filename_glob, "**.rb", 'Glob pattern for matching helper ruby files'
+ app.config.define_setting :helpers_filename_to_module_name_proc, Proc.new { |filename|
basename = File.basename(filename, File.extname(filename))
basename.camelcase
- }
+ }, 'Proc implementing the conversion from helper filename to module name'
# After config
app.after_configuration do
- helpers_path = File.expand_path(helpers_dir, root)
+ helpers_path = File.join(root, config[:helpers_dir])
next unless File.exists?(helpers_path)
- Dir[File.join(helpers_path, helpers_filename_glob)].each do |filename|
- module_name = helpers_filename_to_module_name_proc.call(filename)
+ Dir[File.join(helpers_path, config[:helpers_filename_glob])].each do |filename|
+ module_name = config[:helpers_filename_to_module_name_proc].call(filename)
next unless module_name
require filename
View
2  middleman-core/lib/middleman-core/core_extensions/file_watcher.rb
@@ -29,7 +29,7 @@ def registered(app)
# Before parsing config, load the data/ directory
app.before_configuration do
- files.reload_path(data_dir)
+ files.reload_path(config[:data_dir])
end
# After config, load everything else
View
2  middleman-core/lib/middleman-core/core_extensions/front_matter.rb
@@ -62,7 +62,7 @@ def data(path)
def clear_data(file)
# Copied from Sitemap::Store#file_to_path, but without
# removing the file extension
- file = File.expand_path(file, @app.root)
+ file = File.join(@app.root, file)
prefix = @app.source_dir.sub(/\/$/, "") + "/"
return unless file.include?(prefix)
path = file.sub(prefix, "")
View
4 middleman-core/lib/middleman-core/core_extensions/rendering.rb
@@ -257,7 +257,7 @@ def options_for_ext(ext)
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) : {}
+ engine_options = config[ext.to_sym] || {}
options.merge!(engine_options)
end
@@ -272,7 +272,7 @@ def options_for_ext(ext)
# @return [String]
def fetch_layout(engine, opts)
# The layout name comes from either the system default or the options
- local_layout = opts.has_key?(:layout) ? opts[:layout] : layout
+ local_layout = opts.has_key?(:layout) ? opts[:layout] : config[:layout]
return false unless local_layout
# Look for engine-specific options
View
10 middleman-core/lib/middleman-core/core_extensions/routing.rb
@@ -28,12 +28,12 @@ module InstanceMethods
# @param [String, Symbol] layout_name
# @return [void]
def with_layout(layout_name, &block)
- old_layout = layout
+ old_layout = config[:layout]
- set :layout, layout_name
+ config[:layout] = layout_name
instance_exec(&block) if block_given?
ensure
- set :layout, old_layout
+ config[:layout] = old_layout
end
# The page method allows the layout to be set on a specific path
@@ -50,7 +50,7 @@ def page(url, opts={}, &block)
blocks << block if block_given?
# Default layout
- opts[:layout] = layout if opts[:layout].nil?
+ opts[:layout] = config[:layout] if opts[:layout].nil?
# If the url is a regexp
if url.is_a?(Regexp) || url.include?("*")
@@ -66,7 +66,7 @@ def page(url, opts={}, &block)
# Normalized path
url = '/' + Middleman::Util.normalize_path(url)
if url.end_with?('/') || File.directory?(File.join(source_dir, url))
- url = File.join(url, index_file)
+ url = File.join(url, config[:index_file])
end
# Setup proxy
View
8 middleman-core/lib/middleman-core/core_extensions/ruby_encoding.rb
@@ -6,6 +6,10 @@ class << self
# Once registerd
def registered(app)
+ # Default string encoding for templates and output.
+ # @return [String]
+ app.config.define_setting :encoding, "utf-8", 'Default string encoding for templates and output'
+
app.send :include, InstanceMethods
end
@@ -15,8 +19,8 @@ def registered(app)
module InstanceMethods
def initialize
if Object.const_defined?(:Encoding)
- Encoding.default_internal = encoding
- Encoding.default_external = encoding
+ Encoding.default_internal = config[:encoding]
+ Encoding.default_external = config[:encoding]
end
super
View
6 middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb
@@ -11,10 +11,14 @@ class << self
# Once registered
def registered(app)
+ # Whether to catch and display exceptions
+ # @return [Boolean]
+ app.config.define_setting :show_exceptions, true, 'Whether to catch and display exceptions'
+
# When in dev
app.configure :development do
# Include middlemare
- if show_exceptions
+ if config[:show_exceptions]
use ::Middleman::CoreExtensions::ShowExceptions::Middleware
end
end
View
2  middleman-core/lib/middleman-core/preview_server.rb
@@ -71,7 +71,7 @@ def new_app
opts = @options
@app =::Middleman::Application.server.inst do
if opts[:environment]
- set :environment, opts[:environment].to_sym
+ config[:environment] = opts[:environment].to_sym
end
logger(opts[:debug] ? 0 : 1, opts[:instrumenting] || false)
View
10 middleman-core/lib/middleman-core/renderers/erb.rb
@@ -8,8 +8,8 @@ class << self
# once registered
def registered(app)
# Setup a default ERb engine
- app.set :erb_engine, :erb
- app.set :erb_engine_prefix, ::Tilt
+ app.config.define_setting :erb_engine, :erb, 'The engine to use for rendering ERb templates'
+ app.config.define_setting :erb_engine_prefix, ::Tilt, 'The parent module for ERb template engines'
app.before_configuration do
template_extensions :erb => :html
@@ -19,14 +19,14 @@ def registered(app)
app.after_configuration do
# Find the user's prefered engine
# Convert symbols to classes
- if erb_engine.is_a? Symbol
+ if config[:erb_engine].is_a? Symbol
engine = engine.to_s
engine = engine == "erb" ? "ERB" : engine.camelize
- erb_engine = erb_engine_prefix.const_get("#{engine}Template")
+ config[:erb_engine] = config[:erb_engine_prefix].const_get("#{engine}Template")
end
# Tell Tilt to use the preferred engine
- ::Tilt.prefer(erb_engine)
+ ::Tilt.prefer(config[:erb_engine])
end
end
alias :included :registered
View
6 middleman-core/lib/middleman-core/renderers/less.rb
@@ -11,15 +11,15 @@ class << self
# Once registered
def registered(app)
- # Default sass options
- app.set :less, {}
+ # Default less options
+ app.config.define_setting :less, {}, 'LESS compiler options'
app.before_configuration do
template_extensions :less => :css
end
app.after_configuration do
- ::Less.paths << File.expand_path(css_dir, source_dir)
+ ::Less.paths << File.join(source_dir, config[:css_dir])
end
# Tell Tilt to use it as well (for inline sass blocks)
View
18 middleman-core/lib/middleman-core/renderers/markdown.rb
@@ -10,8 +10,8 @@ class << self
# Once registered
def registered(app)
# Set our preference for a markdown engine
- app.set :markdown_engine, :maruku
- app.set :markdown_engine_prefix, ::Tilt
+ app.config.define_setting :markdown_engine, :maruku, 'Preferred markdown engine'
+ app.config.define_setting :markdown_engine_prefix, ::Tilt, 'The parent module for markdown template engines'
app.before_configuration do
template_extensions :markdown => :html,
@@ -26,24 +26,24 @@ def registered(app)
begin
# Look for the user's preferred engine
- if markdown_engine == :redcarpet
+ if config[:markdown_engine] == :redcarpet
require "middleman-core/renderers/redcarpet"
::Tilt.prefer(::Middleman::Renderers::RedcarpetTemplate)
- elsif !markdown_engine.nil?
+ elsif !config[:markdown_engine].nil?
# Map symbols to classes
- markdown_engine_klass = if markdown_engine.is_a? Symbol
- engine = markdown_engine.to_s
+ markdown_engine_klass = if config[:markdown_engine].is_a? Symbol
+ engine = config[:markdown_engine].to_s
engine = engine == "rdiscount" ? "RDiscount" : engine.camelize
- markdown_engine_prefix.const_get("#{engine}Template")
+ config[:markdown_engine_prefix].const_get("#{engine}Template")
else
- markdown_engine_prefix
+ config[:markdown_engine_prefix]
end
# Tell tilt to use that engine
::Tilt.prefer(markdown_engine_klass)
end
rescue LoadError
- logger.warn "Requested Markdown engine (#{markdown_engine}) not found. Maybe the gem needs to be installed and required?"
+ logger.warn "Requested Markdown engine (#{config[:markdown_engine]}) not found. Maybe the gem needs to be installed and required?"
end
end
end
View
10 middleman-core/lib/middleman-core/renderers/sass.rb
@@ -12,16 +12,16 @@ class << self
# Once registered
def registered(app)
# Default sass options
- app.set :sass, {}
+ app.config.define_setting :sass, {}, 'Sass engine options'
# Location of SASS .sass_cache directory.
# @return [String]
- # set :sass_cache_path, "/tmp/middleman-app-name/sass_cache"
- app.set(:sass_cache_path) { File.join(app.root_path, '.sass_cache') } # runtime compile of path
+ app.config.define_setting :sass_cache_path, nil, 'Location of sass cache' # runtime compile of path
app.before_configuration do
template_extensions :scss => :css,
:sass => :css
+ config[:sass_cache_path] = File.join(app.root_path, '.sass_cache')
end
# Tell Tilt to use it as well (for inline sass blocks)
@@ -76,11 +76,11 @@ def sass_options
more_opts = { :filename => eval_file, :line => line, :syntax => syntax }
if @context.is_a?(::Middleman::Application) && file
- location_of_sass_file = File.expand_path(@context.source, @context.root)
+ location_of_sass_file = @context.source_dir
parts = basename.split('.')
parts.pop
- more_opts[:css_filename] = File.join(location_of_sass_file, @context.css_dir, parts.join("."))
+ more_opts[:css_filename] = File.join(location_of_sass_file, @context.config[:css_dir], parts.join("."))
end
options.merge(more_opts)
View
6 middleman-core/lib/middleman-core/sitemap.rb
@@ -20,10 +20,10 @@ def registered(app)
app.register Middleman::Sitemap::Extensions::Ignores
# Set to automatically convert some characters into a directory
- app.set :automatic_directory_matcher, nil
+ app.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
- app.set :ignored_sitemap_matchers, {
+ app.config.define_setting :ignored_sitemap_matchers, {
# dotfiles and folders in the root
:root_dotfiles => proc { |file| file.match(%r{^\.}) },
@@ -38,7 +38,7 @@ def registered(app)
:layout => proc { |file|
file.match(%r{^source/layout\.}) || file.match(%r{^source/layouts/})
}
- }
+ }, 'Callbacks that can exclude paths from the sitemap'
# Include instance methods
app.send :include, InstanceMethods
View
4 middleman-core/lib/middleman-core/sitemap/extensions/on_disk.rb
@@ -45,7 +45,7 @@ def touch_file(file, rebuild=true)
path = @sitemap.file_to_path(file)
return false unless path
- ignored = @app.ignored_sitemap_matchers.any? do |name, callback|
+ ignored = @app.config[:ignored_sitemap_matchers].any? do |name, callback|
callback.call(file)
end
@@ -85,7 +85,7 @@ def manipulate_resource_list(resources)
::Middleman::Sitemap::Resource.new(
@sitemap,
@sitemap.file_to_path(file),
- File.expand_path(file, @app.root)
+ File.join(@app.root, file)
)
end
end
View
6 middleman-core/lib/middleman-core/sitemap/store.rb
@@ -164,7 +164,7 @@ def metadata_for_path(request_path)
# @param [String] file
# @return [String]
def file_to_path(file)
- file = File.expand_path(file, @app.root)
+ file = File.join(@app.root, file)
prefix = @app.source_dir.sub(/\/$/, "") + "/"
return false unless file.start_with?(prefix)
@@ -172,8 +172,8 @@ def file_to_path(file)
path = file.sub(prefix, "")
# Replace a file name containing automatic_directory_matcher with a folder
- unless @app.automatic_directory_matcher.nil?
- path = path.gsub(@app.automatic_directory_matcher, "/")
+ unless @app.config[:automatic_directory_matcher].nil?
+ path = path.gsub(@app.config[:automatic_directory_matcher], "/")
end
extensionless_path(path)
View
3  middleman-core/lib/middleman-core/step_definitions/builder_steps.rb
@@ -10,9 +10,12 @@
Given /^an empty app$/ do
step %Q{a directory named "empty_app"}
step %Q{I cd to "empty_app"}
+ ENV["MM_ROOT"] = nil
end
Given /^a fixture app "([^\"]*)"$/ do |path|
+ ENV["MM_ROOT"] = nil
+
# This step can be reentered from several places but we don't want
# to keep re-copying and re-cd-ing into ever-deeper directories
next if File.basename(current_dir) == path
View
3  middleman-core/lib/middleman-core/step_definitions/server_steps.rb
@@ -40,9 +40,10 @@
ENV["MM_SOURCE"] = ""
end
+ ENV["MM_ROOT"] = root_dir
+
initialize_commands = @initialize_commands || []
initialize_commands.unshift lambda {
- set :root, root_dir
set :environment, @current_env || :development
set :show_exceptions, false
}
View
6 middleman-core/lib/middleman-core/templates/extension/lib/lib.rb
@@ -7,9 +7,6 @@ class << self
# Called when user `activate`s your extension
def registered(app, options={})
- # Setup extension-specific config
- app.set :config_variable, false
-
# Include class methods
# app.extend ClassMethods
@@ -18,9 +15,6 @@ def registered(app, options={})
app.after_configuration do
# Do something
-
- # config_variable is now either the default or the user's
- # setting from config.rb
end
end
alias :included :registered
View
2  middleman-more/lib/middleman-more/core_extensions/assets.rb
@@ -33,7 +33,7 @@ def asset_url(path, prefix="")
if resource = sitemap.find_resource_by_path(path)
resource.url
else
- File.join(http_prefix, path)
+ File.join(config[:http_prefix], path)
end
end
end
View
38 middleman-more/lib/middleman-more/core_extensions/compass.rb
@@ -19,38 +19,38 @@ def registered(app)
# Location of SASS/SCSS files external to source directory.
# @return [Array]
- # set :sass_assets_paths, ["#{root}/assets/sass/", "/path/2/external/sass/repository/"]
- app.set :sass_assets_paths, []
+ # config[:sass_assets_paths] = ["#{root}/assets/sass/", "/path/2/external/sass/repository/"]
+ app.config.define_setting :sass_assets_paths, [], 'Paths to extra SASS/SCSS files'
app.after_configuration do
- ::Compass.configuration do |config|
- config.project_path = source_dir
- config.environment = :development
- config.cache_path = sass_cache_path
- config.sass_dir = css_dir
- config.additional_import_paths = sass_assets_paths
- config.css_dir = css_dir
- config.javascripts_dir = js_dir
- config.fonts_dir = fonts_dir
- config.images_dir = images_dir
- config.http_path = http_prefix
+ ::Compass.configuration do |compass_config|
+ compass_config.project_path = source_dir
+ compass_config.environment = :development
+ compass_config.cache_path = config[:sass_cache_path]
+ compass_config.sass_dir = config[:css_dir]
+ compass_config.additional_import_paths = config[:sass_assets_paths]
+ compass_config.css_dir = config[:css_dir]
+ compass_config.javascripts_dir = config[:js_dir]
+ compass_config.fonts_dir = config[:fonts_dir]
+ compass_config.images_dir = config[:images_dir]
+ compass_config.http_path = config[:http_prefix]
# Disable this initially, the cache_buster extension will
# re-enable it if requested.
- config.asset_cache_buster :none
+ compass_config.asset_cache_buster :none
# Disable this initially, the relative_assets extension will
# re-enable it if requested.
- config.relative_assets = false
+ compass_config.relative_assets = false
# Default output style
- config.output_style = :nested
+ compass_config.output_style = :nested
# No line-comments in test mode (changing paths mess with sha1)
- config.line_comments = false if ENV["TEST"]
+ compass_config.line_comments = false if ENV["TEST"]
- if respond_to?(:asset_host) && asset_host.is_a?(Proc)
- config.asset_host(&asset_host)
+ if config.defines_setting?(:asset_host) && config[:asset_host].is_a?(Proc)
+ compass_config.asset_host(&config[:asset_host])
end
end
View
8 middleman-more/lib/middleman-more/core_extensions/default_helpers.rb
@@ -20,7 +20,7 @@ def registered(app)
app.helpers Helpers
- app.set :relative_links, false
+ app.config.define_setting :relative_links, false, 'Whether to generate relative links instead of absolute ones'
end
alias :included :registered
end
@@ -110,7 +110,7 @@ def asset_path(kind, source)
# :relative option which, if set to true, will produce
# relative URLs instead of absolute URLs. You can also add
#
- # set :relative_links, true
+ # config[:relative_links] = true
#
# to config.rb to have all links default to relative.
def link_to(*args, &block)
@@ -136,10 +136,10 @@ def link_to(*args, &block)
resource = sitemap.find_resource_by_path(url)
- # Allow people to turn on relative paths for all links with set :relative_links, true
+ # Allow people to turn on relative paths for all links with config[:relative_links] = true
# but still override on a case by case basis with the :relative parameter.
effective_relative = relative || false
- if relative.nil? && relative_links
+ if relative.nil? && config[:relative_links]
effective_relative = true
end
View
4 middleman-more/lib/middleman-more/core_extensions/i18n.rb
@@ -9,11 +9,11 @@ class << self
# Once registerd
def registered(app, options={})
- app.set :locales_dir, "locales"
+ app.config.define_setting :locales_dir, "locales", 'The directory holding your locale configurations'
# Needed for helpers as well
app.after_configuration do
- locales_glob = File.join(locales_dir, "*.yml");
+ locales_glob = File.join(config[:locales_dir], "*.yml");
::I18n.load_path += Dir[File.join(root, locales_glob)]
::I18n.reload!
View
12 middleman-more/lib/middleman-more/extensions/asset_host.rb
@@ -11,7 +11,7 @@ class << self
# Once registered
def registered(app)
# Default to no host
- app.set :asset_host, false
+ app.config.define_setting :asset_host, false, 'The asset host to use, or false for no asset host, or a Proc to determine asset host'
# Include methods
app.send :include, InstanceMethods
@@ -30,12 +30,12 @@ module InstanceMethods
# @return [String]
def asset_url(path, prefix="")
original_output = super
- return original_output unless asset_host
+ return original_output unless config[:asset_host]
- asset_prefix = if asset_host.is_a?(Proc)
- asset_host.call(original_output)
- elsif asset_host.is_a?(String)
- asset_host
+ asset_prefix = if config[:asset_host].is_a?(Proc)
+ config[:asset_host].call(original_output)
+ elsif config[:asset_host].is_a?(String)
+ config[:asset_host]
end
File.join(asset_prefix, original_output)
View
4 middleman-more/lib/middleman-more/extensions/minify_css.rb
@@ -10,13 +10,13 @@ class << self
# Once registered
def registered(app, options={})
- app.set :css_compressor, false
+ app.config.define_setting :css_compressor, nil, 'Set the CSS compressor to use. Deprecated in favor of the :compressor option when activating :minify_css'
ignore = Array(options[:ignore]) << /\.min\./
inline = options[:inline] || false
app.after_configuration do
- chosen_compressor = css_compressor || options[:compressor] || begin
+ chosen_compressor = config[:css_compressor] || options[:compressor] || begin
require "middleman-more/extensions/minify_css/rainpress"
::Rainpress
end
View
2  middleman-more/lib/middleman-more/extensions/minify_javascript.rb
@@ -10,7 +10,7 @@ class << self
# Once registered
def registered(app, options={})
- app.set :js_compressor, false
+ app.config.define_setting :js_compressor, nil, 'Set the JS compressor to use. Deprecated in favor of the :compressor option when activating :minify_js'
ignore = Array(options[:ignore]) << /\.min\./
inline = options[:inline] || false
Something went wrong with that request. Please try again.