poefy-sqlite3 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 601ccce9d7cf3212b804700e0071548fe4e88669
4
+ data.tar.gz: 6619ec5b781ff1677302925782bd86369dc484e9
5
+ SHA512:
6
+ metadata.gz: 51a75059555a8147f33b70776fe1d17255e487d4b0e8f77e708b61a1cf1e1240a861625a6810a83c72f882022800ada63bbb67ec8c1f52de6e1ae719fac4e5a0
7
+ data.tar.gz: 66644fda8fd56121eeedc553958136a917a0a0e9f7fd2de5952f3258eb6972a1c34dcd89904d4c5ff5ae2ba47e9c33c0b87d3422215b4d3f980503fe4d8cf780
data/.gitignore ADDED
@@ -0,0 +1,77 @@
1
+
2
+ ################################################################################
3
+ # Ruby specific files
4
+
5
+ *.gem
6
+ *.rbc
7
+ /.config
8
+ /coverage/
9
+ /InstalledFiles
10
+ /pkg/
11
+ /spec/reports/
12
+ /test/tmp/
13
+ /test/version_tmp/
14
+ /tmp/
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+
21
+ ## Documentation cache and generated files:
22
+ /.yardoc/
23
+ /_yardoc/
24
+ /doc/
25
+ /rdoc/
26
+
27
+ ## Environment normalisation:
28
+ /.bundle/
29
+ /vendor/bundle
30
+ /lib/bundler/man/
31
+
32
+ # for a library or gem, you might want to ignore these files since the code is
33
+ # intended to run in multiple environments; otherwise, check them in:
34
+ Gemfile.lock
35
+ .ruby-version
36
+ .ruby-gemset
37
+
38
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
39
+ .rvmrc
40
+
41
+ ################################################################################
42
+ # Rails stuff
43
+
44
+ # Ignore all logfiles and tempfiles.
45
+ /log/*
46
+ /tmp/*
47
+ !/log/.keep
48
+ !/tmp/.keep
49
+
50
+ # Ignore Byebug command history file.
51
+ .byebug_history
52
+
53
+ # Ignore application configuration
54
+ /config/application.yml
55
+
56
+ ################################################################################
57
+ # System and config files
58
+ desktop.ini
59
+ .agignore
60
+ .ignore
61
+ *.lnk
62
+
63
+ ################################################################################
64
+ # App specific files
65
+
66
+ # Development files
67
+ work*.rb
68
+ /~/
69
+
70
+ # Config files
71
+ settings.yml
72
+
73
+ # Data files
74
+ /data/
75
+
76
+ # Output files
77
+ /output/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (C) 2017 Paul Thompson
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ Full text of this licence: <https://www.gnu.org/licenses/gpl.html>
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # poefy-sqlite3
2
+
3
+ by Paul Thompson - nossidge@gmail.com
4
+
5
+ SQLite interface for the 'poefy' gem.
6
+
7
+ Please see the [poefy](https://github.com/nossidge/poefy) documentation.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.verbose = false
6
+ end
7
+ task :default => :spec
8
+ task :test => :spec
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: UTF-8
3
+
4
+ ################################################################################
5
+ # Extend 'Database' class for connecting to a sqlite3 database.
6
+ # These methods are specific to sqlite3.
7
+ # Other databases should be implemented in separate gems.
8
+ ################################################################################
9
+
10
+ require 'sqlite3'
11
+
12
+ ################################################################################
13
+
14
+ module Poefy
15
+
16
+ class Database
17
+
18
+ # Open a connection, execute a query, close the connection.
19
+ def self.single_exec! database_name, sql
20
+ path = Database::path database_name
21
+ con = SQLite3::Database.open path
22
+ rs = con.execute sql
23
+ con.close
24
+ rs
25
+ end
26
+
27
+ # List all database files in the directory.
28
+ # Does not include databases used for testing.
29
+ def self.list
30
+ Dir[Poefy.root + '/data/*.db'].map do |i|
31
+ File.basename(i, '.db')
32
+ end.reject do |i|
33
+ i.start_with?('spec_')
34
+ end.sort - ['test']
35
+ end
36
+
37
+ # Get the description of a database.
38
+ def self.desc database_name
39
+ begin
40
+ sql = "SELECT comment FROM comment;"
41
+ Database::single_exec!(database_name, sql).flatten.first
42
+ rescue
43
+ ''
44
+ end
45
+ end
46
+
47
+ # List all database files and their descriptions.
48
+ def self.list_with_desc
49
+ Database::list.map do |i|
50
+ begin
51
+ [i, Database::desc(i)]
52
+ rescue
53
+ [i, '']
54
+ end
55
+ end.to_h
56
+ end
57
+
58
+ # Get the path of a database.
59
+ def self.path database_name
60
+ Poefy.root + '/data/' + File.basename(database_name, '.db') + '.db'
61
+ end
62
+
63
+ ############################################################################
64
+
65
+ # This is the type of database that is being used.
66
+ # It is also used as a signifier that a database has been specified.
67
+ def type
68
+ 'sqlite3'
69
+ end
70
+
71
+ # Get/set the description of the database.
72
+ def desc
73
+ Database::desc @name
74
+ end
75
+ def desc=(description)
76
+ execute! "DELETE FROM comment;"
77
+ execute! "INSERT INTO comment VALUES ( ? );", description.to_s
78
+ end
79
+
80
+ # The number of lines in the table.
81
+ def count
82
+ return 0 if not exists?
83
+ sql = "SELECT COUNT(*) AS num FROM #{table};"
84
+ execute!(sql).first['num'].to_i
85
+ end
86
+
87
+ # See if the database file exists or not.
88
+ def exists?
89
+ File.exists?(db_file)
90
+ end
91
+
92
+ # Get all rhyming lines for the word.
93
+ def rhymes word, key = nil
94
+ return nil if word.nil?
95
+
96
+ sql = <<-SQL
97
+ SELECT rhyme, final_word, syllables, line
98
+ FROM lines
99
+ WHERE rhyme = ?
100
+ ORDER BY rhyme, final_word, syllables, line
101
+ SQL
102
+ output = word.to_phrase.rhymes.keys.map do |rhyme|
103
+ rs = execute!(sql, [rhyme]).to_a
104
+ rs.each{ |a| a.reject!{ |k| k.is_a? Numeric }}
105
+ end.flatten
106
+
107
+ if !key.nil? and %w[rhyme final_word syllables line].include?(key)
108
+ output.map!{ |i| i[key] }
109
+ end
110
+ output
111
+ end
112
+
113
+ private
114
+
115
+ # The name of the table.
116
+ def table
117
+ 'lines'
118
+ end
119
+
120
+ # Create a new database.
121
+ def new_connection
122
+ File.delete(db_file) if File.exists?(db_file)
123
+ @db = SQLite3::Database.new(db_file)
124
+ @db.results_as_hash = true
125
+ end
126
+
127
+ # Open a connection to the database.
128
+ def open_connection
129
+ @db = SQLite3::Database.open(db_file)
130
+ @db.results_as_hash = true
131
+ end
132
+
133
+ # Execute a query.
134
+ def execute! sql, *args
135
+ db.execute sql, *args
136
+ end
137
+
138
+ # Insert an array of poefy-described lines.
139
+ def insert_lines table_name, rows
140
+ sql = "INSERT INTO #{table_name} VALUES ( ?, ?, ?, ? )"
141
+ db.transaction do |db_tr|
142
+ rows.each do |line|
143
+ db_tr.execute sql, line
144
+ end
145
+ end
146
+ end
147
+
148
+ ##########################################################################
149
+
150
+ # Find the correct database file.
151
+ # If local, just use the value.
152
+ # Else, use the database in /data/ directory.
153
+ def db_file
154
+ if @local
155
+ @name
156
+ elsif @db_file
157
+ @db_file
158
+ else
159
+ path = Poefy.root + '/data'
160
+ file = File.basename(@name, '.db')
161
+ @db_file = path + '/' + file + '.db'
162
+ end
163
+ end
164
+
165
+ ##########################################################################
166
+
167
+ # Create the table and the index.
168
+ def create_table table_name, description = nil
169
+ execute! <<-SQL
170
+ CREATE TABLE #{table_name} (
171
+ line TEXT,
172
+ syllables SMALLINT,
173
+ final_word TEXT,
174
+ rhyme TEXT
175
+ );
176
+ SQL
177
+ execute! <<-SQL
178
+ CREATE TABLE comment (
179
+ comment TEXT
180
+ );
181
+ SQL
182
+ execute! <<-SQL
183
+ CREATE INDEX idx ON #{table_name} (
184
+ rhyme, final_word, line
185
+ );
186
+ SQL
187
+ self.desc = description
188
+ end
189
+
190
+ ##########################################################################
191
+
192
+ # Define SQL of the stored procedures.
193
+ def sprocs_sql_hash
194
+ sql = {}
195
+ sql[:rbc] = <<-SQL
196
+ SELECT rhyme, COUNT(rhyme) AS count
197
+ FROM (
198
+ SELECT rhyme, final_word, COUNT(final_word) AS wc
199
+ FROM #{table}
200
+ GROUP BY rhyme, final_word
201
+ )
202
+ GROUP BY rhyme
203
+ HAVING count >= ?
204
+ SQL
205
+ sql[:rbcs] = <<-SQL
206
+ SELECT rhyme, COUNT(rhyme) AS count
207
+ FROM (
208
+ SELECT rhyme, final_word, COUNT(final_word) AS wc
209
+ FROM #{table}
210
+ WHERE syllables BETWEEN ? AND ?
211
+ GROUP BY rhyme, final_word
212
+ )
213
+ GROUP BY rhyme
214
+ HAVING count >= ?
215
+ SQL
216
+ sql[:la] = <<-SQL
217
+ SELECT line, syllables, final_word, rhyme
218
+ FROM #{table} WHERE rhyme = ?
219
+ SQL
220
+ sql[:las] = <<-SQL
221
+ SELECT line, syllables, final_word, rhyme
222
+ FROM #{table} WHERE rhyme = ?
223
+ AND syllables BETWEEN ? AND ?
224
+ SQL
225
+ sql
226
+ end
227
+
228
+ # Create the stored procedures in the database.
229
+ def create_sprocs
230
+ sprocs_sql_hash.each do |key, value|
231
+ @sproc[key] = db.prepare value
232
+ end
233
+ rescue
234
+ handle_error \
235
+ "ERROR: Database table structure is invalid.\n" +
236
+ " Please manually DROP the corrupt table and recreate it."
237
+ end
238
+
239
+ # Find rhymes and counts greater than a certain length.
240
+ def sproc_rhymes_by_count rhyme_count
241
+ @sproc[:rbc].reset!
242
+ @sproc[:rbc].bind_param(1, rhyme_count)
243
+ @sproc[:rbc].execute.to_a
244
+ end
245
+
246
+ # Also adds syllable selection.
247
+ def sproc_rhymes_by_count_syllables rhyme_count, syllable_min_max
248
+ @sproc[:rbcs].reset!
249
+ @sproc[:rbcs].bind_param(1, syllable_min_max[:min])
250
+ @sproc[:rbcs].bind_param(2, syllable_min_max[:max])
251
+ @sproc[:rbcs].bind_param(3, rhyme_count)
252
+ @sproc[:rbcs].execute.to_a
253
+ end
254
+
255
+ # Find all lines for a certain rhyme.
256
+ def sproc_lines_by_rhyme rhyme
257
+ @sproc[:la].reset!
258
+ @sproc[:la].bind_param(1, rhyme)
259
+ @sproc[:la].execute.to_a
260
+ end
261
+
262
+ # Also adds syllable selection.
263
+ def sproc_lines_by_rhyme_syllables rhyme, syllable_min_max
264
+ @sproc[:las].reset!
265
+ @sproc[:las].bind_param(1, rhyme)
266
+ @sproc[:las].bind_param(2, syllable_min_max[:min])
267
+ @sproc[:las].bind_param(3, syllable_min_max[:max])
268
+ @sproc[:las].execute.to_a
269
+ end
270
+
271
+ end
272
+
273
+ end
274
+
275
+ ################################################################################
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: UTF-8
3
+
4
+ module Poefy
5
+
6
+ module Sqlite3
7
+
8
+ def self.version_number
9
+ major = 0
10
+ minor = 1
11
+ tiny = 0
12
+ pre = nil
13
+
14
+ string = [major, minor, tiny, pre].compact.join('.')
15
+ Gem::Version.new string
16
+ end
17
+
18
+ def self.version_date
19
+ '2017-10-02'
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,31 @@
1
+ # Encoding: UTF-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'poefy/sqlite3/version.rb'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'poefy-sqlite3'
9
+ s.authors = ['Paul Thompson']
10
+ s.email = ['nossidge@gmail.com']
11
+
12
+ s.summary = %q{SQLite interface for the 'poefy' gem}
13
+ s.description = %q{SQLite interface for the 'poefy' gem}
14
+ s.homepage = 'https://github.com/nossidge/poefy-sqlite3'
15
+
16
+ s.version = Poefy::Sqlite3.version_number
17
+ s.date = Poefy::Sqlite3.version_date
18
+ s.license = 'GPL-3.0'
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.require_paths = ['lib']
23
+
24
+ s.add_development_dependency('bundler', '~> 1.13')
25
+ s.add_development_dependency('rake', '~> 10.0')
26
+ s.add_development_dependency('rspec', '~> 3.0')
27
+ s.add_development_dependency('ruby_rhymes', '~> 0.1')
28
+
29
+ s.add_runtime_dependency('poefy', '~> 1.0', '>= 1.0.0')
30
+ s.add_runtime_dependency('sqlite3', '~> 1.3', '>= 1.3.13')
31
+ end
@@ -0,0 +1,686 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: UTF-8
3
+
4
+ ################################################################################
5
+
6
+ describe Poefy::Poem, "-- SQLite" do
7
+
8
+ before(:all) do
9
+ require 'poefy/sqlite3'
10
+ @root = Poefy.root
11
+ dbs = %w{spec_test_tiny spec_shakespeare spec_whitman}
12
+ dbs.each do |db_name|
13
+ db_file = "#{@root}/data/#{db_name}.db"
14
+ File.delete(db_file) if File.exists?(db_file)
15
+ end
16
+ end
17
+
18
+ after(:all) do
19
+ dbs = %w{spec_test_tiny spec_shakespeare spec_whitman}
20
+ dbs.each do |db_name|
21
+ db_file = "#{@root}/data/#{db_name}.db"
22
+ File.delete(db_file) if File.exists?(db_file)
23
+ end
24
+ end
25
+
26
+ ##############################################################################
27
+
28
+ describe "using tiny dataset 'spec_test_tiny'" do
29
+ corpus = "spec_test_tiny"
30
+ db_file = "#{Poefy.root}/data/#{corpus}.db"
31
+
32
+ # Create a small corpus of a few rhymes.
33
+ text_array = %w{man plan flan can dan fish dish wish bee sea tree flea}
34
+ text_array.map!{ |i| 'a ' + i }
35
+ text_string = text_array.join("\n")
36
+ row_count = text_array.count
37
+
38
+ before(:each) do
39
+ @poefy = Poefy::Poem.new(corpus, { proper: false })
40
+ end
41
+ after(:each) do
42
+ @poefy.close
43
+ end
44
+ it "initialised object not nil" do
45
+ expect(@poefy).to_not be_nil
46
+ end
47
+
48
+ # Create corpora in the three different ways.
49
+ describe "@poefy#make_database!" do
50
+
51
+ it "Use array of strings" do
52
+ @poefy.make_database! text_array
53
+ expect(@poefy.corpus.exists?).to be true
54
+ expect(File.exists?(db_file)).to be true
55
+ expect(@poefy.corpus.count).to be row_count
56
+ poem = @poefy.poem({ rhyme: 'aabb' })
57
+ expect(poem.count).to be 4
58
+ end
59
+
60
+ it "Use one long newline delimited string" do
61
+ @poefy.make_database! text_string
62
+ expect(@poefy.corpus.exists?).to be true
63
+ expect(File.exists?(db_file)).to be true
64
+ expect(@poefy.corpus.count).to be row_count
65
+ poem = @poefy.poem({ rhyme: 'aabb' })
66
+ expect(poem.count).to be 4
67
+ end
68
+
69
+ it "Use text lines from a file" do
70
+
71
+ # Create a temp file.
72
+ tmp = Tempfile.new('spec-', Poefy.root + '/spec')
73
+ text_path = tmp.path
74
+ tmp.write text_string
75
+ tmp.close
76
+
77
+ @poefy.make_database! text_path
78
+ expect(@poefy.corpus.exists?).to be true
79
+ expect(File.exists?(db_file)).to be true
80
+ expect(@poefy.corpus.count).to be row_count
81
+ poem = @poefy.poem({ rhyme: 'aabb' })
82
+ expect(poem.count).to be 4
83
+
84
+ # Delete the temp file.
85
+ tmp.delete
86
+ end
87
+ end
88
+
89
+ # Make sure that the description can be updated as specified
90
+ # and that it doesn't cause SQL injection.
91
+ describe "corpus description using #desc=" do
92
+ it "@poefy.corpus.desc is initially empty" do
93
+ expect(@poefy.corpus.desc).to eq ''
94
+ end
95
+
96
+ values = [
97
+ "test",
98
+ " -- test",
99
+ "; -- test",
100
+ "test' -- ",
101
+ "test'' -- ",
102
+ "'test' -- ",
103
+ "'test'' -- ",
104
+ "Shakespeare's sonnets",
105
+ "Shakespeare's -- sonnets",
106
+ "Shakespeare's; -- sonnets",
107
+ "test' ; INSERT INTO spec_test_tiny VALUES('foo') -- ",
108
+ "105 OR 1=1",
109
+ "' or ''='"
110
+ ]
111
+ values.each do |value|
112
+ it "@poefy.corpus.desc = #{value}" do
113
+ @poefy.corpus.desc = value
114
+ expect(@poefy.corpus.desc).to eq value
115
+ expect(@poefy.corpus.count).to be row_count
116
+ end
117
+ end
118
+ end
119
+
120
+ describe ":rhyme option" do
121
+
122
+ describe "should return nil" do
123
+ it "blank, no argument" do
124
+ poem = @poefy.poem
125
+ expect(poem).to be_nil
126
+ end
127
+ it "({ })" do
128
+ poem = @poefy.poem ({ })
129
+ expect(poem).to be_nil
130
+ end
131
+ it "({ rhyme: nil })" do
132
+ poem = @poefy.poem ({ rhyme: nil })
133
+ expect(poem).to be_nil
134
+ end
135
+ it "({ rhyme: ' ' })" do
136
+ poem = @poefy.poem ({ rhyme: ' ' })
137
+ expect(poem).to be_nil
138
+ end
139
+ it "({ rhyme: '' })" do
140
+ poem = @poefy.poem ({ rhyme: '' })
141
+ expect(poem).to be_nil
142
+ end
143
+ end
144
+
145
+ describe "should return correct number of lines" do
146
+ rhymes = %w{a b z A aa ab zz AA AB AA1 A1 B1 Z1 AB1 A1A1A1A1B1B1B1B1B1}
147
+ rhymes += ['A1A1A1 A1A1A1 B1B1B1B1B1B1','a b c a b c']
148
+ rhymes += [' abc','abc ',' abc ']
149
+ rhymes += ['n aaa n','n aXXXa N1']
150
+ rhymes.each do |i|
151
+ it "({ rhyme: '#{i}' })" do
152
+ poem = @poefy.poem ({ rhyme: i })
153
+ expect(poem.count).to be i.gsub(/[0-9]/,'').length
154
+ end
155
+ end
156
+ end
157
+
158
+ describe "should accept characters other than number" do
159
+ rhymes = %w{. , : .. ., ,, :: (()) @ ~ <<>< A1A1A1...a;}
160
+ rhymes.each do |i|
161
+ it "({ rhyme: '#{i}' })" do
162
+ poem = @poefy.poem ({ rhyme: i })
163
+ expect(poem.count).to be i.gsub(/[0-9]/,'').length
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "should be nil if can't parse rhyme string" do
169
+ rhymes = %w{a1 b1 ab1 Ab1 AAAAABb1 1 1111 1122 11221 ;;::1. }
170
+ rhymes += ['AA Bb1','11 11','11 1 1','..1.']
171
+ rhymes.each do |i|
172
+ it "({ rhyme: '#{i}' })" do
173
+ poem = @poefy.poem ({ rhyme: i })
174
+ expect(poem).to be_nil
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "should be nil if can't complete rhyme string" do
180
+ rhymes = %w{aaaaaa abcd aaaaabbbbb}
181
+ rhymes.each do |i|
182
+ it "({ rhyme: '#{i}' })" do
183
+ poem = @poefy.poem ({ rhyme: i })
184
+ expect(poem).to be_nil
185
+ end
186
+ end
187
+ end
188
+
189
+ describe "should correctly repeat uppercase lines" do
190
+ lines = 200
191
+ it "({ rhyme: 'A' * #{lines} })" do
192
+ poem = @poefy.poem ({ rhyme: 'A' * lines })
193
+ expect(poem.count).to be lines
194
+ expect(poem.uniq.count).to be 1
195
+ end
196
+ it "({ rhyme: ('A'..'C').to_a.map { |i| i * #{lines} }.join })" do
197
+ rhyme = ('A'..'C').to_a.map { |i| i * lines }.join
198
+ poem = @poefy.poem ({ rhyme: rhyme })
199
+ expect(poem.count).to be lines * 3
200
+ expect(poem.uniq.count).to be 3
201
+ end
202
+ end
203
+
204
+ describe "should be nil if can't complete repeating rhyme string" do
205
+ lines = 200
206
+ it "({ rhyme: ('A'..'D').to_a.map { |i| i * #{lines} }.join })" do
207
+ rhyme = ('A'..'D').to_a.map { |i| i * lines }.join
208
+ poem = @poefy.poem ({ rhyme: rhyme })
209
+ expect(poem).to be_nil
210
+ end
211
+ end
212
+
213
+ end
214
+
215
+ describe ":form option" do
216
+
217
+ describe "should return correct number of lines" do
218
+ it "({ form: :default })" do
219
+ poem = @poefy.poem ({ form: :default })
220
+ expect(poem.count).to be 1
221
+ end
222
+ end
223
+
224
+ describe "should be nil if given a named form it can't fulfil" do
225
+ it "({ form: 'sonnet' })" do
226
+ poem = @poefy.poem ({ form: 'sonnet' })
227
+ expect(poem).to be_nil
228
+ end
229
+ it "({ form: :villanelle })" do
230
+ poem = @poefy.poem ({ form: :villanelle })
231
+ expect(poem).to be_nil
232
+ end
233
+ end
234
+
235
+ describe "should be nil if given a junk named form" do
236
+ it "({ form: 'sonnet_junk' })" do
237
+ poem = @poefy.poem ({ form: 'sonnet_junk' })
238
+ expect(poem).to be_nil
239
+ end
240
+ it "({ form: :not_a_form })" do
241
+ poem = @poefy.poem ({ form: :not_a_form })
242
+ expect(poem).to be_nil
243
+ end
244
+ it "({ form: :not_a_form, indent: '0010' })" do
245
+ poem = @poefy.poem ({ form: :not_a_form, indent: '0010' })
246
+ expect(poem).to be_nil
247
+ end
248
+ end
249
+
250
+ describe "should be valid if given a junk named form, and a rhyme" do
251
+ it "({ form: :not_a_form, rhyme: 'abcb' })" do
252
+ poem = @poefy.poem ({ form: :not_a_form, rhyme: 'abcb' })
253
+ expect(poem.count).to be 4
254
+ end
255
+ end
256
+
257
+ describe "should overwrite a named form if another option is specified" do
258
+ it "({ form: 'default', rhyme: 'ab' })" do
259
+ poem = @poefy.poem ({ form: 'default', rhyme: 'ab' })
260
+ expect(poem.count).to be 2
261
+ end
262
+ it "({ form: :villanelle, rhyme: 'abcb' })" do
263
+ poem = @poefy.poem ({ form: :villanelle, rhyme: 'abcb' })
264
+ expect(poem.count).to be 4
265
+ end
266
+ end
267
+ end
268
+ end
269
+
270
+ ##############################################################################
271
+
272
+ describe "using dataset 'spec_shakespeare'" do
273
+
274
+ file_txt = "shakespeare_sonnets.txt"
275
+ file_db = "spec_shakespeare.db"
276
+
277
+ # All the Shakespeare lines are pentameter, so some forms should fail.
278
+ forms = Poefy::PoeticForms::POETIC_FORMS
279
+ forms_fail = [:limerick, :haiku, :common, :ballad, :double_dactyl]
280
+ forms_pass = forms.keys - forms_fail
281
+
282
+ before(:each) do
283
+ @poefy = Poefy::Poem.new(file_db, { proper: false })
284
+ end
285
+ after(:each) do
286
+ @poefy.close
287
+ end
288
+
289
+ it "initialised object not nil" do
290
+ expect(@poefy).to_not be_nil
291
+ end
292
+
293
+ describe "#make_database( '#{@root}/data/#{file_txt}', true )" do
294
+ it "should make the database '#{@root}/data/#{file_db}" do
295
+ db_file = "#{@root}/data/#{file_db}"
296
+ input = `sed '/[a-z]/!d' #{@root}/data/#{file_txt}`
297
+ @poefy.make_database input
298
+ expect(@poefy.corpus.exists?).to be true
299
+ expect(File.exists?(db_file)).to be true
300
+ end
301
+ end
302
+
303
+ describe "using acrostic option" do
304
+ describe "should return correct number of lines" do
305
+ it "({ form: :sonnet, acrostic: 'pauldpthompson' })" do
306
+ poem = @poefy.poem ({ form: :sonnet,
307
+ acrostic: 'pauldpthompson' })
308
+ expect(poem.count).to be 14
309
+ end
310
+ end
311
+ describe "should fail to be created" do
312
+ it "({ form: :sonnet, acrostic: 'qqqqqqqqqqqqqq' })" do
313
+ poem = @poefy.poem ({ form: :sonnet,
314
+ acrostic: 'qqqqqqqqqqqqqq' })
315
+ expect(poem).to be_nil
316
+ end
317
+ end
318
+ end
319
+
320
+ describe "using form string" do
321
+ describe "should return correct number of lines" do
322
+
323
+ # Make sure each form's lines match the expected output.
324
+ # Generate a few to be sure.
325
+ forms_pass.each do |form|
326
+ it "({ form: #{form} })" do
327
+ 10.times do
328
+ poem = @poefy.poem ({ form: form })
329
+ expect(poem.count).to satisfy do |c|
330
+ [*forms[form][:rhyme]].map do |r|
331
+ r.gsub(/[0-9]/,'').length
332
+ end.include?(c)
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
338
+
339
+ describe "should fail to be created" do
340
+ forms_fail.each do |form|
341
+ it "({ form: #{form} })" do
342
+ 4.times do
343
+ poem = @poefy.poem ({ form: form })
344
+ expect(poem).to be_nil
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ describe "make sonnets" do
352
+ sonnet_options = [
353
+ { rhyme: 'ababcdcdefefgg' },
354
+ { rhyme: 'abab cdcd efef gg', indent: '0101 0101 0011 01' },
355
+ { form: 'sonnet' },
356
+ { form: :sonnet, syllable: 0 },
357
+ { form: :sonnet, syllable: 10 },
358
+ { form: :sonnet, regex: /^[A-Z].*$/ },
359
+ { form: :sonnet, regex: '^[A-Z].*$' },
360
+ { form: :sonnet, acrostic: 'pauldpthompson' },
361
+ { form: 'sonnet', indent: '01010101001101' },
362
+ { form: 'sonnet', proper: false }
363
+ ]
364
+ sonnet_options.each do |option|
365
+ it "#{option}" do
366
+ 4.times do
367
+ poem = @poefy.poem(option)
368
+ expect(poem).to_not be_nil
369
+ end
370
+ end
371
+ end
372
+ end
373
+ end
374
+
375
+ ##############################################################################
376
+
377
+ describe "using dataset 'spec_whitman'" do
378
+
379
+ file_txt = "whitman_leaves.txt"
380
+ file_db = "spec_whitman.db"
381
+
382
+ # There's a good mix of syllable count, so all forms should pass.
383
+ forms = Poefy::PoeticForms::POETIC_FORMS
384
+ forms_pass = forms.keys
385
+
386
+ before(:each) do
387
+ @poefy = Poefy::Poem.new(file_db, { proper: false })
388
+ end
389
+ after(:each) do
390
+ @poefy.close
391
+ end
392
+
393
+ it "initialised object not nil" do
394
+ expect(@poefy).to_not be_nil
395
+ end
396
+
397
+ describe "#make_database( '#{@root}/data/#{file_txt}', true )" do
398
+ it "should make the database '#{@root}/data/#{file_db}" do
399
+ db_file = "#{@root}/data/#{file_db}"
400
+ input = `sed '/[a-z]/!d' #{@root}/data/#{file_txt}`
401
+ @poefy.make_database input
402
+ expect(@poefy.corpus.exists?).to be true
403
+ expect(File.exists?(db_file)).to be true
404
+ end
405
+ end
406
+
407
+ describe "using form string" do
408
+ describe "should return correct number of lines" do
409
+
410
+ # Make sure each form's lines match the expected output.
411
+ # Generate a few to be sure.
412
+ forms_pass.each do |form|
413
+ it "({ form: #{form} })" do
414
+ 10.times do
415
+ poem = @poefy.poem ({ form: form })
416
+ expect(poem.count).to satisfy do |c|
417
+ [*forms[form][:rhyme]].map do |r|
418
+ r.gsub(/[0-9]/,'').length
419
+ end.include?(c)
420
+ end
421
+ end
422
+ end
423
+ end
424
+ end
425
+ end
426
+
427
+ describe "make sonnets" do
428
+ sonnet_options = [
429
+ { rhyme: 'ababcdcdefefgg' },
430
+ { rhyme: 'abab cdcd efef gg', indent: '0101 0101 0011 01' },
431
+ { form: 'sonnet' },
432
+ { form: :sonnet, syllable: 0 },
433
+ { form: :sonnet, syllable: 10 },
434
+ { form: :sonnet, regex: /^[A-Z].*$/ },
435
+ { form: :sonnet, regex: '^[A-Z].*$' },
436
+ { form: :sonnet, acrostic: 'pauldpthompson' },
437
+ { form: 'sonnet', indent: '01010101001101' },
438
+ { form: 'sonnet', proper: false }
439
+ ]
440
+ sonnet_options.each do |option|
441
+ it "#{option}" do
442
+ 4.times do
443
+ poem = @poefy.poem(option)
444
+ expect(poem).to_not be_nil
445
+ end
446
+ end
447
+ end
448
+ end
449
+
450
+ describe "using syllable string" do
451
+
452
+ it "({ rhyme: 'abcb defe', syllable: '[8,6,8,6,0,8,6,8,6]' })" do
453
+ options = {
454
+ rhyme: 'abcb defe',
455
+ syllable: '[8,6,8,6,0,8,6,8,6]'
456
+ }
457
+ poem = @poefy.poem (options)
458
+ expect(poem.count).to be options[:rhyme].length
459
+ end
460
+
461
+ it "({ rhyme: 'abcb defe', syllable: '[8,6,8,6,8,6,8,6]' })" do
462
+ options = {
463
+ rhyme: 'abcb defe',
464
+ syllable: '[8,6,8,6,8,6,8,6]'
465
+ }
466
+ poem = @poefy.poem (options)
467
+ expect(poem.count).to be options[:rhyme].length
468
+ end
469
+ end
470
+ end
471
+
472
+ ##############################################################################
473
+
474
+ describe "reusing the same Poem instance" do
475
+ it "should correctly merge the option hashes" do
476
+
477
+ # Default to use rondeau poetic form, and proper sentence validation
478
+ poefy = Poefy::Poem.new(
479
+ 'spec_shakespeare',
480
+ { form: 'rondeau', proper: true }
481
+ )
482
+
483
+ # Generate a properly sentenced rondeau
484
+ poem = poefy.poem
485
+ expect(poem.count).to be 17
486
+
487
+ # Generate a rondeau without proper validation
488
+ poem = poefy.poem ({ proper: false })
489
+ expect(poem.count).to be 17
490
+
491
+ # Generate a proper rondeau with a certain indentation
492
+ poem = poefy.poem ({ indent: '01012 0012 010112' })
493
+ expect(poem.count).to be 17
494
+
495
+ # Generate other forms
496
+ poem = poefy.poem ({ rhyme: 'abbaabbacdecde' })
497
+ expect(poem.count).to be 14
498
+ poem = poefy.poem ({ form: 'sonnet' })
499
+ expect(poem.count).to be 14
500
+ poem = poefy.poem ({ form: 'ballade' })
501
+ expect(poem.count).to be 31
502
+
503
+ # Generate a default rondeau again
504
+ poem = poefy.poem
505
+ expect(poem.count).to be 17
506
+
507
+ poefy.close
508
+ end
509
+ end
510
+
511
+ ##############################################################################
512
+
513
+ describe "using the transform option" do
514
+
515
+ it "should correctly transform the output 1" do
516
+ poefy = Poefy::Poem.new :spec_shakespeare
517
+ transform_hash = {
518
+ 4 => proc { |line, num, poem| line.upcase },
519
+ 12 => proc { |line, num, poem| line.upcase }
520
+ }
521
+ poem = poefy.poem({ form: :sonnet, transform: transform_hash })
522
+ expect(poem.count).to be 14
523
+ expect(poem[3]).to eq poem[3].upcase
524
+ expect(poem[11]).to eq poem[11].upcase
525
+ poefy.close
526
+ end
527
+
528
+ it "should correctly transform the output 2" do
529
+ poefy = Poefy::Poem.new :spec_shakespeare
530
+ transform_hash = {
531
+ 4 => proc { |line, num, poem| poem.count },
532
+ -3 => proc { |line, num, poem| poem.count },
533
+ 7 => proc { |line, num, poem| 'test string' }
534
+ }
535
+ poem = poefy.poem({ form: :sonnet, transform: transform_hash })
536
+ expect(poem.count).to be 14
537
+ expect(poem[3]).to eq '14'
538
+ expect(poem[11]).to eq '14'
539
+ expect(poem[6]).to eq 'test string'
540
+ poefy.close
541
+ end
542
+
543
+ it "should correctly transform the output 3" do
544
+ poefy = Poefy::Poem.new :spec_shakespeare
545
+ transform_proc = proc { |line, num, poem| line.downcase }
546
+ poem = poefy.poem({ form: :sonnet, transform: transform_proc })
547
+ expect(poem.count).to be 14
548
+ poem.each do |i|
549
+ expect(i).to eq i.downcase
550
+ end
551
+ poefy.close
552
+ end
553
+
554
+ it "should correctly transform the output 4" do
555
+ poefy = Poefy::Poem.new :spec_shakespeare
556
+ transform_proc = proc { |line, num, poem| "#{num} #{line.downcase}" }
557
+ poem = poefy.poem({ form: :sonnet, transform: transform_proc })
558
+ expect(poem.count).to be 14
559
+ poem.each.with_index do |line, index|
560
+ expect(line).to eq line.downcase
561
+ first_word = line.split(' ').first
562
+ expect(first_word).to eq (index + 1).to_s
563
+ end
564
+ poefy.close
565
+ end
566
+ end
567
+
568
+ ##############################################################################
569
+
570
+ describe "using the form_from_text option" do
571
+ before(:all) do
572
+ @text = <<-TEXT
573
+ [Chorus 1]
574
+ Oh yeah, I'll tell you something
575
+ I think you'll understand
576
+ When I'll say that something
577
+ I want to hold your hand
578
+ I want to hold your hand
579
+ I want to hold your hand
580
+
581
+ [Verse 1]
582
+ Oh please, say to me
583
+ You'll let me be your man
584
+ And please, say to me
585
+ You'll let me hold your hand
586
+ I'll let me hold your hand
587
+ I want to hold your hand
588
+ TEXT
589
+ @line_count = @text.split("\n").count
590
+ end
591
+
592
+ it "should use the exact poetic form 1" do
593
+ poefy = Poefy::Poem.new(:spec_whitman, {
594
+ form_from_text: @text
595
+ })
596
+ poem = poefy.poem
597
+ poem.map!(&:strip!)
598
+ expect(poem.count).to be @line_count
599
+ expect(poem[0]).to eq "[Chorus 1]"
600
+ expect(poem[8]).to eq "[Verse 1]"
601
+ expect(poem[5]).to eq poem[4]
602
+ expect(poem[6]).to eq poem[4]
603
+ poefy.close
604
+ end
605
+
606
+ it "should use the exact poetic form 2" do
607
+ poefy = Poefy::Poem.new :spec_whitman
608
+ poem = poefy.poem({
609
+ form_from_text: @text
610
+ })
611
+ poem.map!(&:strip!)
612
+ expect(poem.count).to be @line_count
613
+ expect(poem[0]).to eq "[Chorus 1]"
614
+ expect(poem[8]).to eq "[Verse 1]"
615
+ expect(poem[5]).to eq poem[4]
616
+ expect(poem[6]).to eq poem[4]
617
+ poefy.close
618
+ end
619
+
620
+ it "should correctly modify the poetic form 1" do
621
+ poefy = Poefy::Poem.new(:spec_whitman, {
622
+ form_from_text: @text,
623
+ syllable: 6
624
+ })
625
+ poem = poefy.poem
626
+ poem.map!(&:strip!)
627
+ expect(poem.count).to be @line_count
628
+ expect(poem[0]).to eq "[Chorus 1]"
629
+ expect(poem[8]).to eq "[Verse 1]"
630
+ expect(poem[5]).to eq poem[4]
631
+ expect(poem[6]).to eq poem[4]
632
+ poefy.close
633
+ end
634
+
635
+ it "should correctly modify the poetic form 2" do
636
+ poefy = Poefy::Poem.new :spec_whitman
637
+ poem = poefy.poem({
638
+ form_from_text: @text,
639
+ syllable: 6
640
+ })
641
+ poem.map!(&:strip!)
642
+ expect(poem.count).to be @line_count
643
+ expect(poem[0]).to eq "[Chorus 1]"
644
+ expect(poem[8]).to eq "[Verse 1]"
645
+ expect(poem[5]).to eq poem[4]
646
+ expect(poem[6]).to eq poem[4]
647
+ poefy.close
648
+ end
649
+
650
+ it "should correctly modify the poetic form 3" do
651
+ poefy = Poefy::Poem.new(:spec_whitman, {
652
+ form_from_text: @text
653
+ })
654
+ poem = poefy.poem({
655
+ syllable: 6
656
+ })
657
+ poem.map!(&:strip!)
658
+ expect(poem.count).to be @line_count
659
+ expect(poem[0]).to eq "[Chorus 1]"
660
+ expect(poem[8]).to eq "[Verse 1]"
661
+ expect(poem[5]).to eq poem[4]
662
+ expect(poem[6]).to eq poem[4]
663
+ poefy.close
664
+ end
665
+
666
+ it "should correctly replace the poetic form" do
667
+ poefy = Poefy::Poem.new(:spec_whitman, {
668
+ syllable: 6
669
+ })
670
+ poem = poefy.poem({
671
+ form_from_text: @text
672
+ })
673
+ poem.map!(&:strip!)
674
+ expect(poem.count).to be @line_count
675
+ expect(poem[0]).to eq "[Chorus 1]"
676
+ expect(poem[8]).to eq "[Verse 1]"
677
+ expect(poem[5]).to eq poem[4]
678
+ expect(poem[6]).to eq poem[4]
679
+ poefy.close
680
+ end
681
+
682
+ end
683
+
684
+ end
685
+
686
+ ################################################################################
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'tempfile'
5
+ require 'poefy'
6
+
7
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
8
+
9
+ RSpec.configure do |config|
10
+ # some (optional) config here
11
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poefy-sqlite3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Thompson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby_rhymes
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: poefy
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.0.0
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.0'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.0.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: sqlite3
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.3'
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 1.3.13
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '1.3'
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 1.3.13
109
+ description: SQLite interface for the 'poefy' gem
110
+ email:
111
+ - nossidge@gmail.com
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files: []
115
+ files:
116
+ - ".gitignore"
117
+ - ".rspec"
118
+ - Gemfile
119
+ - LICENSE
120
+ - README.md
121
+ - Rakefile
122
+ - lib/poefy/sqlite3.rb
123
+ - lib/poefy/sqlite3/version.rb
124
+ - poefy-sqlite3.gemspec
125
+ - spec/poefy_sqlite3_spec.rb
126
+ - spec/spec_helper.rb
127
+ homepage: https://github.com/nossidge/poefy-sqlite3
128
+ licenses:
129
+ - GPL-3.0
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.5.2
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: SQLite interface for the 'poefy' gem
151
+ test_files: []