text-gen 0.12.6 → 0.13.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/lib/text/gen/context.rb +13 -2
- data/lib/text/gen/filter/base.rb +4 -3
- data/lib/text/gen/filter/pluralize.rb +20 -7
- data/lib/text/gen/filter/replace.rb +1 -1
- data/lib/text/gen/filter.rb +1 -1
- data/lib/text/gen/meta.rb +1 -1
- data/lib/text/gen/runner.rb +38 -8
- data/lib/text/gen/segment/reference.rb +1 -1
- data/lib/text/gen/store.rb +21 -2
- data/lib/text/gen/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5581ccb42efa3604510e17f8af69e6d5b804cc60702f6e1f7001cebf8def8c54
|
|
4
|
+
data.tar.gz: 840ffc9473992cb64850991e4ee442c774acee38ddbdf40e81257be9c69b756d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 511f34f2a2a29d8c50a85d8b63f504b420047db4e219783525ab855ccd41582b6e9673b3f02bcbb5c2ea1ed9fdf515160a5a6e3b18b251686f55cf0ee3cb10fd
|
|
7
|
+
data.tar.gz: 1b74d7812ff49c5026afd623630435921b7f366c754388439e628a00e0766919458cebf6a22f93bd914f307d8016138b1bcab15104cb01bac3cc132c454d5eb5
|
data/CHANGELOG.md
CHANGED
data/lib/text/gen/context.rb
CHANGED
|
@@ -4,6 +4,8 @@ module Text
|
|
|
4
4
|
module Gen
|
|
5
5
|
# Keep the context for one run.
|
|
6
6
|
class Context
|
|
7
|
+
KNOWN_STRATEGIES = Set.new(%w[random weighted sequence sample])
|
|
8
|
+
|
|
7
9
|
attr_reader :store, :depth
|
|
8
10
|
|
|
9
11
|
def initialize(store:, filters: nil, meta: nil, max_recursion: 10)
|
|
@@ -22,10 +24,19 @@ module Text
|
|
|
22
24
|
def descend!(builder)
|
|
23
25
|
@depth += 1
|
|
24
26
|
@keys << builder["key"]
|
|
25
|
-
@strategy_stack << (builder
|
|
27
|
+
@strategy_stack << strategy_to_stack_item(builder)
|
|
26
28
|
raise MaxRecursionError if @depth > @max_recursion
|
|
27
29
|
end
|
|
28
30
|
|
|
31
|
+
def strategy_to_stack_item(builder)
|
|
32
|
+
strategy, modifier = builder.fetch("strategy", "weighted").split(":", 2)
|
|
33
|
+
unless KNOWN_STRATEGIES.include?(strategy)
|
|
34
|
+
modifier = strategy
|
|
35
|
+
strategy = "weighted"
|
|
36
|
+
end
|
|
37
|
+
[strategy, modifier]
|
|
38
|
+
end
|
|
39
|
+
|
|
29
40
|
def ascend!
|
|
30
41
|
@depth -= 1
|
|
31
42
|
@keys.pop
|
|
@@ -50,7 +61,7 @@ module Text
|
|
|
50
61
|
end
|
|
51
62
|
|
|
52
63
|
def current_strategy
|
|
53
|
-
@strategy_stack.last&.first || "
|
|
64
|
+
@strategy_stack.last&.first || "weighted"
|
|
54
65
|
end
|
|
55
66
|
|
|
56
67
|
def current_modifier
|
data/lib/text/gen/filter/base.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Text
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def component_key
|
|
15
|
-
"fn(#{
|
|
15
|
+
"fn(#{self})"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# Shared utilities
|
|
@@ -33,8 +33,9 @@ module Text
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def to_s
|
|
36
|
-
return "#{
|
|
37
|
-
return "#{
|
|
36
|
+
return "#{type}:#{key}:#{value}" if value
|
|
37
|
+
return "#{type}:#{key}" if key
|
|
38
|
+
|
|
38
39
|
type
|
|
39
40
|
end
|
|
40
41
|
|
|
@@ -52,9 +52,13 @@ module Text
|
|
|
52
52
|
|
|
53
53
|
def pluralize_by_key(str, multiplier, result)
|
|
54
54
|
tokens = tokenize(str)
|
|
55
|
-
word_tokens = tokens.
|
|
55
|
+
word_tokens = tokens.grep(/\w/)
|
|
56
56
|
idx = word_tokens.rindex { |s| to_num(s) }
|
|
57
|
-
num = multiplier > 1
|
|
57
|
+
num = if multiplier > 1
|
|
58
|
+
multiplier
|
|
59
|
+
else
|
|
60
|
+
(idx ? to_num(word_tokens[idx]) : nil)
|
|
61
|
+
end
|
|
58
62
|
return str if num.nil? || num <= 1
|
|
59
63
|
|
|
60
64
|
component = find_component(result, key)
|
|
@@ -68,7 +72,8 @@ module Text
|
|
|
68
72
|
return str unless last_word_idx
|
|
69
73
|
|
|
70
74
|
dc = component_tokens[last_word_idx].downcase
|
|
71
|
-
component_tokens[last_word_idx] =
|
|
75
|
+
component_tokens[last_word_idx] =
|
|
76
|
+
exceptions(dc) || single_letter(dc) || others(dc) || ends_with_y(dc) || simple(dc)
|
|
72
77
|
str.sub(component_text, component_tokens.join)
|
|
73
78
|
end
|
|
74
79
|
|
|
@@ -84,9 +89,13 @@ module Text
|
|
|
84
89
|
|
|
85
90
|
def substitute(str, multiplier = 1)
|
|
86
91
|
tokens = tokenize(str)
|
|
87
|
-
word_tokens = tokens.
|
|
92
|
+
word_tokens = tokens.grep(/\w/)
|
|
88
93
|
idx = word_tokens.rindex { |s| to_num(s) }
|
|
89
|
-
num = multiplier > 1
|
|
94
|
+
num = if multiplier > 1
|
|
95
|
+
multiplier
|
|
96
|
+
else
|
|
97
|
+
(idx ? to_num(word_tokens[idx]) : nil)
|
|
98
|
+
end
|
|
90
99
|
return str if num.nil? || num <= 1
|
|
91
100
|
|
|
92
101
|
tokens.map! { |t| t.match?(/\A#{Regexp.escape(key)}\z/i) ? value : t }
|
|
@@ -97,13 +106,17 @@ module Text
|
|
|
97
106
|
return str if str.empty?
|
|
98
107
|
|
|
99
108
|
tokens = tokenize(str)
|
|
100
|
-
word_tokens = tokens.
|
|
109
|
+
word_tokens = tokens.grep(/\w/)
|
|
101
110
|
return str if word_tokens.length < 2
|
|
102
111
|
|
|
103
112
|
idx = word_tokens.rindex { |s| to_num(s) }
|
|
104
113
|
|
|
105
114
|
# Use the multiplier if available, otherwise parse from text
|
|
106
|
-
num = multiplier > 1
|
|
115
|
+
num = if multiplier > 1
|
|
116
|
+
multiplier
|
|
117
|
+
else
|
|
118
|
+
(idx ? to_num(word_tokens[idx]) : nil)
|
|
119
|
+
end
|
|
107
120
|
|
|
108
121
|
return str if num.nil? || num <= 1
|
|
109
122
|
return str if idx && idx >= word_tokens.length - 1
|
data/lib/text/gen/filter.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Text
|
|
|
14
14
|
def build(hsh_or_key, depth)
|
|
15
15
|
hsh = hsh_or_key.is_a?(Hash) ? hsh_or_key : key_to_hsh(hsh_or_key)
|
|
16
16
|
filter_class = available_filters.find { |f| f.filter_key == hsh["type"] }
|
|
17
|
-
filter_class
|
|
17
|
+
filter_class&.new(hsh, depth)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def key_to_hsh(key)
|
data/lib/text/gen/meta.rb
CHANGED
data/lib/text/gen/runner.rb
CHANGED
|
@@ -68,12 +68,12 @@ module Text
|
|
|
68
68
|
return if items.empty?
|
|
69
69
|
|
|
70
70
|
case context.current_strategy
|
|
71
|
+
when "sample"
|
|
72
|
+
run_random_item(context, items)
|
|
71
73
|
when "sequence"
|
|
72
74
|
run_item_sequence(context, items)
|
|
73
|
-
when "weighted"
|
|
74
|
-
run_weighted_items(context, items)
|
|
75
75
|
else
|
|
76
|
-
|
|
76
|
+
run_weighted_items(context, items)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -94,7 +94,7 @@ module Text
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def run_weighted_items(context, items)
|
|
97
|
-
total_weight =
|
|
97
|
+
total_weight = calculate_total_weight(context, items)
|
|
98
98
|
dice = context.current_modifier
|
|
99
99
|
rand_weight = if dice.nil? || dice.empty? || dice == "*"
|
|
100
100
|
rand(total_weight)
|
|
@@ -142,10 +142,10 @@ module Text
|
|
|
142
142
|
return if results.any?(&:nil?) || results.empty?
|
|
143
143
|
|
|
144
144
|
result = Result.merge(results,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
value: item["value"],
|
|
146
|
+
multiplier: item["multiplier"],
|
|
147
|
+
meta: item["meta"],
|
|
148
|
+
type: context.current_key)
|
|
149
149
|
context.apply_result_filters(result)
|
|
150
150
|
end
|
|
151
151
|
end
|
|
@@ -201,6 +201,36 @@ module Text
|
|
|
201
201
|
end
|
|
202
202
|
end
|
|
203
203
|
|
|
204
|
+
def calculate_weight(context, item)
|
|
205
|
+
weight = item["weight"]
|
|
206
|
+
if weight == "*"
|
|
207
|
+
reference = item["segments"]&.find { |s| s["type"] == "reference" }
|
|
208
|
+
key = reference&.fetch("text")
|
|
209
|
+
weight = lookup_and_count_items(context, key)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
[weight.to_i, 1].max
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def lookup_and_count_items(context, key)
|
|
216
|
+
return 0 unless key
|
|
217
|
+
|
|
218
|
+
builder = context.store.fetch(key)
|
|
219
|
+
return 0 unless builder
|
|
220
|
+
|
|
221
|
+
builder["items"]&.size || 1
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def calculate_total_weight(context, items)
|
|
225
|
+
sum = 0
|
|
226
|
+
items.each do |item|
|
|
227
|
+
weight = calculate_weight(context, item)
|
|
228
|
+
item["weight"] = weight
|
|
229
|
+
sum += weight
|
|
230
|
+
end
|
|
231
|
+
sum
|
|
232
|
+
end
|
|
233
|
+
|
|
204
234
|
def random_from_dice(text)
|
|
205
235
|
rolled = DiceNomShim.roll(text)
|
|
206
236
|
parsed = JSON.parse(rolled).first["lhs"]
|
|
@@ -4,7 +4,7 @@ module Text
|
|
|
4
4
|
module Gen
|
|
5
5
|
module Segment
|
|
6
6
|
class Reference
|
|
7
|
-
REFERENCE_MATCHER = /\[\s*([a-z0-9-]+(
|
|
7
|
+
REFERENCE_MATCHER = /\[\s*([a-z0-9-]+(?:(?:>>|>|:)[a-z0-9-]+)*)\s*\]/
|
|
8
8
|
class << self
|
|
9
9
|
def scan(scanner)
|
|
10
10
|
str = scanner.scan(REFERENCE_MATCHER)
|
data/lib/text/gen/store.rb
CHANGED
|
@@ -6,6 +6,7 @@ module Text
|
|
|
6
6
|
# to save time on database lookups or transformations.
|
|
7
7
|
class Store
|
|
8
8
|
NOT_FOUND_BUILDER = {
|
|
9
|
+
"strategy" => "sample",
|
|
9
10
|
"filters" => [],
|
|
10
11
|
"meta" => {},
|
|
11
12
|
"items" => []
|
|
@@ -33,12 +34,30 @@ module Text
|
|
|
33
34
|
builder = find(key)
|
|
34
35
|
return builder if builder
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
keys = key.split("+")
|
|
38
|
+
builders = keys.map do |key|
|
|
39
|
+
builder = @lookup.call(key)
|
|
40
|
+
builder ||= not_found(key)
|
|
41
|
+
builder
|
|
42
|
+
end
|
|
38
43
|
|
|
44
|
+
builder = merge_builders(builders) if builders.length > 1
|
|
39
45
|
add(key, builder.merge("key" => key.to_s.downcase))
|
|
40
46
|
end
|
|
41
47
|
|
|
48
|
+
def merge_builders(builders)
|
|
49
|
+
all_filters = builders.map { |b| b["filters"] }.flatten
|
|
50
|
+
all_meta = builders.inject({}) { |b, acc| Text::Gen::Meta.merge_meta(acc, b["meta"]) }
|
|
51
|
+
all_items = builders.map { |b| b["items"] }.flatten
|
|
52
|
+
strategy = builders.all? { |b| b["strategy"] == "weighted" } ? "weighted" : "sample"
|
|
53
|
+
{
|
|
54
|
+
"strategy" => strategy,
|
|
55
|
+
"filters" => all_filters,
|
|
56
|
+
"meta" => all_meta,
|
|
57
|
+
"items" => all_items
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
42
61
|
def not_found(key)
|
|
43
62
|
hsh = NOT_FOUND_BUILDER.dup
|
|
44
63
|
hsh["key"] = key
|
data/lib/text/gen/version.rb
CHANGED