random_name_generator 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0"
5
+ end
@@ -1,24 +1,35 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/random_name_generator/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'random_name_generator'
7
- spec.version = '1.0.1'
8
- spec.authors = ['folkengine']
9
- spec.email = ['gaoler@electronicpanopticon.com']
10
- 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"
11
20
 
12
- spec.summary = 'Random Name Generator'
13
- spec.description = 'Generates random names based upon custom collections of syllables. Styles include Elvish, Fantasy, Goblin, and Roman'
14
- 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"]
15
29
 
16
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = 'exe'
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
- spec.require_paths = ['lib']
30
+ # Uncomment to register a new dependency of your gem
31
+ # spec.add_dependency "example-gem", "~> 1.0"
20
32
 
21
- spec.required_ruby_version = '>= 2.1.5'
22
- spec.add_development_dependency 'bundler', '~> 1.11'
23
- 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
24
35
  end