random_name_generator 1.2.2 → 2.0.0

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.
@@ -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,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.2.2'
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. Has Englich(default) and Cyrillic modes.'
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.5'
21
- spec.add_development_dependency 'bundler'
22
- spec.add_development_dependency 'rake'
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
metadata CHANGED
@@ -1,48 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: random_name_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - folkengine
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-28 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
11
+ date: 2021-03-29 00:00:00.000000000 Z
12
+ dependencies: []
41
13
  description: Generates random names based upon custom collections of syllables. Styles
42
- include Elvish, Fantasy, Goblin, and Roman. Has Englich(default) and Cyrillic modes.
14
+ include Elvish, Fantasy, Goblin, and Roman.
43
15
  email:
44
16
  - gaoler@electronicpanopticon.com
45
- executables: []
17
+ executables:
18
+ - random_name_generator
46
19
  extensions: []
47
20
  extra_rdoc_files: []
48
21
  files:
@@ -51,33 +24,41 @@ files:
51
24
  - ".github/workflows/ruby.yml"
52
25
  - ".gitignore"
53
26
  - ".overcommit.yml"
27
+ - ".rspec"
54
28
  - ".rubocop.yml"
29
+ - CHANGELOG.md
55
30
  - Gemfile
56
31
  - Gemfile.lock
57
32
  - LICENSE
58
33
  - README.md
59
34
  - Rakefile
60
35
  - bin/console
61
- - bin/random_name_generator
36
+ - bin/run
62
37
  - bin/setup
63
38
  - config.reek
39
+ - exe/random_name_generator
40
+ - lib/languages/demonic.txt
41
+ - lib/languages/elven-ru.txt
42
+ - lib/languages/elven.txt
43
+ - lib/languages/experimental/curse.txt
44
+ - lib/languages/experimental/demonic.txt
45
+ - lib/languages/fantasy-ru.txt
46
+ - lib/languages/fantasy.txt
47
+ - lib/languages/goblin-ru.txt
48
+ - lib/languages/goblin.txt
49
+ - lib/languages/roman-ru.txt
50
+ - lib/languages/roman.txt
64
51
  - lib/random_name_generator.rb
65
- - lib/random_name_generator/languages/demonic.txt
66
- - lib/random_name_generator/languages/elven-ru.txt
67
- - lib/random_name_generator/languages/elven.txt
68
- - lib/random_name_generator/languages/fantasy-ru.txt
69
- - lib/random_name_generator/languages/fantasy.txt
70
- - lib/random_name_generator/languages/goblin-ru.txt
71
- - lib/random_name_generator/languages/goblin.txt
72
- - lib/random_name_generator/languages/roman-ru.txt
73
- - lib/random_name_generator/languages/roman.txt
74
- - lib/random_name_generator/random_name_generator.rb
75
- - lib/random_name_generator/rng_syllable.rb
52
+ - lib/random_name_generator/syllable.rb
53
+ - lib/random_name_generator/version.rb
76
54
  - random_name_generator.gemspec
77
55
  homepage: https://github.com/folkengine/random_name_generator
78
56
  licenses:
79
- - GPL-3.0
80
- metadata: {}
57
+ - LGPL-3.0
58
+ metadata:
59
+ homepage_uri: https://github.com/folkengine/random_name_generator
60
+ source_code_uri: https://github.com/folkengine/random_name_generator
61
+ changelog_uri: https://github.com/folkengine/random_name_generator/CHANGELOG.md
81
62
  post_install_message:
82
63
  rdoc_options: []
83
64
  require_paths:
@@ -86,7 +67,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
67
  requirements:
87
68
  - - ">="
88
69
  - !ruby/object:Gem::Version
89
- version: '2.5'
70
+ version: 2.5.0
90
71
  required_rubygems_version: !ruby/object:Gem::Requirement
91
72
  requirements:
92
73
  - - ">="