poefy 0.6.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rspec +0 -1
- data/README.md +185 -37
- data/bin/poefy +88 -56
- data/bin/poefy_make +93 -0
- data/lib/poefy/conditional_sample.rb +85 -0
- data/lib/poefy/core_extensions/array.rb +78 -39
- data/lib/poefy/database.rb +53 -176
- data/lib/poefy/db_type.rb +64 -0
- data/lib/poefy/generation.rb +5 -27
- data/lib/poefy/handle_error.rb +9 -1
- data/lib/poefy/{poefy_gen_base.rb → poem_base.rb} +17 -37
- data/lib/poefy/poetic_form_from_text.rb +1 -1
- data/lib/poefy/poetic_forms.rb +0 -1
- data/lib/poefy/self.rb +39 -21
- data/lib/poefy/string_manipulation.rb +1 -1
- data/lib/poefy/version.rb +26 -29
- data/lib/poefy.rb +10 -15
- data/poefy.gemspec +16 -5
- data/spec/poefy_unit_spec.rb +199 -0
- data/spec/spec_helper.rb +2 -0
- metadata +53 -14
- data/data/spec_test_tiny.txt +0 -12
- data/lib/poefy/conditional_satisfaction.rb +0 -226
- data/spec/poefy_spec.rb +0 -722
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c669c795f0aa86b7641c6b0246bf7af4c70a044c
|
4
|
+
data.tar.gz: 1d6b45c4c036677c7dcffa769576eac72e997d7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83b5d17cea7d870b77cd04ee06120f24ccd7b09fc4184472c1c9a893e0c9aeea64b9d255b9585515689ff06e19a1d9fe3cd841c1eda89d124a2807ff9b25a5c3
|
7
|
+
data.tar.gz: 58e698d002d74198bbd10fbea4a66f402a664e8d182a6c1c4ee2455b3829ad068b3de81437f03d8ad5d9ab76585ce79357de5179c795f356b539f8d543b9fea1
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
+
__Warning: This project is undergoing serious revision at the moment, and parts of this readme are invalid.__
|
2
|
+
|
3
|
+
__For the correct documentation for the most recent gem version (0.6.1), please see the revision here:
|
4
|
+
[README.md](https://github.com/nossidge/poefy/blob/fb4e39a88296074075a8ad1708e60747f3323baf/README.md)__
|
5
|
+
|
6
|
+
__Version 1.0.0 is coming soon, with Postgres support as the major feature.__
|
7
|
+
|
8
|
+
|
1
9
|
# Poefy
|
2
10
|
|
3
11
|
by [Paul Thompson](https://tilde.town/~nossidge) - nossidge@gmail.com
|
4
12
|
|
5
|
-
Create poems from an input text file, by generating and querying a SQLite database that describes each line.
|
13
|
+
Create rhyming poems from an input text file, by generating and querying a SQLite or PostgreSQL database that describes each line.
|
6
14
|
|
7
15
|
Poems are created using a template to select lines from the database, according to closing rhyme, syllable count, and regex matching.
|
8
16
|
|
@@ -11,59 +19,95 @@ I wrote this because I was banging my head against a wall trying to use [Tracery
|
|
11
19
|
|
12
20
|
## Installation
|
13
21
|
|
14
|
-
|
22
|
+
### Install the base gem
|
15
23
|
|
16
|
-
|
17
|
-
gem 'poefy'
|
18
|
-
```
|
24
|
+
$ gem install poefy
|
19
25
|
|
20
|
-
And then execute:
|
21
26
|
|
22
|
-
|
27
|
+
### Install a database gem
|
23
28
|
|
24
|
-
|
29
|
+
You have two options when it comes to databases.
|
25
30
|
|
26
|
-
$ gem install poefy
|
27
31
|
|
28
|
-
|
32
|
+
#### PostgreSQL
|
33
|
+
|
34
|
+
Install [PostgreSQL 9.0+](https://www.postgresql.org/download/)
|
35
|
+
|
36
|
+
Install the below gem.
|
37
|
+
|
38
|
+
$ gem install poefy-pg
|
39
|
+
|
40
|
+
Create a new user:
|
41
|
+
|
42
|
+
username: 'poefy'
|
43
|
+
password: 'poefy'
|
44
|
+
|
45
|
+
Then create a new database, with the above user as the owner:
|
29
46
|
|
30
|
-
|
47
|
+
database: 'poefy'
|
31
48
|
|
32
|
-
|
49
|
+
Everything is called 'poefy'. Nice and easy.
|
50
|
+
|
51
|
+
|
52
|
+
#### SQLite
|
53
|
+
|
54
|
+
Install [SQLite 3.0+](https://sqlite.org/download.html)
|
55
|
+
|
56
|
+
Just install the below gem. There is no further setup needed.
|
57
|
+
|
58
|
+
$ gem install poefy-sqlite3
|
59
|
+
|
60
|
+
|
61
|
+
### Set up some example corpora
|
62
|
+
|
63
|
+
The repo comes with some initial text files included. To generate corpora for these files, execute the special `poefy_make` binary:
|
64
|
+
|
65
|
+
$ poefy_make
|
66
|
+
|
67
|
+
This command will also setup a `settings.yml` file in the gem root. By default it will be set to 'pg' or 'sqlite3', depending on which gem you installed. If you need to change that setting you can run either of the below:
|
68
|
+
|
69
|
+
$ poefy -D pg
|
70
|
+
$ poefy -D sqlite3
|
71
|
+
|
72
|
+
You can use the `-D` option by itself without the argument to see the current database setting.
|
33
73
|
|
34
74
|
|
35
75
|
## Usage
|
36
76
|
|
37
77
|
### From the Command Line
|
38
78
|
|
39
|
-
|
79
|
+
To make a poefy corpus from a text file, run either of the below:
|
80
|
+
|
81
|
+
$ poefy shakespeare -m < shakespeare_sonnets.txt
|
82
|
+
$ poefy shakespeare --make < shakespeare_sonnets.txt
|
40
83
|
|
41
|
-
|
84
|
+
This will create a corpus describing each line of Shakespeare's sonnets. The type of corpus depends on whether you are using PosgreSQL (saved as a table in the 'poefy' database) or SQLite (saved to a database file as ROOT/data/CORPUS.db).
|
42
85
|
|
43
|
-
Now, whenever you want to make poems using Shakespeare's lines, you can just use `poefy shakespeare` and it will read from the already created
|
86
|
+
Now, whenever you want to make poems using Shakespeare's lines, you can just use `poefy shakespeare` and it will read from the already created corpora:
|
44
87
|
|
45
88
|
$ poefy shakespeare sonnet
|
46
89
|
$ poefy shakespeare limerick
|
47
|
-
$ poefy shakespeare
|
90
|
+
$ poefy shakespeare villanelle
|
48
91
|
|
49
|
-
|
92
|
+
If you later want to remake the corpus, for example to add new lines, you can use the `-m` option again and the existing corpus will be overwritten.
|
50
93
|
|
51
|
-
|
94
|
+
$ cat shakespeare_sonnets.txt shakespeare_plays.txt | poefy shakespeare -m
|
52
95
|
|
53
|
-
|
96
|
+
You can use the `-L` or `--list` option to view available corpora.
|
54
97
|
|
55
|
-
|
98
|
+
__For SQLite users only:__
|
99
|
+
This corpus database file is stored in the same directory as the gem, so it can be accessed by all users on your system. To store a corpus in a different directory, you can use the `-l` or `--local` option:
|
56
100
|
|
57
101
|
$ poefy -l path/to/eliot.db < eliot.txt
|
58
102
|
|
59
103
|
You then need to use the `-l` option when generating poems:
|
60
104
|
|
61
105
|
$ poefy -l path/to/eliot.db rondeau
|
62
|
-
$ poefy
|
106
|
+
$ poefy path/to/eliot.db ballade -l
|
63
107
|
$ cd path/to
|
64
108
|
$ poefy -l eliot.db ballata
|
65
109
|
|
66
|
-
|
110
|
+
Note that using this option, you *do* need to specify the '.db' file extension of the chosen corpus.
|
67
111
|
|
68
112
|
|
69
113
|
#### Option `-f` or `--form`
|
@@ -239,7 +283,7 @@ To clarify: using the `-p` or `--proper` option will DISABLE this functionality.
|
|
239
283
|
|
240
284
|
If the second argument is `rhyme`, then output all lines that rhyme with the word.
|
241
285
|
|
242
|
-
This gives a basic look into the
|
286
|
+
This gives a basic look into the contents of the corpus table.
|
243
287
|
|
244
288
|
````
|
245
289
|
$ poefy dickinson rhyme confuse
|
@@ -270,7 +314,7 @@ You can do the same thing for the other keys: `rhyme`, `final_word`, and `syllab
|
|
270
314
|
|
271
315
|
#### Special case: poetic form from text file
|
272
316
|
|
273
|
-
If you pipe in text and don't use the `-
|
317
|
+
If you pipe in text and don't use the `-m` option to create a corpus, then the output will be a poem with the same structure as the file. This can also be accomplished if the second argument is a reference to a text file. So, assuming you have a [`lyrics`][1] script that will return song lines for you:
|
274
318
|
|
275
319
|
$ lyrics 'carly rae jepsen' 'call me maybe' | tee jep.txt | poefy whitman
|
276
320
|
$ poefy whitman < jep.txt
|
@@ -282,7 +326,7 @@ Any line that is bracketed in `[square]` or `{curly}` braces will be duplicated
|
|
282
326
|
|
283
327
|
Also, any indentation will be preserved, assuming 2 spaces per "indent".
|
284
328
|
|
285
|
-
Here's an example of a song that can be sung to the same tune as "[I Want to Hold Your Hand][
|
329
|
+
Here's an example of a song that can be sung to the same tune as "[I Want to Hold Your Hand][2]", but using lyrics from all Beatles songs:
|
286
330
|
|
287
331
|
````
|
288
332
|
$ poefy beatles data/beatles/i_want_to_hold_your_hand.txt
|
@@ -343,7 +387,8 @@ I'll let me hold your hand You're not the hurting kind
|
|
343
387
|
I want to hold your hand What goes on in your mind?
|
344
388
|
````
|
345
389
|
|
346
|
-
[1]: https://
|
390
|
+
[1]: https://github.com/nossidge/lyrics
|
391
|
+
[2]: https://genius.com/The-beatles-i-want-to-hold-your-hand-lyrics
|
347
392
|
|
348
393
|
|
349
394
|
### As a Ruby Gem
|
@@ -352,17 +397,35 @@ To make a poefy database and generate poems from it:
|
|
352
397
|
|
353
398
|
```ruby
|
354
399
|
require 'poefy'
|
355
|
-
|
356
|
-
|
400
|
+
|
401
|
+
# Choose one of the below require lines.
|
402
|
+
require 'poefy/pg'
|
403
|
+
require 'poefy/sqlite3'
|
404
|
+
|
405
|
+
# Or you could just run this. It will require the
|
406
|
+
# database gem that is specified in 'settings.yml'
|
407
|
+
Poefy.require_db
|
408
|
+
|
409
|
+
# Set up a Poem object using the name of the corpus.
|
410
|
+
poefy = Poefy::Poem.new('shakespeare')
|
411
|
+
|
412
|
+
# Filename is the text file containing the lines.
|
413
|
+
# Description is an explanation of the data.
|
414
|
+
filename = 'shakespeare_sonnets.txt'
|
415
|
+
description = 'The sonnets of Shakespeare'
|
416
|
+
poefy.make_database(filename, description)
|
417
|
+
|
418
|
+
# Close the database link.
|
419
|
+
poefy.close
|
357
420
|
```
|
358
421
|
|
359
|
-
`
|
422
|
+
`filename` will accept a string path to a file, an array of lines, or a long string delimited by newlines. `description` is optional.
|
360
423
|
|
361
424
|
You only have to make the database once. And then to generate poems:
|
362
425
|
|
363
426
|
```ruby
|
364
427
|
# Different ways to generate sonnets
|
365
|
-
poefy = Poefy::
|
428
|
+
poefy = Poefy::Poem.new('shakespeare')
|
366
429
|
puts poefy.poem ({ rhyme: 'ababcdcdefefgg' })
|
367
430
|
puts poefy.poem ({ rhyme: 'abab cdcd efef gg', indent: '0101 0101 0011 01' })
|
368
431
|
puts poefy.poem ({ form: 'sonnet' })
|
@@ -375,13 +438,16 @@ puts poefy.poem ({ form: 'sonnet', indent: '01010101001101' })
|
|
375
438
|
puts poefy.poem ({ form: 'sonnet', proper: false })
|
376
439
|
puts poefy.poem ({ form_from_text: 'how_do_i_love_thee.txt' })
|
377
440
|
puts poefy.poem ({ form_from_text: 'how_do_i_love_thee.txt', syllable: 0 })
|
441
|
+
poefy.close
|
378
442
|
```
|
379
443
|
|
444
|
+
The #poem method requires at least one option of `:rhyme`, `:form`, or `:form_from_text`
|
445
|
+
|
380
446
|
All options can be specified at object initialisation, and subsequent poems will use those options as default:
|
381
447
|
|
382
448
|
```ruby
|
383
449
|
# Default to use rondeau poetic form, and proper sentence validation
|
384
|
-
poefy = Poefy::
|
450
|
+
poefy = Poefy::Poem.new('shakespeare', { form: 'rondeau', proper: true })
|
385
451
|
|
386
452
|
# Generate a properly sentenced rondeau
|
387
453
|
puts poefy.poem
|
@@ -391,6 +457,8 @@ puts poefy.poem ({ proper: false })
|
|
391
457
|
|
392
458
|
# Generate a proper rondeau with a certain indentation
|
393
459
|
puts poefy.poem ({ indent: '01012 0012 010112' })
|
460
|
+
|
461
|
+
poefy.close
|
394
462
|
```
|
395
463
|
|
396
464
|
|
@@ -405,8 +473,9 @@ transform_hash = {
|
|
405
473
|
4 => proc { |line, num, poem| line.upcase },
|
406
474
|
12 => proc { |line, num, poem| line.upcase }
|
407
475
|
}
|
408
|
-
poefy = Poefy::
|
476
|
+
poefy = Poefy::Poem.new 'shakespeare'
|
409
477
|
puts poefy.poem({ form: :sonnet, transform: transform_hash })
|
478
|
+
poefy.close
|
410
479
|
```
|
411
480
|
|
412
481
|
The key for the hash corresponds to the line of the poem, starting from 1 (not 0). You can use negative keys to specify from the end of the poem. Any key that is not an integer or is out of the array bounds will be ignored.
|
@@ -415,8 +484,9 @@ If you don't include a hash, then the proc will be applied to each line. So to a
|
|
415
484
|
|
416
485
|
```ruby
|
417
486
|
transform_proc = proc { |line, num, poem| "#{num.to_s.rjust(2)} #{line}" }
|
418
|
-
poefy = Poefy::
|
487
|
+
poefy = Poefy::Poem.new 'shakespeare'
|
419
488
|
puts poefy.poem({ form: :sonnet, transform: transform_proc })
|
489
|
+
poefy.close
|
420
490
|
```
|
421
491
|
|
422
492
|
The proc arguments `|line, num, poem|` are: the text of the line that is being replaced, the number of the line, and the full poem array as it was before any transformations had occurred.
|
@@ -424,6 +494,84 @@ The proc arguments `|line, num, poem|` are: the text of the line that is being r
|
|
424
494
|
The transformations are implemented after the poem has been generated, but before the `indent` has occurred.
|
425
495
|
|
426
496
|
|
497
|
+
#### Corpus internals
|
498
|
+
|
499
|
+
The `Poefy::Poem.poem` method will do the work of creating a poem for you, but the object also exposes more information about the corpus, if you need it. This is done through the `Poefy::Poem.corpus` object.
|
500
|
+
|
501
|
+
```ruby
|
502
|
+
# If the corpus database already exists:
|
503
|
+
poefy = Poefy::Poem.new('shakespeare')
|
504
|
+
puts poefy.corpus.type # "sqlite3" or "pg"
|
505
|
+
puts poefy.corpus.name # "shakespeare"
|
506
|
+
puts poefy.corpus.count # 2137
|
507
|
+
puts poefy.corpus.exists? # true
|
508
|
+
|
509
|
+
# If the corpus has not been generated yet:
|
510
|
+
poefy = Poefy::Poem.new('plath')
|
511
|
+
puts poefy.corpus.type # "sqlite3" or "pg"
|
512
|
+
puts poefy.corpus.name # "plath"
|
513
|
+
puts poefy.corpus.count # 0
|
514
|
+
puts poefy.corpus.exists? # false
|
515
|
+
```
|
516
|
+
|
517
|
+
To view or change the description of the corpus.
|
518
|
+
|
519
|
+
```ruby
|
520
|
+
poefy = Poefy::Poem.new('shakespeare')
|
521
|
+
puts 'Initial description: ' + poefy.corpus.desc
|
522
|
+
# Initial description: Shakespeare's sonnets
|
523
|
+
|
524
|
+
poefy.corpus.desc = 'a brand new string'
|
525
|
+
puts 'Updated description: ' + poefy.corpus.desc
|
526
|
+
# Updated description: a brand new string
|
527
|
+
```
|
528
|
+
|
529
|
+
There's also a public interface to find rhyming lines within the corpus. Let's say we need to find 6 lines with the same rhyme. First, we will get an array of all rhyme keys that have at least 6 distinct final words. Then select one rhyme at random. Use that rhyme to find all lines that have that rhyme key, and remove lines with duplicate last words (so that we don't rhyme e.g. "tree" with "tree"). Then grab a sample 6 lines from that array.
|
530
|
+
|
531
|
+
```ruby
|
532
|
+
poefy = Poefy::Poem.new('shakespeare')
|
533
|
+
line_count = 6
|
534
|
+
|
535
|
+
rhymes = poefy.corpus.rhymes_by_count(line_count)
|
536
|
+
rhyme = rhymes.sample['rhyme']
|
537
|
+
lines = poefy.corpus.lines_by_rhyme(rhyme)
|
538
|
+
lines = lines.map{ |i| i['line'] }.shuffle
|
539
|
+
lines.uniq!{ |i| i.to_phrase.last_word.downcase }
|
540
|
+
puts lines.sample(line_count)
|
541
|
+
|
542
|
+
# Mine eye and heart are at a mortal war,
|
543
|
+
# Like as the waves make towards the pebbled shore,
|
544
|
+
# Let those whom nature hath not made for store,
|
545
|
+
# All mine was thine, before thou hadst this more.
|
546
|
+
# O! though I love what others do abhor,
|
547
|
+
# To show false Art what beauty was of yore.
|
548
|
+
```
|
549
|
+
|
550
|
+
You can also specify a range for the lines' syllable counts. Just use a hash with keys ':min' and ':max' as the second argument.
|
551
|
+
|
552
|
+
```ruby
|
553
|
+
poefy = Poefy::Poem.new('whitman')
|
554
|
+
line_count = 6
|
555
|
+
syllables = {min: 8, max: 8}
|
556
|
+
|
557
|
+
rhymes = poefy.corpus.rhymes_by_count(line_count, syllables)
|
558
|
+
rhyme = rhymes.sample['rhyme']
|
559
|
+
lines = poefy.corpus.lines_by_rhyme(rhyme, syllables)
|
560
|
+
lines = lines.map{ |i| i['line'] }.shuffle
|
561
|
+
lines.uniq!{ |i| i.to_phrase.last_word.downcase }
|
562
|
+
puts lines.sample(line_count)
|
563
|
+
|
564
|
+
# As I wended the shores I know,
|
565
|
+
# Rhone, and the Guadalquiver flow,
|
566
|
+
# Scooting obliquely high and low.
|
567
|
+
# O heart-sick days! O nights of woe!
|
568
|
+
# Ceaseless she paces to and fro,
|
569
|
+
# To be lost if it must be so!
|
570
|
+
```
|
571
|
+
|
572
|
+
`#rhymes_by_count` and `#lines_by_rhyme` are the only stored procedures that return corpus lines. All the other filtering and line arrangement is done based on the records returned by these two methods.
|
573
|
+
|
574
|
+
|
427
575
|
## Some tips
|
428
576
|
|
429
577
|
### Make a database from a delimited file
|
@@ -432,26 +580,26 @@ Databases are created using data piped into poefy, so you can do any pre-process
|
|
432
580
|
|
433
581
|
Use awk to get final field from tab delimited IRC logs.
|
434
582
|
|
435
|
-
$ awk -F$'\t' '{print $NF}'
|
583
|
+
$ awk -F$'\t' '{print $NF}' irc_log_20170908.txt | poefy -m irc
|
436
584
|
|
437
585
|
|
438
586
|
### Make a database, ignoring short lines
|
439
587
|
|
440
588
|
Use sed to filter out lines that are too short:
|
441
589
|
|
442
|
-
$ sed -r '/^.{,20}$/d' st_therese_of_lisieux.txt | poefy -
|
590
|
+
$ sed -r '/^.{,20}$/d' st_therese_of_lisieux.txt | poefy -m therese
|
443
591
|
|
444
592
|
|
445
593
|
### Make a database, ignoring uppercase lines
|
446
594
|
|
447
595
|
Use sed to filter out lines that do not contain lowercase letters. For example, the sonnets file contains lines with the number of the sonnet, e.g. "CXLVII."
|
448
596
|
|
449
|
-
$ sed -r 'sed '/[a-z]/!d' shakespeare_sonnets.txt | poefy -
|
597
|
+
$ sed -r 'sed '/[a-z]/!d' shakespeare_sonnets.txt | poefy -m shakespeare
|
450
598
|
|
451
599
|
|
452
600
|
### Problem: it won't output lines that I know are valid
|
453
601
|
|
454
|
-
This code uses a gem called `wordfilter` that will automatically filter out lines that contain [grotty words](https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json). If you really definitely truly don't want to exclude a certain word, you can remove
|
602
|
+
This code uses a gem called `wordfilter` that will automatically filter out lines that contain [grotty words](https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json). If you really definitely truly don't want to exclude a certain word, you can remove that word from the blacklist. For example, if your input lines are from a dissertation on the dance styles of the ska and reggae music scenes, in your Ruby code you can call:
|
455
603
|
|
456
604
|
```ruby
|
457
605
|
Wordfilter.remove_word('skank')
|
data/bin/poefy
CHANGED
@@ -2,20 +2,34 @@
|
|
2
2
|
# Encoding: UTF-8
|
3
3
|
|
4
4
|
################################################################################
|
5
|
-
# Use Poefy::
|
5
|
+
# Use Poefy::Poem to make a poem from the command line.
|
6
6
|
################################################################################
|
7
7
|
|
8
8
|
require 'optparse'
|
9
9
|
|
10
10
|
require_relative '../lib/poefy.rb'
|
11
11
|
|
12
|
+
Poefy.console = true
|
13
|
+
Poefy.require_db
|
14
|
+
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
# List the corpora & descriptions in a nice table format.
|
18
|
+
def corpora
|
19
|
+
output = Poefy.corpora_with_desc
|
20
|
+
width = output.keys.max_by(&:length).length
|
21
|
+
output.map do |key, value|
|
22
|
+
sprintf "%-#{width}s %s", key, value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
################################################################################
|
13
27
|
|
14
28
|
def parse_options
|
15
|
-
options = {
|
29
|
+
options = {}
|
16
30
|
|
17
31
|
# Set up variables used later.
|
18
|
-
forms = Poefy
|
32
|
+
forms = Poefy.poetic_forms
|
19
33
|
forms_by_4 = forms.each_slice(4).to_a.map { |i| i.join ', ' }
|
20
34
|
rhyme_docs = " This is the most important argument.
|
21
35
|
All other form strings are based on this.
|
@@ -39,20 +53,18 @@ def parse_options
|
|
39
53
|
Paul Thompson - nossidge@gmail.com
|
40
54
|
].gsub(' ',' ')
|
41
55
|
|
42
|
-
usage = %[Usage: poefy shakespeare < shakespeare_sonnets.txt
|
56
|
+
usage = %[Usage: poefy shakespeare -m < shakespeare_sonnets.txt
|
57
|
+
poefy shakespeare -d "The sonnets of Shakespeare"
|
43
58
|
poefy shakespeare sonnet
|
44
59
|
poefy spoke haiku
|
45
60
|
poefy therese -r 'abab cdcd efef gg' -i '0101 0101 0011 01'
|
46
61
|
poefy whitman -r 'A1bA2 abA1 abA2 abA1 abA2 abA1A2'
|
62
|
+
poefy -Lc
|
47
63
|
].gsub(' ',' ')
|
48
64
|
|
49
|
-
|
50
|
-
.each_slice(4).to_a
|
51
|
-
.map { |i| i.join ', ' }
|
52
|
-
.join("\n" + ' ' * 21)
|
53
|
-
databases = 'Databases available: ' + databases
|
65
|
+
list = 'Corpora: ' + corpora.join("\n ")
|
54
66
|
|
55
|
-
opts.banner = program_info + "\n" + usage + "\n" +
|
67
|
+
opts.banner = program_info + "\n" + usage + "\n" + list + "\n\n"
|
56
68
|
|
57
69
|
# These will be further validated within the class.
|
58
70
|
opts.on('-f', '--form STRING',
|
@@ -62,7 +74,7 @@ def parse_options
|
|
62
74
|
' ' * 39 + forms_by_4.join("\n" + ' ' * 39)) do |s|
|
63
75
|
options[:form] = s
|
64
76
|
end
|
65
|
-
opts.on('-r', '--rhyme STRING', "See
|
77
|
+
opts.on('-r', '--rhyme STRING', "(See 'Description of rhyme string' below)") do |s|
|
66
78
|
options[:rhyme] = s
|
67
79
|
end
|
68
80
|
opts.on('-i', '--indent STRING', "Indentation of each line") do |s|
|
@@ -103,18 +115,52 @@ def parse_options
|
|
103
115
|
options[:number] = n.to_i
|
104
116
|
end
|
105
117
|
|
106
|
-
#
|
118
|
+
# Corpus options.
|
107
119
|
opts.separator nil
|
108
|
-
opts.on('-
|
109
|
-
"
|
110
|
-
|
120
|
+
opts.on('-m', '--make [STRING]',
|
121
|
+
"Make new or overwrite existing corpus with piped input\n" + ' ' * 39 +
|
122
|
+
"Argument is a description of the corpus") do |s|
|
123
|
+
options[:make_corpus] = true
|
124
|
+
options[:corpus_desc] = s
|
125
|
+
end
|
126
|
+
opts.on('-d', '--desc STRING',
|
127
|
+
"Overwrite the description of the corpus") do |s|
|
128
|
+
options[:corpus_desc] = s
|
111
129
|
end
|
112
130
|
opts.on('-l', '--local',
|
113
|
-
"Default is to use database files from /data/\n" + ' ' * 39 +
|
114
|
-
"With this option,
|
131
|
+
"(SQLite only) Default is to use database files from /data/\n" + ' ' * 39 +
|
132
|
+
"With this option, paths are relative to working directory") do
|
115
133
|
options[:local] = true
|
116
134
|
end
|
117
135
|
|
136
|
+
# Database internals.
|
137
|
+
opts.separator nil
|
138
|
+
opts.on('-L', '--list [C|D]',
|
139
|
+
"List all the installed corpora\n" + ' ' * 39 +
|
140
|
+
"Append 'c' or 'd' to list just the corpora or descriptions") do |s|
|
141
|
+
s ||= ' '
|
142
|
+
if s[0].casecmp('c').zero?
|
143
|
+
puts Poefy.corpora
|
144
|
+
elsif s[0].casecmp('d').zero?
|
145
|
+
puts Poefy.corpora_with_desc.values
|
146
|
+
else
|
147
|
+
puts corpora
|
148
|
+
end
|
149
|
+
exit 0
|
150
|
+
end
|
151
|
+
opts.on('-D', '--database [pg|sqlite3]',
|
152
|
+
"Display the database implementation setting\n" + ' ' * 39 +
|
153
|
+
"Append 'pg' or 'sqlite3' to change programs") do |s|
|
154
|
+
s ||= ' '
|
155
|
+
if s[0].casecmp('p').zero?
|
156
|
+
Poefy.database_type = 'pg'
|
157
|
+
elsif s[0].casecmp('s').zero?
|
158
|
+
Poefy.database_type = 'sqlite3'
|
159
|
+
end
|
160
|
+
puts Poefy.database_type
|
161
|
+
exit 0
|
162
|
+
end
|
163
|
+
|
118
164
|
# Help output.
|
119
165
|
opts.separator nil
|
120
166
|
opts.on('-h', '--help', 'Display this help screen' ) do
|
@@ -152,67 +198,53 @@ options = parse_options
|
|
152
198
|
# Read data lines from STDIN.
|
153
199
|
data = (not STDIN.tty? and not STDIN.closed?) ? STDIN.read : nil
|
154
200
|
|
155
|
-
#
|
201
|
+
# Corpus name is the first argument.
|
156
202
|
first_arg = ARGV.first
|
157
203
|
if first_arg.nil?
|
158
|
-
STDERR.puts "ERROR: Please specify a
|
204
|
+
STDERR.puts "ERROR: Please specify a corpus name to read from/to"
|
159
205
|
exit 1
|
160
206
|
end
|
161
207
|
|
162
|
-
# If the first argument is 'make_dbs', then make
|
163
|
-
# databases from the included text files.
|
164
|
-
if first_arg == 'make_dbs'
|
165
|
-
path = File.expand_path('../../data', __FILE__)
|
166
|
-
|
167
|
-
input = `sed '/[a-z]/!d' #{path}/shakespeare_sonnets.txt`
|
168
|
-
poefy = Poefy::PoefyGen.new 'shakespeare'
|
169
|
-
poefy.make_database input, false
|
170
|
-
|
171
|
-
input = `sed '/[a-z]/!d' #{path}/st_therese_of_lisieux.txt`
|
172
|
-
poefy = Poefy::PoefyGen.new 'therese'
|
173
|
-
poefy.make_database input, false
|
174
|
-
|
175
|
-
input = `sed '/[a-z]/!d' #{path}/whitman_leaves.txt`
|
176
|
-
poefy = Poefy::PoefyGen.new 'whitman'
|
177
|
-
poefy.make_database input, false
|
178
|
-
|
179
|
-
input = `sed '/[a-z]/!d' #{path}/emily_dickinson.txt`
|
180
|
-
poefy = Poefy::PoefyGen.new 'dickinson'
|
181
|
-
poefy.make_database input, false
|
182
|
-
|
183
|
-
input = `sed '/[a-z]/!d' #{path}/english_as_she_is_spoke.txt`
|
184
|
-
poefy = Poefy::PoefyGen.new 'spoke'
|
185
|
-
poefy.make_database input, false
|
186
|
-
|
187
|
-
exit 0
|
188
|
-
end
|
189
|
-
|
190
208
|
# Poetic form name is the second argument, if it exists.
|
191
209
|
second_arg = (ARGV.length > 1) ? ARGV[1] : ''
|
192
210
|
options[:form] = second_arg if second_arg != ''
|
193
211
|
|
194
|
-
# If we need to make a
|
195
|
-
# Exit the program after
|
196
|
-
if options[:
|
197
|
-
poefy = Poefy::
|
212
|
+
# If we need to make a corpus.
|
213
|
+
# Exit the program after corpus is generated.
|
214
|
+
if options[:make_corpus]
|
215
|
+
poefy = Poefy::Poem.new first_arg
|
198
216
|
if data
|
199
|
-
poefy.make_database data, true
|
217
|
+
poefy.make_database data, options[:corpus_desc], true
|
200
218
|
poefy.close
|
201
219
|
exit 0
|
202
220
|
else
|
203
|
-
STDERR.puts 'ERROR: Need text input to generate a
|
221
|
+
STDERR.puts 'ERROR: Need text input to generate a corpus'
|
204
222
|
STDERR.puts ' Please pipe some data into the program'
|
205
223
|
exit 1
|
206
224
|
end
|
207
225
|
end
|
208
226
|
|
227
|
+
# If we need to update a corpus description.
|
228
|
+
# Exit the program after corpus is generated.
|
229
|
+
if options[:corpus_desc]
|
230
|
+
poefy = Poefy::Poem.new first_arg
|
231
|
+
begin
|
232
|
+
poefy.corpus.desc = options[:corpus_desc]
|
233
|
+
poefy.close
|
234
|
+
exit 0
|
235
|
+
rescue
|
236
|
+
STDERR.puts "ERROR: Corpus '#{first_arg}' does not yet exist"
|
237
|
+
exit 1
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
209
241
|
# If the second argument is 'rhyme', then output all
|
210
242
|
# lines that rhyme with the word.
|
211
243
|
if second_arg == 'rhyme'
|
212
|
-
poefy = Poefy::
|
244
|
+
poefy = Poefy::Poem.new first_arg
|
213
245
|
third_arg = (ARGV.length > 2) ? ARGV[2] : nil
|
214
246
|
fourth_arg = (ARGV.length > 3) ? ARGV[3] : nil
|
215
|
-
puts poefy.rhymes(third_arg, fourth_arg)
|
247
|
+
puts poefy.corpus.rhymes(third_arg, fourth_arg)
|
216
248
|
exit 0
|
217
249
|
end
|
218
250
|
|
@@ -223,7 +255,7 @@ if data or File.exists?(second_arg)
|
|
223
255
|
end
|
224
256
|
|
225
257
|
# Create poefy object using the options.
|
226
|
-
poefy = Poefy::
|
258
|
+
poefy = Poefy::Poem.new first_arg, options
|
227
259
|
|
228
260
|
# Make the correct number of poems, and output them.
|
229
261
|
number = options[:number] || 1
|