Class: Text::Gen::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/text/gen/runner.rb

Overview

Runner generates results from the builder that is found with the given key.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key:, lookup:, max_recursion: 10, max_attempts: 10, request_filters: []) ⇒ Runner

Returns a new instance of Runner.



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/text/gen/runner.rb', line 13

def initialize(key:, lookup:, max_recursion: 10, max_attempts: 10, request_filters: [])
  @key = key.to_s.downcase
  @lookup = lookup
  @locale = nil
  @store = Store.new
  @unique = false
  @request_filters = request_filters
  @max_attempts = max_attempts
  @max_recursion = max_recursion
  populate_replace
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



10
11
12
# File 'lib/text/gen/runner.rb', line 10

def key
  @key
end

#localeObject

Returns the value of attribute locale.



11
12
13
# File 'lib/text/gen/runner.rb', line 11

def locale
  @locale
end

#lookupObject (readonly)

Returns the value of attribute lookup.



10
11
12
# File 'lib/text/gen/runner.rb', line 10

def lookup
  @lookup
end

#max_attemptsObject (readonly)

Returns the value of attribute max_attempts.



10
11
12
# File 'lib/text/gen/runner.rb', line 10

def max_attempts
  @max_attempts
end

#max_recursionObject (readonly)

Returns the value of attribute max_recursion.



10
11
12
# File 'lib/text/gen/runner.rb', line 10

def max_recursion
  @max_recursion
end

#storeObject

Returns the value of attribute store.



11
12
13
# File 'lib/text/gen/runner.rb', line 11

def store
  @store
end

#uniqueObject

Returns the value of attribute unique.



11
12
13
# File 'lib/text/gen/runner.rb', line 11

def unique
  @unique
end

Class Method Details

.from_hash(hash) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/text/gen/runner.rb', line 198

def from_hash(hash)
  runner = Runner.new(
    key: hash["key"],
    request_filters: hash.fetch("request_filters", [])
  )

  hash.fetch("store", {}).each do |k, b|
    runner.store.add(k, b)
  end

  runner
end

Instance Method Details

#apply_item_filters(items, filters) ⇒ Object

Raises:



180
181
182
183
184
185
186
# File 'lib/text/gen/runner.rb', line 180

def apply_item_filters(items, filters)
  items = Filter.filter_select(items, filters)
  items = Filter.filter_reject(items, filters)
  raise FilterError if items.empty?

  items
end

#apply_result_filters(result, filters) ⇒ Object



166
167
168
169
170
# File 'lib/text/gen/runner.rb', line 166

def apply_result_filters(result, filters)
  result = Filter.result_select(result, filters)
  result = Filter.result_reject(result, filters) if result
  result
end

#apply_result_function(result, filters) ⇒ Object



172
173
174
# File 'lib/text/gen/runner.rb', line 172

def apply_result_function(result, filters)
  Filter.functions(result, filters)
end

#fetch_builder(key) ⇒ Object



45
46
47
48
49
# File 'lib/text/gen/runner.rb', line 45

def fetch_builder(key)
  builder = @store.find(key) || lookup.call(key)
  @store.add(key, builder)
  builder
end

#merge_filters(builder, filters) ⇒ Object



176
177
178
# File 'lib/text/gen/runner.rb', line 176

def merge_filters(builder, filters)
  builder.key?("filters") ? builder["filters"] + filters : filters
end

#populate_replaceObject

A filter of type “replace:key:value” creates a temporary builder that always returns the given value.



31
32
33
34
35
# File 'lib/text/gen/runner.rb', line 31

def populate_replace
  @request_filters.each do |f|
    store.add(f["key"], Filter.constant_builder(f["key"], f["value"])) if f["type"] == "replace"
  end
end

#random_from_dice(text) ⇒ Object



143
144
145
146
147
148
149
# File 'lib/text/gen/runner.rb', line 143

def random_from_dice(text)
  rolled = DiceNomShim.roll(text)
  parsed = JSON.parse(rolled).first["lhs"]
  count = parsed["values"].size
  total = parsed["total"]
  [total, count]
end

#random_item(strategy, items) ⇒ Object



77
78
79
80
81
82
83
84
85
# File 'lib/text/gen/runner.rb', line 77

def random_item(strategy, items)
  if strategy.nil? || strategy.empty? || strategy == "random"
    items.sample
  else
    total, count = random_from_dice(strategy)
    total -= count # make the roll 0-indexed
    items[total]
  end
end

#run(count: 1) ⇒ Object



37
38
39
40
41
42
43
# File 'lib/text/gen/runner.rb', line 37

def run(count: 1)
  builder = fetch_builder(key)

  ResultAccumulator.accumulate(unique: unique?, count: count, max_attempts: max_attempts) do
    run_builder(key, builder, @request_filters, 0)
  end
end

#run_builder(_key, builder, filters, depth) ⇒ Object

A builder is hash with a key field, items, filters, and meta

Raises:



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/text/gen/runner.rb', line 52

def run_builder(_key, builder, filters, depth)
  depth += 1
  raise MaxRecursionError if depth > max_recursion

  current_filters = merge_filters(builder, filters)
  current_items = apply_item_filters(builder["items"], current_filters)
  result = run_items(builder["strategy"], current_items, current_filters, builder["meta"], depth)
  return unless result

  result.merge_meta(builder["meta"])
  result = apply_result_function(result, current_filters)
  apply_result_filters(result, current_filters)
end

#run_dice_segment(seg) ⇒ Object



151
152
153
154
# File 'lib/text/gen/runner.rb', line 151

def run_dice_segment(seg)
  total, = random_from_dice(seg["text"])
  Result.new(text: total.to_s, multiplier: total, type: :dice)
end

#run_item(item, depth) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/text/gen/runner.rb', line 116

def run_item(item, depth)
  locale_item = Filter.replace_locale(item, locale)
  item = locale_item || item

  results = item["segments"].map { |seg| run_segment(seg, depth) }
  result = Result.merge(results,
                        value: item["value"],
                        multiplier: item["multiplier"],
                        filters: item["filters"],
                        meta: item["meta"])
  result = apply_result_function(result, item["filters"])
  apply_result_filters(result, item["filters"])
end

#run_item_sequence(items, filters, meta, depth) ⇒ Object



96
97
98
99
# File 'lib/text/gen/runner.rb', line 96

def run_item_sequence(items, filters, meta, depth)
  results = items.map { |item| run_item(item, depth) }
  Result.merge(results, filters:, meta:, type: :sequence)
end

#run_items(strategy, items, filters, meta, depth) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/text/gen/runner.rb', line 66

def run_items(strategy, items, filters, meta, depth)
  case strategy
  when "sequence"
    run_item_sequence(items, filters, meta, depth)
  when "weighted"
    run_weighted_items(items, meta, depth)
  else
    run_random_item(strategy, items, meta, depth)
  end
end

#run_number_segment(seg) ⇒ Object



156
157
158
159
# File 'lib/text/gen/runner.rb', line 156

def run_number_segment(seg)
  num = seg["text"].to_i
  Result.new(text: num.to_s, multiplier: num, type: :number)
end

#run_random_item(strategy, items, meta, depth) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/text/gen/runner.rb', line 87

def run_random_item(strategy, items, meta, depth)
  item = random_item(strategy, items)
  return unless item

  result = run_item(item, depth)
  result.merge_meta(meta)
  result
end

#run_reference_segment(seg, depth) ⇒ Object



161
162
163
164
# File 'lib/text/gen/runner.rb', line 161

def run_reference_segment(seg, depth)
  key = seg["text"]
  run_builder(key, fetch_builder(key), seg.fetch("filters", []), depth)
end

#run_segment(seg, depth) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/text/gen/runner.rb', line 130

def run_segment(seg, depth)
  case seg["type"]
  when "dice"
    run_dice_segment(seg)
  when "number"
    run_number_segment(seg)
  when "reference"
    run_reference_segment(seg, depth)
  else
    Result.new(text: seg["text"], value: seg["value"], type: :constant)
  end
end

#run_weighted_items(items, meta, depth) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/text/gen/runner.rb', line 101

def run_weighted_items(items, meta, depth)
  total_weight = items.sum { |item| [item.fetch("weight", 1).to_i, 1].max }
  rand_weight = rand(total_weight)
  current_weight = 0
  item = items.find do |item|
    current_weight += [item.fetch("weight", 1).to_i, 1].max
    current_weight > rand_weight
  end
  return unless item

  result = run_item(item, depth)
  result.merge_meta(meta)
  result
end

#to_hObject



188
189
190
191
192
193
194
195
# File 'lib/text/gen/runner.rb', line 188

def to_h
  {
    "key" => key,
    "request_filters" => request_filters,
    "request_meta" => request_meta,
    "store" => store.to_h
  }
end

#unique?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/text/gen/runner.rb', line 25

def unique?
  @unique
end