173 lines
5.1 KiB
Ruby
173 lines
5.1 KiB
Ruby
require 'sinatra/base'
|
|
require 'yaml'
|
|
require 'erb'
|
|
|
|
module Sinatra
|
|
# = Sinatra::ConfigFile
|
|
#
|
|
# <tt>Sinatra::ConfigFile</tt> is an extension that allows you to load the
|
|
# application's configuration from YAML files. It automatically detects if
|
|
# the files contain specific environment settings and it will use those
|
|
# corresponding to the current one.
|
|
#
|
|
# You can access those options through +settings+ within the application. If
|
|
# you try to get the value for a setting that hasn't been defined in the
|
|
# config file for the current environment, you will get whatever it was set
|
|
# to in the application.
|
|
#
|
|
# == Usage
|
|
#
|
|
# Once you have written your configurations to a YAML file you can tell the
|
|
# extension to load them. See below for more information about how these
|
|
# files are interpreted.
|
|
#
|
|
# For the examples, lets assume the following config.yml file:
|
|
#
|
|
# greeting: Welcome to my file configurable application
|
|
#
|
|
# === Classic Application
|
|
#
|
|
# require "sinatra"
|
|
# require "sinatra/config_file"
|
|
#
|
|
# config_file 'path/to/config.yml'
|
|
#
|
|
# get '/' do
|
|
# @greeting = settings.greeting
|
|
# haml :index
|
|
# end
|
|
#
|
|
# # The rest of your classic application code goes here...
|
|
#
|
|
# === Modular Application
|
|
#
|
|
# require "sinatra/base"
|
|
# require "sinatra/config_file"
|
|
#
|
|
# class MyApp < Sinatra::Base
|
|
# register Sinatra::ConfigFile
|
|
#
|
|
# config_file 'path/to/config.yml'
|
|
#
|
|
# get '/' do
|
|
# @greeting = settings.greeting
|
|
# haml :index
|
|
# end
|
|
#
|
|
# # The rest of your modular application code goes here...
|
|
# end
|
|
#
|
|
# === Config File Format
|
|
#
|
|
# In its most simple form this file is just a key-value list:
|
|
#
|
|
# foo: bar
|
|
# something: 42
|
|
# nested:
|
|
# a: 1
|
|
# b: 2
|
|
#
|
|
# But it also can provide specific environment configuration. There are two
|
|
# ways to do that: at the file level and at the settings level.
|
|
#
|
|
# At the settings level (e.g. in 'path/to/config.yml'):
|
|
#
|
|
# development:
|
|
# foo: development
|
|
# bar: bar
|
|
# test:
|
|
# foo: test
|
|
# bar: bar
|
|
# production:
|
|
# foo: production
|
|
# bar: bar
|
|
#
|
|
# Or at the file level:
|
|
#
|
|
# foo:
|
|
# development: development
|
|
# test: test
|
|
# production: production
|
|
# bar: bar
|
|
#
|
|
# In either case, <tt>settings.foo</tt> will return the environment name, and
|
|
# <tt>settings.bar</tt> will return <tt>"bar"</tt>.
|
|
#
|
|
# If you wish to provide defaults that may be shared among all the
|
|
# environments, this can be done by using a YAML alias, and then overwriting
|
|
# values in environments where appropriate:
|
|
#
|
|
# default: &common_settings
|
|
# foo: 'foo'
|
|
# bar: 'bar'
|
|
#
|
|
# production:
|
|
# <<: *common_settings
|
|
# bar: 'baz' # override the default value
|
|
#
|
|
module ConfigFile
|
|
# When the extension is registered sets the +environments+ setting to the
|
|
# traditional environments: development, test and production.
|
|
def self.registered(base)
|
|
base.set :environments, %w[test production development]
|
|
end
|
|
|
|
# Loads the configuration from the YAML files whose +paths+ are passed as
|
|
# arguments, filtering the settings for the current environment. Note that
|
|
# these +paths+ can actually be globs.
|
|
def config_file(*paths)
|
|
Dir.chdir(root || '.') do
|
|
paths.each do |pattern|
|
|
Dir.glob(pattern) do |file|
|
|
raise UnsupportedConfigType unless ['.yml', '.yaml', '.erb'].include?(File.extname(file))
|
|
|
|
logger.info "loading config file '#{file}'" if logging? && respond_to?(:logger)
|
|
document = ERB.new(File.read(file)).result
|
|
yaml = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(document) : YAML.load(document)
|
|
config = config_for_env(yaml)
|
|
config.each_pair { |key, value| set(key, value) }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class UnsupportedConfigType < StandardError
|
|
def message
|
|
'Invalid config file type, use .yml, .yaml or .erb'
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
# Given a +hash+ containing application configuration it returns
|
|
# settings applicable to the current environment. Note: It gives
|
|
# precedence to environment settings defined at the root-level.
|
|
def config_for_env(hash)
|
|
return from_environment_key(hash) if environment_keys?(hash)
|
|
|
|
hash.each_with_object(IndifferentHash[]) do |(k, v), acc|
|
|
if environment_keys?(v)
|
|
acc.merge!(k => v[environment.to_s]) if v.key?(environment.to_s)
|
|
else
|
|
acc.merge!(k => v)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Given a +hash+ returns the settings corresponding to the current
|
|
# environment.
|
|
def from_environment_key(hash)
|
|
hash[environment.to_s] || hash[environment.to_sym] || {}
|
|
end
|
|
|
|
# Returns true if supplied with a hash that has any recognized
|
|
# +environments+ in its root keys.
|
|
def environment_keys?(hash)
|
|
hash.is_a?(Hash) && hash.any? { |k, _| environments.include?(k.to_s) }
|
|
end
|
|
end
|
|
|
|
register ConfigFile
|
|
Delegator.delegate :config_file
|
|
end
|