dunmanifestin 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/dunmanifestin +49 -0
- data/lib/dunmanifestin.rb +11 -0
- data/lib/dunmanifestin/custom_inflections.rb +5 -0
- data/lib/dunmanifestin/generator.rb +46 -0
- data/lib/dunmanifestin/list.rb +30 -0
- data/lib/dunmanifestin/list_loader.rb +46 -0
- data/lib/dunmanifestin/manifestation.rb +30 -0
- data/lib/dunmanifestin/member.rb +18 -0
- data/lib/dunmanifestin/phrase.rb +198 -0
- data/lib/dunmanifestin/string.rb +38 -0
- data/lists/default/activated +12 -0
- data/lists/default/adverb +13 -0
- data/lists/default/ageGroup +5 -0
- data/lists/default/alienName +33 -0
- data/lists/default/alignment +10 -0
- data/lists/default/animal +30 -0
- data/lists/default/appearance +33 -0
- data/lists/default/attitude +17 -0
- data/lists/default/bag +4 -0
- data/lists/default/baggage +29 -0
- data/lists/default/baseItem +47 -0
- data/lists/default/buildingType +11 -0
- data/lists/default/clothing +7 -0
- data/lists/default/color +41 -0
- data/lists/default/container +7 -0
- data/lists/default/curse +10 -0
- data/lists/default/denizen +3 -0
- data/lists/default/denizenDetail +6 -0
- data/lists/default/description +3 -0
- data/lists/default/desire +26 -0
- data/lists/default/disability +8 -0
- data/lists/default/disease +10 -0
- data/lists/default/economy +11 -0
- data/lists/default/encounter +2409 -0
- data/lists/default/englishName +230 -0
- data/lists/default/epithet +13 -0
- data/lists/default/facet +17 -0
- data/lists/default/facetOfCulture +3 -0
- data/lists/default/family +5 -0
- data/lists/default/fear +30 -0
- data/lists/default/finnishName +81 -0
- data/lists/default/foodOrDrink +19 -0
- data/lists/default/geologicalFormation +14 -0
- data/lists/default/greenlandicName +43 -0
- data/lists/default/grossBodyPart +8 -0
- data/lists/default/group +6 -0
- data/lists/default/hardMaterial +6 -0
- data/lists/default/height +4 -0
- data/lists/default/japaneseName +202 -0
- data/lists/default/jewelery +13 -0
- data/lists/default/koboldName +68 -0
- data/lists/default/latinName +40 -0
- data/lists/default/magicItemDescription +24 -0
- data/lists/default/material +3 -0
- data/lists/default/metal +3 -0
- data/lists/default/mineral +3 -0
- data/lists/default/monster +160 -0
- data/lists/default/name +86 -0
- data/lists/default/namePrefix +30 -0
- data/lists/default/nameSuffix +18 -0
- data/lists/default/negativeAdverb +6 -0
- data/lists/default/negativeQuality +19 -0
- data/lists/default/neutralQuality +14 -0
- data/lists/default/nonPreciousMetal +6 -0
- data/lists/default/object +5 -0
- data/lists/default/person +4 -0
- data/lists/default/personName +3 -0
- data/lists/default/personality +34 -0
- data/lists/default/place +10 -0
- data/lists/default/placeName +4 -0
- data/lists/default/placeSuffix +36 -0
- data/lists/default/positiveAdverb +5 -0
- data/lists/default/positiveQuality +12 -0
- data/lists/default/preciousMetal +4 -0
- data/lists/default/preciousStone +6 -0
- data/lists/default/profession +21 -0
- data/lists/default/province +3 -0
- data/lists/default/quality +4 -0
- data/lists/default/qualityWithAdverb +4 -0
- data/lists/default/race +11 -0
- data/lists/default/raceOrProfession +5 -0
- data/lists/default/reason +15 -0
- data/lists/default/resource +9 -0
- data/lists/default/root +6 -0
- data/lists/default/secret +9 -0
- data/lists/default/settlementDetail +6 -0
- data/lists/default/settlementType +7 -0
- data/lists/default/softMaterial +7 -0
- data/lists/default/structureDetail +8 -0
- data/lists/default/structureType +24 -0
- data/lists/default/superpower +6 -0
- data/lists/default/topicOfConversation +5 -0
- data/lists/default/weapon +149 -0
- data/lists/default/wearable +4 -0
- data/lists/default/wearableQuality +15 -0
- data/lists/default/weildable +10 -0
- data/lists/default/welshName +79 -0
- data/lists/huoquitlan/originalAnimal +250 -0
- data/lists/huoquitlan/originalDenizen +849 -0
- data/lists/huoquitlan/originalItemName +33 -0
- data/lists/huoquitlan/originalNPC +99 -0
- data/lists/huoquitlan/originalName +226 -0
- data/lists/hypotheticals/noun +373 -0
- data/lists/hypotheticals/root +15 -0
- data/lists/hypotheticals/transitiveVerb +628 -0
- data/lists/hypotheticals/verbs +653 -0
- data/lists/sophistry/root +269 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZGY3OWM3NzkwOWIwZmNjYjllYjlkMWUzMzIwOWE5ZmU2YzY5MDhkNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmZhYjIwYWYyOWU3ZjkzYWFmMGMyN2U1YzE3NDY4NmE2N2YwZGQzYQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDdjOGY5ODNiOTMyYzViNmIwNjUwN2RjNjViOTk4ZGQxYWEyMmQ2ZmM4NmY4
|
10
|
+
YjVlYmI0ZDRmNGRjNjBlYTdmNzU3N2Q0MmVhY2ViZmQyZjVjMDA0MmNkZDgx
|
11
|
+
MzI3MTAyODA4NWIwMTEzNDIwYmU4MzY1Zjg5NzFiYTJlNzIyYmY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
M2U3MWZmNjUwM2FhZWNlZjg1M2Y1M2VlZDA0MTdkNDhmMDRlNjQzNDAxM2Mx
|
14
|
+
N2EzNjg4ZTliOWEyMDQ3YzNjMTc1OWRjMDk4Yzk3NzA4NmZlNmFiNzhjMWMw
|
15
|
+
ZjI5MDJmNGM4YjU0OTc3MjEwZTc3M2VjMzA3ZDFkMDAzNjcxYWM=
|
data/bin/dunmanifestin
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dunmanifestin'
|
4
|
+
|
5
|
+
user_demands = Trollop::options do
|
6
|
+
opt :debug, "Display errors and logging", short: '-d'
|
7
|
+
opt :interactive, "Use an interactive command prompt", short: '-i'
|
8
|
+
opt :count, "Specify how many lines of output to generate at once", type: :integer, short: '-n'
|
9
|
+
opt :copy, "Copies manifestation into your clipboard", short: '-c'
|
10
|
+
opt :genre, "Specify a genre, e.g. '-g scifi'", type: :string, short: '-g', default: 'default'
|
11
|
+
opt :phrase, "Specify a phrase or list, e.g. 'The [animal] sat on the [article]' or '[weapon]'", type: :string, short: '-p', default: '[root]'
|
12
|
+
opt :chomp, "remove the trailing newline from the output", short: '-h'
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_from_prompt
|
16
|
+
print "dunmanifestin > "
|
17
|
+
gets.chomp
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
root_phrase_class = Class.new(Phrase) { list user_demands[:phrase] }
|
22
|
+
ListLoader.new(user_demands[:genre]).load
|
23
|
+
|
24
|
+
if user_demands[:interactive]
|
25
|
+
print "---------------------------------------------------------------------\n"+
|
26
|
+
"Type 'quit' to exit the prompt. Press return to generate more output.\n"+
|
27
|
+
"---------------------------------------------------------------------\n\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
fulltext = ""
|
31
|
+
|
32
|
+
while true
|
33
|
+
(user_demands[:count] || 1).times do
|
34
|
+
text = root_phrase_class.new.inspect
|
35
|
+
fulltext += "\n#{text}"
|
36
|
+
text += "\n" unless user_demands[:chomp]
|
37
|
+
print text
|
38
|
+
end
|
39
|
+
|
40
|
+
`echo #{fulltext.inspect} | pbcopy $1` if user_demands[:copy]
|
41
|
+
|
42
|
+
break if !user_demands[:interactive] || get_from_prompt == 'quit'
|
43
|
+
end
|
44
|
+
|
45
|
+
rescue => e
|
46
|
+
raise e if user_demands[:debug]
|
47
|
+
ensure
|
48
|
+
`rm #{user_demands[:genre]}.list 2>&1` unless user_demands[:debug]
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) # For dev/use when no gem is installed
|
2
|
+
|
3
|
+
require 'trollop'
|
4
|
+
require 'dunmanifestin/member.rb'
|
5
|
+
require 'dunmanifestin/list.rb'
|
6
|
+
require 'dunmanifestin/generator.rb'
|
7
|
+
require 'dunmanifestin/string.rb'
|
8
|
+
require 'dunmanifestin/custom_inflections.rb'
|
9
|
+
require 'dunmanifestin/phrase.rb'
|
10
|
+
require 'dunmanifestin/manifestation.rb'
|
11
|
+
require 'dunmanifestin/list_loader.rb'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Generator
|
2
|
+
def self.from_file path
|
3
|
+
new File.open(path).readlines.map(&:chomp).reject { |line| line.empty? }.unshift('root')
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize lines
|
7
|
+
lines.inject do |list, line|
|
8
|
+
create_or_append_list(list, line)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def lists
|
13
|
+
@lists ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate kind
|
17
|
+
kind = kind.to_s
|
18
|
+
list = lists[kind] || lists['|' + kind]
|
19
|
+
return "{#{kind}?}" unless list
|
20
|
+
list.sample.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def manifest phrase
|
24
|
+
phrase.to_s
|
25
|
+
#phrase.listerpolate(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing slug
|
29
|
+
generate slug
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def create_or_append_list list, line
|
35
|
+
if line.is_name?
|
36
|
+
list = List.new(name: line, universe: self)
|
37
|
+
else
|
38
|
+
list << line
|
39
|
+
end
|
40
|
+
|
41
|
+
list
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class NoSuchList < StandardError
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class List
|
2
|
+
attr_accessor :name
|
3
|
+
|
4
|
+
def initialize opts={}
|
5
|
+
@name = opts.fetch(:name, 'default')
|
6
|
+
@members = opts.fetch(:members, [])
|
7
|
+
@universe = opts.fetch(:universe)
|
8
|
+
@universe.lists[name] = self
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def << rough_member
|
13
|
+
pieces = rough_member.split('@')
|
14
|
+
|
15
|
+
weight = pieces.length > 1 ? pieces.shift.to_i : 1
|
16
|
+
|
17
|
+
attrs = {body: pieces.pop, list: self, universe: universe}
|
18
|
+
attrs.merge!(frequency: pieces.pop) if pieces.any?
|
19
|
+
member = Member.new(attrs)
|
20
|
+
|
21
|
+
weight.times { members << member }
|
22
|
+
end
|
23
|
+
|
24
|
+
def sample
|
25
|
+
members.sample
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_accessor :members, :universe
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class ListLoader
|
2
|
+
def initialize genre = 'default'
|
3
|
+
@genre = genre
|
4
|
+
end
|
5
|
+
|
6
|
+
def load genre=@genre
|
7
|
+
dir_of_this_file = File.dirname(__FILE__)
|
8
|
+
default_list_dir = File.join(*%W(#{dir_of_this_file} .. .. lists default ** *))
|
9
|
+
Dir[default_list_dir].each { |list_path| create_list_from(list_path) }
|
10
|
+
|
11
|
+
if genre != 'default'
|
12
|
+
Dir[File.join(*%W(#{dir_of_this_file} .. lists #{genre} ** *))].each { |list_path| create_list_from(list_path) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def create_list_from path
|
19
|
+
newlines_before_a_pipe = /\n(?=\|)/
|
20
|
+
everything_up_to_the_first_newline_if_first_character_is_a_pipe = /^\|(.*?)\n/
|
21
|
+
everything_after_the_last_slash = /\/.+$/
|
22
|
+
|
23
|
+
lists = File.open(path).read.split(newlines_before_a_pipe)
|
24
|
+
lists.each_with_index do |_list, i|
|
25
|
+
list_name = _list.match(everything_up_to_the_first_newline_if_first_character_is_a_pipe)[1].to_s
|
26
|
+
|
27
|
+
if list_name.empty?
|
28
|
+
list_name = path.match(everything_after_the_last_slash).to_s
|
29
|
+
else
|
30
|
+
_list.gsub!(everything_up_to_the_first_newline_if_first_character_is_a_pipe, '')
|
31
|
+
end
|
32
|
+
|
33
|
+
phrase_class_name = list_name.underscore.camelize
|
34
|
+
begin
|
35
|
+
qlass = "Phrase::#{phrase_class_name}".constantize
|
36
|
+
rescue NameError
|
37
|
+
qlass = Class.new(Phrase)
|
38
|
+
Phrase.const_set phrase_class_name, qlass
|
39
|
+
end
|
40
|
+
|
41
|
+
qlass.list(_list)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Manifestation
|
2
|
+
attr_accessor :text
|
3
|
+
|
4
|
+
def initialize desired
|
5
|
+
@text = manifestation of: desired[:phrase], from: desired[:genre]
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def concatenate_lists_in genre
|
11
|
+
unless system("find ./lists/#{genre}/* -exec cat {} > #{genre}.list + 2>&1")
|
12
|
+
puts "There is no lists/#{genre} directory in which to find lists."
|
13
|
+
raise StandardError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def manifestation desire
|
18
|
+
concatenate_lists_in(desire[:from])
|
19
|
+
|
20
|
+
world = Generator.from_file "#{desire[:from]}.list"
|
21
|
+
|
22
|
+
text = world.manifest desire[:of]
|
23
|
+
while text.length > 500
|
24
|
+
text = world.manifest desire[:of]
|
25
|
+
end
|
26
|
+
|
27
|
+
text
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Member
|
2
|
+
attr_reader :body, :list
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
@list = opts.fetch(:list)
|
6
|
+
@freq = opts.fetch(:frequency, 1)
|
7
|
+
@body = opts.fetch(:body)
|
8
|
+
@universe = opts.fetch(:universe)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
body.listerpolate(universe).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :universe
|
18
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
class Phrase
|
4
|
+
def self.list new_list = nil
|
5
|
+
return @list unless new_list
|
6
|
+
|
7
|
+
if new_list.is_a? String
|
8
|
+
new_list = new_list.split_on_newlines_and_strip
|
9
|
+
end
|
10
|
+
|
11
|
+
new_list.map! do |line|
|
12
|
+
multiplier_regex = /^\d+@/
|
13
|
+
multiplier = line.match(multiplier_regex).to_s.to_i
|
14
|
+
multiplier = 1 if multiplier < 1
|
15
|
+
[line.gsub(multiplier_regex, '')] * multiplier
|
16
|
+
end.flatten!.reject! { |i| i.nil? || i.empty? }
|
17
|
+
|
18
|
+
@list = new_list
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize dsl_string = self.class.list.sample
|
22
|
+
compile parse dsl_string
|
23
|
+
end
|
24
|
+
|
25
|
+
def compile parsed_dsl
|
26
|
+
template = parsed_dsl[:template]
|
27
|
+
|
28
|
+
@variable_classes = []
|
29
|
+
@inflection_delegates = {
|
30
|
+
:plural => [],
|
31
|
+
:possessive => [],
|
32
|
+
:article => [],
|
33
|
+
:capitalize => [],
|
34
|
+
}
|
35
|
+
|
36
|
+
inflections = []
|
37
|
+
|
38
|
+
parsed_dsl[:variables].each_with_index do |variable, i|
|
39
|
+
rough_var_class = variable[:rough_variable_class]
|
40
|
+
|
41
|
+
variable[:inflections_to_delegate].each do |inflection|
|
42
|
+
@inflection_delegates[inflection.to_sym] << i
|
43
|
+
end
|
44
|
+
|
45
|
+
inflections[i] = []
|
46
|
+
|
47
|
+
variable[:inflections_to_apply].each do |inflection|
|
48
|
+
inflections[i] << inflection.to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
@variable_classes << "Phrase::#{rough_var_class.camelize}".constantize
|
53
|
+
rescue NameError
|
54
|
+
@variable_classes << eval(%Q|Class.new(Phrase) do
|
55
|
+
def initialize
|
56
|
+
@to_s_proc = -> { "{#{rough_var_class} ??}" }
|
57
|
+
end
|
58
|
+
end|)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@to_s_proc = -> {
|
63
|
+
self.variables.each_with_index do |variable, i|
|
64
|
+
inflections[i].each do |inflection|
|
65
|
+
variable.send "#{inflection}!"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
template.zip(self.variables).flatten.map(&:to_s).join('')
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse dsl_string = @dsl_string
|
73
|
+
# A dsl string like "[adjective] [noun.possessive#plural]" will be parsed into
|
74
|
+
# { :variables =>
|
75
|
+
# [ { :rough_variable_class => 'adjective',
|
76
|
+
# :inflections_to_delegate => [],
|
77
|
+
# :inflections_to_apply => []
|
78
|
+
# },
|
79
|
+
# { :rough_variable_class => 'noun',
|
80
|
+
# :inflections_to_delegate => [:plural],
|
81
|
+
# :inflections_to_apply => [:possessive]
|
82
|
+
# }
|
83
|
+
# ],
|
84
|
+
# :template => ["", " "]
|
85
|
+
# }
|
86
|
+
#
|
87
|
+
tokens = dsl_string.split(/[\[\]]/)
|
88
|
+
template = []; variables = [];
|
89
|
+
|
90
|
+
tokens.each_with_index do |token, i|
|
91
|
+
if i % 2 == 0
|
92
|
+
template << token
|
93
|
+
else
|
94
|
+
variables << token
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
hash = {:variables => [], :template => template}
|
99
|
+
|
100
|
+
variables.each_with_index do |variable, i|
|
101
|
+
components = variable.split(/\b/)
|
102
|
+
rough_var_class = components.shift
|
103
|
+
inflections_to_delegate = []
|
104
|
+
inflections_to_apply = []
|
105
|
+
|
106
|
+
components.each_with_index do |v, k|
|
107
|
+
inflections_to_delegate << v if components[k-1] == '#'
|
108
|
+
inflections_to_apply << v if components[k-1] == '.'
|
109
|
+
end
|
110
|
+
|
111
|
+
hash[:variables] << {
|
112
|
+
:rough_variable_class => rough_var_class,
|
113
|
+
:inflections_to_delegate => inflections_to_delegate,
|
114
|
+
:inflections_to_apply => inflections_to_apply,
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
hash
|
119
|
+
end
|
120
|
+
|
121
|
+
def variables
|
122
|
+
@variables ||= @variable_classes.map(&:new)
|
123
|
+
end
|
124
|
+
|
125
|
+
def plural?; !!@plural end
|
126
|
+
def possessive?; !!@possessive end
|
127
|
+
def article?; !!@article end
|
128
|
+
def capitalize?; !!@capitalize end
|
129
|
+
|
130
|
+
def plural!
|
131
|
+
@plural = true
|
132
|
+
|
133
|
+
@inflection_delegates[:plural].each do |delegate|
|
134
|
+
variables[delegate].plural!
|
135
|
+
end
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
def article!
|
140
|
+
@article = true
|
141
|
+
|
142
|
+
@inflection_delegates[:article].each do |delegate|
|
143
|
+
variables[delegate].article!
|
144
|
+
end
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def possessive!
|
149
|
+
@possessive = true
|
150
|
+
|
151
|
+
@inflection_delegates[:possessive].each do |delegate|
|
152
|
+
variables[delegate].possessive!
|
153
|
+
end
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
def capitalize!
|
158
|
+
@capitalize = true
|
159
|
+
|
160
|
+
@inflection_delegates[:capitalize].each do |delegate|
|
161
|
+
variables[delegate].capitalize!
|
162
|
+
end
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def to_s
|
167
|
+
render_inflections @to_s_proc.call
|
168
|
+
end
|
169
|
+
|
170
|
+
def render_inflections string
|
171
|
+
if plural?
|
172
|
+
string = string.pluralize if @inflection_delegates[:plural].empty?
|
173
|
+
if possessive? && @inflection_delegates[:possessive].empty?
|
174
|
+
if string =~ /s$/
|
175
|
+
string = "#{string}'"
|
176
|
+
else
|
177
|
+
string = "#{string}'s"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
else
|
181
|
+
#singular
|
182
|
+
if article? && @inflection_delegates[:article].empty?
|
183
|
+
if string =~ /^[aeiou]/i
|
184
|
+
string = "an #{string}"
|
185
|
+
else
|
186
|
+
string = "a #{string}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
if possessive? && @inflection_delegates[:possessive].empty?
|
190
|
+
string = "#{string}'s"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
string = string.capitalize if capitalize?
|
195
|
+
|
196
|
+
string
|
197
|
+
end
|
198
|
+
end
|