rwdeliza 0.03
Sign up to get free protection for your applications and to get access to all the features.
- 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
|