dunmanifestin 0.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.
Files changed (109) hide show
  1. checksums.yaml +15 -0
  2. data/bin/dunmanifestin +49 -0
  3. data/lib/dunmanifestin.rb +11 -0
  4. data/lib/dunmanifestin/custom_inflections.rb +5 -0
  5. data/lib/dunmanifestin/generator.rb +46 -0
  6. data/lib/dunmanifestin/list.rb +30 -0
  7. data/lib/dunmanifestin/list_loader.rb +46 -0
  8. data/lib/dunmanifestin/manifestation.rb +30 -0
  9. data/lib/dunmanifestin/member.rb +18 -0
  10. data/lib/dunmanifestin/phrase.rb +198 -0
  11. data/lib/dunmanifestin/string.rb +38 -0
  12. data/lists/default/activated +12 -0
  13. data/lists/default/adverb +13 -0
  14. data/lists/default/ageGroup +5 -0
  15. data/lists/default/alienName +33 -0
  16. data/lists/default/alignment +10 -0
  17. data/lists/default/animal +30 -0
  18. data/lists/default/appearance +33 -0
  19. data/lists/default/attitude +17 -0
  20. data/lists/default/bag +4 -0
  21. data/lists/default/baggage +29 -0
  22. data/lists/default/baseItem +47 -0
  23. data/lists/default/buildingType +11 -0
  24. data/lists/default/clothing +7 -0
  25. data/lists/default/color +41 -0
  26. data/lists/default/container +7 -0
  27. data/lists/default/curse +10 -0
  28. data/lists/default/denizen +3 -0
  29. data/lists/default/denizenDetail +6 -0
  30. data/lists/default/description +3 -0
  31. data/lists/default/desire +26 -0
  32. data/lists/default/disability +8 -0
  33. data/lists/default/disease +10 -0
  34. data/lists/default/economy +11 -0
  35. data/lists/default/encounter +2409 -0
  36. data/lists/default/englishName +230 -0
  37. data/lists/default/epithet +13 -0
  38. data/lists/default/facet +17 -0
  39. data/lists/default/facetOfCulture +3 -0
  40. data/lists/default/family +5 -0
  41. data/lists/default/fear +30 -0
  42. data/lists/default/finnishName +81 -0
  43. data/lists/default/foodOrDrink +19 -0
  44. data/lists/default/geologicalFormation +14 -0
  45. data/lists/default/greenlandicName +43 -0
  46. data/lists/default/grossBodyPart +8 -0
  47. data/lists/default/group +6 -0
  48. data/lists/default/hardMaterial +6 -0
  49. data/lists/default/height +4 -0
  50. data/lists/default/japaneseName +202 -0
  51. data/lists/default/jewelery +13 -0
  52. data/lists/default/koboldName +68 -0
  53. data/lists/default/latinName +40 -0
  54. data/lists/default/magicItemDescription +24 -0
  55. data/lists/default/material +3 -0
  56. data/lists/default/metal +3 -0
  57. data/lists/default/mineral +3 -0
  58. data/lists/default/monster +160 -0
  59. data/lists/default/name +86 -0
  60. data/lists/default/namePrefix +30 -0
  61. data/lists/default/nameSuffix +18 -0
  62. data/lists/default/negativeAdverb +6 -0
  63. data/lists/default/negativeQuality +19 -0
  64. data/lists/default/neutralQuality +14 -0
  65. data/lists/default/nonPreciousMetal +6 -0
  66. data/lists/default/object +5 -0
  67. data/lists/default/person +4 -0
  68. data/lists/default/personName +3 -0
  69. data/lists/default/personality +34 -0
  70. data/lists/default/place +10 -0
  71. data/lists/default/placeName +4 -0
  72. data/lists/default/placeSuffix +36 -0
  73. data/lists/default/positiveAdverb +5 -0
  74. data/lists/default/positiveQuality +12 -0
  75. data/lists/default/preciousMetal +4 -0
  76. data/lists/default/preciousStone +6 -0
  77. data/lists/default/profession +21 -0
  78. data/lists/default/province +3 -0
  79. data/lists/default/quality +4 -0
  80. data/lists/default/qualityWithAdverb +4 -0
  81. data/lists/default/race +11 -0
  82. data/lists/default/raceOrProfession +5 -0
  83. data/lists/default/reason +15 -0
  84. data/lists/default/resource +9 -0
  85. data/lists/default/root +6 -0
  86. data/lists/default/secret +9 -0
  87. data/lists/default/settlementDetail +6 -0
  88. data/lists/default/settlementType +7 -0
  89. data/lists/default/softMaterial +7 -0
  90. data/lists/default/structureDetail +8 -0
  91. data/lists/default/structureType +24 -0
  92. data/lists/default/superpower +6 -0
  93. data/lists/default/topicOfConversation +5 -0
  94. data/lists/default/weapon +149 -0
  95. data/lists/default/wearable +4 -0
  96. data/lists/default/wearableQuality +15 -0
  97. data/lists/default/weildable +10 -0
  98. data/lists/default/welshName +79 -0
  99. data/lists/huoquitlan/originalAnimal +250 -0
  100. data/lists/huoquitlan/originalDenizen +849 -0
  101. data/lists/huoquitlan/originalItemName +33 -0
  102. data/lists/huoquitlan/originalNPC +99 -0
  103. data/lists/huoquitlan/originalName +226 -0
  104. data/lists/hypotheticals/noun +373 -0
  105. data/lists/hypotheticals/root +15 -0
  106. data/lists/hypotheticals/transitiveVerb +628 -0
  107. data/lists/hypotheticals/verbs +653 -0
  108. data/lists/sophistry/root +269 -0
  109. metadata +156 -0
@@ -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=
@@ -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,5 @@
1
+ require 'active_support/inflector'
2
+
3
+ ActiveSupport::Inflector.inflections do |inflect|
4
+ inflect.irregular 'human', 'humans'
5
+ end
@@ -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