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.
@@ -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
@@ -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
+ +тин
@@ -1,2 +1,150 @@
1
- require File.join(File.dirname(__FILE__), 'random_name_generator', 'random_name_generator')
2
- require File.join(File.dirname(__FILE__), 'random_name_generator', 'rng_syllable')
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RandomNameGenerator
4
+ VERSION = "2.0.1"
5
+ end
@@ -1,23 +1,35 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
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 = 'random_name_generator'
6
- spec.version = '1.0.3'
7
- spec.authors = ['folkengine']
8
- spec.email = ['gaoler@electronicpanopticon.com']
9
- spec.licenses = ['GPL-3.0']
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
- 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'
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
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
- spec.bindir = 'exe'
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
- spec.required_ruby_version = '>= 2.2'
21
- spec.add_development_dependency 'bundler', '~> 1.11'
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