xqsr3 0.39.10 → 0.39.11
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/CHANGES.md +22 -0
- data/EXAMPLES.md +4 -5
- data/FAQ.md +0 -3
- data/NEWS.md +1 -0
- data/README.md +24 -20
- data/TODO.md +17 -7
- data/docs/components/README.md +61 -0
- data/docs/components/array-utilities.md +120 -0
- data/docs/components/command-line-utilities.md +151 -0
- data/docs/components/containers.md +143 -0
- data/docs/components/conversion.md +166 -0
- data/docs/components/diagnostics.md +210 -0
- data/docs/components/extensions.md +232 -0
- data/docs/components/hash-utilities.md +192 -0
- data/docs/components/io.md +188 -0
- data/docs/components/quality.md +251 -0
- data/docs/components/string-utilities.md +218 -0
- data/docs/guides/README.md +23 -0
- data/docs/guides/choosing-a-component.md +183 -0
- data/docs/guides/formatting-and-writing-output.md +182 -0
- data/docs/guides/getting-started.md +181 -0
- data/docs/guides/handling-failures.md +157 -0
- data/docs/guides/parsing-and-validating-input.md +262 -0
- data/docs/guides/processing-collections.md +195 -0
- data/docs/reference/README.md +38 -0
- data/examples/count_word_frequencies.md +3 -2
- data/lib/xqsr3/array_utilities/join_with_or.rb +3 -2
- data/lib/xqsr3/command_line_utilities/map_option_string.rb +3 -2
- data/lib/xqsr3/containers/frequency_map.rb +53 -53
- data/lib/xqsr3/containers/multi_map.rb +5 -4
- data/lib/xqsr3/conversion/bool_parser.rb +5 -4
- data/lib/xqsr3/conversion/integer_parser.rb +4 -4
- data/lib/xqsr3/diagnostics/exception_utilities.rb +7 -4
- data/lib/xqsr3/diagnostics/exceptions/with_cause.rb +24 -16
- data/lib/xqsr3/diagnostics/inspect_builder.rb +2 -2
- data/lib/xqsr3/doc_.rb +20 -5
- data/lib/xqsr3/extensions/hash/slice.rb +2 -0
- data/lib/xqsr3/extensions/integer/to_s_grp.rb +3 -2
- data/lib/xqsr3/extensions/string/map_option_string.rb +2 -0
- data/lib/xqsr3/hash_utilities/key_matching.rb +3 -3
- data/lib/xqsr3/quality/parameter_checking.rb +17 -16
- data/lib/xqsr3/string_utilities/ends_with.rb +3 -3
- data/lib/xqsr3/string_utilities/nil_if_empty.rb +3 -3
- data/lib/xqsr3/string_utilities/nil_if_whitespace.rb +3 -3
- data/lib/xqsr3/string_utilities/quote_if.rb +3 -2
- data/lib/xqsr3/string_utilities/starts_with.rb +3 -3
- data/lib/xqsr3/version.rb +2 -2
- metadata +21 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7be376b875d05077dcd53dc79b7a85d79f23931761ba1c765b9015f4b29a06d2
|
|
4
|
+
data.tar.gz: 7e78f40749a6a290600acf1d2695b8e45634be651dfa752fb23423d227283e6f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02ca2e98c607a51edbccb38082527fc2c9d800e6c5f632d8826296f16e114682c02b83bdf6ba5be747eaf444694a90efdeaa7cf96580d39fa1e7097148fb167a
|
|
7
|
+
data.tar.gz: f8500bc1f235ea1ef60de441641edb9b371563cb58102d923d0b482725a427cd0c115bf6366a5718e070e81fe0d52c3da827f98951c5f138413d932cc00987b8
|
data/CHANGES.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# xqsr3 - Changes <!-- omit in toc -->
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 0.39.11 - 29th August 2026
|
|
5
|
+
|
|
6
|
+
* Added a user-oriented component catalogue under **docs/components/**, covering standalone components, extensions, loading paths, API summaries, and representative usage;
|
|
7
|
+
* Added task-oriented guides under **docs/guides/** for getting started, component selection, input parsing and validation, collection processing, failure handling, and output formatting;
|
|
8
|
+
* Normalised legacy Markdown inline-code, checklist, table, and heading markup in **README.md**, **EXAMPLES.md**, **FAQ.md**, **TODO.md**, and the example guide;
|
|
9
|
+
* Added **docs/reference/README.md** describing the generated RDoc reference, and updated the Unix and Windows RDoc helpers to exclude authored **docs/** and **examples/** content from generated output;
|
|
10
|
+
* Included authored **docs/** content in the gem package while continuing to exclude generated **doc/** output;
|
|
11
|
+
* Set the generated RDoc title to the **xqsr3** API reference, and excluded project boilerplate pages from the reference;
|
|
12
|
+
* Expanded source-level RDoc documentation and visibility annotations for the public API, including **FrequencyMap**, **BoolParser**, **ExceptionUtilities**, **WithCause**, **ParameterChecking**, and extension classes;
|
|
13
|
+
* Replaced a remaining placeholder example and legacy RDoc markup in public API comments;
|
|
14
|
+
* Extended **README.md** with linked component categories and navigation to the component catalogue and user guides;
|
|
15
|
+
* Added a GitHub Actions Documentation job to **.github/workflows/ruby.yml** that generates an RDoc coverage report under Ruby 3.4, and aligned its push branch triggers with the canonical set;
|
|
16
|
+
* Added Ruby 4.0 to the GitHub Actions test matrix across the supported operating systems;
|
|
17
|
+
* Made the RDoc coverage check fail when a documentable API entity is undocumented;
|
|
18
|
+
* Added `--help` support to the Unix and Windows RDoc helpers, using project metadata from **.sis/**;
|
|
19
|
+
* Made the Unix and Windows RDoc helpers runnable from any working directory, with `--pwd` selecting the caller's directory and `SIS_RDOC_DOC_DIR` controlling the generated-document directory;
|
|
20
|
+
* Added documentation follow-up items to **TODO.md**;
|
|
21
|
+
* Removed the **.vscode/** ignore rule from **.gitignore**;
|
|
22
|
+
* Refreshed `Updated:` fields and copyright date ranges in modified library sources;
|
|
23
|
+
* Bumped the library version to 0.39.11 and recorded the release in **NEWS.md**;
|
|
24
|
+
|
|
25
|
+
|
|
4
26
|
## 0.39.10 - 28th August 2026
|
|
5
27
|
|
|
6
28
|
* **Gemfile.lock** is no longer tracked in the repository, completing the **0.39.9** lockfile work (`lockfile false` in **Gemfile**, **.gitignore** entry, and `spec.files` exclusion in **xqsr3.gemspec**);
|
data/EXAMPLES.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# xqsr3 - Examples <!-- omit in toc -->
|
|
2
2
|
|
|
3
|
-
|Name|Source & Description|Summary|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
| Name | Source & Description | Summary |
|
|
4
|
+
| -------------------------- | -------------------- | ------- |
|
|
5
|
+
| **count_word_frequencies** | [examples/count_word_frequencies.rb](./examples/count_word_frequencies.rb)<br/>[examples/count_word_frequencies.md](./examples/count_word_frequencies.md) | Simple example supporting `--help` and `--version` |
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
<!-- ########################### end of file ########################### -->
|
|
9
|
-
|
|
8
|
+
<!-- ########################### end of file ########################### -->
|
data/FAQ.md
CHANGED
data/NEWS.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Date | News Item |
|
|
4
4
|
| ------------------- | ------------------------------------------------------------------------------------ |
|
|
5
|
+
| 29th August 2026 | [**xqsr3** 0.39.11](https://github.com/synesissoftware/xqsr3/releases/tag/0.39.11) |
|
|
5
6
|
| 28th August 2026 | [**xqsr3** 0.39.10](https://github.com/synesissoftware/xqsr3/releases/tag/0.39.10) |
|
|
6
7
|
| 21st August 2026 | [**xqsr3** 0.39.9](https://github.com/synesissoftware/xqsr3/releases/tag/0.39.9) |
|
|
7
8
|
| 20th August 2026 | [**xqsr3** 0.39.8](https://github.com/synesissoftware/xqsr3/releases/tag/0.39.8) |
|
data/README.md
CHANGED
|
@@ -49,13 +49,13 @@ gem install xqsr3
|
|
|
49
49
|
or add it to your `Gemfile`.
|
|
50
50
|
|
|
51
51
|
Use is via specific APIs or groups. For example, in order to use the
|
|
52
|
-
|
|
52
|
+
`FrequencyMap` class you would `require` the source file, as in:
|
|
53
53
|
|
|
54
54
|
```Ruby
|
|
55
55
|
require 'xqsr3/containers/frequency_map'
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
Alternatively, to use
|
|
58
|
+
Alternatively, to use _all_ **test/unit** extensions you would `require` all
|
|
59
59
|
relative via the file:
|
|
60
60
|
|
|
61
61
|
```Ruby
|
|
@@ -69,34 +69,38 @@ which brings in nine extensions.
|
|
|
69
69
|
|
|
70
70
|
**xqsr3** provides components in the following categories:
|
|
71
71
|
|
|
72
|
-
* Array Utilities
|
|
73
|
-
* Command-line Utilities
|
|
74
|
-
* Containers
|
|
75
|
-
* Conversion
|
|
76
|
-
* Diagnostics
|
|
77
|
-
* Hash Utilities
|
|
78
|
-
* IO
|
|
79
|
-
* Quality
|
|
80
|
-
* String Utilities
|
|
72
|
+
* [Array Utilities](./docs/components/array-utilities.md);
|
|
73
|
+
* [Command-line Utilities](./docs/components/command-line-utilities.md);
|
|
74
|
+
* [Containers](./docs/components/containers.md);
|
|
75
|
+
* [Conversion](./docs/components/conversion.md);
|
|
76
|
+
* [Diagnostics](./docs/components/diagnostics.md);
|
|
77
|
+
* [Hash Utilities](./docs/components/hash-utilities.md);
|
|
78
|
+
* [IO](./docs/components/io.md);
|
|
79
|
+
* [Quality](./docs/components/quality.md);
|
|
80
|
+
* [String Utilities](./docs/components/string-utilities.md);
|
|
81
81
|
* ~~XML Utilities~~ **NOTE**: The **XML** components formerly in **xqsr3** in
|
|
82
82
|
versions **0.29**-**0.30** are now contained in the separate project
|
|
83
83
|
[**xqsr3-xml**](https://github.com/synesissoftware/xqsr3-xml/).
|
|
84
84
|
|
|
85
85
|
and extensions to the following standard library components:
|
|
86
86
|
|
|
87
|
-
* Array extensions
|
|
88
|
-
* Enumerable extensions
|
|
89
|
-
* Hash extensions
|
|
90
|
-
* Integer extensions
|
|
91
|
-
* IO extensions
|
|
92
|
-
* Kernel extensions
|
|
93
|
-
* String extensions
|
|
94
|
-
* test/unit extensions
|
|
87
|
+
* [Array extensions](./docs/components/extensions.md#array-extensions);
|
|
88
|
+
* [Enumerable extensions](./docs/components/extensions.md#enumerable-extensions);
|
|
89
|
+
* [Hash extensions](./docs/components/extensions.md#hash-extensions);
|
|
90
|
+
* [Integer extensions](./docs/components/extensions.md#integer-extensions);
|
|
91
|
+
* [IO extensions](./docs/components/extensions.md#io-extensions);
|
|
92
|
+
* [Kernel extensions](./docs/components/extensions.md#kernel-extensions);
|
|
93
|
+
* [String extensions](./docs/components/extensions.md#string-extensions);
|
|
94
|
+
* [test/unit extensions](./docs/components/extensions.md#testunit-extensions);
|
|
95
|
+
|
|
96
|
+
The complete [component catalogue](./docs/components/README.md) provides
|
|
97
|
+
loading instructions and initial API summaries. The task-oriented guides are
|
|
98
|
+
available under [docs/guides/](./docs/guides/README.md).
|
|
95
99
|
|
|
96
100
|
|
|
97
101
|
## Examples
|
|
98
102
|
|
|
99
|
-
Examples are provided in the
|
|
103
|
+
Examples are provided in the `examples` directory, along with a markdown description for each. A detailed list TOC of them is provided in [EXAMPLES.md](./EXAMPLES.md).
|
|
100
104
|
|
|
101
105
|
|
|
102
106
|
## Project Information
|
data/TODO.md
CHANGED
|
@@ -3,8 +3,18 @@
|
|
|
3
3
|
|
|
4
4
|
## Functional improvements
|
|
5
5
|
|
|
6
|
-
* [x] ~~~prepare `IO.writelines` (and related helpers) for frozen-string-literal defaults (Ruby 3.4+ warnings under `-W`)
|
|
7
|
-
* [x] ~~~quiet Ruby 3.4 `test-unit` warnings for blocks passed to `assert_nil` / `assert_not_nil` in **test/unit/quality/tc_parameter_checking.rb
|
|
6
|
+
* [x] ~~~prepare `IO.writelines` (and related helpers) for frozen-string-literal defaults (Ruby 3.4+ warnings under `-W`)~~~ - ✅;
|
|
7
|
+
* [x] ~~~quiet Ruby 3.4 `test-unit` warnings for blocks passed to `assert_nil` / `assert_not_nil` in **test/unit/quality/tc_parameter_checking.rb**~~~ - ✅;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Documentation
|
|
11
|
+
|
|
12
|
+
* [x] ~~~curated component catalogue under **docs/components/**~~~ - ✅;
|
|
13
|
+
* [x] ~~~task-oriented user guide under **docs/guides/**~~~ - ✅;
|
|
14
|
+
* [ ] Additional example programs covering the public component categories;
|
|
15
|
+
* [x] ~~~Expanded generated API reference~~~ - ✅;
|
|
16
|
+
* [ ] Executable cookbook and recipe documentation;
|
|
17
|
+
* [ ] Static documentation website with search and versioned references;
|
|
8
18
|
|
|
9
19
|
|
|
10
20
|
## Performance improvements
|
|
@@ -14,11 +24,11 @@
|
|
|
14
24
|
|
|
15
25
|
## Packaging improvements
|
|
16
26
|
|
|
17
|
-
* [
|
|
18
|
-
* [x] ~~~remove **Gemfile.lock
|
|
19
|
-
* [x] ~~~obtain a **run_all_unit_tests.sh** (from **misc-dev-scripts**) that skips `tput` when `$TERM` is unset or stdout is not a TTY (CI: `tput: No value for $TERM and no -T specified`)
|
|
20
|
-
* [x] ~~~after the packaging/boilerplate/CI baseline release: bump **VERSION**, drop gemspec `required_ruby_version` `< 4` upper bound, and align **CHANGES
|
|
21
|
-
* [x] ~~~gemspec polish: `https` homepage, Rubygems `metadata` URIs, stop using `Date.today`, include **CHANGES.md** in packaged files
|
|
27
|
+
* [x] ~~~**README.md** and **docs/*.md** introductory elements of main features~~~ - ✅;
|
|
28
|
+
* [x] ~~~remove **Gemfile.lock**~~~ - ✅;
|
|
29
|
+
* [x] ~~~obtain a **run_all_unit_tests.sh** (from **misc-dev-scripts**) that skips `tput` when `$TERM` is unset or stdout is not a TTY (CI: `tput: No value for $TERM and no -T specified`)~~~ - ✅;
|
|
30
|
+
* [x] ~~~after the packaging/boilerplate/CI baseline release: bump **VERSION**, drop gemspec `required_ruby_version` `< 4` upper bound, and align **CHANGES**~~~ - ✅;
|
|
31
|
+
* [x] ~~~gemspec polish: `https` homepage, Rubygems `metadata` URIs, stop using `Date.today`, include **CHANGES.md** in packaged files~~~ - ✅;
|
|
22
32
|
|
|
23
33
|
|
|
24
34
|
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# xqsr3 Component Catalogue <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
This catalogue is the user-oriented guide to the components provided by
|
|
4
|
+
**xqsr3**. It is organised by component category rather than by Ruby source
|
|
5
|
+
file.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Table of Contents <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
- [Using the catalogue](#using-the-catalogue)
|
|
11
|
+
- [Categories](#categories)
|
|
12
|
+
- [Related workflows](#related-workflows)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Using the catalogue
|
|
16
|
+
|
|
17
|
+
Components are loaded explicitly. Each category page documents the relevant
|
|
18
|
+
`require` path, public entry points, and representative usage.
|
|
19
|
+
|
|
20
|
+
The catalogue documents the supported public surface. Internal files and
|
|
21
|
+
implementation details are intentionally excluded.
|
|
22
|
+
|
|
23
|
+
The ten category pages correspond to the public top-level component entry
|
|
24
|
+
points under `lib/xqsr3/`. The `Extensions` page additionally covers the
|
|
25
|
+
opt-in monkey patches, while `all_extensions.rb` is documented as its
|
|
26
|
+
broad-scope loading choice.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Categories
|
|
30
|
+
|
|
31
|
+
* [Array Utilities](./array-utilities.md);
|
|
32
|
+
* [Command-line Utilities](./command-line-utilities.md);
|
|
33
|
+
* [Containers](./containers.md);
|
|
34
|
+
* [Conversion](./conversion.md);
|
|
35
|
+
* [Diagnostics](./diagnostics.md);
|
|
36
|
+
* [Extensions](./extensions.md);
|
|
37
|
+
* [Hash Utilities](./hash-utilities.md);
|
|
38
|
+
* [IO](./io.md);
|
|
39
|
+
* [Quality](./quality.md);
|
|
40
|
+
* [String Utilities](./string-utilities.md);
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Related workflows
|
|
44
|
+
|
|
45
|
+
Use the catalogue alongside the task-oriented guides:
|
|
46
|
+
|
|
47
|
+
* [Choosing a Component](../guides/choosing-a-component.md) explains how to
|
|
48
|
+
select a category and loading scope;
|
|
49
|
+
* [Getting Started](../guides/getting-started.md) demonstrates a minimal
|
|
50
|
+
application workflow;
|
|
51
|
+
* [Parsing and Validating External Input](../guides/parsing-and-validating-input.md)
|
|
52
|
+
combines string, conversion, and quality components;
|
|
53
|
+
* [Processing Collections](../guides/processing-collections.md) combines
|
|
54
|
+
containers, hash utilities, and extensions;
|
|
55
|
+
* [Handling Failures](../guides/handling-failures.md) combines quality and
|
|
56
|
+
diagnostics components;
|
|
57
|
+
* [Formatting and Writing Output](../guides/formatting-and-writing-output.md)
|
|
58
|
+
combines array, IO, and string utilities.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# xqsr3 Array Utilities <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
Array utilities provide standalone operations for working with Ruby arrays.
|
|
4
|
+
The current component is a formatter for presenting alternatives in
|
|
5
|
+
human-readable text.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Table of Contents <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
- [Loading](#loading)
|
|
11
|
+
- [When to use it](#when-to-use-it)
|
|
12
|
+
- [JoinWithOr](#joinwithor)
|
|
13
|
+
- [Formatting options](#formatting-options)
|
|
14
|
+
- [Standalone and extension forms](#standalone-and-extension-forms)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Loading
|
|
18
|
+
|
|
19
|
+
```Ruby
|
|
20
|
+
require 'xqsr3/array_utilities'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or load the component directly:
|
|
24
|
+
|
|
25
|
+
```Ruby
|
|
26
|
+
require 'xqsr3/array_utilities/join_with_or'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The standalone module is
|
|
30
|
+
`Xqsr3::ArrayUtilities::JoinWithOr`.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## When to use it
|
|
34
|
+
|
|
35
|
+
Use `join_with_or` for messages that describe alternatives, such as accepted
|
|
36
|
+
formats, permitted values, or choices presented to a user. It is not a
|
|
37
|
+
general-purpose serialization method: it adds grammatical spacing and an
|
|
38
|
+
optional Oxford comma.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## `JoinWithOr`
|
|
42
|
+
|
|
43
|
+
`Xqsr3::ArrayUtilities::JoinWithOr.join_with_or` formats values using these
|
|
44
|
+
cardinality rules:
|
|
45
|
+
|
|
46
|
+
* `nil` and an empty array produce `''`;
|
|
47
|
+
* one value produces that value;
|
|
48
|
+
* two values are joined with `or` and no comma;
|
|
49
|
+
* three or more values use commas and, by default, an Oxford comma before
|
|
50
|
+
`or`.
|
|
51
|
+
|
|
52
|
+
```Ruby
|
|
53
|
+
require 'xqsr3/array_utilities/join_with_or'
|
|
54
|
+
|
|
55
|
+
formatter = Xqsr3::ArrayUtilities::JoinWithOr
|
|
56
|
+
|
|
57
|
+
formatter.join_with_or([])
|
|
58
|
+
# => ''
|
|
59
|
+
formatter.join_with_or(['red'])
|
|
60
|
+
# => 'red'
|
|
61
|
+
formatter.join_with_or(['red', 'green'])
|
|
62
|
+
# => 'red or green'
|
|
63
|
+
formatter.join_with_or(['red', 'green', 'blue'])
|
|
64
|
+
# => 'red, green, or blue'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Values are interpolated into the result, so they do not need to be strings.
|
|
68
|
+
The array argument itself must be an `Array` or `nil`; another type raises
|
|
69
|
+
`TypeError`.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Formatting options
|
|
73
|
+
|
|
74
|
+
The `or` word, separator, Oxford-comma policy, and quote character are
|
|
75
|
+
independent options:
|
|
76
|
+
|
|
77
|
+
```Ruby
|
|
78
|
+
formatter.join_with_or(
|
|
79
|
+
['red', 'green', 'blue'],
|
|
80
|
+
or: 'OR',
|
|
81
|
+
separator: ';',
|
|
82
|
+
oxford_comma: false,
|
|
83
|
+
quote_char: '"',
|
|
84
|
+
)
|
|
85
|
+
# => '"red"; "green" OR "blue"'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The options are:
|
|
89
|
+
|
|
90
|
+
* `or` replaces the default word `or`;
|
|
91
|
+
* `separator` replaces the default comma between items;
|
|
92
|
+
* `oxford_comma: false` removes the separator before `or` for lists of three
|
|
93
|
+
or more values;
|
|
94
|
+
* `quote_char` surrounds every value with the supplied character.
|
|
95
|
+
|
|
96
|
+
The Oxford-comma option has no effect for zero, one, or two values. A
|
|
97
|
+
`quote_char` is applied literally to both sides and does not escape quote
|
|
98
|
+
characters already present in a value.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Standalone and extension forms
|
|
102
|
+
|
|
103
|
+
The extension form adds `Array#join_with_or`:
|
|
104
|
+
|
|
105
|
+
```Ruby
|
|
106
|
+
require 'xqsr3/extensions/array/join_with_or'
|
|
107
|
+
|
|
108
|
+
['red', 'green', 'blue'].join_with_or
|
|
109
|
+
# => 'red, green, or blue'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The extension delegates to the standalone implementation. Use the standalone
|
|
113
|
+
form in reusable libraries that want to avoid modifying `Array`; use the
|
|
114
|
+
extension form when method syntax improves the surrounding application code.
|
|
115
|
+
|
|
116
|
+
For executable behavioural examples, see
|
|
117
|
+
`test/unit/array_utilities/tc_join_with_or.rb`.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# xqsr3 Command-line Utilities <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
Command-line utilities support compact mapping from user-facing option text
|
|
4
|
+
to stable Ruby symbols. The component is particularly useful when a command
|
|
5
|
+
line accepts both long option names and declared single-letter shortcuts.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Table of Contents <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
- [Loading](#loading)
|
|
11
|
+
- [When to use it](#when-to-use-it)
|
|
12
|
+
- [MapOptionString](#mapoptionstring)
|
|
13
|
+
- [Option-string grammar](#option-string-grammar)
|
|
14
|
+
- [Standalone and extension forms](#standalone-and-extension-forms)
|
|
15
|
+
- [Failure and matching behaviour](#failure-and-matching-behaviour)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Loading
|
|
19
|
+
|
|
20
|
+
Load the command-line utility category:
|
|
21
|
+
|
|
22
|
+
```Ruby
|
|
23
|
+
require 'xqsr3/command_line_utilities'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or load the component directly:
|
|
27
|
+
|
|
28
|
+
```Ruby
|
|
29
|
+
require 'xqsr3/command_line_utilities/map_option_string'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The module is defined as
|
|
33
|
+
`Xqsr3::CommandLineUtilities::MapOptionString`.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## When to use it
|
|
37
|
+
|
|
38
|
+
Use `MapOptionString` when the application has a fixed set of option
|
|
39
|
+
spellings and wants the result to be a symbol suitable for dispatch:
|
|
40
|
+
|
|
41
|
+
```Ruby
|
|
42
|
+
options = ['help', 'version', 'verbose']
|
|
43
|
+
option = 'verbose'
|
|
44
|
+
|
|
45
|
+
Xqsr3::CommandLineUtilities::MapOptionString
|
|
46
|
+
.map_option_string_from_string(option, options)
|
|
47
|
+
# => :verbose
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
It is not a complete command-line parser. It does not consume `ARGV`, parse
|
|
51
|
+
option arguments, or validate an option's value.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## `MapOptionString`
|
|
55
|
+
|
|
56
|
+
`map_option_string_from_string(string, option_strings)` returns the symbol
|
|
57
|
+
corresponding to the first matching declared option. A declared option
|
|
58
|
+
without shortcut syntax maps to itself:
|
|
59
|
+
|
|
60
|
+
```Ruby
|
|
61
|
+
require 'xqsr3/command_line_utilities/map_option_string'
|
|
62
|
+
|
|
63
|
+
mapper = Xqsr3::CommandLineUtilities::MapOptionString
|
|
64
|
+
declared = ['help', 'version', 'dry-run']
|
|
65
|
+
|
|
66
|
+
mapper.map_option_string_from_string('help', declared)
|
|
67
|
+
# => :help
|
|
68
|
+
mapper.map_option_string_from_string('dry-run', declared)
|
|
69
|
+
# => :dry_run
|
|
70
|
+
mapper.map_option_string_from_string('unknown', declared)
|
|
71
|
+
# => nil
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The canonical option text is converted to a symbol using the String Utilities
|
|
75
|
+
symbol rules. Consequently, hyphens become underscores in the returned
|
|
76
|
+
symbol.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Option-string grammar
|
|
80
|
+
|
|
81
|
+
Place each shortcut character in square brackets within its long spelling:
|
|
82
|
+
|
|
83
|
+
```Ruby
|
|
84
|
+
declared = ['[h]elp', '[v]ersion', '[d]ry-[r]un']
|
|
85
|
+
|
|
86
|
+
mapper.map_option_string_from_string('h', declared)
|
|
87
|
+
# => :help
|
|
88
|
+
mapper.map_option_string_from_string('help', declared)
|
|
89
|
+
# => :help
|
|
90
|
+
mapper.map_option_string_from_string('dr', declared)
|
|
91
|
+
# => :dry_run
|
|
92
|
+
mapper.map_option_string_from_string('dry-run', declared)
|
|
93
|
+
# => :dry_run
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Every bracketed character contributes to the shortcut. Thus `[d]ry-[r]un`
|
|
97
|
+
declares `dr`; the unbracketed long form remains `dry-run`. Text between
|
|
98
|
+
brackets is retained in the long spelling and removed from the shortcut.
|
|
99
|
+
|
|
100
|
+
Shortcut matching is exact. Partial long names and individual unbracketed
|
|
101
|
+
characters do not match:
|
|
102
|
+
|
|
103
|
+
```Ruby
|
|
104
|
+
mapper.map_option_string_from_string('d', declared)
|
|
105
|
+
# => nil
|
|
106
|
+
mapper.map_option_string_from_string('dry', declared)
|
|
107
|
+
# => nil
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## Standalone and extension forms
|
|
112
|
+
|
|
113
|
+
The standalone form is useful when the caller wants explicit dependencies:
|
|
114
|
+
|
|
115
|
+
```Ruby
|
|
116
|
+
Xqsr3::CommandLineUtilities::MapOptionString
|
|
117
|
+
.map_option_string_from_string('v', ['[v]ersion'])
|
|
118
|
+
# => :version
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The extension form adds `String#map_option_string`:
|
|
122
|
+
|
|
123
|
+
```Ruby
|
|
124
|
+
require 'xqsr3/extensions/string/map_option_string'
|
|
125
|
+
|
|
126
|
+
'v'.map_option_string(['[v]ersion'])
|
|
127
|
+
# => :version
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The extension also defines `NilClass#map_option_string`, which returns `nil`.
|
|
131
|
+
Other receiver types must respond to `to_str`.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## Failure and matching behaviour
|
|
135
|
+
|
|
136
|
+
An unmatched input returns `nil`; no exception is raised for an ordinary
|
|
137
|
+
non-match. Matching is performed in declaration order, so duplicate or
|
|
138
|
+
overlapping declarations should be avoided.
|
|
139
|
+
|
|
140
|
+
The canonical option string is converted to a symbol only after a match.
|
|
141
|
+
Names containing characters that the symbol converter rejects can therefore
|
|
142
|
+
produce `nil` even though the option text matched.
|
|
143
|
+
|
|
144
|
+
The optional `options` argument is accepted for interface compatibility but
|
|
145
|
+
does not currently alter the mapping rules.
|
|
146
|
+
|
|
147
|
+
For executable behavioural examples, see
|
|
148
|
+
`test/unit/command_line_utilities/tc_map_option_string.rb`.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# xqsr3 Containers <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
The container components provide focused collection types for common
|
|
4
|
+
counting and key-to-multiple-value use cases.
|
|
5
|
+
|
|
6
|
+
Use `FrequencyMap` when each key has one numeric count. Use `MultiMap` when
|
|
7
|
+
each key has an ordered collection of values. Both preserve the distinction
|
|
8
|
+
between the number of keys and the number of associated items.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Table of Contents <!-- omit in toc -->
|
|
12
|
+
|
|
13
|
+
- [Loading](#loading)
|
|
14
|
+
- [Choosing a container](#choosing-a-container)
|
|
15
|
+
- [FrequencyMap](#frequencymap)
|
|
16
|
+
- [MultiMap](#multimap)
|
|
17
|
+
- [Shared conventions](#shared-conventions)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Loading
|
|
21
|
+
|
|
22
|
+
Load both containers through the category entry point:
|
|
23
|
+
|
|
24
|
+
```Ruby
|
|
25
|
+
require 'xqsr3/containers'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or load only the component required by the application:
|
|
29
|
+
|
|
30
|
+
```Ruby
|
|
31
|
+
require 'xqsr3/containers/frequency_map'
|
|
32
|
+
require 'xqsr3/containers/multi_map'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The classes are defined in `Xqsr3::Containers`.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Choosing a container
|
|
39
|
+
|
|
40
|
+
* Choose `FrequencyMap` for histograms, frequency tables, and tallying;
|
|
41
|
+
* Choose `MultiMap` for one-to-many relationships and grouped values;
|
|
42
|
+
* Choose a regular `Hash` when neither counting nor one-to-many behaviour is
|
|
43
|
+
required.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## `FrequencyMap`
|
|
47
|
+
|
|
48
|
+
`Xqsr3::Containers::FrequencyMap` maps each element to a numeric count. It
|
|
49
|
+
includes `Enumerable`, and its `count` method returns the total number of
|
|
50
|
+
observations, while `size` returns the number of distinct elements.
|
|
51
|
+
|
|
52
|
+
```Ruby
|
|
53
|
+
require 'xqsr3/containers/frequency_map'
|
|
54
|
+
|
|
55
|
+
frequencies = Xqsr3::Containers::FrequencyMap::ByElement[
|
|
56
|
+
'ruby', 'ruby', 'crystal', 'ruby',
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
frequencies['ruby'] # => 3
|
|
60
|
+
frequencies['crystal'] # => 1
|
|
61
|
+
frequencies['python'] # => 0
|
|
62
|
+
frequencies.size # => 2
|
|
63
|
+
frequencies.count # => 4
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`ByElement[...]` is the convenient constructor when starting with a sequence
|
|
67
|
+
of observations. `FrequencyMap[...]` also accepts a `Hash`, an array of
|
|
68
|
+
`[key, count]` pairs, or an even-length key/count array.
|
|
69
|
+
|
|
70
|
+
The primary mutation methods are:
|
|
71
|
+
|
|
72
|
+
* `push(key, count = 1)` adds to the existing count and removes the key when
|
|
73
|
+
the resulting count is zero;
|
|
74
|
+
* `store(key, count)` replaces the existing count and removes the key when
|
|
75
|
+
`count` is zero;
|
|
76
|
+
* `<< key` records one observation;
|
|
77
|
+
* `delete(key)` removes the key and its contribution to the total;
|
|
78
|
+
* `merge` and `merge!` combine counts for duplicate keys.
|
|
79
|
+
|
|
80
|
+
Counts must be integers. A push that would make an individual count negative
|
|
81
|
+
raises `RangeError`; invalid count values raise `TypeError`.
|
|
82
|
+
|
|
83
|
+
Useful queries include `each`, `each_by_key`, `each_by_frequency`, `fetch`,
|
|
84
|
+
`has_key?`, `has_value?`, `key`, `keys`, `values`, `to_a`, and `to_h`.
|
|
85
|
+
Indexing an absent key returns zero, whereas `fetch` can return a supplied
|
|
86
|
+
default, invoke a block, or raise `KeyError`.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## `MultiMap`
|
|
90
|
+
|
|
91
|
+
`Xqsr3::Containers::MultiMap` maps each key to an array of values. It includes
|
|
92
|
+
`Enumerable`, and its `size` is the number of keys while `count` is the total
|
|
93
|
+
number of stored values.
|
|
94
|
+
|
|
95
|
+
```Ruby
|
|
96
|
+
require 'xqsr3/containers/multi_map'
|
|
97
|
+
|
|
98
|
+
groups = Xqsr3::Containers::MultiMap.new
|
|
99
|
+
groups.push :ruby, 'MRI', 'JRuby'
|
|
100
|
+
groups.push :ruby, 'TruffleRuby'
|
|
101
|
+
groups.push :python, 'CPython'
|
|
102
|
+
|
|
103
|
+
groups[:ruby] # => ['MRI', 'JRuby', 'TruffleRuby']
|
|
104
|
+
groups[:python] # => ['CPython']
|
|
105
|
+
groups.size # => 2
|
|
106
|
+
groups.count # => 4
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Pushing a key with no values still creates the key and associates it with an
|
|
110
|
+
empty array. Indexing an absent key returns `nil`, which differs from an
|
|
111
|
+
existing key whose value array is empty.
|
|
112
|
+
|
|
113
|
+
The primary mutation methods are:
|
|
114
|
+
|
|
115
|
+
* `push(key, *values)` appends values to the key's existing array;
|
|
116
|
+
* `store(key, *values)` replaces the key's value array;
|
|
117
|
+
* `delete(key)` removes all values mapped to the key;
|
|
118
|
+
* `multi_merge` and `multi_merge!` concatenate values for duplicate keys;
|
|
119
|
+
* `strict_merge` and `strict_merge!` replace values for duplicate keys.
|
|
120
|
+
|
|
121
|
+
`MultiMap[...]` accepts a `Hash` whose values are arrays, an array of
|
|
122
|
+
`[key, value, ...]` entries, or multiple such entries. `each` yields one
|
|
123
|
+
`[key, value]` pair for every stored value. Use `each_unflattened` when the
|
|
124
|
+
value array must be yielded as a whole.
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
## Shared conventions
|
|
128
|
+
|
|
129
|
+
Both containers provide `assoc`, `clear`, `delete`, `each_key`, `fetch`,
|
|
130
|
+
`flatten`, `has_key?`, `keys`, `length`, `shift`, `size`, `to_a`, `to_hash`,
|
|
131
|
+
and `values`-style operations. Both support `dup`, equality comparison with
|
|
132
|
+
their corresponding `Hash` representation, and enumerator-returning methods
|
|
133
|
+
when no block is supplied.
|
|
134
|
+
|
|
135
|
+
The containers retain insertion order through their underlying Ruby hashes.
|
|
136
|
+
Methods explicitly described as sorted—`FrequencyMap#each_by_key` and
|
|
137
|
+
`FrequencyMap#each_by_frequency`—perform ordering work at enumeration time.
|
|
138
|
+
|
|
139
|
+
For executable behavioural examples, see the unit tests in
|
|
140
|
+
`test/unit/containers/`.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
<!-- ########################### end of file ########################### -->
|