random_name_generator 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  - - ">="