/
config_file.rb
172 lines (162 loc) · 5.13 KB
/
config_file.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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