rwdeliza 0.03
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/ElizaData/database/db.1 +7015 -0
- data/ElizaData/database/db.10 +7001 -0
- data/ElizaData/database/db.11 +7001 -0
- data/ElizaData/database/db.12 +7003 -0
- data/ElizaData/database/db.13 +7003 -0
- data/ElizaData/database/db.14 +7008 -0
- data/ElizaData/database/db.15 +7001 -0
- data/ElizaData/database/db.16 +7001 -0
- data/ElizaData/database/db.17 +7001 -0
- data/ElizaData/database/db.18 +7001 -0
- data/ElizaData/database/db.19 +7001 -0
- data/ElizaData/database/db.2 +7001 -0
- data/ElizaData/database/db.20 +5467 -0
- data/ElizaData/database/db.3 +7001 -0
- data/ElizaData/database/db.4 +7001 -0
- data/ElizaData/database/db.5 +7001 -0
- data/ElizaData/database/db.6 +7001 -0
- data/ElizaData/database/db.7 +7001 -0
- data/ElizaData/database/db.8 +7001 -0
- data/ElizaData/database/db.9 +7001 -0
- data/ElizaData/responses/hello.res +1 -0
- data/ElizaData/responses/i_agree.res +1 -0
- data/ElizaData/responses/i_am_listening_to_you.res +1 -0
- data/ElizaData/responses/please_explain.res +1 -0
- data/ElizaData/responses/thank_you.res +1 -0
- data/ElizaData/tiny.dict +211 -0
- data/ElizaData/words/adjectives1.words +906 -0
- data/ElizaData/words/adjectives2w.words +1 -0
- data/ElizaData/words/noun0.words +15 -0
- data/ElizaData/words/noun1.words +1391 -0
- data/ElizaData/words/noun2.words +1924 -0
- data/ElizaData/words/noun4.words +330 -0
- data/ElizaData/words/pronoun1.words +6 -0
- data/ElizaData/words/verb4.words +350 -0
- data/ElizaData/words/verb42.words +391 -0
- data/ElizaData/words/verb42w.words +1 -0
- data/ElizaData/words/verb43.words +402 -0
- data/ElizaData/words/verb43w.words +1 -0
- data/ElizaData/words/verb45.words +452 -0
- data/ElizaData/words/verb4w.words +1 -0
- data/ElizaData/words/verb5.words +13 -0
- data/ElizaData/words/verb61.words +35 -0
- data/ElizaData/words/verb62.words +41 -0
- data/ElizaData/words/verb83.words +17 -0
- data/Readme.txt +462 -0
- data/bin/rwdeliza +19 -0
- data/code/01rwdcore/01rwdcore.rb +29 -0
- data/code/01rwdcore/02helptexthashbegin.rb +4 -0
- data/code/01rwdcore/03helptexthash.rb +23 -0
- data/code/01rwdcore/04helptextend.rb +6 -0
- data/code/01rwdcore/jumplinkcommand.rb +26 -0
- data/code/01rwdcore/openhelpwindow.rb +31 -0
- data/code/01rwdcore/returntomain.rb +10 -0
- data/code/01rwdcore/rundocuments.rb +10 -0
- data/code/01rwdcore/runeditconfiguration.rb +10 -0
- data/code/01rwdcore/runhelpabout.rb +10 -0
- data/code/01rwdcore/runopentinkerdocument.rb +7 -0
- data/code/01rwdcore/rwdtinkerversion.rb +22 -0
- data/code/01rwdcore/rwdwindowreturn.rb +9 -0
- data/code/01rwdcore/selectiontab.rb +9 -0
- data/code/01rwdcore/setuphelpaboutoptions.rb +13 -0
- data/code/01rwdcore/setuptinkerdocuments.rb +6 -0
- data/code/01rwdcore/test_cases.rb +109 -0
- data/code/01rwdcore/test_harness.rb +13 -0
- data/code/01rwdcore/uploadreturns.rb +62 -0
- data/code/dd0viewphoto/dd0viewphoto.rb +3 -0
- data/code/superant.com.rwdeliza/0uninstallapplet.rb +10 -0
- data/code/superant.com.rwdeliza/eliza01.rb +45 -0
- data/code/superant.com.rwdeliza/helptexthashrwdeliza.rb +39 -0
- data/code/superant.com.rwdeliza/openhelpwindowrwdeliza.rb +23 -0
- data/code/superant.com.rwdeliza/runrwdshellwindow.rb +12 -0
- data/code/superant.com.rwdeliza/rwdtinkerversion.rb +10 -0
- data/code/superant.com.rwdeliza/tagsentence.rb +39 -0
- data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/helptexthashtinkerwin2.rb +61 -0
- data/code/superant.com.rwdtinkerbackwindow/initiateapplets.rb +240 -0
- data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +34 -0
- data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +20 -0
- data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +12 -0
- data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +53 -0
- data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +12 -0
- data/code/superant.com.rwdtinkerbackwindow/listzips.rb +27 -0
- data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +22 -0
- data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -0
- data/code/superant.com.rwdtinkerbackwindow/network.rb +87 -0
- data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +38 -0
- data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +24 -0
- data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +46 -0
- data/code/superant.com.rwdtinkerbackwindow/removeappletvariables.rb +52 -0
- data/code/superant.com.rwdtinkerbackwindow/runremoteinstall.rb +11 -0
- data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +15 -0
- data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +13 -0
- data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +22 -0
- data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +24 -0
- data/code/superant.com.words/dictlookup.rb +20 -0
- data/code/superant.com.words/runfortunewindow.rb +14 -0
- data/code/superant.com.words/runrwdwordsbackwindow.rb +10 -0
- data/code/superant.com.words/runrwdwordsversion.rb +14 -0
- data/code/superant.com.words/rwdtinkerversion.rb +10 -0
- data/code/zz0applicationend/zz0end.rb +4 -0
- data/configuration/language.dist +8 -0
- data/configuration/rwdapplicationidentity.dist +3 -0
- data/configuration/rwdtinker.dist +18 -0
- data/configuration/rwdweliza-0.03.dist +31 -0
- data/configuration/tinkerwin2variables.dist +17 -0
- data/gui/00coreguibegin/applicationguitop.rwd +4 -0
- data/gui/frontwindow0/cc0openphoto.rwd +22 -0
- data/gui/frontwindowselections/00selectiontabbegin.rwd +11 -0
- data/gui/frontwindowselections/jumplinkcommands.rwd +15 -0
- data/gui/frontwindowselections/wwselectionend.rwd +3 -0
- data/gui/frontwindowtdocuments/00documentbegin.rwd +6 -0
- data/gui/frontwindowtdocuments/tinkerdocuments.rwd +14 -0
- data/gui/frontwindowtdocuments/zzdocumentend.rwd +8 -0
- data/gui/helpaboutbegin/zzzrwdlasttab.rwd +6 -0
- data/gui/helpaboutbegin/zzzzhelpscreenstart.rwd +3 -0
- data/gui/helpaboutbegin/zzzzzzhelpabouttab.rwd +15 -0
- data/gui/helpaboutzend/helpscreenend.rwd +3 -0
- data/gui/helpaboutzend/zhelpscreenstart2.rwd +3 -0
- data/gui/helpaboutzend/zzzzhelpabout2.rwd +15 -0
- data/gui/helpaboutzend/zzzzhelpscreen2end.rwd +3 -0
- data/gui/tinkerbackwindows/superant.com.refreshwindow/fortunerefreshwindowtwo.rwd +9 -0
- data/gui/tinkerbackwindows/superant.com.rwdeliza/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.rwdeliza/1eliza.rwd +21 -0
- data/gui/tinkerbackwindows/superant.com.rwdeliza/4sentance.rwd +21 -0
- data/gui/tinkerbackwindows/superant.com.rwdeliza/98jumplinkcommands.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.rwdeliza/zbackend.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/20downloadftp.rwd +45 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/67viewconfiguration.rwd +29 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/70rwddiagnostics.rwd +16 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/m01menubegin.rwd +18 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/zvbackend.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/40rwdlistzips.rwd +41 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/45installremotezip.rwd +44 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/50rwdlistapplets.rwd +44 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/60editconfiguration.rwd +30 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/70rwddiagnostics.rwd +29 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/81jumplinkcommands.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/9backend.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/1appname.rwd +31 -0
- data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/9end.rwd +4 -0
- data/gui/tinkerbackwindows/superant.com.versionwindow/1appname.rwd +19 -0
- data/gui/tinkerbackwindows/superant.com.versionwindow/helpaboutwindow.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.words/1appname.rwd +4 -0
- data/gui/tinkerbackwindows/superant.com.words/1dictionary.rwd +19 -0
- data/gui/tinkerbackwindows/superant.com.words/3rwdfortune.rwd +14 -0
- data/gui/tinkerbackwindows/superant.com.words/77jumplinkcommands.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.words/z9end.rwd +6 -0
- data/gui/zzcoreguiend/yy9rwdend.rwd +4 -0
- data/init.rb +277 -0
- data/installed/rwdweliza-0.03.inf +24 -0
- data/installed/temp.rb +1 -0
- data/lang/en/rwdcore/languagefile.rb +58 -0
- data/lang/es/rwdcore/languagefile-es.rb +62 -0
- data/lang/fr/rwdcore/languagefile.rb +64 -0
- data/lang/jp/rwdcore/languagefile.rb +72 -0
- data/lang/nl/rwdcore/languagefile.rb +75 -0
- data/lib/dict.rb +438 -0
- data/lib/druida.rb +499 -0
- data/lib/hashslice.rb +71 -0
- data/lib/linguistics.rb +360 -0
- data/lib/linguistics/en.rb +1601 -0
- data/lib/linguistics/en/infinitive.rb +1148 -0
- data/lib/linguistics/en/linkparser.rb +142 -0
- data/lib/linguistics/en/wordnet.rb +253 -0
- data/lib/linguistics/iso639.rb +456 -0
- data/lib/linkparser.rb +461 -0
- data/lib/linkparser/connection.rb +81 -0
- data/lib/linkparser/connector.rb +201 -0
- data/lib/linkparser/definition.rb +225 -0
- data/lib/linkparser/dictionary.rb +208 -0
- data/lib/linkparser/linkage.rb +185 -0
- data/lib/linkparser/log.rb +39 -0
- data/lib/linkparser/sentence.rb +79 -0
- data/lib/linkparser/utils.rb +540 -0
- data/lib/linkparser/word.rb +92 -0
- data/lib/rconftool.rb +380 -0
- data/lib/rwd/browser.rb +123 -0
- data/lib/rwd/ftools.rb +174 -0
- data/lib/rwd/mime.rb +328 -0
- data/lib/rwd/net.rb +866 -0
- data/lib/rwd/ruby.rb +889 -0
- data/lib/rwd/rwd.rb +1942 -0
- data/lib/rwd/sgml.rb +236 -0
- data/lib/rwd/thread.rb +63 -0
- data/lib/rwd/tree.rb +371 -0
- data/lib/rwd/xml.rb +101 -0
- data/lib/zip/ioextras.rb +114 -0
- data/lib/zip/stdrubyext.rb +111 -0
- data/lib/zip/tempfile_bugfixed.rb +195 -0
- data/lib/zip/zip.rb +1378 -0
- data/lib/zip/zipfilesystem.rb +558 -0
- data/lib/zip/ziprequire.rb +61 -0
- data/rwd_files/HowTo_Eliza.txt +195 -0
- data/rwd_files/HowTo_Tinker.txt +471 -0
- data/rwd_files/HowTo_TinkerWin2.txt +202 -0
- data/rwd_files/Readme.txt +57 -0
- data/rwd_files/RubyWebDialogs.html +6 -0
- data/rwd_files/favicon.ico +0 -0
- data/rwd_files/rdoc-style.css +175 -0
- data/rwd_files/rwdapplications.html +54 -0
- data/rwd_files/tinker.png +0 -0
- data/rwdconfig.dist +21 -0
- data/rwdeliza.rb +1 -0
- data/tests/RubyGauge.rb +179 -0
- data/tests/checkdepends.sh +4 -0
- data/tests/cleancnf.sh +6 -0
- data/tests/makedist-rwdweliza.rb +56 -0
- data/tests/makedist.rb +66 -0
- data/tests/rdep.rb +354 -0
- data/tests/totranslate.lang +93 -0
- data/zips/rwdwaddresses-1.05.zip +0 -0
- data/zips/rwdwcalc-0.61.zip +0 -0
- data/zips/rwdwgutenberg-0.09.zip +0 -0
- data/zips/rwdwschedule-1.04.zip +0 -0
- data/zips/rwdwshell-1.04.zip +0 -0
- data/zips/temp.rb +1 -0
- data/zips/wrubyslippers-1.06.zip +0 -0
- metadata +282 -0
data/lib/druida.rb
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
#
|
|
3
|
+
#Copyright (c) 2007 Federico Zagarzaz�
|
|
4
|
+
#
|
|
5
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
#of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
#in the Software without restriction, including without limitation the rights
|
|
8
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
#copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
#furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
#The above copyright notice and this permission notice shall be included in
|
|
13
|
+
#all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
#THE SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
require 'optparse'
|
|
24
|
+
require 'ostruct'
|
|
25
|
+
require 'yaml'
|
|
26
|
+
require 'fileutils'
|
|
27
|
+
require 'enumerator'
|
|
28
|
+
|
|
29
|
+
# default settings
|
|
30
|
+
NAME = 'druida'
|
|
31
|
+
VER = '1.0.0'
|
|
32
|
+
DB_DIR_PATH = "ElizaData/database"
|
|
33
|
+
DB_PREFIX = '/db.'
|
|
34
|
+
DB_NELS = 1000 # max num of elements
|
|
35
|
+
# for each db file.
|
|
36
|
+
# little files =>
|
|
37
|
+
# faster and < mem
|
|
38
|
+
# when user wants
|
|
39
|
+
# a random quote.
|
|
40
|
+
LP = 5 # left padding
|
|
41
|
+
MAX_TAGS_LEN = 42
|
|
42
|
+
MAX_TAG_LEN = 40
|
|
43
|
+
MAX_STR_LEN = 700
|
|
44
|
+
MAX_STR_NLINES = 7 # quotes, not books
|
|
45
|
+
EX = <<EOF
|
|
46
|
+
Examples:
|
|
47
|
+
# #{NAME}
|
|
48
|
+
Prints a random quote.
|
|
49
|
+
|
|
50
|
+
# #{NAME} -t rating -s "4 > x > 1"
|
|
51
|
+
Prints all quotes with the given rating(s).
|
|
52
|
+
|
|
53
|
+
# #{NAME} -t tags -s wisdom,life
|
|
54
|
+
Search for quotes with the given tags.
|
|
55
|
+
|
|
56
|
+
# #{NAME} -t author -s 'Seneca' -p
|
|
57
|
+
Print a random quote from Seneca.
|
|
58
|
+
|
|
59
|
+
# #{NAME} -a
|
|
60
|
+
Adds quote to database.
|
|
61
|
+
|
|
62
|
+
# #{NAME} -e 12
|
|
63
|
+
Edit quote 12.
|
|
64
|
+
|
|
65
|
+
# #{NAME} -t author -s 'Joe Doe' \\
|
|
66
|
+
-t tags -s \"drugs,sex\" -t rating -s \">2\" \\
|
|
67
|
+
-t text -s 'wild'
|
|
68
|
+
Print quotes of 'Joe Doe', that have the
|
|
69
|
+
tags 'drugs' and 'sex', a rating of more than
|
|
70
|
+
two stars, and contain the word 'wild'.
|
|
71
|
+
|
|
72
|
+
EOF
|
|
73
|
+
|
|
74
|
+
class String
|
|
75
|
+
# return longest words of string
|
|
76
|
+
# (QuoteDB -> find_similar)
|
|
77
|
+
def key_words
|
|
78
|
+
arr = self.gsub(/[^\w\s]/, '').split(' ').sort_by {|w| w.length}
|
|
79
|
+
arr[(arr.length / 2)..(arr.length - 1)]
|
|
80
|
+
end
|
|
81
|
+
def count_lines
|
|
82
|
+
n = 0
|
|
83
|
+
scan(/\n/) {n+=1}
|
|
84
|
+
n
|
|
85
|
+
end
|
|
86
|
+
def count_words
|
|
87
|
+
n= 0
|
|
88
|
+
scan(/\b\S+\b/) {n+=1}
|
|
89
|
+
n
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class Quote
|
|
94
|
+
attr_accessor :quote, :author, :info, :rating
|
|
95
|
+
attr_reader :tags
|
|
96
|
+
def initialize(a, r, t, i, q)
|
|
97
|
+
@quote = q
|
|
98
|
+
@author = a
|
|
99
|
+
@tags = t.uniq
|
|
100
|
+
@info = i
|
|
101
|
+
@rating = r.nil? ? 0 : r
|
|
102
|
+
end
|
|
103
|
+
def tags=(arr)
|
|
104
|
+
@tags = arr
|
|
105
|
+
@tags.uniq!
|
|
106
|
+
end
|
|
107
|
+
def print(n = nil, quiet = false)
|
|
108
|
+
puts @quote
|
|
109
|
+
puts ' '*LP + '-- ' + @author
|
|
110
|
+
puts ' '*LP + @info unless quiet
|
|
111
|
+
puts ' '*LP + "(rating: #{@rating})" unless quiet
|
|
112
|
+
puts ' '*LP + '(tags: ' + @tags.join(', ') + ')' unless quiet
|
|
113
|
+
puts ' '*LP + "[#{n}]" unless quiet || n == nil
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
class QuoteDB
|
|
117
|
+
def initialize(db_path, db_nums = [])
|
|
118
|
+
@db_path = db_path
|
|
119
|
+
@db = []
|
|
120
|
+
@db_nums = db_nums # -> save()
|
|
121
|
+
|
|
122
|
+
# convert relative to absolute quote index(for user), -> index()
|
|
123
|
+
@offset = @db_nums.length == 1 ? DB_NELS * (@db_nums[0] - 1) : 0
|
|
124
|
+
|
|
125
|
+
# database is split into multiple files of DB_NELS length
|
|
126
|
+
@db_nums.each {|n| @db += YAML.load_file(@db_path + n.to_s) }
|
|
127
|
+
end
|
|
128
|
+
def empty?
|
|
129
|
+
@db.empty?
|
|
130
|
+
end
|
|
131
|
+
def add(arr)
|
|
132
|
+
@db << Quote.new(*arr)
|
|
133
|
+
end
|
|
134
|
+
def del(n)
|
|
135
|
+
@db.delete_at(n) unless empty?
|
|
136
|
+
end
|
|
137
|
+
def last_num
|
|
138
|
+
empty? ? nil : @db.length - 1
|
|
139
|
+
end
|
|
140
|
+
def length
|
|
141
|
+
@db.length
|
|
142
|
+
end
|
|
143
|
+
def index(q)
|
|
144
|
+
@db.index(q) + @offset
|
|
145
|
+
end
|
|
146
|
+
def [](n)
|
|
147
|
+
empty? ? nil : @db[n]
|
|
148
|
+
end
|
|
149
|
+
def remove_duplicates
|
|
150
|
+
dups = []
|
|
151
|
+
@db.each do |q|
|
|
152
|
+
next if dups.include?(q)
|
|
153
|
+
a = find_similar(q.author, q.quote.key_words)
|
|
154
|
+
a.shift
|
|
155
|
+
dups += a if ! a.empty?
|
|
156
|
+
end
|
|
157
|
+
if ! dups.empty?
|
|
158
|
+
puts "removing #{dups.length} quotes..."
|
|
159
|
+
@db -= dups
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
def find_similar(author, key_words)
|
|
163
|
+
# pretty basic function, much room for improvement
|
|
164
|
+
|
|
165
|
+
# use the longest word in author's name to catch more
|
|
166
|
+
r = Regexp.new(author.key_words.last, true)
|
|
167
|
+
ret = []
|
|
168
|
+
@db.find_all {|q| q.author =~ r}.each do |q|
|
|
169
|
+
ret << q if key_words.all? {|w| q.quote.gsub(/[^\w\s]/, '') =~ Regexp.new(w, true) }
|
|
170
|
+
end
|
|
171
|
+
ret
|
|
172
|
+
end
|
|
173
|
+
def search_tags(arr, ret = [])
|
|
174
|
+
ret = @db.find_all {|q| arr.all? {|t| q.tags.include?(t)} } unless empty?
|
|
175
|
+
ret
|
|
176
|
+
end
|
|
177
|
+
def search_ratings(arr, ret = [])
|
|
178
|
+
return ret if empty? || arr.empty?
|
|
179
|
+
num_left = arr[0] =~ /\d/
|
|
180
|
+
num, cnd = num_left ? [arr[0].to_i, arr[1]] : [arr[1].to_i, arr[0]]
|
|
181
|
+
arr.slice!(0..1)
|
|
182
|
+
|
|
183
|
+
ret = @db.find_all do |q|
|
|
184
|
+
r = q.rating
|
|
185
|
+
case cnd
|
|
186
|
+
when '>' : num_left ? (num > r) : (r > num)
|
|
187
|
+
when '>=': num_left ? (num >= r) : (r >= num)
|
|
188
|
+
when '=' : num != r
|
|
189
|
+
when '<=': num_left ? (num <= r) : (r <= num)
|
|
190
|
+
when '<' : num_left ? (num < r) : (r < num)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
search_ratings(arr, ret)
|
|
194
|
+
end
|
|
195
|
+
def search_quotes(str, ret = [])
|
|
196
|
+
return if empty?
|
|
197
|
+
r = Regexp.new(str, true)
|
|
198
|
+
ret = @db.find_all {|q| q.quote =~ r}
|
|
199
|
+
ret
|
|
200
|
+
end
|
|
201
|
+
def search_authors(str, ret = [])
|
|
202
|
+
return if empty?
|
|
203
|
+
r = Regexp.new(str, true)
|
|
204
|
+
ret = @db.find_all {|q| q.author =~ r}
|
|
205
|
+
ret
|
|
206
|
+
end
|
|
207
|
+
def save
|
|
208
|
+
puts 'saving...'
|
|
209
|
+
|
|
210
|
+
# delete all db files that were loaded(if any)
|
|
211
|
+
# to avoid files being left over when deleting quotes
|
|
212
|
+
@db_nums.each {|n| FileUtils.rm(@db_path + n.to_s) }
|
|
213
|
+
|
|
214
|
+
# modify only the db file that was loaded(editing)
|
|
215
|
+
i = @db_nums.empty? ? 1 : @db_nums.first
|
|
216
|
+
|
|
217
|
+
@db.each_slice(DB_NELS) do |a|
|
|
218
|
+
File.open(@db_path + i.to_s, 'w') {|f| YAML.dump(a, f)}
|
|
219
|
+
i += 1
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def invalid_strings?(arr)
|
|
225
|
+
arr.each do |x|
|
|
226
|
+
return true unless x.length < MAX_STR_LEN
|
|
227
|
+
return true unless x.count_lines < MAX_STR_NLINES
|
|
228
|
+
end
|
|
229
|
+
false
|
|
230
|
+
end
|
|
231
|
+
def invalid_tags?(arr)
|
|
232
|
+
return true unless arr.empty? || arr.length <= MAX_TAGS_LEN
|
|
233
|
+
return true unless arr.empty? || ! arr.find {|t| t.length > MAX_TAG_LEN}
|
|
234
|
+
false
|
|
235
|
+
end
|
|
236
|
+
def invalid_rating?(r)
|
|
237
|
+
return true unless r.nil? || 0 <= r && r < 6
|
|
238
|
+
false
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# handle search argument(s)
|
|
242
|
+
def parse_search(quotedb, type, str)
|
|
243
|
+
s, ret = str.dup, nil
|
|
244
|
+
case type
|
|
245
|
+
when :tags
|
|
246
|
+
s = s.split(',')
|
|
247
|
+
raise "Invalid --search argument." if s.empty?
|
|
248
|
+
ret = quotedb.search_tags(s)
|
|
249
|
+
when :rating
|
|
250
|
+
s = s.split(' '); s.delete("x")
|
|
251
|
+
raise "Invalid --search argument." if s.length != 2 && s.length != 4
|
|
252
|
+
raise "Invalid --search argument." if s.find {|x| x =~ /[^<>=0-6]/}
|
|
253
|
+
ret = quotedb.search_ratings(s)
|
|
254
|
+
when :author
|
|
255
|
+
raise "invalid author string(too long)" if invalid_strings?([s])
|
|
256
|
+
ret = quotedb.search_authors(s)
|
|
257
|
+
when :text
|
|
258
|
+
raise "invalid quote string(too long)" if invalid_strings?([s])
|
|
259
|
+
ret = quotedb.search_quotes(s)
|
|
260
|
+
end
|
|
261
|
+
ret.nil? ? [] : ret
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# get quote data from user, don't ask for quote text
|
|
265
|
+
# when importing from a fortune's file
|
|
266
|
+
def get_quote_data(importing = false)
|
|
267
|
+
|
|
268
|
+
print 'Author : ' ; author = gets
|
|
269
|
+
print 'Info : ' ; info = gets
|
|
270
|
+
print 'Rating(int, 0 <= x < 6) : ' ; rating = gets
|
|
271
|
+
print 'Tags (space separated) : ' ; tags = gets
|
|
272
|
+
( print 'Quote (carefully enter, ctrl + d to end) : '; quote = ''
|
|
273
|
+
while line = gets
|
|
274
|
+
quote << line
|
|
275
|
+
end ) unless importing
|
|
276
|
+
|
|
277
|
+
raise "you've to enter quote data before pressing ctrl + d." if tags.nil?
|
|
278
|
+
[author, info, tags, quote].each {|x| x.chomp! unless x.nil?}
|
|
279
|
+
|
|
280
|
+
quote = '' if quote !~ /\w/ # otherwise if user press enters more than once
|
|
281
|
+
# when editing, it'll accidentally delete the quote.
|
|
282
|
+
# see main()
|
|
283
|
+
tags = tags.split(' ')
|
|
284
|
+
rating = rating =~ /^\d/ ? rating.to_i : nil
|
|
285
|
+
|
|
286
|
+
raise "invalid string(too long)" if invalid_strings?([quote, author, info])
|
|
287
|
+
raise "invalid tags(too many or too long)" if invalid_tags?(tags)
|
|
288
|
+
raise "invalid rating" if invalid_rating?(rating)
|
|
289
|
+
|
|
290
|
+
return [author, rating, tags, info, quote]
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def import_fortune_quotes(quotedb, in_file)
|
|
294
|
+
raise "#{in_file} not readable." unless File.readable?(in_file)
|
|
295
|
+
IO.popen("file #{in_file}") { |f| raise "not a text file." unless f.gets =~ /text/}
|
|
296
|
+
|
|
297
|
+
c, ignored, found_sep = 0, 0, false
|
|
298
|
+
author, rating, tags, info = get_quote_data(true)
|
|
299
|
+
|
|
300
|
+
# file's quotes separator: '%'
|
|
301
|
+
File.open(in_file, 'r') do |f|
|
|
302
|
+
quote = ''
|
|
303
|
+
f.each_line do |l|
|
|
304
|
+
if l !~ /^%$/
|
|
305
|
+
quote << l
|
|
306
|
+
else
|
|
307
|
+
if quote =~ /\w/ && ! invalid_strings?([quote])
|
|
308
|
+
c+=1; found_sep = true
|
|
309
|
+
quotedb.add([author, rating, tags, info, quote])
|
|
310
|
+
else
|
|
311
|
+
ignored+=1
|
|
312
|
+
end
|
|
313
|
+
quote = ''
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
raise "file has an invalid format (is it a fortune cookie file?)" unless found_sep
|
|
318
|
+
puts "#{c} quotes were added, #{ignored} ignored."
|
|
319
|
+
quotedb.save
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def main
|
|
323
|
+
|
|
324
|
+
options = OpenStruct.new
|
|
325
|
+
options.num = nil # int
|
|
326
|
+
options.search = [] # str
|
|
327
|
+
options.type_ = [] # sym
|
|
328
|
+
options.rand = false
|
|
329
|
+
options.add = false
|
|
330
|
+
options.edit = nil # int
|
|
331
|
+
options.del = nil # int
|
|
332
|
+
options.dups = false
|
|
333
|
+
options.len = false
|
|
334
|
+
options.quiet = true
|
|
335
|
+
options.import = nil # str (path to file)
|
|
336
|
+
options.count = 0
|
|
337
|
+
|
|
338
|
+
opts = OptionParser.new do |opts|
|
|
339
|
+
opts.banner = "Usage: #{NAME} [options]"
|
|
340
|
+
opts.separator ""
|
|
341
|
+
opts.on("-n", "--num n", "Print quote n.",
|
|
342
|
+
"(first element is indexed by 0)") {|n| options.num = n; options.count+=1}
|
|
343
|
+
opts.on("-a", "--add", "Add a quote to database.") {options.add = true; options.count+=1}
|
|
344
|
+
opts.on("-e", "--edit num", "Edit quote num.") {|n| options.edit = n; options.count+=1}
|
|
345
|
+
opts.on("-d", "--del num", "Delete quote num.") {|n| options.del = n; options.count+=1}
|
|
346
|
+
opts.on("-s", "--search string",
|
|
347
|
+
"Search quotes database(requires --type).",
|
|
348
|
+
"(tags: comma separated list)",
|
|
349
|
+
"(rating: you can use [>,<,=])") {|s| options.search << s; options.count+=1}
|
|
350
|
+
opts.on("-t", "--type type", [:author, :tags, :rating, :text],
|
|
351
|
+
"Type of search(author, tags, rating, text).",
|
|
352
|
+
"(requires --search).") {|t| options.type_ << t; options.count+=1}
|
|
353
|
+
opts.on("-p", "--print_rand", "Print random quote.") {options.rand = true; options.count+=1}
|
|
354
|
+
opts.on("-v", "--verbose", "Print extra quote information.") {options.quiet = false}
|
|
355
|
+
opts.on("--import fortune_file",
|
|
356
|
+
"Import quotes from a fortune file(full path).") {|f| options.import = f; options.count+=1}
|
|
357
|
+
opts.on("--duplicates",
|
|
358
|
+
"Remove \"possible\" duplicates(slow).") {options.dups = true; options.count+=1}
|
|
359
|
+
opts.on("--length", "Print number of quotes in database.") {options.len = true; options.count+=1}
|
|
360
|
+
opts.on_tail("-?", "--examples", "Show examples.") {puts EX; exit(0)}
|
|
361
|
+
opts.on_tail("-V", "--version", "Show version.") {puts "#{NAME + ' ' + VER}"; exit(0)}
|
|
362
|
+
opts.on_tail("-h", "--help", "Show this message.") {puts opts; exit(0)}
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
begin
|
|
366
|
+
db_path = File.expand_path(DB_DIR_PATH)
|
|
367
|
+
FileUtils.mkdir_p(db_path) unless File.directory?(db_path)
|
|
368
|
+
|
|
369
|
+
# build array of numbers out of db files(see QuoteDB.new)
|
|
370
|
+
r = Regexp.new(/^#{DB_PREFIX.sub(/\//, '')}(\d+)/)
|
|
371
|
+
db_nfiles = []
|
|
372
|
+
Dir.foreach(db_path) {|f| db_nfiles << $1.to_i if f =~ r }
|
|
373
|
+
|
|
374
|
+
# not acceptable decrease in performace(human time)
|
|
375
|
+
# raise "you can't have a db.0 file. (check #{DB_DIR_PATH})" if db_nfiles.include?(0)
|
|
376
|
+
# n = db_nfiles.length
|
|
377
|
+
db_nfiles = db_nfiles.sort
|
|
378
|
+
# if ! db_nfiles.empty? && (db_nfiles.inject {|sum, n| sum + n} != n*(n+1) / 2)
|
|
379
|
+
# raise "db.* files are not continuous."
|
|
380
|
+
# end
|
|
381
|
+
|
|
382
|
+
# prepare path to database files for loading
|
|
383
|
+
db_path += DB_PREFIX
|
|
384
|
+
|
|
385
|
+
# databases must be writable text files
|
|
386
|
+
# db_nfiles.each do |n|
|
|
387
|
+
# IO.popen("file #{db_path + n.to_s}") do |f|
|
|
388
|
+
# raise "database #{n} is not a text file." unless f.gets =~ /text/
|
|
389
|
+
# end
|
|
390
|
+
# raise "database #{n} is not writable." unless File.writable?(db_path + n.to_s)
|
|
391
|
+
# end
|
|
392
|
+
|
|
393
|
+
opts.parse!
|
|
394
|
+
raise "invalid input (see --help)." if ARGV.length != 0
|
|
395
|
+
|
|
396
|
+
if ! db_nfiles.empty? && (options.count == 0 || (options.count == 1 && options.rand) )
|
|
397
|
+
# load a random database file(faster and eats less memory than lading all)
|
|
398
|
+
quotedb = QuoteDB.new(db_path, [rand(db_nfiles.length) + 1] )
|
|
399
|
+
|
|
400
|
+
# pick a random quote from loaded database, convert to absolute value when printing
|
|
401
|
+
q = quotedb[rand(quotedb.length)]
|
|
402
|
+
q.print(quotedb.index(q), options.quiet)
|
|
403
|
+
else
|
|
404
|
+
case options.count
|
|
405
|
+
when 1
|
|
406
|
+
if options.num || options.edit
|
|
407
|
+
num = (options.num || options.edit).to_i
|
|
408
|
+
|
|
409
|
+
# the file num (suffix) for num
|
|
410
|
+
fn = (num / DB_NELS) + 1
|
|
411
|
+
|
|
412
|
+
raise "out of range (no file)." unless File.exist?(db_path + fn.to_s)
|
|
413
|
+
quotedb = QuoteDB.new(db_path, [fn])
|
|
414
|
+
|
|
415
|
+
# convert user's num to relative num inside quotedb
|
|
416
|
+
n = num % DB_NELS
|
|
417
|
+
|
|
418
|
+
raise "out of range." unless n < quotedb.length
|
|
419
|
+
|
|
420
|
+
if options.num
|
|
421
|
+
quotedb[n].print(num, options.quiet)
|
|
422
|
+
else
|
|
423
|
+
puts 'leave empty the fields you don\'t want to edit.'
|
|
424
|
+
arr, q = get_quote_data, quotedb[n]
|
|
425
|
+
q.author = arr[0] unless arr[0].empty?
|
|
426
|
+
q.rating = arr[1] unless ! arr[1]
|
|
427
|
+
q.tags = arr[2] unless arr[2].empty?
|
|
428
|
+
q.info = arr[3] unless arr[3].empty?
|
|
429
|
+
q.quote = arr[4] unless arr[4].empty?
|
|
430
|
+
quotedb.save
|
|
431
|
+
end
|
|
432
|
+
else
|
|
433
|
+
quotedb = QuoteDB.new(db_path, db_nfiles)
|
|
434
|
+
if options.len
|
|
435
|
+
puts "Length: #{quotedb.length}"
|
|
436
|
+
elsif options.add
|
|
437
|
+
arr = get_quote_data
|
|
438
|
+
raise "missing author/quote field." if arr[0].empty? || arr[4].empty?
|
|
439
|
+
qn = quotedb.find_similar(arr[0], arr[4].key_words)
|
|
440
|
+
if ! qn.empty?
|
|
441
|
+
puts "Similar quote(s) exists: #{qn.join(', ')} (indices)"
|
|
442
|
+
print "\nProceed? (yes/no) : "; ans = gets
|
|
443
|
+
(puts "Canceled."; exit(0)) if ans !~ /^yes/
|
|
444
|
+
end
|
|
445
|
+
quotedb.add(arr); quotedb.save
|
|
446
|
+
elsif options.import
|
|
447
|
+
import_fortune_quotes(quotedb, options.import)
|
|
448
|
+
elsif options.del
|
|
449
|
+
raise "out of range." unless options.del.to_i < quotedb.length
|
|
450
|
+
quotedb.del(options.del.to_i); quotedb.save
|
|
451
|
+
elsif options.dups
|
|
452
|
+
quotedb.remove_duplicates
|
|
453
|
+
quotedb.save
|
|
454
|
+
else
|
|
455
|
+
raise "Invalid option (see --help)."
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
when 2
|
|
459
|
+
quotedb = QuoteDB.new(db_path, db_nfiles)
|
|
460
|
+
if ! options.search.empty?
|
|
461
|
+
raise "Incompatible options (see --help)." if options.type_.empty?
|
|
462
|
+
a = parse_search(quotedb, options.type_[0], options.search[0])
|
|
463
|
+
if a.empty?
|
|
464
|
+
puts 'none found'
|
|
465
|
+
else
|
|
466
|
+
a.each {|q| q.print(quotedb.index(q), options.quiet) }
|
|
467
|
+
end
|
|
468
|
+
else
|
|
469
|
+
raise "Incompatible options (see --help)."
|
|
470
|
+
end
|
|
471
|
+
else
|
|
472
|
+
quotedb = QuoteDB.new(db_path, db_nfiles)
|
|
473
|
+
if options.search.length == options.type_.length && options.count < 10
|
|
474
|
+
a = []
|
|
475
|
+
options.search.length.times do |i|
|
|
476
|
+
r = parse_search(quotedb, options.type_[i], options.search[i])
|
|
477
|
+
a = a.empty? ? r : a & r
|
|
478
|
+
end
|
|
479
|
+
if a.empty?
|
|
480
|
+
puts 'none found'
|
|
481
|
+
else
|
|
482
|
+
rnd = rand(a.length)
|
|
483
|
+
if options.rand
|
|
484
|
+
a[rnd].print(quotedb.index(a[rnd]), options.quiet)
|
|
485
|
+
else
|
|
486
|
+
a.each {|q| q.print(quotedb.index(q), options.quiet) }
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
else
|
|
490
|
+
raise "Incompatible options (see --help)."
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
rescue StandardError => bang
|
|
495
|
+
puts "\n" + 'Oops, ' + bang
|
|
496
|
+
exit(1)
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
main
|