fat_config 0.7.1 → 0.8.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/CHANGELOG.md +22 -4
- data/CHANGELOG.org +10 -0
- data/README.md +73 -41
- data/README.org +48 -2
- data/lib/fat_config/reader.rb +103 -54
- data/lib/fat_config/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 431c883197a326bde2824b5b605b667adede33fcee328575d3c123e6a051918b
|
|
4
|
+
data.tar.gz: f97f4216cfddebe0d5c4b034b387005916c38e3e61d22b57b67de41001c6d367
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 756d931f4a0a11b1d235f406b6c8624bd140ed11045a3aa6eeed85edb425d5139648cffc0866d3e59be6b2b73eeecbd689d641c0765d65b9915b0649672b6149
|
|
7
|
+
data.tar.gz: 7b896e62e452f926038b84c65405d10329edcb48c816a257da14025d11e5890bf54c5f1cd9ee40f211c8396b423335e756ea8305355b2c9a62f31a30f57d2db1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
- [Version 0.
|
|
2
|
-
- [Version 0.
|
|
1
|
+
- [Version 0.8.1 <span class="timestamp-wrapper"><span class="timestamp">[2026-11-14 Sat]</span></span>](#orgd39cf28)
|
|
2
|
+
- [Version 0.8.0](#orgd2c1c74)
|
|
3
|
+
- [Version 0.7.1 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-06 Fri]</span></span>](#org1b3a9f5)
|
|
4
|
+
- [Version 0.7.0 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-05 Thu]</span></span>](#orgd5760a0)
|
|
3
5
|
|
|
4
6
|
|
|
5
|
-
<a id="
|
|
7
|
+
<a id="orgd39cf28"></a>
|
|
8
|
+
|
|
9
|
+
# Version 0.8.1 <span class="timestamp-wrapper"><span class="timestamp">[2026-11-14 Sat]</span></span>
|
|
10
|
+
|
|
11
|
+
- Fix Windows environment-selected config filenames and classic user paths.
|
|
12
|
+
- Use semicolons for Windows XDG\_CONFIG\_DIRS lists, preserving Unix colons and directory precedence.
|
|
13
|
+
- Support Windows paths under test sandbox root prefixes.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
<a id="orgd2c1c74"></a>
|
|
17
|
+
|
|
18
|
+
# Version 0.8.0
|
|
19
|
+
|
|
20
|
+
- Allow user to specify an explicit user or system config directory, ignoring XDG and classic convention.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<a id="org1b3a9f5"></a>
|
|
6
24
|
|
|
7
25
|
# Version 0.7.1 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-06 Fri]</span></span>
|
|
8
26
|
|
|
9
27
|
- Improved error diagnostics on ParseError
|
|
10
28
|
|
|
11
29
|
|
|
12
|
-
<a id="
|
|
30
|
+
<a id="orgd5760a0"></a>
|
|
13
31
|
|
|
14
32
|
# Version 0.7.0 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-05 Thu]</span></span>
|
|
15
33
|
|
data/CHANGELOG.org
CHANGED
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
user would find useful.
|
|
7
7
|
5. Give each heading a version number and an inactive date (C-c ! is useful here).
|
|
8
8
|
|
|
9
|
+
* Version 0.8.1 [2026-11-14 Sat]
|
|
10
|
+
- Fix Windows environment-selected config filenames and classic user paths.
|
|
11
|
+
- Use semicolons for Windows XDG_CONFIG_DIRS lists, preserving Unix colons
|
|
12
|
+
and directory precedence.
|
|
13
|
+
- Support Windows paths under test sandbox root prefixes.
|
|
14
|
+
|
|
15
|
+
* Version 0.8.0
|
|
16
|
+
- Allow user to specify an explicit user or system config directory, ignoring
|
|
17
|
+
XDG and classic convention.
|
|
18
|
+
|
|
9
19
|
* Version 0.7.1 [2026-02-06 Fri]
|
|
10
20
|
- Improved error diagnostics on ParseError
|
|
11
21
|
|
data/README.md
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
- [
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- [
|
|
7
|
-
- [
|
|
8
|
-
- [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
<!-- Generated by gem_docs -->
|
|
2
|
+
|
|
3
|
+
- [Introduction](#orgcd63dc2)
|
|
4
|
+
- [Installation](#org15c7887)
|
|
5
|
+
- [Usage:](#org56d9f5b)
|
|
6
|
+
- [Following XDG Standards](#org3be69dd)
|
|
7
|
+
- [Following Classic UNIX Standards](#org064ccaf)
|
|
8
|
+
- [Explicitly Providing Config Directories](#orge127d5b)
|
|
9
|
+
- [Windows Paths](#org70b57bc)
|
|
10
|
+
- [Available Config File Styles](#org9c70294)
|
|
11
|
+
- [Hash Keys](#org9f8575c)
|
|
12
|
+
- [Hash Values](#orgdba3006)
|
|
13
|
+
- [YAML](#org07f50e6)
|
|
14
|
+
- [TOML](#org3c19011)
|
|
15
|
+
- [JSON](#orgdc9ffb1)
|
|
16
|
+
- [INI](#orgd9553d5)
|
|
17
|
+
- [Creating a Reader](#orgfd67663)
|
|
18
|
+
- [Calling the `read` method on a `Reader`](#orgd2e0f2e)
|
|
15
19
|
- [Parsing Environment and Command Line Strings](#parsing-environment-and-command-line-strings)
|
|
16
|
-
- [Development](#
|
|
17
|
-
- [Contributing](#
|
|
18
|
-
- [License](#
|
|
20
|
+
- [Development](#org247b85b)
|
|
21
|
+
- [Contributing](#org52f251b)
|
|
22
|
+
- [License](#orgd18d129)
|
|
23
|
+
|
|
24
|
+
Version: 0.8.1
|
|
19
25
|
|
|
20
26
|
[](https://github.com/ddoherty03/fat_config/actions/workflows/main.yml)
|
|
21
27
|
|
|
22
28
|
|
|
23
|
-
<a id="
|
|
29
|
+
<a id="orgcd63dc2"></a>
|
|
24
30
|
|
|
25
31
|
# Introduction
|
|
26
32
|
|
|
@@ -29,7 +35,7 @@ Allowing a user to configure an application to change its behavior at runtime ca
|
|
|
29
35
|
`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
36
|
|
|
31
37
|
|
|
32
|
-
<a id="
|
|
38
|
+
<a id="org15c7887"></a>
|
|
33
39
|
|
|
34
40
|
# Installation
|
|
35
41
|
|
|
@@ -46,7 +52,7 @@ gem install fat_config
|
|
|
46
52
|
```
|
|
47
53
|
|
|
48
54
|
|
|
49
|
-
<a id="
|
|
55
|
+
<a id="org56d9f5b"></a>
|
|
50
56
|
|
|
51
57
|
# Usage:
|
|
52
58
|
|
|
@@ -64,21 +70,21 @@ config = reader.read
|
|
|
64
70
|
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
71
|
|
|
66
72
|
|
|
67
|
-
<a id="
|
|
73
|
+
<a id="org3be69dd"></a>
|
|
68
74
|
|
|
69
75
|
## Following XDG Standards
|
|
70
76
|
|
|
71
77
|
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
78
|
|
|
73
79
|
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
|
|
80
|
+
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 directories separated by `File::PATH_SEPARATOR` (colon on Unix, semicolon on Windows), 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
81
|
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
82
|
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
83
|
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
84
|
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
85
|
|
|
80
86
|
|
|
81
|
-
<a id="
|
|
87
|
+
<a id="org064ccaf"></a>
|
|
82
88
|
|
|
83
89
|
## Following Classic UNIX Standards
|
|
84
90
|
|
|
@@ -101,21 +107,43 @@ With the optional `:xdg` keyword parameter to `FatConfig::Reader#read` set to `f
|
|
|
101
107
|
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
108
|
|
|
103
109
|
|
|
104
|
-
<a id="
|
|
110
|
+
<a id="orge127d5b"></a>
|
|
111
|
+
|
|
112
|
+
## Explicitly Providing Config Directories
|
|
113
|
+
|
|
114
|
+
When the `Reader` is created, the user can give an explicit `user_dir:`, `sys_dir:` parameter or both. If given, the XDG or classic conventions for locating config files are ignored regardless of the setting of the `xdg:` parameter.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
<a id="org70b57bc"></a>
|
|
118
|
+
|
|
119
|
+
## Windows Paths
|
|
120
|
+
|
|
121
|
+
Native Windows Ruby accepts drive-qualified filenames and backslashes for `APPNAME_CONFIG` and `APPNAME_SYS_CONFIG`, as well as explicit `user_dir:` and `sys_dir:` paths. Paths containing spaces need no extra quoting inside the Ruby string or environment variable value. UNC filenames retain their server and share prefix.
|
|
122
|
+
|
|
123
|
+
On Windows, separate `XDG_CONFIG_DIRS` entries with semicolons, for example `C:/Company/config;D:/Shared/config`. The first directory has highest priority. Unix continues to use colons. `XDG_CONFIG_HOME` is always a single directory.
|
|
124
|
+
|
|
125
|
+
Default locations remain `/etc`, `/etc/xdg`, and `~/.config`; FatConfig does not automatically select AppData or ProgramData. Set explicit directories or environment variables when those locations are desired.
|
|
126
|
+
|
|
127
|
+
An empty or nil `root_prefix:` leaves expanded filenames intact. A nonempty prefix is intended for test sandboxes: on Windows, `C:/Users/me/config.yml` maps to `<root_prefix>/Users/me/config.yml`. Drive letters are removed only when applying a sandbox prefix, so different drives share the sandbox root. Explicit `user_dir:` and `sys_dir:` continue to bypass `root_prefix:`.
|
|
128
|
+
|
|
129
|
+
**TOML is currently unsupported on native Windows.** The `tomlib 0.7.3` dependency can crash the Ruby process on malformed TOML, rather than raising a parse error. Use YAML, JSON, or INI on Windows until the dependency is fixed.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
<a id="org9c70294"></a>
|
|
105
133
|
|
|
106
134
|
## Available Config File Styles
|
|
107
135
|
|
|
108
136
|
`FatConfig::Reader.new` takes the optional keyword argument, `:style`, to indicate what style to use for config files. It can be one of:
|
|
109
137
|
|
|
110
138
|
- **`yaml`:** See [YAML Specs](https://yaml.org/spec/1.2.2/),
|
|
111
|
-
- **`toml`:** See [TOML Specs](https://toml.io/en/),
|
|
139
|
+
- **`toml`:** See [TOML Specs](https://toml.io/en/) (currently unsupported on native Windows),
|
|
112
140
|
- **`json`:** See [JSON Specs](https://datatracker.ietf.org/doc/html/rfc8259), or
|
|
113
141
|
- **`ini`:** See [INI File on Wikipedia](https://en.wikipedia.org/wiki/INI_file)
|
|
114
142
|
|
|
115
143
|
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
144
|
|
|
117
145
|
|
|
118
|
-
<a id="
|
|
146
|
+
<a id="org9f8575c"></a>
|
|
119
147
|
|
|
120
148
|
## Hash Keys
|
|
121
149
|
|
|
@@ -124,14 +152,14 @@ Any keys that are Strings will be converted to a symbol, using the names given i
|
|
|
124
152
|
Keys that are not Strings will be left alone, so that, for example, you might have Integer keys, which may be useful below the top level.
|
|
125
153
|
|
|
126
154
|
|
|
127
|
-
<a id="
|
|
155
|
+
<a id="orgdba3006"></a>
|
|
128
156
|
|
|
129
157
|
## Hash Values
|
|
130
158
|
|
|
131
159
|
Whether the values of the returned Hash will be 'deserialized' into a Ruby object is controlled by the style of the configuration files.
|
|
132
160
|
|
|
133
161
|
|
|
134
|
-
<a id="
|
|
162
|
+
<a id="org07f50e6"></a>
|
|
135
163
|
|
|
136
164
|
### YAML
|
|
137
165
|
|
|
@@ -148,7 +176,7 @@ The `:yaml` style deserializes the following types:
|
|
|
148
176
|
- Date, DateTime, and Time, which FatConfig adds to the foregoing default types deserialized by the default YAML library.
|
|
149
177
|
|
|
150
178
|
|
|
151
|
-
<a id="
|
|
179
|
+
<a id="org3c19011"></a>
|
|
152
180
|
|
|
153
181
|
### TOML
|
|
154
182
|
|
|
@@ -156,15 +184,15 @@ The `:toml` style deserializes the following types:
|
|
|
156
184
|
|
|
157
185
|
- TrueClass (exactly the string 'true')
|
|
158
186
|
- FalseClass (exactly the string 'false')
|
|
159
|
-
- Integer (when it looks like an whole number or 0x
|
|
187
|
+
- Integer (when it looks like an whole number or 0x… or 0o… hex or octal)
|
|
160
188
|
- Float (when it looks like an decimal number)
|
|
161
189
|
- String (only if enclosed in single- or double-quotes)
|
|
162
|
-
- Array (when sub-elements enclosed in [
|
|
190
|
+
- Array (when sub-elements enclosed in […], each typed by these rules)
|
|
163
191
|
- Hash, ([hash-key] followed by sub-elements, each typed by these rules) and,
|
|
164
192
|
- Date and Time, when given in ISO form YYYY-MM-DD or YYYY-MM-DDThh:mm:ss
|
|
165
193
|
|
|
166
194
|
|
|
167
|
-
<a id="
|
|
195
|
+
<a id="orgdc9ffb1"></a>
|
|
168
196
|
|
|
169
197
|
### JSON
|
|
170
198
|
|
|
@@ -175,12 +203,12 @@ The `:json` style deserializes the following types:
|
|
|
175
203
|
- Integer (when it looks like an decimal whole number, but NO provision hex or octal)
|
|
176
204
|
- Float (when it looks like an decimal number)
|
|
177
205
|
- String (only if enclosed in single- or double-quotes)
|
|
178
|
-
- Array (when sub-elements enclosed in [
|
|
179
|
-
- Hash, (when sub-elements enclosed in {
|
|
206
|
+
- Array (when sub-elements enclosed in […], each typed by these rules)
|
|
207
|
+
- Hash, (when sub-elements enclosed in {…}, each typed by these rules) and,
|
|
180
208
|
- Date and Time, NOT deserialized, returns a parse error
|
|
181
209
|
|
|
182
210
|
|
|
183
|
-
<a id="
|
|
211
|
+
<a id="orgd9553d5"></a>
|
|
184
212
|
|
|
185
213
|
### INI
|
|
186
214
|
|
|
@@ -188,7 +216,7 @@ The `:ini` style deserializes the following types:
|
|
|
188
216
|
|
|
189
217
|
- TrueClass (exactly the string 'true')
|
|
190
218
|
- FalseClass (exactly the string 'false')
|
|
191
|
-
- Integer (when it looks like an whole number or 0x
|
|
219
|
+
- Integer (when it looks like an whole number or 0x… or 0o… hex or octal)
|
|
192
220
|
- Float (when it looks like an decimal number)
|
|
193
221
|
- String (anything else)
|
|
194
222
|
- Array NOT deserialized, returned as a String
|
|
@@ -196,7 +224,7 @@ The `:ini` style deserializes the following types:
|
|
|
196
224
|
- Date and Time, NOT deserialized, returned as a String
|
|
197
225
|
|
|
198
226
|
|
|
199
|
-
<a id="
|
|
227
|
+
<a id="orgfd67663"></a>
|
|
200
228
|
|
|
201
229
|
## Creating a Reader
|
|
202
230
|
|
|
@@ -205,15 +233,19 @@ When creating a `Reader`, the `#new` method takes a mandatory argument that spec
|
|
|
205
233
|
- `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.
|
|
206
234
|
- `xdg:` either `true`, to follow the XDG standard for where to find config files, or `false`, to follow classic UNIX conventions.
|
|
207
235
|
- `root_prefix:`, to locate the root of the file system somewhere other than `/`. This is probably only useful in testing `FatConfig`.
|
|
236
|
+
- `user_dir:`, to explicitly set the name of the user directory in which to look for the app's config files, thus ignoring the setting of `xdg:` for the user-level settings.
|
|
237
|
+
- `sys_dir:`, to explicitly set the name of the system directory in which to look for the app's config files, thus ignoring the setting of `xdg:` for the system-level settings.
|
|
208
238
|
|
|
209
239
|
```ruby
|
|
210
240
|
reader1 = FatConfig.new('labrat') # Use XDG and YAML
|
|
211
241
|
reader2 = FatConfig.new('labrat', style: 'toml') # Use XDG and TOML
|
|
212
242
|
reader3 = FatConfig.new('labrat', style: 'ini', xdg: false) # Use classic UNIX and INI style
|
|
243
|
+
reader4 = FatConfig.new('labrat', user_dir: '~/labrat') # Look in ~/labrat for user settings
|
|
244
|
+
reader5 = FatConfig.new('labrat', sys_dir: '/etc/labrat') # Look in /etc/labrat for system settings
|
|
213
245
|
```
|
|
214
246
|
|
|
215
247
|
|
|
216
|
-
<a id="
|
|
248
|
+
<a id="orgd2e0f2e"></a>
|
|
217
249
|
|
|
218
250
|
## Calling the `read` method on a `Reader`
|
|
219
251
|
|
|
@@ -276,7 +308,7 @@ Here are the parsing rules:
|
|
|
276
308
|
4. These rules apply regardless of style being used for config files.
|
|
277
309
|
|
|
278
310
|
|
|
279
|
-
<a id="
|
|
311
|
+
<a id="org247b85b"></a>
|
|
280
312
|
|
|
281
313
|
# Development
|
|
282
314
|
|
|
@@ -285,14 +317,14 @@ After checking out the repo, run \`bin/setup\` to install dependencies. Then, ru
|
|
|
285
317
|
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).
|
|
286
318
|
|
|
287
319
|
|
|
288
|
-
<a id="
|
|
320
|
+
<a id="org52f251b"></a>
|
|
289
321
|
|
|
290
322
|
# Contributing
|
|
291
323
|
|
|
292
324
|
Bug reports and pull requests are welcome on GitHub at <https://github.com/ddoherty03/fat_config>.
|
|
293
325
|
|
|
294
326
|
|
|
295
|
-
<a id="
|
|
327
|
+
<a id="orgd18d129"></a>
|
|
296
328
|
|
|
297
329
|
# License
|
|
298
330
|
|
data/README.org
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
#+PROPERTY: header-args:sh :exports code :eval no
|
|
6
6
|
#+PROPERTY: header-args:bash :exports code :eval no
|
|
7
7
|
|
|
8
|
+
# gem_docs:version begin
|
|
9
|
+
Version: 0.8.1
|
|
10
|
+
# gem_docs:version end
|
|
11
|
+
|
|
12
|
+
|
|
8
13
|
[[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
14
|
|
|
10
15
|
* Introduction
|
|
@@ -30,6 +35,8 @@ the files in the proper priority. It can be set to read ~YAML~, ~TOML~,
|
|
|
30
35
|
- [[#usage][Usage:]]
|
|
31
36
|
- [[#following-xdg-standards][Following XDG Standards]]
|
|
32
37
|
- [[#following-classic-unix-standards][Following Classic UNIX Standards]]
|
|
38
|
+
- [[#explicitly-providing-config-directories][Explicitly Providing Config Directories]]
|
|
39
|
+
- [[#windows-paths][Windows Paths]]
|
|
33
40
|
- [[#available-config-file-styles][Available Config File Styles]]
|
|
34
41
|
- [[#hash-keys][Hash Keys]]
|
|
35
42
|
- [[#hash-values][Hash Values]]
|
|
@@ -84,7 +91,8 @@ from the following locations, from lowest priority to highest:
|
|
|
84
91
|
file, it will look in that file for any system-level config file.
|
|
85
92
|
2. If the environment variable ~MYAPP_SYS_CONFIG~ is NOT set, it will read any
|
|
86
93
|
system-level config file from ~/etc/xdg/myapp~ or, if the ~XDG_CONFIG_DIRS~
|
|
87
|
-
environment variable is set to a list of
|
|
94
|
+
environment variable is set to a list of directories separated by ~File::PATH_SEPARATOR~ (colon on Unix,
|
|
95
|
+
semicolon on Windows), it
|
|
88
96
|
will look in each of those instead of ~/etc/xdg~ for config directories
|
|
89
97
|
called ~myapp~. If more than one ~XDG_CONFIG_DIRS~ is given, they are
|
|
90
98
|
treated as listed in order of precedence, so the first-listed directory
|
|
@@ -164,12 +172,42 @@ hypothetical application called ~myapp~:
|
|
|
164
172
|
~Hash~, it is used directly and merged into the hash returned from the
|
|
165
173
|
prior methods.
|
|
166
174
|
|
|
175
|
+
** Explicitly Providing Config Directories
|
|
176
|
+
When the =Reader= is created, the user can give an explicit =user_dir:=,
|
|
177
|
+
=sys_dir:= parameter or both. If given, the XDG or classic conventions for
|
|
178
|
+
locating config files are ignored regardless of the setting of the =xdg:=
|
|
179
|
+
parameter.
|
|
180
|
+
** Windows Paths
|
|
181
|
+
Native Windows Ruby accepts drive-qualified filenames and backslashes for
|
|
182
|
+
~APPNAME_CONFIG~ and ~APPNAME_SYS_CONFIG~, as well as explicit ~user_dir:~ and
|
|
183
|
+
~sys_dir:~ paths. Paths containing spaces need no extra quoting inside the
|
|
184
|
+
Ruby string or environment variable value. UNC filenames retain their server
|
|
185
|
+
and share prefix.
|
|
186
|
+
|
|
187
|
+
On Windows, separate ~XDG_CONFIG_DIRS~ entries with semicolons, for example
|
|
188
|
+
~C:/Company/config;D:/Shared/config~. The first directory has highest priority.
|
|
189
|
+
Unix continues to use colons. ~XDG_CONFIG_HOME~ is always a single directory.
|
|
190
|
+
|
|
191
|
+
Default locations remain ~/etc~, ~/etc/xdg~, and =~/.config=; FatConfig does
|
|
192
|
+
not automatically select AppData or ProgramData. Set explicit directories or
|
|
193
|
+
environment variables when those locations are desired.
|
|
194
|
+
|
|
195
|
+
An empty or nil ~root_prefix:~ leaves expanded filenames intact. A nonempty
|
|
196
|
+
prefix is intended for test sandboxes: on Windows, ~C:/Users/me/config.yml~
|
|
197
|
+
maps to ~<root_prefix>/Users/me/config.yml~. Drive letters are removed only
|
|
198
|
+
when applying a sandbox prefix, so different drives share the sandbox root.
|
|
199
|
+
Explicit ~user_dir:~ and ~sys_dir:~ continue to bypass ~root_prefix:~.
|
|
200
|
+
|
|
201
|
+
*TOML is currently unsupported on native Windows.* The ~tomlib 0.7.3~
|
|
202
|
+
dependency can crash the Ruby process on malformed TOML, rather than raising
|
|
203
|
+
a parse error. Use YAML, JSON, or INI on Windows until the dependency is fixed.
|
|
204
|
+
|
|
167
205
|
** Available Config File Styles
|
|
168
206
|
~FatConfig::Reader.new~ takes the optional keyword argument, ~:style~, to
|
|
169
207
|
indicate what style to use for config files. It can be one of:
|
|
170
208
|
|
|
171
209
|
- ~yaml~ :: See [[https://yaml.org/spec/1.2.2/][YAML Specs]],
|
|
172
|
-
- ~toml~ :: See [[https://toml.io/en/][TOML Specs]],
|
|
210
|
+
- ~toml~ :: See [[https://toml.io/en/][TOML Specs]] (currently unsupported on native Windows),
|
|
173
211
|
- ~json~ :: See [[https://datatracker.ietf.org/doc/html/rfc8259][JSON Specs]], or
|
|
174
212
|
- ~ini~ :: See [[https://en.wikipedia.org/wiki/INI_file][INI File on Wikipedia]]
|
|
175
213
|
|
|
@@ -253,11 +291,19 @@ sought. It also takes a few optional keyword arguments:
|
|
|
253
291
|
files, or ~false~, to follow classic UNIX conventions.
|
|
254
292
|
- ~root_prefix:~, to locate the root of the file system somewhere other than
|
|
255
293
|
~/~. This is probably only useful in testing ~FatConfig~.
|
|
294
|
+
- =user_dir:=, to explicitly set the name of the user directory in which to
|
|
295
|
+
look for the app's config files, thus ignoring the setting of =xdg:= for the
|
|
296
|
+
user-level settings.
|
|
297
|
+
- =sys_dir:=, to explicitly set the name of the system directory in which to
|
|
298
|
+
look for the app's config files, thus ignoring the setting of =xdg:= for the
|
|
299
|
+
system-level settings.
|
|
256
300
|
|
|
257
301
|
#+begin_src ruby :eval no
|
|
258
302
|
reader1 = FatConfig.new('labrat') # Use XDG and YAML
|
|
259
303
|
reader2 = FatConfig.new('labrat', style: 'toml') # Use XDG and TOML
|
|
260
304
|
reader3 = FatConfig.new('labrat', style: 'ini', xdg: false) # Use classic UNIX and INI style
|
|
305
|
+
reader4 = FatConfig.new('labrat', user_dir: '~/labrat') # Look in ~/labrat for user settings
|
|
306
|
+
reader5 = FatConfig.new('labrat', sys_dir: '/etc/labrat') # Look in /etc/labrat for system settings
|
|
261
307
|
#+end_src
|
|
262
308
|
|
|
263
309
|
** Calling the ~read~ method on a ~Reader~
|
data/lib/fat_config/reader.rb
CHANGED
|
@@ -12,8 +12,9 @@ module FatConfig
|
|
|
12
12
|
# - ~xdg~ :: whether follow XDG desktop conventions, by default true; if
|
|
13
13
|
# false, use "classic" UNIX config practices with /etc/ and ~/.baserc.
|
|
14
14
|
# - ~root_prefix~ :: an alternate root of the assumed file system, by
|
|
15
|
-
# default ''. This
|
|
15
|
+
# default ''. This facilitates testing.
|
|
16
16
|
attr_reader :app_name, :style, :root_prefix, :xdg
|
|
17
|
+
attr_reader :user_dir, :sys_dir
|
|
17
18
|
|
|
18
19
|
# Config file may be located in either the xdg locations (containing any
|
|
19
20
|
# variant of base: base, base.yml, or base.yaml) or in the classic
|
|
@@ -38,7 +39,7 @@ module FatConfig
|
|
|
38
39
|
# b. Then, either:
|
|
39
40
|
# A. The file pointed to by the environment variable APPNAME_SYS_CONFIG or
|
|
40
41
|
# B. System classic config files,
|
|
41
|
-
def initialize(app_name, style: :yaml, xdg: true, root_prefix: '')
|
|
42
|
+
def initialize(app_name, style: :yaml, xdg: true, root_prefix: '', user_dir: nil, sys_dir: nil)
|
|
42
43
|
@app_name = app_name.strip.downcase
|
|
43
44
|
raise ArgumentError, "reader app name may not be blank" if @app_name.blank?
|
|
44
45
|
|
|
@@ -63,6 +64,10 @@ module FatConfig
|
|
|
63
64
|
msg = "config style must be one of #{VALID_CONFIG_STYLES.join(', ')}"
|
|
64
65
|
raise ArgumentError, msg
|
|
65
66
|
end
|
|
67
|
+
# Optional override of directories instead of locating them by XDG or
|
|
68
|
+
# classical conventions.
|
|
69
|
+
@user_dir = user_dir
|
|
70
|
+
@sys_dir = sys_dir
|
|
66
71
|
end
|
|
67
72
|
|
|
68
73
|
# Return a Hash of the config files for app_name directories. For
|
|
@@ -102,6 +107,60 @@ module FatConfig
|
|
|
102
107
|
merge_command_line(result, command_line, verbose: verbose)
|
|
103
108
|
end
|
|
104
109
|
|
|
110
|
+
# Return a Hash of Arrays with the outer Hash having the key system:
|
|
111
|
+
# pointing to an Array of system paths and the key :user pointing to an
|
|
112
|
+
# Array of user paths.
|
|
113
|
+
#
|
|
114
|
+
# @param base [String] base name to use for finding config paths
|
|
115
|
+
# @param user_dir [String] optional override of directory with user config files
|
|
116
|
+
# @param sys_dir [String] optional override of directory with system config files
|
|
117
|
+
def config_paths(base = app_name)
|
|
118
|
+
sys_configs = []
|
|
119
|
+
sys_env_name = "#{app_name.upcase}_SYS_CONFIG"
|
|
120
|
+
if sys_dir
|
|
121
|
+
sys_configs = find_config_files_in_dir(base, sys_dir)
|
|
122
|
+
elsif ENV[sys_env_name]
|
|
123
|
+
sys_fname = prefixed_path(File.expand_path(ENV[sys_env_name]))
|
|
124
|
+
sys_configs << sys_fname if File.readable?(sys_fname)
|
|
125
|
+
else
|
|
126
|
+
sys_configs +=
|
|
127
|
+
if xdg
|
|
128
|
+
find_xdg_sys_config_files(base)
|
|
129
|
+
else
|
|
130
|
+
find_classic_sys_config_files(base)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
usr_configs = []
|
|
135
|
+
usr_env_name = "#{app_name.upcase}_CONFIG"
|
|
136
|
+
if user_dir
|
|
137
|
+
usr_configs = find_config_files_in_dir(base, user_dir)
|
|
138
|
+
elsif ENV[usr_env_name]
|
|
139
|
+
usr_fname = prefixed_path(File.expand_path(ENV[usr_env_name]))
|
|
140
|
+
usr_configs << usr_fname if File.readable?(usr_fname)
|
|
141
|
+
else
|
|
142
|
+
usr_configs <<
|
|
143
|
+
if xdg
|
|
144
|
+
find_xdg_user_config_file(base)
|
|
145
|
+
else
|
|
146
|
+
find_classic_user_config_file(base)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
{ system: sys_configs.compact, user: usr_configs.compact }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
# Leave native absolute paths intact unless a sandbox root was requested.
|
|
155
|
+
# A Windows drive cannot appear inside the sandbox path; map its root to
|
|
156
|
+
# root_prefix, just as the Unix filesystem root is mapped there.
|
|
157
|
+
def prefixed_path(path)
|
|
158
|
+
return path if root_prefix.to_s.strip.empty?
|
|
159
|
+
|
|
160
|
+
path = path.sub(/\A[A-Za-z]:/, '') if File::ALT_SEPARATOR
|
|
161
|
+
File.join(root_prefix, path)
|
|
162
|
+
end
|
|
163
|
+
|
|
105
164
|
def merge_environment(start_hash, verbose: false)
|
|
106
165
|
return start_hash if ENV[env_name].blank?
|
|
107
166
|
|
|
@@ -138,35 +197,25 @@ module FatConfig
|
|
|
138
197
|
"#{app_name.upcase}_OPTIONS"
|
|
139
198
|
end
|
|
140
199
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if ENV[sys_env_name]
|
|
145
|
-
sys_fname = File.join(root_prefix, File.expand_path(ENV[sys_env_name]))
|
|
146
|
-
sys_configs << sys_fname if File.readable?(sys_fname)
|
|
147
|
-
else
|
|
148
|
-
sys_configs +=
|
|
149
|
-
if xdg
|
|
150
|
-
find_xdg_sys_config_files(base)
|
|
151
|
-
else
|
|
152
|
-
find_classic_sys_config_files(base)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
200
|
+
########################################################################
|
|
201
|
+
# Explicit config files
|
|
202
|
+
########################################################################
|
|
155
203
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
204
|
+
# Return a list of readable config files with basename base for the
|
|
205
|
+
# current style in directory dir.
|
|
206
|
+
#
|
|
207
|
+
# @param base [String] base name of config file
|
|
208
|
+
# @param dir [String] directory to search for config giles
|
|
209
|
+
def find_config_files_in_dir(base, dir)
|
|
210
|
+
configs = []
|
|
211
|
+
dir = File.expand_path(dir)
|
|
212
|
+
base_candidates = style.dir_constrained_base_names(base)
|
|
213
|
+
base_candidates.each do |f|
|
|
214
|
+
if File.readable?(File.join(dir, f))
|
|
215
|
+
configs << File.join(dir, f)
|
|
216
|
+
end
|
|
168
217
|
end
|
|
169
|
-
|
|
218
|
+
configs
|
|
170
219
|
end
|
|
171
220
|
|
|
172
221
|
########################################################################
|
|
@@ -181,15 +230,15 @@ module FatConfig
|
|
|
181
230
|
# $XDG_CONFIG_DIRS (default: "/etc/xdg"): precedence-ordered set of system configuration directories.
|
|
182
231
|
|
|
183
232
|
# Return the absolute path names of all XDG system config files for
|
|
184
|
-
# app_name with the basename variants of base. Return
|
|
185
|
-
# files first, highest last. Prefix the search
|
|
186
|
-
# if given.
|
|
233
|
+
# app_name in the current style with the basename variants of base. Return
|
|
234
|
+
# the lowest priority files first, highest last. Prefix the search
|
|
235
|
+
# locations with dir_prefix if given.
|
|
187
236
|
def find_xdg_sys_config_files(base = app_name)
|
|
188
237
|
configs = []
|
|
189
|
-
xdg_search_dirs = ENV['XDG_CONFIG_DIRS']&.split(
|
|
238
|
+
xdg_search_dirs = ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR)&.reverse || ['/etc/xdg']
|
|
190
239
|
xdg_search_dirs.each do |dir|
|
|
191
240
|
dir = File.expand_path(File.join(dir, app_name))
|
|
192
|
-
dir =
|
|
241
|
+
dir = prefixed_path(dir)
|
|
193
242
|
base_candidates = style.dir_constrained_base_names(base)
|
|
194
243
|
config_fname = base_candidates.find { |b| File.readable?(File.join(dir, b)) }
|
|
195
244
|
configs << File.join(dir, config_fname) if config_fname
|
|
@@ -198,16 +247,16 @@ module FatConfig
|
|
|
198
247
|
end
|
|
199
248
|
|
|
200
249
|
# Return the absolute path name of any XDG user config files for app_name
|
|
201
|
-
# with the basename variants of base. The
|
|
202
|
-
# variable for the user configs is intended to
|
|
203
|
-
# config directory, not a list of
|
|
204
|
-
# system config. Return the name of
|
|
205
|
-
# XDG_CONFIG_HOME (or ~/.config by default).
|
|
206
|
-
# with dir_prefix if given.
|
|
250
|
+
# in the current style with the basename variants of base. The
|
|
251
|
+
# XDG_CONFIG_HOME environment variable for the user configs is intended to
|
|
252
|
+
# be the name of a single xdg config directory, not a list of
|
|
253
|
+
# path-separated directories as for the system config. Return the name of
|
|
254
|
+
# a config file for this app in XDG_CONFIG_HOME (or ~/.config by default).
|
|
255
|
+
# Prefix the search location with dir_prefix if given.
|
|
207
256
|
def find_xdg_user_config_file(base = app_name)
|
|
208
257
|
xdg_search_dir = ENV['XDG_CONFIG_HOME'] || ['~/.config']
|
|
209
258
|
dir = File.expand_path(File.join(xdg_search_dir, app_name))
|
|
210
|
-
dir =
|
|
259
|
+
dir = prefixed_path(dir)
|
|
211
260
|
return unless Dir.exist?(dir)
|
|
212
261
|
|
|
213
262
|
base_candidates = style.dir_constrained_base_names(base)
|
|
@@ -222,20 +271,20 @@ module FatConfig
|
|
|
222
271
|
########################################################################
|
|
223
272
|
|
|
224
273
|
# Return the absolute path names of all "classic" system config files for
|
|
225
|
-
# app_name with the basename variants of base. Return
|
|
226
|
-
# files first, highest last. Prefix the search
|
|
227
|
-
# if given.
|
|
274
|
+
# app_name in the current style with the basename variants of base. Return
|
|
275
|
+
# the lowest priority files first, highest last. Prefix the search
|
|
276
|
+
# locations with dir_prefix if given.
|
|
228
277
|
def find_classic_sys_config_files(base = app_name)
|
|
229
278
|
configs = []
|
|
230
279
|
env_config = ENV["#{app_name.upcase}_SYS_CONFIG"]
|
|
231
|
-
if env_config && File.readable?(config =
|
|
280
|
+
if env_config && File.readable?(config = prefixed_path(File.expand_path(env_config)))
|
|
232
281
|
configs = [config]
|
|
233
|
-
elsif File.readable?(config =
|
|
282
|
+
elsif File.readable?(config = prefixed_path("/etc/#{base}"))
|
|
234
283
|
configs = [config]
|
|
235
|
-
elsif File.readable?(config =
|
|
284
|
+
elsif File.readable?(config = prefixed_path("/etc/#{base}rc"))
|
|
236
285
|
configs = [config]
|
|
237
286
|
else
|
|
238
|
-
dir =
|
|
287
|
+
dir = prefixed_path("/etc/#{app_name}")
|
|
239
288
|
if Dir.exist?(dir)
|
|
240
289
|
base_candidates = style.classic_base_names(base)
|
|
241
290
|
config = base_candidates.find { |b| File.readable?(File.join(dir, b)) }
|
|
@@ -246,22 +295,22 @@ module FatConfig
|
|
|
246
295
|
end
|
|
247
296
|
|
|
248
297
|
# Return the absolute path names of all "classic" system config files for
|
|
249
|
-
# app_name with the basename variants of base. Return
|
|
250
|
-
# files first, highest last. Prefix the search
|
|
251
|
-
# given.
|
|
298
|
+
# app_name in the current style with the basename variants of base. Return
|
|
299
|
+
# the lowest priority files first, highest last. Prefix the search
|
|
300
|
+
# locations with dir_prefix if given.
|
|
252
301
|
def find_classic_user_config_file(base = app_name)
|
|
253
302
|
env_config = ENV["#{app_name.upcase}_CONFIG"]
|
|
254
|
-
if env_config && File.readable?(config =
|
|
303
|
+
if env_config && File.readable?(config = prefixed_path(File.expand_path(env_config)))
|
|
255
304
|
config
|
|
256
305
|
else
|
|
257
|
-
config_dir =
|
|
306
|
+
config_dir = prefixed_path(File.expand_path("~/"))
|
|
258
307
|
base_candidates = style.dotted_base_names(base)
|
|
259
308
|
base_fname = base_candidates.find do |b|
|
|
260
309
|
File.file?(File.join(config_dir, b)) && File.readable?(File.join(config_dir, b))
|
|
261
310
|
end
|
|
262
311
|
if base_fname
|
|
263
312
|
File.join(config_dir, base_fname)
|
|
264
|
-
elsif Dir.exist?(config_dir =
|
|
313
|
+
elsif Dir.exist?(config_dir = prefixed_path(File.expand_path("~/.#{app_name}")))
|
|
265
314
|
base_candidates = style.dir_constrained_base_names(base)
|
|
266
315
|
base_fname = base_candidates.find { |b| File.readable?(File.join(config_dir, b)) }
|
|
267
316
|
File.join(config_dir, base_fname) if base_fname
|
data/lib/fat_config/version.rb
CHANGED
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.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel E. Doherty
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-11-14 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|