random_name_generator 4.0.3 → 4.0.5

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.
@@ -0,0 +1,82 @@
1
+ ---
2
+ type: Ruby Class
3
+ title: RandomNameGenerator::Generator
4
+ description: Reads a syllable file into three buckets and assembles a name by walking prefix → middles → suffix.
5
+ resource: https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator.rb
6
+ tags: [ruby, api, core]
7
+ timestamp: 2026-07-26T00:00:00Z
8
+ ---
9
+
10
+ The workhorse class. One `Generator` wraps one language file; `compose` may be
11
+ called repeatedly on the same instance.
12
+
13
+ # Construction
14
+
15
+ ```ruby
16
+ Generator.new(language = RandomNameGenerator::FANTASY, random: Random.new)
17
+ ```
18
+
19
+ `initialize` calls the private `refresh`, which reads every non-blank line of
20
+ the language `File`, turns it into a [Syllable](/library/syllable.md), and
21
+ pushes it into `@pre_syllables`, `@sur_syllables`, or `@mid_syllables`
22
+ according to `prefix?`/`suffix?`. It then rewinds the file handle — necessary
23
+ because the language constants are shared open `File` objects
24
+ (see [the module](/library/module.md)).
25
+
26
+ Blank lines are skipped, so a syllable file may be visually grouped by bucket.
27
+
28
+ # Composition algorithm
29
+
30
+ `compose_array(count)` returns an array of `Syllable`; `compose(count)` maps it
31
+ to strings, joins, and `capitalize`s the result.
32
+
33
+ 1. Sample a prefix from `pre_syllables`.
34
+ 2. If `count < 2`, return just that prefix — a one-syllable name.
35
+ 3. Append `count - 2` middles, each chosen from the candidates in
36
+ `mid_syllables` compatible with the syllable before it.
37
+ 4. Append one suffix from `sur_syllables`, compatible with the last middle.
38
+
39
+ So a name is always *prefix + (count-2) middles + suffix*, and a two-syllable
40
+ name is prefix + suffix with no middle at all. `count` defaults to
41
+ `RandomNameGenerator.pick_number_of_syllables`.
42
+
43
+ Note that `compose` capitalizes the joined string, which in Ruby also
44
+ **downcases the remainder** — and `Syllable` already downcases its input, so
45
+ generated names are always `Titlecase`.
46
+
47
+ # Failure mode
48
+
49
+ `determine_next_syllable` raises `ArgumentError` when no candidate in the
50
+ bucket is compatible with the current syllable:
51
+
52
+ ```
53
+ No syllable in <path> is compatible with "<syllable>" — check its +v/+c/-v/-c flags
54
+ ```
55
+
56
+ This is the practical hazard when authoring a language: over-constrained
57
+ adjacency flags, or a bucket too small to satisfy them. `spec/languages/test-incompatible.txt`
58
+ is the fixture that pins this behavior. See
59
+ [the syllable file format](/formats/syllable-file-format.md).
60
+
61
+ # Public surface
62
+
63
+ | Member | Notes |
64
+ |--------|-------|
65
+ | `#compose(count = …)` | Capitalized `String`. |
66
+ | `#compose_array(count = …)` | `Array<Syllable>`. |
67
+ | `#language` | The `File` it was built from. |
68
+ | `#pre_syllables` / `#mid_syllables` / `#sur_syllables` | The parsed buckets — useful in specs to assert a file loaded as intended. |
69
+ | `#to_s` | `"RandomNameGenerator::Generator (goblin.txt)"` — basename only. |
70
+
71
+ # Examples
72
+
73
+ ```ruby
74
+ # Deterministic: seed the injected Random, and pass an explicit count so the
75
+ # count itself is not drawn from global randomness.
76
+ rng = RandomNameGenerator::Generator.new(RandomNameGenerator::ELVEN, random: Random.new(42))
77
+ rng.compose(3)
78
+ ```
79
+
80
+ # Citations
81
+
82
+ [1] [lib/random_name_generator.rb](https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator.rb)
@@ -0,0 +1,7 @@
1
+ # Library
2
+
3
+ The Ruby API, from the outside in.
4
+
5
+ * [RandomNameGenerator (module)](module.md) - top-level facade: language constants, factory methods, and the syllable-count distribution.
6
+ * [RandomNameGenerator::Generator](generator.md) - reads a syllable file into three buckets and assembles a name by walking prefix → middles → suffix.
7
+ * [RandomNameGenerator::Syllable](syllable.md) - parses one line of a language file into a syllable plus its position and adjacency rules.
@@ -0,0 +1,69 @@
1
+ ---
2
+ type: Ruby Module
3
+ title: RandomNameGenerator (module)
4
+ description: Top-level facade — holds one File constant per language, factory methods, and the syllable-count distribution.
5
+ resource: https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator.rb
6
+ tags: [ruby, api, entrypoint]
7
+ timestamp: 2026-07-26T00:00:00Z
8
+ ---
9
+
10
+ `RandomNameGenerator` is a module, not a class. It exists to (a) name every
11
+ bundled syllable file as a constant, and (b) act as a static factory for
12
+ [Generator](/library/generator.md), which does the actual work.
13
+
14
+ # Language constants
15
+
16
+ Each language is an **open `File` object** created at load time from
17
+ `lib/languages/`, not a path string:
18
+
19
+ ```ruby
20
+ GOBLIN = File.new("#{dirname}/languages/goblin.txt")
21
+ ```
22
+
23
+ That has two consequences worth knowing: the file handles are opened when the
24
+ module is required, and `Generator#refresh` must `rewind` the handle after
25
+ reading so a second `Generator` on the same constant still sees content. See
26
+ the [language catalog](/languages/catalog.md) for the full list.
27
+
28
+ # API
29
+
30
+ | Method | Purpose |
31
+ |--------|---------|
32
+ | `RandomNameGenerator.new(language = FANTASY, random: Random.new)` | Static factory returning a `Generator`. Not a constructor — the module has no instances. |
33
+ | `RandomNameGenerator.flip_mode` | `Generator` over a random pick of `FANTASY`, `ELVEN`, `GOBLIN`, `ROMAN`. |
34
+ | `RandomNameGenerator.flip_mode_cyrillic` | Same, over the four `*_RU` constants. |
35
+ | `RandomNameGenerator.pick_number_of_syllables(random: Random.new)` | Samples the default syllable count. |
36
+
37
+ `flip_mode` and `flip_mode_cyrillic` take no `random:` keyword — they use
38
+ `Array#sample` with global randomness for the language pick, so they are not
39
+ seedable. Only `.new` and `pick_number_of_syllables` accept an injected
40
+ `Random`; see [injected randomness](/decisions/injected-randomness.md).
41
+
42
+ # Syllable-count distribution
43
+
44
+ `pick_number_of_syllables` samples from a literal weighted array rather than
45
+ computing a distribution:
46
+
47
+ ```ruby
48
+ [2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5]
49
+ ```
50
+
51
+ That is 4/18 twos, 10/18 threes, 3/18 fours, 1/18 fives — three-syllable names
52
+ are the common case by design.
53
+
54
+ # Examples
55
+
56
+ ```ruby
57
+ require "random_name_generator"
58
+
59
+ rng = RandomNameGenerator.new(RandomNameGenerator::GOBLIN)
60
+ puts rng.compose(3)
61
+
62
+ flip = RandomNameGenerator.flip_mode
63
+ puts flip.compose
64
+ ```
65
+
66
+ # Citations
67
+
68
+ [1] [lib/random_name_generator.rb](https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator.rb)
69
+ [2] [README — Usage](https://github.com/folkengine/random_name_generator/blob/main/README.md)
@@ -0,0 +1,83 @@
1
+ ---
2
+ type: Ruby Class
3
+ title: RandomNameGenerator::Syllable
4
+ description: Parses one line of a language file into a syllable plus its position and adjacency rules, and answers compatibility questions.
5
+ resource: https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator/syllable.rb
6
+ tags: [ruby, api, parsing]
7
+ timestamp: 2026-07-26T00:00:00Z
8
+ ---
9
+
10
+ `Syllable` absorbs all the parsing complexity of the
11
+ [syllable file format](/formats/syllable-file-format.md) so that
12
+ [Generator](/library/generator.md) only has to sample from arrays and ask
13
+ `compatible?`. It is not meant to be called directly in normal use.
14
+
15
+ Extracting this class is the main structural departure from the Java original
16
+ the gem was ported from.
17
+
18
+ # Parsing
19
+
20
+ `Syllable.new(args)` accepts a `String` line, or another `Syllable` (which
21
+ clones it via `#raw`). The line is stripped, **downcased**, and split on
22
+ whitespace:
23
+
24
+ - token 0 is the syllable, matched against `/([+-]?)(.+)/` — a leading `-`
25
+ sets `prefix?`, a leading `+` sets `suffix?`, anything else is a middle;
26
+ - remaining tokens are flags, order-independent.
27
+
28
+ An empty syllable raises `ArgumentError, "Empty String is not allowed."`.
29
+ Note that flags are matched by exact token, so an unrecognized flag is
30
+ silently ignored rather than rejected.
31
+
32
+ # Compatibility
33
+
34
+ Two independent rules decide whether syllable B may follow syllable A —
35
+ `A.compatible?(B)` is false if either fails:
36
+
37
+ | Rule | Source | Meaning |
38
+ |------|--------|---------|
39
+ | next | `A`'s `+v` / `+c` | B must *start* with a vowel / consonant. |
40
+ | previous | `B`'s `-v` / `-c` | A must *end* with a vowel / consonant. |
41
+
42
+ Both requirements default to `:letter` (unconstrained). Within each pair the
43
+ parse is `if/elsif`, so a line carrying both `+v` and `+c` keeps only `+v`,
44
+ and one carrying both `-v` and `-c` keeps only `-v`.
45
+
46
+ # Character classes
47
+
48
+ `VOWELS` and `CONSONANTS` are frozen arrays of single-character strings
49
+ covering Latin, extended IPA-ish, and Cyrillic letters — this is what lets the
50
+ Cyrillic language files work with the same engine. Membership is tested on
51
+ `syllable[0]` and `syllable[-1]`.
52
+
53
+ `y` is deliberately in **both** sets: as a semivowel it satisfies either a
54
+ `+v` or a `+c` requirement. A character in *neither* set (a digit, an
55
+ apostrophe) makes both `vowel_last?` and
56
+ `consonant_last?` false, which means it can never violate a `-v`/`-c`
57
+ requirement — such a syllable is universally acceptable as a predecessor.
58
+
59
+ # Public surface
60
+
61
+ | Member | Notes |
62
+ |--------|-------|
63
+ | `#compatible?(next)` / `#incompatible?(next)` | The pair used by `Generator`. |
64
+ | `#prefix?` / `#suffix?` | Bucket assignment. |
65
+ | `#vowel_first?` / `#consonant_first?` / `#vowel_last?` / `#consonant_last?` | Class membership of the first/last character. |
66
+ | `#next_syllable_universal?`, `#next_syllable_must_start_with_vowel?`, `#next_syllable_must_start_with_consonant?` | Reads of `next_syllable_requirement`. |
67
+ | `#previous_syllable_universal?`, `#previous_syllable_must_end_with_vowel?`, `#previous_syllable_must_end_with_consonant?` | Reads of `previous_syllable_requirement`. |
68
+ | `#raw` | The original stripped line — including sigil and flags. |
69
+ | `#to_s` / `#to_str` | The bare syllable text; `to_str` makes it implicitly coercible in string ops. |
70
+
71
+ # Examples
72
+
73
+ ```ruby
74
+ s = RandomNameGenerator::Syllable.new("-foo +c")
75
+ s.prefix? # => true
76
+ s.to_s # => "foo"
77
+ s.raw # => "-foo +c"
78
+ s.next_syllable_must_start_with_consonant? # => true
79
+ ```
80
+
81
+ # Citations
82
+
83
+ [1] [lib/random_name_generator/syllable.rb](https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator/syllable.rb) — the class doc there is the authoritative statement of the rules.
data/.okf/log.md ADDED
@@ -0,0 +1,9 @@
1
+ # Update Log
2
+
3
+ ## 2026-07-26
4
+ * **Initialization**: Scaffolded the bundle with `okf_init.py` and replaced the placeholder concept with a real [overview](/overview.md).
5
+ * **Creation**: Documented the Ruby API — [module](/library/module.md), [Generator](/library/generator.md), [Syllable](/library/syllable.md).
6
+ * **Creation**: Captured the [syllable file format](/formats/syllable-file-format.md), the [language catalog](/languages/catalog.md) (14 files, bucket sizes as of gem 4.0.4), and [adding a language](/languages/adding-a-language.md).
7
+ * **Creation**: Documented the [CLI](/interfaces/cli.md), including flag precedence, Cyrillic fall-through, and the missing Welsh flag.
8
+ * **Creation**: Established development playbooks — [build and test](/development/build-and-test.md), [conventions](/development/conventions.md), [release](/development/release.md).
9
+ * **Creation**: Recorded three decisions — [injected randomness](/decisions/injected-randomness.md), [slop as a runtime dependency](/decisions/slop-runtime-dependency.md), [the Ruby 3.4 floor](/decisions/ruby-3-4-minimum.md).
data/.okf/overview.md ADDED
@@ -0,0 +1,59 @@
1
+ ---
2
+ type: Project
3
+ title: random_name_generator
4
+ description: Ruby gem that composes names from per-language syllable files, shipping a library API and a CLI.
5
+ resource: https://github.com/folkengine/random_name_generator
6
+ tags: [ruby, gem, overview]
7
+ timestamp: 2026-07-26T00:00:00Z
8
+ ---
9
+
10
+ A Ruby gem (3.4+) that builds names — Elven, Goblin, Roman, Klingon, Belter,
11
+ Welsh, and more — by assembling syllables drawn from plain-text language files.
12
+ It is a port of
13
+ [java-random-name-generator](https://github.com/folkengine/java-random-name-generator),
14
+ which descends from Sinipull's GPL'd post on codecall.net. Published as
15
+ [random_name_generator](https://rubygems.org/gems/random_name_generator) under
16
+ LGPL-3.0.
17
+
18
+ # Shape
19
+
20
+ ```
21
+ lib/languages/*.txt the domain data — syllables + adjacency flags
22
+ lib/random_name_generator/syllable.rb parses one line
23
+ lib/random_name_generator.rb constants, factories, Generator
24
+ exe/random_name_generator slop-based CLI
25
+ ```
26
+
27
+ The whole system is one idea: a **syllable file** is a list of prefixes,
28
+ middles, and suffixes, each optionally constrained by what may precede or
29
+ follow it. Everything else reads that file and samples from it.
30
+
31
+ | Layer | Concept |
32
+ |-------|---------|
33
+ | Data format | [Syllable file format](/formats/syllable-file-format.md) |
34
+ | Parsing | [Syllable](/library/syllable.md) |
35
+ | Composition | [Generator](/library/generator.md) |
36
+ | Public API | [RandomNameGenerator module](/library/module.md) |
37
+ | Command line | [CLI](/interfaces/cli.md) |
38
+ | The data itself | [Language catalog](/languages/catalog.md) |
39
+
40
+ # Properties
41
+
42
+ - **Pure**: file in, string out. No network, no threads, no global mutable
43
+ state beyond the shared `File` constants.
44
+ - **Seedable**: randomness is injected, not global — see
45
+ [that decision](/decisions/injected-randomness.md).
46
+ - **Extensible by data**: adding a language means adding a text file and
47
+ wiring it up, not changing the algorithm. See
48
+ [adding a language](/languages/adding-a-language.md).
49
+
50
+ # Working here
51
+
52
+ `bundle exec rake` is the gate (spec then rubocop) —
53
+ see [build and test](/development/build-and-test.md) and
54
+ [conventions](/development/conventions.md).
55
+
56
+ # Citations
57
+
58
+ [1] [README.md](https://github.com/folkengine/random_name_generator/blob/main/README.md)
59
+ [2] [RandomNameGeneratorHub](https://github.com/folkengine/RandomNameGeneratorHub) — ports in other languages.
data/AI-BOM.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AI Bill of Materials — random_name_generator
2
2
 
3
- _Last updated: 2026-07-19 · random_name_generator v4.0.2_
3
+ _Last updated: 2026-07-26 · random_name_generator v4.0.5_
4
4
 
5
5
  An inventory of every AI component associated with this repository — development
6
6
  tools used to build it, AI-generated content shipped within it, and external AI
@@ -20,6 +20,7 @@ to provenance.
20
20
  | Tool | Vendor | Role | Notes |
21
21
  |------|--------|------|-------|
22
22
  | Claude Code | Anthropic | AI coding assistant | Introduced in 4.0.0; drives the [`lang-gen`](./.claude/skills/lang-gen/SKILL.md) skill and general maintenance |
23
+ | `okf` skill | — | Knowledge-bundle authoring | External Claude Code skill; authored and maintains the [`.okf/`](./.okf/index.md) bundle. Not vendored in this repo |
23
24
 
24
25
  ---
25
26
 
@@ -43,6 +44,9 @@ All output was human-reviewed before commit.
43
44
  | [`lang-gen`](./.claude/skills/lang-gen/SKILL.md) | Claude Code skill | — | Generates a fully integrated language from a plain-English theme |
44
45
  | [German Curse](./lib/languages/experimental/german-curse.txt) (`GERMAN_CURSE`) | Language syllable file | `lang-gen` | Experimental; seeded from real roots, extended with invented syllables |
45
46
  | [Demonic](./lib/languages/experimental/demonic.txt) (`DEMONIC`) | Language syllable file | `lang-gen` | Experimental; completed from infernal-name source lists |
47
+ | [Welsh](./lib/languages/welsh.txt) (`WELSH`) | Language syllable file | `lang-gen` | Added in 4.0.4; seeded from real Welsh name roots |
48
+ | [Belter](./lib/languages/belter.txt) (`BELTER`) | Language syllable file | `lang-gen` | Added in 4.0.4; Belter creole (The Expanse), an invented language |
49
+ | [`.okf/`](./.okf/index.md) | Knowledge bundle | `okf` skill | Added in 4.0.5; 14 OKF concept files across 6 areas — the API, syllable format, CLI, and decisions |
46
50
  | [Portable lang-gen prompt](./docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md) | Text prompt | — | LLM-agnostic version of the skill |
47
51
 
48
52
  ---
@@ -81,5 +85,6 @@ no network calls and requires no API keys. None are planned.
81
85
  |----------|---------|
82
86
  | [`docs/AUDIT_Fable_5.md`](./docs/AUDIT_Fable_5.md) | Full-codebase audit with empirically verified findings |
83
87
  | [`.claude/skills/lang-gen/SKILL.md`](./.claude/skills/lang-gen/SKILL.md) | The lang-gen language-generation skill |
88
+ | [`.okf/index.md`](./.okf/index.md) | AI-authored knowledge bundle; [`.okf/log.md`](./.okf/log.md) is its change log |
84
89
  | [`README.md`](./README.md) | Project overview, including the lang-gen workflow |
85
90
  | [`docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md`](./docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md) | Paste-into-any-LLM version of the prompt |
data/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  ## Version 4
2
2
 
3
+ ## 4.0.5 - unreleased
4
+
5
+ - Added an [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
6
+ knowledge bundle in `.okf/` — 14 concept files across 6 areas covering the
7
+ Ruby API, the syllable file format, the language catalog, the CLI, the
8
+ development playbooks, and three recorded decisions.
9
+ - Expanded `CLAUDE.md` with the project's architecture, conventions, and the
10
+ rules for consulting and maintaining the knowledge bundle.
11
+ - Documented the bundle in `README.md`.
12
+
13
+ ## 4.0.4 - 2026-07-19
14
+
15
+ - Added the Welsh language (`WELSH`), seeded from real Welsh name roots.
16
+ Note: no CLI flag was wired up for it — reachable from the library only.
17
+ - Added the Belter language (`BELTER`), the creole from The Expanse, with a
18
+ `-b`/`--belter` CLI flag.
19
+ - Both files were generated with the `lang-gen` skill.
20
+
21
+ ## 4.0.3 - 2026-07-19
22
+
23
+ Fixes from the first full-codebase audit (see [`docs/AUDIT_Fable_5.md`](./docs/AUDIT_Fable_5.md)).
24
+
25
+ - **`slop` is now a runtime dependency** in the gemspec rather than a Gemfile
26
+ entry, so the installed CLI actually starts.
27
+ - **Fixed `compose(1)` crashing**: `compose_array` returns `[@pre]` for counts
28
+ below 2 instead of a `String`, making the return type honest.
29
+ - **Fixed blank lines in language files**: `refresh` now strips before the
30
+ empty check.
31
+ - **Fixed a potential infinite loop**: `determine_next_syllable` pre-filters
32
+ compatible candidates instead of rejection-sampling, and raises
33
+ `ArgumentError` naming the file and syllable when no candidate exists.
34
+ - **Cyrillic and German letters are now classified**: added Cyrillic vowels and
35
+ consonants plus `ö`, `ü`, `ß`, so the `+v`/`+c`/`-v`/`-c` flags in the four
36
+ `*-ru.txt` files and in `german-curse.txt` are actually enforced. They were
37
+ silent no-ops before.
38
+ - Fixed the broken `Syllable` clone constructor and a malformed
39
+ `raise ArgumentError`.
40
+ - Documented the intentional dual classification of `y` as both vowel and
41
+ consonant.
42
+ - Added `spec/languages/test-blank.txt` and `test-incompatible.txt` fixtures,
43
+ plus an adjacency spec that walks composed names pairwise.
44
+ - Corrected the README syllable range to "between 2 and 5" and fixed four
45
+ "eyllable" typos.
46
+
47
+ ## 4.0.2 - 2026-07-19
48
+
49
+ - Added a `-d`/`--demonic` CLI flag for the experimental `DEMONIC` language,
50
+ which had shipped without a way to select it from the command line.
51
+ - Added a `-k`/`--klingon` CLI flag for `KLINGON`, likewise unreachable before.
52
+
53
+ ## 4.0.1 - 2026-07-19
54
+
55
+ - Added the `lang-gen` skill, which generates a fully integrated language from
56
+ a plain-English theme.
57
+ - Added the experimental German Curse language (`GERMAN_CURSE`) via `lang-gen`,
58
+ with a `-ß`/`--german-curse` CLI flag.
59
+ - Added a portable, LLM-agnostic version of the `lang-gen` prompt in `docs/`.
60
+
3
61
  ## 4.0.0 - 2026-07-18
4
62
 
5
63
  - Raised minimum required Ruby version to 3.4.0 (dropping 3.0–3.3 support).
@@ -7,8 +65,31 @@
7
65
  - Bumped dependencies: `rake` (~> 13.4), `rexml`, `concurrent-ruby`.
8
66
  - Updated CI workflow and Rubocop settings.
9
67
 
68
+ ## Version 3
69
+
70
+ ## 3.0.0 - 2024-10-05
71
+
72
+ - Bumped the major version to mark the removal of Ruby 2.x support.
73
+
10
74
  ## Version 2
11
75
 
76
+ ## 2.1.1 - 2024-10-05
77
+
78
+ - Added Ruby 3.3.5 to the CI matrix.
79
+ - Updated Rubocop settings and applied the resulting style fixes across the
80
+ specs.
81
+ - Moved `spec/syllable_spec.rb` to `spec/random_name_generator/syllable_spec.rb`.
82
+
83
+ ## 2.1.0 - 2023-12-17
84
+
85
+ - Added a devcontainer (`.devcontainer/`) for containerized development.
86
+ - Updated the CI workflow and Rubocop settings.
87
+ - Refreshed dependencies.
88
+
89
+ ## 2.0.1 - 2021-08-08
90
+
91
+ - Updated dependencies.
92
+
12
93
  ## 2.0.0 - 2021-03-28
13
94
 
14
95
  - Major Refactor
data/CLAUDE.md ADDED
@@ -0,0 +1,49 @@
1
+ # CLAUDE.md
2
+
3
+ ## Project
4
+
5
+ `random_name_generator` — a Ruby gem (Ruby 3.4.10) that builds names by assembling
6
+ syllables from per-language `.txt` files. Ships a library API and a `slop`-based CLI
7
+ (`exe/random_name_generator`).
8
+
9
+ ## Commands
10
+
11
+ - **Full check (the gate):** `bundle exec rake` — runs `spec` then `rubocop`.
12
+ - **Tests:** `bundle exec rspec` — one line: `bundle exec rspec spec/random_name_generator_spec.rb:42`
13
+ - **Lint:** `bundle exec rubocop` (auto-fix `-A`) · **Smells:** `bundle exec reek`
14
+ - **Console:** `bin/console` · **Build:** `bundle exec rake build`
15
+ - **Run CLI:** `bundle exec exe/random_name_generator -g`
16
+
17
+ ## Architecture
18
+
19
+ - `lib/random_name_generator.rb` — the module. Each language is a `File` constant, e.g.
20
+ `GOBLIN = File.new(".../goblin.txt")`. `Generator` reads it and composes a name.
21
+ - `lib/random_name_generator/syllable.rb` — parses one line: `-` = first, `+` = last,
22
+ else middle; `+v/+c/-v/-c` are vowel/consonant adjacency rules (see class doc).
23
+ - `lib/languages/*.txt` — the domain data: plain, Cyrillic (`*-ru.txt`), `experimental/`.
24
+ - `exe/random_name_generator` — CLI; flags (`-e/-g/-r/-k/-b/-c/-x/-d/-ß`) pick a constant.
25
+
26
+ ## Conventions
27
+
28
+ - **Randomness is injected:** `Generator.new(lang, random: Random.new)`. For deterministic
29
+ specs pass a seeded `Random.new(seed)` — never `srand` or global state.
30
+ - **`slop` is a runtime dep** (in the gemspec, not just the Gemfile) — the installed CLI needs it.
31
+ - **RuboCop is source of truth** (`.rubocop.yml`): double quotes, LineLength 180, MethodLength 11.
32
+ RSpec: `expect` only. Test fixtures live in `spec/languages/`.
33
+ - Pure file-in/string-out: no network, no threads.
34
+
35
+ ## Adding a language
36
+
37
+ `.txt` file → `File` constant → CLI flag (if user-facing) → spec → README + CHANGELOG.
38
+ The `lang-gen` skill automates this.
39
+
40
+ ## Knowledge bundle
41
+
42
+ `.okf/` is an [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
43
+ bundle (markdown + YAML frontmatter) carrying the detail this file compresses: the
44
+ syllable-file grammar, per-language bucket counts, CLI selection quirks, and the
45
+ reasoning behind the conventions above. Start at `.okf/index.md`.
46
+
47
+ - **Consult it** before changing the composition algorithm, the syllable format, or the CLI.
48
+ - **Maintain it:** when a change invalidates a concept, update that file's body and
49
+ `timestamp`, then append a dated entry to `.okf/log.md`. The `okf` skill covers the flow.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- random_name_generator (4.0.3)
4
+ random_name_generator (4.0.5)
5
5
  slop (~> 4.10)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -41,7 +41,7 @@ Or install it yourself as:
41
41
  generate a first and last name for you:
42
42
 
43
43
  ```shell
44
- $> exe/random_name_generator [-egrkfcxdß?]
44
+ $> exe/random_name_generator [-egrkbfcxdß?]
45
45
  ```
46
46
 
47
47
  You can also install it so that it's instantly available to you:
@@ -59,8 +59,10 @@ RandomNameGenerator comes with several styles of syllable files:
59
59
  [Fantasy](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/fantasy.txt),
60
60
  [Goblin](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/goblin.txt),
61
61
  [Roman](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/roman.txt),
62
+ [Klingon](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/klingon.txt),
63
+ [Welsh](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/welsh.txt),
62
64
  and
63
- [Klingon](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/klingon.txt).
65
+ [Belter](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/belter.txt).
64
66
  By default it uses Fantasy. Instantiate RandomNameGenerator and then
65
67
  call compose on the object to generate a random name. If you don't pass
66
68
  in the number of syllables you want for your name to compose, it will
@@ -148,9 +150,18 @@ call `$❯ rake reek`
148
150
  Bug reports and pull requests are welcome on GitHub at
149
151
  https://github.com/folkengine/random_name_generator.
150
152
 
153
+ ### Knowledge bundle
154
+
155
+ This project uses the [`.okf/`](.okf/index.md) as an
156
+ [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
157
+ reference to how the code is structured. It documents the syllable file
158
+ grammar, a catalog of every bundled language with its constant and flag,
159
+ how composition and its failure modes work, and the reasoning behind
160
+ conventions such as injected randomness.
161
+
151
162
  ## Skills
152
163
 
153
- This ships with a skill designed to work with [Claude Code](https://claude.com/claude-code)
164
+ Version 4.x of this library ships with a skill designed to work with [Claude Code](https://claude.com/claude-code)
154
165
  and other LLMs under `.claude/skills/`.
155
166
 
156
167
  - [lang-gen](.claude/skills/lang-gen/SKILL.md): Generate a new random_name_generator language from a free-text theme (e.g. "german curse words"), assembles flagged pre/mid/sur syllable collections, registers the File constant, adds a smoke spec and README entry, and samples names to verify.
@@ -183,6 +194,14 @@ This will:
183
194
  6. Verify that all three buckets are non-empty, then sample
184
195
  composed names so you can eyeball the result.
185
196
 
197
+ Here's a sample:
198
+
199
+ ```txt
200
+ Parmaqo'ochu'
201
+ Hiqejajvam
202
+ Tiq'emey
203
+ ```
204
+
186
205
  The experimental [German Curse](lib/languages/experimental/german-curse.txt)
187
206
  language was generated this way.
188
207
 
@@ -12,6 +12,7 @@ opts = Slop.parse do |o|
12
12
  o.bool "-g", "--goblin", "Use Goblin syllable file"
13
13
  o.bool "-r", "--roman", "Use Roman syllable file"
14
14
  o.bool "-k", "--klingon", "Use Klingon syllable file"
15
+ o.bool "-b", "--belter", "Use Belter syllable file"
15
16
  o.bool "-f", "--flipmode", "Flip mode in effect"
16
17
  o.bool "-c", "--cyrillic", "Use Cyrillic mode"
17
18
  o.bool "-x", "--xrated", "Generate Curse words [NEEDS WORK]"
@@ -30,6 +31,7 @@ else
30
31
  lang = RandomNameGenerator::GOBLIN if opts.goblin?
31
32
  lang = RandomNameGenerator::ROMAN if opts.roman?
32
33
  lang = RandomNameGenerator::KLINGON if opts.klingon?
34
+ lang = RandomNameGenerator::BELTER if opts.belter?
33
35
  lang = RandomNameGenerator::CURSE if opts.xrated?
34
36
  lang = RandomNameGenerator::DEMONIC if opts.demonic?
35
37
  lang = RandomNameGenerator::GERMAN_CURSE if opts.german_curse?
@@ -0,0 +1,102 @@
1
+ -bel
2
+ -ber
3
+ -bos
4
+ -che
5
+ -da +c
6
+ -du
7
+ -fel
8
+ -gut
9
+ -im
10
+ -ka
11
+ -kep
12
+ -ko
13
+ -kop
14
+ -kow
15
+ -mal
16
+ -mi +c
17
+ -nak
18
+ -oye
19
+ -pash
20
+ -pel
21
+ -pom
22
+ -sa +c
23
+ -sab
24
+ -sha
25
+ -shu
26
+ -ta
27
+ -teng
28
+ -tich
29
+ -to
30
+ -tu
31
+ -wel
32
+ -xa
33
+ -xi
34
+ -ya +c
35
+ -ze
36
+ al
37
+ ang
38
+ at
39
+ be
40
+ da
41
+ deng
42
+ do
43
+ eng
44
+ ere -c
45
+ ga
46
+ im -c
47
+ ka
48
+ ken
49
+ la
50
+ lom
51
+ low
52
+ lu
53
+ ma
54
+ mang
55
+ mi
56
+ na
57
+ nga
58
+ ok
59
+ ol
60
+ pa
61
+ ra
62
+ sa
63
+ se
64
+ sha
65
+ shi
66
+ ta
67
+ teng
68
+ ti
69
+ to
70
+ tu
71
+ un
72
+ wa
73
+ we
74
+ xa
75
+ ya
76
+ +a -c
77
+ +ang
78
+ +atna
79
+ +da
80
+ +deng
81
+ +eng -c
82
+ +im -c
83
+ +ing
84
+ +kang
85
+ +lowda
86
+ +mang
87
+ +na
88
+ +nya
89
+ +owda -c
90
+ +pa
91
+ +ra
92
+ +sa
93
+ +shang
94
+ +ta
95
+ +teng
96
+ +tim
97
+ +to
98
+ +tu
99
+ +wa
100
+ +wala
101
+ +xa
102
+ +ya