A Ruby CLI tool that randomly pairs people into 1-on-1 couples while enforcing workspace and history-based constraints. Designed to work with Ruby 2.6.10.
- Register people through an interactive step-by-step prompt
- View all registered people as a JSON array with
/list - Randomly generate 1-on-1 pairings with constraint enforcement
- Persist data across sessions using a local
datafile - Constraint rules:
- C1 – Members of a 2-person workspace cannot be paired with each other
- C2 – Members sharing the same workspace and gender (group ≤ 3) cannot be paired with each other
- C3 – People who were coupled within the last 14 days cannot be paired again
| Requirement | Version |
|---|---|
| Ruby | 2.6.10 |
| Standard Library | json, time (bundled with Ruby) |
No external gems are required.
git clone <repository-url>
cd random_couplerThat's it. No bundle install needed.
bash run.shrun.batRuby 2.6.x must be installed in advance on Windows.
If Ruby is not found,run.batwill display the download URL (rubyinstaller.org) and exit.
If a different Ruby version is detected, you will be asked whether to continue.
ruby coupler.rb| Command | Description |
|---|---|
/add |
Register people through interactive prompts |
/list |
Print all registered people, couple records, and group records |
/couple |
Randomly pair 2 eligible people |
/group_N |
Divide all eligible people into groups of N (e.g. /group_3) |
/clear |
Delete couple and group records older than 14 days |
/init_people |
Reset all registered people (with confirmation) |
/init_couples or /init_couple |
Reset all couple records (with confirmation) |
/init_groups or /init_group |
Reset all group records (with confirmation) |
/quit |
Save data to file and exit |
Running /add starts an interactive prompt that asks for each field one at a time.
| Field | Input | Notes |
|---|---|---|
name |
Free text | Cannot be empty |
gender |
m or f |
Case-insensitive. m → male, f → female. Any other value triggers an error and re-prompt. |
workspace |
Free text | Case-insensitive. Team-A and team-a are treated as the same workspace (stored lowercase). |
After each person is registered, you are asked whether to add another:
y(orY) — continue to register the next personn(orN) — finish and return to the main prompt
> /add
Name: Alice
Gender (m/f): f
Workspace: Team-A
Registered: Alice | female | team-a
Total people: 1
Add another person? (y/n): y
Name: Bob
Gender (m/f): x
Error: Invalid gender 'x'. Please enter 'm' (male) or 'f' (female).
Gender (m/f): m
Workspace: TEAM-A
Registered: Bob | male | team-a
Total people: 2
Add another person? (y/n): n
Displays all registered people, couple records, and group records in JSON format.
> /list
========================================
People (4)
========================================
[ ... ]
========================================
Couple Records (1)
========================================
[
{ "person1": "Alice", "person2": "Dave", "coupled_at": "2026-05-08T14:00:00+09:00" }
]
========================================
Group Records (1)
========================================
[
{ "members": ["Bob", "Carol", "Eve"], "grouped_at": "2026-05-08T15:00:00+09:00" }
]
Each /couple call produces exactly one pair, chosen randomly from all eligible people.
> /couple
========================================
Matching Result
========================================
Alice (team-a/female) <-> Dave (team-b/male)
========================================
If no valid pair can be found, an error message is displayed and no changes are made.
Divides all eligible people into groups of N. Replace N with any integer ≥ 2.
> /group_3
========================================
Group Results (size: 3)
========================================
Group 1 [3]: Alice, Dave, Frank
Group 2 [3]: Bob, Carol, Eve
Group 3 [2]: Grace, Hank
========================================
| Remaining people | Behaviour |
|---|---|
Exactly N |
Forms a normal group of N |
| Between 2 and N−1 | Forms a smaller final group as-is |
| Exactly 1 | Merged into the last group (group becomes N+1) |
People blocked by the 14-day rule (C3) are skipped and noted in the output.
If no valid grouping is possible under the constraints, an error message is displayed and no changes are made.
If a workspace has exactly 2 members, those two people must be paired with someone from a different workspace.
If a workspace has 3 or fewer members of the same gender, those members cannot be paired with each other. They must be paired with:
- Someone from a different workspace, or
- Someone of a different gender in the same workspace
Anyone who appears in a couple or group record within the last 14 days cannot participate in any new pairing or grouping until the cooldown expires.
The blocked list is recomputed from all records every time /couple or /group_N is run.
If no valid pairing or grouping is possible after applying all constraints, the command outputs an error and does nothing.
- Generate all possible combinations of 2 people from the registered list.
- Filter out combinations that violate any active constraint (C1, C2, C3).
- Pick one combination at random from the remaining valid pairs.
- If no valid pair exists, report failure without making any changes.
> /clear
Cleared 2 couple record(s) and 1 group record(s) (total: 3).
Remaining: 1 couple record(s), 0 group record(s).
Removes all couple and group records whose timestamp is older than 14 days.
- If no records have expired, a message is displayed and nothing is changed.
- Changes take effect in memory immediately and are saved to
dataon/quit.
When you type /quit, all people and couple history are saved to a file named data in the working directory (JSON format).
When the program starts, it checks for a data file. If the file exists and its structure is valid, the data is loaded into memory automatically.
{
"people": [
{ "name": "Alice", "gender": "female", "workspace": "team-a" }
],
"couples": [
{
"person1": "Alice",
"person2": "Bob",
"coupled_at": "2026-05-08T11:30:00+09:00"
}
]
}The
datafile is listed in.gitignoreand will not be committed to version control.
The application itself does not require external gems at runtime, but this repository includes RSpec for automated tests.
bundle install
bundle exec rspecIf the rspec executable is not resolved correctly in your environment, you can run the test suite directly with Ruby:
ruby -rrspec/core -e 'exit RSpec::Core::Runner.run(["spec"])'Current test coverage includes:
- interactive add flow
- list output
- couple generation
- group generation
- constraint logic
- expired record cleanup
- reset commands
random-coupler/
├── coupler.rb # Main program
├── run.sh # Launcher for macOS/Linux (auto-installs Ruby 2.6 if missing)
├── run.bat # Launcher for Windows (Ruby must be pre-installed)
├── Gemfile # Development/test dependency definition
├── .gitignore # Git ignore rules
├── README.md # This file (English)
├── README_KR.md # Korean version
├── functions/
│ ├── fn_add.rb
│ ├── fn_clear.rb
│ ├── fn_constraints.rb
│ ├── fn_couple.rb
│ ├── fn_group.rb
│ ├── fn_init_couples.rb
│ ├── fn_init_groups.rb
│ ├── fn_init_people.rb
│ └── fn_list.rb
└── spec/
├── spec_helper.rb
└── functions/
├── fn_add_spec.rb
├── fn_clear_spec.rb
├── fn_constraints_spec.rb
├── fn_couple_spec.rb
├── fn_group_spec.rb
├── fn_init_couples_spec.rb
├── fn_init_groups_spec.rb
├── fn_init_people_spec.rb
└── fn_list_spec.rb
This project is released under the MIT License.