sqlui 0.1.70 → 0.1.72
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/.release-version +1 -1
- data/app/github/cache.rb +2 -3
- data/app/github/caching_client.rb +5 -1
- data/app/github/client.rb +28 -1
- data/app/github/file.rb +16 -5
- data/app/github/paths.rb +16 -10
- data/app/github/tree.rb +32 -6
- data/app/github/tree_client.rb +79 -21
- data/app/pigs.rb +124 -0
- data/app/saved_config.rb +4 -1
- data/app/server.rb +86 -33
- data/app/sqlui.rb +36 -1
- data/app/views/databases.erb +50 -29
- data/app/views/error.erb +10 -2
- data/app/views/redirect.erb +20 -0
- data/app/views/sqlui.erb +34 -13
- data/client/resources/favicon.svg +50 -1
- data/client/resources/github.svg +3 -0
- data/client/resources/help.css +1 -1
- data/client/resources/saved.css +96 -0
- data/client/resources/sqlui.css +60 -53
- data/client/resources/sqlui.js +186 -100
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d93fb898461c1843f631c16ba879898e54e12374c89bdc49f702420e06d7789e
|
4
|
+
data.tar.gz: 875364afb309801a644900301051cdbe96939d12aa3980eb2e1460668e032b24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3868ba4eac83d9584e6da037ee34e475010b47e0ff4dcdb791837f81125a77f4090c38fd60360f1a12f4fd2f3c5402092b4a936c5eb670c15ab1518583c04b3e
|
7
|
+
data.tar.gz: f9c9c07fdb3016aec05fb2f99c5d307eafc95b2fa9d4d693afb83af71a521d5fa32c9b03137c1f30293218186f432a2eff1a28490290f974b25163126c399fea
|
data/.release-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.72
|
data/app/github/cache.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'logger'
|
4
|
+
|
3
5
|
require_relative '../checks'
|
4
6
|
|
5
7
|
module Github
|
@@ -26,8 +28,6 @@ module Github
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def [](key)
|
29
|
-
check_non_empty_string(key: key)
|
30
|
-
|
31
31
|
@mutex.synchronize do
|
32
32
|
evict
|
33
33
|
if (value = @hash[key])
|
@@ -41,7 +41,6 @@ module Github
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def []=(key, value)
|
44
|
-
check_non_empty_string(key: key)
|
45
44
|
check_is_a(value: [Entry, value])
|
46
45
|
|
47
46
|
@mutex.synchronize do
|
@@ -20,7 +20,7 @@ module Github
|
|
20
20
|
check_positive_integer(cache_for: cache_for)
|
21
21
|
|
22
22
|
if (cache_entry = @cache[url])
|
23
|
-
return cache_entry.value
|
23
|
+
return cache_entry.value.deep_dup
|
24
24
|
end
|
25
25
|
|
26
26
|
response = @client.get(url)
|
@@ -32,5 +32,9 @@ module Github
|
|
32
32
|
check_non_empty_string(url: url)
|
33
33
|
@client.get(url)
|
34
34
|
end
|
35
|
+
|
36
|
+
def post(url, request)
|
37
|
+
@client.post(url, request)
|
38
|
+
end
|
35
39
|
end
|
36
40
|
end
|
data/app/github/client.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'base64'
|
3
4
|
require 'json'
|
4
5
|
require 'logger'
|
5
6
|
require 'rest-client'
|
@@ -28,9 +29,35 @@ module Github
|
|
28
29
|
'X-GitHub-Api-Version' => '2022-11-28'
|
29
30
|
}
|
30
31
|
)
|
31
|
-
|
32
|
+
|
33
|
+
raise "GET #{url} returned #{response.code}, expected 200: #{response}" unless response.code == 200
|
34
|
+
|
35
|
+
JSON.parse(response)
|
36
|
+
rescue RestClient::RequestFailed => e
|
37
|
+
@logger.error("#{self.class} GET #{url} failed: #{e.response.code} #{e.response}")
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
|
41
|
+
def post(url, request)
|
42
|
+
check_non_empty_string(url: url)
|
43
|
+
check_is_a(request: [Hash, request])
|
44
|
+
|
45
|
+
@logger.info "#{self.class} POST #{url}"
|
46
|
+
response = RestClient.post(
|
47
|
+
url,
|
48
|
+
request.to_json,
|
49
|
+
{
|
50
|
+
'Accept' => 'application/vnd.github+json',
|
51
|
+
'Authorization' => "Bearer #{@access_token}",
|
52
|
+
'X-GitHub-Api-Version' => '2022-11-28'
|
53
|
+
}
|
54
|
+
)
|
55
|
+
raise "POST #{url} failed: #{response.code} #{response}" unless response.code == 201
|
32
56
|
|
33
57
|
JSON.parse(response)
|
58
|
+
rescue RestClient::RequestFailed => e
|
59
|
+
@logger.error("#{self.class} POST #{url} failed: #{e.response.code} #{e.response}")
|
60
|
+
raise e
|
34
61
|
end
|
35
62
|
end
|
36
63
|
end
|
data/app/github/file.rb
CHANGED
@@ -7,13 +7,24 @@ module Github
|
|
7
7
|
class File
|
8
8
|
include Checks
|
9
9
|
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :full_path, :path, :tree_sha, :content, :github_url
|
11
11
|
|
12
|
-
def initialize(owner:, repo:,
|
13
|
-
check_non_empty_string(owner: owner, repo: repo,
|
12
|
+
def initialize(owner:, repo:, ref:, tree_sha:, path:, content:)
|
13
|
+
check_non_empty_string(owner: owner, repo: repo, ref: ref, path: path, tree_sha: tree_sha)
|
14
|
+
@full_path = "#{owner}/#{repo}/#{ref}/#{path}"
|
15
|
+
@path = path
|
16
|
+
@tree_sha = tree_sha
|
14
17
|
@content = check_is_a(content: [String, content])
|
15
|
-
@
|
16
|
-
|
18
|
+
@github_url = "https://github.com/#{owner}/#{repo}/blob/#{ref}/#{path}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
self.class == other.class &&
|
23
|
+
@full_path == other.full_path &&
|
24
|
+
@path == other.path &&
|
25
|
+
@tree_sha == other.tree_sha &&
|
26
|
+
@content == other.content &&
|
27
|
+
@github_url == other.github_url
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
data/app/github/paths.rb
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../checks'
|
4
|
+
|
3
5
|
module Github
|
4
6
|
# Methods for dealing with GitHub paths.
|
5
7
|
class Paths
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
class << self
|
9
|
+
include Checks
|
10
|
+
|
11
|
+
# "<owner>/<repo>/<ref>/<some_path>"
|
12
|
+
PATH_PATTERN = %r{^(?:[^/]+/){3}.*[^/]$}
|
13
|
+
private_constant :PATH_PATTERN
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
# Parses a path like "<owner>/<repo>/<ref>/<some_path>" into owner, repo, ref, path.
|
16
|
+
def parse_file_path(path)
|
17
|
+
check_non_empty_string(path: path)
|
18
|
+
raise "invalid path: #{path}" unless PATH_PATTERN.match?(path)
|
14
19
|
|
15
|
-
|
16
|
-
|
20
|
+
owner, repo, ref, *path = path.split('/')
|
21
|
+
path = path.join('/')
|
17
22
|
|
18
|
-
|
23
|
+
[owner, repo, ref, path]
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
data/app/github/tree.rb
CHANGED
@@ -9,9 +9,12 @@ module Github
|
|
9
9
|
include Checks
|
10
10
|
include Enumerable
|
11
11
|
|
12
|
-
attr_reader :truncated
|
12
|
+
attr_reader :owner, :repo, :ref, :truncated, :files
|
13
13
|
|
14
|
-
def initialize(files:, truncated: false)
|
14
|
+
def initialize(owner:, repo:, ref:, files:, truncated: false)
|
15
|
+
@owner = check_non_empty_string(owner: owner)
|
16
|
+
@repo = check_non_empty_string(repo: repo)
|
17
|
+
@ref = check_non_empty_string(ref: ref)
|
15
18
|
@files = check_enumerable_of(files, File)
|
16
19
|
@truncated = check_boolean(truncated: truncated)
|
17
20
|
end
|
@@ -19,22 +22,45 @@ module Github
|
|
19
22
|
class << self
|
20
23
|
include Checks
|
21
24
|
|
22
|
-
def for(owner:, repo:,
|
23
|
-
check_non_empty_string(owner: owner, repo: repo,
|
25
|
+
def for(owner:, repo:, ref:, tree_response:)
|
26
|
+
check_non_empty_string(owner: owner, repo: repo, ref: ref)
|
24
27
|
check_is_a(tree_response: [Hash, tree_response])
|
25
28
|
|
26
29
|
truncated = check_boolean(truncated: tree_response['truncated'])
|
27
30
|
tree = check_is_a(tree: [Array, tree_response['tree']])
|
28
31
|
files = tree.map do |blob|
|
29
|
-
File.new(
|
32
|
+
File.new(
|
33
|
+
owner: owner,
|
34
|
+
repo: repo,
|
35
|
+
ref: ref,
|
36
|
+
tree_sha: tree_response['sha'],
|
37
|
+
path: blob['path'],
|
38
|
+
content: blob['content']
|
39
|
+
)
|
30
40
|
end
|
31
41
|
|
32
|
-
Tree.new(files: files, truncated: truncated)
|
42
|
+
Tree.new(owner: owner, repo: repo, ref: ref, files: files, truncated: truncated)
|
33
43
|
end
|
34
44
|
end
|
35
45
|
|
46
|
+
def [](path)
|
47
|
+
@files.find { |f| f.path == path }
|
48
|
+
end
|
49
|
+
|
36
50
|
def each(&block)
|
37
51
|
@files.each(&block)
|
38
52
|
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
self.class == other.class &&
|
56
|
+
@files == other.files &&
|
57
|
+
@truncated == other.truncated
|
58
|
+
end
|
59
|
+
|
60
|
+
def <<(file)
|
61
|
+
check_is_a(file: [File, file])
|
62
|
+
|
63
|
+
@files << file unless @files.include?(file)
|
64
|
+
end
|
39
65
|
end
|
40
66
|
end
|
data/app/github/tree_client.rb
CHANGED
@@ -4,8 +4,11 @@ require 'base64'
|
|
4
4
|
require 'concurrent/executor/fixed_thread_pool'
|
5
5
|
require 'json'
|
6
6
|
require 'logger'
|
7
|
+
require 'rest-client'
|
7
8
|
|
8
9
|
require_relative 'caching_client'
|
10
|
+
require_relative 'client'
|
11
|
+
require_relative 'paths'
|
9
12
|
require_relative 'tree'
|
10
13
|
require_relative '../checks'
|
11
14
|
require_relative '../count_down_latch'
|
@@ -22,10 +25,7 @@ module Github
|
|
22
25
|
end
|
23
26
|
|
24
27
|
DEFAULT_MAX_TREE_CACHE_AGE_SECONDS = 60 * 5 # 5 minutes
|
25
|
-
private_constant :DEFAULT_MAX_TREE_CACHE_AGE_SECONDS
|
26
|
-
|
27
28
|
DEFAULT_MAX_FILE_CACHE_AGE_SECONDS = 60 * 60 * 24 * 7 # 1 week
|
28
|
-
private_constant :DEFAULT_MAX_FILE_CACHE_AGE_SECONDS
|
29
29
|
|
30
30
|
MAX_TREE_SIZE = 50
|
31
31
|
private_constant :MAX_TREE_SIZE
|
@@ -38,14 +38,18 @@ module Github
|
|
38
38
|
@logger = check_non_nil(logger: logger)
|
39
39
|
end
|
40
40
|
|
41
|
-
def get_tree(owner:, repo:,
|
42
|
-
check_non_empty_string(owner: owner, repo: repo,
|
41
|
+
def get_tree(owner:, repo:, ref:, regex:, cache: true)
|
42
|
+
check_non_empty_string(owner: owner, repo: repo, ref: ref)
|
43
43
|
check_is_a(regex: [Regexp, regex])
|
44
44
|
|
45
|
-
response =
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
response = if cache
|
46
|
+
@client.get_with_caching(
|
47
|
+
"https://api.github.com/repos/#{owner}/#{repo}/git/trees/#{ref}?recursive=true",
|
48
|
+
cache_for: DEFAULT_MAX_TREE_CACHE_AGE_SECONDS
|
49
|
+
)
|
50
|
+
else
|
51
|
+
@client.get_without_caching("https://api.github.com/repos/#{owner}/#{repo}/git/trees/#{ref}?recursive=true")
|
52
|
+
end
|
49
53
|
|
50
54
|
response['tree'] = response['tree'].select { |blob| regex.match?(blob['path']) }
|
51
55
|
raise "trees with more than #{MAX_TREE_SIZE} blobs not supported" if response['tree'].size > MAX_TREE_SIZE
|
@@ -63,7 +67,72 @@ module Github
|
|
63
67
|
latch.await(timeout: 10)
|
64
68
|
raise 'failed to load saved files' unless response['tree'].all? { |blob| blob['content'] }
|
65
69
|
|
66
|
-
Tree.for(owner: owner, repo: repo,
|
70
|
+
Tree.for(owner: owner, repo: repo, ref: ref, tree_response: response)
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_commit_with_file(owner:, repo:, base_sha:, branch:, path:, content:, author_name:, author_email:)
|
74
|
+
check_non_empty_string(
|
75
|
+
owner: owner,
|
76
|
+
repo: repo,
|
77
|
+
base_sha: base_sha,
|
78
|
+
branch: branch,
|
79
|
+
path: path,
|
80
|
+
content: content,
|
81
|
+
author_name: author_name,
|
82
|
+
author_email: author_email
|
83
|
+
)
|
84
|
+
|
85
|
+
begin
|
86
|
+
@client.get_without_caching("https://api.github.com/repos/#{owner}/#{repo}/git/ref/#{branch}")
|
87
|
+
raise "branch already exists: #{owner}/#{repo}/#{branch}"
|
88
|
+
rescue RestClient::NotFound
|
89
|
+
# ignored
|
90
|
+
end
|
91
|
+
|
92
|
+
blob_response = @client.post(
|
93
|
+
"https://api.github.com/repos/#{owner}/#{repo}/git/blobs",
|
94
|
+
{
|
95
|
+
content: Base64.encode64(content),
|
96
|
+
encoding: 'base64'
|
97
|
+
}
|
98
|
+
)
|
99
|
+
tree_response = @client.post(
|
100
|
+
"https://api.github.com/repos/#{owner}/#{repo}/git/trees",
|
101
|
+
{
|
102
|
+
base_tree: base_sha,
|
103
|
+
tree: [
|
104
|
+
{
|
105
|
+
path: path,
|
106
|
+
mode: '100644',
|
107
|
+
type: 'blob',
|
108
|
+
sha: check_non_empty_string(sha: blob_response['sha'])
|
109
|
+
}
|
110
|
+
]
|
111
|
+
}
|
112
|
+
)
|
113
|
+
message = path.size > 43 ? "Update [...]#{path[-38..]}" : "Update #{path}"
|
114
|
+
commit_response = @client.post(
|
115
|
+
"https://api.github.com/repos/#{owner}/#{repo}/git/commits",
|
116
|
+
{
|
117
|
+
message: message,
|
118
|
+
author: {
|
119
|
+
name: 'SQLUI',
|
120
|
+
email: 'nicholasdower+sqlui@gmail.com',
|
121
|
+
date: Time.now.iso8601
|
122
|
+
},
|
123
|
+
parents: [
|
124
|
+
base_sha
|
125
|
+
],
|
126
|
+
tree: check_non_empty_string(sha: tree_response['sha'])
|
127
|
+
}
|
128
|
+
)
|
129
|
+
@client.post(
|
130
|
+
"https://api.github.com/repos/#{owner}/#{repo}/git/refs",
|
131
|
+
{
|
132
|
+
ref: "refs/heads/#{branch}",
|
133
|
+
sha: check_non_empty_string(sha: commit_response['sha'])
|
134
|
+
}
|
135
|
+
)
|
67
136
|
end
|
68
137
|
|
69
138
|
private
|
@@ -78,16 +147,5 @@ module Github
|
|
78
147
|
)
|
79
148
|
Base64.decode64(response['content'])
|
80
149
|
end
|
81
|
-
|
82
|
-
# Returns the contents of the file at the specified path. Uses the cache.
|
83
|
-
def get_file_content_without_caching(owner:, repo:, path:, ref:)
|
84
|
-
check_non_empty_string(owner: owner, repo: repo, sha: ref, path: path)
|
85
|
-
|
86
|
-
response = @client.get_without_caching(
|
87
|
-
"https://api.github.com/repos/#{owner}/#{repo}/contents/#{path}?ref=#{ref}"
|
88
|
-
)
|
89
|
-
|
90
|
-
Base64.decode64(response['content'])
|
91
|
-
end
|
92
150
|
end
|
93
151
|
end
|
data/app/pigs.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# You know, pig stuff.
|
4
|
+
class Pigs
|
5
|
+
NAMES = %w[
|
6
|
+
babe misery piglet snowball squealer wilbur napoleon porky miss-piggy petunia betina
|
7
|
+
belinda pumbaa hamm peppa-pig fifer fiddler practical-pig hampton-j piggy orson pua
|
8
|
+
huxley gub-gub olivia piggy-bank arnold boss-hog
|
9
|
+
].freeze
|
10
|
+
private_constant :NAMES
|
11
|
+
|
12
|
+
POSSESSIVE_NAMES = NAMES.map { |name| "#{name}s" }
|
13
|
+
private_constant :POSSESSIVE_NAMES
|
14
|
+
|
15
|
+
NOUNS = %w[snout ear ears tail hoof hooves foot feet].freeze
|
16
|
+
private_constant :NOUNS
|
17
|
+
|
18
|
+
ADJECTIVES = %w[pink hairy plump round cute dirty smelly tiny adorable slimy dainty big cunning sneaky].freeze
|
19
|
+
private_constant :ADJECTIVES
|
20
|
+
|
21
|
+
GERUND_VERBS = %w[oinking squealing grunting rooting sniffing snorting wallowing trotting rolling].freeze
|
22
|
+
private_constant :GERUND_VERBS
|
23
|
+
|
24
|
+
VERBS = %w[oinks squeals grunts roots sniffs snorts wallows trots rolls swallows].freeze
|
25
|
+
private_constant :VERBS
|
26
|
+
|
27
|
+
ADVERBS = %w[hungrily loudly greedily angrily coyly playfully lazily noisily happily].freeze
|
28
|
+
private_constant :ADVERBS
|
29
|
+
|
30
|
+
FOOD_NOUNS = %w[trotter loin cutlet hock skin jowl cheek rump belly ham bacon back shoulder ear ears tail rib
|
31
|
+
tenderloin pork-chop roast sausage fatback fat tongue].freeze
|
32
|
+
private_constant :FOOD_NOUNS
|
33
|
+
|
34
|
+
PLURAL_FOOD_NOUNS = %w[ears trotters cutlets hocks jowls cheeks ribs spareribs pork-chops sausages steaks].freeze
|
35
|
+
private_constant :PLURAL_FOOD_NOUNS
|
36
|
+
|
37
|
+
FOOD_ADJECTIVES = %w[tasty meaty greasy chewy salty smoky juicy delicious crunchy fatty salted spicy savory succulent
|
38
|
+
moist flavorful tender sweet].freeze
|
39
|
+
private_constant :FOOD_ADJECTIVES
|
40
|
+
|
41
|
+
PIG_ON_PIG_VERBS = %w[snuggles cuddles chases sniffs watches smells cuddles oinks-at squeals-at grunts-at snorts-at
|
42
|
+
wallows-with roots-with trots-with rolls-with grins-at].freeze
|
43
|
+
private_constant :PIG_ON_PIG_VERBS
|
44
|
+
|
45
|
+
COMBOS = [
|
46
|
+
[NAMES],
|
47
|
+
[NAMES, %w[and], NAMES],
|
48
|
+
[NAMES, %w[and], NAMES, %w[are], ADJECTIVES],
|
49
|
+
[NAMES, PIG_ON_PIG_VERBS, NAMES],
|
50
|
+
[GERUND_VERBS, NAMES],
|
51
|
+
[NAMES, GERUND_VERBS],
|
52
|
+
[NAMES, GERUND_VERBS, ADVERBS],
|
53
|
+
[GERUND_VERBS, NAMES, %w[and], NAMES],
|
54
|
+
[NAMES, %w[and], NAMES, GERUND_VERBS],
|
55
|
+
[NAMES, %w[and], NAMES, GERUND_VERBS, ADVERBS],
|
56
|
+
[NAMES, VERBS],
|
57
|
+
[ADJECTIVES, NAMES],
|
58
|
+
[NAMES, %w[is], ADJECTIVES],
|
59
|
+
[ADJECTIVES, %w[and], ADJECTIVES, NAMES],
|
60
|
+
[NAMES, VERBS, ADVERBS],
|
61
|
+
[POSSESSIVE_NAMES, NOUNS],
|
62
|
+
[POSSESSIVE_NAMES, ADJECTIVES, NOUNS],
|
63
|
+
[POSSESSIVE_NAMES, ADJECTIVES, %w[and], ADJECTIVES, NOUNS],
|
64
|
+
[ADJECTIVES, NOUNS],
|
65
|
+
[POSSESSIVE_NAMES, FOOD_ADJECTIVES, FOOD_NOUNS],
|
66
|
+
[POSSESSIVE_NAMES, FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
|
67
|
+
[NAMES, %w[has-a], FOOD_ADJECTIVES, FOOD_NOUNS],
|
68
|
+
[NAMES, %w[has], FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
|
69
|
+
[FOOD_NOUNS],
|
70
|
+
[FOOD_ADJECTIVES, FOOD_NOUNS],
|
71
|
+
[FOOD_ADJECTIVES, FOOD_ADJECTIVES, FOOD_NOUNS],
|
72
|
+
[%w[a one], FOOD_ADJECTIVES, FOOD_NOUNS],
|
73
|
+
[%w[a one], FOOD_ADJECTIVES, FOOD_ADJECTIVES, FOOD_NOUNS],
|
74
|
+
[PLURAL_FOOD_NOUNS],
|
75
|
+
[FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
|
76
|
+
[FOOD_ADJECTIVES, FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
|
77
|
+
[%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of],
|
78
|
+
PLURAL_FOOD_NOUNS],
|
79
|
+
[%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of], FOOD_ADJECTIVES,
|
80
|
+
PLURAL_FOOD_NOUNS],
|
81
|
+
[%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of], FOOD_ADJECTIVES,
|
82
|
+
FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS]
|
83
|
+
].freeze
|
84
|
+
private_constant :COMBOS
|
85
|
+
|
86
|
+
COMBO_COUNTS = COMBOS.map do |combo|
|
87
|
+
size = 1
|
88
|
+
used = []
|
89
|
+
combo.each do |list|
|
90
|
+
size *= list.size - used.count(list)
|
91
|
+
used << list
|
92
|
+
end
|
93
|
+
size
|
94
|
+
end
|
95
|
+
private_constant :COMBO_COUNTS
|
96
|
+
|
97
|
+
TOTAL_COMBOS = COMBO_COUNTS.sum
|
98
|
+
private_constant :TOTAL_COMBOS
|
99
|
+
|
100
|
+
COMBO_SUM = COMBO_COUNTS.each_with_object([0]).map do |i, j|
|
101
|
+
j[0] = j[0] + i
|
102
|
+
end
|
103
|
+
private_constant :COMBO_SUM
|
104
|
+
|
105
|
+
def self.total_combos
|
106
|
+
TOTAL_COMBOS
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.generate_phrase
|
110
|
+
rand = rand(TOTAL_COMBOS)
|
111
|
+
COMBOS.each_with_index do |combo, i|
|
112
|
+
next unless rand < COMBO_SUM[i]
|
113
|
+
|
114
|
+
used = []
|
115
|
+
parts = []
|
116
|
+
combo.each do |list|
|
117
|
+
list -= used
|
118
|
+
used << list.sample
|
119
|
+
parts << used.last
|
120
|
+
end
|
121
|
+
return parts.join('-')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/app/saved_config.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative 'args'
|
|
4
4
|
|
5
5
|
# Config for saved files.
|
6
6
|
class SavedConfig
|
7
|
-
attr_reader :token, :owner, :repo, :branch, :regex
|
7
|
+
attr_reader :token, :owner, :repo, :branch, :regex, :author_name, :author_email
|
8
8
|
|
9
9
|
def initialize(hash)
|
10
10
|
@token = Args.fetch_non_empty_string(hash, :token).strip
|
@@ -12,5 +12,8 @@ class SavedConfig
|
|
12
12
|
@repo = Args.fetch_non_empty_string(hash, :repo).strip
|
13
13
|
@branch = Args.fetch_non_empty_string(hash, :branch).strip
|
14
14
|
@regex = Regexp.new(Args.fetch_non_empty_string(hash, :regex))
|
15
|
+
author = Args.fetch_non_empty_hash(hash, :author)
|
16
|
+
@author_name = Args.fetch_non_empty_string(author, :name).strip
|
17
|
+
@author_email = Args.fetch_non_empty_string(author, :email).strip
|
15
18
|
end
|
16
19
|
end
|