aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2020-12-08 02:53:10 +0900
committernsfisis <nsfisis@gmail.com>2020-12-08 02:55:44 +0900
commitf9f462cd2feb811891fe4e4919534cbdb6dcba2c (patch)
treeecb670b0242daa7e7e1df77c146f3881c3e075e8
downloadrand-word-gen-f9f462cd2feb811891fe4e4919534cbdb6dcba2c.tar.gz
rand-word-gen-f9f462cd2feb811891fe4e4919534cbdb6dcba2c.tar.zst
rand-word-gen-f9f462cd2feb811891fe4e4919534cbdb6dcba2c.zip
first commit
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock191
-rw-r--r--Cargo.toml12
-rw-r--r--LICENSE-MIT21
-rw-r--r--README.md56
-rw-r--r--build.rs46
-rw-r--r--src/lib.rs32
-rw-r--r--src/main.rs41
8 files changed, 400 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..d3c194f
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,191 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand-word-gen"
+version = "1.0.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "rand",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..49ad710
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "rand-word-gen"
+version = "1.0.0"
+authors = ["nsfisis"]
+edition = "2018"
+description = "Generates random pseudo-English words."
+license = "MIT"
+
+[dependencies]
+anyhow = "1.0.34"
+clap = "2.33.3"
+rand = "0.7.3"
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..bcfcb41
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 nsfisis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1cbb290
--- /dev/null
+++ b/README.md
@@ -0,0 +1,56 @@
+# Random word generator
+
+Generates random pseudo-English words. It is mainly for naming your hobby projects in a moment.
+
+It internally uses "Markov chain" to generate words. The chain model is built in a compiling phase of the tool, referring to `words` file (`/usr/share/dict/words`).
+
+## Usage
+
+```
+$ rand-word-gen
+eendo
+ddips
+uphr
+blinta
+unto
+ont
+vedaro
+dera
+ekarrb
+goice
+sfodo
+ainis
+rier
+fatem
+myimd
+grasic
+honge
+ustoge
+ear
+nal
+
+# Sets a number of generated words.
+$ rand-word-gen -n 5
+piva
+ors
+glo
+mapt
+blclyp
+```
+
+See `rand-word-gen --help` for details.
+
+## Build
+
+```
+$ cargo build --release
+```
+
+## TODO
+
+* Pass a custom words file at runtime.
+* Specify length of generated words.
+
+## License
+
+MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..dcf1cc3
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,46 @@
+use std::fs::File;
+use std::io::{BufRead, BufReader, BufWriter, Result, Write};
+use std::path::Path;
+
+const NUM_LETTERS: usize = 26;
+
+fn main() -> Result<()> {
+ let chars = {
+ let file = File::open("/usr/share/dict/words")?;
+ let reader = BufReader::new(file);
+ parse(reader)?
+ };
+
+ let out_path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("prebuilt_model.rs");
+ let file = File::create(out_path)?;
+ let mut writer = BufWriter::new(file);
+ writeln!(writer, "[")?;
+ for i in 0..(NUM_LETTERS + 1) {
+ write!(writer, "[")?;
+ for j in 0..(NUM_LETTERS + 1) {
+ write!(writer, "{},", chars[i][j])?;
+ }
+ writeln!(writer, "],")?;
+ }
+ writeln!(writer, "]")?;
+
+ Ok(())
+}
+
+fn parse(r: BufReader<File>) -> Result<[[usize; NUM_LETTERS + 1]; NUM_LETTERS + 1]> {
+ let mut chars = [[0; NUM_LETTERS + 1]; NUM_LETTERS + 1];
+ for line in r.lines() {
+ let word = line?;
+ let mut prefix = NUM_LETTERS;
+ for c in word.bytes() {
+ let c = c.to_ascii_lowercase();
+ if !c.is_ascii_lowercase() {
+ continue;
+ }
+ let i = (c - b'a') as usize;
+ chars[prefix][i] += 1;
+ prefix = i;
+ }
+ }
+ Ok(chars)
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..db8020e
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,32 @@
+use rand::distributions::{Distribution, WeightedIndex};
+use rand::RngCore;
+
+const NUM_OF_LETTERS: usize = 26;
+
+pub struct Model {
+ chars: [[usize; NUM_OF_LETTERS + 1]; NUM_OF_LETTERS + 1],
+}
+
+impl Model {
+ pub fn new() -> Model {
+ let chars = include!(concat!(env!("OUT_DIR"), "/prebuilt_model.rs"));
+ Model { chars }
+ }
+
+ pub fn generate<Rng: RngCore>(&self, rng: &mut Rng, len: usize) -> String {
+ let mut result = String::with_capacity(len);
+ let mut prefix = NUM_OF_LETTERS;
+ for _ in 0..len {
+ let chars = &self.chars[prefix];
+ let c = select_one_char(rng, &chars);
+ result.push(c as char);
+ prefix = (c - b'a') as usize;
+ }
+ result
+ }
+}
+
+fn select_one_char<Rng: RngCore>(rng: &mut Rng, freq: &[usize; NUM_OF_LETTERS + 1]) -> u8 {
+ let dist = WeightedIndex::new(freq).expect("invalid frequency");
+ b'a' + (dist.sample(rng) as u8)
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..4ebe0fa
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,41 @@
+use anyhow::{Context, Result};
+use rand::distributions::{Distribution, Uniform};
+use rand_word_gen::Model;
+use std::io::{BufWriter, Write};
+
+fn main() -> Result<()> {
+ let words = parse_args()?;
+
+ let model = Model::new();
+ let out = std::io::stdout();
+ let mut out = BufWriter::new(out.lock());
+ let mut rng = rand::thread_rng();
+ let dist = Uniform::from(3..=6);
+ for _ in 0..words {
+ let len = dist.sample(&mut rng);
+ writeln!(out, "{}", model.generate(&mut rng, len))?;
+ }
+
+ Ok(())
+}
+
+fn parse_args() -> Result<usize> {
+ use clap::{crate_description, crate_version, value_t, App, Arg};
+
+ let matches = App::new("rand-word-gen")
+ .version(crate_version!())
+ .version_short("v")
+ .about(crate_description!())
+ .arg(
+ Arg::with_name("words")
+ .short("n")
+ .long("words")
+ .value_name("NUMBER_OF_WORDS")
+ .default_value("20")
+ .help("Sets number of generated words"),
+ )
+ .get_matches();
+
+ let words = value_t!(matches, "words", usize).context("'--words' must be a number")?;
+ Ok(words)
+}