random_name_generator 4.0.4 → 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.
- checksums.yaml +4 -4
- data/.okf/decisions/index.md +5 -0
- data/.okf/decisions/injected-randomness.md +41 -0
- data/.okf/decisions/ruby-3-4-minimum.md +34 -0
- data/.okf/decisions/slop-runtime-dependency.md +34 -0
- data/.okf/development/build-and-test.md +55 -0
- data/.okf/development/conventions.md +58 -0
- data/.okf/development/index.md +5 -0
- data/.okf/development/release.md +44 -0
- data/.okf/formats/index.md +3 -0
- data/.okf/formats/syllable-file-format.md +69 -0
- data/.okf/index.md +19 -0
- data/.okf/interfaces/cli.md +65 -0
- data/.okf/interfaces/index.md +3 -0
- data/.okf/languages/adding-a-language.md +59 -0
- data/.okf/languages/catalog.md +70 -0
- data/.okf/languages/index.md +4 -0
- data/.okf/library/generator.md +82 -0
- data/.okf/library/index.md +7 -0
- data/.okf/library/module.md +69 -0
- data/.okf/library/syllable.md +83 -0
- data/.okf/log.md +9 -0
- data/.okf/overview.md +59 -0
- data/AI-BOM.md +6 -1
- data/CHANGELOG.md +81 -0
- data/CLAUDE.md +49 -0
- data/Gemfile.lock +1 -1
- data/README.md +18 -1
- data/lib/random_name_generator/version.rb +1 -1
- metadata +24 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a9a162ecd9a8953ea3383bc847dcc18a8a61506b5802ea4cd8f94daeaaf5f9b
|
|
4
|
+
data.tar.gz: 746bcfeb89b0506e7cb7f03e92f6805efc9d2493fd603bd46b363f24888089f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc4d3f93f9945579b0e984ee0badd0c6ba96e52fa52239eee8300d6b17d0490f2390337b695e8fc34fde8eca49c6b9bd9197a5403c5538967f0c6d2244743b6b
|
|
7
|
+
data.tar.gz: 4af48dfe789cd3517f0256418f3378a0ba078c2c9b55acbad2dfbc6353b6a9f1d0453778b67c2afe8c56963018cedc66fc54c9dba4b09b048c0dd3f484ff364f
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Decisions
|
|
2
|
+
|
|
3
|
+
* [Randomness is injected, never global](injected-randomness.md) - generators take a `random:` keyword so specs can seed them; `srand` and global state are banned.
|
|
4
|
+
* [slop is a runtime dependency](slop-runtime-dependency.md) - the CLI ships inside the gem, so its option parser must be in the gemspec.
|
|
5
|
+
* [Ruby 3.4 is the floor](ruby-3-4-minimum.md) - version 4.0.0 dropped Ruby 3.0–3.3; CI tests 3.4, 4.0, and head.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Decision
|
|
3
|
+
title: Randomness is injected, never global
|
|
4
|
+
description: Generators take a `random:` keyword so specs can seed them; `srand` and global state are banned.
|
|
5
|
+
tags: [decision, testing, api]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Decision
|
|
10
|
+
|
|
11
|
+
Every sampling point that can be controlled takes an injected `Random`:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
RandomNameGenerator::Generator.new(lang, random: Random.new(seed))
|
|
15
|
+
RandomNameGenerator.pick_number_of_syllables(random: Random.new(seed))
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`Generator` stores it as `@rnd` and passes it to every `Array#sample` call in
|
|
19
|
+
the composition path. Specs that need determinism pass a seeded `Random` —
|
|
20
|
+
they never call `srand` or otherwise touch global randomness.
|
|
21
|
+
|
|
22
|
+
# Why
|
|
23
|
+
|
|
24
|
+
Global `srand` is process-wide: one spec seeding it changes the behavior of
|
|
25
|
+
every later example, and parallel or reordered runs stop being reproducible.
|
|
26
|
+
An injected `Random` scopes determinism to the object that needs it.
|
|
27
|
+
|
|
28
|
+
# Limits
|
|
29
|
+
|
|
30
|
+
Two entry points remain non-seedable because they sample the *language* with a
|
|
31
|
+
bare `Array#sample`: `RandomNameGenerator.flip_mode` and
|
|
32
|
+
`.flip_mode_cyrillic`. Their specs assert on type and shape rather than on a
|
|
33
|
+
specific name. Also note that `compose` with no argument draws its syllable
|
|
34
|
+
count from `pick_number_of_syllables`'s **default** `Random.new` — for a fully
|
|
35
|
+
deterministic name, pass the count explicitly.
|
|
36
|
+
|
|
37
|
+
See [Generator](/library/generator.md) and [the module](/library/module.md).
|
|
38
|
+
|
|
39
|
+
# Citations
|
|
40
|
+
|
|
41
|
+
[1] [CLAUDE.md — Conventions](https://github.com/folkengine/random_name_generator/blob/main/CLAUDE.md)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Decision
|
|
3
|
+
title: Ruby 3.4 is the floor
|
|
4
|
+
description: Version 4.0.0 dropped Ruby 3.0–3.3; CI tests 3.4, 4.0, and head.
|
|
5
|
+
tags: [decision, ruby, ci]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Decision
|
|
10
|
+
|
|
11
|
+
`required_ruby_version >= 3.4.0` as of gem version **4.0.0** (2026-07-18).
|
|
12
|
+
`.tool-versions` pins the development interpreter to `ruby 3.4.10`, and
|
|
13
|
+
RuboCop's `TargetRubyVersion` is `3.4`.
|
|
14
|
+
|
|
15
|
+
Support for Ruby 3.0 through 3.3 was dropped in the same release, alongside
|
|
16
|
+
dependency bumps (`rake ~> 13.4`, `rexml`, `concurrent-ruby`).
|
|
17
|
+
|
|
18
|
+
# CI matrix
|
|
19
|
+
|
|
20
|
+
`.github/workflows/ruby.yml` runs the full gate on `3.4`, `4.0`, and `head`.
|
|
21
|
+
`head` is `continue-on-error: true` — it exists to catch 4.1 regressions early
|
|
22
|
+
without letting a broken nightly red the build. See
|
|
23
|
+
[build and test](/development/build-and-test.md).
|
|
24
|
+
|
|
25
|
+
# Implications
|
|
26
|
+
|
|
27
|
+
The floor is a hard constraint on new code: 3.4-and-later syntax is fine, and
|
|
28
|
+
the four decimal places of `.tool-versions` should track whatever patch the
|
|
29
|
+
CI `3.4` job resolves to. Raising the floor again is a **major** version bump.
|
|
30
|
+
|
|
31
|
+
# Citations
|
|
32
|
+
|
|
33
|
+
[1] [CHANGELOG.md — 4.0.0](https://github.com/folkengine/random_name_generator/blob/main/CHANGELOG.md)
|
|
34
|
+
[2] [.github/workflows/ruby.yml](https://github.com/folkengine/random_name_generator/blob/main/.github/workflows/ruby.yml)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Decision
|
|
3
|
+
title: slop is a runtime dependency
|
|
4
|
+
description: The CLI ships inside the gem, so its option parser must be in the gemspec — a Gemfile entry is invisible to installed gems.
|
|
5
|
+
tags: [decision, packaging, cli]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Decision
|
|
10
|
+
|
|
11
|
+
`slop ~> 4.10` is declared with `spec.add_dependency` in
|
|
12
|
+
`random_name_generator.gemspec`, not merely in the `Gemfile`.
|
|
13
|
+
|
|
14
|
+
# Why
|
|
15
|
+
|
|
16
|
+
`exe/random_name_generator` ships as a gem executable and does
|
|
17
|
+
`require "slop"` at the top. A `Gemfile` entry only affects development in
|
|
18
|
+
this checkout; it is not carried into the published gem. Without the gemspec
|
|
19
|
+
dependency, `gem install random_name_generator` followed by
|
|
20
|
+
`random_name_generator -g` fails with `LoadError` on a machine that happens
|
|
21
|
+
not to have slop.
|
|
22
|
+
|
|
23
|
+
The gemspec carries an inline comment saying exactly this, so the classification
|
|
24
|
+
survives future dependency cleanups.
|
|
25
|
+
|
|
26
|
+
# Scope
|
|
27
|
+
|
|
28
|
+
This applies to anything the shipped [CLI](/interfaces/cli.md) or `lib/`
|
|
29
|
+
requires at runtime. Test and lint tooling (rspec, rubocop, reek, rake) stays
|
|
30
|
+
in the Gemfile — those are correctly development-only.
|
|
31
|
+
|
|
32
|
+
# Citations
|
|
33
|
+
|
|
34
|
+
[1] [random_name_generator.gemspec](https://github.com/folkengine/random_name_generator/blob/main/random_name_generator.gemspec)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Build, test, and lint
|
|
4
|
+
description: The commands that gate a change, and what each one enforces.
|
|
5
|
+
tags: [development, testing, ci]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# The gate
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
bundle exec rake # => spec, then rubocop
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`rake default` is `%i[spec rubocop]`. Reek is wired as its own task
|
|
16
|
+
(`rake reek`, `fail_on_error: true`) but is **not** part of the default task —
|
|
17
|
+
run it deliberately.
|
|
18
|
+
|
|
19
|
+
| Command | Purpose |
|
|
20
|
+
|---------|---------|
|
|
21
|
+
| `bundle exec rspec` | Tests. One example: `bundle exec rspec spec/random_name_generator_spec.rb:42`. |
|
|
22
|
+
| `bundle exec rubocop` | Lint. `-A` to autocorrect. |
|
|
23
|
+
| `bundle exec reek` | Smell detection, configured by `config.reek`. |
|
|
24
|
+
| `bin/console` | IRB with the gem loaded. |
|
|
25
|
+
| `bundle exec rake build` | Builds the `.gem` into `pkg/`. |
|
|
26
|
+
| `bundle exec exe/random_name_generator -g` | Run the [CLI](/interfaces/cli.md) from the checkout. |
|
|
27
|
+
|
|
28
|
+
# Test layout
|
|
29
|
+
|
|
30
|
+
- `spec/random_name_generator_spec.rb` — module constants, factory methods,
|
|
31
|
+
and `Generator` behavior. Generators for the four base languages are built
|
|
32
|
+
once in a `before(:all)` block.
|
|
33
|
+
- `spec/random_name_generator/syllable_spec.rb` — parsing and adjacency rules.
|
|
34
|
+
- `spec/languages/*.txt` — fixtures that pin format edges (blank lines, a
|
|
35
|
+
one-syllable-per-bucket file, every flag combination, and an unsatisfiable
|
|
36
|
+
file that must raise). See
|
|
37
|
+
[the syllable file format](/formats/syllable-file-format.md).
|
|
38
|
+
|
|
39
|
+
`spec_helper.rb` disables RSpec monkey patching, forces `expect` syntax, and
|
|
40
|
+
persists example status to `.rspec_status`.
|
|
41
|
+
|
|
42
|
+
# CI
|
|
43
|
+
|
|
44
|
+
`.github/workflows/ruby.yml` runs `bundle exec rake` on pushes to `main`,
|
|
45
|
+
`v*` tags, and every pull request, against a matrix of Ruby `3.4`, `4.0`, and
|
|
46
|
+
`head`. The `head` job is `continue-on-error` — a broken nightly must not red
|
|
47
|
+
the run — and installs uncached with the latest bundler, since pairing a fixed
|
|
48
|
+
gem cache with a moving interpreter causes `CorruptBundlerInstallError`.
|
|
49
|
+
|
|
50
|
+
Overcommit hooks are configured in `.overcommit.yml`.
|
|
51
|
+
|
|
52
|
+
# Citations
|
|
53
|
+
|
|
54
|
+
[1] [Rakefile](https://github.com/folkengine/random_name_generator/blob/main/Rakefile)
|
|
55
|
+
[2] [.github/workflows/ruby.yml](https://github.com/folkengine/random_name_generator/blob/main/.github/workflows/ruby.yml)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Convention
|
|
3
|
+
title: Code conventions
|
|
4
|
+
description: Style, smell, and testing rules this repo enforces — RuboCop is the source of truth.
|
|
5
|
+
tags: [development, style, lint]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# RuboCop is the arbiter
|
|
10
|
+
|
|
11
|
+
`.rubocop.yml` settles style questions; don't relitigate them in review.
|
|
12
|
+
|
|
13
|
+
| Setting | Value |
|
|
14
|
+
|---------|-------|
|
|
15
|
+
| `TargetRubyVersion` | 3.4, `NewCops: enable` |
|
|
16
|
+
| String literals | **double quotes** (including in interpolation) |
|
|
17
|
+
| `Layout/LineLength` | 180 |
|
|
18
|
+
| `Metrics/MethodLength` | 11 |
|
|
19
|
+
| `Metrics/ClassLength` | disabled |
|
|
20
|
+
| `Metrics/BlockLength` | excluded for `spec/**/*` |
|
|
21
|
+
| `Style/HashSyntax` | shorthand `either` |
|
|
22
|
+
|
|
23
|
+
Plugins: `rubocop-rspec`, `rubocop-rake`.
|
|
24
|
+
|
|
25
|
+
RSpec cops are relaxed where the existing spec style needs it —
|
|
26
|
+
`BeforeAfterAll` and `InstanceVariable` are disabled (the specs build shared
|
|
27
|
+
generators in `before(:all)`), `MultipleExpectations` is off, and
|
|
28
|
+
`NestedGroups` allows 5.
|
|
29
|
+
|
|
30
|
+
Every source file carries `# frozen_string_literal: true`.
|
|
31
|
+
|
|
32
|
+
# Reek
|
|
33
|
+
|
|
34
|
+
`config.reek` disables `IrresponsibleModule` and `TooManyMethods`, caps
|
|
35
|
+
instance variables at 10, and caps statements at 8 (excluding `initialize`).
|
|
36
|
+
Where a class legitimately exceeds a smell threshold, it carries an inline
|
|
37
|
+
`:reek:` annotation rather than a config exemption — e.g. `:reek:TooManyConstants`
|
|
38
|
+
on [the module](/library/module.md) and `:reek:TooManyMethods` on
|
|
39
|
+
[Syllable](/library/syllable.md).
|
|
40
|
+
|
|
41
|
+
# Testing
|
|
42
|
+
|
|
43
|
+
- `expect` syntax only; monkey patching disabled.
|
|
44
|
+
- Fixtures live in `spec/languages/`, never inline.
|
|
45
|
+
- Never use `srand` or global randomness for determinism — pass a seeded
|
|
46
|
+
`Random`. See [injected randomness](/decisions/injected-randomness.md).
|
|
47
|
+
|
|
48
|
+
# Shape of the code
|
|
49
|
+
|
|
50
|
+
Pure file-in / string-out: no network, no threads, no mutable global state
|
|
51
|
+
beyond the shared `File` constants. Keeping it that way is what makes the
|
|
52
|
+
library trivially embeddable.
|
|
53
|
+
|
|
54
|
+
# Citations
|
|
55
|
+
|
|
56
|
+
[1] [.rubocop.yml](https://github.com/folkengine/random_name_generator/blob/main/.rubocop.yml)
|
|
57
|
+
[2] [config.reek](https://github.com/folkengine/random_name_generator/blob/main/config.reek)
|
|
58
|
+
[3] [CLAUDE.md](https://github.com/folkengine/random_name_generator/blob/main/CLAUDE.md)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
* [Build, test, and lint](build-and-test.md) - the commands that gate a change, and what each one enforces.
|
|
4
|
+
* [Code conventions](conventions.md) - style, smell, and testing rules; RuboCop is the source of truth.
|
|
5
|
+
* [Releasing the gem](release.md) - version bump, changelog, and the rake release path to RubyGems.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Releasing the gem
|
|
4
|
+
description: Version bump, changelog, and the rake release path to RubyGems.
|
|
5
|
+
resource: https://rubygems.org/gems/random_name_generator
|
|
6
|
+
tags: [development, release, packaging]
|
|
7
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
The gem is published as
|
|
11
|
+
[random_name_generator](https://rubygems.org/gems/random_name_generator) under
|
|
12
|
+
LGPL-3.0. Current version: **4.0.4** (`lib/random_name_generator/version.rb`).
|
|
13
|
+
|
|
14
|
+
# Steps
|
|
15
|
+
|
|
16
|
+
1. Bump `RandomNameGenerator::VERSION` in `lib/random_name_generator/version.rb`
|
|
17
|
+
— the gemspec reads it, so it is the single source of truth.
|
|
18
|
+
2. Add a CHANGELOG entry under a `## <version> - <YYYY-MM-DD>` heading.
|
|
19
|
+
3. Run the gate: `bundle exec rake` (see
|
|
20
|
+
[build and test](/development/build-and-test.md)).
|
|
21
|
+
4. `bundle exec rake release` — tags, pushes commits and the tag, and pushes
|
|
22
|
+
the `.gem` to RubyGems. Pushing a `v*` tag also triggers CI.
|
|
23
|
+
|
|
24
|
+
`rubygems_mfa_required` is set in the gemspec metadata, so the push requires
|
|
25
|
+
MFA.
|
|
26
|
+
|
|
27
|
+
# Packaging notes
|
|
28
|
+
|
|
29
|
+
- `spec.files` comes from `git ls-files`, minus `test/`, `spec/`, and
|
|
30
|
+
`features/` — an untracked language file will **not** ship.
|
|
31
|
+
- `bindir` is `exe`; executables are derived from tracked files there.
|
|
32
|
+
- `required_ruby_version >= 3.4.0` — see
|
|
33
|
+
[the Ruby floor](/decisions/ruby-3-4-minimum.md).
|
|
34
|
+
- `slop ~> 4.10` is a runtime dependency, not a development one — see
|
|
35
|
+
[why](/decisions/slop-runtime-dependency.md).
|
|
36
|
+
|
|
37
|
+
`bundle exec rake install` installs the gem locally, which is how you get a
|
|
38
|
+
bare `random_name_generator` command on `PATH` for testing the
|
|
39
|
+
[CLI](/interfaces/cli.md).
|
|
40
|
+
|
|
41
|
+
# Citations
|
|
42
|
+
|
|
43
|
+
[1] [random_name_generator.gemspec](https://github.com/folkengine/random_name_generator/blob/main/random_name_generator.gemspec)
|
|
44
|
+
[2] [CHANGELOG.md](https://github.com/folkengine/random_name_generator/blob/main/CHANGELOG.md)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: File Format
|
|
3
|
+
title: Syllable file format (.txt)
|
|
4
|
+
description: Line-oriented grammar for language files — one syllable per line, a position sigil, and optional adjacency flags.
|
|
5
|
+
tags: [format, domain, languages]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The syllable file is the domain data of this project; everything in
|
|
10
|
+
`lib/` is machinery for reading it. The format is deliberately plain text so a
|
|
11
|
+
language can be authored, diffed, and reviewed by hand.
|
|
12
|
+
|
|
13
|
+
# Schema
|
|
14
|
+
|
|
15
|
+
One syllable per line. Blank lines are ignored. Leading/trailing whitespace is
|
|
16
|
+
stripped and the whole line is downcased.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
[sigil]syllable [flag] [flag]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Element | Values | Meaning |
|
|
23
|
+
|---------|--------|---------|
|
|
24
|
+
| sigil | `-` | Prefix — may only appear first in a name. |
|
|
25
|
+
| | `+` | Suffix — may only appear last. |
|
|
26
|
+
| | *(none)* | Middle. |
|
|
27
|
+
| syllable | any characters | The text contributed to the name. |
|
|
28
|
+
| flags | `+v` | The **next** syllable must start with a vowel. |
|
|
29
|
+
| | `+c` | The next syllable must start with a consonant. |
|
|
30
|
+
| | `-v` | The **previous** syllable must end with a vowel. |
|
|
31
|
+
| | `-c` | The previous syllable must end with a consonant. |
|
|
32
|
+
|
|
33
|
+
Flags are whitespace-separated and order-independent. `+v`/`+c` are mutually
|
|
34
|
+
exclusive (first wins), as are `-v`/`-c`.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
-ang +c prefix "ang", next syllable must begin with a consonant
|
|
38
|
+
bryn middle, unconstrained
|
|
39
|
+
+wen -c suffix "wen", only after a syllable ending in a consonant
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
# Authoring constraints
|
|
43
|
+
|
|
44
|
+
- **All three buckets must be non-empty.** A file with no suffixes cannot
|
|
45
|
+
compose a name of two or more syllables.
|
|
46
|
+
- **Flags must be satisfiable.** If some syllable's `+v` has no vowel-initial
|
|
47
|
+
candidate in the middle or suffix bucket, composition raises `ArgumentError`
|
|
48
|
+
at generation time, not load time — see [Generator](/library/generator.md).
|
|
49
|
+
Sparse buckets plus aggressive flags is the usual cause.
|
|
50
|
+
- Use flags only where the phonetics actually demand them. Most lines in the
|
|
51
|
+
bundled languages carry none.
|
|
52
|
+
|
|
53
|
+
# Where the files live
|
|
54
|
+
|
|
55
|
+
Curated languages are in `lib/languages/`; edgier or less polished sets are in
|
|
56
|
+
`lib/languages/experimental/`. Cyrillic variants use the `-ru.txt` suffix and
|
|
57
|
+
rely on `Syllable`'s Cyrillic character classes. See the
|
|
58
|
+
[language catalog](/languages/catalog.md) and
|
|
59
|
+
[adding a language](/languages/adding-a-language.md).
|
|
60
|
+
|
|
61
|
+
Test fixtures in `spec/languages/` exercise the edges of the format:
|
|
62
|
+
`test-blank.txt` (blank lines), `test-micro.txt` (one syllable per bucket, no
|
|
63
|
+
trailing newline), `test-tiny.txt` (every flag combination), and
|
|
64
|
+
`test-incompatible.txt` (a file whose flags cannot be satisfied).
|
|
65
|
+
|
|
66
|
+
# Citations
|
|
67
|
+
|
|
68
|
+
[1] [Syllable class documentation](https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator/syllable.rb)
|
|
69
|
+
[2] [java-random-name-generator](https://github.com/folkengine/java-random-name-generator) — the port's origin; the format is inherited from it.
|
data/.okf/index.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
okf_version: '0.1'
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# random_name_generator Knowledge Bundle
|
|
6
|
+
|
|
7
|
+
Knowledge about the `random_name_generator` Ruby gem — how names are composed
|
|
8
|
+
from syllable files, what ships, and how to work on it.
|
|
9
|
+
|
|
10
|
+
* [Overview](overview.md) - the project at a glance: shape, properties, and where to start.
|
|
11
|
+
|
|
12
|
+
# Areas
|
|
13
|
+
|
|
14
|
+
* [library/](library/) - the Ruby API: module, Generator, Syllable.
|
|
15
|
+
* [formats/](formats/) - the syllable file format that drives everything.
|
|
16
|
+
* [languages/](languages/) - the shipped syllable files and how to add one.
|
|
17
|
+
* [interfaces/](interfaces/) - the command line executable.
|
|
18
|
+
* [development/](development/) - build, test, lint, and release.
|
|
19
|
+
* [decisions/](decisions/) - choices worth not re-deriving.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: CLI
|
|
3
|
+
title: random_name_generator (executable)
|
|
4
|
+
description: The slop-based command line interface — one boolean flag per language, printing a two-name pair.
|
|
5
|
+
resource: https://github.com/folkengine/random_name_generator/blob/main/exe/random_name_generator
|
|
6
|
+
tags: [cli, interface]
|
|
7
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
```shell
|
|
11
|
+
$ bundle exec exe/random_name_generator [-egrkbfcxdß?]
|
|
12
|
+
$ random_name_generator --german-curse # after `bundle exec rake install`
|
|
13
|
+
Dummkopfischpopelsepp Schnoddmistmann
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The script always prints **two** composed names separated by a space —
|
|
17
|
+
a first and last name — each with a randomly drawn syllable count.
|
|
18
|
+
|
|
19
|
+
# Flags
|
|
20
|
+
|
|
21
|
+
| Flag | Long | Selects |
|
|
22
|
+
|------|------|---------|
|
|
23
|
+
| `-e` | `--elven` | `ELVEN` (or `ELVEN_RU` with `-c`) |
|
|
24
|
+
| `-g` | `--goblin` | `GOBLIN` / `GOBLIN_RU` |
|
|
25
|
+
| `-r` | `--roman` | `ROMAN` / `ROMAN_RU` |
|
|
26
|
+
| `-k` | `--klingon` | `KLINGON` |
|
|
27
|
+
| `-b` | `--belter` | `BELTER` |
|
|
28
|
+
| `-x` | `--xrated` | `CURSE` *[NEEDS WORK]* |
|
|
29
|
+
| `-d` | `--demonic` | `DEMONIC` |
|
|
30
|
+
| `-ß` | `--german-curse` | `GERMAN_CURSE` *[NEEDS WORK]* |
|
|
31
|
+
| `-c` | `--cyrillic` | Switches to the Cyrillic branch; alone it means `FANTASY_RU`. |
|
|
32
|
+
| `-f` | `--flipmode` | Random language per name; honors `-c`. |
|
|
33
|
+
| `-?` | `--help` | Prints the slop usage block. |
|
|
34
|
+
|
|
35
|
+
With no flags, the default is `FANTASY`.
|
|
36
|
+
|
|
37
|
+
# Selection semantics
|
|
38
|
+
|
|
39
|
+
Language selection is a straight run of `if` assignments against a `lang`
|
|
40
|
+
variable initialized to `FANTASY`, split into a Cyrillic and a non-Cyrillic
|
|
41
|
+
branch. Consequences worth knowing:
|
|
42
|
+
|
|
43
|
+
- **Last flag in source order wins**, not last on the command line —
|
|
44
|
+
`-e -g` yields Goblin because the `GOBLIN` assignment comes after `ELVEN`.
|
|
45
|
+
- The Cyrillic branch only knows Elven, Goblin, and Roman, so `-c -k`,
|
|
46
|
+
`-c -b`, `-c -d` etc. fall through to `FANTASY_RU`.
|
|
47
|
+
- `-f` short-circuits language selection entirely; `-?` short-circuits
|
|
48
|
+
everything but `-f`.
|
|
49
|
+
- There is **no flag for Welsh** — see the
|
|
50
|
+
[language catalog](/languages/catalog.md).
|
|
51
|
+
|
|
52
|
+
The CLI exposes no syllable-count option; every name uses
|
|
53
|
+
`RandomNameGenerator.pick_number_of_syllables`.
|
|
54
|
+
|
|
55
|
+
# Packaging
|
|
56
|
+
|
|
57
|
+
Option parsing uses [slop](https://rubygems.org/gems/slop), which is therefore
|
|
58
|
+
a **runtime** dependency of the gem, not merely a Gemfile entry — see
|
|
59
|
+
[that decision](/decisions/slop-runtime-dependency.md). The gemspec sets
|
|
60
|
+
`bindir = "exe"` and derives `executables` from the tracked files under it.
|
|
61
|
+
|
|
62
|
+
# Citations
|
|
63
|
+
|
|
64
|
+
[1] [exe/random_name_generator](https://github.com/folkengine/random_name_generator/blob/main/exe/random_name_generator)
|
|
65
|
+
[2] [README — Installation](https://github.com/folkengine/random_name_generator/blob/main/README.md)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Adding a language
|
|
4
|
+
description: The five touch points a new syllable file has to reach, and the lang-gen skill that automates them.
|
|
5
|
+
tags: [languages, playbook, contributing]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
A language is not just a file — it has to be registered, exercised, and
|
|
10
|
+
documented. Missing one of these is the usual review comment.
|
|
11
|
+
|
|
12
|
+
# Steps
|
|
13
|
+
|
|
14
|
+
1. **Write the `.txt`.** Follow the
|
|
15
|
+
[syllable file format](/formats/syllable-file-format.md). Curated languages
|
|
16
|
+
go in `lib/languages/`; edgy or unpolished ones in
|
|
17
|
+
`lib/languages/experimental/`. Cyrillic variants take the `-ru.txt` suffix.
|
|
18
|
+
2. **Register the `File` constant** in `lib/random_name_generator.rb`, grouped
|
|
19
|
+
with its peers (plain / Cyrillic / experimental).
|
|
20
|
+
3. **Add a CLI flag** in `exe/random_name_generator` if the language is
|
|
21
|
+
user-facing — both the `o.bool` declaration and the assignment in the
|
|
22
|
+
correct branch of the Cyrillic conditional. See [the CLI](/interfaces/cli.md).
|
|
23
|
+
4. **Add a spec** to `spec/random_name_generator_spec.rb`. A smoke test that
|
|
24
|
+
composes names at each syllable count is enough to catch an unsatisfiable
|
|
25
|
+
flag set, which otherwise only surfaces at runtime.
|
|
26
|
+
5. **Document it** — README (with a link to the file) and CHANGELOG.
|
|
27
|
+
|
|
28
|
+
# Verification
|
|
29
|
+
|
|
30
|
+
Beyond the spec, check that all three buckets are non-empty and that names
|
|
31
|
+
actually compose at 1..5 syllables:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
bundle exec ruby -Ilib -e '
|
|
35
|
+
require "random_name_generator"
|
|
36
|
+
g = RandomNameGenerator.new(RandomNameGenerator::WELSH)
|
|
37
|
+
(1..5).each { |n| puts "#{n}: #{Array.new(5) { g.compose(n) }.join(" ")}" }
|
|
38
|
+
'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then run the gate: `bundle exec rake` — see
|
|
42
|
+
[build and test](/development/build-and-test.md).
|
|
43
|
+
|
|
44
|
+
# The lang-gen skill
|
|
45
|
+
|
|
46
|
+
`.claude/skills/lang-gen/SKILL.md` automates the whole flow from a plain-English
|
|
47
|
+
theme, e.g. `/lang-gen Klingon words of joy`. It derives the slug, constant,
|
|
48
|
+
and destination directory (routing edgy themes to `experimental/`), authors the
|
|
49
|
+
three buckets with adjacency flags, performs steps 2–5, and samples names to
|
|
50
|
+
verify. `GERMAN_CURSE` was generated this way.
|
|
51
|
+
|
|
52
|
+
A portable text version of the same prompt lives at
|
|
53
|
+
`docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md` for use outside
|
|
54
|
+
Claude Code.
|
|
55
|
+
|
|
56
|
+
# Citations
|
|
57
|
+
|
|
58
|
+
[1] [CLAUDE.md — Adding a language](https://github.com/folkengine/random_name_generator/blob/main/CLAUDE.md)
|
|
59
|
+
[2] [README — lang-gen](https://github.com/folkengine/random_name_generator/blob/main/README.md)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Catalog
|
|
3
|
+
title: Language catalog
|
|
4
|
+
description: Every bundled syllable file — its constant, path, CLI flag, and bucket sizes.
|
|
5
|
+
tags: [languages, data, catalog]
|
|
6
|
+
timestamp: 2026-07-26T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Fourteen syllable files ship with the gem. Each is bound to a `File` constant
|
|
10
|
+
on [the module](/library/module.md) and, where user-facing, to a
|
|
11
|
+
[CLI](/interfaces/cli.md) flag.
|
|
12
|
+
|
|
13
|
+
# Curated languages
|
|
14
|
+
|
|
15
|
+
| Constant | File | CLI | pre / mid / suf |
|
|
16
|
+
|----------|------|-----|-----------------|
|
|
17
|
+
| `FANTASY` | `lib/languages/fantasy.txt` | *(default)* | 179 / 153 / 18 |
|
|
18
|
+
| `ELVEN` | `lib/languages/elven.txt` | `-e` | 36 / 21 / 27 |
|
|
19
|
+
| `GOBLIN` | `lib/languages/goblin.txt` | `-g` | 19 / 13 / 16 |
|
|
20
|
+
| `ROMAN` | `lib/languages/roman.txt` | `-r` | 15 / 10 / 10 |
|
|
21
|
+
| `KLINGON` | `lib/languages/klingon.txt` | `-k` | 40 / 35 / 36 |
|
|
22
|
+
| `BELTER` | `lib/languages/belter.txt` | `-b` | 35 / 40 / 27 |
|
|
23
|
+
| `WELSH` | `lib/languages/welsh.txt` | *(none)* | 35 / 32 / 24 |
|
|
24
|
+
|
|
25
|
+
`WELSH` is reachable from the library but has **no CLI flag** — the one gap
|
|
26
|
+
between the constant set and `exe/random_name_generator`.
|
|
27
|
+
|
|
28
|
+
# Cyrillic variants
|
|
29
|
+
|
|
30
|
+
Same four base styles, transliterated into Cyrillic syllables. They work
|
|
31
|
+
because `Syllable::VOWELS` and `CONSONANTS` include the Cyrillic alphabet
|
|
32
|
+
(see [Syllable](/library/syllable.md)).
|
|
33
|
+
|
|
34
|
+
| Constant | File | CLI | pre / mid / suf |
|
|
35
|
+
|----------|------|-----|-----------------|
|
|
36
|
+
| `FANTASY_RU` | `lib/languages/fantasy-ru.txt` | `-c` | 180 / 157 / 19 |
|
|
37
|
+
| `ELVEN_RU` | `lib/languages/elven-ru.txt` | `-c -e` | 36 / 21 / 27 |
|
|
38
|
+
| `GOBLIN_RU` | `lib/languages/goblin-ru.txt` | `-c -g` | 19 / 13 / 16 |
|
|
39
|
+
| `ROMAN_RU` | `lib/languages/roman-ru.txt` | `-c -r` | 15 / 10 / 10 |
|
|
40
|
+
|
|
41
|
+
The Cyrillic set is what `-c` selects, and it is also the pool for
|
|
42
|
+
`RandomNameGenerator.flip_mode_cyrillic`. `KLINGON`, `BELTER`, and `WELSH`
|
|
43
|
+
have no Cyrillic counterpart, so `-c -k` silently yields `FANTASY_RU`.
|
|
44
|
+
|
|
45
|
+
# Experimental languages
|
|
46
|
+
|
|
47
|
+
Edgier, less curated sets under `lib/languages/experimental/`. Opt-in only.
|
|
48
|
+
|
|
49
|
+
| Constant | File | CLI | pre / mid / suf |
|
|
50
|
+
|----------|------|-----|-----------------|
|
|
51
|
+
| `CURSE` | `experimental/curse.txt` | `-x` | 24 / 7 / 32 |
|
|
52
|
+
| `DEMONIC` | `experimental/demonic.txt` | `-d` | 111 / 64 / 73 |
|
|
53
|
+
| `GERMAN_CURSE` | `experimental/german-curse.txt` | `-ß` | 105 / 98 / 127 |
|
|
54
|
+
|
|
55
|
+
`CURSE` and `GERMAN_CURSE` are marked `[NEEDS WORK]` in the CLI help.
|
|
56
|
+
`CURSE`'s middle bucket holds only 7 syllables, so names of three or more
|
|
57
|
+
syllables repeat heavily. `GERMAN_CURSE` was produced by the `lang-gen` skill
|
|
58
|
+
and is the worked example for [adding a language](/languages/adding-a-language.md).
|
|
59
|
+
|
|
60
|
+
# Flip mode
|
|
61
|
+
|
|
62
|
+
`RandomNameGenerator.flip_mode` samples only `FANTASY`, `ELVEN`, `GOBLIN`, and
|
|
63
|
+
`ROMAN` — the four original styles. New languages are **not** picked up by
|
|
64
|
+
flip mode automatically; the arrays in `lib/random_name_generator.rb` are
|
|
65
|
+
hard-coded.
|
|
66
|
+
|
|
67
|
+
# Citations
|
|
68
|
+
|
|
69
|
+
[1] [lib/random_name_generator.rb](https://github.com/folkengine/random_name_generator/blob/main/lib/random_name_generator.rb)
|
|
70
|
+
[2] [README — Usage](https://github.com/folkengine/random_name_generator/blob/main/README.md)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# Languages
|
|
2
|
+
|
|
3
|
+
* [Language catalog](catalog.md) - every bundled syllable file: its constant, path, CLI flag, and bucket sizes.
|
|
4
|
+
* [Adding a language](adding-a-language.md) - the five touch points a new syllable file has to reach, and the lang-gen skill that automates them.
|
|
@@ -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-
|
|
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
data/README.md
CHANGED
|
@@ -150,9 +150,18 @@ call `$❯ rake reek`
|
|
|
150
150
|
Bug reports and pull requests are welcome on GitHub at
|
|
151
151
|
https://github.com/folkengine/random_name_generator.
|
|
152
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
|
+
|
|
153
162
|
## Skills
|
|
154
163
|
|
|
155
|
-
|
|
164
|
+
Version 4.x of this library ships with a skill designed to work with [Claude Code](https://claude.com/claude-code)
|
|
156
165
|
and other LLMs under `.claude/skills/`.
|
|
157
166
|
|
|
158
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.
|
|
@@ -185,6 +194,14 @@ This will:
|
|
|
185
194
|
6. Verify that all three buckets are non-empty, then sample
|
|
186
195
|
composed names so you can eyeball the result.
|
|
187
196
|
|
|
197
|
+
Here's a sample:
|
|
198
|
+
|
|
199
|
+
```txt
|
|
200
|
+
Parmaqo'ochu'
|
|
201
|
+
Hiqejajvam
|
|
202
|
+
Tiq'emey
|
|
203
|
+
```
|
|
204
|
+
|
|
188
205
|
The experimental [German Curse](lib/languages/experimental/german-curse.txt)
|
|
189
206
|
language was generated this way.
|
|
190
207
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: random_name_generator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- folkengine
|
|
@@ -38,12 +38,35 @@ files:
|
|
|
38
38
|
- ".devcontainer/devcontainer.json"
|
|
39
39
|
- ".github/workflows/ruby.yml"
|
|
40
40
|
- ".gitignore"
|
|
41
|
+
- ".okf/decisions/index.md"
|
|
42
|
+
- ".okf/decisions/injected-randomness.md"
|
|
43
|
+
- ".okf/decisions/ruby-3-4-minimum.md"
|
|
44
|
+
- ".okf/decisions/slop-runtime-dependency.md"
|
|
45
|
+
- ".okf/development/build-and-test.md"
|
|
46
|
+
- ".okf/development/conventions.md"
|
|
47
|
+
- ".okf/development/index.md"
|
|
48
|
+
- ".okf/development/release.md"
|
|
49
|
+
- ".okf/formats/index.md"
|
|
50
|
+
- ".okf/formats/syllable-file-format.md"
|
|
51
|
+
- ".okf/index.md"
|
|
52
|
+
- ".okf/interfaces/cli.md"
|
|
53
|
+
- ".okf/interfaces/index.md"
|
|
54
|
+
- ".okf/languages/adding-a-language.md"
|
|
55
|
+
- ".okf/languages/catalog.md"
|
|
56
|
+
- ".okf/languages/index.md"
|
|
57
|
+
- ".okf/library/generator.md"
|
|
58
|
+
- ".okf/library/index.md"
|
|
59
|
+
- ".okf/library/module.md"
|
|
60
|
+
- ".okf/library/syllable.md"
|
|
61
|
+
- ".okf/log.md"
|
|
62
|
+
- ".okf/overview.md"
|
|
41
63
|
- ".overcommit.yml"
|
|
42
64
|
- ".rspec"
|
|
43
65
|
- ".rubocop.yml"
|
|
44
66
|
- ".tool-versions"
|
|
45
67
|
- AI-BOM.md
|
|
46
68
|
- CHANGELOG.md
|
|
69
|
+
- CLAUDE.md
|
|
47
70
|
- Gemfile
|
|
48
71
|
- Gemfile.lock
|
|
49
72
|
- LICENSE
|