eunomia_gen 0.1.6 → 0.2.0
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/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +67 -0
- data/README.md +10 -10
- data/lib/eunomia/element.rb +3 -0
- data/lib/eunomia/generator.rb +81 -28
- data/lib/eunomia/hash_helpers.rb +10 -4
- data/lib/eunomia/item.rb +17 -27
- data/lib/eunomia/request.rb +17 -24
- data/lib/eunomia/result.rb +10 -16
- data/lib/eunomia/segment/common.rb +5 -1
- data/lib/eunomia/segment/constant.rb +7 -2
- data/lib/eunomia/segment/dice.rb +4 -0
- data/lib/eunomia/segment/number.rb +7 -1
- data/lib/eunomia/segment/reference.rb +6 -2
- data/lib/eunomia/segment/text.rb +4 -0
- data/lib/eunomia/segment.rb +3 -1
- data/lib/eunomia/selector.rb +14 -3
- data/lib/eunomia/separator.rb +1 -1
- data/lib/eunomia/store.rb +4 -4
- data/lib/eunomia/version.rb +1 -1
- data/lib/eunomia.rb +13 -14
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bd9d4df4c021ff782daad47aafdd3ec4e16bcabe47cccbf81cd9d5dbf3816c2
|
|
4
|
+
data.tar.gz: d5de7918c9d7d8ff2c62f7c5b4376c020442574f1dda00cc4de43529a1eafcb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b328162d070df9ed863886cae24a72e884b7b732bb5300dc42c09f7a0650de5921c008a68df9f40cfe2af6760f2ff48e51c0a2ec1f3336a56a7178628f6d8d94
|
|
7
|
+
data.tar.gz: 012fd582fb8a5726e5bd5ee55c57bbae27b8d51153f3e9e056e1f4cff81fe119a4f71cee36d03fd7da74bb76765f674f7dc0fc509fb5993d21f42b902399814a
|
data/.rubocop.yml
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
require: rubocop-rspec
|
|
4
|
+
|
|
1
5
|
AllCops:
|
|
2
6
|
NewCops: enable
|
|
3
|
-
TargetRubyVersion: 3.
|
|
7
|
+
TargetRubyVersion: 3.1
|
|
8
|
+
SuggestExtensions: false
|
|
4
9
|
|
|
5
10
|
Style/StringLiterals:
|
|
6
11
|
EnforcedStyle: double_quotes
|
|
7
12
|
|
|
8
13
|
Style/StringLiteralsInInterpolation:
|
|
9
14
|
EnforcedStyle: double_quotes
|
|
15
|
+
|
|
16
|
+
RSpec/ExampleLength:
|
|
17
|
+
Max: 20
|
|
18
|
+
|
|
19
|
+
RSpec/MultipleExpectations:
|
|
20
|
+
Max: 5
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2024-12-21 18:48:58 UTC using RuboCop version 1.66.1.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 2
|
|
10
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
11
|
+
Metrics/AbcSize:
|
|
12
|
+
Max: 29
|
|
13
|
+
|
|
14
|
+
# Offense count: 2
|
|
15
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
16
|
+
Metrics/MethodLength:
|
|
17
|
+
Max: 13
|
|
18
|
+
|
|
19
|
+
# Offense count: 2
|
|
20
|
+
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
|
21
|
+
Metrics/ParameterLists:
|
|
22
|
+
Max: 8
|
|
23
|
+
|
|
24
|
+
# Offense count: 2
|
|
25
|
+
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
|
26
|
+
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
|
27
|
+
Naming/MethodParameterName:
|
|
28
|
+
Exclude:
|
|
29
|
+
- 'lib/eunomia/result.rb'
|
|
30
|
+
- 'lib/eunomia/segment/dice.rb'
|
|
31
|
+
|
|
32
|
+
# Offense count: 1
|
|
33
|
+
# Configuration parameters: Max, CountAsOne.
|
|
34
|
+
RSpec/ExampleLength:
|
|
35
|
+
Exclude:
|
|
36
|
+
- 'spec/eunomia/selector_spec.rb'
|
|
37
|
+
|
|
38
|
+
# Offense count: 2
|
|
39
|
+
# Configuration parameters: Max.
|
|
40
|
+
RSpec/MultipleExpectations:
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'spec/eunomia/segment/dice_spec.rb'
|
|
43
|
+
- 'spec/eunomia/segment_spec.rb'
|
|
44
|
+
|
|
45
|
+
# Offense count: 1
|
|
46
|
+
# Configuration parameters: AllowedPatterns.
|
|
47
|
+
# AllowedPatterns: ^expect_, ^assert_
|
|
48
|
+
RSpec/NoExpectationExample:
|
|
49
|
+
Exclude:
|
|
50
|
+
- 'spec/examples/**/*.rb'
|
|
51
|
+
- 'spec/eunomia/request_spec.rb'
|
|
52
|
+
|
|
53
|
+
# Offense count: 1
|
|
54
|
+
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
|
|
55
|
+
# Include: **/*_spec.rb
|
|
56
|
+
RSpec/SpecFilePathFormat:
|
|
57
|
+
Exclude:
|
|
58
|
+
- '**/spec/routing/**/*'
|
|
59
|
+
- 'spec/eunomia/tags_spec.rb'
|
|
60
|
+
|
|
61
|
+
# Offense count: 1
|
|
62
|
+
# Configuration parameters: AllowedConstants.
|
|
63
|
+
Style/Documentation:
|
|
64
|
+
Exclude:
|
|
65
|
+
- 'spec/**/*'
|
|
66
|
+
- 'test/**/*'
|
|
67
|
+
- 'lib/eunomia/separator.rb'
|
data/README.md
CHANGED
|
@@ -71,7 +71,7 @@ data = [
|
|
|
71
71
|
]
|
|
72
72
|
|
|
73
73
|
Eunomia.add(data)
|
|
74
|
-
request = Eunomia::Request.new("fruit",
|
|
74
|
+
request = Eunomia::Request.new("fruit", locale: "es", unique: true, alts: { "kiwi" => "a small flightless bird" })
|
|
75
75
|
arr = []
|
|
76
76
|
5.times { arr << request.generate.to_s }
|
|
77
77
|
p arr.join(", ") # => "manzana, banana, orange, pear, a small flightless bird"
|
|
@@ -101,7 +101,7 @@ request = Eunomia::Request.new("random-fruit", functions: %w[pluralize reverse])
|
|
|
101
101
|
p request.generate.to_s # => "3 sananab"
|
|
102
102
|
|
|
103
103
|
request = Eunomia::Request.new("random-fruit", functions: %w[reverse pluralize])
|
|
104
|
-
p request.generate.to_s # => "3
|
|
104
|
+
p request.generate.to_s # => "3 iwiks"
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
### Weights
|
|
@@ -125,31 +125,31 @@ If the first segment is not a number the multiplier defaults to 1.
|
|
|
125
125
|
A constant hash can be added to the request. A string that matches the hash key will be replaced by the
|
|
126
126
|
constant value.
|
|
127
127
|
|
|
128
|
-
###
|
|
128
|
+
### Filtering
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
plants could be filtered to only those that are also names to generate a character name.
|
|
132
|
-
to an item are also added as
|
|
130
|
+
Filters can be used to filter items. For example, some plant names are also used as names. So a list of
|
|
131
|
+
plants could be filtered to only those that are also names to generate a character name. Filters assigned
|
|
132
|
+
to an item are also added as metadata to the result if the filter is in `key:value` format.
|
|
133
133
|
|
|
134
134
|
```ruby
|
|
135
135
|
data = [
|
|
136
136
|
{ key: "plant", items: %w[[flower] [tree]] },
|
|
137
137
|
{ key: "flower", items: [
|
|
138
|
-
{ segments: "rose",
|
|
138
|
+
{ segments: "rose", filters: %w[name:plant] },
|
|
139
139
|
{ segments: "hydrangea" }
|
|
140
140
|
]
|
|
141
141
|
},
|
|
142
142
|
{ key: "tree", items: [
|
|
143
|
-
{ segments: "ash",
|
|
143
|
+
{ segments: "ash", filters: %w[name:plant] },
|
|
144
144
|
{ segments: "oak" }
|
|
145
145
|
]
|
|
146
146
|
}
|
|
147
147
|
]
|
|
148
148
|
|
|
149
149
|
Eunomia.add(data)
|
|
150
|
-
val = Eunomia.generate("plant",
|
|
150
|
+
val = Eunomia.generate("plant", filters: %w[name:plant], functions: ["capitalize"])
|
|
151
151
|
p val.to_s # => "Rose" or "Ash"
|
|
152
|
-
p val.meta # => { "
|
|
152
|
+
p val.meta # => { "filter" => "name:plant" }
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
## Development
|
data/lib/eunomia/element.rb
CHANGED
data/lib/eunomia/generator.rb
CHANGED
|
@@ -6,40 +6,57 @@ module Eunomia
|
|
|
6
6
|
class Generator
|
|
7
7
|
include Eunomia::HashHelpers
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
PASS_FILTER_ATTEMPTS = 20
|
|
10
|
+
|
|
11
|
+
# Normalized identifier for this generator
|
|
12
|
+
attr_reader :key
|
|
13
|
+
|
|
14
|
+
# Key value pairs of string values to swap out for this generator results
|
|
15
|
+
attr_reader :alts
|
|
16
|
+
|
|
17
|
+
# Key vaule pair of generator keys to values; if the key is seen the value is replaced
|
|
18
|
+
# with the constant value
|
|
19
|
+
attr_reader :constants
|
|
20
|
+
|
|
21
|
+
# Functions to apply to the generated string from this generator
|
|
22
|
+
attr_reader :functions
|
|
23
|
+
|
|
24
|
+
# Filters are key value paris that must match the generated metadata to be selected
|
|
25
|
+
attr_reader :filters
|
|
26
|
+
|
|
27
|
+
# Are the items selected in order (sequence) or random
|
|
28
|
+
attr_reader :gen
|
|
29
|
+
|
|
30
|
+
# The items in this generator
|
|
31
|
+
attr_reader :items
|
|
32
|
+
|
|
33
|
+
# The random number generator used to select items
|
|
34
|
+
attr_reader :selector
|
|
18
35
|
|
|
19
36
|
def initialize(hsh)
|
|
20
37
|
@key = field_or_raise(hsh, :key)
|
|
21
|
-
@aliases = list_field(hsh, :aliases)
|
|
22
38
|
@functions = list_field(hsh, :functions)
|
|
23
39
|
@alts = hash_field(hsh, :alts)
|
|
24
|
-
@
|
|
25
|
-
@
|
|
40
|
+
@constants = hash_field(hsh, :constants)
|
|
41
|
+
@filters = filters_field(hsh)
|
|
42
|
+
@gen = field_or_nil(hsh, :gen).to_s == "sequence" ? :sequence : :random
|
|
26
43
|
@selector = Eunomia::Selector.new(field_or_nil(hsh, :rng))
|
|
27
44
|
@items = items_from(hsh)
|
|
28
45
|
raise "Generators must have items" if @items.empty?
|
|
29
46
|
end
|
|
30
47
|
|
|
48
|
+
def random?
|
|
49
|
+
gen == :random
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def sequence?
|
|
53
|
+
!random?
|
|
54
|
+
end
|
|
55
|
+
|
|
31
56
|
def items_from(hsh)
|
|
32
57
|
list_field(hsh, :items).map do |item|
|
|
33
58
|
item = { segments: item } if item.is_a?(String)
|
|
34
|
-
Eunomia::Item.new(@key, item
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def item_tags
|
|
39
|
-
@item_tags ||= begin
|
|
40
|
-
set = Set.new
|
|
41
|
-
items.each { |item| set += item.available_tags }
|
|
42
|
-
set
|
|
59
|
+
Eunomia::Item.new(@key, item)
|
|
43
60
|
end
|
|
44
61
|
end
|
|
45
62
|
|
|
@@ -50,22 +67,58 @@ module Eunomia
|
|
|
50
67
|
alts[key][segment] || segment
|
|
51
68
|
end
|
|
52
69
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return items if tags.empty?
|
|
70
|
+
def passes_filters?(result)
|
|
71
|
+
return true if filters.empty?
|
|
56
72
|
|
|
57
|
-
|
|
73
|
+
# For every filter defined on this generator
|
|
74
|
+
filters.all? do |key, values|
|
|
75
|
+
found = result.meta[key]
|
|
76
|
+
found && (values.include?("*") || found.any? { |f| values.include?(f) })
|
|
77
|
+
end
|
|
58
78
|
end
|
|
59
79
|
|
|
60
80
|
def generate(request)
|
|
61
|
-
|
|
81
|
+
trys = PASS_FILTER_ATTEMPTS
|
|
82
|
+
|
|
83
|
+
loop do
|
|
84
|
+
trys -= 1
|
|
85
|
+
break if trys <= 0
|
|
86
|
+
|
|
87
|
+
result = if random?
|
|
88
|
+
generate_random(request, items)
|
|
89
|
+
else
|
|
90
|
+
generate_sequence(request, items)
|
|
91
|
+
end
|
|
92
|
+
return result if passes_filters?(result)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
raise "Unable to generate a filtered result after #{PASS_FILTER_ATTEMPTS} attempts"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def generate_random(request, items)
|
|
62
99
|
item = selector.select(items)
|
|
63
100
|
raise "No items found for #{key}" unless item
|
|
64
101
|
|
|
65
102
|
result = item.generate(request)
|
|
66
|
-
result.apply(alts, functions, locale: request.
|
|
67
|
-
result.merge_meta(meta)
|
|
103
|
+
result.apply(alts, functions, locale: request.locale)
|
|
68
104
|
result
|
|
69
105
|
end
|
|
106
|
+
|
|
107
|
+
def generate_sequence(request, items)
|
|
108
|
+
result = Eunomia::Result.new(key)
|
|
109
|
+
items.each do |item|
|
|
110
|
+
result.append(item.generate(request))
|
|
111
|
+
end
|
|
112
|
+
result
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def to_h
|
|
116
|
+
hsh = { key:, gen:, items: items.map(&:to_h) }
|
|
117
|
+
hsh[:rng] = selector if selector.count
|
|
118
|
+
hsh[:filters] = filters_to_tags(filters) unless filters.empty?
|
|
119
|
+
hsh[:alts] = alts unless alts.empty?
|
|
120
|
+
hsh[:functions] = functions unless functions.empty?
|
|
121
|
+
hsh
|
|
122
|
+
end
|
|
70
123
|
end
|
|
71
124
|
end
|
data/lib/eunomia/hash_helpers.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
|
+
# Lookup methods for hashes to kandle symbol and string keys
|
|
4
5
|
module HashHelpers
|
|
5
6
|
def field_or_nil(hsh, key)
|
|
6
7
|
hsh[key.to_sym] || hsh[key.to_s]
|
|
@@ -25,11 +26,16 @@ module Eunomia
|
|
|
25
26
|
field.is_a?(String) ? field.split(/\s+/) : field
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
def
|
|
29
|
-
tags = list_field(hsh, :
|
|
30
|
-
|
|
29
|
+
def filters_field(hsh)
|
|
30
|
+
tags = list_field(hsh, :filters)
|
|
31
|
+
tags.each_with_object({}) do |tag, filters|
|
|
32
|
+
key, values = tag.split(":")
|
|
33
|
+
filters[key] = Set.new(values.split(","))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
def filters_to_tags(hsh)
|
|
38
|
+
hsh.to_a.map { |k, v| "#{k}:#{v.join(",")}" }.join(" ")
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def alts_field(hsh)
|
data/lib/eunomia/item.rb
CHANGED
|
@@ -8,13 +8,12 @@ module Eunomia
|
|
|
8
8
|
attr_reader :key,
|
|
9
9
|
:weight,
|
|
10
10
|
:value,
|
|
11
|
-
:tags,
|
|
12
11
|
:alts,
|
|
13
12
|
:meta,
|
|
14
13
|
:functions,
|
|
15
14
|
:segments
|
|
16
15
|
|
|
17
|
-
def initialize(key, hsh
|
|
16
|
+
def initialize(key, hsh)
|
|
18
17
|
@key = key
|
|
19
18
|
@weight = int_field(hsh, :weight).clamp(1, 1000)
|
|
20
19
|
@value = int_field(hsh, :value).clamp(0, 1_000_000)
|
|
@@ -22,22 +21,10 @@ module Eunomia
|
|
|
22
21
|
@meta = meta_field(hsh)
|
|
23
22
|
@functions = list_field(hsh, :functions)
|
|
24
23
|
@segments = scan(field_or_raise(hsh, :segments)).flatten
|
|
25
|
-
@tags = tags_field(hsh)
|
|
26
|
-
@tags += add_tags if add_tags
|
|
27
|
-
@available_tags = nil
|
|
28
24
|
end
|
|
29
25
|
|
|
30
|
-
def
|
|
31
|
-
@
|
|
32
|
-
s = Set.new
|
|
33
|
-
s += tags
|
|
34
|
-
refs = segments.filter { |seg| seg.is_a?(Eunomia::Segment::Reference) }
|
|
35
|
-
unless refs.empty?
|
|
36
|
-
s = refs[0].item_tags
|
|
37
|
-
refs[1..].each { |ref| s &= ref.item_tags }
|
|
38
|
-
end
|
|
39
|
-
s
|
|
40
|
-
end
|
|
26
|
+
def meta_keys
|
|
27
|
+
@meta_keys ||= (Set.new(meta.keys) + segments.map(&:meta_keys).inject(&:merge))
|
|
41
28
|
end
|
|
42
29
|
|
|
43
30
|
def scan(obj)
|
|
@@ -47,14 +34,6 @@ module Eunomia
|
|
|
47
34
|
obj.map { |e| Eunomia::Segment.build(e) }.flatten
|
|
48
35
|
end
|
|
49
36
|
|
|
50
|
-
def match_tags?(tags)
|
|
51
|
-
return true if tags.nil? || tags.empty?
|
|
52
|
-
return true if (tags - self.tags).empty?
|
|
53
|
-
return true if (tags - available_tags).empty?
|
|
54
|
-
|
|
55
|
-
false
|
|
56
|
-
end
|
|
57
|
-
|
|
58
37
|
def alt_for(key, segment)
|
|
59
38
|
return segment unless key
|
|
60
39
|
return segment unless alts[key]
|
|
@@ -63,12 +42,23 @@ module Eunomia
|
|
|
63
42
|
end
|
|
64
43
|
|
|
65
44
|
def generate(request)
|
|
66
|
-
result = Eunomia::Result.new(key, value:
|
|
45
|
+
result = Eunomia::Result.new(key, value:)
|
|
67
46
|
segments.each { |seg| result.append(seg.generate(request)) }
|
|
68
|
-
result.apply(alts, functions, locale: request.
|
|
47
|
+
result.apply(alts, functions, locale: request.locale)
|
|
69
48
|
result.merge_meta(meta)
|
|
70
|
-
result.add_tags_as_meta(tags)
|
|
71
49
|
result
|
|
72
50
|
end
|
|
51
|
+
|
|
52
|
+
def to_h
|
|
53
|
+
hsh = {
|
|
54
|
+
segments: segments.map(&:to_s).join,
|
|
55
|
+
weight:
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
hsh[:value] = value if value != 0
|
|
59
|
+
hsh[:meta] = meta unless meta.empty?
|
|
60
|
+
hsh[:functinos] = functions unless functions.empty?
|
|
61
|
+
hsh
|
|
62
|
+
end
|
|
73
63
|
end
|
|
74
64
|
end
|
data/lib/eunomia/request.rb
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@alt_key = alt_key
|
|
10
|
-
@alts = alts || {}
|
|
11
|
-
@meta = meta || {}
|
|
12
|
-
@tags = Set.new(tags || [])
|
|
13
|
-
@constants = constants || {}
|
|
14
|
-
@functions = functions || []
|
|
15
|
-
@depth = 0
|
|
16
|
-
@unique = unique ? Set.new : nil
|
|
17
|
-
end
|
|
4
|
+
# Encapsuate a request for string generation
|
|
5
|
+
class Request < Eunomia::Generator
|
|
6
|
+
# If not nil, a set of value strings; this is
|
|
7
|
+
# Persisted across calls to generate
|
|
8
|
+
attr_reader :unique
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
end
|
|
10
|
+
# If given, alts are chosen from the given locale key
|
|
11
|
+
attr_reader :locale
|
|
22
12
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
13
|
+
# The current depth (calls to generate) for the run
|
|
14
|
+
attr_reader :depth
|
|
26
15
|
|
|
27
|
-
def
|
|
28
|
-
|
|
16
|
+
def initialize(key, alts: {}, locale: nil, constants: {}, filters: [], functions: [], unique: false)
|
|
17
|
+
hsh = { key:, items: ["request"], alts:, constants:, filters:, gen: "sequence", functions: }
|
|
18
|
+
@unique = unique ? Set.new : nil
|
|
19
|
+
@depth = 0
|
|
20
|
+
@locale = locale
|
|
21
|
+
super(hsh)
|
|
29
22
|
end
|
|
30
23
|
|
|
31
24
|
def increase_depth
|
|
@@ -40,10 +33,10 @@ module Eunomia
|
|
|
40
33
|
100.times do
|
|
41
34
|
result = gen.generate(self)
|
|
42
35
|
result.apply(alts, functions)
|
|
43
|
-
return result if
|
|
36
|
+
return result if passes_filters?(result) && (!unique || unique.add?(result.to_s))
|
|
44
37
|
end
|
|
45
38
|
|
|
46
|
-
raise "Unable to find a unique result"
|
|
39
|
+
raise "Unable to find a unique result that passes filters"
|
|
47
40
|
end
|
|
48
41
|
end
|
|
49
42
|
end
|
data/lib/eunomia/result.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
|
+
# A generated result
|
|
4
5
|
class Result
|
|
5
6
|
attr_reader :key, :display, :elements, :multiplier, :base_value, :meta
|
|
6
7
|
|
|
@@ -9,16 +10,17 @@ module Eunomia
|
|
|
9
10
|
@base_value = value
|
|
10
11
|
@multiplier = multiplier
|
|
11
12
|
@elements = []
|
|
12
|
-
@meta = Hash.new {|h,k| h[k] = Set.new}
|
|
13
|
+
@meta = Hash.new { |h, k| h[k] = Set.new }
|
|
13
14
|
@display = ""
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def append(obj)
|
|
17
|
-
|
|
18
|
+
case obj
|
|
19
|
+
when Element
|
|
18
20
|
append_element(obj)
|
|
19
|
-
|
|
21
|
+
when Result
|
|
20
22
|
append_result(obj)
|
|
21
|
-
|
|
23
|
+
when Separator
|
|
22
24
|
append_separator(obj)
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -55,19 +57,11 @@ module Eunomia
|
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
|
-
def add_tags_as_meta(tags)
|
|
59
|
-
tags.each do |tag|
|
|
60
|
-
arr = tag.split(':')
|
|
61
|
-
@meta[arr[0]] << arr[1].gsub("-", " ") if arr.length > 1
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
|
|
66
60
|
def apply_translations(alts, locale: nil)
|
|
67
61
|
arr = to_s.split(/\s+/)
|
|
68
|
-
arr
|
|
62
|
+
arr.map do |segment|
|
|
69
63
|
hsh = alts[segment]
|
|
70
|
-
hsh
|
|
64
|
+
hsh.is_a?(Hash) ? hsh[locale] || hsh["*"] || segment : hsh || segment
|
|
71
65
|
end
|
|
72
66
|
end
|
|
73
67
|
|
|
@@ -76,10 +70,10 @@ module Eunomia
|
|
|
76
70
|
end
|
|
77
71
|
|
|
78
72
|
def apply(alts, functions, locale: nil)
|
|
79
|
-
arr = apply_translations(alts, locale:
|
|
73
|
+
arr = apply_translations(alts, locale:)
|
|
80
74
|
arr = apply_functions(arr, functions)
|
|
81
75
|
|
|
82
|
-
@display = arr.join(
|
|
76
|
+
@display = arr.join(" ")
|
|
83
77
|
self
|
|
84
78
|
end
|
|
85
79
|
|
|
@@ -14,7 +14,11 @@ module Eunomia
|
|
|
14
14
|
|
|
15
15
|
def generate(_request)
|
|
16
16
|
calc # update values for dynamic segments
|
|
17
|
-
Eunomia::Element.new(text, value
|
|
17
|
+
Eunomia::Element.new(text, value:, multiplier:)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def meta_keys
|
|
21
|
+
Set.new
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
def calc; end
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
4
|
module Segment
|
|
5
|
+
# Represents a constant in a segment.
|
|
5
6
|
class Constant
|
|
6
7
|
include Common
|
|
7
8
|
|
|
8
|
-
SEPARATOR_MATCHER = /\p{Space}|\p{Punct}/
|
|
9
|
+
SEPARATOR_MATCHER = /\p{Space}|\p{Punct}|[+]/
|
|
9
10
|
|
|
10
11
|
attr_reader :text
|
|
11
12
|
|
|
@@ -14,10 +15,14 @@ module Eunomia
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def generate(_request)
|
|
17
|
-
calc # update values for dynamic segments
|
|
18
|
+
# calc # update values for dynamic segments
|
|
18
19
|
Eunomia::Separator.new(text)
|
|
19
20
|
end
|
|
20
21
|
|
|
22
|
+
def to_s
|
|
23
|
+
text
|
|
24
|
+
end
|
|
25
|
+
|
|
21
26
|
def self.build(scanner)
|
|
22
27
|
str = scanner.scan(SEPARATOR_MATCHER)
|
|
23
28
|
new(str) if str
|
data/lib/eunomia/segment/dice.rb
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
4
|
module Segment
|
|
5
|
+
# Represents a number in a segment. The value
|
|
6
|
+
# is the multiplier for the item.
|
|
5
7
|
class Number
|
|
6
8
|
include Common
|
|
7
9
|
|
|
8
|
-
NUMBER_MATCHER = /(
|
|
10
|
+
NUMBER_MATCHER = /([+-]?\d+)/
|
|
9
11
|
|
|
10
12
|
attr_reader :text, :multipler
|
|
11
13
|
|
|
@@ -14,6 +16,10 @@ module Eunomia
|
|
|
14
16
|
@text = number.to_s
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
def to_s
|
|
20
|
+
text
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
def self.build(scanner)
|
|
18
24
|
str = scanner.scan(NUMBER_MATCHER)
|
|
19
25
|
new(str) if str
|
|
@@ -30,8 +30,8 @@ module Eunomia
|
|
|
30
30
|
@generator ||= Eunomia.lookup(key)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
34
|
-
generator.
|
|
33
|
+
def meta_keys
|
|
34
|
+
generator.meta_keys
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def generate(request)
|
|
@@ -45,6 +45,10 @@ module Eunomia
|
|
|
45
45
|
@lookup ||= label.nil? ? key : "#{key}:#{label}"
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def to_s
|
|
49
|
+
"[#{lookup}]"
|
|
50
|
+
end
|
|
51
|
+
|
|
48
52
|
def self.build(scanner)
|
|
49
53
|
str = scanner.scan(REFERENCE_MATCHER)
|
|
50
54
|
return unless str
|
data/lib/eunomia/segment/text.rb
CHANGED
data/lib/eunomia/segment.rb
CHANGED
|
@@ -10,6 +10,8 @@ require_relative "segment/number"
|
|
|
10
10
|
require_relative "segment/reference"
|
|
11
11
|
|
|
12
12
|
module Eunomia
|
|
13
|
+
class EunomiaParseError < StandardError; end
|
|
14
|
+
|
|
13
15
|
# Segment represents a single token in an `Item`.
|
|
14
16
|
module Segment
|
|
15
17
|
def self.build(str)
|
|
@@ -21,7 +23,7 @@ module Eunomia
|
|
|
21
23
|
Eunomia::Segment::Number.build(ss) ||
|
|
22
24
|
Eunomia::Segment::Text.build(ss) ||
|
|
23
25
|
Eunomia::Segment::Constant.build(ss)
|
|
24
|
-
raise "Unable to parse #{ss.rest} (#{ss.rest_size})" unless seg
|
|
26
|
+
raise EunomiaParseError, "Unable to parse #{ss.rest} (#{ss.rest_size})" unless seg
|
|
25
27
|
|
|
26
28
|
arr << seg
|
|
27
29
|
end
|
data/lib/eunomia/selector.rb
CHANGED
|
@@ -39,6 +39,14 @@ module Eunomia
|
|
|
39
39
|
nil
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
def sequence(items)
|
|
43
|
+
# Weights for a sequence are the chance of not appearing in the
|
|
44
|
+
# result
|
|
45
|
+
items.select do |item|
|
|
46
|
+
item.weight <= count.nil? ? rand(1..100) : roll
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
42
50
|
def random(items)
|
|
43
51
|
max_weight = items.map(&:weight).sum
|
|
44
52
|
if count.nil? || count >= max_weight
|
|
@@ -50,10 +58,13 @@ module Eunomia
|
|
|
50
58
|
end
|
|
51
59
|
end
|
|
52
60
|
|
|
61
|
+
# zero-index roll of dice (e.g. 3d6 => 0..15)
|
|
53
62
|
def roll
|
|
54
|
-
sum
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
(1..count).inject(0) { |sum, _| sum + rand(range) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to_s
|
|
67
|
+
count ? "#{count}d#{range}" : "random"
|
|
57
68
|
end
|
|
58
69
|
end
|
|
59
70
|
end
|
data/lib/eunomia/separator.rb
CHANGED
data/lib/eunomia/store.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Eunomia
|
|
4
|
+
class EunomiaKeyNotFoundError < StandardError; end
|
|
5
|
+
|
|
4
6
|
# Store holds all the generators. Generators are stored by key.
|
|
5
7
|
class Store
|
|
6
8
|
def initialize
|
|
@@ -8,7 +10,7 @@ module Eunomia
|
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def lookup(key)
|
|
11
|
-
@generators[key] or raise
|
|
13
|
+
@generators[key] or raise EunomiaKeyNotFoundError, "Generator #{key} not found"
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def keys
|
|
@@ -31,9 +33,7 @@ module Eunomia
|
|
|
31
33
|
else
|
|
32
34
|
gen = Eunomia::Generator.new(hsh_or_array)
|
|
33
35
|
@generators[gen.key] = gen
|
|
34
|
-
gen
|
|
35
|
-
@generators[alias_key] = gen
|
|
36
|
-
end
|
|
36
|
+
gen
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
data/lib/eunomia/version.rb
CHANGED
data/lib/eunomia.rb
CHANGED
|
@@ -13,42 +13,41 @@ require_relative "eunomia/result"
|
|
|
13
13
|
require_relative "eunomia/segment"
|
|
14
14
|
require_relative "eunomia/functions"
|
|
15
15
|
|
|
16
|
+
# A random data generator
|
|
16
17
|
module Eunomia
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@@functions = Functions.new
|
|
20
|
-
@@generators = Store.new
|
|
18
|
+
@functions = Functions.new
|
|
19
|
+
@generators = Store.new
|
|
21
20
|
|
|
22
21
|
def self.lookup(key)
|
|
23
|
-
|
|
22
|
+
@generators.lookup(key)
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def self.generate(key, request = nil)
|
|
27
|
-
request
|
|
28
|
-
|
|
26
|
+
request ||= Request.new(key)
|
|
27
|
+
@generators.lookup(key).generate(request)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
def self.read(path)
|
|
32
|
-
|
|
31
|
+
@generators.read(path)
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def self.add(hsh_or_array)
|
|
36
|
-
|
|
35
|
+
@generators.add(hsh_or_array)
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
def self.add_function(name, function)
|
|
40
|
-
|
|
39
|
+
@functions.add(name, function)
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
def self.keys
|
|
44
|
-
|
|
43
|
+
@generators.keys
|
|
45
44
|
end
|
|
46
45
|
|
|
47
|
-
def self.request(key, alts: {},
|
|
48
|
-
Request.new(key, alts:,
|
|
46
|
+
def self.request(key, alts: {}, locale: nil, filters: [], functions: [], constants: {}, unique: false)
|
|
47
|
+
Request.new(key, alts:, locale:, filters:, functions:, constants:, unique:)
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
def self.apply(arr, functions)
|
|
52
|
-
|
|
51
|
+
@functions.apply(arr, functions)
|
|
53
52
|
end
|
|
54
53
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: eunomia_gen
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- G Palmer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Create random string with a focus on RPGs similar to fantasynamegenerators.com
|
|
14
14
|
email:
|
|
@@ -20,6 +20,7 @@ extra_rdoc_files: []
|
|
|
20
20
|
files:
|
|
21
21
|
- ".rspec"
|
|
22
22
|
- ".rubocop.yml"
|
|
23
|
+
- ".rubocop_todo.yml"
|
|
23
24
|
- ".zed/settings.json"
|
|
24
25
|
- ".zed/tasks.json"
|
|
25
26
|
- CHANGELOG.md
|
|
@@ -71,14 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
71
72
|
requirements:
|
|
72
73
|
- - ">="
|
|
73
74
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 3.
|
|
75
|
+
version: 3.1.0
|
|
75
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
77
|
requirements:
|
|
77
78
|
- - ">="
|
|
78
79
|
- !ruby/object:Gem::Version
|
|
79
80
|
version: 3.3.11
|
|
80
81
|
requirements: []
|
|
81
|
-
rubygems_version: 3.5.
|
|
82
|
+
rubygems_version: 3.5.23
|
|
82
83
|
signing_key:
|
|
83
84
|
specification_version: 4
|
|
84
85
|
summary: Generate random strings from a hash specification
|