poefy-pg 1.1.0 → 2.0.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.
data/lib/poefy/pg.rb CHANGED
@@ -1,294 +1,294 @@
1
- #!/usr/bin/env ruby
2
- # Encoding: UTF-8
3
-
4
- ################################################################################
5
- # Extend 'Database' class for connecting to a PostgreSQL database.
6
- # These methods are specific to PostgreSQL.
7
- # Other databases should be implemented in separate gems.
8
- ################################################################################
9
-
10
- require 'pg'
11
-
12
- ################################################################################
13
-
14
- module Poefy
15
-
16
- class Database
17
-
18
- # Details for the database connection.
19
- def self.connection
20
- PG.connect(
21
- :dbname => 'poefy',
22
- :user => 'poefy',
23
- :password => 'poefy'
24
- )
25
- end
26
-
27
- # Open a class-wide connection, execute a query.
28
- def self.single_exec! sql, sql_args = nil
29
- output = nil
30
- begin
31
- @@con ||= Database::connection
32
- output = if sql_args
33
- @@con.exec(sql, [*sql_args]).values
34
- else
35
- @@con.exec(sql).values
36
- end
37
- end
38
- output
39
- end
40
-
41
- # List all tables in the database.
42
- # Does not include tables used for testing.
43
- def self.list
44
- rs = Database::single_exec! <<-SQL
45
- SELECT table_name
46
- FROM information_schema.tables
47
- WHERE table_schema = 'public';
48
- SQL
49
- rs.flatten.reject do |i|
50
- i.start_with?('spec_')
51
- end.sort - ['test']
52
- end
53
-
54
- # Get the description of a table.
55
- def self.desc table_name
56
- begin
57
- sql = "SELECT obj_description($1::regclass, 'pg_class');"
58
- single_exec!(sql, [table_name]).flatten.first.to_s
59
- rescue
60
- ''
61
- end
62
- end
63
-
64
- # List all database files and their descriptions.
65
- def self.list_with_desc
66
- Database::list.map do |i|
67
- begin
68
- [i, Database::desc(i)]
69
- rescue
70
- [i, '']
71
- end
72
- end.to_h
73
- end
74
-
75
- ############################################################################
76
-
77
- # This is the type of database that is being used.
78
- # It is also used as a signifier that a database has been specified.
79
- def type
80
- 'pg'
81
- end
82
-
83
- # Get/set the description of the table.
84
- def desc
85
- Database::desc table
86
- end
87
- def desc=(description)
88
- safe_desc = description.to_s.gsub("'","''")
89
- execute! "COMMENT ON TABLE #{table} IS '#{safe_desc}';"
90
- end
91
-
92
- # The number of lines in the table.
93
- def count
94
- return 0 if not exists?
95
- sql = "SELECT COUNT(*) AS num FROM #{table};"
96
- execute!(sql).first['num'].to_i
97
- end
98
-
99
- # See if the table exists or not.
100
- # Attempt to access table, and return false on error.
101
- def exists?
102
- open_connection
103
- @db.exec("SELECT $1::regclass", [*table])
104
- true
105
- rescue PG::UndefinedTable
106
- false
107
- end
108
-
109
- # Get all rhyming lines for the word.
110
- def rhymes word, key = nil
111
- return nil if word.nil?
112
-
113
- sql = <<-SQL
114
- SELECT rhyme, final_word, syllables, line
115
- FROM #{table}
116
- WHERE rhyme = $1
117
- ORDER BY rhyme, final_word, syllables, line
118
- SQL
119
- output = word.to_phrase.rhymes.keys.map do |rhyme|
120
- execute!(sql, [rhyme]).to_a
121
- end.flatten
122
-
123
- if !key.nil? and %w[rhyme final_word syllables line].include?(key)
124
- output.map!{ |i| i[key] }
125
- end
126
- output
127
- end
128
-
129
- private
130
-
131
- # The name of the table.
132
- def table
133
- @name
134
- end
135
-
136
- # Create a new table.
137
- def new_connection
138
- open_connection
139
- end
140
-
141
- # Open a connection to the database.
142
- def open_connection
143
- @db ||= Database::connection
144
- end
145
-
146
- # Execute a query.
147
- def execute! sql, *args
148
- db.exec sql, *args
149
- end
150
-
151
- # Insert an array of lines.
152
- def insert_lines table_name, rows
153
- sql = "INSERT INTO #{table_name} VALUES ( $1, $2, $3, $4 )"
154
- db.transaction do |db_tr|
155
- rows.each do |line|
156
- db_tr.exec sql, line
157
- end
158
- end
159
- end
160
-
161
- ##########################################################################
162
-
163
- # Create the table and the index.
164
- def create_table table_name, description = nil
165
- index_name = 'idx_' + table_name
166
- execute! <<-SQL
167
- SET client_min_messages TO WARNING;
168
- DROP INDEX IF EXISTS #{index_name};
169
- DROP TABLE IF EXISTS #{table_name};
170
- CREATE TABLE #{table_name} (
171
- line TEXT,
172
- syllables SMALLINT,
173
- final_word TEXT,
174
- rhyme TEXT
175
- );
176
- CREATE INDEX #{index_name} ON #{table_name} (
177
- rhyme, final_word, line
178
- );
179
- SQL
180
- self.desc = description
181
- end
182
-
183
- ##########################################################################
184
-
185
- # Define SQL of the stored procedures.
186
- def sprocs_sql_hash
187
- sql = {}
188
- sql[:rbc] = <<-SQL
189
- SELECT rhyme, COUNT(rhyme) AS count
190
- FROM (
191
- SELECT rhyme, final_word, COUNT(final_word) AS wc
192
- FROM #{table}
193
- GROUP BY rhyme, final_word
194
- ) AS sub_table
195
- GROUP BY rhyme
196
- HAVING COUNT(rhyme) >= $1
197
- SQL
198
- sql[:rbcs] = <<-SQL
199
- SELECT rhyme, COUNT(rhyme) AS count
200
- FROM (
201
- SELECT rhyme, final_word, COUNT(final_word) AS wc
202
- FROM #{table}
203
- WHERE syllables BETWEEN $1 AND $2
204
- GROUP BY rhyme, final_word
205
- ) AS sub_table
206
- GROUP BY rhyme
207
- HAVING COUNT(rhyme) >= $3
208
- SQL
209
- sql[:la] = <<-SQL
210
- SELECT line, syllables, final_word, rhyme
211
- FROM #{table} WHERE rhyme = $1
212
- SQL
213
- sql[:las] = <<-SQL
214
- SELECT line, syllables, final_word, rhyme
215
- FROM #{table} WHERE rhyme = $1
216
- AND syllables BETWEEN $2 AND $3
217
- SQL
218
- sql
219
- end
220
-
221
- # Create the stored procedures in the database.
222
- def create_sprocs
223
- sprocs_sql_hash.each do |key, value|
224
- db.prepare key.to_s, value
225
- end
226
- rescue
227
- msg = "ERROR: Database table structure is invalid." +
228
- "\n Please manually DROP the corrupt table and recreate it."
229
- raise Poefy::StructureInvalid.new(msg)
230
- end
231
-
232
- # Find rhymes and counts greater than a certain length.
233
- def sproc_rhymes_by_count rhyme_count
234
- rs = db.exec_prepared 'rbc', [rhyme_count]
235
- rs.values.map do |row|
236
- {
237
- 'rhyme' => row[0],
238
- 'count' => row[1].to_i
239
- }
240
- end
241
- end
242
-
243
- # Also adds syllable selection.
244
- def sproc_rhymes_by_count_syllables rhyme_count, syllable_min_max
245
- arg_array = [
246
- syllable_min_max[:min],
247
- syllable_min_max[:max],
248
- rhyme_count
249
- ]
250
- rs = db.exec_prepared 'rbcs', arg_array
251
- rs.values.map do |row|
252
- {
253
- 'rhyme' => row[0],
254
- 'count' => row[1].to_i
255
- }
256
- end
257
- end
258
-
259
- # Find all lines for a certain rhyme.
260
- def sproc_lines_by_rhyme rhyme
261
- rs = db.exec_prepared 'la', [rhyme]
262
- rs.values.map do |row|
263
- {
264
- 'line' => row[0],
265
- 'syllables' => row[1].to_i,
266
- 'final_word' => row[2],
267
- 'rhyme' => row[3]
268
- }
269
- end
270
- end
271
-
272
- # Also adds syllable selection.
273
- def sproc_lines_by_rhyme_syllables rhyme, syllable_min_max
274
- arg_array = [
275
- rhyme,
276
- syllable_min_max[:min],
277
- syllable_min_max[:max]
278
- ]
279
- rs = db.exec_prepared 'las', arg_array
280
- rs.values.map do |row|
281
- {
282
- 'line' => row[0],
283
- 'syllables' => row[1].to_i,
284
- 'final_word' => row[2],
285
- 'rhyme' => row[3]
286
- }
287
- end
288
- end
289
-
290
- end
291
-
292
- end
293
-
294
- ################################################################################
1
+ #!/usr/bin/env ruby
2
+ # Encoding: UTF-8
3
+
4
+ ################################################################################
5
+ # Extend 'Database' class for connecting to a PostgreSQL database.
6
+ # These methods are specific to PostgreSQL.
7
+ # Other databases should be implemented in separate gems.
8
+ ################################################################################
9
+
10
+ require 'pg'
11
+
12
+ ################################################################################
13
+
14
+ module Poefy
15
+
16
+ class Database
17
+
18
+ # Details for the database connection.
19
+ def self.connection
20
+ PG.connect(
21
+ :dbname => 'poefy',
22
+ :user => 'poefy',
23
+ :password => 'poefy'
24
+ )
25
+ end
26
+
27
+ # Open a class-wide connection, execute a query.
28
+ def self.single_exec! sql, sql_args = nil
29
+ output = nil
30
+ begin
31
+ @@con ||= Database::connection
32
+ output = if sql_args
33
+ @@con.exec(sql, [*sql_args]).values
34
+ else
35
+ @@con.exec(sql).values
36
+ end
37
+ end
38
+ output
39
+ end
40
+
41
+ # List all tables in the database.
42
+ # Does not include tables used for testing.
43
+ def self.list
44
+ rs = Database::single_exec! <<-SQL
45
+ SELECT table_name
46
+ FROM information_schema.tables
47
+ WHERE table_schema = 'public';
48
+ SQL
49
+ rs.flatten.reject do |i|
50
+ i.start_with?('spec_')
51
+ end.sort - ['test']
52
+ end
53
+
54
+ # Get the description of a table.
55
+ def self.desc table_name
56
+ begin
57
+ sql = "SELECT obj_description($1::regclass, 'pg_class');"
58
+ single_exec!(sql, [table_name]).flatten.first.to_s
59
+ rescue
60
+ ''
61
+ end
62
+ end
63
+
64
+ # List all database files and their descriptions.
65
+ def self.list_with_desc
66
+ Database::list.map do |i|
67
+ begin
68
+ [i, Database::desc(i)]
69
+ rescue
70
+ [i, '']
71
+ end
72
+ end.to_h
73
+ end
74
+
75
+ ############################################################################
76
+
77
+ # This is the type of database that is being used.
78
+ # It is also used as a signifier that a database has been specified.
79
+ def type
80
+ 'pg'
81
+ end
82
+
83
+ # Get/set the description of the table.
84
+ def desc
85
+ Database::desc table
86
+ end
87
+ def desc=(description)
88
+ safe_desc = description.to_s.gsub("'","''")
89
+ execute! "COMMENT ON TABLE #{table} IS '#{safe_desc}';"
90
+ end
91
+
92
+ # The number of lines in the table.
93
+ def count
94
+ return 0 unless exist?
95
+ sql = "SELECT COUNT(*) AS num FROM #{table};"
96
+ execute!(sql).first['num'].to_i
97
+ end
98
+
99
+ # See if the table exists or not.
100
+ # Attempt to access table, and return false on error.
101
+ def exist?
102
+ open_connection
103
+ @db.exec("SELECT $1::regclass", [*table])
104
+ true
105
+ rescue PG::UndefinedTable
106
+ false
107
+ end
108
+
109
+ # Get all rhyming lines for the word.
110
+ def rhymes word, key = nil
111
+ return nil if word.nil?
112
+
113
+ sql = <<-SQL
114
+ SELECT rhyme, final_word, syllables, line
115
+ FROM #{table}
116
+ WHERE rhyme = $1
117
+ ORDER BY rhyme, final_word, syllables, line
118
+ SQL
119
+ output = word.to_phrase.rhymes.keys.map do |rhyme|
120
+ execute!(sql, [rhyme]).to_a
121
+ end.flatten
122
+
123
+ if !key.nil? and %w[rhyme final_word syllables line].include?(key)
124
+ output.map!{ |i| i[key] }
125
+ end
126
+ output
127
+ end
128
+
129
+ private
130
+
131
+ # The name of the table.
132
+ def table
133
+ @name
134
+ end
135
+
136
+ # Create a new table.
137
+ def new_connection
138
+ open_connection
139
+ end
140
+
141
+ # Open a connection to the database.
142
+ def open_connection
143
+ @db ||= Database::connection
144
+ end
145
+
146
+ # Execute a query.
147
+ def execute! sql, *args
148
+ db.exec sql, *args
149
+ end
150
+
151
+ # Insert an array of lines.
152
+ def insert_lines table_name, rows
153
+ sql = "INSERT INTO #{table_name} VALUES ( $1, $2, $3, $4 )"
154
+ db.transaction do |db_tr|
155
+ rows.each do |line|
156
+ db_tr.exec sql, line
157
+ end
158
+ end
159
+ end
160
+
161
+ ##########################################################################
162
+
163
+ # Create the table and the index.
164
+ def create_table table_name, description = nil
165
+ index_name = 'idx_' + table_name
166
+ execute! <<-SQL
167
+ SET client_min_messages TO WARNING;
168
+ DROP INDEX IF EXISTS #{index_name};
169
+ DROP TABLE IF EXISTS #{table_name};
170
+ CREATE TABLE #{table_name} (
171
+ line TEXT,
172
+ syllables SMALLINT,
173
+ final_word TEXT,
174
+ rhyme TEXT
175
+ );
176
+ CREATE INDEX #{index_name} ON #{table_name} (
177
+ rhyme, final_word, line
178
+ );
179
+ SQL
180
+ self.desc = description
181
+ end
182
+
183
+ ##########################################################################
184
+
185
+ # Define SQL of the stored procedures.
186
+ def sprocs_sql_hash
187
+ sql = {}
188
+ sql[:rbc] = <<-SQL
189
+ SELECT rhyme, COUNT(rhyme) AS count
190
+ FROM (
191
+ SELECT rhyme, final_word, COUNT(final_word) AS wc
192
+ FROM #{table}
193
+ GROUP BY rhyme, final_word
194
+ ) AS sub_table
195
+ GROUP BY rhyme
196
+ HAVING COUNT(rhyme) >= $1
197
+ SQL
198
+ sql[:rbcs] = <<-SQL
199
+ SELECT rhyme, COUNT(rhyme) AS count
200
+ FROM (
201
+ SELECT rhyme, final_word, COUNT(final_word) AS wc
202
+ FROM #{table}
203
+ WHERE syllables BETWEEN $1 AND $2
204
+ GROUP BY rhyme, final_word
205
+ ) AS sub_table
206
+ GROUP BY rhyme
207
+ HAVING COUNT(rhyme) >= $3
208
+ SQL
209
+ sql[:la] = <<-SQL
210
+ SELECT line, syllables, final_word, rhyme
211
+ FROM #{table} WHERE rhyme = $1
212
+ SQL
213
+ sql[:las] = <<-SQL
214
+ SELECT line, syllables, final_word, rhyme
215
+ FROM #{table} WHERE rhyme = $1
216
+ AND syllables BETWEEN $2 AND $3
217
+ SQL
218
+ sql
219
+ end
220
+
221
+ # Create the stored procedures in the database.
222
+ def create_sprocs
223
+ sprocs_sql_hash.each do |key, value|
224
+ db.prepare key.to_s, value
225
+ end
226
+ rescue
227
+ msg = "ERROR: Database table structure is invalid." +
228
+ "\n Please manually DROP the corrupt table and recreate it."
229
+ raise Poefy::StructureInvalid.new(msg)
230
+ end
231
+
232
+ # Find rhymes and counts greater than a certain length.
233
+ def sproc_rhymes_by_count rhyme_count
234
+ rs = db.exec_prepared 'rbc', [rhyme_count]
235
+ rs.values.map do |row|
236
+ {
237
+ 'rhyme' => row[0],
238
+ 'count' => row[1].to_i
239
+ }
240
+ end
241
+ end
242
+
243
+ # Also adds syllable selection.
244
+ def sproc_rhymes_by_count_syllables rhyme_count, syllable_min_max
245
+ arg_array = [
246
+ syllable_min_max[:min],
247
+ syllable_min_max[:max],
248
+ rhyme_count
249
+ ]
250
+ rs = db.exec_prepared 'rbcs', arg_array
251
+ rs.values.map do |row|
252
+ {
253
+ 'rhyme' => row[0],
254
+ 'count' => row[1].to_i
255
+ }
256
+ end
257
+ end
258
+
259
+ # Find all lines for a certain rhyme.
260
+ def sproc_lines_by_rhyme rhyme
261
+ rs = db.exec_prepared 'la', [rhyme]
262
+ rs.values.map do |row|
263
+ {
264
+ 'line' => row[0],
265
+ 'syllables' => row[1].to_i,
266
+ 'final_word' => row[2],
267
+ 'rhyme' => row[3]
268
+ }
269
+ end
270
+ end
271
+
272
+ # Also adds syllable selection.
273
+ def sproc_lines_by_rhyme_syllables rhyme, syllable_min_max
274
+ arg_array = [
275
+ rhyme,
276
+ syllable_min_max[:min],
277
+ syllable_min_max[:max]
278
+ ]
279
+ rs = db.exec_prepared 'las', arg_array
280
+ rs.values.map do |row|
281
+ {
282
+ 'line' => row[0],
283
+ 'syllables' => row[1].to_i,
284
+ 'final_word' => row[2],
285
+ 'rhyme' => row[3]
286
+ }
287
+ end
288
+ end
289
+
290
+ end
291
+
292
+ end
293
+
294
+ ################################################################################
data/poefy-pg.gemspec CHANGED
@@ -15,12 +15,14 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.version = Poefy::Pg.version_number
17
17
  s.date = Poefy::Pg.version_date
18
- s.license = 'GPL-3.0'
18
+ s.license = 'GPL-3.0-or-later'
19
19
 
20
20
  s.files = `git ls-files`.split("\n")
21
21
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
22
  s.require_paths = ['lib']
23
23
 
24
+ s.required_ruby_version = '>= 3.2.0'
25
+
24
26
  s.add_development_dependency('bundler', '~> 1.13')
25
27
  s.add_development_dependency('rake', '~> 10.0')
26
28
  s.add_development_dependency('rspec', '~> 3.0')