fat_config 0.4.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.envrc +1 -0
- data/.rubocop.yml +5 -8
- data/.yardopts +4 -0
- data/README.md +289 -0
- data/README.org +80 -33
- data/Rakefile +4 -0
- data/lib/fat_config/core_ext/array_ext.rb +26 -0
- data/lib/fat_config/core_ext/hash_ext.rb +15 -10
- data/lib/fat_config/errors.rb +2 -0
- data/lib/fat_config/reader.rb +2 -2
- data/lib/fat_config/style.rb +5 -4
- data/lib/fat_config/styles/ini_style.rb +13 -1
- data/lib/fat_config/styles/json_style.rb +2 -0
- data/lib/fat_config/styles/toml_style.rb +2 -0
- data/lib/fat_config/styles/yaml_style.rb +28 -9
- data/lib/fat_config/version.rb +1 -1
- data/lib/fat_config.rb +24 -7
- metadata +10 -7
- data/rubocop-global.yml +0 -180
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41cf78034335f9fd05433c7058f26fff973575eb0b6becf4f501a15027905c9c
|
|
4
|
+
data.tar.gz: 6987287fa5d625c0c97c1427add4d7777dea525100d220b8f28241720b85b340
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b55c2816b7c7402a751242af54e6e6cf54c4b67965e1b276f743c8a4ae991c6e7752c62ca5ff27a69e64eab2b2eb6bb1c8573c4ec3e3a57d5b4eae072e2813aa
|
|
7
|
+
data.tar.gz: 5d8c20611e05bd4af1745fa00dd1e83295c066fa53d40d3e955df032aa71cf144c5331298f42740d0e26b06f94e5a2a2838a875614a1b8685405d427f269023c
|
data/.envrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PATH_add .bundle/bin
|
data/.rubocop.yml
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
inherit_gem:
|
|
2
|
+
rubocop-ddoherty: 'config/default.yml'
|
|
2
3
|
|
|
3
4
|
AllCops:
|
|
4
|
-
TargetRubyVersion: 3.3
|
|
5
5
|
Include:
|
|
6
6
|
- 'lib/**/*'
|
|
7
|
-
- 'bin/**/*'
|
|
8
7
|
- 'spec/**/*'
|
|
9
|
-
# - 'features/**/*'
|
|
10
8
|
Exclude:
|
|
9
|
+
- 'test/tmp/**/*'
|
|
11
10
|
- 'spec/tmp/**/*'
|
|
12
|
-
- 'spec/.examples
|
|
13
|
-
- '
|
|
14
|
-
- '.simplecov'
|
|
15
|
-
- 'features/**/*'
|
|
11
|
+
- 'spec/.examples*'
|
|
12
|
+
- 'vendor/bundle/**/*'
|
data/.yardopts
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
- [Introduction](#org1f0d9bd)
|
|
2
|
+
- [Installation](#org3f8a5fd)
|
|
3
|
+
- [Usage:](#org5c5fe0f)
|
|
4
|
+
- [Following XDG Standards](#org7e6640a)
|
|
5
|
+
- [Following Classic UNIX Standards](#orgbc610e8)
|
|
6
|
+
- [Available Config File Styles](#orgacf5ac1)
|
|
7
|
+
- [Hash Keys](#orgf87b1a5)
|
|
8
|
+
- [Hash Values](#org451482b)
|
|
9
|
+
- [YAML](#orgef8563a)
|
|
10
|
+
- [TOML](#orgcf8804e)
|
|
11
|
+
- [JSON](#org549e838)
|
|
12
|
+
- [INI](#org12513cc)
|
|
13
|
+
- [Creating a Reader](#org7a0f2a9)
|
|
14
|
+
- [Calling the `read` method on a `Reader`](#org7e439f9)
|
|
15
|
+
- [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings)
|
|
16
|
+
- [Development](#org1fdfa48)
|
|
17
|
+
- [Contributing](#org4454a76)
|
|
18
|
+
- [License](#org8a2eaa6)
|
|
19
|
+
|
|
20
|
+
[](https://github.com/ddoherty03/fat_config/actions/workflows/main.yml)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<a id="org1f0d9bd"></a>
|
|
24
|
+
|
|
25
|
+
# Introduction
|
|
26
|
+
|
|
27
|
+
Allowing a user to configure an application to change its behavior at runtime can be seen as constructing a ruby `Hash` that merges settings from a variety of sources in a hierarchical fashion: first from system-wide file settings, merged with user-level file settings, merged with environment variable settings, merged with command-line parameters. Constructing this Hash, while needed by nearly any command-line app, can be a tedious chore, especially when there are standards, such as the XDG standards and Unix tradition, that may or may not be followed.
|
|
28
|
+
|
|
29
|
+
`FatConfig` eliminates the tedium of reading configuration files and the environment to populate a Hash of configuration settings. You need only define a `FatConfig::Reader` and call its `#read` method to look for, read, translate, and merge any config files into a single Hash that encapsulates all the files in the proper priority. It can be set to read `YAML`, `TOML`, `JSON`, or `INI` config files.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<a id="org3f8a5fd"></a>
|
|
33
|
+
|
|
34
|
+
# Installation
|
|
35
|
+
|
|
36
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
bundle add fat_config
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
gem install fat_config
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
<a id="org5c5fe0f"></a>
|
|
50
|
+
|
|
51
|
+
# Usage:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require 'fat_config'
|
|
55
|
+
|
|
56
|
+
reader = FatConfig::Reader.new('myapp')
|
|
57
|
+
config = reader.read
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `reader.read` method will parse the config files (by default assumed to be YAML files), config environment variable, and optional command-line parameters and return the composite config as a Hash.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<a id="org7e6640a"></a>
|
|
68
|
+
|
|
69
|
+
## Following XDG Standards
|
|
70
|
+
|
|
71
|
+
By default, `FatConfig::Reader#read` follows the [XDG Desktop Standards](https://specifications.freedesktop.org/basedir-spec/latest/), reading configuration settings for a hypothetical application called `myapp` from the following locations, from lowest priority to highest:
|
|
72
|
+
|
|
73
|
+
1. If the environment variable `MYAPP_SYS_CONFIG` is set to the name of a file, it will look in that file for any system-level config file.
|
|
74
|
+
2. If the environment variable `MYAPP_SYS_CONFIG` is NOT set, it will read any system-level config file from `/etc/xdg/myapp` or, if the `XDG_CONFIG_DIRS` environment variable is set to a list of colon-separated directories, it will look in each of those instead of `/etc/xdg` for config directories called `myapp`. If more than one `XDG_CONFIG_DIRS` is given, they are treated as listed in order of precedence, so the first-listed directory will be given priority over later ones. All such directories will be read, and any config file found will be merged into the resulting Hash, but they will be visited in reverse order so that the earlier-named directories override the earlier ones.
|
|
75
|
+
3. If the environment variable `MYAPP_CONFIG` is set to a file name, it will look in that file any user-level config file.
|
|
76
|
+
4. If the environment variable `MYAPP_CONFIG` is NOT set, it will read any user-level config file from `$HOME/.config/myapp` or, if the `XDG_CONFIG_HOME` environment variable is set to an alternative directory, it will look in `XDG_CONFIG_HOME/.config` for a config directory called 'myapp'. Note that in this case, `XDG_CONFIG_HOME` is intended to contain the name of a single directory, not a list of directories as with the system-level config files.
|
|
77
|
+
5. It will then merge in any options set in the environment variable `MYAPP_OPTIONS`, overriding any conflicting settings gotten from reading the system- and user-level files. It will interpret the String from the environment variable as discussed below in [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings).
|
|
78
|
+
6. Finally, it will merge in any options given in the optional `command_line:` named parameter to the `#read` method. That parameter can either be a `Hash` or a `String`. If it is a `String`, it is interpreted the same way as the environment variable `MYAPP_OPTIONS` as explained below in [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings); if it is a `Hash`, it is used directly and merged into the hash returned from the prior methods.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
<a id="orgbc610e8"></a>
|
|
82
|
+
|
|
83
|
+
## Following Classic UNIX Standards
|
|
84
|
+
|
|
85
|
+
With the optional `:xdg` keyword parameter to `FatConfig::Reader#read` set to `false`, it will follow "classic" UNIX config file conventions. There is no "standard" here, but there are some conventions, and the closest thing I can find to describe the conventions is this from the [UNIX File Hierarchy Standard](https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s08.html#homeReferences) website:
|
|
86
|
+
|
|
87
|
+
> User specific configuration files for applications are stored in the user's home directory in a file that starts with the '.' character (a "dot file"). If an application needs to create more than one dot file then they should be placed in a subdirectory with a name starting with a '.' character, (a "dot directory"). In this case the configuration files should not start with the '.' character.
|
|
88
|
+
|
|
89
|
+
`FatConfig`'s implementation of this suggestion are as follows for a hypothetical application called `myapp`:
|
|
90
|
+
|
|
91
|
+
1. If the environment variable `MYAPP_SYS_CONFIG` is set to a file name, it will look in that file for any system-level config file.
|
|
92
|
+
2. If the environment variable `MYAPP_SYS_CONFIG` is NOT set, then either
|
|
93
|
+
- if the file `/etc/my_app` exists and is readable, it is considered the system-wide config file for `my_app`, or
|
|
94
|
+
- if the file `/etc/my_apprc` exists and is readable, it is considered the system-wide config file for `my_app`, or
|
|
95
|
+
- if the *directory* `/etc/my_app` exists, the first file named `config`, `config.yml`, `config.yaml` (this assumes the default YAML style, the extensions looked for will be adjusted for other styles) , `myapp.config`, or `myapp.cfg` that is readable will be considered the system-wide config file for `my_app`
|
|
96
|
+
3. If the environment variable `MYAPP_CONFIG` is set to a file name, it will look in that file for any user-level config file.
|
|
97
|
+
4. If the environment variable `MYAPP_CONFIG` is NOT set, then either,
|
|
98
|
+
- if the file, `~/.my_app` or `~/.my_apprc~` exist and are readable, that file is used as the user-level config file,
|
|
99
|
+
- otherwise, if the directory `~/.my_app/` exists, the first file in that directory named `config`, `config.yml`, `config.yaml`, `myapp.config`, or `myapp.cfg` that is readable will be considered the user-level config file for `my_app`
|
|
100
|
+
5. It will then merge in any options set in the environment variable `MYAPP_OPTIONS`, overriding any conflicting settings gotten from reading the system- and user-level file. It will interpret the environment setting as explained below in [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings).
|
|
101
|
+
6. Finally, it will merge in any options given in the optional `command_line:` named parameter to the `#read` method. That parameter can either be a `Hash` or a `String`. If it is a `String`, it will interpret the string as explained below in [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings); if it is a `Hash`, it is used directly and merged into the hash returned from the prior methods.
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
<a id="orgacf5ac1"></a>
|
|
105
|
+
|
|
106
|
+
## Available Config File Styles
|
|
107
|
+
|
|
108
|
+
`FatConfig::Reader.new` takes the optional keyword argument, `:style`, to indicate what style to use for config files. It can be one of:
|
|
109
|
+
|
|
110
|
+
- **`yaml`:** See [YAML Specs](https://yaml.org/spec/1.2.2/),
|
|
111
|
+
- **`toml`:** See [TOML Specs](https://toml.io/en/),
|
|
112
|
+
- **`json`:** See [JSON Specs](https://datatracker.ietf.org/doc/html/rfc8259), or
|
|
113
|
+
- **`ini`:** See [INI File on Wikipedia](https://en.wikipedia.org/wiki/INI_file)
|
|
114
|
+
|
|
115
|
+
By default, the style is `yaml`. Note that the style only pertains to the syntax of on-disk configuration files. Configuration can also be set by an environment variable, `MYAPP_OPTIONS` and by a command-line string optionally provided to the `#read` method. Those are simple parsers that parse strings of option settings as explained below. See, [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings).
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
<a id="orgf87b1a5"></a>
|
|
119
|
+
|
|
120
|
+
## Hash Keys
|
|
121
|
+
|
|
122
|
+
The returned Hash will have symbols as keys, using the names given in the config files, except that they will have any hyphens converted to the underscore. Thus the config setting "page-width: 6.5in" in a config file will result in a Hash entry of `{ page_width: '6.5in' }`.
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
<a id="org451482b"></a>
|
|
126
|
+
|
|
127
|
+
## Hash Values
|
|
128
|
+
|
|
129
|
+
Whether the values of the returned Hash will be 'deserialized' into a Ruby object is controlled by the style of the configuration files. For example, the `:yaml` style deserializes the following types:
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
<a id="orgef8563a"></a>
|
|
133
|
+
|
|
134
|
+
### YAML
|
|
135
|
+
|
|
136
|
+
- TrueClass (the string 'true' of whatever case)
|
|
137
|
+
- FalseClass (the string 'false' of whatever case)
|
|
138
|
+
- NilClass (when no value given)
|
|
139
|
+
- Integer (when it looks like an whole number)
|
|
140
|
+
- Float (when it looks like an decimal number)
|
|
141
|
+
- String (if not one of the other classes or if enclosed in single- or double-quotes)
|
|
142
|
+
- Array (when sub-elements introduced with '-', each typed by these rules)
|
|
143
|
+
- Hash, (when sub-elements introduced with 'key:', each typed by these rules) and,
|
|
144
|
+
- Date, DateTime, and Time, which FatConfig adds to the foregoing default types deserialized by the default YAML library.
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
<a id="orgcf8804e"></a>
|
|
148
|
+
|
|
149
|
+
### TOML
|
|
150
|
+
|
|
151
|
+
- TrueClass (exactly the string 'true')
|
|
152
|
+
- FalseClass (exactly the string 'false')
|
|
153
|
+
- Integer (when it looks like an whole number or 0x… or 0o… hex or octal)
|
|
154
|
+
- Float (when it looks like an decimal number)
|
|
155
|
+
- String (only if enclosed in single- or double-quotes)
|
|
156
|
+
- Array (when sub-elements enclosed in […], each typed by these rules)
|
|
157
|
+
- Hash, ([hash-key] followed by sub-elements, each typed by these rules) and,
|
|
158
|
+
- Date and Time, when given in ISO form YYYY-MM-DD or YYYY-MM-DDThh:mm:ss
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
<a id="org549e838"></a>
|
|
162
|
+
|
|
163
|
+
### JSON
|
|
164
|
+
|
|
165
|
+
- TrueClass (exactly the string 'true')
|
|
166
|
+
- FalseClass (exactly the string 'false')
|
|
167
|
+
- Integer (when it looks like an decimal whole number, but NO provision hex or octal)
|
|
168
|
+
- Float (when it looks like an decimal number)
|
|
169
|
+
- String (only if enclosed in single- or double-quotes)
|
|
170
|
+
- Array (when sub-elements enclosed in […], each typed by these rules)
|
|
171
|
+
- Hash, (when sub-elements enclosed in {…}, each typed by these rules) and,
|
|
172
|
+
- Date and Time, NOT deserialized, returns a parse error
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
<a id="org12513cc"></a>
|
|
176
|
+
|
|
177
|
+
### INI
|
|
178
|
+
|
|
179
|
+
- TrueClass (exactly the string 'true')
|
|
180
|
+
- FalseClass (exactly the string 'false')
|
|
181
|
+
- Integer (when it looks like an whole number or 0x… or 0o… hex or octal)
|
|
182
|
+
- Float (when it looks like an decimal number)
|
|
183
|
+
- String (anything else)
|
|
184
|
+
- Array NOT deserialized, returned as a String
|
|
185
|
+
- Hash, NOT deserialized, returned as a String
|
|
186
|
+
- Date and Time, NOT deserialized, returned as a String
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
<a id="org7a0f2a9"></a>
|
|
190
|
+
|
|
191
|
+
## Creating a Reader
|
|
192
|
+
|
|
193
|
+
When creating a `Reader`, the `#new` method takes a mandatory argument that specifies the name of the application for which configuration files are to be sought. It also takes a few optional keyword arguments:
|
|
194
|
+
|
|
195
|
+
- `style:` specify a style for the config files other than YAML, the choices are `yaml`, `toml`, `json`, and `ini`. This can be given either as a String or Symbol in upper or lower case.
|
|
196
|
+
- `xdg:` either `true`, to follow the XDG standard for where to find config files, or `false`, to follow classic UNIX conventions.
|
|
197
|
+
- `root_prefix:`, to locate the root of the file system somewhere other than `/`. This is probably only useful in testing `FatConfig`.
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
reader1 = FatConfig.new('labrat') # Use XDG and YAML
|
|
201
|
+
reader2 = FatConfig.new('labrat', style: 'toml') # Use XDG and TOML
|
|
202
|
+
reader3 = FatConfig.new('labrat', style: 'ini', xdg: false) # Use classic UNIX and INI style
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
<a id="org7e439f9"></a>
|
|
207
|
+
|
|
208
|
+
## Calling the `read` method on a `Reader`
|
|
209
|
+
|
|
210
|
+
Once a `Reader` is created, you can get the completely merged configuration as a Hash by calling `Reader#read`. The `read` method can take several parameters:
|
|
211
|
+
|
|
212
|
+
- **`alternative base`:** as the first positional parameter, you can give an alternative base name to use for the config files other than the app\_name given in the `Reader.new` constructor. This is useful for applications that may want to have more than one set of configuration files. If given, this name only affects the base names of the config files, not the directory in which they are to be sought: those always use the app name.
|
|
213
|
+
- **`command_line:`:** if you want a command-line to override config values, you can supply one as either a String or a Hash to the `command_line:` keyword parameter. See below for how a String is parsed.
|
|
214
|
+
- **`verbose:`:** if you set `verbose:` true as a keyword argument, the `read` method will report details of how the configuration was built on `$stderr`.
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
reader = FatConfig::Reader.new('labrat')
|
|
218
|
+
reader.read # YAML configs with basename 'labrat'; XDG conventions
|
|
219
|
+
|
|
220
|
+
# Now read another config set in directories named 'labrat' but with base
|
|
221
|
+
# names of 'labeldb'. Overrride any setting named fog_psi with command-line
|
|
222
|
+
# value, and report config build on $stderr.
|
|
223
|
+
reader.read('labeldb', command_line: "--fog-psi=3.41mm", verbose: true)
|
|
224
|
+
|
|
225
|
+
# Similar with a Hash for the command-line
|
|
226
|
+
cl = { fog_psi: '3.41mm' }
|
|
227
|
+
reader.read('labeldb', command_line: cl, verbose: true)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
<a id="parsing-environment-and-command-line-strings"></a>
|
|
232
|
+
|
|
233
|
+
## Parsing Environment and Command Line Strings
|
|
234
|
+
|
|
235
|
+
The highest priority configs are those contained in the environment variable or in any `command-line:` key-word parameter given to the `#read` method. In the case of the environment variable, the setting is always a String read from the environment.
|
|
236
|
+
|
|
237
|
+
The `command_line:` key-word parameter can be set to either a String or a Hash. When a Hash is provided, it is used unaltered as a config hash. When a String is provided (and in the case of the environment variable), the string should be something like this:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
--hello-thing='hello, world' --gb=goodbye world --doit --the_num=3.14159 --the-date=2024-11-27 --no-bueno --~junk
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
And it is parsed into this Hash:
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
{
|
|
247
|
+
:hello_thing=>"hello, world",
|
|
248
|
+
:gb=>"goodbye",
|
|
249
|
+
:doit=>true,
|
|
250
|
+
:the_num=>"3.14159",
|
|
251
|
+
:the_date=>"2024-11-27",
|
|
252
|
+
:bueno=>false,
|
|
253
|
+
:junk=>false
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Here are the parsing rules:
|
|
258
|
+
|
|
259
|
+
1. A config element is either of the following, everything else is ignored:
|
|
260
|
+
1. an "option," of the form "`--<option-name>=<value>`" or
|
|
261
|
+
|
|
262
|
+
2. a "flag" of the form "`--<flag-name>`"
|
|
263
|
+
|
|
264
|
+
2. All option values are returned as String's and are not deserialized into Ruby objects,
|
|
265
|
+
3. All flags are returned as a boolean `true` or `false`. If the flag name starts with 'no', 'no-', 'no\_', '!', or '~', it is set to `false` and the option name has the negating prefix stripped; otherwise, it is set to `true`.
|
|
266
|
+
4. These rules apply regardless of style being used for config files.
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
<a id="org1fdfa48"></a>
|
|
270
|
+
|
|
271
|
+
# Development
|
|
272
|
+
|
|
273
|
+
After checking out the repo, run \`bin/setup\` to install dependencies. Then, run \`rake spec\` to run the tests. You can also run \`bin/console\` for an interactive prompt that will allow you to experiment.
|
|
274
|
+
|
|
275
|
+
To install this gem onto your local machine, run \`bundle exec rake install\`. To release a new version, update the version number in \`version.rb\`, and then run \`bundle exec rake release\`, which will create a git tag for the version, push git commits and the created tag, and push the \`.gem\` file to [rubygems.org](https://rubygems.org).
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
<a id="org4454a76"></a>
|
|
279
|
+
|
|
280
|
+
# Contributing
|
|
281
|
+
|
|
282
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/ddoherty03/fat_config>.
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
<a id="org8a2eaa6"></a>
|
|
286
|
+
|
|
287
|
+
# License
|
|
288
|
+
|
|
289
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/README.org
CHANGED
|
@@ -1,11 +1,48 @@
|
|
|
1
|
-
|
|
1
|
+
#+TITLE: FatConfig
|
|
2
|
+
#+PROPERTY: header-args:ruby :results value :colnames no :hlines yes :exports both :dir "./"
|
|
3
|
+
#+PROPERTY: header-args:ruby+ :wrap example :session fat_config_session :eval yes
|
|
4
|
+
#+PROPERTY: header-args:ruby+ :prologue "$:.unshift('./lib') unless $:.first == './lib'; require 'fat_config'"
|
|
5
|
+
#+PROPERTY: header-args:sh :exports code :eval no
|
|
6
|
+
#+PROPERTY: header-args:bash :exports code :eval no
|
|
7
|
+
|
|
8
|
+
[[https://github.com/ddoherty03/fat_config/actions/workflows/main.yml][https://github.com/ddoherty03/fat_config/actions/workflows/main.yml/badge.svg?branch=master]]
|
|
9
|
+
|
|
10
|
+
* Introduction
|
|
11
|
+
Allowing a user to configure an application to change its behavior at runtime
|
|
12
|
+
can be seen as constructing a ruby ~Hash~ that merges settings from a variety
|
|
13
|
+
of sources in a hierarchical fashion: first from system-wide file settings,
|
|
14
|
+
merged with user-level file settings, merged with environment variable
|
|
15
|
+
settings, merged with command-line parameters. Constructing this Hash, while
|
|
16
|
+
needed by nearly any command-line app, can be a tedious chore, especially when
|
|
17
|
+
there are standards, such as the XDG standards and Unix tradition, that may or
|
|
18
|
+
may not be followed.
|
|
2
19
|
|
|
3
20
|
~FatConfig~ eliminates the tedium of reading configuration files and the
|
|
4
21
|
environment to populate a Hash of configuration settings. You need only
|
|
5
|
-
define a ~FatConfig::Reader~ and
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
~
|
|
22
|
+
define a ~FatConfig::Reader~ and call its ~#read~ method to look for, read,
|
|
23
|
+
translate, and merge any config files into a single Hash that encapsulates all
|
|
24
|
+
the files in the proper priority. It can be set to read ~YAML~, ~TOML~,
|
|
25
|
+
~JSON~, or ~INI~ config files.
|
|
26
|
+
|
|
27
|
+
* Table of Contents :toc:noexport:
|
|
28
|
+
- [[#introduction][Introduction]]
|
|
29
|
+
- [[#installation][Installation]]
|
|
30
|
+
- [[#usage][Usage:]]
|
|
31
|
+
- [[#following-xdg-standards][Following XDG Standards]]
|
|
32
|
+
- [[#following-classic-unix-standards][Following Classic UNIX Standards]]
|
|
33
|
+
- [[#available-config-file-styles][Available Config File Styles]]
|
|
34
|
+
- [[#hash-keys][Hash Keys]]
|
|
35
|
+
- [[#hash-values][Hash Values]]
|
|
36
|
+
- [[#yaml][YAML]]
|
|
37
|
+
- [[#toml][TOML]]
|
|
38
|
+
- [[#json][JSON]]
|
|
39
|
+
- [[#ini][INI]]
|
|
40
|
+
- [[#creating-a-reader][Creating a Reader]]
|
|
41
|
+
- [[#calling-the-read-method-on-a-reader][Calling the ~read~ method on a ~Reader~]]
|
|
42
|
+
- [[#parsing-environment-and-command-line-strings][Parsing Environment and Command Line Strings]]
|
|
43
|
+
- [[#development][Development]]
|
|
44
|
+
- [[#contributing][Contributing]]
|
|
45
|
+
- [[#license][License]]
|
|
9
46
|
|
|
10
47
|
* Installation
|
|
11
48
|
|
|
@@ -30,6 +67,10 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
|
30
67
|
config = reader.read
|
|
31
68
|
#+end_src
|
|
32
69
|
|
|
70
|
+
#+RESULTS:
|
|
71
|
+
#+begin_example
|
|
72
|
+
#+end_example
|
|
73
|
+
|
|
33
74
|
The ~reader.read~ method will parse the config files (by default assumed to be
|
|
34
75
|
YAML files), config environment variable, and optional command-line parameters
|
|
35
76
|
and return the composite config as a Hash.
|
|
@@ -49,26 +90,26 @@ from the following locations, from lowest priority to highest:
|
|
|
49
90
|
treated as listed in order of precedence, so the first-listed directory
|
|
50
91
|
will be given priority over later ones. All such directories will be read,
|
|
51
92
|
and any config file found will be merged into the resulting Hash, but they
|
|
52
|
-
will be visited in reverse order so that the
|
|
93
|
+
will be visited in reverse order so that the earlier-named directories
|
|
53
94
|
override the earlier ones.
|
|
54
95
|
3. If the environment variable ~MYAPP_CONFIG~ is set to a file name, it will
|
|
55
96
|
look in that file any user-level config file.
|
|
56
97
|
4. If the environment variable ~MYAPP_CONFIG~ is NOT set, it will read any
|
|
57
98
|
user-level config file from ~$HOME/.config/myapp~ or, if the
|
|
58
99
|
~XDG_CONFIG_HOME~ environment variable is set to an alternative directory,
|
|
59
|
-
it will look ~XDG_CONFIG_HOME/.config~ for a config directory called
|
|
100
|
+
it will look in ~XDG_CONFIG_HOME/.config~ for a config directory called
|
|
60
101
|
'myapp'. Note that in this case, ~XDG_CONFIG_HOME~ is intended to contain
|
|
61
102
|
the name of a single directory, not a list of directories as with the
|
|
62
103
|
system-level config files.
|
|
63
104
|
5. It will then merge in any options set in the environment variable
|
|
64
105
|
~MYAPP_OPTIONS~, overriding any conflicting settings gotten from reading
|
|
65
|
-
the system- and user-level
|
|
66
|
-
environment variable as discussed below in [[
|
|
106
|
+
the system- and user-level files. It will interpret the String from the
|
|
107
|
+
environment variable as discussed below in [[#parsing-environment-and-command-line-strings][Parsing Environment and Command
|
|
67
108
|
Line Strings]].
|
|
68
109
|
6. Finally, it will merge in any options given in the optional ~command_line:~
|
|
69
110
|
named parameter to the ~#read~ method. That parameter can either be a
|
|
70
111
|
~Hash~ or a ~String~. If it is a ~String~, it is interpreted the same way
|
|
71
|
-
as the environment variable ~MYAPP_OPTIONS~ as explained below in [[
|
|
112
|
+
as the environment variable ~MYAPP_OPTIONS~ as explained below in [[#parsing-environment-and-command-line-strings][Parsing
|
|
72
113
|
Environment and Command Line Strings]]; if it is a ~Hash~, it is used
|
|
73
114
|
directly and merged into the hash returned from the prior methods.
|
|
74
115
|
|
|
@@ -140,18 +181,21 @@ of option settings as explained below. See, [[*Parsing Environment and Command
|
|
|
140
181
|
Line Strings]].
|
|
141
182
|
|
|
142
183
|
** Hash Keys
|
|
143
|
-
|
|
144
|
-
config files, except that they will have any hyphens converted to the
|
|
145
|
-
underscore
|
|
146
|
-
result in a Hash entry of ~{
|
|
184
|
+
Any keys that are Strings will be converted to a symbol, using the names given
|
|
185
|
+
in the config files, except that they will have any hyphens converted to the
|
|
186
|
+
underscore so they are suitable for use as a method call. Thus the config
|
|
187
|
+
setting "page-width: 6.5in" in a config file will result in a Hash entry of ~{
|
|
188
|
+
page_width: '6.5in' }~.
|
|
189
|
+
|
|
190
|
+
Keys that are not Strings will be left alone, so that, for example, you might
|
|
191
|
+
have Integer keys, which may be useful below the top level.
|
|
147
192
|
|
|
148
193
|
** Hash Values
|
|
149
194
|
Whether the values of the returned Hash will be 'deserialized' into a Ruby
|
|
150
|
-
object is controlled by the style of the configuration files.
|
|
151
|
-
the ~:yaml~ style deserializes the following types:
|
|
195
|
+
object is controlled by the style of the configuration files.
|
|
152
196
|
|
|
153
197
|
*** YAML
|
|
154
|
-
|
|
198
|
+
The ~:yaml~ style deserializes the following types:
|
|
155
199
|
- TrueClass (the string 'true' of whatever case)
|
|
156
200
|
- FalseClass (the string 'false' of whatever case)
|
|
157
201
|
- NilClass (when no value given)
|
|
@@ -164,7 +208,7 @@ the ~:yaml~ style deserializes the following types:
|
|
|
164
208
|
types deserialized by the default YAML library.
|
|
165
209
|
|
|
166
210
|
*** TOML
|
|
167
|
-
|
|
211
|
+
The ~:toml~ style deserializes the following types:
|
|
168
212
|
- TrueClass (exactly the string 'true')
|
|
169
213
|
- FalseClass (exactly the string 'false')
|
|
170
214
|
- Integer (when it looks like an whole number or 0x... or 0o... hex or octal)
|
|
@@ -175,7 +219,7 @@ the ~:yaml~ style deserializes the following types:
|
|
|
175
219
|
- Date and Time, when given in ISO form YYYY-MM-DD or YYYY-MM-DDThh:mm:ss
|
|
176
220
|
|
|
177
221
|
*** JSON
|
|
178
|
-
|
|
222
|
+
The ~:json~ style deserializes the following types:
|
|
179
223
|
- TrueClass (exactly the string 'true')
|
|
180
224
|
- FalseClass (exactly the string 'false')
|
|
181
225
|
- Integer (when it looks like an decimal whole number, but NO provision hex
|
|
@@ -187,7 +231,7 @@ the ~:yaml~ style deserializes the following types:
|
|
|
187
231
|
- Date and Time, NOT deserialized, returns a parse error
|
|
188
232
|
|
|
189
233
|
*** INI
|
|
190
|
-
|
|
234
|
+
The ~:ini~ style deserializes the following types:
|
|
191
235
|
- TrueClass (exactly the string 'true')
|
|
192
236
|
- FalseClass (exactly the string 'false')
|
|
193
237
|
- Integer (when it looks like an whole number or 0x... or 0o... hex or octal)
|
|
@@ -210,18 +254,16 @@ sought. It also takes a few optional keyword arguments:
|
|
|
210
254
|
- ~root_prefix:~, to locate the root of the file system somewhere other than
|
|
211
255
|
~/~. This is probably only useful in testing ~FatConfig~.
|
|
212
256
|
|
|
213
|
-
#+begin_src ruby
|
|
214
|
-
require 'fat_config'
|
|
215
|
-
|
|
257
|
+
#+begin_src ruby :eval no
|
|
216
258
|
reader1 = FatConfig.new('labrat') # Use XDG and YAML
|
|
217
259
|
reader2 = FatConfig.new('labrat', style: 'toml') # Use XDG and TOML
|
|
218
260
|
reader3 = FatConfig.new('labrat', style: 'ini', xdg: false) # Use classic UNIX and INI style
|
|
219
261
|
#+end_src
|
|
220
262
|
|
|
221
|
-
** Calling the
|
|
263
|
+
** Calling the ~read~ method on a ~Reader~
|
|
222
264
|
Once a ~Reader~ is created, you can get the completely merged configuration as
|
|
223
265
|
a Hash by calling ~Reader#read~. The ~read~ method can take several
|
|
224
|
-
|
|
266
|
+
parameters:
|
|
225
267
|
|
|
226
268
|
- ~alternative base~ :: as the first positional parameter, you can give an
|
|
227
269
|
alternative base name to use for the config files other than the app_name
|
|
@@ -235,9 +277,7 @@ parameter:
|
|
|
235
277
|
- ~verbose:~ :: if you set ~verbose:~ true as a keyword argument, the ~read~
|
|
236
278
|
method will report details of how the configuration was built on ~$stderr~.
|
|
237
279
|
|
|
238
|
-
#+begin_src ruby
|
|
239
|
-
require 'fat_config'
|
|
240
|
-
|
|
280
|
+
#+begin_src ruby :eval no
|
|
241
281
|
reader = FatConfig::Reader.new('labrat')
|
|
242
282
|
reader.read # YAML configs with basename 'labrat'; XDG conventions
|
|
243
283
|
|
|
@@ -252,6 +292,10 @@ parameter:
|
|
|
252
292
|
#+end_src
|
|
253
293
|
|
|
254
294
|
** Parsing Environment and Command Line Strings
|
|
295
|
+
:PROPERTIES:
|
|
296
|
+
:CUSTOM_ID: parsing-environment-and-command-line-strings
|
|
297
|
+
:END:
|
|
298
|
+
|
|
255
299
|
The highest priority configs are those contained in the environment variable
|
|
256
300
|
or in any ~command-line:~ key-word parameter given to the ~#read~ method. In
|
|
257
301
|
the case of the environment variable, the setting is always a String read from
|
|
@@ -268,9 +312,9 @@ should be something like this:
|
|
|
268
312
|
|
|
269
313
|
And it is parsed into this Hash:
|
|
270
314
|
|
|
271
|
-
#+begin_src ruby
|
|
315
|
+
#+begin_src ruby :eval no
|
|
272
316
|
{
|
|
273
|
-
|
|
317
|
+
:hello_thing=>"hello, world",
|
|
274
318
|
:gb=>"goodbye",
|
|
275
319
|
:doit=>true,
|
|
276
320
|
:the_num=>"3.14159",
|
|
@@ -282,9 +326,12 @@ And it is parsed into this Hash:
|
|
|
282
326
|
|
|
283
327
|
Here are the parsing rules:
|
|
284
328
|
|
|
285
|
-
1. A config element is either
|
|
286
|
-
|
|
287
|
-
|
|
329
|
+
1. A config element is either of the following, everything else is ignored:
|
|
330
|
+
|
|
331
|
+
a. an "option," of the form "~--<option-name>=<value>~" or
|
|
332
|
+
|
|
333
|
+
b. a "flag" of the form "~--<flag-name>~"
|
|
334
|
+
|
|
288
335
|
2. All option values are returned as String's and are not deserialized into
|
|
289
336
|
Ruby objects,
|
|
290
337
|
3. All flags are returned as a boolean ~true~ or ~false~. If the flag name
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Array
|
|
4
|
+
# Transform String hash keys to symbols suitable for calling as methods,
|
|
5
|
+
# i.e., translate any hyphens to underscores. This is the form we want to
|
|
6
|
+
# keep config hashes in Labrat. Leave non-String keys alone, so, e.g., an
|
|
7
|
+
# Integer can be a key below the top-level
|
|
8
|
+
def methodize
|
|
9
|
+
new_arr = []
|
|
10
|
+
each do |v|
|
|
11
|
+
new_arr <<
|
|
12
|
+
case v
|
|
13
|
+
when Hash, Array
|
|
14
|
+
v.methodize
|
|
15
|
+
when Symbol, String
|
|
16
|
+
# In case the key is a Symbol like :"a key-for-me", convert it back to
|
|
17
|
+
# a String, then let #as_sym convert it to a proper Symbol that can be
|
|
18
|
+
# used as a method call.
|
|
19
|
+
v.as_sym
|
|
20
|
+
else
|
|
21
|
+
v
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
new_arr
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Hash
|
|
4
|
-
# Transform hash keys to symbols suitable for calling as methods,
|
|
5
|
-
# translate any hyphens to underscores. This is the form we want to
|
|
6
|
-
# config hashes in Labrat.
|
|
4
|
+
# Transform String hash keys to symbols suitable for calling as methods,
|
|
5
|
+
# i.e., translate any hyphens to underscores. This is the form we want to
|
|
6
|
+
# keep config hashes in Labrat. Leave non-String keys alone, so, e.g., an
|
|
7
|
+
# Integer can be a key below the top-level
|
|
7
8
|
def methodize
|
|
8
9
|
new_hash = {}
|
|
9
10
|
each_pair do |k, v|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
case k
|
|
12
|
+
when String
|
|
13
|
+
new_hash[k.as_sym] = v.kind_of?(Hash) ? v.methodize : v
|
|
14
|
+
when Symbol
|
|
15
|
+
# In case the key is a Symbol like :"a key-for-me", convert it back to
|
|
16
|
+
# a String, then let #as_sym convert it to a proper Symbol that can be
|
|
17
|
+
# used as a method call.
|
|
18
|
+
new_hash[k.to_s.as_sym] = v.kind_of?(Hash) ? v.methodize : v
|
|
19
|
+
else
|
|
20
|
+
new_hash[k] = v.kind_of?(Hash) ? v.methodize : v
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
new_hash
|
|
19
24
|
end
|
data/lib/fat_config/errors.rb
CHANGED
data/lib/fat_config/reader.rb
CHANGED
|
@@ -228,7 +228,7 @@ module FatConfig
|
|
|
228
228
|
def find_classic_sys_config_files(base = app_name)
|
|
229
229
|
configs = []
|
|
230
230
|
env_config = ENV["#{app_name.upcase}_SYS_CONFIG"]
|
|
231
|
-
if env_config && File.readable?(
|
|
231
|
+
if env_config && File.readable?(config = File.join(root_prefix, File.expand_path(env_config)))
|
|
232
232
|
configs = [config]
|
|
233
233
|
elsif File.readable?(config = File.join(root_prefix, "/etc/#{base}"))
|
|
234
234
|
configs = [config]
|
|
@@ -251,7 +251,7 @@ module FatConfig
|
|
|
251
251
|
# given.
|
|
252
252
|
def find_classic_user_config_file(base = app_name)
|
|
253
253
|
env_config = ENV["#{app_name.upcase}_CONFIG"]
|
|
254
|
-
if env_config && File.readable?(
|
|
254
|
+
if env_config && File.readable?(config = File.join(root_prefix, File.expand_path(env_config)))
|
|
255
255
|
config
|
|
256
256
|
else
|
|
257
257
|
config_dir = File.join(root_prefix, File.expand_path("~/"))
|
data/lib/fat_config/style.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FatConfig
|
|
2
4
|
# This class acts as a super class for specific styles of config files. The
|
|
3
5
|
# subclass must provide a load_file method that takes a file name, reads it
|
|
@@ -29,11 +31,10 @@ module FatConfig
|
|
|
29
31
|
file_hash = load_file(f)
|
|
30
32
|
next unless file_hash
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else
|
|
35
|
-
raise "Error loading file #{f}:\n#{File.read(f)[0..500]}"
|
|
34
|
+
unless file_hash.is_a?(Hash)
|
|
35
|
+
raise FatConfig::ParseError, "Error loading file #{f}:\n#{File.read(f)[0..500]}"
|
|
36
36
|
end
|
|
37
|
+
|
|
37
38
|
if verbose
|
|
38
39
|
warn "Merging system config from file '#{f}':" if sys_files.include?(f)
|
|
39
40
|
warn "Merging user config from file '#{f}':" if usr_files.include?(f)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FatConfig
|
|
2
4
|
class INIStyle < Style
|
|
3
5
|
def load_string(str)
|
|
@@ -11,7 +13,17 @@ module FatConfig
|
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def load_file(file_name)
|
|
14
|
-
IniFile.load(file_name)
|
|
16
|
+
ini = IniFile.load(file_name)
|
|
17
|
+
config = {}
|
|
18
|
+
ini.each_section do |sec|
|
|
19
|
+
case ini[sec]
|
|
20
|
+
when Hash
|
|
21
|
+
config[sec.to_sym] = ini[sec].methodize
|
|
22
|
+
else
|
|
23
|
+
config[sec.to_sym] = ini[sec]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
config
|
|
15
27
|
rescue IniFile::Error => ex
|
|
16
28
|
raise FatConfig::ParseError, ex.to_s
|
|
17
29
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'date'
|
|
2
4
|
|
|
3
5
|
module FatConfig
|
|
@@ -17,29 +19,46 @@ module FatConfig
|
|
|
17
19
|
# - Array
|
|
18
20
|
# - Hash
|
|
19
21
|
#
|
|
20
|
-
# Recursive data structures are not allowed by default. Arbitrary
|
|
21
|
-
# can be allowed by adding those classes to the permitted_classes
|
|
22
|
+
# Recursive data structures are not allowed by Psych by default. Arbitrary
|
|
23
|
+
# classes can be allowed by adding those classes to the permitted_classes
|
|
22
24
|
# keyword argument. They are additive. For example, to allow Date
|
|
23
25
|
# deserialization:
|
|
24
26
|
#
|
|
25
27
|
# Config.read adds Date, etc., to permitted classes, but provides for no others.
|
|
26
28
|
class YAMLStyle < Style
|
|
27
|
-
def load_string(str)
|
|
28
|
-
Psych.safe_load(
|
|
29
|
+
def load_string(str, top_sym: :config)
|
|
30
|
+
data = Psych.safe_load(
|
|
29
31
|
str,
|
|
30
|
-
symbolize_names:
|
|
32
|
+
symbolize_names: false,
|
|
31
33
|
permitted_classes: [Date, DateTime, Time],
|
|
32
|
-
)
|
|
34
|
+
)
|
|
35
|
+
case data
|
|
36
|
+
when Hash
|
|
37
|
+
data.methodize
|
|
38
|
+
when Array
|
|
39
|
+
{ top_sym => data.methodize }
|
|
40
|
+
when NilClass
|
|
41
|
+
{}
|
|
42
|
+
end
|
|
33
43
|
rescue Psych::SyntaxError => ex
|
|
34
44
|
raise FatConfig::ParseError, ex.to_s
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
def load_file(file_name)
|
|
38
|
-
|
|
48
|
+
top_sym = File.basename(file_name).sub(/\.[^\.]*$/, '').as_sym
|
|
49
|
+
data = Psych.safe_load_file(
|
|
39
50
|
file_name,
|
|
40
|
-
symbolize_names:
|
|
51
|
+
symbolize_names: false,
|
|
41
52
|
permitted_classes: [Date, DateTime, Time],
|
|
42
|
-
)
|
|
53
|
+
)
|
|
54
|
+
case data
|
|
55
|
+
when Hash
|
|
56
|
+
data.methodize
|
|
57
|
+
when Array
|
|
58
|
+
{ top_sym => data.methodize }
|
|
59
|
+
when NilClass
|
|
60
|
+
{}
|
|
61
|
+
end
|
|
43
62
|
rescue Psych::SyntaxError => ex
|
|
44
63
|
raise FatConfig::ParseError, ex.to_s
|
|
45
64
|
end
|
data/lib/fat_config/version.rb
CHANGED
data/lib/fat_config.rb
CHANGED
|
@@ -8,13 +8,30 @@ require 'tomlib'
|
|
|
8
8
|
require 'inifile'
|
|
9
9
|
require 'json'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
# Gem Overview (extracted from README.org by gem_docs)
|
|
12
|
+
#
|
|
13
|
+
# * Introduction
|
|
14
|
+
# Allowing a user to configure an application to change its behavior at runtime
|
|
15
|
+
# can be seen as constructing a ruby ~Hash~ that merges settings from a variety
|
|
16
|
+
# of sources in a hierarchical fashion: first from system-wide file settings,
|
|
17
|
+
# merged with user-level file settings, merged with environment variable
|
|
18
|
+
# settings, merged with command-line parameters. Constructing this Hash, while
|
|
19
|
+
# needed by nearly any command-line app, can be a tedious chore, especially when
|
|
20
|
+
# there are standards, such as the XDG standards and Unix tradition, that may or
|
|
21
|
+
# may not be followed.
|
|
22
|
+
#
|
|
23
|
+
# ~FatConfig~ eliminates the tedium of reading configuration files and the
|
|
24
|
+
# environment to populate a Hash of configuration settings. You need only
|
|
25
|
+
# define a ~FatConfig::Reader~ and call its ~#read~ method to look for, read,
|
|
26
|
+
# translate, and merge any config files into a single Hash that encapsulates all
|
|
27
|
+
# the files in the proper priority. It can be set to read ~YAML~, ~TOML~,
|
|
28
|
+
# ~JSON~, or ~INI~ config files.
|
|
17
29
|
module FatConfig
|
|
18
30
|
class Error < StandardError; end
|
|
19
|
-
|
|
31
|
+
require_relative "fat_config/version"
|
|
32
|
+
require_relative "fat_config/errors"
|
|
33
|
+
require_relative "fat_config/core_ext/hash_ext"
|
|
34
|
+
require_relative "fat_config/core_ext/array_ext"
|
|
35
|
+
require_relative "fat_config/reader"
|
|
36
|
+
require_relative "fat_config/style"
|
|
20
37
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fat_config
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel E. Doherty
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|
|
@@ -81,13 +81,17 @@ executables: []
|
|
|
81
81
|
extensions: []
|
|
82
82
|
extra_rdoc_files: []
|
|
83
83
|
files:
|
|
84
|
+
- ".envrc"
|
|
84
85
|
- ".rspec"
|
|
85
86
|
- ".rubocop.yml"
|
|
87
|
+
- ".yardopts"
|
|
86
88
|
- LICENSE.txt
|
|
89
|
+
- README.md
|
|
87
90
|
- README.org
|
|
88
91
|
- Rakefile
|
|
89
92
|
- TODO.org
|
|
90
93
|
- lib/fat_config.rb
|
|
94
|
+
- lib/fat_config/core_ext/array_ext.rb
|
|
91
95
|
- lib/fat_config/core_ext/hash_ext.rb
|
|
92
96
|
- lib/fat_config/errors.rb
|
|
93
97
|
- lib/fat_config/reader.rb
|
|
@@ -97,15 +101,14 @@ files:
|
|
|
97
101
|
- lib/fat_config/styles/toml_style.rb
|
|
98
102
|
- lib/fat_config/styles/yaml_style.rb
|
|
99
103
|
- lib/fat_config/version.rb
|
|
100
|
-
- rubocop-global.yml
|
|
101
104
|
- sig/fat_config.rbs
|
|
102
|
-
homepage: https://
|
|
105
|
+
homepage: https://github.com/ddoherty.net/fat_config
|
|
103
106
|
licenses:
|
|
104
107
|
- MIT
|
|
105
108
|
metadata:
|
|
106
109
|
allowed_push_host: https://rubygems.org
|
|
107
|
-
homepage_uri: https://
|
|
108
|
-
source_code_uri: https://
|
|
110
|
+
homepage_uri: https://github.com/ddoherty.net/fat_config
|
|
111
|
+
source_code_uri: https://github.com/ddoherty.net/fat_config
|
|
109
112
|
rdoc_options: []
|
|
110
113
|
require_paths:
|
|
111
114
|
- lib
|
|
@@ -120,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
120
123
|
- !ruby/object:Gem::Version
|
|
121
124
|
version: '0'
|
|
122
125
|
requirements: []
|
|
123
|
-
rubygems_version:
|
|
126
|
+
rubygems_version: 4.0.0
|
|
124
127
|
specification_version: 4
|
|
125
128
|
summary: Library to read config from standard XDG or classic locations.
|
|
126
129
|
test_files: []
|
data/rubocop-global.yml
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
require:
|
|
2
|
-
- rubocop-rake
|
|
3
|
-
|
|
4
|
-
plugins:
|
|
5
|
-
- rubocop-performance
|
|
6
|
-
- rubocop-rspec
|
|
7
|
-
|
|
8
|
-
inherit_gem:
|
|
9
|
-
rubocop-shopify: rubocop.yml
|
|
10
|
-
|
|
11
|
-
AllCops:
|
|
12
|
-
NewCops: enable
|
|
13
|
-
# TargetRubyVersion: 3.0
|
|
14
|
-
|
|
15
|
-
Style/DateTime:
|
|
16
|
-
Enabled: false
|
|
17
|
-
|
|
18
|
-
Style/StringLiteralsInInterpolation:
|
|
19
|
-
Enabled: true
|
|
20
|
-
EnforcedStyle: single_quotes
|
|
21
|
-
|
|
22
|
-
Style/MethodCallWithArgsParentheses:
|
|
23
|
-
Enabled: false
|
|
24
|
-
|
|
25
|
-
Style/StringLiterals:
|
|
26
|
-
Enabled: false
|
|
27
|
-
|
|
28
|
-
Style/WordArray:
|
|
29
|
-
Enabled: false
|
|
30
|
-
|
|
31
|
-
Style/SymbolArray:
|
|
32
|
-
Enabled: false
|
|
33
|
-
|
|
34
|
-
Style/TrailingCommaInHashLiteral:
|
|
35
|
-
Enabled: false
|
|
36
|
-
|
|
37
|
-
Style/TrailingCommaInArrayLiteral:
|
|
38
|
-
Enabled: false
|
|
39
|
-
|
|
40
|
-
Style/HashSyntax:
|
|
41
|
-
Enabled: false
|
|
42
|
-
|
|
43
|
-
Style/ClassMethodsDefinitions:
|
|
44
|
-
Enabled: true
|
|
45
|
-
EnforcedStyle: def_self
|
|
46
|
-
|
|
47
|
-
Layout/LineLength:
|
|
48
|
-
Enabled: true
|
|
49
|
-
Max: 120
|
|
50
|
-
# To make it possible to copy or click on URIs in the code, we allow lines
|
|
51
|
-
# containing a URI to be longer than Max.
|
|
52
|
-
AllowHeredoc: true
|
|
53
|
-
AllowURI: true
|
|
54
|
-
URISchemes:
|
|
55
|
-
- http
|
|
56
|
-
- https
|
|
57
|
-
|
|
58
|
-
Layout/ArgumentAlignment:
|
|
59
|
-
Enabled: true
|
|
60
|
-
EnforcedStyle: with_first_argument
|
|
61
|
-
|
|
62
|
-
Naming/InclusiveLanguage:
|
|
63
|
-
Enabled: false
|
|
64
|
-
|
|
65
|
-
Metrics/AbcSize:
|
|
66
|
-
# The ABC size is a calculated magnitude, so this number can be a Fixnum or
|
|
67
|
-
# a Float.
|
|
68
|
-
Enabled: false
|
|
69
|
-
Max: 50
|
|
70
|
-
|
|
71
|
-
Metrics/BlockNesting:
|
|
72
|
-
Enabled: false
|
|
73
|
-
Max: 3
|
|
74
|
-
|
|
75
|
-
Metrics/BlockLength:
|
|
76
|
-
Enabled: false
|
|
77
|
-
Max: 25
|
|
78
|
-
|
|
79
|
-
Metrics/ClassLength:
|
|
80
|
-
Enabled: false
|
|
81
|
-
CountComments: false # count full line comments?
|
|
82
|
-
Max: 100
|
|
83
|
-
|
|
84
|
-
Metrics/ModuleLength:
|
|
85
|
-
Enabled: false
|
|
86
|
-
CountComments: false # count full line comments?
|
|
87
|
-
Max: 100
|
|
88
|
-
|
|
89
|
-
Metrics/MethodLength:
|
|
90
|
-
Enabled: false
|
|
91
|
-
CountComments: false # count full line comments?
|
|
92
|
-
Max: 10
|
|
93
|
-
|
|
94
|
-
# Avoid complex methods.
|
|
95
|
-
Metrics/CyclomaticComplexity:
|
|
96
|
-
Enabled: false
|
|
97
|
-
Max: 20
|
|
98
|
-
|
|
99
|
-
Metrics/ParameterLists:
|
|
100
|
-
Max: 5
|
|
101
|
-
CountKeywordArgs: false
|
|
102
|
-
|
|
103
|
-
Metrics/PerceivedComplexity:
|
|
104
|
-
Enabled: false
|
|
105
|
-
Max: 8
|
|
106
|
-
|
|
107
|
-
Layout/MultilineOperationIndentation:
|
|
108
|
-
EnforcedStyle: aligned
|
|
109
|
-
|
|
110
|
-
Layout/MultilineMethodCallIndentation:
|
|
111
|
-
EnforcedStyle: indented_relative_to_receiver
|
|
112
|
-
SupportedStyles:
|
|
113
|
-
- aligned
|
|
114
|
-
- indented
|
|
115
|
-
- indented_relative_to_receiver
|
|
116
|
-
# By default, the indentation width from Style/IndentationWidth is used
|
|
117
|
-
# But it can be overridden by setting this parameter
|
|
118
|
-
IndentationWidth: ~
|
|
119
|
-
|
|
120
|
-
# Though the style guides recommend against them, I like perl back references.
|
|
121
|
-
# They are much more concise than the recommended: $2 vs. Regexp.last_match(2).
|
|
122
|
-
# Two characters versus 18!
|
|
123
|
-
# Cop supports --auto-correct.
|
|
124
|
-
Style/PerlBackrefs:
|
|
125
|
-
Enabled: false
|
|
126
|
-
|
|
127
|
-
# Cop supports --auto-correct.
|
|
128
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
|
|
129
|
-
# SupportedStyles: line_count_based, semantic, braces_for_chaining
|
|
130
|
-
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
|
|
131
|
-
# FunctionalMethods: let, let!, subject, watch
|
|
132
|
-
# IgnoredMethods: lambda, proc, it
|
|
133
|
-
Style/BlockDelimiters:
|
|
134
|
-
EnforcedStyle: braces_for_chaining
|
|
135
|
-
ProceduralMethods: expect
|
|
136
|
-
|
|
137
|
-
# Cop supports --auto-correct.
|
|
138
|
-
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
|
139
|
-
Layout/ExtraSpacing:
|
|
140
|
-
AllowForAlignment: true
|
|
141
|
-
|
|
142
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
|
143
|
-
# SupportedStyles: format, sprintf, percent
|
|
144
|
-
Style/FormatString:
|
|
145
|
-
Enabled: false
|
|
146
|
-
|
|
147
|
-
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
|
148
|
-
# NamePrefix: is_, has_, have_
|
|
149
|
-
# NamePrefixBlacklist: is_, has_, have_
|
|
150
|
-
# NameWhitelist: is_a?
|
|
151
|
-
Naming/PredicateName:
|
|
152
|
-
AllowedMethods: has_overlaps_within?
|
|
153
|
-
Exclude:
|
|
154
|
-
- 'spec/**/*'
|
|
155
|
-
|
|
156
|
-
# Cop supports --auto-correct.
|
|
157
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
|
158
|
-
# SupportedStyles: always, never
|
|
159
|
-
Style/FrozenStringLiteralComment:
|
|
160
|
-
Enabled: false
|
|
161
|
-
EnforcedStyle: always
|
|
162
|
-
|
|
163
|
-
# I like using !! to convert a value to boolean.
|
|
164
|
-
Style/DoubleNegation:
|
|
165
|
-
Enabled: false
|
|
166
|
-
|
|
167
|
-
RSpec/MultipleExpectations:
|
|
168
|
-
Enabled: false
|
|
169
|
-
|
|
170
|
-
RSpec/ExampleLength:
|
|
171
|
-
Enabled: false
|
|
172
|
-
|
|
173
|
-
RSpec/DescribedClass:
|
|
174
|
-
Enabled: false
|
|
175
|
-
|
|
176
|
-
RSpec/MultipleMemoizedHelpers:
|
|
177
|
-
Max: 10
|
|
178
|
-
|
|
179
|
-
RSpec/NestedGroups:
|
|
180
|
-
Max: 5
|