fat_config 0.8.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79f4dfb77fd0ccc161c28ad847a93ce649930294a4d444ce5e9f83ac0b49b761
4
- data.tar.gz: dd9db0f013fdcfb1bb36c84e085b4932d7d6a0a59a53db3b8d6088957701bc12
3
+ metadata.gz: 431c883197a326bde2824b5b605b667adede33fcee328575d3c123e6a051918b
4
+ data.tar.gz: f97f4216cfddebe0d5c4b034b387005916c38e3e61d22b57b67de41001c6d367
5
5
  SHA512:
6
- metadata.gz: 147f0b15e9431d4f3d9009eddecb87070c734d1d49858d18fcaabd2a98815c84cd2cb6c3b7d388f162656346e38d8486af211534b11c019a446d14207419ff2b
7
- data.tar.gz: 7d404f53df4b4e5ae034b62728ec11a4eb155c320f92ccb993fd17d2dfd2721b8bed04e7768ad9f8ef02dc70ca36a15fc06fbc7536dcb2cb1e96ec47afbbacfd
6
+ metadata.gz: 756d931f4a0a11b1d235f406b6c8624bd140ed11045a3aa6eeed85edb425d5139648cffc0866d3e59be6b2b73eeecbd689d641c0765d65b9915b0649672b6149
7
+ data.tar.gz: 7b896e62e452f926038b84c65405d10329edcb48c816a257da14025d11e5890bf54c5f1cd9ee40f211c8396b423335e756ea8305355b2c9a62f31a30f57d2db1
data/CHANGELOG.md CHANGED
@@ -1,15 +1,33 @@
1
- - [Version 0.7.1 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-06 Fri]</span></span>](#org48cabe8)
2
- - [Version 0.7.0 <span class="timestamp-wrapper"><span class="timestamp">[2026-02-05 Thu]</span></span>](#orga2f16a3)
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="org48cabe8"></a>
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="orga2f16a3"></a>
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,12 @@
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
+
9
15
  * Version 0.8.0
10
16
  - Allow user to specify an explicit user or system config directory, ignoring
11
17
  XDG and classic convention.
data/README.md CHANGED
@@ -1,26 +1,32 @@
1
- - [Introduction](#orgc4b482f)
2
- - [Installation](#orgbce0696)
3
- - [Usage:](#org7684da4)
4
- - [Following XDG Standards](#orga8e28a3)
5
- - [Following Classic UNIX Standards](#orgd716a45)
6
- - [Available Config File Styles](#org152041e)
7
- - [Hash Keys](#orgb744014)
8
- - [Hash Values](#org02d5c86)
9
- - [YAML](#org73fadf6)
10
- - [TOML](#orge78f21a)
11
- - [JSON](#org22479cd)
12
- - [INI](#org850bdf4)
13
- - [Creating a Reader](#org570f7c5)
14
- - [Calling the `read` method on a `Reader`](#org9637e7b)
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](#orgda3ea75)
17
- - [Contributing](#orgfb56ba2)
18
- - [License](#org0377369)
20
+ - [Development](#org247b85b)
21
+ - [Contributing](#org52f251b)
22
+ - [License](#orgd18d129)
23
+
24
+ Version: 0.8.1
19
25
 
20
26
  [![img](https://github.com/ddoherty03/fat_config/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/ddoherty03/fat_config/actions/workflows/main.yml)
21
27
 
22
28
 
23
- <a id="orgc4b482f"></a>
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="orgbce0696"></a>
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="org7684da4"></a>
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="orga8e28a3"></a>
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 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.
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="orgd716a45"></a>
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="org152041e"></a>
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="orgb744014"></a>
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="org02d5c86"></a>
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="org73fadf6"></a>
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="orge78f21a"></a>
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&#x2026; or 0o&#x2026; hex or octal)
187
+ - Integer (when it looks like an whole number or 0x&hellip; or 0o&hellip; 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 [&#x2026;], each typed by these rules)
190
+ - Array (when sub-elements enclosed in [&hellip;], 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="org22479cd"></a>
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 [&#x2026;], each typed by these rules)
179
- - Hash, (when sub-elements enclosed in {&#x2026;}, each typed by these rules) and,
206
+ - Array (when sub-elements enclosed in [&hellip;], each typed by these rules)
207
+ - Hash, (when sub-elements enclosed in {&hellip;}, each typed by these rules) and,
180
208
  - Date and Time, NOT deserialized, returns a parse error
181
209
 
182
210
 
183
- <a id="org850bdf4"></a>
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&#x2026; or 0o&#x2026; hex or octal)
219
+ - Integer (when it looks like an whole number or 0x&hellip; or 0o&hellip; 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="org570f7c5"></a>
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="org9637e7b"></a>
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="orgda3ea75"></a>
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="orgfb56ba2"></a>
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="org0377369"></a>
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
@@ -31,6 +36,7 @@ the files in the proper priority. It can be set to read ~YAML~, ~TOML~,
31
36
  - [[#following-xdg-standards][Following XDG Standards]]
32
37
  - [[#following-classic-unix-standards][Following Classic UNIX Standards]]
33
38
  - [[#explicitly-providing-config-directories][Explicitly Providing Config Directories]]
39
+ - [[#windows-paths][Windows Paths]]
34
40
  - [[#available-config-file-styles][Available Config File Styles]]
35
41
  - [[#hash-keys][Hash Keys]]
36
42
  - [[#hash-values][Hash Values]]
@@ -85,7 +91,8 @@ from the following locations, from lowest priority to highest:
85
91
  file, it will look in that file for any system-level config file.
86
92
  2. If the environment variable ~MYAPP_SYS_CONFIG~ is NOT set, it will read any
87
93
  system-level config file from ~/etc/xdg/myapp~ or, if the ~XDG_CONFIG_DIRS~
88
- environment variable is set to a list of colon-separated directories, it
94
+ environment variable is set to a list of directories separated by ~File::PATH_SEPARATOR~ (colon on Unix,
95
+ semicolon on Windows), it
89
96
  will look in each of those instead of ~/etc/xdg~ for config directories
90
97
  called ~myapp~. If more than one ~XDG_CONFIG_DIRS~ is given, they are
91
98
  treated as listed in order of precedence, so the first-listed directory
@@ -170,12 +177,37 @@ hypothetical application called ~myapp~:
170
177
  =sys_dir:= parameter or both. If given, the XDG or classic conventions for
171
178
  locating config files are ignored regardless of the setting of the =xdg:=
172
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
+
173
205
  ** Available Config File Styles
174
206
  ~FatConfig::Reader.new~ takes the optional keyword argument, ~:style~, to
175
207
  indicate what style to use for config files. It can be one of:
176
208
 
177
209
  - ~yaml~ :: See [[https://yaml.org/spec/1.2.2/][YAML Specs]],
178
- - ~toml~ :: See [[https://toml.io/en/][TOML Specs]],
210
+ - ~toml~ :: See [[https://toml.io/en/][TOML Specs]] (currently unsupported on native Windows),
179
211
  - ~json~ :: See [[https://datatracker.ietf.org/doc/html/rfc8259][JSON Specs]], or
180
212
  - ~ini~ :: See [[https://en.wikipedia.org/wiki/INI_file][INI File on Wikipedia]]
181
213
 
@@ -120,7 +120,7 @@ module FatConfig
120
120
  if sys_dir
121
121
  sys_configs = find_config_files_in_dir(base, sys_dir)
122
122
  elsif ENV[sys_env_name]
123
- sys_fname = File.join(root_prefix, File.expand_path(ENV[sys_env_name]))
123
+ sys_fname = prefixed_path(File.expand_path(ENV[sys_env_name]))
124
124
  sys_configs << sys_fname if File.readable?(sys_fname)
125
125
  else
126
126
  sys_configs +=
@@ -136,7 +136,7 @@ module FatConfig
136
136
  if user_dir
137
137
  usr_configs = find_config_files_in_dir(base, user_dir)
138
138
  elsif ENV[usr_env_name]
139
- usr_fname = File.join(root_prefix, File.expand_path(ENV[usr_env_name]))
139
+ usr_fname = prefixed_path(File.expand_path(ENV[usr_env_name]))
140
140
  usr_configs << usr_fname if File.readable?(usr_fname)
141
141
  else
142
142
  usr_configs <<
@@ -151,6 +151,16 @@ module FatConfig
151
151
 
152
152
  private
153
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
+
154
164
  def merge_environment(start_hash, verbose: false)
155
165
  return start_hash if ENV[env_name].blank?
156
166
 
@@ -225,10 +235,10 @@ module FatConfig
225
235
  # locations with dir_prefix if given.
226
236
  def find_xdg_sys_config_files(base = app_name)
227
237
  configs = []
228
- xdg_search_dirs = ENV['XDG_CONFIG_DIRS']&.split(':')&.reverse || ['/etc/xdg']
238
+ xdg_search_dirs = ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR)&.reverse || ['/etc/xdg']
229
239
  xdg_search_dirs.each do |dir|
230
240
  dir = File.expand_path(File.join(dir, app_name))
231
- dir = File.join(root_prefix, dir) unless root_prefix.nil? || root_prefix.strip.empty?
241
+ dir = prefixed_path(dir)
232
242
  base_candidates = style.dir_constrained_base_names(base)
233
243
  config_fname = base_candidates.find { |b| File.readable?(File.join(dir, b)) }
234
244
  configs << File.join(dir, config_fname) if config_fname
@@ -240,13 +250,13 @@ module FatConfig
240
250
  # in the current style with the basename variants of base. The
241
251
  # XDG_CONFIG_HOME environment variable for the user configs is intended to
242
252
  # be the name of a single xdg config directory, not a list of
243
- # colon-separated directories as for the system config. Return the name of
253
+ # path-separated directories as for the system config. Return the name of
244
254
  # a config file for this app in XDG_CONFIG_HOME (or ~/.config by default).
245
255
  # Prefix the search location with dir_prefix if given.
246
256
  def find_xdg_user_config_file(base = app_name)
247
257
  xdg_search_dir = ENV['XDG_CONFIG_HOME'] || ['~/.config']
248
258
  dir = File.expand_path(File.join(xdg_search_dir, app_name))
249
- dir = File.join(root_prefix, dir) unless root_prefix.to_s.strip.empty?
259
+ dir = prefixed_path(dir)
250
260
  return unless Dir.exist?(dir)
251
261
 
252
262
  base_candidates = style.dir_constrained_base_names(base)
@@ -267,14 +277,14 @@ module FatConfig
267
277
  def find_classic_sys_config_files(base = app_name)
268
278
  configs = []
269
279
  env_config = ENV["#{app_name.upcase}_SYS_CONFIG"]
270
- if env_config && File.readable?(config = File.join(root_prefix, File.expand_path(env_config)))
280
+ if env_config && File.readable?(config = prefixed_path(File.expand_path(env_config)))
271
281
  configs = [config]
272
- elsif File.readable?(config = File.join(root_prefix, "/etc/#{base}"))
282
+ elsif File.readable?(config = prefixed_path("/etc/#{base}"))
273
283
  configs = [config]
274
- elsif File.readable?(config = File.join(root_prefix, "/etc/#{base}rc"))
284
+ elsif File.readable?(config = prefixed_path("/etc/#{base}rc"))
275
285
  configs = [config]
276
286
  else
277
- dir = File.join(root_prefix, "/etc/#{app_name}")
287
+ dir = prefixed_path("/etc/#{app_name}")
278
288
  if Dir.exist?(dir)
279
289
  base_candidates = style.classic_base_names(base)
280
290
  config = base_candidates.find { |b| File.readable?(File.join(dir, b)) }
@@ -290,17 +300,17 @@ module FatConfig
290
300
  # locations with dir_prefix if given.
291
301
  def find_classic_user_config_file(base = app_name)
292
302
  env_config = ENV["#{app_name.upcase}_CONFIG"]
293
- if env_config && File.readable?(config = File.join(root_prefix, File.expand_path(env_config)))
303
+ if env_config && File.readable?(config = prefixed_path(File.expand_path(env_config)))
294
304
  config
295
305
  else
296
- config_dir = File.join(root_prefix, File.expand_path("~/"))
306
+ config_dir = prefixed_path(File.expand_path("~/"))
297
307
  base_candidates = style.dotted_base_names(base)
298
308
  base_fname = base_candidates.find do |b|
299
309
  File.file?(File.join(config_dir, b)) && File.readable?(File.join(config_dir, b))
300
310
  end
301
311
  if base_fname
302
312
  File.join(config_dir, base_fname)
303
- elsif Dir.exist?(config_dir = File.join(root_prefix, File.expand_path("~/.#{app_name}")))
313
+ elsif Dir.exist?(config_dir = prefixed_path(File.expand_path("~/.#{app_name}")))
304
314
  base_candidates = style.dir_constrained_base_names(base)
305
315
  base_fname = base_candidates.find { |b| File.readable?(File.join(config_dir, b)) }
306
316
  File.join(config_dir, base_fname) if base_fname
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FatConfig
4
- VERSION = "0.8.0"
4
+ VERSION = "0.8.1"
5
5
  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.8.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: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-11-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  requirements: []
128
- rubygems_version: 4.0.0
128
+ rubygems_version: 3.6.2
129
129
  specification_version: 4
130
130
  summary: Library to read config from standard XDG or classic locations.
131
131
  test_files: []