random_name_generator 1.0.3 → 2.0.1
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/.github/workflows/ruby.yml +22 -0
- data/.gitignore +3 -2
- data/.rspec +3 -0
- data/.rubocop.yml +15 -22
- data/CHANGELOG.md +16 -0
- data/Gemfile +13 -13
- data/Gemfile.lock +67 -105
- data/LICENSE +160 -669
- data/README.md +68 -43
- data/Rakefile +10 -19
- data/bin/console +5 -6
- data/bin/run +3 -0
- data/exe/random_name_generator +43 -0
- data/lib/{random_name_generator/languages → languages}/demonic.txt +19 -11
- data/lib/languages/elven-ru.txt +84 -0
- data/lib/{random_name_generator/languages → languages}/elven.txt +0 -0
- data/lib/languages/experimental/curse.txt +63 -0
- data/lib/languages/experimental/demonic.txt +350 -0
- data/lib/languages/fantasy-ru.txt +356 -0
- data/lib/{random_name_generator/languages → languages}/fantasy.txt +0 -0
- data/lib/languages/goblin-ru.txt +48 -0
- data/lib/{random_name_generator/languages → languages}/goblin.txt +0 -0
- data/lib/languages/roman-ru.txt +35 -0
- data/lib/{random_name_generator/languages → languages}/roman.txt +0 -0
- data/lib/random_name_generator.rb +150 -2
- data/lib/random_name_generator/syllable.rb +181 -0
- data/lib/random_name_generator/version.rb +5 -0
- data/random_name_generator.gemspec +29 -17
- metadata +34 -50
- data/.travis.yml +0 -4
- data/bin/random_name_generator +0 -27
- data/lib/random_name_generator/random_name_generator.rb +0 -107
- data/lib/random_name_generator/rng_syllable.rb +0 -175
File without changes
|
@@ -0,0 +1,48 @@
|
|
1
|
+
-ваа +c
|
2
|
+
-боо +c
|
3
|
+
-гар
|
4
|
+
-бар
|
5
|
+
-дар
|
6
|
+
-жар
|
7
|
+
-вар
|
8
|
+
-кра
|
9
|
+
-гра
|
10
|
+
-дра
|
11
|
+
-зра
|
12
|
+
-гоб
|
13
|
+
-доб
|
14
|
+
-роб
|
15
|
+
-фоб
|
16
|
+
-зоб
|
17
|
+
-раг
|
18
|
+
-наг
|
19
|
+
-даг
|
20
|
+
бра
|
21
|
+
га
|
22
|
+
да
|
23
|
+
до
|
24
|
+
го
|
25
|
+
зе
|
26
|
+
ша
|
27
|
+
наз
|
28
|
+
зуб
|
29
|
+
зу
|
30
|
+
на
|
31
|
+
гор
|
32
|
+
бу +c
|
33
|
+
+быр
|
34
|
+
+гыр
|
35
|
+
+дыр
|
36
|
+
+выр
|
37
|
+
+зыр
|
38
|
+
+ыр -c
|
39
|
+
+зог
|
40
|
+
+рог
|
41
|
+
+гог
|
42
|
+
+ог -c
|
43
|
+
+гул
|
44
|
+
+дул
|
45
|
+
+бул
|
46
|
+
+рул
|
47
|
+
+ул -c
|
48
|
+
+ргх -v
|
File without changes
|
@@ -0,0 +1,35 @@
|
|
1
|
+
-а
|
2
|
+
-ал
|
3
|
+
-ау +c
|
4
|
+
-ан
|
5
|
+
-ба
|
6
|
+
-бе
|
7
|
+
-би
|
8
|
+
-бр +v
|
9
|
+
-да
|
10
|
+
-ди
|
11
|
+
-до
|
12
|
+
-ду
|
13
|
+
-е
|
14
|
+
-эу +c
|
15
|
+
-фа
|
16
|
+
би
|
17
|
+
бе
|
18
|
+
бо
|
19
|
+
бу
|
20
|
+
нул +v
|
21
|
+
гу
|
22
|
+
да
|
23
|
+
ау +c -c
|
24
|
+
фри
|
25
|
+
гус
|
26
|
+
+тус
|
27
|
+
+лус
|
28
|
+
+лиус
|
29
|
+
+нус
|
30
|
+
+эс
|
31
|
+
+иус -c
|
32
|
+
+кус
|
33
|
+
+тор
|
34
|
+
+цио
|
35
|
+
+тин
|
File without changes
|
@@ -1,2 +1,150 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "random_name_generator/version"
|
4
|
+
require_relative "random_name_generator/syllable"
|
5
|
+
|
6
|
+
# RandomNameGenerator:
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# rng = RandomNameGenerator::Generator.new(RandomNameGenerator::GOBLIN)
|
11
|
+
# puts rng.compose(3)
|
12
|
+
#
|
13
|
+
# By default RandomNameGenerator uses the Fantasy syllable file and creates a name with between 2 and 5 syllables.
|
14
|
+
#
|
15
|
+
# rng = RandomNameGenerator::Generator.new
|
16
|
+
# puts rng.compose
|
17
|
+
#
|
18
|
+
# :reek:TooManyConstants
|
19
|
+
# :reek:TooManyInstanceVariables
|
20
|
+
# :reek:TooManyStatements
|
21
|
+
module RandomNameGenerator
|
22
|
+
dirname = File.dirname(__FILE__)
|
23
|
+
|
24
|
+
ELVEN = File.new("#{dirname}/languages/elven.txt")
|
25
|
+
FANTASY = File.new("#{dirname}/languages/fantasy.txt")
|
26
|
+
GOBLIN = File.new("#{dirname}/languages/goblin.txt")
|
27
|
+
ROMAN = File.new("#{dirname}/languages/roman.txt")
|
28
|
+
|
29
|
+
ELVEN_RU = File.new("#{dirname}/languages/elven-ru.txt")
|
30
|
+
FANTASY_RU = File.new("#{dirname}/languages/fantasy-ru.txt")
|
31
|
+
GOBLIN_RU = File.new("#{dirname}/languages/goblin-ru.txt")
|
32
|
+
ROMAN_RU = File.new("#{dirname}/languages/roman-ru.txt")
|
33
|
+
|
34
|
+
# Experimental
|
35
|
+
CURSE = File.new("#{dirname}/languages/experimental/curse.txt")
|
36
|
+
|
37
|
+
# Static factory method that instantiates a RandomNameGenerator in a random language.
|
38
|
+
def self.flip_mode
|
39
|
+
langs = [RandomNameGenerator::FANTASY,
|
40
|
+
RandomNameGenerator::ELVEN,
|
41
|
+
RandomNameGenerator::GOBLIN,
|
42
|
+
RandomNameGenerator::ROMAN]
|
43
|
+
Generator.new(langs.sample)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Static factory method that instantiates a RandomNameGenerator in a random
|
47
|
+
# Cyrillic based language.
|
48
|
+
def self.flip_mode_cyrillic
|
49
|
+
langs = [RandomNameGenerator::FANTASY_RU,
|
50
|
+
RandomNameGenerator::ELVEN_RU,
|
51
|
+
RandomNameGenerator::GOBLIN_RU,
|
52
|
+
RandomNameGenerator::ROMAN_RU]
|
53
|
+
Generator.new(langs.sample)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.pick_number_of_syllables(random: Random.new)
|
57
|
+
[2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5].sample(random: random)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Static factory method for the Generator class.
|
61
|
+
def self.new(language = RandomNameGenerator::FANTASY, random: Random.new)
|
62
|
+
Generator.new(language, random: random)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Generator
|
66
|
+
#
|
67
|
+
# Workhorse class that assembles names from dialect files.
|
68
|
+
#
|
69
|
+
class Generator
|
70
|
+
attr_reader :language, :pre_syllables, :sur_syllables, :mid_syllables
|
71
|
+
|
72
|
+
def initialize(language = RandomNameGenerator::FANTASY, random: Random.new)
|
73
|
+
@pre = nil
|
74
|
+
@language = language
|
75
|
+
@rnd = random
|
76
|
+
@pre_syllables = []
|
77
|
+
@mid_syllables = []
|
78
|
+
@sur_syllables = []
|
79
|
+
|
80
|
+
refresh
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns the composed name as an array of Syllables.
|
84
|
+
def compose_array(count = RandomNameGenerator.pick_number_of_syllables)
|
85
|
+
@pre = pre_syllables.sample(random: @rnd)
|
86
|
+
return @pre.to_s.capitalize if count < 2
|
87
|
+
|
88
|
+
name = determine_middle_syllables(count - 2, @pre)
|
89
|
+
name << determine_last_syllable(name.last)
|
90
|
+
name
|
91
|
+
end
|
92
|
+
|
93
|
+
def compose(count = RandomNameGenerator.pick_number_of_syllables)
|
94
|
+
compose_array(count).map(&:to_s).join.capitalize
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_s
|
98
|
+
"RandomNameGenerator::Generator (#{@language.path.split("/")[-1]})"
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def determine_middle_syllables(count, pre)
|
104
|
+
determine_next_syllables(count, pre, @mid_syllables)
|
105
|
+
end
|
106
|
+
|
107
|
+
def determine_last_syllable(next_to_last_syllable)
|
108
|
+
determine_next_syllable(next_to_last_syllable, @sur_syllables)
|
109
|
+
end
|
110
|
+
|
111
|
+
def determine_next_syllables(count, pre, syllables)
|
112
|
+
name = Array(pre)
|
113
|
+
return name if count < 1
|
114
|
+
|
115
|
+
next_syllable = pre
|
116
|
+
count.times do
|
117
|
+
next_syllable = determine_next_syllable(next_syllable, syllables)
|
118
|
+
name << next_syllable
|
119
|
+
end
|
120
|
+
name
|
121
|
+
end
|
122
|
+
|
123
|
+
def determine_next_syllable(this_syllable, sampler)
|
124
|
+
next_syllable = ""
|
125
|
+
loop do
|
126
|
+
next_syllable = sampler.sample(random: @rnd)
|
127
|
+
break unless this_syllable.incompatible?(next_syllable)
|
128
|
+
end
|
129
|
+
next_syllable
|
130
|
+
end
|
131
|
+
|
132
|
+
# Loops through the language file, and pushes each syllable into the correct array.
|
133
|
+
def refresh
|
134
|
+
@language.readlines.each do |line|
|
135
|
+
push(RandomNameGenerator::Syllable.new(line)) unless line.empty?
|
136
|
+
end
|
137
|
+
@language.rewind
|
138
|
+
end
|
139
|
+
|
140
|
+
def push(syllable)
|
141
|
+
if syllable.prefix?
|
142
|
+
@pre_syllables.push(syllable)
|
143
|
+
elsif syllable.suffix?
|
144
|
+
@sur_syllables.push(syllable)
|
145
|
+
else
|
146
|
+
@mid_syllables.push(syllable)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RandomNameGenerator
|
4
|
+
# Syllable: Class for managing properties of individual syllables with in language name file. Each line within a file
|
5
|
+
# translates into a syllable object. The reason behind this class is to take over most of the complexity of parsing each
|
6
|
+
# syllable, greatly simplifying the work done by RandomNameGenerator. This code is not meant to be called directly as a
|
7
|
+
# part of standard usage.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# syllable = Syllable.new('-foo +c')
|
12
|
+
#
|
13
|
+
# This creates a foo syllable object that needs to be the first syllable and followed by a constant.
|
14
|
+
#
|
15
|
+
# For testing purposes, passing in another Syllable object will create a clone:
|
16
|
+
#
|
17
|
+
# syllable_clone = Syllable.new(syllable)
|
18
|
+
#
|
19
|
+
# SYLLABLE CLASSIFICATION:
|
20
|
+
# Name is usually composed from 3 different class of syllables, which include prefix, middle part and suffix.
|
21
|
+
# To declare syllable as a prefix in the file, insert "-" as a first character of the line.
|
22
|
+
# To declare syllable as a suffix in the file, insert "+" as a first character of the line.
|
23
|
+
# everything else is read as a middle part.
|
24
|
+
#
|
25
|
+
# NUMBER OF SYLLABLES:
|
26
|
+
# Names may have any positive number of syllables. In case of 2 syllables, name will be composed from prefix and suffix.
|
27
|
+
# In case of 1 syllable, name will be chosen from amongst the prefixes.
|
28
|
+
# In case of 3 and more syllables, name will begin with prefix, is filled with middle parts and ended with suffix.
|
29
|
+
#
|
30
|
+
# ASSIGNING RULES:
|
31
|
+
# I included a way to set 4 kind of rules for every syllable. To add rules to the syllables, write them right after the
|
32
|
+
# syllable and SEPARATE WITH WHITESPACE. (example: "aad +v -c"). The order of rules is not important.
|
33
|
+
#
|
34
|
+
# RULES:
|
35
|
+
# 1) +v means that next syllable must definitely start with a vowel.
|
36
|
+
# 2) +c means that next syllable must definitely start with a consonant.
|
37
|
+
# 3) -v means that this syllable can only be added to another syllable, that ends with a vowel.
|
38
|
+
# 4) -c means that this syllable can only be added to another syllable, that ends with a consonant.
|
39
|
+
#
|
40
|
+
# :reek:TooManyMethods
|
41
|
+
# :reek:TooManyInstanceVariables
|
42
|
+
class Syllable
|
43
|
+
attr_reader :raw, :syllable, :next_syllable_requirement, :previous_syllable_requirement
|
44
|
+
|
45
|
+
VOWELS = %w[i y ɨ ʉ ɯ u ɪ ʏ ʊ ɯ ʊ e ø ɘ ɵ ɤ o ø ə ɵ ɤ o ɛ œ ɜ ɞ ʌ ɔ æ ɐ ɞ a ɶ ä ɒ ɑ].freeze
|
46
|
+
CONSONANTS = %w[b ɓ ʙ β c d ɗ ɖ ð f g h j k l ł m ɱ n ɳ p q r s t v w x y z].freeze
|
47
|
+
|
48
|
+
def initialize(args)
|
49
|
+
@raw = args.strip
|
50
|
+
@syllable = ""
|
51
|
+
@is_prefix = false
|
52
|
+
@is_suffix = false
|
53
|
+
@next_syllable_requirement = :letter
|
54
|
+
@previous_syllable_requirement = :letter
|
55
|
+
|
56
|
+
if args.is_a?(Syllable)
|
57
|
+
parse_args(args.raw)
|
58
|
+
else
|
59
|
+
parse_args(args)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def incompatible?(next_syllable)
|
64
|
+
(next_incompatible?(next_syllable) || previous_incompatible?(next_syllable))
|
65
|
+
end
|
66
|
+
|
67
|
+
def compatible?(next_syllable)
|
68
|
+
!incompatible?(next_syllable)
|
69
|
+
end
|
70
|
+
|
71
|
+
def prefix?
|
72
|
+
@is_prefix
|
73
|
+
end
|
74
|
+
|
75
|
+
def suffix?
|
76
|
+
@is_suffix
|
77
|
+
end
|
78
|
+
|
79
|
+
def consonant_first?
|
80
|
+
CONSONANTS.include?(syllable[0])
|
81
|
+
end
|
82
|
+
|
83
|
+
def vowel_first?
|
84
|
+
VOWELS.include?(syllable[0])
|
85
|
+
end
|
86
|
+
|
87
|
+
def consonant_last?
|
88
|
+
CONSONANTS.include?(syllable[-1])
|
89
|
+
end
|
90
|
+
|
91
|
+
def vowel_last?
|
92
|
+
VOWELS.include?(syllable[-1])
|
93
|
+
end
|
94
|
+
|
95
|
+
def next_syllable_universal?
|
96
|
+
@next_syllable_requirement == :letter
|
97
|
+
end
|
98
|
+
|
99
|
+
def next_syllable_must_start_with_vowel?
|
100
|
+
@next_syllable_requirement == :vowel
|
101
|
+
end
|
102
|
+
|
103
|
+
def next_syllable_must_start_with_consonant?
|
104
|
+
@next_syllable_requirement == :consonant
|
105
|
+
end
|
106
|
+
|
107
|
+
def previous_syllable_universal?
|
108
|
+
@previous_syllable_requirement == :letter
|
109
|
+
end
|
110
|
+
|
111
|
+
def previous_syllable_must_end_with_vowel?
|
112
|
+
@previous_syllable_requirement == :vowel
|
113
|
+
end
|
114
|
+
|
115
|
+
def previous_syllable_must_end_with_consonant?
|
116
|
+
@previous_syllable_requirement == :consonant
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
@syllable
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_str
|
124
|
+
@syllable
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# :reek:FeatureEnvy
|
130
|
+
def parse_args(args)
|
131
|
+
args = args.to_s.strip.downcase.split
|
132
|
+
parse_syllable(args[0])
|
133
|
+
parse_flags(args[1..-1])
|
134
|
+
end
|
135
|
+
|
136
|
+
def parse_syllable(syll)
|
137
|
+
raise ArgumentError "Empty String is not allowed." if syll.empty?
|
138
|
+
|
139
|
+
captures = /([+-]?)(.+)/.match(syll).captures
|
140
|
+
parse_prefix(captures[0])
|
141
|
+
@syllable = captures[1]
|
142
|
+
end
|
143
|
+
|
144
|
+
# :reek:ControlParameter
|
145
|
+
def parse_prefix(prefix)
|
146
|
+
case prefix
|
147
|
+
when "-"
|
148
|
+
@is_prefix = true
|
149
|
+
when "+"
|
150
|
+
@is_suffix = true
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def parse_flags(flags)
|
155
|
+
if flags.include?("+v")
|
156
|
+
@next_syllable_requirement = :vowel
|
157
|
+
elsif flags.include?("+c")
|
158
|
+
@next_syllable_requirement = :consonant
|
159
|
+
end
|
160
|
+
if flags.include?("-v")
|
161
|
+
@previous_syllable_requirement = :vowel
|
162
|
+
elsif flags.include?("-c")
|
163
|
+
@previous_syllable_requirement = :consonant
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def next_incompatible?(next_syllable)
|
168
|
+
vnc = (next_syllable_must_start_with_vowel? && next_syllable.consonant_first?)
|
169
|
+
cnv = (next_syllable_must_start_with_consonant? && next_syllable.vowel_first?)
|
170
|
+
|
171
|
+
(vnc || cnv)
|
172
|
+
end
|
173
|
+
|
174
|
+
def previous_incompatible?(next_syllable)
|
175
|
+
vlc = (vowel_last? && next_syllable.previous_syllable_must_end_with_consonant?)
|
176
|
+
clv = (consonant_last? && next_syllable.previous_syllable_must_end_with_vowel?)
|
177
|
+
|
178
|
+
(vlc || clv)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -1,23 +1,35 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/random_name_generator/version"
|
3
4
|
|
4
5
|
Gem::Specification.new do |spec|
|
5
|
-
spec.name =
|
6
|
-
spec.version =
|
7
|
-
spec.authors = [
|
8
|
-
spec.email = [
|
9
|
-
|
6
|
+
spec.name = "random_name_generator"
|
7
|
+
spec.version = RandomNameGenerator::VERSION
|
8
|
+
spec.authors = ["folkengine"]
|
9
|
+
spec.email = ["gaoler@electronicpanopticon.com"]
|
10
|
+
|
11
|
+
spec.summary = "Random Name Generator"
|
12
|
+
spec.description = "Generates random names based upon custom collections of syllables. Styles include Elvish, Fantasy, Goblin, and Roman."
|
13
|
+
spec.homepage = "https://github.com/folkengine/random_name_generator"
|
14
|
+
spec.license = "LGPL-3.0"
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/folkengine/random_name_generator"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/folkengine/random_name_generator/CHANGELOG.md"
|
10
20
|
|
11
|
-
|
12
|
-
|
13
|
-
spec.
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
14
29
|
|
15
|
-
|
16
|
-
spec.
|
17
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
-
spec.require_paths = ['lib']
|
30
|
+
# Uncomment to register a new dependency of your gem
|
31
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
19
32
|
|
20
|
-
|
21
|
-
|
22
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
33
|
+
# For more information and examples about making a new gem, checkout our
|
34
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
23
35
|
end
|