dunmanifestin 1.1.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/dunmanifestin +0 -2
- data/lib/dunmanifestin.rb +0 -1
- data/lib/dunmanifestin/array.rb +4 -25
- data/lib/dunmanifestin/churn.rb +35 -0
- data/lib/dunmanifestin/custom_inflections.rb +1 -0
- data/lib/dunmanifestin/genre.rb +31 -0
- data/lib/dunmanifestin/palette.rb +88 -32
- data/lib/dunmanifestin/phrase.rb +79 -139
- data/lib/dunmanifestin/terminator.rb +65 -27
- metadata +7 -11
- data/lib/dunmanifestin/generator.rb +0 -46
- data/lib/dunmanifestin/list.rb +0 -31
- data/lib/dunmanifestin/list_loader.rb +0 -20
- data/lib/dunmanifestin/manifestation.rb +0 -30
- data/lib/dunmanifestin/member.rb +0 -18
- data/lib/dunmanifestin/string.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe034e91906b9ceaa0c86e037a01edfb69ad6c737ab9fdbb626becd610bc234b
|
4
|
+
data.tar.gz: 820efff91dd927269b89fee2462747d303870b97b3648957c20c524768da0b30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a0bfbe9e373a9ae7730a5d1db22bd6b4fbbe46e4fe69a9cdaefe7e15b70f913d12c4bf45ae9dc51b5575ddb0c1ebe61e9bddf8aaf3346d67de380807be6f006
|
7
|
+
data.tar.gz: 40ee4e7f6a31d3310af75923e9dd5d34fbad1698bbe5703801de62189d07236886d8ad5c60c0de7181fd305b03010d096640068387787837b415097ea9e519c8
|
data/bin/dunmanifestin
CHANGED
@@ -12,8 +12,6 @@ user_demands = Optimist::options do
|
|
12
12
|
opt :phrase, "Specify a phrase or list, e.g. 'The [animal] sat on the [article]' or '[weapon]'", type: :string, short: '-p'
|
13
13
|
opt :chomp, "remove the trailing newline from the output", short: '-o'
|
14
14
|
opt :file, "Read a file as the phrase", type: :string, short: '-f'
|
15
|
-
opt :coarse_seed, "Set this number to encourage phrases to resolve somewhat predictably", type: :integer, short: "-s"
|
16
|
-
opt :fine_seed, "Set this number (alongside -s) to lock phrases into resolving completely predictably", type: :integer, short: "-e"
|
17
15
|
end
|
18
16
|
|
19
17
|
begin
|
data/lib/dunmanifestin.rb
CHANGED
@@ -7,5 +7,4 @@ require_relative 'dunmanifestin/string'
|
|
7
7
|
require_relative 'dunmanifestin/custom_inflections'
|
8
8
|
require_relative 'dunmanifestin/phrase'
|
9
9
|
require_relative 'dunmanifestin/manifestation'
|
10
|
-
require_relative 'dunmanifestin/list_loader'
|
11
10
|
require_relative 'dunmanifestin/terminator'
|
data/lib/dunmanifestin/array.rb
CHANGED
@@ -1,30 +1,9 @@
|
|
1
|
-
require_relative 'integer'
|
2
|
-
|
3
1
|
class Array
|
4
|
-
|
5
|
-
|
6
|
-
class << self
|
7
|
-
attr_accessor :coarse_seed, :fine_seed, :diversity, :recurrences
|
8
|
-
|
9
|
-
def meta_random
|
10
|
-
@meta_random ||= @fine_seed ? Random.new(@fine_seed) : Random.new
|
11
|
-
end
|
12
|
-
|
13
|
-
def randoms
|
14
|
-
@coarse_seed ||= meta_random.rand(Integer::MAX)
|
15
|
-
@recurrences ||= 500
|
16
|
-
@randoms ||= @recurrences.times.map do |i|
|
17
|
-
Random.new(@coarse_seed + (i % (@diversity||Integer::MAX)))
|
18
|
-
end
|
19
|
-
end
|
2
|
+
def even_elements
|
3
|
+
select.each_with_index { |_, i| i.even? }
|
20
4
|
end
|
21
5
|
|
22
|
-
def
|
23
|
-
|
24
|
-
# p $count += 1
|
25
|
-
self.sample(
|
26
|
-
1,
|
27
|
-
random: randoms.sample(1, random: meta_random).pop
|
28
|
-
).pop
|
6
|
+
def odd_elements
|
7
|
+
select.each_with_index { |_, i| i.odd? }
|
29
8
|
end
|
30
9
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Churn
|
2
|
+
# A churn is a data structure that stores a set of things.
|
3
|
+
# You can randomly pick one of those things by calling its
|
4
|
+
# sample() method.
|
5
|
+
#
|
6
|
+
# The wrinkle is that the set of sampleable things is not
|
7
|
+
# closed. The churn will sometimes, at random, generate a
|
8
|
+
# totally new item. You can also explicitly request a
|
9
|
+
# novel item by calling generate(). Any new items
|
10
|
+
# generated are added to the churn and may be picked on
|
11
|
+
# future calls to sample().
|
12
|
+
#
|
13
|
+
# Control how often the churn generates new things using
|
14
|
+
# the novelty: parameter to initialize().
|
15
|
+
|
16
|
+
def initialize novelty:
|
17
|
+
@novelty = novelty
|
18
|
+
@generated = 0
|
19
|
+
@slots = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def sample
|
23
|
+
return yield if @novelty == 0
|
24
|
+
r = (rand * (@novelty + @slots.length)).floor
|
25
|
+
@slots[r] ||= yield
|
26
|
+
end
|
27
|
+
|
28
|
+
def generate
|
29
|
+
return yield if @novelty == 0
|
30
|
+
@slots[@generated] ||= yield
|
31
|
+
value = @slots[@generated]
|
32
|
+
@generated += 1
|
33
|
+
value
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Genre
|
2
|
+
GAP_BETWEEN_PALETTES = /\n(?=\|)/
|
3
|
+
|
4
|
+
def self.from_directories paths
|
5
|
+
new palettes_from paths
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.palettes_from paths
|
9
|
+
paths.flat_map do |path|
|
10
|
+
Dir[File.join(path, '**', '*.pal')].flat_map do |filename|
|
11
|
+
File.read(filename)
|
12
|
+
.split(GAP_BETWEEN_PALETTES)
|
13
|
+
.map do |textual_palette|
|
14
|
+
Palette.new(textual_palette, filename)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize palette_list
|
21
|
+
self.palettes = Hash[palette_list.map { |p| [p.name, p] }]
|
22
|
+
end
|
23
|
+
|
24
|
+
def palette_named name
|
25
|
+
palettes[name] || NullPalette.new(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
attr_accessor :palettes
|
31
|
+
end
|
@@ -1,42 +1,98 @@
|
|
1
|
+
require_relative './phrase'
|
2
|
+
require_relative './churn'
|
3
|
+
|
4
|
+
class NullPalette
|
5
|
+
def initialize name
|
6
|
+
@name = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
@name
|
11
|
+
end
|
12
|
+
|
13
|
+
def sample _, _, _
|
14
|
+
"{#{@name} ??}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
1
18
|
class Palette
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
19
|
+
GAP_BETWEEN_LISTS = /\n(?=\|)/
|
20
|
+
PALETTE_TITLE = /^\|(.*?)\n/
|
21
|
+
COMMENT = %r{//.*$}
|
22
|
+
REPETITION_PREFIX = /^\d+@/
|
23
|
+
|
24
|
+
def initialize raw_text, filename
|
25
|
+
@raw_text = raw_text
|
26
|
+
@filename = filename
|
27
|
+
end
|
11
28
|
|
12
|
-
|
13
|
-
|
14
|
-
|
29
|
+
def name
|
30
|
+
return file_basename if not titled?
|
31
|
+
lines.first.sub(/\|(\w+).*$/, '\1')
|
32
|
+
end
|
15
33
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
34
|
+
def sample genre, inflections = [], constraints = []
|
35
|
+
if inflections.any?
|
36
|
+
# don't use the churn if there are inflections, since
|
37
|
+
# the inflected text would be cached by the churn and
|
38
|
+
# could then `recur` in places where we don't want any
|
39
|
+
# inflections.
|
40
|
+
phrases.sample.reify genre, inflections
|
41
|
+
else
|
42
|
+
if constraints.include? :recur
|
43
|
+
churn.sample { phrases.sample.reify genre }
|
20
44
|
else
|
21
|
-
|
22
|
-
# These comments should be tests.
|
23
|
-
body.gsub!(PALETTE_TITLE, '')
|
45
|
+
churn.generate { phrases.sample.reify genre }
|
24
46
|
end
|
25
|
-
|
26
|
-
# This metaprogramming is mysterious to me.
|
27
|
-
qlass = declare_phrase_class list_name
|
28
|
-
# Where is 'list' defined?
|
29
|
-
qlass.list body
|
30
|
-
rescue NoMethodError
|
31
47
|
end
|
48
|
+
rescue NoMethodError
|
49
|
+
"{#{name} ??}"
|
50
|
+
end
|
51
|
+
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
53
|
+
|
54
|
+
def file_basename
|
55
|
+
File.basename(@filename, '.pal')
|
56
|
+
end
|
57
|
+
|
58
|
+
def churn
|
59
|
+
@churn ||= Churn.new novelty: novelty
|
60
|
+
end
|
61
|
+
|
62
|
+
def novelty
|
63
|
+
lines.first.sub(/^.*\*(\d+).*$/, '\1').to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def phrases
|
67
|
+
@phrases ||= begin
|
68
|
+
lines[valid_phrase_range]
|
69
|
+
.map { |line| line.sub(COMMENT, '') }
|
70
|
+
.map(&:strip)
|
71
|
+
.reject(&:empty?)
|
72
|
+
.flat_map { |line|
|
73
|
+
if line =~ REPETITION_PREFIX
|
74
|
+
[line.sub(REPETITION_PREFIX, '')] * line.to_i
|
75
|
+
else
|
76
|
+
[line]
|
77
|
+
end
|
78
|
+
}
|
79
|
+
.map(&Phrase.method(:new))
|
40
80
|
end
|
41
81
|
end
|
82
|
+
|
83
|
+
def valid_phrase_range
|
84
|
+
titled? ? 1..-1 : 0..-1
|
85
|
+
end
|
86
|
+
|
87
|
+
def lines
|
88
|
+
@lines ||= text.gsub(/>>(.+?)<</m, '').split("\n") | text.scan(/>>(.+?)<</m).flatten
|
89
|
+
end
|
90
|
+
|
91
|
+
def text
|
92
|
+
@text ||= @raw_text.strip
|
93
|
+
end
|
94
|
+
|
95
|
+
def titled?
|
96
|
+
lines[0][0] == '|'
|
97
|
+
end
|
42
98
|
end
|
data/lib/dunmanifestin/phrase.rb
CHANGED
@@ -2,175 +2,115 @@ require 'active_support/inflector'
|
|
2
2
|
require_relative 'custom_inflections'
|
3
3
|
require_relative 'array'
|
4
4
|
|
5
|
-
class
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
new_list = new_list.split_on_newlines_and_strip if new_list.is_a?(String) unless multiline_document
|
10
|
-
new_list = [new_list] if multiline_document
|
11
|
-
|
12
|
-
new_list.map! do |line|
|
13
|
-
multiplier_regex = /^\d+@/
|
14
|
-
multiplier = line.match(multiplier_regex).to_s.to_i
|
15
|
-
multiplier = 1 if multiplier < 1
|
16
|
-
[line.gsub(multiplier_regex, '')] * multiplier
|
17
|
-
end.flatten!.reject! { |i| i.nil? || i.empty? }
|
5
|
+
class NullPhrase
|
6
|
+
def initialize dsl_string
|
7
|
+
@dsl_string = dsl_string
|
8
|
+
end
|
18
9
|
|
19
|
-
|
10
|
+
def reify _, _
|
11
|
+
@dsl_string
|
20
12
|
end
|
13
|
+
end
|
21
14
|
|
22
|
-
|
15
|
+
class Phrase
|
16
|
+
def initialize dsl_string
|
23
17
|
raise "Try again." unless dsl_string
|
24
|
-
|
18
|
+
@dsl_string = dsl_string
|
25
19
|
end
|
26
20
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
@variable_classes = []
|
31
|
-
@inflection_delegates = {
|
32
|
-
:plural => [],
|
33
|
-
:possessive => [],
|
34
|
-
:article => [],
|
35
|
-
:capitalize => [],
|
21
|
+
def reify genre, requested_inflections = []
|
22
|
+
vals = variables.map { |variable|
|
23
|
+
variable.reify genre, requested_inflections
|
36
24
|
}
|
25
|
+
inflect requested_inflections, constant_segments.zip(vals).flatten.join('')
|
26
|
+
end
|
37
27
|
|
38
|
-
|
39
|
-
|
40
|
-
parsed_dsl[:variables].each_with_index do |variable, i|
|
41
|
-
rough_var_class = variable[:rough_variable_class]
|
28
|
+
private
|
42
29
|
|
43
|
-
|
44
|
-
|
45
|
-
|
30
|
+
def variables
|
31
|
+
parsed_dsl[:variables]
|
32
|
+
end
|
46
33
|
|
47
|
-
|
34
|
+
def constant_segments
|
35
|
+
parsed_dsl[:constant_segments]
|
36
|
+
end
|
48
37
|
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
def parsed_dsl
|
39
|
+
@parsed_dsl ||= begin
|
40
|
+
tokens = @dsl_string.split(/[\[\]]/)
|
41
|
+
constant_segments = tokens.even_elements
|
42
|
+
variables = tokens.odd_elements
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
44
|
+
{
|
45
|
+
:variables => variables.map(&Variable.method(:new)),
|
46
|
+
:constant_segments => constant_segments
|
47
|
+
}
|
58
48
|
end
|
59
|
-
|
60
|
-
@to_s_proc = -> {
|
61
|
-
self.variables.each_with_index do |variable, i|
|
62
|
-
inflections[i].each { |inflection| variable.inflect inflection }
|
63
|
-
end
|
64
|
-
template.zip(self.variables).flatten.map(&:to_s).join('')
|
65
|
-
}
|
66
49
|
end
|
67
50
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
# },
|
75
|
-
# { :rough_variable_class => 'noun',
|
76
|
-
# :inflections_to_delegate => [:plural],
|
77
|
-
# :inflections_to_apply => [:possessive]
|
78
|
-
# }
|
79
|
-
# ],
|
80
|
-
# :template => ["", " "]
|
81
|
-
# }
|
82
|
-
#
|
83
|
-
tokens = dsl_string.split(/[\[\]]/)
|
84
|
-
template = []; variables = [];
|
85
|
-
|
86
|
-
tokens.each_with_index do |token, i|
|
87
|
-
if i % 2 == 0
|
88
|
-
template << token
|
89
|
-
else
|
90
|
-
variables << token
|
91
|
-
end
|
92
|
-
end
|
51
|
+
def inflect inflections, string
|
52
|
+
plural = inflections.include? :plural
|
53
|
+
article = inflections.include? :article
|
54
|
+
possessive = inflections.include? :possessive
|
55
|
+
capitalize = inflections.include? :capitalize
|
56
|
+
titleize = inflections.include? :titleize
|
93
57
|
|
94
|
-
|
58
|
+
# Good, now turn this into a stateless function.
|
59
|
+
string = string.pluralize if plural && variables.none?(&:delegated_plural?)
|
60
|
+
string = (string =~ /s$/) ? "#{string}'" : "#{string}'s" if plural && possessive && variables.none?(&:delegated_plural?)
|
61
|
+
string = "#{string}'s" if !plural && possessive && variables.none?(&:delegated_possessive?)
|
62
|
+
string = (string =~ /^[aeiou]/i) ? "an #{string}" : "a #{string}" if !plural && article && variables.none?(&:delegated_article?)
|
63
|
+
string = string[0].capitalize + string[1 .. -1] if capitalize
|
64
|
+
string = string.titleize if titleize
|
95
65
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
inflections_to_delegate = []
|
100
|
-
inflections_to_apply = []
|
66
|
+
string
|
67
|
+
end
|
68
|
+
end
|
101
69
|
|
102
|
-
|
103
|
-
|
104
|
-
|
70
|
+
class Variable
|
71
|
+
def initialize dsl_string
|
72
|
+
components = dsl_string.split(/\b/)
|
73
|
+
self.palette_name = components.shift
|
74
|
+
|
75
|
+
self.inflections_delegated_to_me = []
|
76
|
+
self.demanded_inflections = []
|
77
|
+
self.constraints = []
|
78
|
+
|
79
|
+
components.each_with_index do |v, k|
|
80
|
+
case components[k-1]
|
81
|
+
when '#'
|
82
|
+
inflections_delegated_to_me << v.to_sym
|
83
|
+
when '.'
|
84
|
+
demanded_inflections << v.to_sym
|
85
|
+
when ':'
|
86
|
+
constraints << v.to_sym
|
105
87
|
end
|
106
|
-
|
107
|
-
hash[:variables] << {
|
108
|
-
:rough_variable_class => rough_var_class,
|
109
|
-
:inflections_to_delegate => inflections_to_delegate,
|
110
|
-
:inflections_to_apply => inflections_to_apply,
|
111
|
-
}
|
112
88
|
end
|
113
|
-
|
114
|
-
hash
|
115
|
-
end
|
116
|
-
|
117
|
-
def variables
|
118
|
-
@variables ||= @variable_classes.map(&:new)
|
119
89
|
end
|
120
90
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
def titleize?; !!@titleize end
|
126
|
-
|
127
|
-
def titleize!
|
128
|
-
delegates = @inflection_delegates[:capitalize]
|
129
|
-
delegates.each { |delegate| variables[delegate].capitalize! }
|
91
|
+
def reify genre, inflections_of_parent_phrase
|
92
|
+
inherited_inflections = inflections_of_parent_phrase & inflections_delegated_to_me
|
93
|
+
inflections = demanded_inflections | inherited_inflections
|
94
|
+
genre.palette_named(palette_name).sample genre, inflections, constraints
|
130
95
|
end
|
131
96
|
|
132
|
-
def
|
133
|
-
|
134
|
-
self.instance_variable_set("@#{inflection}", true)
|
135
|
-
return (titleize! && self) if inflection == :titleize
|
136
|
-
|
137
|
-
delegates = @inflection_delegates[inflection]
|
138
|
-
delegates.each { |delegate| variables[delegate].inflect inflection }
|
139
|
-
self
|
140
|
-
rescue NoMethodError
|
141
|
-
puts "==> Failed to inflect: .#{inflection}?"
|
142
|
-
puts "==> Valid inflections are: plural, possessive, article, capitalize, titleize"
|
143
|
-
self
|
97
|
+
def delegated_plural?
|
98
|
+
inflections_delegated_to_me.include? :plural
|
144
99
|
end
|
145
100
|
|
146
|
-
def
|
147
|
-
|
101
|
+
def delegated_article?
|
102
|
+
inflections_delegated_to_me.include? :article
|
148
103
|
end
|
149
104
|
|
150
|
-
def
|
151
|
-
|
152
|
-
string = string.pluralize if plural? && @inflection_delegates[:plural].empty?
|
153
|
-
string = (string =~ /s$/) ? "#{string}'" : "#{string}'s" if plural? && possessive? && @inflection_delegates[:possessive].empty?
|
154
|
-
string = "#{string}'s" if !plural? && possessive? && @inflection_delegates[:possessive].empty?
|
155
|
-
string = (string =~ /^[aeiou]/i) ? "an #{string}" : "a #{string}" if !plural? && article? && @inflection_delegates[:article].empty?
|
156
|
-
string = string[0].capitalize + string[1 .. -1] if capitalize?
|
157
|
-
string = string.titleize if titleize?
|
158
|
-
|
159
|
-
string
|
105
|
+
def delegated_possessive?
|
106
|
+
inflections_delegated_to_me.include? :possessive
|
160
107
|
end
|
161
108
|
|
162
109
|
private
|
163
110
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
170
|
-
end
|
171
|
-
RUBY
|
172
|
-
|
173
|
-
eval(class_definition)
|
174
|
-
end
|
175
|
-
|
111
|
+
attr_accessor \
|
112
|
+
:demanded_inflections,
|
113
|
+
:palette_name,
|
114
|
+
:inflections_delegated_to_me,
|
115
|
+
:constraints
|
176
116
|
end
|
@@ -1,41 +1,27 @@
|
|
1
|
+
require_relative 'genre'
|
1
2
|
require_relative 'phrase'
|
2
|
-
require_relative '
|
3
|
-
require_relative 'string'
|
3
|
+
require_relative 'palette'
|
4
4
|
|
5
5
|
class Terminator
|
6
|
-
def initialize(
|
7
|
-
@list_loader = list_loader
|
6
|
+
def initialize(shell: Shell)
|
8
7
|
@shell = shell
|
9
8
|
end
|
10
9
|
|
11
10
|
def address demands
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Array.recurrences = 20
|
16
|
-
phrase_string = phrasing(demands[:phrase], demands[:file])
|
17
|
-
root_phrase_class = Class.new(Phrase) { list phrase_string, !!demands[:file] }
|
18
|
-
list_loader.load demands[:genre]
|
19
|
-
print interactive_banner if demands[:interactive]
|
20
|
-
|
21
|
-
construction_loop(
|
22
|
-
root_phrase_class,
|
23
|
-
(demands[:count] || 1),
|
24
|
-
demands[:chomp],
|
25
|
-
demands[:copy],
|
26
|
-
demands[:interactive]
|
27
|
-
)
|
11
|
+
self.demands = demands
|
12
|
+
print interactive_banner if interactive
|
13
|
+
construction_loop
|
28
14
|
end
|
29
15
|
|
30
16
|
private
|
31
|
-
DEFAULT_ROOT_PHRASEAGE = '[root]'
|
32
|
-
attr_accessor :list_loader, :shell
|
33
17
|
|
34
|
-
|
18
|
+
attr_accessor :shell, :demands
|
19
|
+
|
20
|
+
def construction_loop
|
35
21
|
fulltext = ""
|
36
22
|
while true
|
37
23
|
volume.times do
|
38
|
-
text =
|
24
|
+
text = Phrase.new(phrasing).reify genre
|
39
25
|
fulltext += "\n#{text}"
|
40
26
|
text += "\n" unless chomp
|
41
27
|
shell.puts text
|
@@ -43,13 +29,21 @@ class Terminator
|
|
43
29
|
|
44
30
|
`echo #{fulltext.inspect} | pbcopy $1` if copy
|
45
31
|
|
46
|
-
break unless
|
32
|
+
break unless interactive
|
47
33
|
break if get_from_prompt == 'quit'
|
48
34
|
end
|
49
35
|
end
|
50
36
|
|
51
|
-
def
|
52
|
-
|
37
|
+
def genre
|
38
|
+
@genre ||= Genre.from_directories genre_directories
|
39
|
+
end
|
40
|
+
|
41
|
+
def genre_directories
|
42
|
+
([default_genre_path] + demanded_genres).reject(&:empty?)
|
43
|
+
end
|
44
|
+
|
45
|
+
def phrasing
|
46
|
+
demanded_phrase || demanded_file_contents || '[root]'
|
53
47
|
end
|
54
48
|
|
55
49
|
def get_from_prompt
|
@@ -63,6 +57,50 @@ class Terminator
|
|
63
57
|
[bar, message, bar].join "\n"
|
64
58
|
end
|
65
59
|
|
60
|
+
def chomp
|
61
|
+
demands[:chomp]
|
62
|
+
end
|
63
|
+
|
64
|
+
def copy
|
65
|
+
demands[:copy]
|
66
|
+
end
|
67
|
+
|
68
|
+
def volume
|
69
|
+
demands[:count] || 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def interactive
|
73
|
+
demands[:interactive]
|
74
|
+
end
|
75
|
+
|
76
|
+
def demanded_genres
|
77
|
+
demands[:genre] ? demands[:genre].split(':') : []
|
78
|
+
end
|
79
|
+
|
80
|
+
def demanded_file
|
81
|
+
demands[:file]
|
82
|
+
end
|
83
|
+
|
84
|
+
def demanded_file_contents
|
85
|
+
demanded_file && File.read(demanded_file)
|
86
|
+
end
|
87
|
+
|
88
|
+
def demanded_phrase
|
89
|
+
demands[:phrase]
|
90
|
+
end
|
91
|
+
|
92
|
+
def coarse_seed
|
93
|
+
demands[:coarse_seed]
|
94
|
+
end
|
95
|
+
|
96
|
+
def fine_seed
|
97
|
+
demands[:fine_seed]
|
98
|
+
end
|
99
|
+
|
100
|
+
def default_genre_path
|
101
|
+
File.join(*%W(#{File.dirname(__FILE__)} .. .. default-genre))
|
102
|
+
end
|
103
|
+
|
66
104
|
module Shell
|
67
105
|
class << self
|
68
106
|
def method_missing method, *args
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dunmanifestin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- gavmor
|
8
8
|
- benchristel
|
9
9
|
- AlexLerman
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2019-04-
|
13
|
+
date: 2019-04-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -83,7 +83,7 @@ dependencies:
|
|
83
83
|
description: The point of Dunmanifestin [is] to inject chaos into humans' cliched
|
84
84
|
ideas or, at least, let them be hunter-gatherers instead of farmers of culture.
|
85
85
|
-- B. Christel
|
86
|
-
email:
|
86
|
+
email: morgan.gavin@gmail.com
|
87
87
|
executables:
|
88
88
|
- dunmanifestin
|
89
89
|
extensions: []
|
@@ -98,18 +98,14 @@ files:
|
|
98
98
|
- default-genre/verb.pal
|
99
99
|
- lib/dunmanifestin.rb
|
100
100
|
- lib/dunmanifestin/array.rb
|
101
|
+
- lib/dunmanifestin/churn.rb
|
101
102
|
- lib/dunmanifestin/custom_inflections.rb
|
102
|
-
- lib/dunmanifestin/
|
103
|
+
- lib/dunmanifestin/genre.rb
|
103
104
|
- lib/dunmanifestin/integer.rb
|
104
|
-
- lib/dunmanifestin/list.rb
|
105
|
-
- lib/dunmanifestin/list_loader.rb
|
106
|
-
- lib/dunmanifestin/manifestation.rb
|
107
|
-
- lib/dunmanifestin/member.rb
|
108
105
|
- lib/dunmanifestin/palette.rb
|
109
106
|
- lib/dunmanifestin/phrase.rb
|
110
|
-
- lib/dunmanifestin/string.rb
|
111
107
|
- lib/dunmanifestin/terminator.rb
|
112
|
-
homepage: http://github.com/
|
108
|
+
homepage: http://github.com/gavmor/dunmanifestin
|
113
109
|
licenses:
|
114
110
|
- MIT
|
115
111
|
metadata: {}
|
@@ -1,46 +0,0 @@
|
|
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
|
data/lib/dunmanifestin/list.rb
DELETED
@@ -1,31 +0,0 @@
|
|
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
|
-
puts members
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
def << rough_member
|
14
|
-
pieces = rough_member.split('@')
|
15
|
-
|
16
|
-
weight = pieces.length > 1 ? pieces.shift.to_i : 1
|
17
|
-
|
18
|
-
attrs = {body: pieces.pop, list: self, universe: universe}
|
19
|
-
attrs.merge!(frequency: pieces.pop) if pieces.any?
|
20
|
-
member = Member.new(attrs)
|
21
|
-
|
22
|
-
weight.times { members << member }
|
23
|
-
end
|
24
|
-
|
25
|
-
def sample
|
26
|
-
members.sample
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
attr_accessor :members, :universe
|
31
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require_relative 'phrase'
|
2
|
-
require_relative 'string'
|
3
|
-
require_relative 'palette'
|
4
|
-
|
5
|
-
class ListLoader
|
6
|
-
DEFAULT_GENRE = File.join(*%W(#{File.dirname(__FILE__)} .. .. default-genre))
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def load super_genre=''
|
10
|
-
[DEFAULT_GENRE, (super_genre || '').split(":")]
|
11
|
-
.flatten.compact.each(&method(:load_genre))
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def load_genre dirname
|
17
|
-
Dir[File.join(dirname, '**' '*.pal')].each(&Palette.method(:expose))
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,30 +0,0 @@
|
|
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
|
-
|
data/lib/dunmanifestin/member.rb
DELETED
@@ -1,18 +0,0 @@
|
|
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
|
data/lib/dunmanifestin/string.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
class String
|
4
|
-
def is_name?
|
5
|
-
self[0] == '|'
|
6
|
-
end
|
7
|
-
|
8
|
-
def listerpolate universe
|
9
|
-
body = self
|
10
|
-
|
11
|
-
while body.match(/\[\w+\]/) do
|
12
|
-
slug = body.match(/\[\w+\]/).to_s
|
13
|
-
phrase = universe.send(slug.gsub('[', '').gsub(']', ''))
|
14
|
-
body = body.sub(slug, phrase)
|
15
|
-
end
|
16
|
-
|
17
|
-
body
|
18
|
-
end
|
19
|
-
|
20
|
-
alias :original_capitalize :capitalize
|
21
|
-
|
22
|
-
def capitalize
|
23
|
-
case_mapping = {
|
24
|
-
"ä" => "Ä",
|
25
|
-
"ö" => "Ö",
|
26
|
-
}
|
27
|
-
|
28
|
-
s = original_capitalize
|
29
|
-
case_mapping.each_pair do |lower, upper|
|
30
|
-
s.gsub!(%r{^#{lower}}, upper)
|
31
|
-
end
|
32
|
-
s
|
33
|
-
end
|
34
|
-
|
35
|
-
def split_on_newlines_and_strip
|
36
|
-
split(/\s*\n\s*/).reject(&:empty?)
|
37
|
-
end
|
38
|
-
end
|